add index page with a cards list
This commit is contained in:
+57
-19
@@ -3,7 +3,7 @@
|
||||
#[macro_use] extern crate rocket;
|
||||
#[macro_use] extern crate serde;
|
||||
|
||||
use serde_json::json;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
//use rocket::request::FromSegments;
|
||||
//use rocket::http::uri::Segments;
|
||||
@@ -21,37 +21,72 @@ use std::collections::HashMap;
|
||||
use std::env;
|
||||
use crate::store::form::RenderedField;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct FormContext<'a> {
|
||||
fn render_empty_fields<'a>(store : &'a Store) -> Vec<RenderedField<'a>> {
|
||||
let indexes = &store.index;
|
||||
|
||||
store.model.fields.iter().map(|(key, field)| {
|
||||
RenderedField::from_template_field(key, field, None, indexes)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
#[derive(Serialize,Debug)]
|
||||
struct RenderedCard<'a> {
|
||||
pub fields : Vec<RenderedField<'a>>,
|
||||
pub id : usize,
|
||||
}
|
||||
|
||||
fn render_card_fields<'a>(store : &'a Store, values : &'a serde_json::Map<String, Value>) -> Vec<RenderedField<'a>> {
|
||||
let indexes = &store.index;
|
||||
|
||||
store.model.fields.iter().map(|(key, field)| {
|
||||
RenderedField::from_template_field(key, field, values.get(key), indexes)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
#[derive(Serialize,Debug)]
|
||||
struct ListContext<'a> {
|
||||
pub fields : Vec<RenderedField<'a>>,
|
||||
pub cards : Vec<RenderedCard<'a>>,
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
fn index(store : State<RwLock<Store>>) -> Template {
|
||||
|
||||
let rg = store.read();
|
||||
|
||||
let tags = json!(["foo", "bar"]);
|
||||
|
||||
let indexes = &rg.index;
|
||||
let context = FormContext {
|
||||
fields: rg.model.fields.iter().map(|(key, field)| {
|
||||
let value = if key == "tags" {
|
||||
Some(&tags)
|
||||
let context = ListContext {
|
||||
fields: render_empty_fields(&rg),
|
||||
cards: rg.items.iter().filter_map(|(id, card)| {
|
||||
if let Value::Object(map) = card {
|
||||
Some(RenderedCard {
|
||||
fields: render_card_fields(&rg, map),
|
||||
id: *id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
RenderedField::from_template_field(key, field, value, indexes)
|
||||
}).collect()
|
||||
}
|
||||
}).collect(),
|
||||
};
|
||||
|
||||
Template::render("index", context)
|
||||
}
|
||||
|
||||
//#[post("/add", data="<record>")]
|
||||
//fn add_part(store : State<RwLock<Store>>, record : Form<store::Part>) -> Redirect {
|
||||
// store.write().add(record.into_inner());
|
||||
// Redirect::to(uri!(index))
|
||||
//}
|
||||
#[derive(Serialize)]
|
||||
struct AddCardContext<'a> {
|
||||
pub fields : Vec<RenderedField<'a>>,
|
||||
}
|
||||
|
||||
#[get("/add")]
|
||||
fn add(store : State<RwLock<Store>>) -> Template {
|
||||
|
||||
let rg = store.read();
|
||||
|
||||
let context = AddCardContext {
|
||||
fields: render_empty_fields(&rg)
|
||||
};
|
||||
|
||||
Template::render("add", context)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cwd = env::current_dir().unwrap();
|
||||
@@ -62,5 +97,8 @@ fn main() {
|
||||
.attach(Template::fairing())
|
||||
.manage(RwLock::new(store))
|
||||
.mount("/", StaticFiles::from(cwd.join("templates/static/")))
|
||||
.mount("/", routes![index]).launch();
|
||||
.mount("/", routes![
|
||||
index,
|
||||
add,
|
||||
]).launch();
|
||||
}
|
||||
|
||||
@@ -102,6 +102,8 @@ impl<'a> RenderedField<'a> {
|
||||
|
||||
if let Some(Value::String(s)) = value {
|
||||
rendered.value = Cow::Borrowed(&s.as_str());
|
||||
} else if let Some(def) = default {
|
||||
rendered.value = def.to_owned().into();
|
||||
}
|
||||
}
|
||||
FieldKind::FreeEnum { enum_group } => {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{%- for field in fields %}
|
||||
<!-- {{ field.key }} -->
|
||||
<div class="Row">
|
||||
{%- if field.kind == "string" -%}
|
||||
{{ form::text(field=field) }}
|
||||
|
||||
{%- elif field.kind == "text" -%}
|
||||
{{ form::longtext(field=field) }}
|
||||
|
||||
{%- elif field.kind == "number" -%}
|
||||
{{ form::number(field=field) }}
|
||||
|
||||
{%- elif field.kind == "bool" -%}
|
||||
{{ form::checkbox(field=field) }}
|
||||
|
||||
{%- elif field.kind == "select" -%}
|
||||
{{ form::select(field=field) }}
|
||||
|
||||
{%- elif field.kind == "free_select" -%}
|
||||
{{ form::free_select(field=field) }}
|
||||
|
||||
{%- elif field.kind == "tags" -%}
|
||||
{{ form::tags(field=field) }}
|
||||
|
||||
{%- elif field.kind == "free_tags" -%}
|
||||
{{ form::free_tags(field=field) }}
|
||||
|
||||
{%- else -%}
|
||||
TODO {{ field.key }}
|
||||
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endfor %}
|
||||
@@ -2,12 +2,15 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock title %}</title>
|
||||
<title>{% block title %}{% endblock title %} • Inventory</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="taggle.css">
|
||||
<script src="taggle.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}{% endblock content %}
|
||||
<nav class="top-nav">
|
||||
{% block nav %}{% endblock %}
|
||||
</nav>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
{% extends "_layout" %}
|
||||
{% import "_form_macros" as form %}
|
||||
|
||||
{% block title -%}
|
||||
Add Record
|
||||
{%- endblock %}
|
||||
|
||||
{% block nav -%}
|
||||
<a href="/">Index</a>
|
||||
{%- endblock %}
|
||||
|
||||
{% block content -%}
|
||||
<form action="/add" method="POST" class="Form">
|
||||
<div class="Row indented">
|
||||
<h1>New Record</h1>
|
||||
</div>
|
||||
{% include "_fields" %}
|
||||
<div class="Row indented">
|
||||
<button type="submit">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
{%- endblock %}
|
||||
+37
-46
@@ -1,50 +1,41 @@
|
||||
{% extends "layout" %}
|
||||
{% import "form_macros" as form %}
|
||||
{% extends "_layout" %}
|
||||
{% import "_form_macros" as form %}
|
||||
|
||||
{% block title -%}
|
||||
Form
|
||||
{%- endblock title %}
|
||||
Inventory
|
||||
{%- endblock %}
|
||||
|
||||
{% block nav -%}
|
||||
<a href="/add">Add</a>
|
||||
{%- endblock %}
|
||||
|
||||
{% block content -%}
|
||||
<form action="/add" method="POST" class="Form">
|
||||
<div class="Row indented">
|
||||
<h1>New Record</h1>
|
||||
</div>
|
||||
{%- for field in fields %}
|
||||
<!-- {{ field.key }} -->
|
||||
<div class="Row">
|
||||
{%- if field.kind == "string" -%}
|
||||
{{ form::text(field=field) }}
|
||||
|
||||
{%- elif field.kind == "text" -%}
|
||||
{{ form::longtext(field=field) }}
|
||||
|
||||
{%- elif field.kind == "number" -%}
|
||||
{{ form::number(field=field) }}
|
||||
|
||||
{%- elif field.kind == "bool" -%}
|
||||
{{ form::checkbox(field=field) }}
|
||||
|
||||
{%- elif field.kind == "select" -%}
|
||||
{{ form::select(field=field) }}
|
||||
|
||||
{%- elif field.kind == "free_select" -%}
|
||||
{{ form::free_select(field=field) }}
|
||||
|
||||
{%- elif field.kind == "tags" -%}
|
||||
{{ form::tags(field=field) }}
|
||||
|
||||
{%- elif field.kind == "free_tags" -%}
|
||||
{{ form::free_tags(field=field) }}
|
||||
|
||||
{%- else -%}
|
||||
{{ field.key }}
|
||||
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{%- endfor %}
|
||||
<div class="Row indented">
|
||||
<button type="submit">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
{%- endblock content %}
|
||||
<table class="cards-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{%- for field in fields %}
|
||||
<th>{{ field.label }}</th>
|
||||
{%- endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%- for card in cards %}
|
||||
<tr>
|
||||
{%- for field in card.fields %}
|
||||
<td>
|
||||
{%- if field.kind == "bool" -%}
|
||||
{% if field.checked %}
|
||||
✔
|
||||
{% else %}
|
||||
✘
|
||||
{% endif %}
|
||||
{%- else -%}
|
||||
{{ field.value }}
|
||||
{%- endif -%}
|
||||
</td>
|
||||
{%- endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{%- endblock %}
|
||||
|
||||
@@ -12,6 +12,26 @@ html, textarea, select {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
nav.top-nav {
|
||||
margin: 0 auto;
|
||||
margin-bottom: .5rem;
|
||||
width: 900px;
|
||||
border-bottom: 1px solid silver;
|
||||
}
|
||||
|
||||
nav.top-nav a {
|
||||
display: inline-block;
|
||||
padding: .75rem;
|
||||
|
||||
color: gray;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
nav.top-nav a:hover {
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.Form .Row {
|
||||
display: flex;
|
||||
padding: .25rem;
|
||||
@@ -85,3 +105,26 @@ textarea:focus,
|
||||
box-shadow: none;
|
||||
outline: 0 none !important;
|
||||
}
|
||||
|
||||
.cards-table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 auto;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.cards-table td,
|
||||
.cards-table th {
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
.cards-table thead th {
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
|
||||
.cards-table tbody td {
|
||||
border-bottom: 1px solid silver;
|
||||
}
|
||||
|
||||
.cards-table tbody tr:last-child td {
|
||||
border-bottom: 2px solid silver;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user