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:
co-authored by
Claude Opus 5
parent
d0e02eb976
commit
3496b4a2df
+12
-2
@@ -33,7 +33,7 @@ function render() {
|
||||
const theme = document.documentElement.dataset.theme || 'dark';
|
||||
app.innerHTML = `
|
||||
<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>
|
||||
<h1>Aime <span class="sub">Anruf-Assistent</span></h1>
|
||||
</div>
|
||||
@@ -53,6 +53,12 @@ function render() {
|
||||
</header>
|
||||
<main id="view"></main>`;
|
||||
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 = () =>
|
||||
applyTheme(document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark');
|
||||
app.querySelector('#recbtn').onclick = toggleRecord;
|
||||
@@ -903,7 +909,7 @@ async function refreshRecList() {
|
||||
${r.summary ? `<div class="summary-snip">${escapeHtml(r.summary)}</div>` : ''}
|
||||
</div>
|
||||
<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 danger icon" data-del="${r.id}" title="In den Papierkorb">🗑</button>
|
||||
</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]; }
|
||||
|
||||
// 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_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
@@ -395,158 +395,166 @@ body.resizing { cursor: col-resize; user-select: none; }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* { transition: none !important; animation: none !important; }
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Suche — Google-Anmutung, aber in der Aime-Palette: viel Weißraum, eine
|
||||
dominante Eingabezeile, Treffer als Textblöcke ohne Karten-Rahmen.
|
||||
========================================================================== */
|
||||
.search-page { max-width: 46rem; margin: 0 auto; padding: 1rem 1rem 4rem; }
|
||||
/* Startzustand: Suchfeld optisch mittig, wie eine leere Suchseite. */
|
||||
.search-page.landing { padding-top: 12vh; }
|
||||
.search-page.has-results { padding-top: 1.25rem; }
|
||||
|
||||
.search-box {
|
||||
display: flex; align-items: center; gap: .5rem;
|
||||
border: 1px solid var(--line); border-radius: 2rem;
|
||||
background: var(--surface); box-shadow: var(--shadow);
|
||||
padding: .35rem .35rem .35rem 1rem;
|
||||
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-ico { opacity: .55; font-size: 1rem; }
|
||||
.search-input {
|
||||
flex: 1; border: 0; outline: 0; background: transparent; color: var(--fg);
|
||||
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:hover { color: var(--fg); }
|
||||
.search-go {
|
||||
border: 0; border-radius: 1.6rem; cursor: pointer;
|
||||
background: var(--accent); color: var(--accent-fg);
|
||||
font: inherit; font-weight: 600; padding: .55rem 1.1rem;
|
||||
}
|
||||
.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 .example {
|
||||
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;
|
||||
}
|
||||
.search-hints .example:hover { border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
.searching { padding: 1.5rem 0; }
|
||||
.search-empty { padding: 1.5rem 0; }
|
||||
|
||||
/* Antwortkasten: abgesetzt wie eine KI-Übersicht, nicht wie ein Treffer. */
|
||||
.answer-box {
|
||||
margin: 1.25rem 0 .5rem; padding: .9rem 1rem;
|
||||
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-body { line-height: 1.55; white-space: pre-wrap; }
|
||||
/* Platzhalterbalken, solange das LLM rechnet (30-90 s sind hier normal). */
|
||||
.answer-body.skeleton { display: flex; flex-direction: column; gap: .45rem; }
|
||||
.answer-body.skeleton span {
|
||||
height: .7rem; border-radius: .35rem; background: var(--line); opacity: .55;
|
||||
animation: pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
.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(3) { width: 45%; animation-delay: .36s; }
|
||||
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: .7; } }
|
||||
.answer-src { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .4rem; }
|
||||
.src-chip {
|
||||
border: 1px solid var(--line); background: var(--surface); color: var(--fg);
|
||||
border-radius: 1rem; font: inherit; font-size: .8rem; padding: .2rem .6rem; cursor: pointer;
|
||||
}
|
||||
.src-chip:hover { border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
.result-meta { margin: .9rem 0 .3rem; }
|
||||
.results { list-style: none; margin: 0; padding: 0; }
|
||||
.result { padding: .85rem 0; cursor: pointer; border-bottom: 1px solid var(--line); }
|
||||
.result:hover .result-title { text-decoration: underline; }
|
||||
.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-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 mark { background: var(--warn-soft); color: inherit; font-weight: 600; padding: 0 .1em; border-radius: .15em; }
|
||||
|
||||
/* ==========================================================================
|
||||
Papierkorb + Umbenennen
|
||||
========================================================================== */
|
||||
.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:hover { color: var(--fg); border-color: var(--line); }
|
||||
.btn.ghost.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
|
||||
.trash-hint, .trash-empty { padding: .6rem .75rem; }
|
||||
.item.rec.trashed { opacity: .8; }
|
||||
.item.rec.trashed b { text-decoration: line-through; text-decoration-color: var(--muted); }
|
||||
.days-left { color: var(--muted); }
|
||||
.days-left.urgent { color: var(--danger); font-weight: 600; }
|
||||
/* Der Stift sitzt neben der H2 des Detailkopfs, ohne die Zeile umzubrechen. */
|
||||
.rename-btn { vertical-align: middle; margin-left: -.25rem; opacity: .55; }
|
||||
.rename-btn:hover { opacity: 1; }
|
||||
.item.rec [data-ren] { opacity: .45; }
|
||||
.item.rec:hover [data-ren] { opacity: 1; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.search-page.landing { padding-top: 6vh; }
|
||||
.search-go { padding: .55rem .8rem; }
|
||||
}
|
||||
/* Abschnittstitel in der Zusammenfassung ("Neuer Projektleiter vorgestellt:").
|
||||
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. */
|
||||
.summary .sum-head {
|
||||
font-weight: 700;
|
||||
color: var(--fg);
|
||||
line-height: 2.2;
|
||||
}
|
||||
/* ---- Projektansicht ---------------------------------------------------------
|
||||
Ordnergitter (Ebene 1) und darin eine Reiterleiste für die Unterreiter
|
||||
(Ebene 2). Die Reiter sehen bewusst anders aus als die Kopfzeilen-Tabs, damit
|
||||
klar bleibt: das ist eine Ebene INNERHALB eines Ordners. */
|
||||
.proj-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
|
||||
.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-card {
|
||||
display: flex; align-items: center; gap: 10px; cursor: pointer;
|
||||
background: var(--surface-2); border: 1px solid var(--line);
|
||||
border-radius: 10px; padding: 12px 14px; transition: border-color .1s, background .1s;
|
||||
}
|
||||
.proj-card:hover { border-color: var(--accent); }
|
||||
.proj-card .grow { flex: 1; min-width: 0; }
|
||||
.proj-card b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.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; }
|
||||
.ptab {
|
||||
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;
|
||||
}
|
||||
.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.add { color: var(--muted); border-style: dashed; border-color: var(--line); }
|
||||
.ptab.add:hover { color: var(--accent); border-color: var(--accent); }
|
||||
.ptab-n { font-size: 11px; opacity: .7; margin-left: 4px; }
|
||||
|
||||
.proj-level { margin-top: 14px; }
|
||||
.proj-level-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
|
||||
.proj-level-head .grow { flex: 1; }
|
||||
.proj-level .item.rec { cursor: pointer; }
|
||||
|
||||
/* 📌 in der Aufnahmenliste: blass, solange die Aufnahme nirgends hängt. */
|
||||
.pinbtn { opacity: .45; position: relative; }
|
||||
.item.rec:hover .pinbtn { opacity: 1; }
|
||||
.pinbtn.pinned { opacity: 1; border-color: var(--accent); color: var(--accent); }
|
||||
.pin-n { font-size: 10px; font-weight: 700; margin-left: 2px; vertical-align: super; }
|
||||
|
||||
/* ---- Modal ---- */
|
||||
.modal-back {
|
||||
position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
|
||||
display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px;
|
||||
}
|
||||
.modal { width: min(520px, 100%); max-height: 85vh; overflow: auto; margin: 0; }
|
||||
.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; }
|
||||
|
||||
/* ==========================================================================
|
||||
Suche — Google-Anmutung, aber in der Aime-Palette: viel Weißraum, eine
|
||||
dominante Eingabezeile, Treffer als Textblöcke ohne Karten-Rahmen.
|
||||
========================================================================== */
|
||||
.search-page { max-width: 46rem; margin: 0 auto; padding: 1rem 1rem 4rem; }
|
||||
/* Startzustand: Suchfeld optisch mittig, wie eine leere Suchseite. */
|
||||
.search-page.landing { padding-top: 12vh; }
|
||||
.search-page.has-results { padding-top: 1.25rem; }
|
||||
|
||||
.search-box {
|
||||
display: flex; align-items: center; gap: .5rem;
|
||||
border: 1px solid var(--line); border-radius: 2rem;
|
||||
background: var(--surface); box-shadow: var(--shadow);
|
||||
padding: .35rem .35rem .35rem 1rem;
|
||||
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-ico { opacity: .55; font-size: 1rem; }
|
||||
.search-input {
|
||||
flex: 1; border: 0; outline: 0; background: transparent; color: var(--fg);
|
||||
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:hover { color: var(--fg); }
|
||||
.search-go {
|
||||
border: 0; border-radius: 1.6rem; cursor: pointer;
|
||||
background: var(--accent); color: var(--accent-fg);
|
||||
font: inherit; font-weight: 600; padding: .55rem 1.1rem;
|
||||
}
|
||||
.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 .example {
|
||||
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;
|
||||
}
|
||||
.search-hints .example:hover { border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
.searching { padding: 1.5rem 0; }
|
||||
.search-empty { padding: 1.5rem 0; }
|
||||
|
||||
/* Antwortkasten: abgesetzt wie eine KI-Übersicht, nicht wie ein Treffer. */
|
||||
.answer-box {
|
||||
margin: 1.25rem 0 .5rem; padding: .9rem 1rem;
|
||||
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-body { line-height: 1.55; white-space: pre-wrap; }
|
||||
/* Platzhalterbalken, solange das LLM rechnet (30-90 s sind hier normal). */
|
||||
.answer-body.skeleton { display: flex; flex-direction: column; gap: .45rem; }
|
||||
.answer-body.skeleton span {
|
||||
height: .7rem; border-radius: .35rem; background: var(--line); opacity: .55;
|
||||
animation: pulse 1.4s ease-in-out infinite;
|
||||
}
|
||||
.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(3) { width: 45%; animation-delay: .36s; }
|
||||
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: .7; } }
|
||||
.answer-src { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .4rem; }
|
||||
.src-chip {
|
||||
border: 1px solid var(--line); background: var(--surface); color: var(--fg);
|
||||
border-radius: 1rem; font: inherit; font-size: .8rem; padding: .2rem .6rem; cursor: pointer;
|
||||
}
|
||||
.src-chip:hover { border-color: var(--accent); color: var(--accent); }
|
||||
|
||||
.result-meta { margin: .9rem 0 .3rem; }
|
||||
.results { list-style: none; margin: 0; padding: 0; }
|
||||
.result { padding: .85rem 0; cursor: pointer; border-bottom: 1px solid var(--line); }
|
||||
.result:hover .result-title { text-decoration: underline; }
|
||||
.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-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 mark { background: var(--warn-soft); color: inherit; font-weight: 600; padding: 0 .1em; border-radius: .15em; }
|
||||
|
||||
/* ==========================================================================
|
||||
Papierkorb + Umbenennen
|
||||
========================================================================== */
|
||||
.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:hover { color: var(--fg); border-color: var(--line); }
|
||||
.btn.ghost.active { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
|
||||
.trash-hint, .trash-empty { padding: .6rem .75rem; }
|
||||
.item.rec.trashed { opacity: .8; }
|
||||
.item.rec.trashed b { text-decoration: line-through; text-decoration-color: var(--muted); }
|
||||
.days-left { color: var(--muted); }
|
||||
.days-left.urgent { color: var(--danger); font-weight: 600; }
|
||||
/* Der Stift sitzt neben der H2 des Detailkopfs, ohne die Zeile umzubrechen. */
|
||||
.rename-btn { vertical-align: middle; margin-left: -.25rem; opacity: .55; }
|
||||
.rename-btn:hover { opacity: 1; }
|
||||
.item.rec [data-ren] { opacity: .45; }
|
||||
.item.rec:hover [data-ren] { opacity: 1; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.search-page.landing { padding-top: 6vh; }
|
||||
.search-go { padding: .55rem .8rem; }
|
||||
}
|
||||
/* Abschnittstitel in der Zusammenfassung ("Neuer Projektleiter vorgestellt:").
|
||||
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. */
|
||||
.summary .sum-head {
|
||||
font-weight: 700;
|
||||
color: var(--fg);
|
||||
line-height: 2.2;
|
||||
}
|
||||
/* ---- Projektansicht ---------------------------------------------------------
|
||||
Ordnergitter (Ebene 1) und darin eine Reiterleiste für die Unterreiter
|
||||
(Ebene 2). Die Reiter sehen bewusst anders aus als die Kopfzeilen-Tabs, damit
|
||||
klar bleibt: das ist eine Ebene INNERHALB eines Ordners. */
|
||||
.proj-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
|
||||
.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-card {
|
||||
display: flex; align-items: center; gap: 10px; cursor: pointer;
|
||||
background: var(--surface-2); border: 1px solid var(--line);
|
||||
border-radius: 10px; padding: 12px 14px; transition: border-color .1s, background .1s;
|
||||
}
|
||||
.proj-card:hover { border-color: var(--accent); }
|
||||
.proj-card .grow { flex: 1; min-width: 0; }
|
||||
.proj-card b { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.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; }
|
||||
.ptab {
|
||||
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;
|
||||
}
|
||||
.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.add { color: var(--muted); border-style: dashed; border-color: var(--line); }
|
||||
.ptab.add:hover { color: var(--accent); border-color: var(--accent); }
|
||||
.ptab-n { font-size: 11px; opacity: .7; margin-left: 4px; }
|
||||
|
||||
.proj-level { margin-top: 14px; }
|
||||
.proj-level-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
|
||||
.proj-level-head .grow { flex: 1; }
|
||||
.proj-level .item.rec { cursor: pointer; }
|
||||
|
||||
/* Stecknadel in der Aufnahmenliste: blass, solange die Aufnahme nirgends
|
||||
hängt — angeheftet wird sie gruen (dieselbe Farbe wie „KI ✓“, also
|
||||
„erledigt/zugeordnet“). Das Icon ist ein SVG mit currentColor; ein 📌-Emoji
|
||||
wäre in jedem Zustand rot geblieben. */
|
||||
.pinbtn { opacity: .45; position: relative; display: inline-flex; align-items: center; gap: 1px; }
|
||||
.item.rec:hover .pinbtn { opacity: 1; }
|
||||
.pinbtn.pinned { opacity: 1; border-color: var(--ok); color: var(--ok); background: var(--ok-soft); }
|
||||
.pin-n { font-size: 10px; font-weight: 700; vertical-align: super; }
|
||||
|
||||
/* ---- Modal ---- */
|
||||
.modal-back {
|
||||
position: fixed; inset: 0; background: rgba(0, 0, 0, .5);
|
||||
display: flex; align-items: center; justify-content: center; z-index: 50; padding: 20px;
|
||||
}
|
||||
.modal { width: min(520px, 100%); max-height: 85vh; overflow: auto; margin: 0; }
|
||||
.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); }
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum,
|
||||
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
|
||||
|
||||
Der erste Reiter eines Projekts hieß fest „Ordner". Er trägt jetzt einen frei wählbaren Namen, genau wie
|
||||
|
||||
@@ -84,9 +84,11 @@ flowchart LR
|
||||
end
|
||||
```
|
||||
|
||||
Der 📌-Knopf in der Aufnahmenliste trägt die Zahl der Projekte, in denen die Aufnahme hängt, und ist
|
||||
farbig markiert, sobald sie irgendwo angeheftet ist (`GET /api/pins/counts` — ein Request für die ganze
|
||||
Liste, nicht einer pro Zeile). Die Zahl steckt zusätzlich in der Listen-Signatur `state.lastListSig`, damit
|
||||
Der Nadel-Knopf in der Aufnahmenliste trägt die Zahl der Projekte, in denen die Aufnahme hängt, und wird
|
||||
**grün** (`--ok`, dieselbe Farbe wie „KI ✓"), sobald sie irgendwo angeheftet ist — sonst bleibt er blass
|
||||
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
|
||||
anfassen") aufzuweichen.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user