2 Commits

Author SHA1 Message Date
26424469db feat: center hints over the timeline + add hubris footer
- KeyboardHints: switch from fixed positioning to absolute, mounted
  inside the main content column. The column is now relative-positioned
  so the hints overlay centers against the timeline area instead of the
  raw viewport (which was off-center because of the sidebars).
- AppFooter: tiny "Built with hubris • <YEAR in roman>" pinned to the
  bottom-right corner of the main column. Year is computed at render
  time and converted via a small toRoman helper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:34:18 +02:00
ec4a14976d style: switch primary accent from teal to deep royal blue
Replace #4f98a3 (desaturated teal) with #3b6ed8 (deep royal blue) as
the app's primary accent. Affects every text-primary, bg-primary,
ring-primary, border-primary class — selection rings, active sidebar
rows, the active filter pill background, the loupe info button when
open, etc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 21:30:46 +02:00
5 changed files with 59 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import { TopBar } from './components/layout/TopBar'
import { ScanProgress } from './components/ScanProgress'
import { ToastContainer } from './components/ToastContainer'
import { KeyboardHints } from './components/KeyboardHints'
import { AppFooter } from './components/AppFooter'
import { PreviewView } from './components/preview/PreviewView'
import { FilterBar } from './components/filter/FilterBar'
import { DiscardActionBar } from './components/discard/DiscardActionBar'
@@ -66,13 +67,19 @@ function App() {
{/* Main column — filter bar, discard bar, timeline. Lives to the
* right of the left sidebar so the filter row doesn't bleed
* across the sidebar. */}
<div className="flex min-w-0 flex-1 flex-col">
* across the sidebar. relative so the KeyboardHints overlay
* centers against this column, not the viewport. */}
<div className="relative flex min-w-0 flex-1 flex-col">
<FilterBar />
<DiscardActionBar />
<div className="flex-1 overflow-auto">
<Timeline />
</div>
{/* Floating keyboard hints — bottom-center of the main column,
* glassy. Mounted here so it's centered against the timeline,
* not the viewport (which would be offset by the sidebars). */}
<KeyboardHints />
<AppFooter />
</div>
{/* Right Sidebar */}
@@ -85,10 +92,6 @@ function App() {
</div>
</div>
{/* Floating keyboard hints — pinned bottom-center, glassy. Sits
* above the timeline and below the toast layer. */}
<KeyboardHints />
{/* Scan Progress Indicator */}
<ScanProgress />

View File

@@ -0,0 +1,43 @@
/**
* Tiny corner footer pinned to the bottom-right of the main column.
* Renders "Built with hubris • <year in roman numerals>", refreshed
* once per page load.
*/
const ROMAN_PAIRS: [number, string][] = [
[1000, 'M'],
[900, 'CM'],
[500, 'D'],
[400, 'CD'],
[100, 'C'],
[90, 'XC'],
[50, 'L'],
[40, 'XL'],
[10, 'X'],
[9, 'IX'],
[5, 'V'],
[4, 'IV'],
[1, 'I'],
]
function toRoman(n: number): string {
let result = ''
for (const [value, symbol] of ROMAN_PAIRS) {
while (n >= value) {
result += symbol
n -= value
}
}
return result
}
export function AppFooter() {
const year = new Date().getFullYear()
return (
<div className="pointer-events-none absolute bottom-2 right-3 z-10 text-[10px] text-text-faint">
<span className="pointer-events-auto">
Built with hubris {toRoman(year)}
</span>
</div>
)
}

View File

@@ -25,7 +25,11 @@ export function KeyboardHints() {
]
return (
<div className="pointer-events-none fixed bottom-4 left-1/2 z-30 -translate-x-1/2">
// Absolute (not fixed) so the parent's flex/position context can
// center it relative to the timeline area, not the viewport. Mount
// inside the main column in App.tsx so it isn't offset by the
// sidebar widths.
<div className="pointer-events-none absolute bottom-4 left-1/2 z-30 -translate-x-1/2">
<div className="pointer-events-auto flex items-center gap-3 rounded-full border border-border/60 bg-surface/40 px-4 py-1.5 shadow-lg ring-1 ring-white/5 backdrop-blur-md">
{hints.map((hint, i) => (
<div key={i} className="flex items-center gap-1.5">

View File

@@ -12,7 +12,7 @@
--color-text: #e8e6e0;
--color-text-muted: #878580;
--color-text-faint: #4a4845;
--color-primary: #4f98a3;
--color-primary: #3b6ed8;
--color-pick: #4f9e5c;
--color-reject: #c25a5a;
--color-star: #d4a340;

View File

@@ -17,7 +17,7 @@ export default {
text: '#e8e6e0',
'text-muted': '#878580',
'text-faint': '#4a4845',
primary: '#4f98a3', // desaturated teal
primary: '#3b6ed8', // deep royal blue
pick: '#4f9e5c', // green for picked
reject: '#c25a5a', // red for rejected
star: '#d4a340', // amber for stars