summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam T. Carpenter <atc@53hor.net>2021-04-09 18:50:55 -0400
committerAdam T. Carpenter <atc@53hor.net>2021-04-09 18:50:55 -0400
commit201a37e8d3d0ef4c59b184c0707ec8ddd301a25a (patch)
tree1aae6c03bfb9f694adea81510dacf586311fcc12
parent881e4bf3c9141b4bebaefaf6385652ed46d9a9fe (diff)
downloadtwinh-201a37e8d3d0ef4c59b184c0707ec8ddd301a25a.tar.xz
twinh-201a37e8d3d0ef4c59b184c0707ec8ddd301a25a.zip
spruced up templates, some repo impl
-rw-r--r--Cargo.toml10
-rw-r--r--artifacts/ui-demo.html119
-rw-r--r--src/config.rs2
-rw-r--r--src/main.rs13
-rw-r--r--src/repo/constants.rs9
-rw-r--r--src/repo/mod.rs28
-rw-r--r--src/routes/mod.rs (renamed from src/handlers/mod.rs)45
-rw-r--r--src/templates/base.hbs155
-rw-r--r--src/templates/index.hbs74
-rw-r--r--src/templates/index.html85
-rw-r--r--src/templates/login.hbs7
-rw-r--r--src/templates/login.html6
-rw-r--r--src/templates/mod.rs25
-rw-r--r--src/templates/suggestions.hbs9
14 files changed, 394 insertions, 193 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 465754c..13b4535 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,14 +5,14 @@ authors = ["Adam T. Carpenter <atc@53hor.net>"]
edition = "2018"
[dependencies]
-bincode = "1.3"
+bincode = "1"
env_logger = "0.8"
-handlebars = "3.5"
+handlebars = "3"
hyper = { version = "0.14", default-features = false, features = ["full"] }
hyper-rustls = "0.22"
log = "0.4"
-once_cell = "1.7"
-serde = { version = "1.0", features = ["derive"]}
+once_cell = "1"
+serde = { version = "1", features = ["derive"]}
serde_urlencoded = "0.7"
sled = "0.34"
-tokio = { version = "1.2", default-features = false, features = ["full"] }
+tokio = { version = "1", default-features = false, features = ["full"] }
diff --git a/artifacts/ui-demo.html b/artifacts/ui-demo.html
index 6fe3a18..09dc9cb 100644
--- a/artifacts/ui-demo.html
+++ b/artifacts/ui-demo.html
@@ -11,6 +11,10 @@
padding: 0;
}
+ .model::before {
+ content: "➥";
+ }
+
.topbar {
background-color: var(--balboa);
box-shadow: 0 0 0.5em black;
@@ -31,6 +35,10 @@
padding: 14px 14px;
}
+ .topbar li.right {
+ float: right;
+ }
+
.topbar li a {
color: white;
text-decoration: none;
@@ -42,38 +50,46 @@
z-index: -1;
position: fixed;
top: 3em;
- left: -20%;
+ left: 0;
width: 20%;
height: 100%;
transition: 0.25s;
}
- .sidebar ul {
- list-style-type: none;
+ .sidebar button {
+ display: block;
+ background: none;
+ border: 0 none;
+ cursor: pointer;
+ color: white;
}
- .sidebar a {
- color: white;
- text-decoration: none;
+ .model {
+ margin-left: 20px;
}
- #menu:target .sidebar {
- left: 0;
+ .model::before {
+ content: "➥";
}
- .menuToggle a.closeMenu {
- display: none;
+ #hidden:target .sidebar {
+ left: -20%;
}
- #menu:target .menuToggle a.closeMenu {
- display: block;
+
+ .menuToggle a.openMenu {
+ display: none;
}
- #menu:target .menuToggle a.openMenu {
+ #hidden:target .menuToggle a.closeMenu {
display: none;
}
- #menu:target section {
- margin-left: 20%;
+ #hidden:target .menuToggle a.openMenu {
+ display: block;
+ }
+
+ #hidden:target section {
+ margin-left: 0;
}
.catalogTable {
@@ -105,6 +121,7 @@
}
section {
+ margin-left: 20%;
transition: margin-left 0.25s;
padding-top: 2em;
padding-left: 2em;
@@ -112,12 +129,12 @@
}
</style>
</head>
- <body id="menu">
+ <body id="hidden">
<nav class="topbar">
<ul>
<li>
<div class="menuToggle">
- <a class="openMenu" href="#menu"
+ <a class="openMenu" href="#"
><span
><svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
<path
@@ -125,7 +142,7 @@
d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z"
/></svg></span
></a>
- <a class="closeMenu" href="#"
+ <a class="closeMenu" href="#hidden"
><span
><svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
<path
@@ -135,57 +152,57 @@
></a>
</div>
</li>
- <li><a href="#menu">Catalog</a></li>
- <li><a href="#">Parts List</a></li>
- <li><a href="#">Cars List</a></li>
+ <li><a href="#">Index</a></li>
+ <li><a href="#">Parts</a></li>
+ <li><a href="#">Cars</a></li>
<li><a href="#">Suggestions</a></li>
<li><a href="#">About</a></li>
- <li><a href="#">Login</a></li>
+ <li class="right"><a href="#">Login</a></li>
</ul>
</nav>
<nav class="sidebar">
- <ul>
- <li>
- <a href="#menu">Hudson</a>
- <ul>
- <li><a href="#menu">Hornet</a></li>
- </ul>
- </li>
- <li><a href="#menu">Essex</a></li>
- <li><a href="#menu">Terraplane</a></li>
- </ul>
+ {{#each makes}}
+ <form action="/parts">
+ {{#if (eq this ../selected_make)}}
+ <button disabled class="make">
+ {{ this }}
+ </button>
+ <input type="hidden" name="make" value="{{ ../selected_make }}" />
+ {{#each ../models}}
+ {{#if (eq this ../../selected_model)}}
+ <button disabled class="model">{{ this }}</button>
+ {{else}}
+ <button class="model" name="model" value="{{ this }}">
+ {{ this }}
+ </button>
+ {{/if}}
+ {{else}}
+ <button disabled class="model">(No models found)</button>
+ {{/each}}
+ {{else}}
+ <button class="make" name="make" value="{{ this }}">{{ this }}</button>
+ {{/if}}
+ </form>
+ {{else}}
+ No makes found.
+ {{/each}}
</nav>
<section>
<form>
- <input autofocus type="search" placeholder="hit enter to search!" />
+ <input autofocus type="search" placeholder="hit enter to search" />
</form>
</section>
<section>
<table class="catalogTable">
- <thead>
- <tr>
- <th>Make</th>
- <th>Model</th>
- <th>Engine CID</th>
- <th>Year</th>
- </tr>
- </thead>
<tbody>
+ {{#each parts}}
<tr>
- <td>Hudson</td>
- <td>Wasp</td>
- <td>262ci</td>
- <td>1952</td>
- </tr>
- <tr>
- <td>Hudson</td>
- <td>Hornet</td>
- <td>308ci</td>
- <td>1953</td>
+ <td>{{ this }}</td>
</tr>
+ {{/each}}
</tbody>
</table>
</section>
diff --git a/src/config.rs b/src/config.rs
index 7798967..b3c9715 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,7 +1,7 @@
use once_cell::sync::Lazy;
use std::{env::var, error::Error, net::SocketAddr};
-pub static INSTANCE: Lazy<AppConfig> =
+pub static CONFIG_INSTANCE: Lazy<AppConfig> =
Lazy::new(|| AppConfig::from_env().expect("Error loading config"));
#[derive(Clone, Debug)]
diff --git a/src/main.rs b/src/main.rs
index 1947ff8..4a5a8b1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,28 +1,27 @@
+use crate::config::CONFIG_INSTANCE;
+use crate::error::TwinHError;
use hyper::{
service::{make_service_fn, service_fn},
Server,
};
-use std::convert::Infallible; // TODO:
mod config;
mod error;
-mod handlers;
mod models;
mod repo;
+mod routes;
mod templates;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
- let addr = config::INSTANCE.addr;
+ let addr = CONFIG_INSTANCE.addr;
- let make_svc = make_service_fn(move |_conn| async {
- Ok::<_, Infallible>(service_fn(|req| handlers::router(req)))
- });
+ let make_svc =
+ make_service_fn(move |_conn| async { Ok::<_, TwinHError>(service_fn(routes::router)) });
let server = Server::bind(&addr).serve(make_svc);
let graceful = server.with_graceful_shutdown(shutdown_signal());
- // run until shutdown signal
if let Err(e) = graceful.await {
eprintln!("server error: {}", e);
}
diff --git a/src/repo/constants.rs b/src/repo/constants.rs
index e168a77..6da641f 100644
--- a/src/repo/constants.rs
+++ b/src/repo/constants.rs
@@ -1,11 +1,2 @@
-use once_cell::sync::Lazy;
-use sled::{Config, Db};
-
pub const PARTS_TREE: &str = "parts";
pub const CARS_TREE: &str = "cars";
-pub static REPO_INSTANCE: Lazy<Db> = Lazy::new(|| {
- Config::default()
- .path("/tmp/twinh")
- .open()
- .expect("Couldn't open DB!")
-});
diff --git a/src/repo/mod.rs b/src/repo/mod.rs
index d4c5e44..f0bb95c 100644
--- a/src/repo/mod.rs
+++ b/src/repo/mod.rs
@@ -1,16 +1,36 @@
+use crate::config::CONFIG_INSTANCE;
use crate::error::TwinHError;
use crate::models::Car;
use crate::models::Part;
use bincode::deserialize;
use constants::*;
+use once_cell::sync::Lazy;
+use sled::{Config, Db};
mod constants;
+static REPO_INSTANCE: Lazy<Db> = Lazy::new(|| {
+ Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .temporary(true)
+ .open()
+ .expect("Couldn't open DB!")
+});
+
+pub fn create_demo_db() -> Result<(), TwinHError> {
+ let db = sled::Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .create_new(true)
+ .open()?;
+ let cars_tree = db.open_tree(CARS_TREE)?;
+ Ok(())
+}
+
pub fn create_new_db() -> Result<(), TwinHError> {
- let config = sled::Config::default()
- .path("/var/db/twinh")
- .create_new(true);
- let db = config.open()?;
+ sled::Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .create_new(true)
+ .open()?;
Ok(())
}
diff --git a/src/handlers/mod.rs b/src/routes/mod.rs
index 3ad7f49..1866e49 100644
--- a/src/handlers/mod.rs
+++ b/src/routes/mod.rs
@@ -1,19 +1,20 @@
+use crate::error::TwinHError;
+use crate::repo;
use crate::templates;
-use handlebars::Handlebars;
use hyper::body::HttpBody as _;
use hyper::Method;
use hyper::StatusCode;
use hyper::{Body, Request, Response};
use serde::{Deserialize, Serialize};
-use sled::Db;
-use std::convert::Infallible; // TODO:
-pub async fn router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+pub async fn router(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
match (req.method(), req.uri().path()) {
- (&Method::GET, "/") | (&Method::GET, "/index.html") => index(req).await,
- (&Method::GET, "/login") | (&Method::GET, "/login/index.html") => login().await,
+ (&Method::GET, "/") => index(req).await,
+ (&Method::GET, "/cars") => cars(req).await,
+ (&Method::GET, "/login") => login().await,
(&Method::GET, "/login/google") => login_google().await,
(&Method::GET, "/login/google/code") => login_google_code(req).await,
+ (&Method::GET, "/suggestions") => suggestions().await,
_ => Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body("Not found.".into())
@@ -21,11 +22,17 @@ pub async fn router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
}
}
-async fn login() -> Result<Response<Body>, Infallible> {
- Ok(Response::new(templates::LOGIN_T.into()))
+async fn suggestions() -> Result<Response<Body>, TwinHError> {
+ todo!()
}
-async fn login_google() -> Result<Response<Body>, Infallible> {
+async fn login() -> Result<Response<Body>, TwinHError> {
+ Ok(Response::new(
+ templates::REGISTRY.render("login", &"").unwrap().into(),
+ ))
+}
+
+async fn login_google() -> Result<Response<Body>, TwinHError> {
let uri = hyper::Uri::builder()
.scheme("https")
.authority("accounts.google.com")
@@ -69,7 +76,7 @@ impl Default for AuthRequest {
}
}
-async fn login_google_code(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+async fn login_google_code(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
let query = req.uri().query().unwrap_or_default();
let query = serde_urlencoded::de::from_str::<GoogleOAuthQuery>(query).unwrap();
if query.state != "BLARGH" {
@@ -116,12 +123,14 @@ pub struct AccessToken {
token_type: String,
}
-async fn index(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+async fn cars(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
+ let cars = repo::get_all_cars().unwrap();
+ todo!()
+}
+
+async fn index(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
let query = req.uri().query().unwrap_or_default();
let filter = serde_urlencoded::de::from_str::<PartsQuery>(query).unwrap();
- let mut reg = Handlebars::new();
- reg.register_template_string("index", templates::INDEX_T)
- .unwrap();
let mut data = PartsData::default();
data.makes = Some(vec!["Hudson".into(), "Essex".into(), "Terraplane".into()]);
@@ -140,8 +149,12 @@ async fn index(req: Request<Body>) -> Result<Response<Body>, Infallible> {
data.selected_model = Some(model);
}
- let result = reg.render("index", &data).unwrap();
- Ok(Response::new(result.into()))
+ let body = templates::REGISTRY.render("index", &data).unwrap();
+ let resp = Response::builder()
+ .header(hyper::header::CONTENT_TYPE, "text/html; charset=utf-8")
+ .body(body.into())
+ .unwrap();
+ Ok(resp)
}
#[derive(Debug, Deserialize)]
diff --git a/src/templates/base.hbs b/src/templates/base.hbs
new file mode 100644
index 0000000..df3ba9d
--- /dev/null
+++ b/src/templates/base.hbs
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style>
+ :root {
+ --balboa: #195970;
+ }
+
+ body {
+ margin: 0;
+ padding: 0;
+ font-size: 1em;
+ }
+
+ .model::before {
+ content: "⤷";
+ }
+
+ .topbar {
+ background-color: var(--balboa);
+ box-shadow: 0 0 0.5em black;
+ position: relative;
+ height: 3em;
+ z-index: 2;
+ }
+
+ .topbar ul {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ }
+
+ .topbar li {
+ float: left;
+ display: block;
+ padding: 14px 14px;
+ }
+
+ .topbar li.right {
+ float: right;
+ }
+
+ .topbar li a {
+ color: white;
+ text-decoration: none;
+ }
+
+ .sidebar {
+ background-color: var(--balboa);
+ box-shadow: inset -0.5em 0 0.5em -0.5em black;
+ z-index: 1;
+ position: fixed;
+ top: 3em;
+ left: 0;
+ width: 20%;
+ height: 100%;
+ transition: 0.25s;
+ }
+
+ .sidebar form {
+ padding: 10px 10px;
+ }
+
+ .sidebar button {
+ font-size: 1em;
+ display: block;
+ background: none;
+ border: 0 none;
+ cursor: pointer;
+ color: white;
+ }
+
+ .model {
+ margin-left: 20px;
+ }
+
+ #hidden:target .sidebar {
+ left: -20%;
+ }
+
+ .menuToggle a.openMenu {
+ display: none;
+ }
+
+ #hidden:target .menuToggle a.closeMenu {
+ display: none;
+ }
+
+ #hidden:target .menuToggle a.openMenu {
+ display: block;
+ }
+
+ #hidden:target section {
+ margin-left: 0;
+ }
+
+ .catalogTable {
+ width: 100%;
+ border-collapse: collapse;
+ }
+
+ .catalogTable td,
+ .catalogTable th {
+ padding: 0.5em;
+ }
+
+ .catalogTable tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+
+ .catalogTable tr:hover {
+ background-color: #ddd;
+ }
+
+ .catalogTable th {
+ padding-top: 12px;
+ padding-bottom: 12px;
+ text-align: left;
+ background-color: var(--balboa);
+ color: white;
+ }
+
+ input[type="search"] {
+ width: 100%;
+ }
+
+ section {
+ /* TODO: need to make this not applicable to other templates that don't have sidebar */
+ margin-left: 20%;
+ transition: margin-left 0.25s;
+ padding-top: 2em;
+ padding-left: 2em;
+ padding-right: 2em;
+ }
+ </style>
+</head>
+
+<body id="hidden">
+ <nav class="topbar">
+ <ul>
+ {{~> navItem}}
+ <li><a href="/">Index</a></li>
+ <li><a href="#">Parts</a></li>
+ <li><a href="#">Cars</a></li>
+ <li><a href="#">Suggestions</a></li>
+ <li><a href="#">About</a></li>
+ <li class="right"><a href="/login">Login</a></li>
+ </ul>
+ </nav>
+
+ {{~> body}}
+</body>
+
+</html>
diff --git a/src/templates/index.hbs b/src/templates/index.hbs
new file mode 100644
index 0000000..6bd539b
--- /dev/null
+++ b/src/templates/index.hbs
@@ -0,0 +1,74 @@
+{{#> base}}
+{{#*inline "navItem"}}
+<li>
+ <div class="menuToggle">
+ <a class="openMenu" href="#"><span>
+ <svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
+ <path fill="currentColor" d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" />
+ </svg>
+ </span></a>
+ <a class="closeMenu" href="#hidden"><span>
+ <svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
+ <path fill="currentColor"
+ d="M21,15.61L19.59,17L14.58,12L19.59,7L21,8.39L17.44,12L21,15.61M3,6H16V8H3V6M3,13V11H13V13H3M3,18V16H16V18H3Z" />
+ </svg>
+ </span></a>
+ </div>
+</li>
+{{/inline}}
+{{#*inline "body"}}
+<nav class="sidebar">
+ {{#each makes}}
+ <form action="/">
+ {{#if (eq this ../selected_make)}}
+ <button disabled class="make">
+ {{ this }}
+ </button>
+ <input type="hidden" name="make" value="{{ ../selected_make }}" />
+ {{#each ../models}}
+ {{#if (eq this ../../selected_model)}}
+ <button disabled class="model">{{~ this ~}}</button>
+ {{else}}
+ <button class="model" name="model" value="{{ this }}">
+ {{~ this ~}}
+ </button>
+ {{/if}}
+ {{else}}
+ <button disabled class="model">(No models found)</button>
+ {{/each}}
+ {{else}}
+ <button class="make" name="make" value="{{ this }}">
+ {{~ this ~}}
+ </button>
+ {{/if}}
+ </form>
+ {{else}}
+ <button disabled class="make">(No makes found)</button>
+ {{/each}}
+</nav>
+
+<section>
+ <form>
+ {{#if selected_make}}
+ <input type="hidden" name="make" value="{{ selected_make }}" />
+ {{/if}}
+ {{#if selected_model}}
+ <input type="hidden" name="model" value="{{ selected_model }}" />
+ {{/if}}
+ <input autofocus type="search" name="search" placeholder="hit enter to search" />
+ </form>
+</section>
+
+<section>
+ <table class="catalogTable">
+ <tbody>
+ {{#each parts}}
+ <tr>
+ <td>{{ this }}</td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+</section>
+{{/inline}}
+{{/base}}
diff --git a/src/templates/index.html b/src/templates/index.html
deleted file mode 100644
index 4663f5d..0000000
--- a/src/templates/index.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8" />
-
- <style>
- .make {
- display: block;
- background: none;
- border: 0 none;
- cursor: pointer;
- }
-
- .model {
- display: block;
- background: none;
- border: 0 none;
- cursor: pointer;
- margin-left: 20px;
- }
-
- .sidebar {
- width: 300px;
- height: 100%;
- position: fixed;
- z-index: 1;
- }
-
- .main {
- margin-left: 300px;
- height: 100%;
- }
- </style>
- </head>
- <body>
- <div class="sidebar">
- <h1>Parts Catalog</h1>
- {{#each makes}}
- <form action="/parts">
- {{#if (eq this ../selected_make)}}
- <button disabled class="make">
- {{ this }}
- </button>
- <input type="hidden" name="make" value="{{ ../selected_make }}" />
- {{#each ../models}}
- {{#if (eq this ../../selected_model)}}
- <button disabled class="model">{{ this }}</button>
- {{else}}
- <button class="model" name="model" value="{{ this }}">
- {{ this }}
- </button>
- {{/if}}
- {{else}}
- <button disabled class="model">(No models found)</button>
- {{/each}}
- {{else}}
- <button class="make" name="make" value="{{ this }}">{{ this }}</button>
- {{/if}}
- </form>
- {{else}}
- No makes found.
- {{/each}}
- </div>
-
- <div class="main">
- <form action="/parts">
- <input type="hidden" name="make" value="{{ selected_make }}" />
- <input type="hidden" name="model" value="{{ selected_model }}" />
- <input
- type="search"
- name="search"
- placeholder="Part #, Name, Source, etc."
- />
- <button>Search</button>
- </form>
- <table>
- {{#each parts}}
- <tr>
- <td>{{ this }}</td>
- </tr>
- {{/each}}
- </table>
- </div>
- </body>
-</html>
diff --git a/src/templates/login.hbs b/src/templates/login.hbs
new file mode 100644
index 0000000..84b354b
--- /dev/null
+++ b/src/templates/login.hbs
@@ -0,0 +1,7 @@
+{{#> base}}
+{{#*inline "body"}}
+<body>
+ <a href="/login/google">Login with Google</a>
+</body>
+{{/inline}}
+{{/base}}
diff --git a/src/templates/login.html b/src/templates/login.html
deleted file mode 100644
index 9329a22..0000000
--- a/src/templates/login.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<html>
- <body>
- <a href="/login/google">Login with Google</a>
- </body>
-</html>
diff --git a/src/templates/mod.rs b/src/templates/mod.rs
index 3a6eb2b..534ada0 100644
--- a/src/templates/mod.rs
+++ b/src/templates/mod.rs
@@ -1,9 +1,16 @@
-pub static INDEX_T: &str = include_str!("index.html");
-pub static LOGIN_T: &str = include_str!("login.html");
-pub const CATALOG_L: &str = "/#menu";
-pub const PARTS_L: &str = "/parts";
-pub const PARTS_CSV_L: &str = "/parts.csv";
-pub const CARS_L: &str = "/cars";
-pub const CARS_CSV_L: &str = "/cars.csv";
-pub const SUGGESTIONS_L: &str = "/suggestions";
-pub const LOGIN_L: &str = "/login";
+use handlebars::Handlebars;
+use once_cell::sync::Lazy;
+
+pub static REGISTRY: Lazy<Handlebars> = Lazy::new(|| {
+ let mut handlebars = Handlebars::new();
+ handlebars
+ .register_template_string("index", include_str!("index.hbs"))
+ .unwrap();
+ handlebars
+ .register_template_string("login", include_str!("login.hbs"))
+ .unwrap();
+ handlebars
+ .register_template_string("base", include_str!("base.hbs"))
+ .unwrap();
+ handlebars
+});
diff --git a/src/templates/suggestions.hbs b/src/templates/suggestions.hbs
new file mode 100644
index 0000000..f979be7
--- /dev/null
+++ b/src/templates/suggestions.hbs
@@ -0,0 +1,9 @@
+{{#> base}}
+{{#*inline "body"}}
+<section>
+ <form>
+ <!-- input for new car or part -->
+ </form>
+</section>
+{{/inline}}
+{{/base}}