mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
So many visual improvements
This commit is contained in:
parent
b4f04a2b04
commit
5a99620a0f
@ -19,15 +19,8 @@
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" name="viewport"
|
||||
content="width=device-width, initial-scale=1.0" charset="UTF-8">
|
||||
<style>
|
||||
@media print {
|
||||
|
||||
.no-print,
|
||||
.no-print * {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link data-trunk rel="inline" type="css" href="static/bootstrap.3.4.1.min.css">
|
||||
<link data-trunk rel="inline" type="css" , href="static/app.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -37,31 +37,47 @@ fn recipe_selection(props: RecipeCheckBoxProps) -> View<G> {
|
||||
let id_cloned_2 = id_as_str.clone();
|
||||
let count = Signal::new(format!("{}", app_service.get_recipe_count_by_index(i)));
|
||||
view! {
|
||||
input(type="number", min="0", bind:value=count.clone(), name=format!("recipe_id:{}", i), value=id_as_str.clone(), on:change=move |_| {
|
||||
div(class="form-group col-md-1") {
|
||||
input(type="number", class="item-count-sel", min="0", bind:value=count.clone(), name=format!("recipe_id:{}", i), value=id_as_str.clone(), on:change=move |_| {
|
||||
let mut app_service = app_service.clone();
|
||||
console_log!("setting recipe id: {} to count: {}", i, *count.get());
|
||||
app_service.set_recipe_count_by_index(i, count.get().parse().unwrap());
|
||||
})
|
||||
label(for=id_cloned_2) { (props.title.get()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[component(RecipeSelector<G>)]
|
||||
pub fn recipe_selector() -> View<G> {
|
||||
let app_service = use_context::<AppService>();
|
||||
let titles = create_memo(cloned!(app_service => move || {
|
||||
app_service.get_recipes().get().iter().map(|(i, r)| (*i, r.clone())).collect::<Vec<(usize, Signal<recipes::Recipe>)>>()
|
||||
let length = app_service.get_recipes().get().len();
|
||||
let partition = length/2;
|
||||
let col1 = app_service.get_recipes().get().iter().take(partition).map(|(i, r)| (*i, r.clone())).collect::<Vec<(usize, Signal<recipes::Recipe>)>>();
|
||||
let col2 = app_service.get_recipes().get().iter().skip(partition).map(|(i, r)| (*i, r.clone())).collect::<Vec<(usize, Signal<recipes::Recipe>)>>();
|
||||
(col1, col2)
|
||||
}));
|
||||
let col1 = create_memo(cloned!((titles) => move || titles.get().0.clone()));
|
||||
let col2 = create_memo(cloned!((titles) => move || titles.get().1.clone()));
|
||||
view! {
|
||||
fieldset(class="recipe_selector", class="no-print") {
|
||||
Indexed(IndexedProps{
|
||||
iterable: titles,
|
||||
fieldset(class="recipe_selector no-print container no-left-mgn") {
|
||||
div(class="row") {Indexed(IndexedProps{
|
||||
iterable: col1,
|
||||
template: |(i, recipe)| {
|
||||
view! {
|
||||
RecipeSelection(RecipeCheckBoxProps{i: i, title: create_memo(move || recipe.get().title.clone())})
|
||||
}
|
||||
},
|
||||
})
|
||||
})}
|
||||
div(class="row") {Indexed(IndexedProps{
|
||||
iterable: col2,
|
||||
template: |(i, recipe)| {
|
||||
view! {
|
||||
RecipeSelection(RecipeCheckBoxProps{i: i, title: create_memo(move || recipe.get().title.clone())})
|
||||
}
|
||||
},
|
||||
})}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,22 +98,18 @@ fn shopping_list() -> View<G> {
|
||||
.filter(|(k, _v)| !filtered_keys.get().contains(k))
|
||||
.collect::<Vec<(IngredientKey, Ingredient)>>()
|
||||
}));
|
||||
// TODO(jwall): Sort by categories and names.
|
||||
view! {
|
||||
h1 { "Shopping List" }
|
||||
input(type="button", value="Reset List", class="no-print", on:click=cloned!((ingredients_map, filtered_keys, app_service) => move |_| {
|
||||
// trigger the shopping list generation
|
||||
ingredients_map.set(app_service.get_shopping_list());
|
||||
// clear the filter_signal
|
||||
filtered_keys.set(HashSet::new());
|
||||
}))
|
||||
table(class="shopping_list", style="page-break-after: always;") {
|
||||
let table_view = Signal::new(View::empty());
|
||||
create_effect(
|
||||
cloned!((table_view, ingredients, filtered_keys) => move || {
|
||||
if ingredients.get().len() > 0 {
|
||||
let t = view ! {
|
||||
table(class="shopping-list page-breaker table table-striped table-condensed table-responsive") {
|
||||
tr {
|
||||
th { "Quantity" }
|
||||
th { "Ingredient" }
|
||||
th { " Quantity " }
|
||||
th { " Ingredient " }
|
||||
}
|
||||
Indexed(IndexedProps{
|
||||
iterable: ingredients,
|
||||
tbody {Indexed(IndexedProps{
|
||||
iterable: ingredients.clone(),
|
||||
template: cloned!((filtered_keys) => move |(k, i)| {
|
||||
let amt = Signal::new(format!("{}", i.amt.normalize()));
|
||||
// TODO(jwall): Create effect to reset this amount if it diverges.
|
||||
@ -105,7 +117,7 @@ fn shopping_list() -> View<G> {
|
||||
let form = i.form.map(|form| format!("({})", form)).unwrap_or_default();
|
||||
view! {
|
||||
tr {
|
||||
td { input(bind:value=amt.clone(), type="text") }
|
||||
td { input(bind:value=amt.clone(), class="ingredient-count-sel", type="text") }
|
||||
td {input(type="button", class="no-print", value="X", on:click=cloned!((filtered_keys) => move |_| {
|
||||
let mut keyset = (*filtered_keys.get()).clone();
|
||||
keyset.insert(k.clone());
|
||||
@ -114,8 +126,25 @@ fn shopping_list() -> View<G> {
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
})}
|
||||
}
|
||||
};
|
||||
table_view.set(t);
|
||||
} else {
|
||||
table_view.set(View::empty());
|
||||
}
|
||||
}),
|
||||
);
|
||||
// TODO(jwall): Sort by categories and names.
|
||||
view! {
|
||||
h1 { "Shopping List " input(type="button", value="Reset", class="no-print", on:click=cloned!((ingredients_map, filtered_keys, app_service) => move |_| {
|
||||
// trigger the shopping list generation
|
||||
ingredients_map.set(app_service.get_shopping_list());
|
||||
// clear the filter_signal
|
||||
filtered_keys.set(HashSet::new());
|
||||
}))}
|
||||
|
||||
(table_view.get().as_ref().clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
49
web/static/app.css
Normal file
49
web/static/app.css
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright 2022 Jeremy Wall
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@media print {
|
||||
.no-print,
|
||||
.no-print * {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.page-breaker {
|
||||
page-break-after: always;
|
||||
}
|
||||
}
|
||||
|
||||
.item-count-sel {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.ingredient-count-sel {
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.no-left-mgn {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.shopping-list {
|
||||
width:max-content;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding-bottom: 1ch;
|
||||
}
|
||||
|
||||
body{
|
||||
padding-left: 1ch;
|
||||
}
|
6
web/static/bootstrap.3.4.1.min.css
vendored
Normal file
6
web/static/bootstrap.3.4.1.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user