mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
refactor(agent-skills): rewrite dashboard page as server wrapper + client
This commit is contained in:
@@ -1,172 +1,5 @@
|
||||
"use client";
|
||||
import { AgentSkillsPageClient } from "./AgentSkillsPageClient";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import {
|
||||
AGENT_SKILLS,
|
||||
AGENT_SKILLS_REPO_URL,
|
||||
getAgentSkillRawUrl,
|
||||
getAgentSkillBlobUrl,
|
||||
type AgentSkill,
|
||||
} from "@/shared/constants/agentSkills";
|
||||
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
|
||||
|
||||
function CopyButton({ url }: { url: string }) {
|
||||
const t = useTranslations("agents");
|
||||
const { copied, copy } = useCopyToClipboard();
|
||||
const isCopied = copied === url;
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => void copy(url, url)}
|
||||
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={t("copyRawUrlTitle")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{isCopied ? "check" : "content_copy"}
|
||||
</span>
|
||||
{isCopied ? t("copied") : t("copyUrl")}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function SkillRow({ skill }: { skill: AgentSkill }) {
|
||||
const t = useTranslations("agents");
|
||||
const rawUrl = getAgentSkillRawUrl(skill.id);
|
||||
const blobUrl = getAgentSkillBlobUrl(skill.id);
|
||||
|
||||
return (
|
||||
<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 text-text-main">{skill.name}</span>
|
||||
{skill.isEntry && (
|
||||
<span className="rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-primary">
|
||||
{t("startHere")}
|
||||
</span>
|
||||
)}
|
||||
{skill.isNew && (
|
||||
<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">
|
||||
{t("badgeNew")}
|
||||
</span>
|
||||
)}
|
||||
{skill.endpoint && (
|
||||
<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 text-text-muted">{skill.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<a
|
||||
href={blobUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
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={t("viewOnGithub")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">open_in_new</span>
|
||||
</a>
|
||||
<CopyButton url={rawUrl} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SkillSection({
|
||||
title,
|
||||
subtitle,
|
||||
icon,
|
||||
skills,
|
||||
}: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
icon: string;
|
||||
skills: AgentSkill[];
|
||||
}) {
|
||||
return (
|
||||
<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 text-text-main">{title}</h2>
|
||||
<p className="text-xs text-text-muted">{subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
{skills.map((skill) => (
|
||||
<SkillRow key={skill.id} skill={skill} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AgentSkillsPage() {
|
||||
const t = useTranslations("agents");
|
||||
const apiSkills = AGENT_SKILLS.filter((s) => s.category === "api");
|
||||
const cliSkills = AGENT_SKILLS.filter((s) => s.category === "cli");
|
||||
|
||||
return (
|
||||
<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 text-[18px] text-primary">info</span>
|
||||
<span className="text-sm font-semibold text-text-main">{t("howToUse")}</span>
|
||||
</div>
|
||||
<ol className="space-y-1 text-xs text-text-muted">
|
||||
<li>
|
||||
1.{" "}
|
||||
{t.rich("howToUseStep1", {
|
||||
copyUrl: t("copyUrl"),
|
||||
bold: (chunks) => <strong className="text-text-main">{chunks}</strong>,
|
||||
})}
|
||||
</li>
|
||||
<li>
|
||||
2. {t("howToUseStep2")}
|
||||
<br />
|
||||
<code className="mt-1 block rounded border border-border bg-bg px-2 py-1 font-mono text-[11px]">
|
||||
{t("howToUseStep2Code")}
|
||||
</code>
|
||||
</li>
|
||||
<li>3. {t("howToUseStep3")}</li>
|
||||
</ol>
|
||||
<a
|
||||
href={AGENT_SKILLS_REPO_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-3 inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">open_in_new</span>
|
||||
{t("browseAllSkillsOnGithub")}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Two-column grid: API Skills | CLI Skills */}
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
||||
<SkillSection
|
||||
title={t("apiSkills")}
|
||||
subtitle={t("apiSkillsSubtitle", { count: apiSkills.length })}
|
||||
icon="api"
|
||||
skills={apiSkills}
|
||||
/>
|
||||
<SkillSection
|
||||
title={t("cliSkills")}
|
||||
subtitle={t("cliSkillsSubtitle", { count: cliSkills.length })}
|
||||
icon="terminal"
|
||||
skills={cliSkills}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
export default function Page() {
|
||||
return <AgentSkillsPageClient />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user