From a81016222153a7e0602c09bc239183e0777f17f9 Mon Sep 17 00:00:00 2001 From: Florian Heinz Date: Mon, 13 Apr 2026 17:55:21 +0200 Subject: [PATCH] Polish item builders with icon-based selector cards --- nouri/static/css/styles.css | 229 ++++++++++++++++++++ nouri/static/icons/meal-styles/cold.svg | 1 + nouri/static/icons/meal-styles/portable.svg | 1 + nouri/static/icons/meal-styles/prep.svg | 1 + nouri/static/icons/meal-styles/quick.svg | 1 + nouri/static/icons/meal-styles/savory.svg | 1 + nouri/static/icons/meal-styles/simple.svg | 1 + nouri/static/icons/meal-styles/sweet.svg | 1 + nouri/static/icons/meal-styles/warm.svg | 1 + nouri/templates/items/form.html | 160 +++++++++++--- 10 files changed, 367 insertions(+), 30 deletions(-) create mode 100644 nouri/static/icons/meal-styles/cold.svg create mode 100644 nouri/static/icons/meal-styles/portable.svg create mode 100644 nouri/static/icons/meal-styles/prep.svg create mode 100644 nouri/static/icons/meal-styles/quick.svg create mode 100644 nouri/static/icons/meal-styles/savory.svg create mode 100644 nouri/static/icons/meal-styles/simple.svg create mode 100644 nouri/static/icons/meal-styles/sweet.svg create mode 100644 nouri/static/icons/meal-styles/warm.svg diff --git a/nouri/static/css/styles.css b/nouri/static/css/styles.css index 88307ce..2dfabd3 100644 --- a/nouri/static/css/styles.css +++ b/nouri/static/css/styles.css @@ -848,6 +848,195 @@ legend { display: none; } +.daypart-option-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 0.8rem; +} + +.daypart-option { + position: relative; + display: block; +} + +.daypart-option input { + position: absolute; + opacity: 0; + pointer-events: none; +} + +.daypart-option-card { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.7rem; + min-height: 118px; + padding: 1rem 0.9rem; + border-radius: 22px; + border: 1px solid var(--line); + background: color-mix(in srgb, var(--surface-strong) 84%, #fff 16%); + color: var(--muted); + transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease; + cursor: pointer; +} + +.daypart-option-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.8rem; + height: 2.8rem; + border-radius: 16px; + background: color-mix(in srgb, var(--surface) 78%, #fff 22%); + border: 1px solid color-mix(in srgb, var(--line) 76%, transparent 24%); +} + +.daypart-option-icon .ui-icon { + width: 1.2rem; + height: 1.2rem; +} + +.daypart-option-label { + font-weight: 600; + text-align: center; + line-height: 1.25; +} + +.daypart-option:hover .daypart-option-card { + border-color: var(--accent-soft); + color: var(--text); + transform: translateY(-1px); +} + +.daypart-option input:focus-visible + .daypart-option-card { + outline: 2px solid color-mix(in srgb, var(--accent) 45%, transparent 55%); + outline-offset: 3px; +} + +.daypart-option input:checked + .daypart-option-card { + border-color: color-mix(in srgb, var(--accent) 55%, var(--line) 45%); + background: color-mix(in srgb, var(--accent-soft) 18%, var(--surface-strong) 82%); + box-shadow: 0 12px 30px color-mix(in srgb, var(--accent) 14%, transparent 86%); + color: var(--text); +} + +.daypart-option input:checked + .daypart-option-card .daypart-option-icon { + background: color-mix(in srgb, var(--accent) 16%, var(--surface) 84%); + border-color: color-mix(in srgb, var(--accent) 38%, var(--line) 62%); +} + +.meal-style-option-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 0.8rem; +} + +.meal-style-option { + position: relative; + display: block; +} + +.meal-style-option input { + position: absolute; + opacity: 0; + pointer-events: none; +} + +.meal-style-option-card { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.7rem; + min-height: 110px; + padding: 0.95rem 0.85rem; + border-radius: 22px; + border: 1px solid var(--line); + background: color-mix(in srgb, var(--surface-strong) 84%, #fff 16%); + color: var(--muted); + transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease; + cursor: pointer; +} + +.meal-style-option-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2.8rem; + height: 2.8rem; + border-radius: 16px; + background: color-mix(in srgb, var(--surface) 78%, #fff 22%); + border: 1px solid color-mix(in srgb, var(--line) 76%, transparent 24%); +} + +.meal-style-option-icon .ui-icon { + width: 1.15rem; + height: 1.15rem; +} + +.meal-style-option-label { + font-weight: 600; + text-align: center; + line-height: 1.25; +} + +.meal-style-option:hover .meal-style-option-card { + border-color: var(--accent-soft); + color: var(--text); + transform: translateY(-1px); +} + +.meal-style-option input:focus-visible + .meal-style-option-card { + outline: 2px solid color-mix(in srgb, var(--accent) 45%, transparent 55%); + outline-offset: 3px; +} + +.meal-style-option input:checked + .meal-style-option-card { + border-color: color-mix(in srgb, var(--accent) 55%, var(--line) 45%); + background: color-mix(in srgb, var(--accent-soft) 18%, var(--surface-strong) 82%); + box-shadow: 0 12px 30px color-mix(in srgb, var(--accent) 14%, transparent 86%); + color: var(--text); +} + +.meal-style-option input:checked + .meal-style-option-card .meal-style-option-icon { + background: color-mix(in srgb, var(--accent) 16%, var(--surface) 84%); + border-color: color-mix(in srgb, var(--accent) 38%, var(--line) 62%); +} + +[data-theme="dark"] .daypart-option-card, +[data-theme="dark"] .meal-style-option-card { + background: + linear-gradient( + 180deg, + color-mix(in srgb, var(--surface-soft) 72%, #4a403c 28%), + color-mix(in srgb, var(--surface-strong) 86%, #241f1d 14%) + ); + border-color: color-mix(in srgb, var(--line) 54%, rgba(243, 177, 125, 0.18) 46%); + color: color-mix(in srgb, var(--muted) 92%, white 8%); + box-shadow: inset 0 1px 0 rgba(255, 233, 217, 0.03); +} + +[data-theme="dark"] .daypart-option-icon, +[data-theme="dark"] .meal-style-option-icon { + background: + linear-gradient( + 180deg, + color-mix(in srgb, var(--surface-soft) 82%, #544743 18%), + color-mix(in srgb, var(--surface) 88%, #2a2321 12%) + ); + border-color: color-mix(in srgb, var(--line) 52%, rgba(243, 177, 125, 0.22) 48%); +} + +[data-theme="dark"] .daypart-option:hover .daypart-option-card, +[data-theme="dark"] .meal-style-option:hover .meal-style-option-card { + background: + linear-gradient( + 180deg, + color-mix(in srgb, var(--surface-soft) 66%, #554945 34%), + color-mix(in srgb, var(--surface-strong) 82%, #2b2523 18%) + ); + border-color: color-mix(in srgb, var(--accent) 28%, var(--line) 72%); +} + .quick-select-card { display: flex; align-items: flex-start; @@ -1881,6 +2070,46 @@ legend { mask-image: url("../icons/dayparts/late-snack.svg"); } +.icon-meal-style-sweet { + -webkit-mask-image: url("../icons/meal-styles/sweet.svg"); + mask-image: url("../icons/meal-styles/sweet.svg"); +} + +.icon-meal-style-savory { + -webkit-mask-image: url("../icons/meal-styles/savory.svg"); + mask-image: url("../icons/meal-styles/savory.svg"); +} + +.icon-meal-style-warm { + -webkit-mask-image: url("../icons/meal-styles/warm.svg"); + mask-image: url("../icons/meal-styles/warm.svg"); +} + +.icon-meal-style-cold { + -webkit-mask-image: url("../icons/meal-styles/cold.svg"); + mask-image: url("../icons/meal-styles/cold.svg"); +} + +.icon-meal-style-quick { + -webkit-mask-image: url("../icons/meal-styles/quick.svg"); + mask-image: url("../icons/meal-styles/quick.svg"); +} + +.icon-meal-style-simple { + -webkit-mask-image: url("../icons/meal-styles/simple.svg"); + mask-image: url("../icons/meal-styles/simple.svg"); +} + +.icon-meal-style-prep { + -webkit-mask-image: url("../icons/meal-styles/prep.svg"); + mask-image: url("../icons/meal-styles/prep.svg"); +} + +.icon-meal-style-portable { + -webkit-mask-image: url("../icons/meal-styles/portable.svg"); + mask-image: url("../icons/meal-styles/portable.svg"); +} + .icon-archive { -webkit-mask-image: url("../icons/fa/archive.svg"); mask-image: url("../icons/fa/archive.svg"); diff --git a/nouri/static/icons/meal-styles/cold.svg b/nouri/static/icons/meal-styles/cold.svg new file mode 100644 index 0000000..5192002 --- /dev/null +++ b/nouri/static/icons/meal-styles/cold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/portable.svg b/nouri/static/icons/meal-styles/portable.svg new file mode 100644 index 0000000..ec87741 --- /dev/null +++ b/nouri/static/icons/meal-styles/portable.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/prep.svg b/nouri/static/icons/meal-styles/prep.svg new file mode 100644 index 0000000..1a785d0 --- /dev/null +++ b/nouri/static/icons/meal-styles/prep.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/quick.svg b/nouri/static/icons/meal-styles/quick.svg new file mode 100644 index 0000000..132050e --- /dev/null +++ b/nouri/static/icons/meal-styles/quick.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/savory.svg b/nouri/static/icons/meal-styles/savory.svg new file mode 100644 index 0000000..df788de --- /dev/null +++ b/nouri/static/icons/meal-styles/savory.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/simple.svg b/nouri/static/icons/meal-styles/simple.svg new file mode 100644 index 0000000..396b7b4 --- /dev/null +++ b/nouri/static/icons/meal-styles/simple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/sweet.svg b/nouri/static/icons/meal-styles/sweet.svg new file mode 100644 index 0000000..cba32cb --- /dev/null +++ b/nouri/static/icons/meal-styles/sweet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/static/icons/meal-styles/warm.svg b/nouri/static/icons/meal-styles/warm.svg new file mode 100644 index 0000000..c6b670a --- /dev/null +++ b/nouri/static/icons/meal-styles/warm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nouri/templates/items/form.html b/nouri/templates/items/form.html index 83be4f3..9c80346 100644 --- a/nouri/templates/items/form.html +++ b/nouri/templates/items/form.html @@ -5,7 +5,13 @@

{{ item_kind_labels[kind] }}

{% if item %}{{ item.name }} bearbeiten{% else %}Neue{% endif %} {{ item_kind_singular_labels[kind] }}

-

Nur das Nötigste: Name, Sichtbarkeit, für wen etwas gedacht ist, Bild, Tageszeiten und eine kleine Notiz.

+

+ {% if kind == 'food' %} + Name, Sichtbarkeit und ein paar ruhige Hinweise dazu, wie ein Lebensmittel in Vorschlägen gut passt. + {% else %} + Name, Sichtbarkeit, Tageszeit und ein kurzer Charakter der Idee. So bleiben Mahlzeitenideen alltagsnah und leicht pflegbar. + {% endif %} +

{% if item %}
@@ -45,25 +51,95 @@
- + {% if kind == 'food' %} + - +
+ + + +
+ + + Praktisch für Dinge wie Tofu, Joghurt oder Müsli. Extras wie Proteinpulver, Tomatenmark oder Saaten bleiben so eher Ergänzungen. + {% else %} +
+ + + +
+ +
+ Charakter der Mahlzeit +
+ {% for value, label in meal_style_options %} + + {% endfor %} +
+ Nur das auswählen, was wirklich hilft. Alles andere kann leer bleiben. +
+ {% endif %} + + {% if kind == 'food' %} + + {% endif %}