fix: badges
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Card } from "@/components/ui/card";
|
||||
|
||||
import { ModelPickerDialog } from "@/components/ModelPickerDialog";
|
||||
@@ -57,12 +57,15 @@ const STATE_LABEL: Record<ConnectionState, string> = {
|
||||
error: "error",
|
||||
};
|
||||
|
||||
const STATE_TONE: Record<ConnectionState, string> = {
|
||||
idle: "bg-muted text-muted-foreground",
|
||||
connecting: "bg-primary/10 text-primary",
|
||||
open: "bg-emerald-500/10 text-emerald-500 dark:text-emerald-400",
|
||||
closed: "bg-muted text-muted-foreground",
|
||||
error: "bg-destructive/10 text-destructive",
|
||||
const STATE_TONE: Record<
|
||||
ConnectionState,
|
||||
"secondary" | "warning" | "success" | "destructive"
|
||||
> = {
|
||||
idle: "secondary",
|
||||
connecting: "warning",
|
||||
open: "success",
|
||||
closed: "secondary",
|
||||
error: "destructive",
|
||||
};
|
||||
|
||||
interface ChatSidebarProps {
|
||||
@@ -325,7 +328,7 @@ export function ChatSidebar({ channel, className }: ChatSidebarProps) {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Badge className={STATE_TONE[state]}>{STATE_LABEL[state]}</Badge>
|
||||
<Badge tone={STATE_TONE[state]}>{STATE_LABEL[state]}</Badge>
|
||||
</Card>
|
||||
|
||||
{banner && (
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ShieldCheck, ShieldOff, ExternalLink, RefreshCw, LogOut, Terminal, LogI
|
||||
import { api, type OAuthProvider } from "@/lib/api";
|
||||
import { Button, CopyButton } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { OAuthLoginModal } from "@/components/OAuthLoginModal";
|
||||
import { useI18n } from "@/i18n";
|
||||
|
||||
@@ -124,21 +124,21 @@ export function OAuthProvidersCard({ onError, onSuccess }: Props) {
|
||||
<div className="flex flex-col min-w-0 gap-0.5">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="font-medium text-sm">{p.name}</span>
|
||||
<Badge variant="outline" className="text-[11px] uppercase tracking-wide">
|
||||
<Badge tone="outline" className="text-[11px] uppercase tracking-wide">
|
||||
{t.oauth.flowLabels[p.flow]}
|
||||
</Badge>
|
||||
{p.status.logged_in && (
|
||||
<Badge variant="success" className="text-[11px]">
|
||||
<Badge tone="success" className="text-[11px]">
|
||||
{t.oauth.connected}
|
||||
</Badge>
|
||||
)}
|
||||
{expiresLabel === "expired" && (
|
||||
<Badge variant="destructive" className="text-[11px]">
|
||||
<Badge tone="destructive" className="text-[11px]">
|
||||
{t.oauth.expired}
|
||||
</Badge>
|
||||
)}
|
||||
{expiresLabel && expiresLabel !== "expired" && (
|
||||
<Badge variant="outline" className="text-[11px]">
|
||||
<Badge tone="outline" className="text-[11px]">
|
||||
{expiresLabel}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AlertTriangle, Radio, Wifi, WifiOff } from "lucide-react";
|
||||
import type { PlatformStatus } from "@/lib/api";
|
||||
import { isoTimeAgo } from "@/lib/utils";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useI18n } from "@/i18n";
|
||||
|
||||
@@ -9,11 +9,11 @@ export function PlatformsCard({ platforms }: PlatformsCardProps) {
|
||||
const { t } = useI18n();
|
||||
const platformStateBadge: Record<
|
||||
string,
|
||||
{ variant: "success" | "warning" | "destructive"; label: string }
|
||||
{ tone: "success" | "warning" | "destructive"; label: string }
|
||||
> = {
|
||||
connected: { variant: "success", label: t.status.connected },
|
||||
disconnected: { variant: "warning", label: t.status.disconnected },
|
||||
fatal: { variant: "destructive", label: t.status.error },
|
||||
connected: { tone: "success", label: t.status.connected },
|
||||
disconnected: { tone: "warning", label: t.status.disconnected },
|
||||
fatal: { tone: "destructive", label: t.status.error },
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -30,7 +30,7 @@ export function PlatformsCard({ platforms }: PlatformsCardProps) {
|
||||
<CardContent className="grid gap-3">
|
||||
{platforms.map(([name, info]) => {
|
||||
const display = platformStateBadge[info.state] ?? {
|
||||
variant: "outline" as const,
|
||||
tone: "outline" as const,
|
||||
label: info.state,
|
||||
};
|
||||
const IconComponent =
|
||||
@@ -76,10 +76,10 @@ export function PlatformsCard({ platforms }: PlatformsCardProps) {
|
||||
</div>
|
||||
|
||||
<Badge
|
||||
variant={display.variant}
|
||||
tone={display.tone}
|
||||
className="shrink-0 self-start sm:self-center"
|
||||
>
|
||||
{display.variant === "success" && (
|
||||
{display.tone === "success" && (
|
||||
<span className="mr-1 inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-current" />
|
||||
)}
|
||||
{display.label}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center border px-2 py-0.5 font-compressed text-[0.65rem] tracking-[0.15em] uppercase transition-colors",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border-foreground/20 bg-foreground/10 text-foreground",
|
||||
secondary: "border-border bg-secondary text-secondary-foreground",
|
||||
destructive: "border-destructive/30 bg-destructive/15 text-destructive",
|
||||
outline: "border-border text-muted-foreground",
|
||||
success: "grain border-emerald-600/30 bg-emerald-950/70 text-emerald-400",
|
||||
warning: "border-warning/30 bg-warning/15 text-warning",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export function Badge({
|
||||
className,
|
||||
variant,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof badgeVariants>) {
|
||||
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import type { AnalyticsResponse, AnalyticsDailyEntry, AnalyticsModelEntry, Analy
|
||||
import { timeAgo } from "@/lib/utils";
|
||||
import { Button, Stats } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { usePageHeader } from "@/contexts/usePageHeader";
|
||||
import { useI18n } from "@/i18n";
|
||||
import { PluginSlot } from "@/plugins";
|
||||
@@ -279,7 +279,7 @@ export default function AnalyticsPage() {
|
||||
{loading && (
|
||||
<div className="h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
)}
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{periodLabel}
|
||||
</Badge>
|
||||
</span>,
|
||||
|
||||
@@ -36,7 +36,7 @@ import { AutoField } from "@/components/AutoField";
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { useI18n } from "@/i18n";
|
||||
import { usePageHeader } from "@/contexts/usePageHeader";
|
||||
import { PluginSlot } from "@/plugins";
|
||||
@@ -484,7 +484,7 @@ export default function ConfigPage() {
|
||||
<Search className="h-4 w-4" />
|
||||
{t.config.searchResults}
|
||||
</CardTitle>
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{searchMatchedFields.length} {t.config.fields.replace("{s}", searchMatchedFields.length !== 1 ? "s" : "")}
|
||||
</Badge>
|
||||
</div>
|
||||
@@ -508,7 +508,7 @@ export default function ConfigPage() {
|
||||
<CategoryIcon category={activeCategory} className="h-4 w-4" />
|
||||
{prettyCategoryName(activeCategory)}
|
||||
</CardTitle>
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{activeFields.length} {t.config.fields.replace("{s}", activeFields.length !== 1 ? "s" : "")}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useToast } from "@/hooks/useToast";
|
||||
import { useConfirmDelete } from "@/hooks/useConfirmDelete";
|
||||
import { Toast } from "@/components/Toast";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectOption } from "@/components/ui/select";
|
||||
@@ -21,7 +21,7 @@ function formatTime(iso?: string | null): string {
|
||||
return d.toLocaleString();
|
||||
}
|
||||
|
||||
const STATUS_VARIANT: Record<string, "success" | "warning" | "destructive"> = {
|
||||
const STATUS_TONE: Record<string, "success" | "warning" | "destructive"> = {
|
||||
enabled: "success",
|
||||
scheduled: "success",
|
||||
paused: "warning",
|
||||
@@ -273,11 +273,11 @@ export default function CronPage() {
|
||||
job.prompt.slice(0, 60) +
|
||||
(job.prompt.length > 60 ? "..." : "")}
|
||||
</span>
|
||||
<Badge variant={STATUS_VARIANT[job.state] ?? "secondary"}>
|
||||
<Badge tone={STATUS_TONE[job.state] ?? "secondary"}>
|
||||
{job.state}
|
||||
</Badge>
|
||||
{job.deliver && job.deliver !== "local" && (
|
||||
<Badge variant="outline">{job.deliver}</Badge>
|
||||
<Badge tone="outline">{job.deliver}</Badge>
|
||||
)}
|
||||
</div>
|
||||
{job.name && (
|
||||
|
||||
@@ -23,7 +23,7 @@ import { useToast } from "@/hooks/useToast";
|
||||
import { OAuthProvidersCard } from "@/components/OAuthProvidersCard";
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useI18n } from "@/i18n";
|
||||
@@ -173,7 +173,7 @@ function EnvVarRow({
|
||||
<div className="flex items-center justify-between gap-2 flex-wrap">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="font-mono-ui text-[0.7rem]">{varKey}</Label>
|
||||
<Badge variant={info.is_set ? "success" : "outline"}>
|
||||
<Badge tone={info.is_set ? "success" : "outline"}>
|
||||
{info.is_set ? t.common.set : t.env.notSet}
|
||||
</Badge>
|
||||
</div>
|
||||
@@ -190,7 +190,7 @@ function EnvVarRow({
|
||||
{info.tools.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{info.tools.map((tool) => (
|
||||
<Badge key={tool} variant="secondary" className="text-[0.6rem] py-0 px-1.5">{tool}</Badge>
|
||||
<Badge key={tool} tone="secondary" className="text-[0.6rem] py-0 px-1.5">{tool}</Badge>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
@@ -296,7 +296,7 @@ function ProviderGroupCard({
|
||||
{expanded ? <ChevronDown className="h-3.5 w-3.5 text-muted-foreground shrink-0" /> : <ChevronRight className="h-3.5 w-3.5 text-muted-foreground shrink-0" />}
|
||||
<span className="font-semibold text-sm tracking-wide">{group.name === "Other" ? t.common.other : group.name}</span>
|
||||
{hasAnyConfigured && (
|
||||
<Badge variant="success" className="text-[0.6rem]">
|
||||
<Badge tone="success" className="text-[0.6rem]">
|
||||
{configuredCount} {t.common.set.toLowerCase()}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FileText, RefreshCw } from "lucide-react";
|
||||
import { api } from "@/lib/api";
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { FilterGroup, Segmented } from "@/components/ui/segmented";
|
||||
@@ -76,7 +76,7 @@ export default function LogsPage() {
|
||||
{loading && (
|
||||
<div className="h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||
)}
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{file} · {level} · {component}
|
||||
</Badge>
|
||||
</span>,
|
||||
@@ -93,7 +93,7 @@ export default function LogsPage() {
|
||||
{t.logs.autoRefresh}
|
||||
</Label>
|
||||
{autoRefresh && (
|
||||
<Badge variant="success" className="text-[10px]">
|
||||
<Badge tone="success" className="text-[10px]">
|
||||
<span className="mr-1 inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-current" />
|
||||
{t.common.live}
|
||||
</Badge>
|
||||
|
||||
@@ -37,7 +37,7 @@ import { Markdown } from "@/components/Markdown";
|
||||
import { PlatformsCard } from "@/components/PlatformsCard";
|
||||
import { Toast } from "@/components/Toast";
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { DeleteConfirmDialog } from "@/components/DeleteConfirmDialog";
|
||||
import { useConfirmDelete } from "@/hooks/useConfirmDelete";
|
||||
@@ -190,7 +190,7 @@ function MessageBubble({
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className={`text-xs font-semibold ${style.text}`}>{label}</span>
|
||||
{isHit && (
|
||||
<Badge variant="warning" className="text-[9px] py-0 px-1.5">
|
||||
<Badge tone="warning" className="text-[9px] py-0 px-1.5">
|
||||
{t.common.match}
|
||||
</Badge>
|
||||
)}
|
||||
@@ -321,7 +321,7 @@ function SessionRow({
|
||||
: t.sessions.untitledSession}
|
||||
</span>
|
||||
{session.is_active && (
|
||||
<Badge variant="success" className="text-[10px] shrink-0">
|
||||
<Badge tone="success" className="text-[10px] shrink-0">
|
||||
<span className="mr-1 inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-current" />
|
||||
{t.common.live}
|
||||
</Badge>
|
||||
@@ -351,7 +351,7 @@ function SessionRow({
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<Badge variant="outline" className="text-[10px]">
|
||||
<Badge tone="outline" className="text-[10px]">
|
||||
{session.source ?? "local"}
|
||||
</Badge>
|
||||
{resumeInChatEnabled && (
|
||||
@@ -437,7 +437,7 @@ export default function SessionsPage() {
|
||||
return;
|
||||
}
|
||||
setAfterTitle(
|
||||
<Badge variant="secondary" className="text-xs tabular-nums">
|
||||
<Badge tone="secondary" className="text-xs tabular-nums">
|
||||
{total}
|
||||
</Badge>,
|
||||
);
|
||||
@@ -672,7 +672,7 @@ export default function SessionsPage() {
|
||||
</span>
|
||||
|
||||
<Badge
|
||||
variant={
|
||||
tone={
|
||||
actionStatus?.running
|
||||
? "warning"
|
||||
: actionStatus?.exit_code === 0
|
||||
@@ -756,7 +756,7 @@ export default function SessionsPage() {
|
||||
</div>
|
||||
|
||||
<Badge
|
||||
variant="outline"
|
||||
tone="outline"
|
||||
className="text-[10px] shrink-0 self-start sm:self-center"
|
||||
>
|
||||
<Database className="mr-1 h-3 w-3" />
|
||||
|
||||
@@ -20,7 +20,7 @@ import type { SkillInfo, ToolsetInfo } from "@/lib/api";
|
||||
import { useToast } from "@/hooks/useToast";
|
||||
import { Toast } from "@/components/Toast";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useI18n } from "@/i18n";
|
||||
@@ -359,7 +359,7 @@ export default function SkillsPage() {
|
||||
<Search className="h-4 w-4" />
|
||||
{t.skills.title}
|
||||
</CardTitle>
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{t.skills.resultCount
|
||||
.replace("{count}", String(searchMatchedSkills.length))
|
||||
.replace(
|
||||
@@ -403,7 +403,7 @@ export default function SkillsPage() {
|
||||
)
|
||||
: t.skills.all}
|
||||
</CardTitle>
|
||||
<Badge variant="secondary" className="text-[10px]">
|
||||
<Badge tone="secondary" className="text-[10px]">
|
||||
{t.skills.skillCount
|
||||
.replace("{count}", String(activeSkills.length))
|
||||
.replace("{s}", activeSkills.length !== 1 ? "s" : "")}
|
||||
@@ -460,7 +460,7 @@ export default function SkillsPage() {
|
||||
{labelText}
|
||||
</span>
|
||||
<Badge
|
||||
variant={ts.enabled ? "success" : "outline"}
|
||||
tone={ts.enabled ? "success" : "outline"}
|
||||
className="text-[10px]"
|
||||
>
|
||||
{ts.enabled
|
||||
@@ -481,7 +481,7 @@ export default function SkillsPage() {
|
||||
{ts.tools.map((tool) => (
|
||||
<Badge
|
||||
key={tool}
|
||||
variant="secondary"
|
||||
tone="secondary"
|
||||
className="text-[10px] font-mono"
|
||||
>
|
||||
{tool}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { api, fetchJSON } from "@/lib/api";
|
||||
import { cn, timeAgo, isoTimeAgo } from "@/lib/utils";
|
||||
import { Button } from "@nous-research/ui";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Badge } from "@nous-research/ui";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectOption } from "@/components/ui/select";
|
||||
|
||||
Reference in New Issue
Block a user