diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/ClaudeToolCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/ClaudeToolCard.js index 25d2bdd..17dc929 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/ClaudeToolCard.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/ClaudeToolCard.js @@ -191,23 +191,23 @@ export default function ClaudeToolCard({ }; return ( - +
-
-
- {tool.name} { e.target.style.display = "none"; }} /> +
+
+ {tool.name} { e.target.style.display = "none"; }} />
-
+
-

{tool.name}

- {configStatus === "configured" && Connected} - {configStatus === "not_configured" && Not configured} - {configStatus === "other" && Other endpoint} +

{tool.name}

+ {configStatus === "configured" && Connected} + {configStatus === "not_configured" && Not configured} + {configStatus === "other" && Other}
-

{tool.description}

+

{tool.description}

- expand_more + expand_more
{isExpanded && ( diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/CodexToolCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/CodexToolCard.js index 80df981..4136e6e 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/CodexToolCard.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/CodexToolCard.js @@ -164,23 +164,23 @@ wire_api = "responses" }; return ( - +
-
-
- {tool.name} { e.target.style.display = "none"; }} /> +
+
+ {tool.name} { e.target.style.display = "none"; }} />
-
+
-

{tool.name}

- {configStatus === "configured" && Connected} - {configStatus === "not_configured" && Not configured} - {configStatus === "other" && Other endpoint} +

{tool.name}

+ {configStatus === "configured" && Connected} + {configStatus === "not_configured" && Not configured} + {configStatus === "other" && Other}
-

{tool.description}

+

{tool.description}

- expand_more + expand_more
{isExpanded && ( diff --git a/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.js b/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.js index ad985c2..5b13444 100644 --- a/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.js +++ b/src/app/(dashboard)/dashboard/cli-tools/components/DefaultToolCard.js @@ -233,43 +233,43 @@ export default function DefaultToolCard({ toolId, tool, isExpanded, onToggle, ba {tool.name} { e.target.style.display = "none"; }} /> ); } if (tool.icon) { - return {tool.icon}; + return {tool.icon}; } return ( {tool.name} { e.target.style.display = "none"; }} /> ); }; return ( - +
-
-
+
+
{renderIcon()}
-
-

{tool.name}

-

{tool.description}

+
+

{tool.name}

+

{tool.description}

- expand_more + expand_more
{isExpanded && ( diff --git a/src/app/(dashboard)/dashboard/combos/page.js b/src/app/(dashboard)/dashboard/combos/page.js index 24e7f3a..3ff8f1a 100644 --- a/src/app/(dashboard)/dashboard/combos/page.js +++ b/src/app/(dashboard)/dashboard/combos/page.js @@ -120,12 +120,13 @@ export default function CombosPage() { {combos.length === 0 ? (
- - layers - -

No combos yet

+
+ layers +
+

No combos yet

+

Create model combos with fallback support

@@ -168,62 +169,57 @@ export default function CombosPage() { function ComboCard({ combo, copied, onCopy, onEdit, onDelete }) { return ( - -
-
- {/* Name + Copy */} -
- layers - {combo.name} - + +
+
+
+ layers
- - {/* Models list */} -
- {combo.models.length === 0 ? ( -

No models added

- ) : ( - combo.models.map((model, index) => ( -
- {index + 1}. - - {model} +
+
+ {combo.name} + +
+
+ {combo.models.length === 0 ? ( + No models + ) : ( + combo.models.slice(0, 3).map((model, index) => ( + + {model.split("/").pop()} - {index === 0 && ( - Primary - )} - {index > 0 && ( - Fallback - )} -
- )) - )} + )) + )} + {combo.models.length > 3 && ( + +{combo.models.length - 3} more + )} +
{/* Actions */} -
+
@@ -321,9 +317,8 @@ function ComboFormModal({ isOpen, combo, onClose, onSave, activeProviders }) { isOpen={isOpen} onClose={onClose} title={isEdit ? "Edit Combo" : "Create Combo"} - size="md" > -
+
{/* Name */}
-

+

Only letters, numbers, - and _ allowed

{/* Models */}
-
- - -
+ {models.length === 0 ? ( -
-

No models added

-

Click "Add Model" to add

+
+ layers +

No models added yet

) : ( -
+
{models.map((model, index) => (
- {/* Priority arrows */} -
+ {/* Index badge */} + {index + 1} + + {/* Model Input */} + handleModelChange(index, e.target.value)} + placeholder="provider/model" + className="flex-1 min-w-0 px-1.5 py-0.5 text-xs font-mono bg-transparent border-0 focus:outline-none text-text-main placeholder:text-text-muted/50" + /> + + {/* Priority arrows - horizontal, always visible */} +
- {/* Model Input */} - handleModelChange(index, e.target.value)} - placeholder="model-name" - className="flex-1" - /> - - {/* Remove */} + {/* Remove - always visible */}
))}
)} + + {/* Add Model button - moved to bottom */} +
{/* Actions */} -
+
+ -
diff --git a/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.js b/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.js index 95952f2..1fead1e 100644 --- a/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.js +++ b/src/app/(dashboard)/dashboard/endpoint/EndpointPageClient.js @@ -293,58 +293,48 @@ export default function APIPageClient({ machineId }) {
{keys.length === 0 ? ( -
- - vpn_key - -

No API keys yet

+
+
+ vpn_key +
+

No API keys yet

+

Create your first API key to get started

+
) : ( -
- - - - - - - - - - - {keys.map((key) => ( - - - - - - - ))} - -
NameKeyCreatedActions
{key.name} -
- - {key.key} - -
-
- {new Date(key.createdAt).toLocaleDateString()} - - -
+
+ {keys.map((key) => ( +
+
+

{key.name}

+
+ {key.key} + +
+

+ Created {new Date(key.createdAt).toLocaleDateString()} +

+
+ +
+ ))}
)} diff --git a/src/app/(dashboard)/dashboard/profile/page.js b/src/app/(dashboard)/dashboard/profile/page.js index caffa2f..3abf5f1 100644 --- a/src/app/(dashboard)/dashboard/profile/page.js +++ b/src/app/(dashboard)/dashboard/profile/page.js @@ -3,6 +3,7 @@ import { useState, useEffect } from "react"; import { Card, Button, Badge, Toggle, Input } from "@/shared/components"; import { useTheme } from "@/shared/hooks/useTheme"; +import { cn } from "@/shared/utils/cn"; import { APP_CONFIG } from "@/shared/constants/config"; export default function ProfilePage() { @@ -117,7 +118,12 @@ export default function ProfilePage() { {/* Routing Preferences */} -

Security

+
+
+ shield +
+

Security

+
@@ -168,7 +174,12 @@ export default function ProfilePage() { {/* Routing Preferences */} -

Routing Strategy

+
+
+ route +
+

Routing Strategy

+
@@ -215,7 +226,12 @@ export default function ProfilePage() { {/* Theme Preferences */} -

Appearance

+
+
+ palette +
+

Appearance

+
@@ -231,34 +247,38 @@ export default function ProfilePage() {
{/* Theme Options */} -
- {["light", "dark", "system"].map((option) => ( - - ))} +
+
+ {["light", "dark", "system"].map((option) => ( + + ))} +
{/* Data Management */} -

Data

+
+
+ database +
+

Data

+
diff --git a/src/app/(dashboard)/dashboard/providers/[id]/page.js b/src/app/(dashboard)/dashboard/providers/[id]/page.js index cfe37df..ba9c56b 100644 --- a/src/app/(dashboard)/dashboard/providers/[id]/page.js +++ b/src/app/(dashboard)/dashboard/providers/[id]/page.js @@ -303,14 +303,18 @@ export default function ProviderDetailPage() {
{connections.length === 0 ? ( -
- - {isOAuth ? "lock" : "key"} - -

No connections yet

+
+
+ {isOAuth ? "lock" : "key"} +
+

No connections yet

+

Add your first connection to get started

+
) : ( -
+
{connections .sort((a, b) => (a.priority || 0) - (b.priority || 0)) .map((conn, index) => ( @@ -618,7 +622,7 @@ function ConnectionRow({ connection, isOAuth, isFirst, isLast, onMoveUp, onMoveD }; return ( -
+
{/* Priority arrows */}
@@ -666,12 +670,12 @@ function ConnectionRow({ connection, isOAuth, isFirst, isLast, onMoveUp, onMoveD onChange={onToggleActive} title={(connection.isActive ?? true) ? "Disable connection" : "Enable connection"} /> -
- -
diff --git a/src/app/(dashboard)/dashboard/providers/page.js b/src/app/(dashboard)/dashboard/providers/page.js index 16a9474..402b651 100644 --- a/src/app/(dashboard)/dashboard/providers/page.js +++ b/src/app/(dashboard)/dashboard/providers/page.js @@ -134,8 +134,8 @@ function ProviderCard({ providerId, provider, stats }) { const [imgError, setImgError] = useState(false); return ( - - + +
- + chevron_right
@@ -199,8 +199,8 @@ function ApiKeyProviderCard({ providerId, provider, stats }) { const { connected, error, errorCode, errorTime } = stats; return ( - - + +
- + chevron_right
diff --git a/src/app/(dashboard)/dashboard/usage/page.js b/src/app/(dashboard)/dashboard/usage/page.js index a02d310..8408888 100644 --- a/src/app/(dashboard)/dashboard/usage/page.js +++ b/src/app/(dashboard)/dashboard/usage/page.js @@ -1,36 +1,21 @@ "use client"; import { useState, Suspense } from "react"; -import { UsageStats, RequestLogger, CardSkeleton } from "@/shared/components"; +import { UsageStats, RequestLogger, CardSkeleton, SegmentedControl } from "@/shared/components"; export default function UsagePage() { const [activeTab, setActiveTab] = useState("overview"); return (
- {/* Tabs */} -
- - -
+ {/* Content */} {activeTab === "overview" ? ( diff --git a/src/app/globals.css b/src/app/globals.css index 70e4f7c..d83e49e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,7 +3,7 @@ @custom-variant dark (&:where(.dark, .dark *)); -/* Claude-inspired Color Palette */ +/* macOS-inspired Color Palette with Terracotta Primary */ :root { /* Primary - Warm Coral/Terracotta */ --color-primary: #D97757; @@ -13,15 +13,15 @@ --color-bg: #FBF9F6; --color-bg-alt: #F5F1ED; --color-surface: #FFFFFF; - --color-sidebar: #F0EFEC; - --color-border: #E6E4DD; + --color-sidebar: rgba(246, 246, 246, 0.8); + --color-border: rgba(0, 0, 0, 0.1); --color-text-main: #383733; --color-text-muted: #75736E; - /* Shadows */ - --shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.03), 0 10px 25px rgba(0, 0, 0, 0.02); - --shadow-warm: 0 4px 20px -2px rgba(217, 119, 87, 0.15); - --shadow-elevated: 0 20px 40px -4px rgba(60, 50, 45, 0.08); + /* Shadows - subtle macOS style */ + --shadow-soft: 0 1px 3px rgba(0, 0, 0, 0.02), 0 4px 12px rgba(0, 0, 0, 0.015); + --shadow-warm: 0 2px 12px -2px rgba(217, 119, 87, 0.12); + --shadow-elevated: 0 12px 28px -4px rgba(60, 50, 45, 0.06); } .dark { @@ -29,15 +29,15 @@ --color-bg: #191918; --color-bg-alt: #1F1F1E; --color-surface: #242423; - --color-sidebar: #1F1F1E; - --color-border: #333331; + --color-sidebar: rgba(30, 30, 30, 0.8); + --color-border: rgba(255, 255, 255, 0.1); --color-text-main: #ECEBE8; --color-text-muted: #9E9D99; - /* Dark shadows */ - --shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.2), 0 10px 25px rgba(0, 0, 0, 0.15); - --shadow-warm: 0 4px 20px -2px rgba(217, 119, 87, 0.2); - --shadow-elevated: 0 20px 40px -4px rgba(0, 0, 0, 0.4); + /* Dark shadows - subtle macOS style */ + --shadow-soft: 0 1px 3px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1); + --shadow-warm: 0 2px 12px -2px rgba(217, 119, 87, 0.15); + --shadow-elevated: 0 12px 28px -4px rgba(0, 0, 0, 0.3); } @theme inline { @@ -72,8 +72,8 @@ --shadow-warm: var(--shadow-warm); --shadow-elevated: var(--shadow-elevated); - /* Font */ - --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + /* Font - macOS system fonts */ + --font-sans: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', system-ui, sans-serif; } /* Base styles */ @@ -182,3 +182,38 @@ body { .animate-border-glow { animation: border-glow 2s ease-in-out infinite; } + +/* macOS Vibrancy/Blur Effect */ +.bg-vibrancy { + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + background: rgba(255, 255, 255, 0.72); +} + +.dark .bg-vibrancy { + background: rgba(30, 30, 30, 0.72); +} + +/* macOS Traffic Lights */ +.traffic-lights { + display: flex; + gap: 8px; +} + +.traffic-light { + width: 12px; + height: 12px; + border-radius: 50%; +} + +.traffic-light.red { + background: #FF5F56; +} + +.traffic-light.yellow { + background: #FFBD2E; +} + +.traffic-light.green { + background: #27C93F; +} diff --git a/src/shared/components/Badge.js b/src/shared/components/Badge.js index 1a412a7..4cd55fc 100644 --- a/src/shared/components/Badge.js +++ b/src/shared/components/Badge.js @@ -3,12 +3,12 @@ import { cn } from "@/shared/utils/cn"; const variants = { - default: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300", + default: "bg-black/5 dark:bg-white/10 text-text-muted", primary: "bg-primary/10 text-primary", - success: "bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400 border border-green-100 dark:border-green-800/30", - warning: "bg-yellow-50 dark:bg-yellow-900/20 text-yellow-700 dark:text-yellow-500 border border-yellow-100 dark:border-yellow-800/30", - error: "bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400 border border-red-100 dark:border-red-800/30", - info: "bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-400 border border-blue-100 dark:border-blue-800/30", + success: "bg-green-500/10 text-green-600 dark:text-green-400", + warning: "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400", + error: "bg-red-500/10 text-red-600 dark:text-red-400", + info: "bg-blue-500/10 text-blue-600 dark:text-blue-400", }; const sizes = { diff --git a/src/shared/components/Button.js b/src/shared/components/Button.js index bb5e8ce..3210b2e 100644 --- a/src/shared/components/Button.js +++ b/src/shared/components/Button.js @@ -3,17 +3,17 @@ import { cn } from "@/shared/utils/cn"; const variants = { - primary: "bg-primary text-white hover:bg-primary-hover shadow-warm", - secondary: "bg-surface border border-border text-text-main hover:bg-black/5 shadow-sm", - outline: "border border-border text-text-main hover:bg-black/5", - ghost: "text-text-muted hover:bg-black/5 hover:text-text-main", + primary: "bg-gradient-to-b from-primary to-primary-hover text-white shadow-sm", + secondary: "bg-white dark:bg-white/10 border border-black/10 dark:border-white/10 text-text-main hover:bg-black/5 dark:hover:bg-white/5", + outline: "border border-black/15 dark:border-white/15 text-text-main hover:bg-black/5", + ghost: "text-text-muted hover:bg-black/5 dark:hover:bg-white/5 hover:text-text-main", danger: "bg-red-500 text-white hover:bg-red-600 shadow-sm", }; const sizes = { - sm: "h-8 px-3 text-xs rounded-md", - md: "h-10 px-5 text-sm rounded-lg", - lg: "h-12 px-8 text-base rounded-xl", + sm: "h-7 px-3 text-xs rounded-md", + md: "h-9 px-4 text-sm rounded-lg", + lg: "h-11 px-6 text-sm rounded-lg", }; export default function Button({ @@ -32,7 +32,7 @@ export default function Button({
+ ); +}; + diff --git a/src/shared/components/Header.js b/src/shared/components/Header.js index d805f20..4c8346e 100644 --- a/src/shared/components/Header.js +++ b/src/shared/components/Header.js @@ -55,7 +55,7 @@ export default function Header({ onMenuClick, showMenuButton = true }) { }; return ( -
+
{/* Mobile menu button */}
{showMenuButton && ( diff --git a/src/shared/components/Input.js b/src/shared/components/Input.js index 85f4588..b81a639 100644 --- a/src/shared/components/Input.js +++ b/src/shared/components/Input.js @@ -38,17 +38,17 @@ export default function Input({ onChange={onChange} disabled={disabled} className={cn( - "w-full py-2.5 px-4 text-sm text-text-main", - "bg-surface border rounded-lg", + "w-full py-2 px-3 text-sm text-text-main", + "bg-white dark:bg-white/5 border border-black/10 dark:border-white/10 rounded-md", "placeholder-text-muted/60", - "focus:ring-2 focus:ring-primary/20 focus:border-primary focus:outline-none", - "transition-all shadow-sm disabled:opacity-50 disabled:cursor-not-allowed", + "focus:ring-1 focus:ring-primary/30 focus:border-primary/50 focus:outline-none", + "transition-all shadow-inner disabled:opacity-50 disabled:cursor-not-allowed", // iOS zoom fix "text-[16px] sm:text-sm", icon && "pl-10", error ? "border-red-500 focus:border-red-500 focus:ring-red-500/20" - : "border-border", + : "", inputClassName )} {...props} diff --git a/src/shared/components/Modal.js b/src/shared/components/Modal.js index 7413cb4..9a2f433 100644 --- a/src/shared/components/Modal.js +++ b/src/shared/components/Modal.js @@ -52,7 +52,7 @@ export default function Modal({
{/* Overlay */}
@@ -60,8 +60,8 @@ export default function Modal({
{/* Header */} {(title || showCloseButton) && ( -
- {title && ( -

- {title} -

- )} +
+
+
+
+
+
+
+ {title && ( +

+ {title} +

+ )} +
{showCloseButton && ( @@ -91,7 +98,7 @@ export default function Modal({ {/* Footer */} {footer && ( -
+
{footer}
)} diff --git a/src/shared/components/SegmentedControl.js b/src/shared/components/SegmentedControl.js new file mode 100644 index 0000000..d93d758 --- /dev/null +++ b/src/shared/components/SegmentedControl.js @@ -0,0 +1,48 @@ +"use client"; + +import { cn } from "@/shared/utils/cn"; + +export default function SegmentedControl({ + options = [], + value, + onChange, + size = "md", + className, +}) { + const sizes = { + sm: "h-7 text-xs", + md: "h-9 text-sm", + lg: "h-11 text-base", + }; + + return ( +
+ {options.map((option) => ( + + ))} +
+ ); +} diff --git a/src/shared/components/Select.js b/src/shared/components/Select.js index 066b805..f11f4ca 100644 --- a/src/shared/components/Select.js +++ b/src/shared/components/Select.js @@ -30,14 +30,14 @@ export default function Select({ onChange={onChange} disabled={disabled} className={cn( - "w-full py-2.5 px-4 pr-10 text-sm text-text-main", - "bg-surface border rounded-lg appearance-none", - "focus:ring-2 focus:ring-primary/20 focus:border-primary focus:outline-none", - "transition-all shadow-sm disabled:opacity-50 disabled:cursor-not-allowed", + "w-full py-2 px-3 pr-10 text-sm text-text-main", + "bg-white dark:bg-white/5 border border-black/10 dark:border-white/10 rounded-md appearance-none", + "focus:ring-1 focus:ring-primary/30 focus:border-primary/50 focus:outline-none", + "transition-all disabled:opacity-50 disabled:cursor-not-allowed", "text-[16px] sm:text-sm", error ? "border-red-500 focus:border-red-500 focus:ring-red-500/20" - : "border-border", + : "", selectClassName )} {...props} diff --git a/src/shared/components/Sidebar.js b/src/shared/components/Sidebar.js index 7d7a1b3..4f19fe3 100644 --- a/src/shared/components/Sidebar.js +++ b/src/shared/components/Sidebar.js @@ -62,9 +62,16 @@ export default function Sidebar({ onClose }) { return ( <> -