diff --git a/frontend/src/components/dashboard/BandwidthChart.tsx b/frontend/src/components/dashboard/BandwidthChart.tsx index d4af369..da9b527 100644 --- a/frontend/src/components/dashboard/BandwidthChart.tsx +++ b/frontend/src/components/dashboard/BandwidthChart.tsx @@ -78,7 +78,7 @@ export function BandwidthChart({ devices }: BandwidthChartProps) { @@ -86,19 +86,19 @@ export function BandwidthChart({ devices }: BandwidthChartProps) { type="category" dataKey="hostname" width={120} - tick={{ fontSize: 11, fill: '#cbd5e1' }} + tick={{ fontSize: 10, fill: 'hsl(var(--text-secondary))' }} axisLine={false} tickLine={false} /> } - cursor={{ fill: '#334155', opacity: 0.5 }} + cursor={{ fill: 'hsl(var(--elevated))', opacity: 0.5 }} /> diff --git a/frontend/src/components/dashboard/EventsTimeline.tsx b/frontend/src/components/dashboard/EventsTimeline.tsx index ba6395c..17cb0aa 100644 --- a/frontend/src/components/dashboard/EventsTimeline.tsx +++ b/frontend/src/components/dashboard/EventsTimeline.tsx @@ -2,7 +2,6 @@ import { useState } from 'react' import { useQuery } from '@tanstack/react-query' import { Bell, Server, HardDrive } from 'lucide-react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Skeleton } from '@/components/ui/skeleton' import { cn } from '@/lib/utils' import { eventsApi, type DashboardEvent, type EventsParams } from '@/lib/eventsApi' import { DeviceLink } from '@/components/ui/device-link' @@ -83,22 +82,6 @@ function EventIcon({ event }: { event: DashboardEvent }) { } } -function TimelineSkeleton() { - return ( -
- {Array.from({ length: 5 }).map((_, i) => ( -
- -
- - -
- -
- ))} -
- ) -} export function EventsTimeline({ tenantId, isSuperAdmin }: EventsTimelineProps) { const [filterType, setFilterType] = useState(undefined) @@ -115,86 +98,79 @@ export function EventsTimeline({ tenantId, isSuperAdmin }: EventsTimelineProps) }) return ( - - -
- - Recent Events - -
- {FILTERS.map((f) => ( - - ))} -
+
+
+ + Recent Events + +
+ {FILTERS.map((f) => ( + + ))}
- - +
+
{isSuperAdmin && !tenantId ? ( -
+
Select a tenant to view events
) : isLoading ? ( - +
+ Loading… +
) : !events || events.length === 0 ? ( -
+
No recent events
) : ( -
-
- {events.map((event) => ( -
- {/* Icon positioned over the timeline line */} -
- -
- - {/* Content */} -
-

- {event.title} -

-

- {event.description} - {event.device_hostname && ( - - —{' '} - {event.device_id ? ( - - {event.device_hostname} - - ) : ( - event.device_hostname - )} - - )} -

-
- - {/* Timestamp */} - - {formatRelativeTime(event.timestamp)} +
+ {events.map((event) => ( +
+
+ +
+
+ + {event.title} + + + {event.description} + {event.device_hostname && ( + + —{' '} + {event.device_id ? ( + + {event.device_hostname} + + ) : ( + event.device_hostname + )} + + )}
- ))} -
+ + {formatRelativeTime(event.timestamp)} + +
+ ))}
)} - - +
+
) } diff --git a/frontend/src/components/dashboard/KpiCards.tsx b/frontend/src/components/dashboard/KpiCards.tsx index 553f4be..4931b76 100644 --- a/frontend/src/components/dashboard/KpiCards.tsx +++ b/frontend/src/components/dashboard/KpiCards.tsx @@ -44,45 +44,31 @@ function KpiCard({ const animatedValue = useAnimatedCounter(value, 800, decimals) return ( - - -
-
- - {label} - -
- - {decimals > 0 ? animatedValue.toFixed(decimals) : animatedValue} - - {suffix && ( - - {suffix} - - )} -
-
-
- {icon} -
-
-
-
+
+ {label} +
+
+ + {decimals > 0 ? animatedValue.toFixed(decimals) : animatedValue} + + {suffix && ( + + {suffix} + + )} +
+
) } diff --git a/frontend/src/components/dashboard/QuickActions.tsx b/frontend/src/components/dashboard/QuickActions.tsx index 72beb62..12f906c 100644 --- a/frontend/src/components/dashboard/QuickActions.tsx +++ b/frontend/src/components/dashboard/QuickActions.tsx @@ -72,34 +72,38 @@ export function QuickActions({ tenantId, isSuperAdmin }: QuickActionsProps) { const actions = getActions(tenantId, isSuperAdmin) return ( - - - +
+
+ Quick Actions - - - -
- {actions.map((action) => ( - -
- {action.icon} -
- + +
+
+ {actions.map((action) => ( + +
+ {action.icon} +
+
+ {action.label} - - ))} -
- - + + {action.description} + +
+ + ))} +
+
) } diff --git a/frontend/src/index.css b/frontend/src/index.css index 90eb620..f5a0cb9 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -35,10 +35,10 @@ --elevated: 39 22% 92%; /* #f0ede4 */ --border-subtle: 30 18% 13% / 0.06; - --border-default: 30 18% 13% / 0.12; + --border-default: 30 18% 13% / 0.14; --text-primary: 43 27% 8%; /* #1a1810 */ - --text-secondary: 40 10% 33%; /* #5e5a4e */ + --text-secondary: 40 12% 30%; /* #564e42 — slightly darker for dense readability */ --text-muted: 36 7% 50%; /* #8a8578 */ --accent: 43 32% 40%; /* #8a7a48 */ diff --git a/web_redesign.md b/web_redesign.md new file mode 100644 index 0000000..9bff9b7 --- /dev/null +++ b/web_redesign.md @@ -0,0 +1,152 @@ +We need to redesign the website to remove all startup / SaaS / marketing patterns. + +Current issue: +It feels too “salesy” and corporate — like a product trying to convince people to use it. + +That is the wrong tone. + +--- + +## Core direction + +This should feel like: +- a tool +- a system +- a project that exists because it needed to exist + +NOT: +- a startup landing page +- a marketing funnel +- a conversion-optimized site + +--- + +## Tone + +- Direct +- Honest +- Slightly indifferent to whether the user signs up +- No hype language +- No promises +- No “transform your workflow” nonsense + +--- + +## Remove immediately + +- Any “hero pitch” language +- Any “why choose us” sections +- Any fake trust signals (logos, testimonials, “companies use this”) +- Any email capture / gated content +- Any “Get Started Now” pressure CTAs + +--- + +## Replace with + +### 1. Simple top section + +- Project name +- One blunt sentence describing what it is +- Links: + - GitHub + - Docs + - Download / Self-host + - SaaS (optional, not emphasized) + +Example tone: +“This is a network control system. It’s in active development. Things may break.” + +--- + +### 2. “What it does” (not marketing) + +- Bullet points +- No adjectives +- No hype + +Bad: +“Powerful, scalable, next-gen network automation” + +Good: +- Monitor device state +- Push configuration +- Track changes +- Run commands across devices + +--- + +### 3. “What it is not” + +This is important for your voice. + +Example: +- Not finished +- Not stable +- Not for everyone +- Not trying to replace everything + +--- + +### 4. Screenshots + +- Real UI +- No mockups +- No gradients / marketing framing +- No captions trying to sell + +--- + +### 5. Development status + +- Be explicit: + - versioning + - breaking changes + - expectations + +--- + +### 6. Pricing (if present) + +- Simple +- No anchoring tricks +- No “save 20%” +- No fake urgency + +--- + +## Visual direction + +- Use the same Warm Precision system +- No big hero sections +- No oversized typography +- No soft gradients +- No “landing page layout” + +Layout should feel like: +- documentation +- system panel +- terminal-adjacent + +--- + +## Anti-pattern check + +If any section feels like: +- it’s trying to convince the user +- it’s trying to impress the user +- it’s trying to capture the user + +Remove or rewrite it. + +--- + +## Goal + +The site should feel like: + +“This exists. If you need it, you’ll understand it.” + +Not: + +“Please use this product.”