feat(ui): full frontend redesign to the Sentry-style design system

Replace the legacy UI with the dark, mono-accent design language from
design/23-sentry.html across every non-canvas surface.

- PlatformShell: fixed 252px sidebar with grouped nav (Platform /
  Operate / Workspace), brand mark, user card, and a topbar with
  search (Cmd+K palette), env badge, upgrade, notifications, and
  theme toggle; mobile collapses to a top bar with horizontal nav
- New shared component kit in shared/components/sentry.tsx:
  SPageHead, SStat, SCard, STable, SSection, SPill, Ticks, Seg,
  GhostBtn/QuietBtn/IconBtn, status tone helpers
- New DashboardPage at / — stats row, per-node CPU chart with
  1h/24h/7d ranges, resource usage tick strips, anomaly box,
  node summary table, recent deployments and project cards;
  real API data with demo-mode fixtures
- Landing page moved to /landing and rebuilt: live host telemetry
  window, install strip, feature grid, template catalog, docs
- Every page (Projects, Templates, Builds, Databases, HA,
  Operations, Activity, Security, Usage, Docs, People, Settings,
  Audit Logs, Webhooks, Admin, NodeDetail, ServiceDetail, auth,
  setup, not-found) migrated to the new kit and tokens
- Nav active state resolves by longest matching href
- Canvas internals intentionally untouched — separate pass

Verified: tsc --noEmit, eslint, vite build, Playwright walkthrough
of every route at desktop and mobile widths (demo + live session).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-10-10 16:42:26 +02:00
1 parent a05d225016
commit 24b9b1267e
42 files changed
+4077 -3018

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -78,8 +78,8 @@ export function ServiceMetricsDashboard() {
userData,
perf: perfPercent,
perfData: [
{ data: perfData1, color: '#7ab8ff', fillOpacity: 0.15 },
{ data: perfData2, color: '#f2c94c', fillOpacity: 0.15 }
{ data: perfData1, color: 'var(--accent-primary)', fillOpacity: 0.15 },
{ data: perfData2, color: 'var(--warning)', fillOpacity: 0.15 }
],
upSpeed: seededRandom(`${serviceId}:upspeed`, 8, 13).toFixed(1),
downSpeed: seededRandom(`${serviceId}:downspeed`, 4, 7).toFixed(1),
@@ -107,9 +107,8 @@ export function ServiceMetricsDashboard() {
};
return (
<div className="min-h-screen" style={{ background: '#16171c' }}>
<div className="min-h-screen" style={{ background: 'var(--bg-void)' }}>
{/* Ambient glow */}
<div className="ambient-glow" />
<div className="flex min-h-screen relative">
{/* Sidebar - self.html exact match */}
@@ -117,8 +116,8 @@ export function ServiceMetricsDashboard() {
className="hidden md:flex shrink-0 flex-col items-center border-r"
style={{
width: '64px',
background: '#111217',
borderRight: '1px solid rgba(255,255,255,0.07)',
background: 'var(--bg-surface)',
borderRight: '1px solid var(--border-subtle)',
padding: '16px 0',
gap: '5px'
}}
@@ -169,10 +168,10 @@ export function ServiceMetricsDashboard() {
style={{
width: '34px',
height: '34px',
background: '#22233a',
background: 'var(--accent-primary-soft)',
fontSize: '11px',
fontWeight: 700,
color: '#9295a4',
color: 'var(--text-tertiary)',
marginTop: '4px',
letterSpacing: '-0.3px'
}}
@@ -188,8 +187,8 @@ export function ServiceMetricsDashboard() {
className="shrink-0 flex items-center"
style={{
height: '52px',
background: '#111217',
borderBottom: '1px solid rgba(255,255,255,0.07)',
background: 'var(--bg-surface)',
borderBottom: '1px solid var(--border-subtle)',
padding: '0 22px',
gap: '14px'
}}
@@ -201,22 +200,22 @@ export function ServiceMetricsDashboard() {
<div className="ml-auto flex items-center" style={{ gap: '8px' }}>
<button
className="rounded-[9px] border bg-transparent text-[#9295a4] font-medium cursor-pointer"
className="rounded-[9px] border bg-transparent text-[var(--text-tertiary)] font-medium cursor-pointer"
style={{
height: '32px',
padding: '0 14px',
border: '1px solid rgba(255,255,255,0.1)',
border: '1px solid var(--border-default)',
fontSize: '13px'
}}
>
Support
</button>
<button
className="rounded-[9px] border-none flex items-center text-[#e8e9f0] font-medium cursor-pointer"
className="rounded-[9px] border-none flex items-center text-[var(--text-primary)] font-medium cursor-pointer"
style={{
height: '32px',
padding: '0 14px',
background: 'rgba(255,255,255,0.08)',
background: 'var(--bg-overlay)',
fontSize: '13px',
gap: '6px'
}}
@@ -229,10 +228,10 @@ export function ServiceMetricsDashboard() {
style={{
width: '32px',
height: '32px',
border: '1px solid rgba(255,255,255,0.1)'
border: '1px solid var(--border-default)'
}}
>
<Bell size={15} color="#9295a4" />
<Bell size={15} />
</button>
</div>
</header>
@@ -245,22 +244,22 @@ export function ServiceMetricsDashboard() {
style={{
gap: '6px',
padding: '14px 0 10px',
color: '#6b6e7d',
color: 'var(--text-tertiary)',
fontSize: '13px'
}}
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#6b6e7d" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--text-tertiary)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="15 18 9 12 15 6"/>
</svg>
<button
onClick={() => navigate(-1)}
style={{ color: '#6b6e7d' }}
className="hover:text-[#9295a4] transition-colors"
style={{ color: 'var(--text-tertiary)' }}
className="hover:text-[var(--text-tertiary)] transition-colors"
>
Servers
</button>
<span style={{ opacity: 0.4 }}>/</span>
<span style={{ color: '#9295a4' }}>[NuFest] - App Project</span>
<span style={{ color: 'var(--text-tertiary)' }}>[NuFest] - App Project</span>
</div>
{/* Project Header */}
@@ -280,7 +279,7 @@ export function ServiceMetricsDashboard() {
</div>
<div>
<div className="flex items-center" style={{ gap: '10px' }}>
<span style={{ fontSize: '20px', fontWeight: 800, letterSpacing: '-0.5px', color: '#e8e9f0' }}>
<span style={{ fontSize: '20px', fontWeight: 800, letterSpacing: '-0.5px', color: 'var(--text-primary)' }}>
[NuFest] - App Project
</span>
<span className={`badge-${isSystemRunning ? 'active' : 'stopped'}`}>
@@ -293,8 +292,8 @@ export function ServiceMetricsDashboard() {
href="https://nufest-dth.app"
target="_blank"
rel="noopener noreferrer"
className="flex items-center hover:text-[#9295a4] transition-colors"
style={{ color: '#6b6e7d', fontSize: '12.5px', textDecoration: 'none', gap: '4px' }}
className="flex items-center hover:text-[var(--text-tertiary)] transition-colors"
style={{ color: 'var(--text-tertiary)', fontSize: '12.5px', textDecoration: 'none', gap: '4px' }}
>
https://nufest-dth.app
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
@@ -304,8 +303,8 @@ export function ServiceMetricsDashboard() {
</svg>
</a>
<button
className="flex items-center hover:text-[#9295a4] transition-colors"
style={{ color: '#6b6e7d', fontSize: '12.5px', gap: '4px' }}
className="flex items-center hover:text-[var(--text-tertiary)] transition-colors"
style={{ color: 'var(--text-tertiary)', fontSize: '12.5px', gap: '4px' }}
>
Project Information
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
@@ -344,7 +343,7 @@ export function ServiceMetricsDashboard() {
<div
className="flex"
style={{
borderBottom: '1px solid rgba(255,255,255,0.07)',
borderBottom: '1px solid var(--border-subtle)',
marginBottom: '18px'
}}
>
@@ -365,16 +364,16 @@ export function ServiceMetricsDashboard() {
{/* Metrics Header */}
<div className="flex items-center justify-between" style={{ marginBottom: '16px' }}>
<span style={{ fontSize: '15px', fontWeight: 700, color: '#e8e9f0' }}>Metrics</span>
<span style={{ fontSize: '15px', fontWeight: 700, color: 'var(--text-primary)' }}>Metrics</span>
<div className="flex items-center" style={{ gap: '8px' }}>
<button
className="rounded-[9px] border flex items-center font-medium cursor-pointer"
style={{
height: '32px',
padding: '0 12px',
border: '1px solid rgba(255,255,255,0.09)',
background: 'rgba(255,255,255,0.04)',
color: '#9295a4',
border: '1px solid var(--border-default)',
background: 'var(--bg-elevated)',
color: 'var(--text-tertiary)',
fontSize: '12.5px',
gap: '6px'
}}
@@ -408,7 +407,7 @@ export function ServiceMetricsDashboard() {
status="good"
statusText="Good"
icon={<Cpu size={16} />}
chart={<LineChart data={metrics.cpuData} color="#b4e34a" height={76} />}
chart={<LineChart data={metrics.cpuData} color="#38bdf8" height={76} />}
animationDelay={0.04}
/>
@@ -418,23 +417,23 @@ export function ServiceMetricsDashboard() {
<div className="card-icon">
<MemoryStick size={16} />
</div>
<span style={{ fontSize: 14, fontWeight: 600, color: '#e8e9f0' }}>RAM Usage</span>
<span style={{ fontSize: 14, fontWeight: 600, color: 'var(--text-primary)' }}>RAM Usage</span>
</div>
<div style={{ fontSize: 38, fontWeight: 900, letterSpacing: '-1.5px', lineHeight: 1, color: '#e8e9f0' }}>
<div style={{ fontSize: 38, fontWeight: 900, letterSpacing: '-1.5px', lineHeight: 1, color: 'var(--text-primary)' }}>
{metrics.ram}%
</div>
<div style={{ fontSize: 12, color: '#6b6e7d', marginTop: 4 }}>
<span style={{ color: '#f2c94c', fontWeight: 700 }}>Average</span> Daily usage
<div style={{ fontSize: 12, color: 'var(--text-tertiary)', marginTop: 4 }}>
<span style={{ color: 'var(--warning)', fontWeight: 700 }}>Average</span> Daily usage
</div>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', margin: '10px 0 4px', position: 'relative' }}>
<DonutChart percentage={metrics.ram} color="#f2c94c" />
<DonutChart percentage={metrics.ram} color="var(--warning)" />
<div style={{ position: 'absolute', bottom: 14, textAlign: 'center' }}>
<div style={{ fontSize: 10.5, color: '#6b6e7d', marginBottom: 1 }}>Used</div>
<div style={{ fontSize: 12.5, fontWeight: 700, color: '#e8e9f0' }}>{metrics.ramUsedGB} GB / 8GB</div>
<div style={{ fontSize: 10.5, color: 'var(--text-tertiary)', marginBottom: 1 }}>Used</div>
<div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text-primary)' }}>{metrics.ramUsedGB} GB / 8GB</div>
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingTop: 4 }}>
<span style={{ fontSize: 13, color: '#6b6e7d', fontWeight: 500, cursor: 'pointer' }}>Details</span>
<span style={{ fontSize: 13, color: 'var(--text-tertiary)', fontWeight: 500, cursor: 'pointer' }}>Details</span>
<div className="arrow-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round">
<polyline points="9 18 15 12 9 6" />