mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
refactor(dashboard): fix dark theme + two-column layout on agent-skills, standardize page widths
- agent-skills: replace all inline style={{ color: "var(--color-xxx, #fallback)" }} with
Tailwind semantic classes (text-text-main, text-text-muted, bg-bg-subtle, border-border,
text-primary, bg-primary/10, bg-emerald-500/10, bg-amber-500/10) — fixes dark mode
- agent-skills: full-width "How to use" card + two-column grid (API Skills | CLI Skills)
on lg+ screens; remove internal p-6 and max-w-3xl (layout already provides padding/max-w)
- audit, webhooks: remove redundant p-6 + mx-auto max-w-7xl (DashboardLayout already wraps
content in max-w-7xl with p-4 sm:p-6 lg:p-10)
- memory: remove extra p-6
- agents: remove p-6 + max-w-5xl mx-auto
- cloud-agents: remove p-6 + max-w-6xl mx-auto
- changelog: remove max-w-5xl mx-auto w-full
- health: remove outer p-6 + max-w-6xl mx-auto; strip redundant p-6 from loading/error states
- translator: remove p-4 sm:p-8 (layout provides padding)
- context/caveman, context/rtk, context/combos: remove mx-auto max-w-6xl
This commit is contained in:
@@ -16,16 +16,14 @@ function CopyButton({ url }: { url: string }) {
|
||||
return (
|
||||
<button
|
||||
onClick={() => void copy(url, url)}
|
||||
className="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium transition-colors"
|
||||
style={{
|
||||
background: isCopied
|
||||
? "var(--color-success-bg, #d1fae5)"
|
||||
: "var(--color-surface-2, #f3f4f6)",
|
||||
color: isCopied ? "var(--color-success, #065f46)" : "var(--color-text-2, #6b7280)",
|
||||
}}
|
||||
className={`flex items-center gap-1 rounded px-2 py-1 text-xs font-medium transition-colors ${
|
||||
isCopied
|
||||
? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-400"
|
||||
: "bg-bg-subtle text-text-muted hover:text-text-main"
|
||||
}`}
|
||||
title="Copy raw URL to clipboard"
|
||||
>
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{isCopied ? "check" : "content_copy"}
|
||||
</span>
|
||||
{isCopied ? "Copied!" : "Copy URL"}
|
||||
@@ -38,65 +36,31 @@ function SkillRow({ skill }: { skill: AgentSkill }) {
|
||||
const blobUrl = getAgentSkillBlobUrl(skill.id);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-start gap-3 rounded-lg border p-3 transition-colors hover:bg-[var(--color-surface-hover,#f9fafb)]"
|
||||
style={{ borderColor: "var(--color-border, #e5e7eb)" }}
|
||||
>
|
||||
<div
|
||||
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg"
|
||||
style={{ background: "var(--color-surface-2, #f3f4f6)" }}
|
||||
>
|
||||
<span
|
||||
className="material-symbols-outlined"
|
||||
style={{ fontSize: 18, color: "var(--color-text-2, #6b7280)" }}
|
||||
>
|
||||
{skill.icon}
|
||||
</span>
|
||||
<div className="flex items-start gap-3 rounded-lg border border-border p-3 transition-colors hover:bg-bg-subtle">
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-bg-subtle">
|
||||
<span className="material-symbols-outlined text-[18px] text-text-muted">{skill.icon}</span>
|
||||
</div>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="mb-0.5 flex flex-wrap items-center gap-1.5">
|
||||
<span className="text-sm font-semibold" style={{ color: "var(--color-text, #111827)" }}>
|
||||
{skill.name}
|
||||
</span>
|
||||
<span className="text-sm font-semibold text-text-main">{skill.name}</span>
|
||||
{skill.isEntry && (
|
||||
<span
|
||||
className="rounded-full px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide"
|
||||
style={{
|
||||
background: "var(--color-primary-bg, #eff6ff)",
|
||||
color: "var(--color-primary, #2563eb)",
|
||||
}}
|
||||
>
|
||||
<span className="rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-primary">
|
||||
Start Here
|
||||
</span>
|
||||
)}
|
||||
{skill.isNew && (
|
||||
<span
|
||||
className="rounded-full px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide"
|
||||
style={{
|
||||
background: "var(--color-warning-bg, #fef3c7)",
|
||||
color: "var(--color-warning, #92400e)",
|
||||
}}
|
||||
>
|
||||
<span className="rounded-full bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-amber-700 dark:text-amber-400">
|
||||
New
|
||||
</span>
|
||||
)}
|
||||
{skill.endpoint && (
|
||||
<code
|
||||
className="rounded px-1.5 py-0.5 text-[10px]"
|
||||
style={{
|
||||
background: "var(--color-surface-2, #f3f4f6)",
|
||||
color: "var(--color-text-2, #6b7280)",
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
>
|
||||
<code className="rounded bg-bg-subtle px-1.5 py-0.5 font-mono text-[10px] text-text-muted">
|
||||
{skill.endpoint}
|
||||
</code>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-xs leading-relaxed" style={{ color: "var(--color-text-2, #6b7280)" }}>
|
||||
{skill.description}
|
||||
</p>
|
||||
<p className="text-xs leading-relaxed text-text-muted">{skill.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
@@ -104,13 +68,10 @@ function SkillRow({ skill }: { skill: AgentSkill }) {
|
||||
href={blobUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium transition-colors hover:bg-[var(--color-surface-2,#f3f4f6)]"
|
||||
style={{ color: "var(--color-text-3, #9ca3af)" }}
|
||||
className="flex items-center gap-1 rounded px-2 py-1 text-xs font-medium text-text-muted transition-colors hover:bg-bg-subtle hover:text-text-main"
|
||||
title="View on GitHub"
|
||||
>
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>
|
||||
open_in_new
|
||||
</span>
|
||||
<span className="material-symbols-outlined text-[14px]">open_in_new</span>
|
||||
</a>
|
||||
<CopyButton url={rawUrl} />
|
||||
</div>
|
||||
@@ -130,21 +91,12 @@ function SkillSection({
|
||||
skills: AgentSkill[];
|
||||
}) {
|
||||
return (
|
||||
<section>
|
||||
<div className="mb-3 flex items-center gap-2">
|
||||
<span
|
||||
className="material-symbols-outlined"
|
||||
style={{ fontSize: 20, color: "var(--color-text-2, #6b7280)" }}
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
<section className="space-y-3 rounded-xl border border-border bg-bg p-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined text-[20px] text-text-muted">{icon}</span>
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold" style={{ color: "var(--color-text, #111827)" }}>
|
||||
{title}
|
||||
</h2>
|
||||
<p className="text-xs" style={{ color: "var(--color-text-3, #9ca3af)" }}>
|
||||
{subtitle}
|
||||
</p>
|
||||
<h2 className="text-sm font-semibold text-text-main">{title}</h2>
|
||||
<p className="text-xs text-text-muted">{subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -161,40 +113,22 @@ export default function AgentSkillsPage() {
|
||||
const cliSkills = AGENT_SKILLS.filter((s) => s.category === "cli");
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-3xl space-y-8 p-6">
|
||||
{/* How to use */}
|
||||
<div
|
||||
className="rounded-lg border p-4"
|
||||
style={{
|
||||
borderColor: "var(--color-border, #e5e7eb)",
|
||||
background: "var(--color-surface-2, #f9fafb)",
|
||||
}}
|
||||
>
|
||||
<div className="space-y-6">
|
||||
{/* How to use — full width */}
|
||||
<div className="rounded-xl border border-border bg-bg-subtle/50 p-4">
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<span
|
||||
className="material-symbols-outlined"
|
||||
style={{ fontSize: 18, color: "var(--color-primary, #2563eb)" }}
|
||||
>
|
||||
info
|
||||
</span>
|
||||
<span className="text-sm font-semibold" style={{ color: "var(--color-text, #111827)" }}>
|
||||
How to use
|
||||
</span>
|
||||
<span className="material-symbols-outlined text-[18px] text-primary">info</span>
|
||||
<span className="text-sm font-semibold text-text-main">How to use</span>
|
||||
</div>
|
||||
<ol className="space-y-1 text-xs" style={{ color: "var(--color-text-2, #6b7280)" }}>
|
||||
<ol className="space-y-1 text-xs text-text-muted">
|
||||
<li>
|
||||
1. Click <strong>Copy URL</strong> on the skill you want your agent to know about.
|
||||
1. Click <strong className="text-text-main">Copy URL</strong> on the skill you want your
|
||||
agent to know about.
|
||||
</li>
|
||||
<li>
|
||||
2. In your AI agent (Claude, Cursor, Cline…), say:
|
||||
<br />
|
||||
<code
|
||||
className="mt-1 block rounded px-2 py-1 font-mono text-[11px]"
|
||||
style={{
|
||||
background: "var(--color-surface, #fff)",
|
||||
border: "1px solid var(--color-border, #e5e7eb)",
|
||||
}}
|
||||
>
|
||||
<code className="mt-1 block rounded border border-border bg-bg px-2 py-1 font-mono text-[11px]">
|
||||
Use the skill at <pasted-url>
|
||||
</code>
|
||||
</li>
|
||||
@@ -207,31 +141,28 @@ export default function AgentSkillsPage() {
|
||||
href={AGENT_SKILLS_REPO_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-3 inline-flex items-center gap-1 text-xs font-medium"
|
||||
style={{ color: "var(--color-primary, #2563eb)" }}
|
||||
className="mt-3 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
|
||||
>
|
||||
<span className="material-symbols-outlined" style={{ fontSize: 14 }}>
|
||||
open_in_new
|
||||
</span>
|
||||
<span className="material-symbols-outlined text-[14px]">open_in_new</span>
|
||||
Browse all skills on GitHub
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* API Skills */}
|
||||
<SkillSection
|
||||
title="API Skills"
|
||||
subtitle={`${apiSkills.length} skills — control OmniRoute via REST / HTTP`}
|
||||
icon="api"
|
||||
skills={apiSkills}
|
||||
/>
|
||||
|
||||
{/* CLI Skills */}
|
||||
<SkillSection
|
||||
title="CLI Skills"
|
||||
subtitle={`${cliSkills.length} skills — control OmniRoute via the omniroute terminal binary`}
|
||||
icon="terminal"
|
||||
skills={cliSkills}
|
||||
/>
|
||||
{/* Two-column grid: API Skills | CLI Skills */}
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
<SkillSection
|
||||
title="API Skills"
|
||||
subtitle={`${apiSkills.length} skills — control OmniRoute via REST / HTTP`}
|
||||
icon="api"
|
||||
skills={apiSkills}
|
||||
/>
|
||||
<SkillSection
|
||||
title="CLI Skills"
|
||||
subtitle={`${cliSkills.length} skills — control OmniRoute via the omniroute terminal binary`}
|
||||
icon="terminal"
|
||||
skills={cliSkills}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ export default function AgentsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-6 max-w-5xl mx-auto">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex justify-end">
|
||||
<Button variant="secondary" onClick={handleRefresh} loading={refreshing}>
|
||||
<span className="material-symbols-outlined text-[16px] mr-1">refresh</span>
|
||||
|
||||
@@ -222,7 +222,7 @@ export default function AuditPage() {
|
||||
const [activeTab, setActiveTab] = useState("compliance");
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl space-y-6 p-6">
|
||||
<div className="space-y-6">
|
||||
<SegmentedControl
|
||||
options={[
|
||||
{ value: "compliance", label: t("complianceTab") },
|
||||
|
||||
@@ -9,7 +9,7 @@ export default function ChangelogPage() {
|
||||
const [activeTab, setActiveTab] = useState<"news" | "changelog">("news");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 max-w-5xl mx-auto w-full">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex justify-end">
|
||||
<div className="w-full sm:w-[240px]">
|
||||
<SegmentedControl
|
||||
|
||||
@@ -254,7 +254,7 @@ export default function CloudAgentsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 p-6 max-w-6xl mx-auto">
|
||||
<div className="flex flex-col gap-6">
|
||||
<Card className="border-purple-500/20 bg-purple-500/5">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
|
||||
@@ -116,7 +116,7 @@ export default function CavemanContextPageClient() {
|
||||
const previewPrompt = `[OmniRoute Caveman Output Mode]\n${t(`preview.${outputMode.intensity}`)}`;
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex max-w-6xl flex-col gap-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<section className="grid grid-cols-1 gap-3 sm:grid-cols-4">
|
||||
{statCards.map(([label, value]) => (
|
||||
<div key={label} className="rounded-lg border border-border bg-surface p-4">
|
||||
|
||||
@@ -174,7 +174,7 @@ export default function CompressionCombosPageClient() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex max-w-6xl flex-col gap-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<section className="rounded-lg border border-border bg-surface p-4">
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-2">
|
||||
<input
|
||||
|
||||
@@ -138,7 +138,7 @@ export default function RtkContextPageClient() {
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex max-w-6xl flex-col gap-6">
|
||||
<div className="flex flex-col gap-6">
|
||||
<section className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4">
|
||||
{statCards.map(([label, value]) => (
|
||||
<div key={label} className="rounded-lg border border-border bg-surface p-4">
|
||||
|
||||
@@ -157,7 +157,7 @@ export default function HealthPage() {
|
||||
|
||||
if (!data && !error) {
|
||||
return (
|
||||
<div className="p-6 flex items-center justify-center min-h-[400px]">
|
||||
<div className="flex items-center justify-center min-h-[400px]">
|
||||
<div className="text-center">
|
||||
<div className="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
|
||||
<p className="text-text-muted mt-4">{t("loadingHealth")}</p>
|
||||
@@ -168,7 +168,7 @@ export default function HealthPage() {
|
||||
|
||||
if (error && !data) {
|
||||
return (
|
||||
<div className="p-6">
|
||||
<div>
|
||||
<div className="bg-red-500/10 border border-red-500/30 rounded-xl p-6 text-center">
|
||||
<span className="material-symbols-outlined text-red-500 text-[32px] mb-2">error</span>
|
||||
<p className="text-red-400">{t("failedToLoad", { error })}</p>
|
||||
@@ -197,7 +197,7 @@ export default function HealthPage() {
|
||||
const lockoutEntries = Object.entries(lockouts || {});
|
||||
|
||||
return (
|
||||
<div className="p-6 space-y-6 max-w-6xl mx-auto">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
{lastRefresh && (
|
||||
<span className="text-xs text-text-muted">
|
||||
|
||||
@@ -203,7 +203,7 @@ export default function MemoryPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6 p-6">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-end gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
{health !== null && (
|
||||
|
||||
@@ -72,7 +72,7 @@ export default function TranslatorPageClient() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 sm:p-8 space-y-6 min-w-0">
|
||||
<div className="space-y-6 min-w-0">
|
||||
<div className="flex justify-end min-w-0 overflow-x-auto">
|
||||
<SegmentedControl
|
||||
options={modes}
|
||||
|
||||
@@ -273,7 +273,7 @@ export default function WebhooksPage() {
|
||||
const isModalOpen = formMode !== null;
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl space-y-6 p-6">
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={openCreateModal}
|
||||
|
||||
Reference in New Issue
Block a user