mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-29 00:01:22 +00:00
Vertice restyle: fullscreen layout, lime/gray palette, mini-canvas project cards
- Token swap to near-black grays + lime accent + yellow secondary across index.css, all shared chart/card components, and every feature page - PlatformShell: 62px icon rail, 46px telemetry ticker topbar, containr wordmark, env pill; mobile header preserved - ProjectsPage rebuilt: cursor heading, host stat row (CPU sparkline, MEM/DISK meters, DEPLOYS), Railway-style mini-canvas project cards, mono deployment feed table - All layout-level max-w-[1400px] caps removed -> w-full px-8 - New lime containr.svg synced to public/, root, and dist - Auth glow, chart series colors, service-type colors retuned to palette - Demo mode now seeds representative host telemetry - Smoke test updated for new heading/copy Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
04d91bd69a
commit
37a56dc6b6
73 files changed
+3008
-487
No files matched your search
@@ -54,10 +54,10 @@ import {
|
||||
|
||||
function SecondaryPageHeader({ title, description }: { title: string; description: string }) {
|
||||
return (
|
||||
<div className="border-b border-[var(--border-subtle)] bg-[var(--bg-base)]/50 backdrop-blur-sm">
|
||||
<div className="mx-auto w-full max-w-[1400px] px-6 py-4">
|
||||
<h1 className="text-xl font-semibold text-[var(--text-primary)]">{title}</h1>
|
||||
<p className="text-sm text-[var(--text-secondary)] mt-1">{description}</p>
|
||||
<div className="border-b border-[var(--border-subtle)]">
|
||||
<div className="w-full px-8 py-5">
|
||||
<h1 className="v-title">{title}<span className="v-cursor">_</span></h1>
|
||||
<p className="v-mono mt-1.5 text-[11px] text-[var(--text-tertiary)]">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -302,7 +302,7 @@ containr-agent`;
|
||||
title="Usage"
|
||||
description="Platform usage metrics and operational summaries"
|
||||
/>
|
||||
<div className="mx-auto w-full max-w-[1400px] px-6 py-6">
|
||||
<div className="w-full px-8 py-6">
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<div className={`w-2 h-2 rounded-full ${liveStatus === 'live' ? 'bg-[var(--success)] animate-pulse' : 'bg-[var(--text-muted)]'}`} />
|
||||
<span className={`text-sm ${liveStatus === 'live' ? 'text-[var(--success)]' : 'text-[var(--text-muted)]'}`}>
|
||||
@@ -340,7 +340,7 @@ containr-agent`;
|
||||
statusText={failedBuilds > 0 ? `${failedBuilds} failed` : 'Healthy'}
|
||||
subtitle={buildActivityBody}
|
||||
icon={<Activity size={18} />}
|
||||
chart={<BarChart data={buildsPerDay} color="#e8316a" height={72} gap={3} />}
|
||||
chart={<BarChart data={buildsPerDay} color="var(--accent-primary)" height={72} gap={3} />}
|
||||
/>
|
||||
<EnhancedMetricCard
|
||||
title="Capacity"
|
||||
@@ -392,7 +392,7 @@ containr-agent`;
|
||||
status={hostStatus(hostLoadPercent)}
|
||||
statusText={host ? { good: 'Good', average: 'Average', warning: 'High' }[hostStatus(hostLoadPercent)] : ''}
|
||||
subtitle={host ? `${host.cpu.cores} cores · 5m ${host.load.load5m.toFixed(2)} · 15m ${host.load.load15m.toFixed(2)}` : 'Loading CPU telemetry.'}
|
||||
chart={<LineAreaChart data={loadHistory.length > 0 ? loadHistory : [0]} color="#ff7043" height={72} />}
|
||||
chart={<LineAreaChart data={loadHistory.length > 0 ? loadHistory : [0]} color="#b4e34a" height={72} />}
|
||||
/>
|
||||
<EnhancedMetricCard
|
||||
title="Memory"
|
||||
@@ -403,7 +403,7 @@ containr-agent`;
|
||||
subtitle={host ? `${formatBytes(host.memory.available)} free` : 'Loading memory telemetry.'}
|
||||
chart={
|
||||
<div className="relative mx-auto" style={{ width: 150 }}>
|
||||
<DonutChart percentage={host?.memory.usagePercent ?? 0} color="#9c7ef0" size={150} thickness={14} />
|
||||
<DonutChart percentage={host?.memory.usagePercent ?? 0} color="#f2c94c" size={150} thickness={14} />
|
||||
<div className="absolute inset-x-0 bottom-0 text-center">
|
||||
<div className="text-[10px] uppercase tracking-wide text-[#6b6e7d]">Used</div>
|
||||
<div className="text-sm font-bold text-[#e8e9f0]">
|
||||
@@ -600,7 +600,7 @@ export function PeoplePage() {
|
||||
title="People"
|
||||
description="Team management and access control"
|
||||
/>
|
||||
<div className="mx-auto w-full max-w-[1400px] px-6 py-6">
|
||||
<div className="w-full px-8 py-6">
|
||||
{profileQuery.isLoading ? (
|
||||
<div className="py-16 text-center">
|
||||
<Loader2 size={24} className="animate-spin mx-auto text-[var(--text-tertiary)]" />
|
||||
@@ -677,8 +677,8 @@ export function PeoplePage() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={createUserMutation.isPending}
|
||||
className="inline-flex h-10 items-center justify-center gap-2 rounded-[var(--radius-md)] px-4 text-sm font-semibold text-white disabled:opacity-60"
|
||||
style={{ background: '#e8316a' }}
|
||||
className="inline-flex h-10 items-center justify-center gap-2 rounded-[var(--radius-md)] px-4 text-sm font-semibold text-[var(--accent-on)] disabled:opacity-60"
|
||||
style={{ background: 'var(--accent-primary)' }}
|
||||
>
|
||||
{createUserMutation.isPending ? <Loader2 size={14} className="animate-spin" /> : <UserPlus size={14} />}
|
||||
Create
|
||||
@@ -764,8 +764,8 @@ function GitProvidersSection() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setFormOpen((open) => !open)}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-white text-sm font-medium shadow-lg transition-all"
|
||||
style={{ background: '#e8316a' }}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-[var(--accent-on)] text-sm font-medium shadow-lg transition-all"
|
||||
style={{ background: 'var(--accent-primary)' }}
|
||||
>
|
||||
<Link2 size={14} />
|
||||
{formOpen ? 'Close' : 'Connect'}
|
||||
@@ -880,8 +880,8 @@ function GitProvidersSection() {
|
||||
<button
|
||||
onClick={() => createMutation.mutate()}
|
||||
disabled={!form.accessToken.trim() || createMutation.isPending}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-white text-sm font-medium shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
style={{ background: '#e8316a' }}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-[var(--accent-on)] text-sm font-medium shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
style={{ background: 'var(--accent-primary)' }}
|
||||
>
|
||||
{createMutation.isPending ? <Loader2 size={14} className="animate-spin" /> : <Check size={14} />}
|
||||
Connect Provider
|
||||
@@ -964,7 +964,7 @@ export function SettingsPage() {
|
||||
title="Settings"
|
||||
description="Manage account profile and local configuration"
|
||||
/>
|
||||
<div className="mx-auto w-full max-w-[1400px] px-6 py-6">
|
||||
<div className="w-full px-8 py-6">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
||||
{/* Profile Section */}
|
||||
<section className="panel p-6">
|
||||
@@ -1015,8 +1015,8 @@ export function SettingsPage() {
|
||||
<button
|
||||
onClick={() => updateProfileMutation.mutate()}
|
||||
disabled={!hasProfileChanges || updateProfileMutation.isPending}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-white text-sm font-medium shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
style={{ background: '#e8316a' }}
|
||||
className="flex items-center gap-2 h-9 px-4 rounded-[var(--radius-md)] text-[var(--accent-on)] text-sm font-medium shadow-lg disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
style={{ background: 'var(--accent-primary)' }}
|
||||
>
|
||||
{updateProfileMutation.isPending ? (
|
||||
<>
|
||||
@@ -1185,7 +1185,7 @@ export function DocsPage() {
|
||||
title="Docs"
|
||||
description="Operational references and API documentation"
|
||||
/>
|
||||
<div className="mx-auto w-full max-w-[1400px] px-6 py-6">
|
||||
<div className="w-full px-8 py-6">
|
||||
{/* API Status Grid */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
<div className="panel p-4">
|
||||
|
||||
@@ -37,15 +37,15 @@ export function ComponentShowcase() {
|
||||
<div className="min-h-screen p-8" style={{ background: '#16171c' }}>
|
||||
<div className="ambient-glow" />
|
||||
|
||||
<div className="max-w-7xl mx-auto relative z-10">
|
||||
<div className="w-full relative z-10">
|
||||
{/* Header */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div
|
||||
className="w-12 h-12 rounded-xl flex items-center justify-center"
|
||||
style={{ background: '#e8316a' }}
|
||||
style={{ background: 'var(--accent-primary)' }}
|
||||
>
|
||||
<Activity size={24} className="text-white" />
|
||||
<Activity size={24} className="text-[var(--accent-on)]" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-[var(--text-primary)]">
|
||||
@@ -97,7 +97,7 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<LineChart
|
||||
data={sampleLineData}
|
||||
color="#ff7043"
|
||||
color="#b4e34a"
|
||||
height={120}
|
||||
showDots={true}
|
||||
smooth={true}
|
||||
@@ -109,7 +109,7 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<LineChart
|
||||
data={sampleLineData}
|
||||
color="#6c8ef0"
|
||||
color="#7ab8ff"
|
||||
height={120}
|
||||
showDots={false}
|
||||
smooth={true}
|
||||
@@ -129,7 +129,7 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<LineAreaChart
|
||||
data={sampleAreaData}
|
||||
color="#e8316a"
|
||||
color="var(--accent-primary)"
|
||||
fillOpacity={0.15}
|
||||
height={150}
|
||||
/>
|
||||
@@ -140,7 +140,7 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<LineAreaChart
|
||||
data={sampleAreaData}
|
||||
color="#3dd68c"
|
||||
color="#5ee6a0"
|
||||
fillOpacity={0.2}
|
||||
height={150}
|
||||
/>
|
||||
@@ -159,8 +159,8 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<MultiLineChart
|
||||
datasets={[
|
||||
{ data: sampleLineData.map(v => v + 10), color: '#6c8ef0', fillOpacity: 0.15 },
|
||||
{ data: sampleLineData, color: '#9c7ef0', fillOpacity: 0.15 }
|
||||
{ data: sampleLineData.map(v => v + 10), color: '#7ab8ff', fillOpacity: 0.15 },
|
||||
{ data: sampleLineData, color: '#f2c94c', fillOpacity: 0.15 }
|
||||
]}
|
||||
height={120}
|
||||
/>
|
||||
@@ -171,7 +171,7 @@ export function ComponentShowcase() {
|
||||
</h3>
|
||||
<BarChart
|
||||
data={sampleBarData}
|
||||
color="#3dd68c"
|
||||
color="#5ee6a0"
|
||||
height={120}
|
||||
gap={2}
|
||||
/>
|
||||
@@ -188,19 +188,19 @@ export function ComponentShowcase() {
|
||||
<h3 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
RAM Usage (65%)
|
||||
</h3>
|
||||
<DonutChart percentage={65} color="#9c7ef0" size={160} />
|
||||
<DonutChart percentage={65} color="#f2c94c" size={160} />
|
||||
</div>
|
||||
<div className="panel p-6 flex flex-col items-center">
|
||||
<h3 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
Disk Usage (82%)
|
||||
</h3>
|
||||
<DonutChart percentage={82} color="#ff7043" size={160} />
|
||||
<DonutChart percentage={82} color="#b4e34a" size={160} />
|
||||
</div>
|
||||
<div className="panel p-6 flex flex-col items-center">
|
||||
<h3 className="text-sm font-medium text-[var(--text-secondary)] mb-4">
|
||||
Network (45%)
|
||||
</h3>
|
||||
<DonutChart percentage={45} color="#6c8ef0" size={160} />
|
||||
<DonutChart percentage={45} color="#7ab8ff" size={160} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -222,7 +222,7 @@ export function ComponentShowcase() {
|
||||
status="good"
|
||||
statusText="Good"
|
||||
icon={<Cpu size={16} />}
|
||||
chart={<LineChart data={sampleLineData} color="#ff7043" height={76} />}
|
||||
chart={<LineChart data={sampleLineData} color="#b4e34a" height={76} />}
|
||||
onClick={() => handleCardClick('CPU Usage')}
|
||||
animationDelay={0.04}
|
||||
/>
|
||||
@@ -233,7 +233,7 @@ export function ComponentShowcase() {
|
||||
status="average"
|
||||
statusText="Average"
|
||||
icon={<MemoryStick size={16} />}
|
||||
chart={<LineChart data={sampleLineData.map(v => v + 20)} color="#9c7ef0" height={76} />}
|
||||
chart={<LineChart data={sampleLineData.map(v => v + 20)} color="#f2c94c" height={76} />}
|
||||
onClick={() => handleCardClick('Memory')}
|
||||
animationDelay={0.09}
|
||||
/>
|
||||
@@ -242,7 +242,7 @@ export function ComponentShowcase() {
|
||||
value="2.4K"
|
||||
subtitle="Last 60 minutes"
|
||||
icon={<Zap size={16} />}
|
||||
chart={<BarChart data={sampleBarData} color="#3dd68c" height={76} gap={2} />}
|
||||
chart={<BarChart data={sampleBarData} color="#5ee6a0" height={76} gap={2} />}
|
||||
onClick={() => handleCardClick('Requests')}
|
||||
animationDelay={0.14}
|
||||
/>
|
||||
@@ -259,7 +259,7 @@ export function ComponentShowcase() {
|
||||
value="475 K"
|
||||
subtitle="Users active right now"
|
||||
icon={<Users size={16} />}
|
||||
chart={<LineAreaChart data={sampleAreaData} color="#e8316a" height={130} />}
|
||||
chart={<LineAreaChart data={sampleAreaData} color="var(--accent-primary)" height={130} />}
|
||||
details={
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{['🇨🇳', '🇮🇩', '🇲🇲', '🇲🇾', '🇯🇵', '🇮🇳', '🇰🇷', '🇵🇭'].map((flag, i) => (
|
||||
@@ -276,7 +276,7 @@ export function ComponentShowcase() {
|
||||
value="12.5K"
|
||||
subtitle="Queries per minute"
|
||||
icon={<Database size={16} />}
|
||||
chart={<LineAreaChart data={sampleAreaData.map(v => v + 10)} color="#6c8ef0" height={130} />}
|
||||
chart={<LineAreaChart data={sampleAreaData.map(v => v + 10)} color="#7ab8ff" height={130} />}
|
||||
details={
|
||||
<div className="flex items-center gap-3 text-xs">
|
||||
<div className="flex items-center gap-1.5">
|
||||
@@ -313,8 +313,8 @@ export function ComponentShowcase() {
|
||||
upSpeed={10.4}
|
||||
downSpeed={5.2}
|
||||
datasets={[
|
||||
{ data: sampleLineData.map(v => v + 20), color: '#6c8ef0', fillOpacity: 0.15 },
|
||||
{ data: sampleLineData.map(v => v + 10), color: '#9c7ef0', fillOpacity: 0.15 }
|
||||
{ data: sampleLineData.map(v => v + 20), color: '#7ab8ff', fillOpacity: 0.15 },
|
||||
{ data: sampleLineData.map(v => v + 10), color: '#f2c94c', fillOpacity: 0.15 }
|
||||
]}
|
||||
onClick={() => handleCardClick('Performance')}
|
||||
animationDelay={0.09}
|
||||
|
||||
Reference in new issue
Block a user