second commit

This commit is contained in:
2026-04-11 19:13:40 +02:00
parent 58bcc8f0f3
commit 87f7859017
25 changed files with 488 additions and 87 deletions
+182 -3
View File
@@ -19,6 +19,9 @@
--radius-sm: 14px;
--panel-blur: 28px;
--font-ui: "SF Pro Display", "Avenir Next", "Segoe UI Variable", "Helvetica Neue", system-ui, sans-serif;
--track-accent: rgba(139, 228, 255, 0.34);
--track-surface: rgba(255, 255, 255, 0.08);
--track-glow: rgba(139, 228, 255, 0.18);
}
*,
@@ -110,7 +113,7 @@ button {
.sidebar {
display: flex;
flex-direction: column;
justify-content: space-between;
justify-content: flex-start;
padding: 1.35rem;
border-radius: var(--radius-xl);
min-height: calc(100vh - 2.5rem);
@@ -153,6 +156,24 @@ button {
letter-spacing: 0.01em;
}
.meta-pill--button {
cursor: pointer;
}
.topbar-date-form {
display: inline-flex;
}
.topbar-date-input {
width: auto;
min-height: 2.2rem;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 999px;
padding: 0.45rem 0.9rem;
background: rgba(255, 255, 255, 0.08);
color: var(--text);
}
.chart-chip--warm {
background: rgba(255, 173, 124, 0.12);
}
@@ -209,6 +230,9 @@ button {
}
.main-nav a {
display: flex;
align-items: center;
gap: 0.8rem;
padding: 0.9rem 1rem;
border-radius: 18px;
color: var(--muted);
@@ -225,6 +249,14 @@ button {
.sidebar-footer {
display: grid;
gap: 0.85rem;
margin-top: auto;
padding-top: 1.2rem;
}
.nav-icon {
width: 1.1rem;
height: 1.1rem;
opacity: 0.9;
}
.user-chip {
@@ -497,6 +529,13 @@ button {
gap: 1rem;
}
.section-head__actions {
display: flex;
gap: 0.7rem;
align-items: center;
flex-wrap: wrap;
}
.field-grid--single {
grid-template-columns: 1fr;
}
@@ -560,8 +599,9 @@ input[type="range"] {
.range-card {
padding: 1rem;
border-radius: var(--radius-md);
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.1);
background: var(--track-surface);
border: 1px solid var(--track-accent);
transition: border-color 220ms ease, background 220ms ease, transform 220ms ease, box-shadow 220ms ease;
}
.range-card output {
@@ -570,6 +610,66 @@ input[type="range"] {
font-weight: 700;
}
.preview-card {
position: relative;
overflow: hidden;
border-color: var(--track-accent);
box-shadow: 0 24px 70px rgba(4, 18, 31, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.preview-card::before {
content: "";
position: absolute;
inset: auto -12% -25% auto;
width: 14rem;
height: 14rem;
border-radius: 50%;
background: radial-gradient(circle, var(--track-glow), transparent 70%);
pointer-events: none;
transition: background 220ms ease, transform 220ms ease;
}
.preview-status {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.8rem;
}
.preview-status__icon {
width: 4.5rem;
height: 4.5rem;
border-radius: 20px;
display: grid;
place-items: center;
background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.preview-status__icon img {
width: 2.3rem;
height: 2.3rem;
}
.preview-status__label {
margin: 0;
font-size: 1.55rem;
font-weight: 750;
}
.preview-scoreline {
margin: 0 0 1rem;
color: var(--muted);
font-size: 0.95rem;
}
.preview-scoreline span {
color: var(--text);
font-size: 1.2rem;
font-weight: 700;
}
.component-list,
.detail-grid {
display: grid;
@@ -684,6 +784,17 @@ input[type="range"] {
text-align: right;
}
.archive-item__actions {
display: flex;
gap: 0.55rem;
flex-wrap: wrap;
}
.archive-action {
min-height: 2.4rem;
padding-inline: 0.85rem;
}
.note-box {
padding: 1rem;
border-radius: 18px;
@@ -740,6 +851,68 @@ input[type="range"] {
width: fit-content;
}
.page-track[data-track-mood="storm"] {
--track-accent: rgba(255, 143, 143, 0.38);
--track-surface: rgba(255, 143, 143, 0.08);
--track-glow: rgba(255, 126, 126, 0.22);
}
.page-track[data-track-mood="heavy"] {
--track-accent: rgba(255, 191, 141, 0.34);
--track-surface: rgba(255, 191, 141, 0.08);
--track-glow: rgba(255, 191, 141, 0.18);
}
.page-track[data-track-mood="steady"] {
--track-accent: rgba(139, 228, 255, 0.34);
--track-surface: rgba(255, 255, 255, 0.08);
--track-glow: rgba(139, 228, 255, 0.18);
}
.page-track[data-track-mood="bright"] {
--track-accent: rgba(143, 243, 198, 0.34);
--track-surface: rgba(143, 243, 198, 0.08);
--track-glow: rgba(143, 243, 198, 0.2);
}
.page-track[data-track-mood="radiant"] {
--track-accent: rgba(255, 233, 140, 0.35);
--track-surface: rgba(255, 233, 140, 0.1);
--track-glow: rgba(255, 233, 140, 0.22);
}
.page-track[data-track-mood] .aurora-one,
.page-track[data-track-mood] .aurora-two,
.page-track[data-track-mood] .range-card,
.page-track[data-track-mood] .preview-card,
.page-track[data-track-mood] .preview-card::before {
transition: background 220ms ease, opacity 220ms ease, transform 220ms ease, border-color 220ms ease, box-shadow 220ms ease;
}
.page-track[data-track-mood="storm"] .aurora-one,
.page-track[data-track-mood="storm"] .aurora-two {
opacity: 0.5;
background: radial-gradient(circle, rgba(255, 128, 128, 0.32), transparent 70%);
}
.page-track[data-track-mood="heavy"] .aurora-one,
.page-track[data-track-mood="heavy"] .aurora-two {
opacity: 0.55;
background: radial-gradient(circle, rgba(255, 192, 128, 0.3), transparent 70%);
}
.page-track[data-track-mood="bright"] .aurora-one,
.page-track[data-track-mood="bright"] .aurora-two {
opacity: 0.72;
background: radial-gradient(circle, rgba(127, 243, 187, 0.3), transparent 70%);
}
.page-track[data-track-mood="radiant"] .aurora-one,
.page-track[data-track-mood="radiant"] .aurora-two {
opacity: 0.78;
background: radial-gradient(circle, rgba(255, 228, 122, 0.32), transparent 70%);
}
@media (max-width: 1100px) {
.shell {
grid-template-columns: 1fr;
@@ -778,6 +951,12 @@ input[type="range"] {
overflow-x: auto;
padding-bottom: 0.4rem;
}
.archive-item,
.preview-status {
flex-direction: column;
align-items: flex-start;
}
}
@media (max-width: 640px) {
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M4 7.5A3.5 3.5 0 0 1 7.5 4H10l1.2 1.6a2 2 0 0 0 1.6.8H16.5A3.5 3.5 0 0 1 20 9.9v6.6A3.5 3.5 0 0 1 16.5 20h-9A3.5 3.5 0 0 1 4 16.5v-9Z" fill="#DFF7FF" opacity=".18"/>
<path d="M8 12h8" stroke="#DFF7FF" stroke-width="2" stroke-linecap="round"/>
<path d="M8 16h5" stroke="#8CFFD1" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<rect x="3" y="3" width="7" height="7" rx="2" fill="#DFF7FF"/>
<rect x="14" y="3" width="7" height="11" rx="2" fill="#90E3FF"/>
<rect x="3" y="14" width="7" height="7" rx="2" fill="#8CFFD1"/>
<rect x="14" y="18" width="7" height="3" rx="1.5" fill="#DFF7FF"/>
</svg>

After

Width:  |  Height:  |  Size: 348 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<circle cx="24" cy="24" r="15" fill="#8CFFD1"/>
<circle cx="19" cy="20.5" r="2" fill="#114F3C"/>
<circle cx="29" cy="20.5" r="2" fill="#114F3C"/>
<path d="M18 27.5c1.7 2.3 3.8 3.5 6 3.5s4.3-1.2 6-3.5" stroke="#114F3C" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 349 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<path d="M15 30c-4.4 0-8-3.4-8-7.6S10.6 15 15 15c1 0 1.9.2 2.8.5C20 11.6 24 9 28.6 9 35.4 9 41 14.3 41 21c0 .5 0 1-.1 1.5 3 1.4 5.1 4.4 5.1 7.9 0 4.9-4.1 8.6-9.3 8.6H15Z" fill="#FFC98F"/>
<path d="M18 34c1.6 1.3 3.6 2 6 2s4.4-.7 6-2" stroke="#8E4C1F" stroke-width="3" stroke-linecap="round"/>
<circle cx="19" cy="24" r="2" fill="#8E4C1F"/>
<circle cx="29" cy="24" r="2" fill="#8E4C1F"/>
</svg>

After

Width:  |  Height:  |  Size: 476 B

+14
View File
@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<circle cx="24" cy="24" r="12" fill="#FFE28A"/>
<path d="M24 4v6" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M24 38v6" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M4 24h6" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M38 24h6" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M10 10l4 4" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M34 34l4 4" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M10 38l4-4" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<path d="M34 14l4-4" stroke="#FFE28A" stroke-width="3" stroke-linecap="round"/>
<circle cx="19" cy="22" r="1.8" fill="#7A5A08"/>
<circle cx="29" cy="22" r="1.8" fill="#7A5A08"/>
<path d="M18 27.5c1.7 2.3 3.8 3.5 6 3.5s4.3-1.2 6-3.5" stroke="#7A5A08" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 994 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<circle cx="24" cy="24" r="15" fill="#A6E8FF"/>
<circle cx="19" cy="21" r="2" fill="#174861"/>
<circle cx="29" cy="21" r="2" fill="#174861"/>
<path d="M18 29h12" stroke="#174861" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none">
<path d="M15 29c-4.4 0-8-3.4-8-7.6S10.6 14 15 14c1 0 1.9.2 2.8.5C20 10.6 24 8 28.6 8 35.4 8 41 13.3 41 20c0 .5 0 1-.1 1.5 3 1.4 5.1 4.4 5.1 7.9 0 4.9-4.1 8.6-9.3 8.6H15Z" fill="#FFB2B2"/>
<path d="M20 34l-2.4 5.4" stroke="#FFE6A6" stroke-width="3" stroke-linecap="round"/>
<path d="M28 34l-2.4 5.4" stroke="#FFE6A6" stroke-width="3" stroke-linecap="round"/>
<path d="M24 22c-2.2 0-4 1.8-4 4" stroke="#7A2437" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 540 B

+7
View File
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<path d="M5 7h14" stroke="#DFF7FF" stroke-width="2" stroke-linecap="round"/>
<path d="M5 17h14" stroke="#DFF7FF" stroke-width="2" stroke-linecap="round"/>
<circle cx="9" cy="7" r="3" fill="#90E3FF"/>
<circle cx="15" cy="17" r="3" fill="#8CFFD1"/>
</svg>

After

Width:  |  Height:  |  Size: 336 B

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
<rect x="3" y="5" width="18" height="16" rx="4" fill="#DFF7FF" opacity=".18"/>
<rect x="6" y="3" width="2" height="4" rx="1" fill="#DFF7FF"/>
<rect x="16" y="3" width="2" height="4" rx="1" fill="#DFF7FF"/>
<path d="M7 11.5h10" stroke="#DFF7FF" stroke-width="2" stroke-linecap="round"/>
<path d="M7 16.5h6" stroke="#8CFFD1" stroke-width="2" stroke-linecap="round"/>
<circle cx="16.5" cy="16.5" r="2.5" fill="#90E3FF"/>
</svg>

After

Width:  |  Height:  |  Size: 511 B

+50 -1
View File
@@ -34,6 +34,10 @@
return value || fallback;
}
function moodIconPath(sentiment) {
return `/assets/icons/mood-${sentiment}.svg`;
}
function updateRangeOutputs() {
document.querySelectorAll("[data-output-for]").forEach(output => {
const input = document.querySelector(`[name="${output.dataset.outputFor}"]`);
@@ -50,6 +54,17 @@
});
}
function initHeaderDatePicker() {
document.querySelectorAll(".topbar-date-input").forEach(input => {
input.addEventListener("change", () => {
const form = input.closest("form");
if (form) {
form.submit();
}
});
});
}
function sleepDurationPoints(hours, points) {
if (hours < 4) {
return Number(points.lt4 || 0);
@@ -123,6 +138,35 @@
return currentIndex > capIndex ? cap : current;
}
function sentimentForLabel(label, ratings) {
const order = ratings.map(item => item.label);
const index = order.indexOf(label);
if (index === -1 || order.length <= 1) {
return "steady";
}
const ratio = index / Math.max(order.length - 1, 1);
if (ratio <= 0.1) {
return "storm";
}
if (ratio <= 0.35) {
return "heavy";
}
if (ratio <= 0.65) {
return "steady";
}
if (ratio <= 0.9) {
return "bright";
}
return "radiant";
}
function evaluateEntry(entry, settings) {
const ratings = sortedRatings(settings.ratings || []);
const scoring = settings.scoring || {};
@@ -151,7 +195,7 @@
}
}
return { total, label, components };
return { total, label, components, sentiment: sentimentForLabel(label, ratings) };
}
function initTrackPreview() {
@@ -169,6 +213,7 @@
const totalNode = card.querySelector("[data-preview-total]");
const labelNode = card.querySelector("[data-preview-label]");
const iconNode = card.querySelector("[data-preview-icon]");
const componentsNode = card.querySelector("[data-preview-components]");
const componentLabels = {
mood: "Stimmung",
@@ -196,6 +241,9 @@
const result = evaluateEntry(collect(), payload.settings);
totalNode.textContent = formatNumber(result.total);
labelNode.textContent = result.label;
iconNode.src = moodIconPath(result.sentiment);
card.dataset.sentiment = result.sentiment;
document.body.dataset.trackMood = result.sentiment;
componentsNode.innerHTML = Object.entries(result.components).map(([key, value]) => {
return `<div><dt>${componentLabels[key] || key}</dt><dd>${formatNumber(Number(value))}</dd></div>`;
}).join("");
@@ -419,6 +467,7 @@
}
updateRangeOutputs();
initHeaderDatePicker();
initTrackPreview();
initDashboardCharts();
})();