mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-06-03 15:02:56 +00:00
ci: update docker build workflow and refine frontend theme
Refactor the CI/CD pipeline to use Docker Buildx for more efficient builds and implement automated image tagging and pushing to GHCR. On the frontend, update the theme system to use a neutral zinc-based dark mode instead of the previous warm dark theme. This includes: - Updating CSS variables in `globals.css` for a more consistent neutral palette. - Replacing `ring` color usage with `muted-foreground` in various UI components to align with the new design language. - Adjusting component backgrounds (e.g., `Header`, `Input`, `WidgetCard`) to use `bg-card` for better visual layering. - Simplifying component styles and removing unnecessary gradients.
This commit is contained in:
+28
-28
@@ -31,28 +31,28 @@
|
||||
--font-geist-mono: "Geist Mono", "ui-monospace", "SFMono-Regular", "Roboto Mono", monospace;
|
||||
}
|
||||
|
||||
/* ── Dark (Rich warm dark — not pure black) ── */
|
||||
/* ── Dark (Neutral zinc-dark — no blue, layered depth) ── */
|
||||
[data-theme="dark"] {
|
||||
--color-background: #0d0d0d;
|
||||
--color-foreground: #ececec;
|
||||
--color-card: #141414;
|
||||
--color-card-foreground: #ececec;
|
||||
--color-popover: #1a1a1a;
|
||||
--color-popover-foreground: #ececec;
|
||||
--color-primary: #ececec;
|
||||
--color-primary-foreground: #0d0d0d;
|
||||
--color-secondary: #1a1a1a;
|
||||
--color-secondary-foreground: #ececec;
|
||||
--color-muted: #1a1a1a;
|
||||
--color-muted-foreground: #888888;
|
||||
--color-accent: #1a1a1a;
|
||||
--color-accent-foreground: #ececec;
|
||||
--color-background: #09090b;
|
||||
--color-foreground: #e4e4e7;
|
||||
--color-card: #111113;
|
||||
--color-card-foreground: #e4e4e7;
|
||||
--color-popover: #141416;
|
||||
--color-popover-foreground: #e4e4e7;
|
||||
--color-primary: #e4e4e7;
|
||||
--color-primary-foreground: #09090b;
|
||||
--color-secondary: #1a1a1c;
|
||||
--color-secondary-foreground: #e4e4e7;
|
||||
--color-muted: #18181b;
|
||||
--color-muted-foreground: #71717a;
|
||||
--color-accent: #1f1f22;
|
||||
--color-accent-foreground: #e4e4e7;
|
||||
--color-destructive: #f43f5e;
|
||||
--color-destructive-foreground: #ececec;
|
||||
--color-border: #262626;
|
||||
--color-ring: #3b82f6;
|
||||
--color-destructive-foreground: #e4e4e7;
|
||||
--color-border: #27272a;
|
||||
--color-ring: #71717a;
|
||||
--color-signal: #f43f5e;
|
||||
--color-input: #262626;
|
||||
--color-input: #27272a;
|
||||
--color-overlay: #050505;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ body {
|
||||
opacity: 0.95;
|
||||
transform: scale(1.03);
|
||||
box-shadow:
|
||||
0px 0px 0px 2px var(--color-ring),
|
||||
0px 0px 0px 2px var(--color-muted-foreground),
|
||||
0px 12px 32px rgba(0, 0, 0, 0.25);
|
||||
z-index: 50;
|
||||
}
|
||||
@@ -145,7 +145,7 @@ body {
|
||||
position: absolute;
|
||||
inset: -4px;
|
||||
border-radius: inherit;
|
||||
border: 2px dashed var(--color-ring);
|
||||
border: 2px dashed var(--color-muted-foreground);
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -154,8 +154,8 @@ body {
|
||||
.drop-target-line {
|
||||
height: 3px;
|
||||
border-radius: 2px;
|
||||
background: var(--color-ring);
|
||||
box-shadow: 0 0 8px var(--color-ring);
|
||||
background: var(--color-muted-foreground);
|
||||
box-shadow: 0 0 8px var(--color-muted-foreground);
|
||||
margin: 4px 0;
|
||||
animation: pulse-line 1.2s ease-in-out infinite;
|
||||
}
|
||||
@@ -181,14 +181,14 @@ body {
|
||||
|
||||
/* ── Colorful badge variants ── */
|
||||
.badge-local {
|
||||
background: #0f291e;
|
||||
background: #0f1a15;
|
||||
color: #34d399;
|
||||
}
|
||||
.badge-external {
|
||||
background: #162038;
|
||||
color: #60a5fa;
|
||||
background: #1a1a1c;
|
||||
color: #a1a1aa;
|
||||
}
|
||||
.badge-custom {
|
||||
background: #231a38;
|
||||
color: #a78bfa;
|
||||
background: #1a1a1c;
|
||||
color: #a1a1aa;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ function AddAppTile({ onClick }: { onClick: () => void }) {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="service-card group flex aspect-square flex-col items-center justify-center gap-2.5 rounded-[24px] border border-dashed border-border bg-card p-4 transition-all duration-300 hover:-translate-y-1 hover:bg-accent hover:border-ring/40 hover:shadow-border-hover"
|
||||
className="service-card group flex aspect-square flex-col items-center justify-center gap-2.5 rounded-[24px] border border-dashed border-border bg-card p-4 transition-all duration-300 hover:-translate-y-1 hover:bg-accent hover:border-muted-foreground/40 hover:shadow-border-hover"
|
||||
>
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-secondary transition-colors group-hover:bg-accent">
|
||||
<Plus className="h-5 w-5 text-muted-foreground transition-colors group-hover:text-foreground" />
|
||||
@@ -128,7 +128,7 @@ function DashboardDragOverlay({ activeId, dashboard }: { activeId: string; dashb
|
||||
|
||||
if (widget) {
|
||||
return (
|
||||
<div className="drag-overlay flex w-56 items-center gap-3 rounded-xl bg-card border border-ring/50 px-4 py-3 shadow-2xl">
|
||||
<div className="drag-overlay flex w-56 items-center gap-3 rounded-xl bg-card border border-muted-foreground/40 px-4 py-3 shadow-2xl">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-accent">
|
||||
<GripVertical className="h-4 w-4 text-accent-foreground" />
|
||||
</div>
|
||||
@@ -216,7 +216,7 @@ export default function DashboardPage() {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col bg-background">
|
||||
<div className="h-14 border-b border-border/50" />
|
||||
<div className="h-14 border-b border-border" />
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-accent">
|
||||
@@ -261,7 +261,7 @@ export default function DashboardPage() {
|
||||
<main className="mx-auto w-full max-w-6xl flex-1 px-4 py-6">
|
||||
{isEmpty ? (
|
||||
<div className="flex flex-col items-center justify-center gap-6 py-32">
|
||||
<div className="flex h-20 w-20 items-center justify-center rounded-[24px] bg-gradient-to-br from-secondary to-accent border border-border shadow-border-card">
|
||||
<div className="flex h-20 w-20 items-center justify-center rounded-[24px] bg-secondary border border-border shadow-border-card">
|
||||
<LayoutGrid className="h-8 w-8 text-muted-foreground" />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
@@ -290,7 +290,7 @@ export default function DashboardPage() {
|
||||
<Card className="mb-6">
|
||||
<CardHeader className="flex flex-row items-center justify-between pb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-0.5 rounded-full bg-ring" />
|
||||
<div className="h-4 w-0.5 rounded-full bg-muted-foreground" />
|
||||
<CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Widgets</CardTitle>
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" onClick={openAddWidget} className="gap-1.5 text-xs rounded-lg hover:bg-accent">
|
||||
@@ -310,7 +310,7 @@ export default function DashboardPage() {
|
||||
) : (
|
||||
<button
|
||||
onClick={openAddWidget}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border bg-secondary/50 p-6 text-sm text-muted-foreground transition-all hover:border-ring/40 hover:bg-accent hover:text-foreground"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border bg-muted p-6 text-sm text-muted-foreground transition-all hover:border-muted-foreground/40 hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<Plus className="h-4 w-4" /> Add your first widget
|
||||
</button>
|
||||
@@ -322,7 +322,7 @@ export default function DashboardPage() {
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between pb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-0.5 rounded-full bg-ring" />
|
||||
<div className="h-4 w-0.5 rounded-full bg-muted-foreground" />
|
||||
<CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Apps</CardTitle>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -370,7 +370,7 @@ export default function DashboardPage() {
|
||||
<div>
|
||||
{groups.length > 0 && (
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<div className="h-4 w-0.5 rounded-full bg-ring" />
|
||||
<div className="h-4 w-0.5 rounded-full bg-muted-foreground" />
|
||||
<span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Ungrouped</span>
|
||||
<span className="text-xs text-muted-foreground font-mono">{ungrouped.length}</span>
|
||||
</div>
|
||||
@@ -401,7 +401,7 @@ export default function DashboardPage() {
|
||||
{groups.length === 0 && ungrouped.length === 0 && (
|
||||
<button
|
||||
onClick={openAddService}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border bg-secondary/50 p-8 text-sm text-muted-foreground transition-all hover:border-ring/40 hover:bg-accent hover:text-foreground"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl border border-dashed border-border bg-muted p-8 text-sm text-muted-foreground transition-all hover:border-muted-foreground/40 hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
<Plus className="h-4 w-4" /> Add your first app
|
||||
</button>
|
||||
|
||||
@@ -48,8 +48,8 @@ export function GroupSection({ group, onEditService, onDeleteService, onEditGrou
|
||||
className="flex flex-1 items-center gap-2.5 group/title min-w-0"
|
||||
onClick={handleToggle}
|
||||
>
|
||||
<div className="flex h-7 w-7 items-center justify-center rounded-lg transition-colors bg-accent">
|
||||
<FolderOpen className="h-3.5 w-3.5 text-accent-foreground" />
|
||||
<div className="flex h-7 w-7 items-center justify-center rounded-lg transition-colors bg-secondary">
|
||||
<FolderOpen className="h-3.5 w-3.5 text-secondary-foreground" />
|
||||
</div>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<span className="text-sm font-semibold truncate">{group.name}</span>
|
||||
|
||||
@@ -157,8 +157,8 @@ export function ServiceCard({
|
||||
)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{/* Gradient accent line at top */}
|
||||
<div className="absolute top-0 left-0 right-0 h-[2px] opacity-0 group-hover:opacity-100 transition-opacity bg-ring" />
|
||||
{/* Accent line at top */}
|
||||
<div className="absolute top-0 left-0 right-0 h-[2px] opacity-0 group-hover:opacity-100 transition-opacity bg-muted-foreground" />
|
||||
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2.5 p-4">
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export function Header({
|
||||
const dateStr = now.toLocaleDateString([], { weekday: "short", month: "short", day: "numeric" });
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-40 w-full border-b border-border bg-background">
|
||||
<header className="sticky top-0 z-40 w-full border-b border-border bg-card">
|
||||
<div className="mx-auto flex h-14 max-w-6xl items-center justify-between px-4">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -7,7 +7,7 @@ const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLI
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"flex h-9 w-full rounded-md border border-border bg-card px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-muted file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -37,9 +37,9 @@ export function WidgetCard({
|
||||
const typeIcon = widgetTypeIcons[widget.type] || <Activity className="h-3.5 w-3.5" />;
|
||||
|
||||
return (
|
||||
<Card className="group relative border-0 overflow-hidden rounded-2xl shadow-[0px_0px_0px_1px_var(--color-border)] hover:shadow-border-hover transition-all duration-200">
|
||||
<Card className="group relative overflow-hidden rounded-2xl border border-border bg-card hover:shadow-border-hover transition-all duration-200">
|
||||
<div className={cn(
|
||||
"absolute top-0 left-0 right-0 h-1 opacity-60 bg-ring"
|
||||
"absolute top-0 left-0 right-0 h-0.5 opacity-40 bg-muted-foreground"
|
||||
)} />
|
||||
<CardHeader className="flex flex-row items-center justify-between pt-4 pb-2 px-4">
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
@@ -156,7 +156,7 @@ function ImageContent({ config }: { config: Record<string, unknown> }) {
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt="Widget image"
|
||||
className="max-h-48 w-full rounded-xl object-cover border border-border/20 shadow-sm"
|
||||
className="max-h-48 w-full rounded-xl object-cover border border-border shadow-sm"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = "none";
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user