fix: replace all buttons for design system buttons

This commit is contained in:
Austin Pickett 2026-04-28 08:57:33 -04:00
parent 529eb29b6a
commit e116957a63
15 changed files with 117 additions and 193 deletions

View file

@ -160,7 +160,10 @@ function resolveIcon(name: string): ComponentType<{ className?: string }> {
return ICON_MAP[name] ?? Puzzle;
}
function buildNavItems(builtIn: NavItem[], manifests: PluginManifest[]): NavItem[] {
function buildNavItems(
builtIn: NavItem[],
manifests: PluginManifest[],
): NavItem[] {
const items = [...builtIn];
for (const manifest of manifests) {
@ -425,18 +428,22 @@ export default function App() {
>
<div
className={cn(
"flex h-14 shrink-0 items-center justify-between gap-2 px-5",
"flex h-14 shrink-0 items-center justify-between gap-2",
"border-b border-current/20",
)}
>
<Typography
className="font-bold text-[1.125rem] leading-[0.95] tracking-[0.0525rem] text-midground"
style={{ mixBlendMode: "plus-lighter" }}
>
Hermes
<br />
Agent
</Typography>
<div className="flex items-center gap-2">
<PluginSlot name="header-left" />
<Typography
className="font-bold text-[1.125rem] leading-[0.95] tracking-[0.0525rem] text-midground"
style={{ mixBlendMode: "plus-lighter" }}
>
Hermes
<br />
Agent
</Typography>
</div>
<button
type="button"
@ -452,8 +459,6 @@ export default function App() {
</button>
</div>
<PluginSlot name="header-left" />
<nav
className="min-h-0 w-full flex-1 overflow-y-auto overflow-x-hidden border-t border-current/10 py-2"
aria-label={t.app.navigation}
@ -545,7 +550,8 @@ export default function App() {
<div
className={cn(
"w-full min-w-0",
(isDocsRoute || isChatRoute) && "min-h-0 flex flex-1 flex-col",
(isDocsRoute || isChatRoute) &&
"min-h-0 flex flex-1 flex-col",
)}
>
<Routes>
@ -579,8 +585,9 @@ export default function App() {
or idle-disconnect after N minutes hidden; neither is
shipped today.
*/}
{embeddedChat && !chatOverriddenByPlugin && (
pluginsLoading ? (
{embeddedChat &&
!chatOverriddenByPlugin &&
(pluginsLoading ? (
// Direct /chat deep-link: plugin manifests haven't resolved
// yet, so we can't tell if a plugin is going to claim this
// route. Show a lightweight placeholder instead of a
@ -593,7 +600,10 @@ export default function App() {
aria-live="polite"
>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Loader2 className="h-4 w-4 animate-spin" aria-hidden />
<Loader2
className="h-4 w-4 animate-spin"
aria-hidden
/>
<span>Loading chat</span>
</div>
</div>
@ -609,8 +619,7 @@ export default function App() {
>
<ChatPage isActive={isChatRoute} />
</div>
)
)}
))}
</div>
<PluginSlot name="post-main" />
</div>

View file

@ -23,8 +23,8 @@
* terminal pane keeps working unimpaired.
*/
import { Button } from "@nous-research/ui";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { ModelPickerDialog } from "@/components/ModelPickerDialog";
@ -337,12 +337,11 @@ export function ChatSidebar({ channel, className }: ChatSidebarProps) {
{error && (
<Button
variant="ghost"
size="sm"
className="mt-1 h-6 px-1.5 text-xs"
outlined
className="mt-1"
onClick={reconnect}
prefix={<RefreshCw />}
>
<RefreshCw className="mr-1 h-3 w-3" />
reconnect
</Button>
)}

View file

@ -1,4 +1,4 @@
import { Button } from "@/components/ui/button";
import { Button } from "@nous-research/ui";
import { Input } from "@/components/ui/input";
import type { GatewayClient } from "@/lib/gatewayClient";
import { Check, Loader2, Search, X } from "lucide-react";
@ -222,10 +222,10 @@ export function ModelPickerDialog({ gw, sessionId, onClose, onSubmit }: Props) {
</label>
<div className="flex items-center gap-2 ml-auto">
<Button variant="ghost" size="sm" onClick={onClose}>
<Button outlined onClick={onClose}>
Cancel
</Button>
<Button size="sm" onClick={confirm} disabled={!canConfirm}>
<Button onClick={confirm} disabled={!canConfirm}>
Switch
</Button>
</div>

View file

@ -1,8 +1,7 @@
import { useEffect, useRef, useState } from "react";
import { ExternalLink, Copy, X, Check, Loader2 } from "lucide-react";
import { H2 } from "@nous-research/ui";
import { Button, H2 } from "@nous-research/ui";
import { api, type OAuthProvider, type OAuthStartResponse } from "@/lib/api";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useI18n } from "@/i18n";
@ -254,7 +253,6 @@ export function OAuthLoginModal({
<Button
onClick={handleSubmitPkceCode}
disabled={!pkceCode.trim()}
size="sm"
>
{t.oauth.submitCode}
</Button>
@ -289,8 +287,7 @@ export function OAuthLoginModal({
}
</code>
<Button
variant="outline"
size="sm"
outlined
onClick={() =>
handleCopyUserCode(
(
@ -301,12 +298,12 @@ export function OAuthLoginModal({
).user_code,
)
}
className="text-xs"
className="!p-2 aspect-square"
>
{codeCopied ? (
<Check className="h-3 w-3" />
<Check className="h-3.5 w-3.5" />
) : (
<Copy className="h-3 w-3" />
<Copy className="h-3.5 w-3.5" />
)}
</Button>
</div>
@ -348,11 +345,10 @@ export function OAuthLoginModal({
{errorMsg || t.oauth.loginFailed}
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" size="sm" onClick={handleClose}>
<Button outlined onClick={handleClose}>
{t.common.close}
</Button>
<Button
size="sm"
onClick={() => {
if (start?.session_id) {
api.cancelOAuthSession(start.session_id).catch(() => {});

View file

@ -1,8 +1,8 @@
import { useEffect, useState, useCallback, useRef } from "react";
import { ShieldCheck, ShieldOff, Copy, ExternalLink, RefreshCw, LogOut, Terminal, LogIn } from "lucide-react";
import { api, type OAuthProvider } from "@/lib/api";
import { Button } from "@nous-research/ui";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { OAuthLoginModal } from "@/components/OAuthLoginModal";
import { useI18n } from "@/i18n";
@ -94,13 +94,11 @@ export function OAuthProvidersCard({ onError, onSuccess }: Props) {
<CardTitle className="text-base">{t.oauth.providerLogins}</CardTitle>
</div>
<Button
variant="ghost"
size="sm"
outlined
onClick={refresh}
disabled={loading}
className="text-xs"
prefix={<RefreshCw className={loading ? "animate-spin" : undefined} />}
>
<RefreshCw className={`h-3 w-3 mr-1 ${loading ? "animate-spin" : ""}`} />
{t.common.refresh}
</Button>
</div>
@ -194,53 +192,42 @@ export function OAuthProvidersCard({ onError, onSuccess }: Props) {
className="inline-flex"
title={`Open ${p.name} docs`}
>
<Button variant="ghost" size="sm" className="h-7 w-7 p-0">
<Button outlined className="!p-1.5 aspect-square">
<ExternalLink className="h-3.5 w-3.5" />
</Button>
</a>
)}
{!p.status.logged_in && p.flow !== "external" && (
<Button
variant="default"
size="sm"
onClick={() => setLoginFor(p)}
className="text-xs h-7"
prefix={<LogIn />}
>
<LogIn className="h-3 w-3 mr-1" />
{t.oauth.login}
</Button>
)}
{!p.status.logged_in && (
<Button
variant="outline"
size="sm"
outlined
onClick={() => handleCopy(p)}
className="text-xs h-7"
title={t.oauth.copyCliCommand}
prefix={copiedId === p.id ? undefined : <Copy />}
>
{copiedId === p.id ? (
<>{t.oauth.copied}</>
) : (
<>
<Copy className="h-3 w-3 mr-1" />
{t.oauth.cli}
</>
)}
{copiedId === p.id ? t.oauth.copied : t.oauth.cli}
</Button>
)}
{p.status.logged_in && p.flow !== "external" && (
<Button
variant="outline"
size="sm"
outlined
onClick={() => handleDisconnect(p)}
disabled={isBusy}
className="text-xs h-7"
prefix={
isBusy ? (
<RefreshCw className="animate-spin" />
) : (
<LogOut />
)
}
>
{isBusy ? (
<RefreshCw className="h-3 w-3 mr-1 animate-spin" />
) : (
<LogOut className="h-3 w-3 mr-1" />
)}
{t.oauth.disconnect}
</Button>
)}

View file

@ -1,38 +0,0 @@
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
export const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap font-mondwest text-xs tracking-[0.1em] uppercase transition-colors cursor-pointer"
+ " disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-foreground/90 text-background hover:bg-foreground",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-border bg-transparent hover:bg-foreground/10 hover:text-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-foreground/10 hover:text-foreground",
link: "text-foreground underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 px-3 text-[0.65rem]",
lg: "h-10 px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
export function Button({
className,
variant,
size,
...props
}: React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>) {
return <button className={cn(buttonVariants({ variant, size }), className)} {...props} />;
}

View file

@ -1,8 +1,8 @@
import { useEffect, useRef } from "react";
import { createPortal } from "react-dom";
import { AlertTriangle } from "lucide-react";
import { Button } from "@nous-research/ui";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
export function ConfirmDialog({
cancelLabel = "Cancel",
@ -101,8 +101,7 @@ export function ConfirmDialog({
<div className="flex items-center justify-end gap-2 p-3">
<Button
type="button"
variant="ghost"
size="sm"
outlined
onClick={onCancel}
disabled={loading}
>
@ -111,10 +110,9 @@ export function ConfirmDialog({
<Button
data-confirm
type="button"
variant={destructive ? "destructive" : "default"}
size="sm"
onClick={onConfirm}
disabled={loading}
className={destructive ? "!bg-destructive !text-destructive-foreground" : undefined}
>
{loading ? "…" : confirmLabel}
</Button>

View file

@ -10,9 +10,9 @@ import {
import { api } from "@/lib/api";
import type { AnalyticsResponse, AnalyticsDailyEntry, AnalyticsModelEntry, AnalyticsSkillEntry } from "@/lib/api";
import { timeAgo } from "@/lib/utils";
import { Button } from "@nous-research/ui";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { usePageHeader } from "@/contexts/usePageHeader";
import { useI18n } from "@/i18n";
import { PluginSlot } from "@/plugins";
@ -317,9 +317,7 @@ export default function AnalyticsPage() {
<Button
key={p.label}
type="button"
variant={days === p.days ? "default" : "outline"}
size="sm"
className="h-7 min-w-0 text-xs"
outlined={days !== p.days}
onClick={() => setDays(p.days)}
>
{p.label}
@ -328,13 +326,11 @@ export default function AnalyticsPage() {
</div>
<Button
type="button"
variant="outline"
size="sm"
outlined
onClick={load}
disabled={loading}
className="h-7 text-xs"
prefix={<RefreshCw />}
>
<RefreshCw className="mr-1 h-3 w-3" />
{t.common.refresh}
</Button>
</div>,

View file

@ -33,8 +33,8 @@ import { getNestedValue, setNestedValue } from "@/lib/nested";
import { useToast } from "@/hooks/useToast";
import { Toast } from "@/components/Toast";
import { AutoField } from "@/components/AutoField";
import { Button } from "@nous-research/ui";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { useI18n } from "@/i18n";
@ -345,10 +345,10 @@ export default function ConfigPage() {
</code>
</div>
<div className="flex items-center gap-1.5">
<Button variant="ghost" size="sm" onClick={handleExport} title={t.config.exportConfig} aria-label={t.config.exportConfig}>
<Button outlined onClick={handleExport} title={t.config.exportConfig} aria-label={t.config.exportConfig} className="!p-2 aspect-square">
<Download className="h-3.5 w-3.5" />
</Button>
<Button variant="ghost" size="sm" onClick={() => fileInputRef.current?.click()} title={t.config.importConfig} aria-label={t.config.importConfig}>
<Button outlined onClick={() => fileInputRef.current?.click()} title={t.config.importConfig} aria-label={t.config.importConfig} className="!p-2 aspect-square">
<Upload className="h-3.5 w-3.5" />
</Button>
<input ref={fileInputRef} type="file" accept=".json" className="hidden" onChange={handleImport} />
@ -358,7 +358,7 @@ export default function ConfigPage() {
: prettyCategoryName(activeCategory);
const resetTitle = t.config.resetScopeTooltip.replace("{scope}", resetScopeLabel);
return (
<Button variant="ghost" size="sm" onClick={handleReset} title={resetTitle} aria-label={resetTitle}>
<Button outlined onClick={handleReset} title={resetTitle} aria-label={resetTitle} className="!p-2 aspect-square">
<RotateCcw className="h-3.5 w-3.5" />
</Button>
);
@ -367,32 +367,19 @@ export default function ConfigPage() {
<div className="w-px h-5 bg-border mx-1" />
<Button
variant={yamlMode ? "default" : "outline"}
size="sm"
outlined={!yamlMode}
onClick={() => setYamlMode(!yamlMode)}
className="gap-1.5"
prefix={yamlMode ? <FormInput /> : <Code />}
>
{yamlMode ? (
<>
<FormInput className="h-3.5 w-3.5" />
{t.common.form}
</>
) : (
<>
<Code className="h-3.5 w-3.5" />
YAML
</>
)}
{yamlMode ? t.common.form : "YAML"}
</Button>
{yamlMode ? (
<Button size="sm" onClick={handleYamlSave} disabled={yamlSaving} className="gap-1.5">
<Save className="h-3.5 w-3.5" />
<Button onClick={handleYamlSave} disabled={yamlSaving} prefix={<Save />}>
{yamlSaving ? t.common.saving : t.common.save}
</Button>
) : (
<Button size="sm" onClick={handleSave} disabled={saving} className="gap-1.5">
<Save className="h-3.5 w-3.5" />
<Button onClick={handleSave} disabled={saving} prefix={<Save />}>
{saving ? t.common.saving : t.common.save}
</Button>
)}

View file

@ -1,6 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { Clock, Pause, Play, Plus, Trash2, Zap } from "lucide-react";
import { H2 } from "@nous-research/ui";
import { Button, H2 } from "@nous-research/ui";
import { api } from "@/lib/api";
import type { CronJob } from "@/lib/api";
import { DeleteConfirmDialog } from "@/components/DeleteConfirmDialog";
@ -9,7 +9,6 @@ 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 { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectOption } from "@/components/ui/select";
@ -166,7 +165,6 @@ export default function CronPage() {
loading={jobDelete.isDeleting}
/>
{/* Create new job form */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
@ -237,9 +235,9 @@ export default function CronPage() {
<Button
onClick={handleCreate}
disabled={creating}
prefix={<Plus />}
className="w-full"
>
<Plus className="h-3 w-3" />
{creating ? t.common.creating : t.common.create}
</Button>
</div>
@ -248,7 +246,6 @@ export default function CronPage() {
</CardContent>
</Card>
{/* Jobs list */}
<div className="flex flex-col gap-3">
<H2
variant="sm"
@ -269,7 +266,6 @@ export default function CronPage() {
{jobs.map((job) => (
<Card key={job.id}>
<CardContent className="flex items-center gap-4 py-4">
{/* Info */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-sm truncate">
@ -306,16 +302,15 @@ export default function CronPage() {
)}
</div>
{/* Actions */}
<div className="flex items-center gap-1 shrink-0">
<Button
variant="ghost"
size="icon"
outlined
title={job.state === "paused" ? t.cron.resume : t.cron.pause}
aria-label={
job.state === "paused" ? t.cron.resume : t.cron.pause
}
onClick={() => handlePauseResume(job)}
className="!p-2 aspect-square"
>
{job.state === "paused" ? (
<Play className="h-4 w-4 text-success" />
@ -325,21 +320,21 @@ export default function CronPage() {
</Button>
<Button
variant="ghost"
size="icon"
outlined
title={t.cron.triggerNow}
aria-label={t.cron.triggerNow}
onClick={() => handleTrigger(job)}
className="!p-2 aspect-square"
>
<Zap className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
outlined
title={t.common.delete}
aria-label={t.common.delete}
onClick={() => jobDelete.requestDelete(job.id)}
className="!p-2 aspect-square"
>
<Trash2 className="h-4 w-4 text-destructive" />
</Button>
@ -348,6 +343,7 @@ export default function CronPage() {
</Card>
))}
</div>
<PluginSlot name="cron:bottom" />
</div>
);

View file

@ -2,12 +2,19 @@ import { useLayoutEffect } from "react";
import { ExternalLink } from "lucide-react";
import { useI18n } from "@/i18n";
import { usePageHeader } from "@/contexts/usePageHeader";
import { buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { PluginSlot } from "@/plugins";
export const HERMES_DOCS_URL = "https://hermes-agent.nousresearch.com/docs/";
const DS_BUTTON_OUTLINED_LINK_CN = cn(
"group relative inline-grid grid-cols-[auto_1fr_auto] items-center",
"px-[.9em_.75em] py-[1.25em] gap-2",
"leading-0 font-bold tracking-[0.2em] uppercase",
"text-midground bg-transparent shadow-midground",
"shadow-[inset_-1px_-1px_0_0_#00000080,inset_1px_1px_0_0_#ffffff80]",
);
export default function DocsPage() {
const { t } = useI18n();
const { setEnd } = usePageHeader();
@ -18,12 +25,9 @@ export default function DocsPage() {
href={HERMES_DOCS_URL}
target="_blank"
rel="noopener noreferrer"
className={cn(
buttonVariants({ variant: "outline", size: "sm" }),
"h-7 text-xs",
)}
className={DS_BUTTON_OUTLINED_LINK_CN}
>
<ExternalLink className="mr-1.5 h-3 w-3" />
<ExternalLink className="size-3.5" />
{t.app.openDocumentation}
</a>,
);

View file

@ -21,9 +21,9 @@ import { Toast } from "@/components/Toast";
import { useConfirmDelete } from "@/hooks/useConfirmDelete";
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 { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useI18n } from "@/i18n";
@ -134,9 +134,8 @@ function EnvVarRow({
{t.env.getKey} <ExternalLink className="h-2.5 w-2.5" />
</a>
)}
<Button size="sm" variant="outline" className="h-6 text-[0.6rem] px-2"
<Button outlined prefix={<Pencil />}
onClick={() => setEdits((prev) => ({ ...prev, [varKey]: "" }))}>
<Pencil className="h-2.5 w-2.5" />
{t.common.set}
</Button>
</div>
@ -159,9 +158,8 @@ function EnvVarRow({
{t.env.getKey} <ExternalLink className="h-2.5 w-2.5" />
</a>
)}
<Button size="sm" variant="outline" className="h-7 text-[0.6rem]"
<Button outlined prefix={<Pencil />}
onClick={() => setEdits((prev) => ({ ...prev, [varKey]: "" }))}>
<Pencil className="h-3 w-3" />
{t.common.set}
</Button>
</div>
@ -206,26 +204,25 @@ function EnvVarRow({
</div>
{info.is_set && (
<Button size="sm" variant="ghost" onClick={() => onReveal(varKey)}
<Button outlined onClick={() => onReveal(varKey)}
title={isRevealed ? t.env.hideValue : t.env.showValue}
aria-label={isRevealed ? `Hide ${varKey}` : `Reveal ${varKey}`}>
aria-label={isRevealed ? `Hide ${varKey}` : `Reveal ${varKey}`}
className="!p-2 aspect-square">
{isRevealed
? <EyeOff className="h-4 w-4" />
: <Eye className="h-4 w-4" />}
</Button>
)}
<Button size="sm" variant="outline"
<Button outlined prefix={<Pencil />}
onClick={() => setEdits((prev) => ({ ...prev, [varKey]: "" }))}>
<Pencil className="h-3 w-3" />
{info.is_set ? t.common.replace : t.common.set}
</Button>
{info.is_set && (
<Button size="sm" variant="ghost"
className="text-destructive hover:text-destructive hover:bg-destructive/10"
<Button outlined prefix={<Trash2 />}
className="text-destructive hover:!text-destructive"
onClick={() => onClear(varKey)} disabled={saving === varKey || clearDialogOpen}>
<Trash2 className="h-3 w-3" />
{saving === varKey ? "..." : t.common.clear}
</Button>
)}
@ -238,13 +235,12 @@ function EnvVarRow({
onChange={(e) => setEdits((prev) => ({ ...prev, [varKey]: e.target.value }))}
placeholder={info.is_set ? t.env.replaceCurrentValue.replace("{preview}", info.redacted_value ?? "---") : t.env.enterValue}
className="flex-1 font-mono-ui text-xs" />
<Button size="sm" onClick={() => onSave(varKey)}
<Button onClick={() => onSave(varKey)} prefix={<Save />}
disabled={saving === varKey || !edits[varKey]}>
<Save className="h-3 w-3" />
{saving === varKey ? "..." : t.common.save}
</Button>
<Button size="sm" variant="ghost" onClick={() => onCancelEdit(varKey)}>
<X className="h-3 w-3" /> {t.common.cancel}
<Button outlined prefix={<X />} onClick={() => onCancelEdit(varKey)}>
{t.common.cancel}
</Button>
</div>
)}
@ -537,7 +533,7 @@ export default function EnvPage() {
{t.env.changesNote}
</p>
</div>
<Button variant="ghost" size="sm" onClick={() => setShowAdvanced(!showAdvanced)}>
<Button outlined onClick={() => setShowAdvanced(!showAdvanced)}>
{showAdvanced ? t.env.hideAdvanced : t.env.showAdvanced}
</Button>
</div>

View file

@ -1,8 +1,8 @@
import { useEffect, useLayoutEffect, useState, useCallback, useRef } from "react";
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 { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
@ -101,13 +101,11 @@ export default function LogsPage() {
</div>
<Button
type="button"
variant="outline"
size="sm"
outlined
onClick={fetchLogs}
disabled={loading}
className="h-7 text-xs"
prefix={<RefreshCw />}
>
<RefreshCw className="mr-1 h-3 w-3" />
{t.common.refresh}
</Button>
</div>,

View file

@ -36,8 +36,8 @@ import { timeAgo } from "@/lib/utils";
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 { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { DeleteConfirmDialog } from "@/components/DeleteConfirmDialog";
import { useConfirmDelete } from "@/hooks/useConfirmDelete";
@ -356,9 +356,8 @@ function SessionRow({
</Badge>
{resumeInChatEnabled && (
<Button
variant="ghost"
size="icon"
className="h-7 w-7 text-muted-foreground hover:text-success"
outlined
className="!p-1.5 aspect-square text-muted-foreground hover:text-success"
aria-label={t.sessions.resumeInChat}
title={t.sessions.resumeInChat}
onClick={(e) => {
@ -370,9 +369,8 @@ function SessionRow({
</Button>
)}
<Button
variant="ghost"
size="icon"
className="h-7 w-7 text-muted-foreground hover:text-destructive"
outlined
className="!p-1.5 aspect-square text-muted-foreground hover:text-destructive"
aria-label={t.sessions.deleteSession}
onClick={(e) => {
e.stopPropagation();
@ -808,9 +806,8 @@ export default function SessionsPage() {
</span>
<div className="flex items-center gap-1">
<Button
variant="outline"
size="sm"
className="h-7 w-7 p-0"
outlined
className="!p-1.5 aspect-square"
disabled={page === 0}
onClick={() => setPage((p) => p - 1)}
aria-label={t.sessions.previousPage}
@ -822,9 +819,8 @@ export default function SessionsPage() {
{Math.ceil(total / PAGE_SIZE)}
</span>
<Button
variant="outline"
size="sm"
className="h-7 w-7 p-0"
outlined
className="!p-1.5 aspect-square"
disabled={(page + 1) * PAGE_SIZE >= total}
onClick={() => setPage((p) => p + 1)}
aria-label={t.sessions.nextPage}

View file

@ -19,9 +19,9 @@ import React, {
} from "react";
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 { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectOption } from "@/components/ui/select";