mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-08 02:14:37 +00:00
8a2d89654b
Add a typed design-system package (Packages/ScarfDesign) with rust-tone color tokens, type scale, spacing/radius tokens, ScarfPageHeader and component primitives (ScarfCard, ScarfBadge, ScarfTextField, ScarfSectionHeader, ScarfDivider, four button styles). Both Mac and iOS targets `import ScarfDesign`. Sidebar redesigned per design/static-site/ui-kit/Sidebar.jsx — glassy translucent background, 224 px width, app-icon header with server pill, custom tokenized rows with rust accent-tint when active, footer with live Hermes-running indicator (wired to ServerLiveStatusRegistry). 14 mockup-backed feature screens redesigned: Settings, Dashboard, Sessions, Memory, Chat (visual sweep), Activity, Cron, Insights, MCPServers, Health, Logs, Tools (full); Projects light-touch. Non-mockup features inherit rust through AccentColor.colorset repoint. Mac AppIcon.appiconset replaced with the rust set. AccentColor.colorset repointed to BrandRust hex (light + dark variants). Visual sweep: every multi-button page-header / action-bar cluster now wraps in .fixedSize(horizontal: true, vertical: false) so labels can't wrap letter-by-letter at narrow widths (regression seen on the MCP detail pane with 4 buttons). Follow-ups landed: - Sidebar Hermes-running probe wired to per-window ServerLiveStatusRegistry (no more placeholder green). - Sessions: today filter predicate (isDateInToday(startedAt)); pill count reflects real count. Starred stays a no-op pending an upstream pinned/starred field on HermesSession. - Dashboard: Recent activity column rendered alongside Recent sessions in a ViewThatFits 2-col grid. Populated from HermesDataService.fetchRecentToolCalls(limit:) flattened to ActivityEntry. ActivityEntry gains a public memberwise init. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
188 lines
7.7 KiB
React
188 lines
7.7 KiB
React
|
|
// MacOS.jsx — Simplified macOS Tahoe (Liquid Glass) window
|
|
// Based on the macOS Tahoe UI Kit. No image assets, no dependencies.
|
|
// Exports: MacWindow, MacSidebar, MacSidebarItem, MacToolbar, MacGlass, MacTrafficLights
|
|
|
|
const MAC_FONT = '-apple-system, BlinkMacSystemFont, "SF Pro", "Helvetica Neue", sans-serif';
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Liquid glass primitive — blur + white tint + inset highlight
|
|
// ─────────────────────────────────────────────────────────────
|
|
function MacGlass({ children, radius = 296, dark = false, style = {} }) {
|
|
return (
|
|
<div style={{ position: 'relative', borderRadius: radius, ...style }}>
|
|
<div style={{
|
|
position: 'absolute', inset: 0, borderRadius: radius,
|
|
background: dark ? 'rgba(255,255,255,0.08)' : 'rgba(255,255,255,0.35)',
|
|
backdropFilter: 'blur(40px) saturate(180%)',
|
|
WebkitBackdropFilter: 'blur(40px) saturate(180%)',
|
|
border: dark ? '0.5px solid rgba(255,255,255,0.12)' : '0.5px solid rgba(255,255,255,0.6)',
|
|
boxShadow: dark
|
|
? '0 8px 40px rgba(0,0,0,0.2)'
|
|
: '0 8px 40px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.4)',
|
|
}} />
|
|
<div style={{ position: 'relative', zIndex: 1 }}>{children}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Traffic lights (14px, Tahoe colors)
|
|
// ─────────────────────────────────────────────────────────────
|
|
function MacTrafficLights({ style = {} }) {
|
|
const dot = (bg) => (
|
|
<div style={{
|
|
width: 14, height: 14, borderRadius: '50%', background: bg,
|
|
border: '0.5px solid rgba(0,0,0,0.1)',
|
|
}} />
|
|
);
|
|
return (
|
|
<div style={{ display: 'flex', gap: 9, alignItems: 'center', padding: 1, ...style }}>
|
|
{dot('#ff736a')}{dot('#febc2e')}{dot('#19c332')}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Toolbar — title + single glass pill icon
|
|
// ─────────────────────────────────────────────────────────────
|
|
function MacToolbar({ title = 'Folder' }) {
|
|
return (
|
|
<div style={{
|
|
display: 'flex', gap: 8, alignItems: 'center', padding: 8, flexShrink: 0,
|
|
}}>
|
|
{/* title */}
|
|
<div style={{
|
|
fontFamily: MAC_FONT, fontSize: 15, fontWeight: 700,
|
|
color: 'rgba(0,0,0,0.85)', whiteSpace: 'nowrap', paddingLeft: 8,
|
|
}}>{title}</div>
|
|
<div style={{ flex: 1 }} />
|
|
{/* single action */}
|
|
<MacGlass>
|
|
<div style={{
|
|
width: 36, height: 36, display: 'flex',
|
|
alignItems: 'center', justifyContent: 'center',
|
|
}}>
|
|
<div style={{ width: 14, height: 14, borderRadius: '50%', background: '#4c4c4c', opacity: 0.4 }} />
|
|
</div>
|
|
</MacGlass>
|
|
{/* search */}
|
|
<MacGlass>
|
|
<div style={{
|
|
width: 140, height: 36, display: 'flex', alignItems: 'center',
|
|
gap: 6, padding: '0 12px',
|
|
}}>
|
|
<svg width="13" height="13" viewBox="0 0 13 13" fill="none">
|
|
<circle cx="5.5" cy="5.5" r="4" stroke="#727272" strokeWidth="1.5"/>
|
|
<path d="M8.5 8.5l3 3" stroke="#727272" strokeWidth="1.5" strokeLinecap="round"/>
|
|
</svg>
|
|
<span style={{
|
|
fontFamily: MAC_FONT, fontSize: 13, fontWeight: 500, color: '#727272',
|
|
}}>Search</span>
|
|
</div>
|
|
</MacGlass>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Sidebar — frosted glass panel floating inside the window
|
|
// ─────────────────────────────────────────────────────────────
|
|
function MacSidebarItem({ label, selected = false }) {
|
|
return (
|
|
<div style={{
|
|
display: 'flex', alignItems: 'center', gap: 6,
|
|
height: 24, padding: '4px 10px 4px 6px', margin: '0 10px',
|
|
borderRadius: 8, position: 'relative',
|
|
fontFamily: MAC_FONT, fontSize: 11, fontWeight: 500,
|
|
}}>
|
|
{selected && (
|
|
<div style={{
|
|
position: 'absolute', inset: 0, borderRadius: 8,
|
|
background: 'rgba(0,0,0,0.11)', mixBlendMode: 'multiply',
|
|
}} />
|
|
)}
|
|
<div style={{
|
|
width: 14, height: 14, borderRadius: '50%',
|
|
background: selected ? '#007aff' : 'rgba(0,0,0,0.4)',
|
|
opacity: selected ? 1 : 0.5, flexShrink: 0, position: 'relative',
|
|
}} />
|
|
<span style={{ color: 'rgba(0,0,0,0.85)', position: 'relative' }}>{label}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function MacSidebar({ children }) {
|
|
return (
|
|
<div style={{
|
|
width: 220, height: '100%', padding: 8, flexShrink: 0,
|
|
position: 'relative', display: 'flex', flexDirection: 'column',
|
|
}}>
|
|
{/* glass panel */}
|
|
<div style={{
|
|
position: 'absolute', inset: 8, borderRadius: 18,
|
|
background: 'rgba(210,225,245,0.45)',
|
|
backdropFilter: 'blur(50px) saturate(200%)',
|
|
WebkitBackdropFilter: 'blur(50px) saturate(200%)',
|
|
border: '0.5px solid rgba(255,255,255,0.5)',
|
|
boxShadow: '0 8px 40px rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.35)',
|
|
}} />
|
|
{/* content */}
|
|
<div style={{
|
|
position: 'relative', zIndex: 1, padding: '10px 0',
|
|
display: 'flex', flexDirection: 'column', gap: 2,
|
|
}}>
|
|
{/* window controls + sidebar toggle */}
|
|
<div style={{
|
|
height: 32, display: 'flex', alignItems: 'center',
|
|
justifyContent: 'space-between', padding: '0 10px', marginBottom: 4,
|
|
}}>
|
|
<MacTrafficLights />
|
|
</div>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function MacSidebarHeader({ title }) {
|
|
return (
|
|
<div style={{
|
|
padding: '14px 18px 5px',
|
|
fontFamily: MAC_FONT, fontSize: 11, fontWeight: 700,
|
|
color: 'rgba(0,0,0,0.5)',
|
|
}}>{title}</div>
|
|
);
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Window — r:26, big shadow, sidebar + toolbar + content
|
|
// ─────────────────────────────────────────────────────────────
|
|
function MacWindow({
|
|
width = 900, height = 600, title = 'Folder',
|
|
sidebar, children,
|
|
}) {
|
|
return (
|
|
<div style={{
|
|
width, height, borderRadius: 26, overflow: 'hidden',
|
|
background: '#fff',
|
|
boxShadow: '0 0 0 1px rgba(0,0,0,0.23), 0 16px 48px rgba(0,0,0,0.35)',
|
|
display: 'flex', position: 'relative',
|
|
fontFamily: MAC_FONT,
|
|
}}>
|
|
<MacSidebar>{sidebar}</MacSidebar>
|
|
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
|
|
<MacToolbar title={title} />
|
|
<div style={{ flex: 1, overflow: 'auto', padding: '4px 8px' }}>
|
|
{children}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
Object.assign(window, {
|
|
MacWindow, MacSidebar, MacSidebarItem, MacSidebarHeader,
|
|
MacToolbar, MacGlass, MacTrafficLights,
|
|
});
|