feat: add notification

This commit is contained in:
Henry Li
2026-01-31 11:08:27 +08:00
parent 4e0571f3b3
commit c62caf95c4
18 changed files with 482 additions and 56 deletions

View File

@@ -6,6 +6,7 @@ import { useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
@@ -19,6 +20,7 @@ import {
ItemDescription,
} from "@/components/ui/item";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { useI18n } from "@/core/i18n/hooks";
import { useEnableSkill, useSkills } from "@/core/skills/hooks";
import type { Skill } from "@/core/skills/type";
@@ -47,61 +49,34 @@ export function SkillSettingsPage() {
function SkillSettingsList({ skills }: { skills: Skill[] }) {
const { t } = useI18n();
const [filter, setFilter] = useState<"public" | "custom">("public");
const [filter, setFilter] = useState<string>("public");
const { mutate: enableSkill } = useEnableSkill();
const filteredSkills = useMemo(
() => skills.filter((skill) => skill.category === filter),
[skills, filter],
);
if (skills.length === 0) {
return (
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<SparklesIcon />
</EmptyMedia>
<EmptyTitle>No agent skill yet</EmptyTitle>
<EmptyDescription>
Put your agent skill folders under the `/skills/custom` folder under
the root folder of DeerFlow.
</EmptyDescription>
</EmptyHeader>
</Empty>
);
}
const handleCreateSkill = () => {
console.log("create skill");
};
return (
<div className="flex w-full flex-col gap-4">
<header className="flex gap-2">
<Button
className="rounded-xl"
size="sm"
variant={filter === "public" ? "default" : "outline"}
onClick={() => setFilter("public")}
>
{t.common.public}
</Button>
<Button
className="rounded-xl"
size="sm"
variant={filter === "custom" ? "default" : "outline"}
onClick={() => setFilter("custom")}
>
{t.common.custom}
</Button>
<header className="flex justify-between">
<div className="flex gap-2">
<Tabs defaultValue="public" onValueChange={setFilter}>
<TabsList variant="line">
<TabsTrigger value="public">{t.common.public}</TabsTrigger>
<TabsTrigger value="custom">{t.common.custom}</TabsTrigger>
</TabsList>
</Tabs>
</div>
<div>
<Button variant="outline" size="sm" onClick={handleCreateSkill}>
Create Skill
</Button>
</div>
</header>
{filteredSkills.length === 0 && (
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<SparklesIcon />
</EmptyMedia>
<EmptyTitle>No skill yet</EmptyTitle>
<EmptyDescription>
Put your skill folders under the `skills/{filter}` folder under
the root folder of DeerFlow.
</EmptyDescription>
</EmptyHeader>
</Empty>
<EmptySkill onCreateSkill={handleCreateSkill} />
)}
{filteredSkills.length > 0 &&
filteredSkills.map((skill) => (
@@ -128,3 +103,23 @@ function SkillSettingsList({ skills }: { skills: Skill[] }) {
</div>
);
}
function EmptySkill({ onCreateSkill }: { onCreateSkill: () => void }) {
return (
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<SparklesIcon />
</EmptyMedia>
<EmptyTitle>No agent skill yet</EmptyTitle>
<EmptyDescription>
Put your agent skill folders under the `/skills/custom` folder under
the root folder of DeerFlow.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button onClick={onCreateSkill}>Create Your First Skill</Button>
</EmptyContent>
</Empty>
);
}