add index page with a cards list

session-crate
Ondřej Hruška 5 years ago
parent 8e5185f643
commit ed65215723
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 76
      src/main.rs
  2. 2
      src/store/form.rs
  3. 33
      templates/_fields.html.tera
  4. 0
      templates/_form_macros.html.tera
  5. 7
      templates/_layout.html.tera
  6. 22
      templates/add.html.tera
  7. 75
      templates/index.html.tera
  8. 43
      templates/static/style.css

@ -3,7 +3,7 @@
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[macro_use] extern crate serde; #[macro_use] extern crate serde;
use serde_json::json; use serde_json::{json, Value};
//use rocket::request::FromSegments; //use rocket::request::FromSegments;
//use rocket::http::uri::Segments; //use rocket::http::uri::Segments;
@ -21,37 +21,72 @@ use std::collections::HashMap;
use std::env; use std::env;
use crate::store::form::RenderedField; use crate::store::form::RenderedField;
#[derive(Serialize)] fn render_empty_fields<'a>(store : &'a Store) -> Vec<RenderedField<'a>> {
struct FormContext<'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 fields : Vec<RenderedField<'a>>,
pub cards : Vec<RenderedCard<'a>>,
} }
#[get("/")] #[get("/")]
fn index(store : State<RwLock<Store>>) -> Template { fn index(store : State<RwLock<Store>>) -> Template {
let rg = store.read();
let tags = json!(["foo", "bar"]); let rg = store.read();
let indexes = &rg.index; let context = ListContext {
let context = FormContext { fields: render_empty_fields(&rg),
fields: rg.model.fields.iter().map(|(key, field)| { cards: rg.items.iter().filter_map(|(id, card)| {
let value = if key == "tags" { if let Value::Object(map) = card {
Some(&tags) Some(RenderedCard {
fields: render_card_fields(&rg, map),
id: *id,
})
} else { } else {
None None
}; }
RenderedField::from_template_field(key, field, value, indexes) }).collect(),
}).collect()
}; };
Template::render("index", context) Template::render("index", context)
} }
//#[post("/add", data="<record>")] #[derive(Serialize)]
//fn add_part(store : State<RwLock<Store>>, record : Form<store::Part>) -> Redirect { struct AddCardContext<'a> {
// store.write().add(record.into_inner()); pub fields : Vec<RenderedField<'a>>,
// Redirect::to(uri!(index)) }
//}
#[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() { fn main() {
let cwd = env::current_dir().unwrap(); let cwd = env::current_dir().unwrap();
@ -62,5 +97,8 @@ fn main() {
.attach(Template::fairing()) .attach(Template::fairing())
.manage(RwLock::new(store)) .manage(RwLock::new(store))
.mount("/", StaticFiles::from(cwd.join("templates/static/"))) .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 { if let Some(Value::String(s)) = value {
rendered.value = Cow::Borrowed(&s.as_str()); rendered.value = Cow::Borrowed(&s.as_str());
} else if let Some(def) = default {
rendered.value = def.to_owned().into();
} }
} }
FieldKind::FreeEnum { enum_group } => { 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"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% block title %}{% endblock title %}</title> <title>{% block title %}{% endblock title %} &bull; Inventory</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="taggle.css"> <link rel="stylesheet" href="taggle.css">
<script src="taggle.min.js"></script> <script src="taggle.min.js"></script>
</head> </head>
<body> <body>
{% block content %}{% endblock content %} <nav class="top-nav">
{% block nav %}{% endblock %}
</nav>
{% block content %}{% endblock %}
</body> </body>
</html> </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 %}

@ -1,50 +1,41 @@
{% extends "layout" %} {% extends "_layout" %}
{% import "form_macros" as form %} {% import "_form_macros" as form %}
{% block title -%} {% block title -%}
Form Inventory
{%- endblock title %} {%- endblock %}
{% block nav -%}
<a href="/add">Add</a>
{%- endblock %}
{% block content -%} {% block content -%}
<form action="/add" method="POST" class="Form"> <table class="cards-table">
<div class="Row indented"> <thead>
<h1>New Record</h1> <tr>
</div>
{%- for field in fields %} {%- for field in fields %}
<!-- {{ field.key }} --> <th>{{ field.label }}</th>
<div class="Row"> {%- endfor %}
{%- if field.kind == "string" -%} </tr>
{{ form::text(field=field) }} </thead>
<tbody>
{%- elif field.kind == "text" -%} {%- for card in cards %}
{{ form::longtext(field=field) }} <tr>
{%- for field in card.fields %}
{%- elif field.kind == "number" -%} <td>
{{ form::number(field=field) }} {%- if field.kind == "bool" -%}
{% if field.checked %}
{%- elif field.kind == "bool" -%}
{{ form::checkbox(field=field) }} {% else %}
{%- elif field.kind == "select" -%} {% endif %}
{{ 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 -%} {%- else -%}
{{ field.key }} {{ field.value }}
{%- endif -%} {%- endif -%}
</div> </td>
{%- endfor %} {%- endfor %}
<div class="Row indented"> </tr>
<button type="submit">Add</button> {% endfor %}
</div> </tbody>
</form> </table>
{%- endblock content %} {%- endblock %}

@ -12,6 +12,26 @@ html, textarea, select {
margin: 0 auto; 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 { .Form .Row {
display: flex; display: flex;
padding: .25rem; padding: .25rem;
@ -85,3 +105,26 @@ textarea:focus,
box-shadow: none; box-shadow: none;
outline: 0 none !important; 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;
}

Loading…
Cancel
Save