feat(gui): Projektansicht mit Ordnern, Unterreitern und angehefteten Aufnahmen
Neuer Reiter neben "Aufnahmen": Projektordner bündeln Aufnahmen zweistufig (Ordner + Unterreiter), auf beiden Ebenen anheftbar. Anheften geht aus dem Projekt heraus (Dropdown mit Filter) oder über den 📌-Knopf in der Aufnahmenliste, der Ordner und Ebene abfragt, neue Ordner anlegt und bestehende Anheftungen zum Lösen zeigt. Klick auf eine angeheftete Aufnahme springt in die Aufnahmen-Ansicht. Ein Pin ist eine Referenz, kein Besitz: die Aufnahme bleibt unverändert in der Liste und darf in mehreren Ordnern hängen. project_pins.tab_id ist INT NOT NULL DEFAULT 0 (0 = Ordner-Ebene) statt NULL, weil MariaDB NULL von UNIQUE-Indizes ausschließt — sonst ließe sich dieselbe Aufnahme mehrfach auf dieselbe Ebene anheften. So macht INSERT IGNORE das Anheften idempotent. purgeRecording räumt project_pins mit ab; getProject blendet Aufnahmen im Papierkorb aus, ohne deren Pin zu löschen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
963ce427da
commit
772385713e
+50
-1
@@ -500,4 +500,53 @@ body.resizing { cursor: col-resize; user-select: none; }
|
||||
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; }
|
||||
|
||||
Reference in New Issue
Block a user