feat(gui): gruene Nadel bei angehefteter Aufnahme, Logo fuehrt zu den Aufnahmen

Der Anheften-Knopf zeigte bei angehefteter Aufnahme nur die Zahl, die Nadel
blieb rot. Sie ist jetzt gruen (--ok, wie das "KI ✓"-Abzeichen). Dafuer
ersetzt ein SVG mit currentColor (ICON_PIN, gleiches Muster wie ICON_TABLE)
das 📌-Emoji: ein Farb-Emoji rendert immer rot, color greift daran nicht.

Klick auf Wellen-Logo und Schriftzug wechselt auf den Reiter "Aufnahmen".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
schakal00783
2026-08-02 23:14:41 +02:00
co-authored by Claude Opus 5
parent d0e02eb976
commit 3496b4a2df
4 changed files with 192 additions and 160 deletions
+12 -2
View File
@@ -33,7 +33,7 @@ function render() {
const theme = document.documentElement.dataset.theme || 'dark'; const theme = document.documentElement.dataset.theme || 'dark';
app.innerHTML = ` app.innerHTML = `
<header class="topbar"> <header class="topbar">
<div class="brand"> <div class="brand" id="brandhome" title="Zu den Aufnahmen">
<svg class="brand-wave" viewBox="0 0 34 20" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><line x1="3" y1="7" x2="3" y2="13"/><line x1="9" y1="4" x2="9" y2="16"/><line x1="15" y1="1" x2="15" y2="19"/><line x1="21" y1="5" x2="21" y2="15"/><line x1="27" y1="8" x2="27" y2="12"/><line x1="33" y1="9.5" x2="33" y2="10.5"/></g></svg> <svg class="brand-wave" viewBox="0 0 34 20" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><line x1="3" y1="7" x2="3" y2="13"/><line x1="9" y1="4" x2="9" y2="16"/><line x1="15" y1="1" x2="15" y2="19"/><line x1="21" y1="5" x2="21" y2="15"/><line x1="27" y1="8" x2="27" y2="12"/><line x1="33" y1="9.5" x2="33" y2="10.5"/></g></svg>
<h1>Aime <span class="sub">Anruf-Assistent</span></h1> <h1>Aime <span class="sub">Anruf-Assistent</span></h1>
</div> </div>
@@ -53,6 +53,12 @@ function render() {
</header> </header>
<main id="view"></main>`; <main id="view"></main>`;
app.querySelectorAll('.tab').forEach(b => b.onclick = () => { state.tab = b.dataset.tab; render(); }); app.querySelectorAll('.tab').forEach(b => b.onclick = () => { state.tab = b.dataset.tab; render(); });
// Logo + Schriftzug = Heimweg zurück auf die Aufnahmen.
app.querySelector('#brandhome').onclick = () => {
if (state.tab === 'recordings') return;
state.tab = 'recordings';
render();
};
app.querySelector('#themetoggle').onclick = () => app.querySelector('#themetoggle').onclick = () =>
applyTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark'); applyTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark');
app.querySelector('#recbtn').onclick = toggleRecord; app.querySelector('#recbtn').onclick = toggleRecord;
@@ -903,7 +909,7 @@ async function refreshRecList() {
${r.summary ? `<div class="summary-snip">${escapeHtml(r.summary)}</div>` : ''} ${r.summary ? `<div class="summary-snip">${escapeHtml(r.summary)}</div>` : ''}
</div> </div>
<button class="btn icon pinbtn ${pinCounts[r.id] ? 'pinned' : ''}" data-pin="${r.id}" <button class="btn icon pinbtn ${pinCounts[r.id] ? 'pinned' : ''}" data-pin="${r.id}"
title="${pinCounts[r.id] ? `In ${pinCounts[r.id]} Projekt(en) angeheftet — verwalten` : 'An ein Projekt anheften'}">📌${pinCounts[r.id] ? `<span class="pin-n">${pinCounts[r.id]}</span>` : ''}</button> title="${pinCounts[r.id] ? `In ${pinCounts[r.id]} Projekt(en) angeheftet — verwalten` : 'An ein Projekt anheften'}">${ICON_PIN}${pinCounts[r.id] ? `<span class="pin-n">${pinCounts[r.id]}</span>` : ''}</button>
<button class="btn icon" data-ren="${r.id}" title="Titel umbenennen">✏️</button> <button class="btn icon" data-ren="${r.id}" title="Titel umbenennen">✏️</button>
<button class="btn danger icon" data-del="${r.id}" title="In den Papierkorb">🗑</button> <button class="btn danger icon" data-del="${r.id}" title="In den Papierkorb">🗑</button>
</div>`; }).join(''); </div>`; }).join('');
@@ -1500,6 +1506,10 @@ const BUBBLE_W = 54;
function tableSeats(n) { return SEAT_LAYOUTS[Math.min(6, Math.max(1, n))] || SEAT_LAYOUTS[6]; } function tableSeats(n) { return SEAT_LAYOUTS[Math.min(6, Math.max(1, n))] || SEAT_LAYOUTS[6]; }
// Toggle-button icons: three people around a table / a text sheet. // Toggle-button icons: three people around a table / a text sheet.
// Stecknadel als SVG statt 📌: ein Farb-Emoji bleibt immer rot, `currentColor`
// lässt sich dagegen einfärben — angeheftet = grün, sonst blass wie die
// übrigen Zeilenknöpfe.
const ICON_PIN = `<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3.5h6l-1 5 3.2 3.2H6.8L10 8.5z"/><line x1="12" y1="11.7" x2="12" y2="20.5"/></g></svg>`;
const ICON_TABLE = `<svg viewBox="0 0 24 24" width="17" height="17" aria-hidden="true"><g fill="currentColor"><rect x="6" y="10" width="12" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="12" cy="4.6" r="2.1"/><circle cx="4" cy="19.4" r="2.1"/><circle cx="20" cy="19.4" r="2.1"/></g></svg>`; const ICON_TABLE = `<svg viewBox="0 0 24 24" width="17" height="17" aria-hidden="true"><g fill="currentColor"><rect x="6" y="10" width="12" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="12" cy="4.6" r="2.1"/><circle cx="4" cy="19.4" r="2.1"/><circle cx="20" cy="19.4" r="2.1"/></g></svg>`;
const ICON_SHEET = `<svg viewBox="0 0 24 24" width="17" height="17" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><rect x="5" y="3" width="14" height="18" rx="2"/><line x1="8.5" y1="8" x2="15.5" y2="8"/><line x1="8.5" y1="12" x2="15.5" y2="12"/><line x1="8.5" y1="16" x2="13" y2="16"/></g></svg>`; const ICON_SHEET = `<svg viewBox="0 0 24 24" width="17" height="17" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><rect x="5" y="3" width="14" height="18" rx="2"/><line x1="8.5" y1="8" x2="15.5" y2="8"/><line x1="8.5" y1="12" x2="15.5" y2="12"/><line x1="8.5" y1="16" x2="13" y2="16"/></g></svg>`;
+163 -155
View File
@@ -395,158 +395,166 @@ body.resizing { cursor: col-resize; user-select: none; }
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; } * { transition: none !important; animation: none !important; }
} }
/* ========================================================================== /* ==========================================================================
Suche — Google-Anmutung, aber in der Aime-Palette: viel Weißraum, eine Suche — Google-Anmutung, aber in der Aime-Palette: viel Weißraum, eine
dominante Eingabezeile, Treffer als Textblöcke ohne Karten-Rahmen. dominante Eingabezeile, Treffer als Textblöcke ohne Karten-Rahmen.
========================================================================== */ ========================================================================== */
.search-page { max-width: 46rem; margin: 0 auto; padding: 1rem 1rem 4rem; } .search-page { max-width: 46rem; margin: 0 auto; padding: 1rem 1rem 4rem; }
/* Startzustand: Suchfeld optisch mittig, wie eine leere Suchseite. */ /* Startzustand: Suchfeld optisch mittig, wie eine leere Suchseite. */
.search-page.landing { padding-top: 12vh; } .search-page.landing { padding-top: 12vh; }
.search-page.has-results { padding-top: 1.25rem; } .search-page.has-results { padding-top: 1.25rem; }
.search-box { .search-box {
display: flex; align-items: center; gap: .5rem; display: flex; align-items: center; gap: .5rem;
border: 1px solid var(--line); border-radius: 2rem; border: 1px solid var(--line); border-radius: 2rem;
background: var(--surface); box-shadow: var(--shadow); background: var(--surface); box-shadow: var(--shadow);
padding: .35rem .35rem .35rem 1rem; padding: .35rem .35rem .35rem 1rem;
transition: box-shadow .15s, border-color .15s; transition: box-shadow .15s, border-color .15s;
} }
.search-box:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } .search-box:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.search-ico { opacity: .55; font-size: 1rem; } .search-ico { opacity: .55; font-size: 1rem; }
.search-input { .search-input {
flex: 1; border: 0; outline: 0; background: transparent; color: var(--fg); flex: 1; border: 0; outline: 0; background: transparent; color: var(--fg);
font: inherit; font-size: 1.05rem; padding: .55rem 0; font: inherit; font-size: 1.05rem; padding: .55rem 0;
} }
.search-clear { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: .95rem; padding: .25rem .4rem; } .search-clear { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: .95rem; padding: .25rem .4rem; }
.search-clear:hover { color: var(--fg); } .search-clear:hover { color: var(--fg); }
.search-go { .search-go {
border: 0; border-radius: 1.6rem; cursor: pointer; border: 0; border-radius: 1.6rem; cursor: pointer;
background: var(--accent); color: var(--accent-fg); background: var(--accent); color: var(--accent-fg);
font: inherit; font-weight: 600; padding: .55rem 1.1rem; font: inherit; font-weight: 600; padding: .55rem 1.1rem;
} }
.search-go:hover { filter: brightness(1.07); } .search-go:hover { filter: brightness(1.07); }
.search-hints { margin-top: 1.5rem; display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; } .search-hints { margin-top: 1.5rem; display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; }
.search-hints .example { .search-hints .example {
border: 1px solid var(--line); border-radius: 1rem; background: var(--surface-2); border: 1px solid var(--line); border-radius: 1rem; background: var(--surface-2);
color: var(--fg); font: inherit; font-size: .88rem; padding: .35rem .8rem; cursor: pointer; text-align: left; color: var(--fg); font: inherit; font-size: .88rem; padding: .35rem .8rem; cursor: pointer; text-align: left;
} }
.search-hints .example:hover { border-color: var(--accent); color: var(--accent); } .search-hints .example:hover { border-color: var(--accent); color: var(--accent); }
.searching { padding: 1.5rem 0; } .searching { padding: 1.5rem 0; }
.search-empty { padding: 1.5rem 0; } .search-empty { padding: 1.5rem 0; }
/* Antwortkasten: abgesetzt wie eine KI-Übersicht, nicht wie ein Treffer. */ /* Antwortkasten: abgesetzt wie eine KI-Übersicht, nicht wie ein Treffer. */
.answer-box { .answer-box {
margin: 1.25rem 0 .5rem; padding: .9rem 1rem; margin: 1.25rem 0 .5rem; padding: .9rem 1rem;
background: var(--accent-soft); border: 1px solid var(--line); border-radius: .75rem; background: var(--accent-soft); border: 1px solid var(--line); border-radius: .75rem;
} }
.answer-head { font-weight: 600; font-size: .82rem; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: .5rem; } .answer-head { font-weight: 600; font-size: .82rem; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-bottom: .5rem; }
.answer-body { line-height: 1.55; white-space: pre-wrap; } .answer-body { line-height: 1.55; white-space: pre-wrap; }
/* Platzhalterbalken, solange das LLM rechnet (30-90 s sind hier normal). */ /* Platzhalterbalken, solange das LLM rechnet (30-90 s sind hier normal). */
.answer-body.skeleton { display: flex; flex-direction: column; gap: .45rem; } .answer-body.skeleton { display: flex; flex-direction: column; gap: .45rem; }
.answer-body.skeleton span { .answer-body.skeleton span {
height: .7rem; border-radius: .35rem; background: var(--line); opacity: .55; height: .7rem; border-radius: .35rem; background: var(--line); opacity: .55;
animation: pulse 1.4s ease-in-out infinite; animation: pulse 1.4s ease-in-out infinite;
} }
.answer-body.skeleton span:nth-child(1) { width: 92%; } .answer-body.skeleton span:nth-child(1) { width: 92%; }
.answer-body.skeleton span:nth-child(2) { width: 78%; animation-delay: .18s; } .answer-body.skeleton span:nth-child(2) { width: 78%; animation-delay: .18s; }
.answer-body.skeleton span:nth-child(3) { width: 45%; animation-delay: .36s; } .answer-body.skeleton span:nth-child(3) { width: 45%; animation-delay: .36s; }
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: .7; } } @keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: .7; } }
.answer-src { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .4rem; } .answer-src { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .4rem; }
.src-chip { .src-chip {
border: 1px solid var(--line); background: var(--surface); color: var(--fg); border: 1px solid var(--line); background: var(--surface); color: var(--fg);
border-radius: 1rem; font: inherit; font-size: .8rem; padding: .2rem .6rem; cursor: pointer; border-radius: 1rem; font: inherit; font-size: .8rem; padding: .2rem .6rem; cursor: pointer;
} }
.src-chip:hover { border-color: var(--accent); color: var(--accent); } .src-chip:hover { border-color: var(--accent); color: var(--accent); }
.result-meta { margin: .9rem 0 .3rem; } .result-meta { margin: .9rem 0 .3rem; }
.results { list-style: none; margin: 0; padding: 0; } .results { list-style: none; margin: 0; padding: 0; }
.result { padding: .85rem 0; cursor: pointer; border-bottom: 1px solid var(--line); } .result { padding: .85rem 0; cursor: pointer; border-bottom: 1px solid var(--line); }
.result:hover .result-title { text-decoration: underline; } .result:hover .result-title { text-decoration: underline; }
.result-src { color: var(--muted); font-size: .78rem; margin-bottom: .15rem; } .result-src { color: var(--muted); font-size: .78rem; margin-bottom: .15rem; }
.result-title { display: block; color: var(--accent); font-size: 1.05rem; text-decoration: none; } .result-title { display: block; color: var(--accent); font-size: 1.05rem; text-decoration: none; }
.result-at { color: var(--muted); font-size: .8rem; font-weight: 400; margin-left: .4rem; } .result-at { color: var(--muted); font-size: .8rem; font-weight: 400; margin-left: .4rem; }
.result-snip { color: var(--fg); font-size: .9rem; line-height: 1.5; margin-top: .2rem; } .result-snip { color: var(--fg); font-size: .9rem; line-height: 1.5; margin-top: .2rem; }
.result-snip mark { background: var(--warn-soft); color: inherit; font-weight: 600; padding: 0 .1em; border-radius: .15em; } .result-snip mark { background: var(--warn-soft); color: inherit; font-weight: 600; padding: 0 .1em; border-radius: .15em; }
/* ========================================================================== /* ==========================================================================
Papierkorb + Umbenennen Papierkorb + Umbenennen
========================================================================== */ ========================================================================== */
.list-bar { display: flex; justify-content: flex-end; padding: .35rem .5rem; border-bottom: 1px solid var(--line); } .list-bar { display: flex; justify-content: flex-end; padding: .35rem .5rem; border-bottom: 1px solid var(--line); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); } .btn.ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn.ghost:hover { color: var(--fg); border-color: var(--line); } .btn.ghost:hover { color: var(--fg); border-color: var(--line); }
.btn.ghost.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); } .btn.ghost.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.trash-hint, .trash-empty { padding: .6rem .75rem; } .trash-hint, .trash-empty { padding: .6rem .75rem; }
.item.rec.trashed { opacity: .8; } .item.rec.trashed { opacity: .8; }
.item.rec.trashed b { text-decoration: line-through; text-decoration-color: var(--muted); } .item.rec.trashed b { text-decoration: line-through; text-decoration-color: var(--muted); }
.days-left { color: var(--muted); } .days-left { color: var(--muted); }
.days-left.urgent { color: var(--danger); font-weight: 600; } .days-left.urgent { color: var(--danger); font-weight: 600; }
/* Der Stift sitzt neben der H2 des Detailkopfs, ohne die Zeile umzubrechen. */ /* Der Stift sitzt neben der H2 des Detailkopfs, ohne die Zeile umzubrechen. */
.rename-btn { vertical-align: middle; margin-left: -.25rem; opacity: .55; } .rename-btn { vertical-align: middle; margin-left: -.25rem; opacity: .55; }
.rename-btn:hover { opacity: 1; } .rename-btn:hover { opacity: 1; }
.item.rec [data-ren] { opacity: .45; } .item.rec [data-ren] { opacity: .45; }
.item.rec:hover [data-ren] { opacity: 1; } .item.rec:hover [data-ren] { opacity: 1; }
@media (max-width: 640px) { @media (max-width: 640px) {
.search-page.landing { padding-top: 6vh; } .search-page.landing { padding-top: 6vh; }
.search-go { padding: .55rem .8rem; } .search-go { padding: .55rem .8rem; }
} }
/* Abschnittstitel in der Zusammenfassung ("Neuer Projektleiter vorgestellt:"). /* Abschnittstitel in der Zusammenfassung ("Neuer Projektleiter vorgestellt:").
Etwas Luft darüber, damit die Blöcke optisch trennen — der Text steht in Etwas Luft darüber, damit die Blöcke optisch trennen — der Text steht in
white-space: pre-line, die Zeilenumbrüche kommen also aus dem Text selbst. */ white-space: pre-line, die Zeilenumbrüche kommen also aus dem Text selbst. */
.summary .sum-head { .summary .sum-head {
font-weight: 700; font-weight: 700;
color: var(--fg); color: var(--fg);
line-height: 2.2; line-height: 2.2;
} }
/* ---- Projektansicht --------------------------------------------------------- /* ---- Projektansicht ---------------------------------------------------------
Ordnergitter (Ebene 1) und darin eine Reiterleiste für die Unterreiter Ordnergitter (Ebene 1) und darin eine Reiterleiste für die Unterreiter
(Ebene 2). Die Reiter sehen bewusst anders aus als die Kopfzeilen-Tabs, damit (Ebene 2). Die Reiter sehen bewusst anders aus als die Kopfzeilen-Tabs, damit
klar bleibt: das ist eine Ebene INNERHALB eines Ordners. */ klar bleibt: das ist eine Ebene INNERHALB eines Ordners. */
.proj-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; } .proj-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.proj-head h3 { margin: 0; flex: 1; } .proj-head h3 { margin: 0; flex: 1; }
.proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; margin-top: 10px; } .proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; margin-top: 10px; }
.proj-card { .proj-card {
display: flex; align-items: center; gap: 10px; cursor: pointer; display: flex; align-items: center; gap: 10px; cursor: pointer;
background: var(--surface-2); border: 1px solid var(--line); background: var(--surface-2); border: 1px solid var(--line);
border-radius: 10px; padding: 12px 14px; transition: border-color .1s, background .1s; border-radius: 10px; padding: 12px 14px; transition: border-color .1s, background .1s;
} }
.proj-card:hover { border-color: var(--accent); } .proj-card:hover { border-color: var(--accent); }
.proj-card .grow { flex: 1; min-width: 0; } .proj-card .grow { flex: 1; min-width: 0; }
.proj-card b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .proj-card b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proj-ico { font-size: 22px; flex: none; } .proj-ico { font-size: 22px; flex: none; }
.proj-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin: 14px 0 0; border-bottom: 1px solid var(--line); padding-bottom: 8px; } .proj-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin: 14px 0 0; border-bottom: 1px solid var(--line); padding-bottom: 8px; }
.ptab { .ptab {
background: transparent; border: 1px solid transparent; color: var(--muted); background: transparent; border: 1px solid transparent; color: var(--muted);
border-radius: 8px 8px 0 0; padding: 6px 12px; cursor: pointer; font: inherit; font-size: .9rem; border-radius: 8px 8px 0 0; padding: 6px 12px; cursor: pointer; font: inherit; font-size: .9rem;
} }
.ptab:hover { color: var(--fg); background: var(--surface-2); } .ptab:hover { color: var(--fg); background: var(--surface-2); }
.ptab.active { color: var(--accent); background: var(--accent-soft); border-color: var(--accent); font-weight: 600; } .ptab.active { color: var(--accent); background: var(--accent-soft); border-color: var(--accent); font-weight: 600; }
.ptab.add { color: var(--muted); border-style: dashed; border-color: var(--line); } .ptab.add { color: var(--muted); border-style: dashed; border-color: var(--line); }
.ptab.add:hover { color: var(--accent); border-color: var(--accent); } .ptab.add:hover { color: var(--accent); border-color: var(--accent); }
.ptab-n { font-size: 11px; opacity: .7; margin-left: 4px; } .ptab-n { font-size: 11px; opacity: .7; margin-left: 4px; }
.proj-level { margin-top: 14px; } .proj-level { margin-top: 14px; }
.proj-level-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; } .proj-level-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.proj-level-head .grow { flex: 1; } .proj-level-head .grow { flex: 1; }
.proj-level .item.rec { cursor: pointer; } .proj-level .item.rec { cursor: pointer; }
/* 📌 in der Aufnahmenliste: blass, solange die Aufnahme nirgends hängt. */ /* Stecknadel in der Aufnahmenliste: blass, solange die Aufnahme nirgends
.pinbtn { opacity: .45; position: relative; } hängt — angeheftet wird sie gruen (dieselbe Farbe wie „KI ✓“, also
.item.rec:hover .pinbtn { opacity: 1; } „erledigt/zugeordnet“). Das Icon ist ein SVG mit currentColor; ein 📌-Emoji
.pinbtn.pinned { opacity: 1; border-color: var(--accent); color: var(--accent); } wäre in jedem Zustand rot geblieben. */
.pin-n { font-size: 10px; font-weight: 700; margin-left: 2px; vertical-align: super; } .pinbtn { opacity: .45; position: relative; display: inline-flex; align-items: center; gap: 1px; }
.item.rec:hover .pinbtn { opacity: 1; }
/* ---- Modal ---- */ .pinbtn.pinned { opacity: 1; border-color: var(--ok); color: var(--ok); background: var(--ok-soft); }
.modal-back { .pin-n { font-size: 10px; font-weight: 700; vertical-align: super; }
position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px; /* ---- Modal ---- */
} .modal-back {
.modal { width: min(520px, 100%); max-height: 85vh; overflow: auto; margin: 0; } position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
.modal h3 { margin-top: 0; } display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px;
.modal-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; } }
.modal select[size] { height: auto; padding: 4px; } .modal { width: min(520px, 100%); max-height: 85vh; overflow: auto; margin: 0; }
.pin-current .item { padding: 6px 10px; } .modal h3 { margin-top: 0; }
.modal-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
.modal select[size] { height: auto; padding: 4px; }
.pin-current .item { padding: 6px 10px; }
/* Logo + Schriftzug führen zurück auf die Aufnahmen. */
.brand { cursor: pointer; user-select: none; }
.brand:hover .brand-wave { filter: brightness(1.15); }
.brand:hover h1 { color: var(--accent); }
+12
View File
@@ -3,6 +3,18 @@
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum, Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
Was, Warum, betroffene Dateien/Backups). Was, Warum, betroffene Dateien/Backups).
## 2026-08-02 (nachgereicht) — Grüne Nadel, Logo führt zurück zu den Aufnahmen
**Nadel grün statt rot:** der Anheften-Knopf in der Aufnahmenliste zeigte bei einer angehefteten Aufnahme
nur die Zahl, die Nadel selbst blieb rot. Sie ist jetzt grün (`--ok`, dieselbe Farbe wie das „KI ✓"-Abzeichen).
Dafür musste das **📌-Emoji einem SVG mit `currentColor` weichen** (`ICON_PIN`, gleiches Muster wie
`ICON_TABLE`/`ICON_SHEET`): ein Farb-Emoji rendert die Schriftart immer rot, `color` greift daran nicht.
**Logo als Heimweg:** ein Klick auf Wellen-Logo und Schriftzug „Aime" wechselt auf den Reiter „Aufnahmen"
(`#brandhome` in `render()`), mit Zeiger-Cursor und Hover-Andeutung als Hinweis darauf.
Dateien: `app/web/src/main.js`, `app/web/src/style.css`.
## 2026-08-02 (nachgereicht) — Ordner-Ebene umbenennbar ## 2026-08-02 (nachgereicht) — Ordner-Ebene umbenennbar
Der erste Reiter eines Projekts hieß fest „Ordner". Er trägt jetzt einen frei wählbaren Namen, genau wie Der erste Reiter eines Projekts hieß fest „Ordner". Er trägt jetzt einen frei wählbaren Namen, genau wie
+5 -3
View File
@@ -84,9 +84,11 @@ flowchart LR
end end
``` ```
Der 📌-Knopf in der Aufnahmenliste trägt die Zahl der Projekte, in denen die Aufnahme hängt, und ist Der Nadel-Knopf in der Aufnahmenliste trägt die Zahl der Projekte, in denen die Aufnahme hängt, und wird
farbig markiert, sobald sie irgendwo angeheftet ist (`GET /api/pins/counts` — ein Request für die ganze **grün** (`--ok`, dieselbe Farbe wie „KI ✓"), sobald sie irgendwo angeheftet ist — sonst bleibt er blass
Liste, nicht einer pro Zeile). Die Zahl steckt zusätzlich in der Listen-Signatur `state.lastListSig`, damit wie die übrigen Zeilenknöpfe (`GET /api/pins/counts` — ein Request für die ganze Liste, nicht einer pro
Zeile). Die Nadel ist deshalb ein **SVG mit `currentColor` (`ICON_PIN`) und kein 📌-Emoji**: ein
Farb-Emoji ist in jedem Zustand rot und lässt sich per CSS nicht umfärben. Die Zahl steckt zusätzlich in der Listen-Signatur `state.lastListSig`, damit
eine neue Anheftung die Liste neu zeichnet, ohne die 5-Sekunden-Regel („keine Änderung → DOM nicht eine neue Anheftung die Liste neu zeichnet, ohne die 5-Sekunden-Regel („keine Änderung → DOM nicht
anfassen") aufzuweichen. anfassen") aufzuweichen.