Zeiterfassung + Visual-Polish (Keycap-Buttons, Space Grotesk)
Zeiterfassung - Neue Tabelle time_entry mit started_at/ended_at/duration_seconds, optional todo_id/bezug, category-Enum (focus/meeting/break/admin/learning/other), description, day_entry_id-Verknüpfung. Partial-Unique-Index erzwingt max. einen aktiven Timer pro User. - tRPC time-Router: now, start (stoppt aktiven automatisch), stop, listToday (Liste + Tagessumme), update, upsertManual (retroaktiv), delete, teamToday (personenübergreifend mit byCategory + aktivem Timer pro User). - TopNav: persistente TimerPill links neben Streak. Quick-Picker mit heutigen ToDos, Kategorie-Auswahl und Freitext-Start. Live-Sekundenzähler. - /heute: TimelineSection mit Edit/Delete pro Eintrag, ToDo-Bindung nachträglich änderbar, Block-nachtragen-Dialog. Pro ToDo-Zeile ▶-Start- und 🕐-Nachtrag-Button. - /puls: TeamTimeSection mit aktiver Timer-Anzeige + Tagessumme + Kategorie-Breakdown pro User (refresh alle 30s, Live-Tick jede Sekunde). Visual - Space Grotesk als Hausschrift (selbst-gehostet, latin + latin-ext) - Keycap-Button-Stil (Gradient + Druckeffekt) für primary/secondary/destructive - Neue Helper-Module: format-duration, time-categories Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
4f33509a0f
commit
95beb99cd4
23 files changed
+3442
-49
No files matched your search
@@ -1,5 +1,29 @@
|
||||
@import 'tailwindcss';
|
||||
|
||||
/* ------ Hausschrift: Space Grotesk (lokal gehostet, wie tool-ctrl.de) ------- */
|
||||
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 300 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-grotesk-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
|
||||
U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
|
||||
U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 300 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/space-grotesk-latin-ext.woff2) format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
|
||||
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F,
|
||||
U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
|
||||
U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* ------ Brand Tokens (UX-Spec § Visual Design Foundation) ------- */
|
||||
|
||||
@theme {
|
||||
@@ -29,7 +53,7 @@
|
||||
--color-trend-down: #b91c1c;
|
||||
|
||||
/* Typografie */
|
||||
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
--font-sans: 'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', 'SF Mono', Menlo, monospace;
|
||||
|
||||
/* Radii */
|
||||
@@ -88,3 +112,84 @@ body {
|
||||
.skip-link:focus {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* ------ Keycap-Buttons (ToolCTRL-Website-Stil) ------- */
|
||||
|
||||
.btn-keycap {
|
||||
position: relative;
|
||||
border-width: 1.5px;
|
||||
border-style: solid;
|
||||
border-radius: 6px;
|
||||
transition:
|
||||
transform 0.08s ease,
|
||||
box-shadow 0.08s ease,
|
||||
background 0.15s ease,
|
||||
color 0.15s ease;
|
||||
}
|
||||
.btn-keycap:active:not(:disabled) {
|
||||
transform: translateY(5px);
|
||||
}
|
||||
.btn-keycap:disabled {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-keycap-solid {
|
||||
background: linear-gradient(180deg, #3a3a3a 0%, #1a1a1a 55%, #0e0e0e 100%);
|
||||
color: #ffffff;
|
||||
border-color: #000000;
|
||||
box-shadow:
|
||||
0 5px 0 0 #000000,
|
||||
0 10px 12px -5px rgba(0, 0, 0, 0.5),
|
||||
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.2),
|
||||
inset 0 -6px 9px -10px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
.btn-keycap-solid:hover:not(:disabled) {
|
||||
background: linear-gradient(180deg, #454545 0%, #232323 55%, #131313 100%);
|
||||
}
|
||||
.btn-keycap-solid:active:not(:disabled) {
|
||||
box-shadow:
|
||||
0 0 0 0 #000000,
|
||||
0 3px 5px -2px rgba(0, 0, 0, 0.5),
|
||||
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.14),
|
||||
inset 0 -5px 8px -10px rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.btn-keycap-ghost {
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f1f1ef 60%, #e5e5e2 100%);
|
||||
color: var(--color-ink);
|
||||
border-color: #bebebe;
|
||||
box-shadow:
|
||||
0 5px 0 0 #b0b0b0,
|
||||
0 10px 12px -6px rgba(0, 0, 0, 0.25),
|
||||
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.95),
|
||||
inset 0 -5px 8px -10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.btn-keycap-ghost:hover:not(:disabled) {
|
||||
background: linear-gradient(180deg, #ffffff 0%, #ececea 60%, #dcdcd9 100%);
|
||||
}
|
||||
.btn-keycap-ghost:active:not(:disabled) {
|
||||
box-shadow:
|
||||
0 0 0 0 #b0b0b0,
|
||||
0 3px 5px -2px rgba(0, 0, 0, 0.22),
|
||||
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.9),
|
||||
inset 0 -4px 7px -10px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.btn-keycap-destructive {
|
||||
background: linear-gradient(180deg, #d54040 0%, #b91c1c 55%, #9a1414 100%);
|
||||
color: #ffffff;
|
||||
border-color: #8a1313;
|
||||
box-shadow:
|
||||
0 5px 0 0 #7a0f0f,
|
||||
0 10px 12px -5px rgba(0, 0, 0, 0.4),
|
||||
inset 0 1.5px 0 0 rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
.btn-keycap-destructive:hover:not(:disabled) {
|
||||
background: linear-gradient(180deg, #e04848 0%, #c92020 55%, #aa1717 100%);
|
||||
}
|
||||
.btn-keycap-destructive:active:not(:disabled) {
|
||||
box-shadow:
|
||||
0 0 0 0 #7a0f0f,
|
||||
0 3px 5px -2px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
Reference in new issue
Block a user