fix(web): use ink chrome and 12px type on secondary pages

Tags, attachments, plugins, templates, and the tag picker follow the 12px and 14px ink palette. Beta badges use the same 12px line height as the surrounding labels.
This commit is contained in:
tianma-if committed 2026-09-26 00:53:08 +08:00
1 parent 875eef0c15
commit ab6bad5218
16 files changed
+103 -104

No files matched your search

+12 -12
View File
@@ -183,7 +183,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
</TooltipProvider>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 text-slate-900 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<Sparkles className="h-4.5 w-4.5 text-emerald-600" />
<Sparkles className="h-4 w-4 text-slate-900" />
{t("aiPrompts.title")}
</h1>
<p className="mt-0.5 text-xs text-slate-500">{t("aiPrompts.description")}</p>
@@ -196,9 +196,9 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
<div className="mx-auto w-full max-w-5xl space-y-6">
<div className="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 className="flex items-center gap-2 text-sm font-bold text-slate-900">
<h2 className="flex items-center gap-2 text-sm font-semibold text-slate-900">
<span>{t("aiPrompts.listTitle")}</span>
<span className="rounded-full bg-emerald-100/70 px-2 py-0.5 text-xs font-semibold text-emerald-800">
<span className="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-700">
{prompts.length}
</span>
</h2>
@@ -227,7 +227,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
className="gap-1.5 border-slate-200 bg-card text-xs font-semibold text-slate-700 shadow-2xs hover:bg-slate-50 hover:text-slate-900"
onClick={startCreating}
>
<Plus className="h-3.5 w-3.5 text-emerald-600" />
<Plus className="h-3.5 w-3.5 text-slate-700" />
{t("aiPrompts.add")}
</Button>
</div>
@@ -241,15 +241,15 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
{editorOpen ? (
<form
className="rounded-xl border border-emerald-200 bg-card p-5 shadow-xs"
className="rounded-xl border border-slate-200 bg-card p-5 shadow-xs"
onSubmit={(event: FormEvent) => {
event.preventDefault();
if (canSubmit && hasChanges) saveMutation.mutate();
}}
>
<div className="mb-4 flex items-center justify-between border-b border-slate-100 pb-3">
<h3 className="flex items-center gap-2 text-sm font-bold text-slate-900">
<Pencil className="h-4 w-4 text-emerald-600" />
<h3 className="flex items-center gap-2 text-sm font-semibold text-slate-900">
<Pencil className="h-4 w-4 text-slate-900" />
{editing ? t("aiPrompts.edit") : t("aiPrompts.add")}
</h3>
<Button aria-label={t("common.close")} size="icon" variant="ghost" className="h-7 w-7 text-slate-400 hover:text-slate-600" type="button" onClick={cancelEditor}>
@@ -259,7 +259,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
<div className="grid gap-4">
<label className="grid gap-1.5 text-xs font-medium text-slate-700">
{t("aiPrompts.name")}
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={form.name}
onChange={(event) => setForm((current) => ({ ...current, name: event.target.value }))}
placeholder={t("aiPrompts.namePlaceholder")}
@@ -305,7 +305,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
</div>
<label className="grid gap-1.5 text-xs font-medium text-slate-700">
{t("aiPrompts.descriptionLabel")}
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={form.description}
onChange={(event) => setForm((current) => ({ ...current, description: event.target.value }))}
placeholder={t("aiPrompts.descriptionPlaceholder")}
@@ -315,7 +315,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
<label className="grid gap-1.5 text-xs font-medium text-slate-700">
{t("aiPrompts.instruction")}
<textarea
className="min-h-36 w-full resize-y rounded-lg border border-slate-200 bg-card p-3 text-sm text-slate-900 outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-emerald-500/20"
className="min-h-36 w-full resize-y rounded-lg border border-slate-200 bg-card p-3 text-sm text-slate-900 outline-none focus-visible:border-slate-400 focus-visible:ring-2 focus-visible:ring-slate-400/25"
value={form.instruction}
onChange={(event) => setForm((current) => ({ ...current, instruction: event.target.value }))}
placeholder={t("aiPrompts.instructionPlaceholder")}
@@ -347,7 +347,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
{prompts.map((prompt) => (
<article
key={prompt.id}
className="group flex flex-col justify-between rounded-xl border border-slate-200 bg-card p-4 transition-all duration-200 hover:border-emerald-300 hover:shadow-md"
className="group flex flex-col justify-between rounded-xl border border-slate-200 bg-card p-4 transition-all duration-200 hover:border-slate-300 hover:shadow-md"
>
<div className="min-w-0">
<div className="flex min-w-0 items-center gap-2">
@@ -421,7 +421,7 @@ export const AiPromptsPane = ({ onClose, onOpenExecutionCenter }: { onClose: ()
{t("aiPrompts.restoreDefaults")}
</Button>
<Button type="button" size="sm" variant="outline" className="gap-1.5" onClick={startCreating}>
<Plus className="h-3.5 w-3.5 text-emerald-600" />
<Plus className="h-3.5 w-3.5 text-slate-700" />
{t("aiPrompts.add")}
</Button>
</div>
+18 -18
View File
@@ -207,10 +207,10 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
</ButtonTooltip>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<Paperclip className="h-4.5 w-4.5 text-emerald-700" />
<Paperclip className="h-4 w-4 text-slate-900" />
{t("assets.title")}
</h1>
<p className="mt-0.5 flex flex-wrap items-center gap-2 text-xs font-medium text-slate-400 uppercase tracking-wider">
<p className="mt-0.5 flex flex-wrap items-center gap-2 text-xs text-slate-500">
<span className="inline-flex items-center gap-1">
<HardDrive className="h-3 w-3" />
{formatBytes(summary.totalBytes)}
@@ -234,10 +234,10 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
<button
key={type}
onClick={() => setFilterType(type)}
className={`rounded-lg px-3 py-1.5 text-xs font-semibold transition-all duration-200 ${
className={`rounded-lg border border-transparent px-3 py-1.5 text-xs transition-colors ${
filterType === type
? "bg-emerald-50 text-emerald-700 border border-emerald-200/50 shadow-[0_1px_2px_rgba(0,0,0,0.02)]"
: "text-slate-500 hover:bg-slate-50 border border-transparent"
? "bg-slate-950 font-semibold text-slate-50"
: "font-medium text-slate-600 hover:bg-slate-100"
}`}
>
{t(`assets.filters.${type}`)}
@@ -256,7 +256,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
aria-label={t("assets.searchPlaceholder")}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="h-9 w-full rounded-lg border border-slate-200 bg-slate-50/50 pl-9 pr-8 text-xs text-slate-800 placeholder-slate-400 transition-colors focus:border-emerald-500/50 focus:bg-card focus:outline-none focus:ring-1 focus:ring-emerald-500/20"
className="h-9 w-full rounded-lg border border-slate-200 bg-slate-50 pl-9 pr-8 text-xs text-slate-800 placeholder:text-slate-400 transition-colors focus:border-slate-400 focus:bg-slate-50 focus:outline-none focus:ring-1 focus:ring-slate-400/30"
/>
{searchQuery && (
<button
@@ -276,7 +276,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
aria-label={t("assets.gridView")}
aria-pressed={layoutMode === "grid"}
className={`flex h-8 w-8 items-center justify-center rounded-md transition-colors ${
layoutMode === "grid" ? "bg-card text-emerald-700 shadow-sm" : "text-slate-400 hover:text-slate-600"
layoutMode === "grid" ? "bg-card text-slate-950 shadow-sm" : "text-slate-400 hover:text-slate-700"
}`}
>
<Grid className="h-4 w-4" />
@@ -288,7 +288,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
aria-label={t("assets.listView")}
aria-pressed={layoutMode === "list"}
className={`flex h-8 w-8 items-center justify-center rounded-md transition-colors ${
layoutMode === "list" ? "bg-card text-emerald-700 shadow-sm" : "text-slate-400 hover:text-slate-600"
layoutMode === "list" ? "bg-card text-slate-950 shadow-sm" : "text-slate-400 hover:text-slate-700"
}`}
>
<List className="h-4 w-4" />
@@ -304,7 +304,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
<div className="mx-auto max-w-4xl">
{resourcesQuery.isLoading ? (
<div className="flex flex-col items-center justify-center py-32 text-slate-400">
<Loader2 className="h-8 w-8 animate-spin text-emerald-600 mb-2" />
<Loader2 className="mb-2 h-8 w-8 animate-spin text-slate-400" />
<span className="text-xs font-medium">{t("assets.loading")}</span>
</div>
) : filteredResources.length === 0 ? (
@@ -325,7 +325,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
{filteredResources.map((resource) => (
<div
key={resource.id}
className="group relative flex flex-col overflow-hidden rounded-xl border border-slate-200 bg-card shadow-sm transition-all duration-200 hover:border-emerald-500/40 hover:shadow-md"
className="group relative flex flex-col overflow-hidden rounded-xl border border-slate-200 bg-card shadow-sm transition-all duration-200 hover:border-slate-300 hover:shadow-md"
>
<ButtonTooltip title={t("assets.deleteAria", { filename: resource.filename || resource.id })}>
<Button
@@ -369,8 +369,8 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
/>
) : (
<div className="flex flex-col items-center gap-1.5 p-3 text-center">
<AttachmentFileIcon mimeType={resource.mimeType} filename={resource.filename} />
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-[9px] font-bold text-slate-500 uppercase tracking-wider">
<AttachmentFileIcon mimeType={resource.mimeType} filename={resource.filename} className="text-slate-700" />
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-xs font-semibold text-slate-500">
{(resource.filename || "").split(".").pop() || "FILE"}
</span>
</div>
@@ -391,7 +391,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
{/* Metadata area */}
<div className="flex flex-col p-3 min-w-0">
<ButtonTooltip title={resource.filename || resource.id}>
<span className="truncate text-xs font-bold text-slate-800 leading-snug group-hover:text-emerald-700 transition-colors">
<span className="truncate text-sm font-semibold leading-snug text-slate-950">
{resource.filename || resource.id}
</span>
</ButtonTooltip>
@@ -404,7 +404,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
? t("assets.deletedMemo")
: t("assets.fromMemo", { source: resource.memoTitle || resource.memoExcerpt || resource.memoId })
}>
<span className="mt-1.5 truncate text-[9px] text-slate-400 border-t border-slate-50 pt-1">
<span className="mt-1.5 truncate border-t border-slate-100 pt-1 text-xs text-slate-500">
📄 {resource.memoDeleted ? t("assets.deletedMemo") : resource.memoTitle || resource.memoExcerpt || t("assets.unnamedMemo")}
</span>
</ButtonTooltip>
@@ -418,7 +418,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
{filteredResources.map((resource) => (
<div
key={resource.id}
className="group relative flex items-center gap-3.5 rounded-xl border border-slate-200/80 bg-card p-3.5 text-left transition-all duration-200 hover:border-emerald-500/35 hover:shadow-sm"
className="group relative flex items-center gap-3.5 rounded-xl border border-slate-200/80 bg-card p-3.5 text-left transition-all duration-200 hover:border-slate-300 hover:shadow-sm"
>
{/* Left Icon/Thumbnail */}
<div
@@ -449,13 +449,13 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
className="p-1"
/>
) : (
<AttachmentFileIcon mimeType={resource.mimeType} filename={resource.filename} />
<AttachmentFileIcon mimeType={resource.mimeType} filename={resource.filename} className="text-slate-700" />
)}
</div>
{/* Mid Info */}
<div className="min-w-0 flex-1">
<span className="block truncate text-sm font-bold text-slate-800 leading-snug group-hover:text-emerald-700 transition-colors">
<span className="block truncate text-sm font-semibold leading-snug text-slate-950">
{resource.filename || resource.id}
</span>
<span className="mt-1 block truncate text-xs font-medium text-slate-400">
@@ -486,7 +486,7 @@ export const AssetsPane = ({ onClose, repository, onOpenExecutionCenter }: Asset
target="_blank"
rel="noreferrer"
aria-label={t("assets.openInNewWindow")}
className="edgeever-reveal-on-touch flex h-8 w-8 items-center justify-center rounded-lg text-slate-350 hover:bg-slate-50 hover:text-emerald-600 opacity-0 group-hover:opacity-100 focus:opacity-100 focus-within:opacity-100 transition-all duration-150"
className="edgeever-reveal-on-touch flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 opacity-0 transition-all duration-150 hover:bg-slate-50 hover:text-slate-800 focus:opacity-100 focus-within:opacity-100 group-hover:opacity-100"
>
<ExternalLink className="h-4 w-4" />
</a>
+14 -13
View File
@@ -151,7 +151,7 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
<button
type="button"
disabled={disabled}
className="flex h-7 min-w-0 max-w-[32rem] items-center gap-1 rounded-md border border-transparent px-1.5 text-left text-xs text-slate-500 outline-none transition hover:border-slate-200 hover:bg-slate-50 focus-visible:border-emerald-300 focus-visible:ring-2 focus-visible:ring-emerald-500/15 disabled:opacity-50 sm:gap-1.5 sm:px-2"
className="flex h-7 min-w-0 max-w-[32rem] items-center gap-1 rounded-md border border-transparent px-1.5 text-left text-xs text-slate-500 outline-none transition hover:border-slate-200 hover:bg-slate-50 focus-visible:border-slate-300 focus-visible:ring-2 focus-visible:ring-slate-400/25 disabled:opacity-50 sm:gap-1.5 sm:px-2"
aria-label={t("editor.tagPicker.open")}
onClick={() => setOpen(true)}
>
@@ -160,7 +160,7 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
{selectedTags.slice(0, 3).map((tag) => (
<span
key={tag}
className="rounded-sm bg-slate-100 px-1.5 py-0.5 text-xs font-medium text-slate-600"
className="shrink-0 whitespace-nowrap rounded-sm bg-slate-100 px-1.5 py-0.5 text-xs font-medium text-slate-600"
>
#{tag}
</span>
@@ -184,8 +184,8 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
className={aiStatus.kind === "error"
? "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-rose-700 outline-none transition hover:bg-rose-50 focus-visible:ring-2 focus-visible:ring-rose-500/20 disabled:opacity-50"
: aiStatus.kind === "success"
? "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-emerald-50 text-emerald-700 outline-none transition focus-visible:ring-2 focus-visible:ring-emerald-500/20 disabled:opacity-50"
: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-emerald-700 outline-none transition hover:bg-emerald-50 focus-visible:ring-2 focus-visible:ring-emerald-500/20 disabled:opacity-50"}
? "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-emerald-50 text-emerald-700 outline-none transition focus-visible:ring-2 focus-visible:ring-slate-400/30 disabled:opacity-50"
: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-slate-600 outline-none transition hover:bg-slate-100 hover:text-slate-950 focus-visible:ring-2 focus-visible:ring-slate-400/30 disabled:opacity-50"}
aria-label={aiDescription}
onClick={() => void generateAndApplyTags()}
>
@@ -208,8 +208,8 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="flex max-h-[min(42rem,calc(100dvh-2rem))] max-w-lg flex-col overflow-hidden">
<DialogHeader>
<DialogTitle>{t("editor.tagPicker.title")}</DialogTitle>
<DialogDescription>{t("editor.tagPicker.description")}</DialogDescription>
<DialogTitle className="text-xs font-semibold leading-5">{t("editor.tagPicker.title")}</DialogTitle>
<DialogDescription className="text-xs leading-5">{t("editor.tagPicker.description")}</DialogDescription>
</DialogHeader>
{selectedTags.length > 0 && (
@@ -218,7 +218,7 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
<button
key={tag}
type="button"
className="inline-flex h-8 items-center gap-1 rounded-full bg-emerald-50 px-3 text-sm font-medium text-emerald-800 outline-none hover:bg-emerald-100 focus-visible:ring-2 focus-visible:ring-emerald-500/30"
className="inline-flex h-7 items-center gap-1 rounded-full bg-slate-100 px-2.5 text-xs font-medium text-slate-800 outline-none hover:bg-slate-200 focus-visible:ring-2 focus-visible:ring-slate-400/40"
onClick={() => toggleTag(tag)}
aria-label={t("editor.tagPicker.remove", { name: tag })}
>
@@ -235,17 +235,18 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
onChange={(event) => setQuery(event.target.value)}
placeholder={t("editor.tagPicker.searchPlaceholder")}
aria-label={t("editor.tagPicker.searchPlaceholder")}
className="h-9 text-xs focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
/>
<Button type="submit" variant="outline" disabled={!normalizedQuery || exactMatch || selectedTags.length >= 24}>
<Button type="submit" variant="outline" size="sm" className="h-9 px-3 text-xs" disabled={!normalizedQuery || exactMatch || selectedTags.length >= 24}>
{t("editor.tagPicker.create")}
</Button>
</form>
<div className="min-h-0 flex-1 overflow-y-auto rounded-md border border-slate-200">
{tagsQuery.isLoading ? (
<p className="px-4 py-8 text-center text-sm text-slate-500">{t("editor.tagPicker.loading")}</p>
<p className="px-4 py-8 text-center text-xs text-slate-500">{t("editor.tagPicker.loading")}</p>
) : visibleTags.length === 0 ? (
<p className="px-4 py-8 text-center text-sm text-slate-500">{t("editor.tagPicker.empty")}</p>
<p className="px-4 py-8 text-center text-xs text-slate-500">{t("editor.tagPicker.empty")}</p>
) : (
visibleTags.map((tag) => {
const selected = selectedTags.includes(tag.name);
@@ -253,12 +254,12 @@ export const EditorTagPicker = ({ contentMarkdown, disabled, loadTags, title, va
<button
key={tag.name}
type="button"
className="flex min-h-11 w-full items-center gap-3 border-b border-slate-100 px-3 text-left text-sm outline-none last:border-b-0 hover:bg-slate-50 focus-visible:bg-emerald-50"
className="flex min-h-11 w-full items-center gap-3 border-b border-slate-100 px-3 text-left text-xs outline-none last:border-b-0 hover:bg-slate-50 focus-visible:bg-slate-100"
onClick={() => toggleTag(tag.name)}
aria-pressed={selected}
>
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded border border-slate-300 text-emerald-700">
{selected && <Check className="h-4 w-4" />}
<span className={`flex h-5 w-5 shrink-0 items-center justify-center rounded border ${selected ? "border-slate-950 bg-slate-950 text-slate-50" : "border-slate-300 bg-card text-transparent"}`}>
{selected && <Check className="h-3.5 w-3.5" />}
</span>
<span className="min-w-0 flex-1 truncate font-medium">#{tag.name}</span>
<span className="text-xs text-slate-400">{t("editor.tagPicker.memoCount", { count: tag.memoCount })}</span>
@@ -29,7 +29,7 @@ export const EvernoteImportGuidePane = ({ onClose, onOpenExecutionCenter }: { on
</Button>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<HelpCircle className="h-4 w-4 text-emerald-700" />
<HelpCircle className="h-4 w-4 text-slate-900" />
{t("evernoteGuide.title")}
</h1>
<p className="mt-0.5 truncate text-xs font-medium text-slate-400">
+2 -2
View File
@@ -326,14 +326,14 @@ const CreateMemoTypeItems = ({ onCreateMemo }: { onCreateMemo: (kind?: NoteCreat
<DropdownMenuItem className="gap-2 text-xs leading-5" onSelect={() => onCreateMemo("infographic")}>
<Presentation className="h-4 w-4 shrink-0" />
<span className="min-w-0 flex-1 truncate">{t("infographic.name")}</span>
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 py-0.5 text-xs font-semibold leading-none tracking-wide text-emerald-700">
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 text-xs font-normal leading-5 text-emerald-700">
Beta
</span>
</DropdownMenuItem>
<DropdownMenuItem className="gap-2 text-xs leading-5" onSelect={() => onCreateMemo("table")}>
<TableProperties className="h-4 w-4 shrink-0" />
<span className="min-w-0 flex-1 truncate">{t("structuredTable.name")}</span>
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 py-0.5 text-xs font-semibold leading-none tracking-wide text-emerald-700">
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 text-xs font-normal leading-5 text-emerald-700">
Beta
</span>
</DropdownMenuItem>
@@ -46,7 +46,7 @@ export const PluginMarketplacePane = ({
<ChevronLeft className="h-5 w-5 text-slate-500" />
</Button>
<h1 className={`flex min-w-0 items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<Store className="h-4 w-4 shrink-0 text-emerald-700" />
<Store className="h-4 w-4 shrink-0 text-slate-900" />
<span className="truncate text-slate-900">{t("plugins.marketplace.title")}</span>
</h1>
</div>
+1 -1
View File
@@ -386,7 +386,7 @@ export const SettingsPane = ({
</div>
<span className="text-xs font-normal leading-5 text-slate-800">{item.label}</span>
{item.badge ? (
<span className="rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 py-0.5 text-xs font-semibold text-emerald-700">
<span className="rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 text-xs font-normal leading-5 text-emerald-700">
{item.badge}
</span>
) : null}
+4 -4
View File
@@ -61,7 +61,7 @@ export const TagsPane = ({
</Button>
</ButtonTooltip>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}><Tag className="h-4 w-4 text-emerald-700" />{t("tagsDialog.title")}</h1>
<h1 className={`flex items-center gap-2 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}><Tag className="h-4 w-4 text-slate-900" />{t("tagsDialog.title")}</h1>
<p className="mt-0.5 text-xs text-slate-500">{t("tagsDialog.count", { count: tags.length })}</p>
</div>
</div>
@@ -80,12 +80,12 @@ export const TagsPane = ({
const isEditing = editingTagName === tag.name;
const nextName = editingTagValue.trim();
return (
<div key={tag.name} className={cn("flex min-h-12 items-center gap-3 rounded-md border border-slate-200 bg-card px-3 py-2", isEditing && "border-emerald-200 bg-emerald-50/30")}>
<div key={tag.name} className={cn("flex min-h-12 items-center gap-3 rounded-md border border-slate-200 bg-card px-3 py-2", isEditing && "border-slate-300 bg-slate-50")}>
{isEditing ? (
<div className="min-w-0 flex-1">
<form className="flex min-w-0 flex-col gap-2 sm:flex-row sm:items-center" onSubmit={(event) => { event.preventDefault(); if (nextName && nextName !== tag.name && !renameMutation.isPending) renameMutation.mutate({ tag: tag.name, name: nextName }); }}>
<label className="sr-only" htmlFor={`tag-rename-${tag.name}`}>{t("tagsDialog.nameLabel")}</label>
<Input id={`tag-rename-${tag.name}`} className="h-9 min-w-0 flex-1 focus-visible:border-emerald-300 focus-visible:ring-emerald-500/20" value={editingTagValue} autoFocus disabled={renameMutation.isPending} maxLength={80} onChange={(event) => setEditingTagValue(event.target.value)} onKeyDown={(event) => { if (event.key === "Escape") { event.preventDefault(); cancelRename(); } }} />
<Input id={`tag-rename-${tag.name}`} className="h-9 min-w-0 flex-1 focus-visible:border-slate-400 focus-visible:ring-slate-400/25" value={editingTagValue} autoFocus disabled={renameMutation.isPending} maxLength={80} onChange={(event) => setEditingTagValue(event.target.value)} onKeyDown={(event) => { if (event.key === "Escape") { event.preventDefault(); cancelRename(); } }} />
<div className="flex shrink-0 gap-2">
<Button className="justify-center" size="sm" type="submit" variant="solid" disabled={!nextName || nextName === tag.name || renameMutation.isPending}>{t("common.save")}</Button>
<Button size="sm" type="button" variant="outline" onClick={cancelRename} disabled={renameMutation.isPending}>{t("common.cancel")}</Button>
@@ -94,7 +94,7 @@ export const TagsPane = ({
</div>
) : (
<button
className="min-w-0 flex-1 rounded-md px-1 py-1 text-left transition hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/30"
className="min-w-0 flex-1 rounded-md px-1 py-1 text-left transition hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400/40"
type="button"
onClick={() => onSelectTag(tag.name)}
>
+20 -20
View File
@@ -173,7 +173,7 @@ export const TemplatesPane = ({
</Tooltip>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 text-slate-900 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<LayoutList className="h-4.5 w-4.5 text-emerald-600" />
<LayoutList className="h-4 w-4 text-slate-900" />
{t("templates.title")}
</h1>
<p className="mt-0.5 text-xs text-slate-500">{t("templates.description")}</p>
@@ -190,9 +190,9 @@ export const TemplatesPane = ({
<section>
<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
<div>
<h2 className="flex items-center gap-2 text-sm font-bold text-slate-900">
<h2 className="flex items-center gap-2 text-sm font-semibold text-slate-900">
<span>{t("templates.myTemplates")}</span>
<span className="rounded-full bg-emerald-100/70 px-2 py-0.5 text-xs font-semibold text-emerald-800">
<span className="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-700">
{savedTemplates.length}
</span>
</h2>
@@ -207,7 +207,7 @@ export const TemplatesPane = ({
onClick={startCreating}
disabled={isCreating}
>
<Plus className="h-3.5 w-3.5 text-emerald-600" />
<Plus className="h-3.5 w-3.5 text-slate-700" />
{t("templates.create")}
</Button>
)}
@@ -215,10 +215,10 @@ export const TemplatesPane = ({
{/* Form for Creating / Editing Template */}
{(editingTemplate || creatingTemplate) && (
<div className="mb-6 rounded-xl border border-emerald-200 bg-card p-5 shadow-xs transition-all">
<div className="mb-6 rounded-xl border border-slate-200 bg-card p-5 shadow-xs transition-all">
<div className="mb-4 flex items-center justify-between border-b border-slate-100 pb-3">
<h3 className="flex items-center gap-2 text-sm font-bold text-slate-900">
<Pencil className="h-4 w-4 text-emerald-600" />
<h3 className="flex items-center gap-2 text-sm font-semibold text-slate-900">
<Pencil className="h-4 w-4 text-slate-900" />
{creatingTemplate ? t("templates.createTemplateTitle") : t("templates.editTemplateTitle")}
</h3>
<Button size="icon" variant="ghost" className="h-7 w-7 text-slate-400 hover:text-slate-600" onClick={cancelEditing}>
@@ -230,7 +230,7 @@ export const TemplatesPane = ({
<div className="grid gap-3 sm:grid-cols-2">
<div>
<label className="mb-1 block text-xs font-medium text-slate-700">{t("templates.name")}</label>
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={draft.name}
onChange={(e) => setDraft((c) => ({ ...c, name: e.target.value }))}
placeholder={t("templates.namePlaceholder")}
@@ -238,7 +238,7 @@ export const TemplatesPane = ({
</div>
<div>
<label className="mb-1 block text-xs font-medium text-slate-700">{t("templates.noteTitle")}</label>
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={draft.title}
onChange={(e) => setDraft((c) => ({ ...c, title: e.target.value }))}
placeholder={t("templates.noteTitlePlaceholder")}
@@ -249,7 +249,7 @@ export const TemplatesPane = ({
<div className="grid gap-3 sm:grid-cols-2">
<div>
<label className="mb-1 block text-xs font-medium text-slate-700">{t("templates.descriptionField")}</label>
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={draft.description}
onChange={(e) => setDraft((c) => ({ ...c, description: e.target.value }))}
placeholder={t("templates.descriptionPlaceholder")}
@@ -257,7 +257,7 @@ export const TemplatesPane = ({
</div>
<div>
<label className="mb-1 block text-xs font-medium text-slate-700">{t("templates.tags")}</label>
<Input
<Input className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
value={draft.tags}
onChange={(e) => setDraft((c) => ({ ...c, tags: e.target.value }))}
placeholder={t("templates.tagsPlaceholder")}
@@ -289,7 +289,7 @@ export const TemplatesPane = ({
{editorTab === "raw" ? (
<textarea
className="min-h-48 w-full resize-y rounded-lg border border-slate-200 bg-card p-3.5 font-mono text-xs text-slate-900 outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-emerald-500/20"
className="min-h-48 w-full resize-y rounded-lg border border-slate-200 bg-card p-3.5 font-mono text-xs text-slate-900 outline-none focus-visible:border-slate-400 focus-visible:ring-2 focus-visible:ring-slate-400/25"
value={draft.contentMarkdown}
onChange={(e) => setDraft((c) => ({ ...c, contentMarkdown: e.target.value }))}
placeholder={t("templates.contentPlaceholder")}
@@ -332,7 +332,7 @@ export const TemplatesPane = ({
{savedTemplates.map((template) => (
<div
key={template.id}
className="group relative flex flex-col justify-between rounded-xl border border-slate-200 bg-card p-4 transition-all duration-200 hover:border-emerald-300 hover:shadow-md cursor-pointer"
className="group relative flex cursor-pointer flex-col justify-between rounded-xl border border-slate-200 bg-card p-4 transition-all duration-200 hover:border-slate-300 hover:shadow-md"
onClick={() =>
setPreviewTemplate({
title: template.name,
@@ -347,10 +347,10 @@ export const TemplatesPane = ({
<div>
<div className="mb-2 flex items-start justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-emerald-50 text-emerald-700">
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-slate-800">
<FilePlus className="h-4 w-4" />
</span>
<h3 className="truncate font-bold text-slate-900 text-sm">{template.name}</h3>
<h3 className="truncate text-sm font-semibold text-slate-900">{template.name}</h3>
</div>
</div>
@@ -425,7 +425,7 @@ export const TemplatesPane = ({
<button
type="button"
className="inline-flex items-center gap-1.5 rounded-lg border border-emerald-200/80 bg-emerald-50/70 px-3 py-1.5 text-xs font-semibold text-emerald-800 hover:bg-emerald-500 hover:text-white hover:border-emerald-500 transition-all duration-200 disabled:opacity-50"
className="inline-flex items-center gap-1.5 rounded-lg bg-slate-950 px-3 py-1.5 text-xs font-semibold text-slate-50 transition-colors hover:bg-slate-800 disabled:opacity-50"
disabled={!canCreateMemo || isCreating}
onClick={(e) => {
e.stopPropagation();
@@ -441,13 +441,13 @@ export const TemplatesPane = ({
</div>
) : !creatingTemplate && !editingTemplate ? (
<div className="flex flex-col items-center justify-center rounded-xl border border-dashed border-slate-200 bg-card p-7 text-center shadow-2xs">
<div className="mb-2.5 flex h-11 w-11 items-center justify-center rounded-full bg-emerald-50 text-emerald-600">
<div className="mb-2.5 flex h-11 w-11 items-center justify-center rounded-full bg-slate-100 text-slate-700">
<Sparkles className="h-5 w-5" />
</div>
<h3 className="text-sm font-bold text-slate-900">{t("templates.emptyMyTemplates")}</h3>
<h3 className="text-sm font-semibold text-slate-900">{t("templates.emptyMyTemplates")}</h3>
<p className="mt-1 max-w-sm text-xs leading-relaxed text-slate-500">{t("templates.emptyMyTemplatesHint")}</p>
<Button type="button" size="sm" variant="outline" className="mt-3.5 gap-1.5 border-slate-200 text-xs font-semibold" onClick={startCreating}>
<Plus className="h-3.5 w-3.5 text-emerald-600" />
<Plus className="h-3.5 w-3.5 text-slate-700" />
{t("templates.create")}
</Button>
</div>
@@ -484,7 +484,7 @@ export const TemplatesPane = ({
)}
<div>
<h4 className="mb-2 text-xs font-semibold text-slate-500 uppercase tracking-wider">{t("templates.previewTitle")}</h4>
<h4 className="mb-2 text-xs font-semibold text-slate-500">{t("templates.previewTitle")}</h4>
<div className="rounded-xl border border-slate-200 bg-card p-4 text-xs text-slate-800 shadow-2xs min-h-[120px]">
<div className="prose prose-xs max-w-none" dangerouslySetInnerHTML={{ __html: previewHtmlContent }} />
</div>
@@ -111,7 +111,7 @@ export const MobileBottomNav = ({
<DropdownMenuItem className="gap-2 text-xs leading-5" onSelect={() => onCreateMemo("table")}>
<TableProperties className="h-4 w-4 shrink-0" />
<span className="min-w-0 flex-1 truncate">{t("structuredTable.name")}</span>
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 py-0.5 text-xs font-semibold leading-none tracking-wide text-emerald-700">
<span className="inline-flex shrink-0 items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 text-xs font-normal leading-5 text-emerald-700">
Beta
</span>
</DropdownMenuItem>
@@ -25,16 +25,16 @@ export const AttachmentFileIcon = ({
const commonClassName = cn("h-8 w-8 shrink-0", className);
switch (kind) {
case "image": return <ImageIcon className={cn(commonClassName, "text-emerald-500")} aria-hidden="true" />;
case "audio": return <Music className={cn(commonClassName, "text-sky-500")} aria-hidden="true" />;
case "video": return <Video className={cn(commonClassName, "text-rose-500")} aria-hidden="true" />;
case "pdf": return <FileText className={cn(commonClassName, "text-rose-600")} aria-hidden="true" />;
case "spreadsheet": return <FileSpreadsheet className={cn(commonClassName, "text-green-600")} aria-hidden="true" />;
case "document": return <FileText className={cn(commonClassName, "text-blue-600")} aria-hidden="true" />;
case "presentation": return <Presentation className={cn(commonClassName, "text-orange-500")} aria-hidden="true" />;
case "archive": return <FileArchive className={cn(commonClassName, "text-amber-500")} aria-hidden="true" />;
case "code": return <FileCode2 className={cn(commonClassName, "text-violet-500")} aria-hidden="true" />;
case "text": return <FileText className={cn(commonClassName, "text-slate-500")} aria-hidden="true" />;
default: return <File className={cn(commonClassName, "text-slate-400")} aria-hidden="true" />;
case "image": return <ImageIcon className={cn("text-emerald-500", commonClassName)} aria-hidden="true" />;
case "audio": return <Music className={cn("text-sky-500", commonClassName)} aria-hidden="true" />;
case "video": return <Video className={cn("text-rose-500", commonClassName)} aria-hidden="true" />;
case "pdf": return <FileText className={cn("text-rose-600", commonClassName)} aria-hidden="true" />;
case "spreadsheet": return <FileSpreadsheet className={cn("text-green-600", commonClassName)} aria-hidden="true" />;
case "document": return <FileText className={cn("text-blue-600", commonClassName)} aria-hidden="true" />;
case "presentation": return <Presentation className={cn("text-orange-500", commonClassName)} aria-hidden="true" />;
case "archive": return <FileArchive className={cn("text-amber-500", commonClassName)} aria-hidden="true" />;
case "code": return <FileCode2 className={cn("text-violet-500", commonClassName)} aria-hidden="true" />;
case "text": return <FileText className={cn("text-slate-500", commonClassName)} aria-hidden="true" />;
default: return <File className={cn("text-slate-400", commonClassName)} aria-hidden="true" />;
}
};
@@ -60,7 +60,7 @@ export const ExecutionCenterPane = ({
</Button>
<div className="min-w-0">
<h1 className={`flex items-center gap-2 text-slate-900 ${WORKSPACE_PAGE_TITLE_CLASSNAME}`}>
<ScrollText className="h-4.5 w-4.5 shrink-0 text-emerald-700" />
<ScrollText className="h-4 w-4 shrink-0 text-slate-900" />
<span className="truncate">{t("executionHistory.centerTitle")}</span>
</h1>
<p className="mt-0.5 hidden truncate text-xs text-slate-500 sm:block">
+1 -1
View File
@@ -128,7 +128,7 @@ export const PdfThumbnail = memo(({ url, label, byteSize, className }: PdfThumbn
return (
<span ref={hostRef} className={cn("relative flex h-full w-full items-center justify-center overflow-hidden", className)}>
{!rendered ? <FileText className="h-8 w-8 text-rose-600" aria-hidden="true" /> : null}
{!rendered ? <FileText className="h-8 w-8 text-slate-600" aria-hidden="true" /> : null}
<canvas
ref={canvasRef}
role={rendered ? "img" : undefined}
@@ -17,10 +17,7 @@ import { getPluginDetailPath, hasPluginSettings, isPluginCardCommand } from "@/l
import type { PluginUpdateInfo } from "@/lib/plugins/plugin-updates";
import type { RegisteredPluginCommand } from "@/lib/plugins/plugin-host";
const sourceBadgeClassName = (sourceKey: ReturnType<typeof getPluginCatalogSourceKey>) =>
sourceKey === "github" || sourceKey === "manifest"
? "bg-amber-50 text-amber-700"
: "bg-emerald-50 text-emerald-700";
const sourceBadgeClassName = "bg-slate-100 text-slate-700";
export const PluginCatalogCard = ({
item,
@@ -63,7 +60,7 @@ export const PluginCatalogCard = ({
aria-label={extension ? t("plugins.details.open", { name }) : undefined}
className={`flex min-w-0 flex-col rounded-lg border border-slate-200 bg-card p-3 ${
extension
? "cursor-pointer transition-colors hover:border-emerald-300 hover:bg-emerald-50/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/70"
? "cursor-pointer transition-colors hover:border-slate-300 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400/40"
: ""
}`}
onClick={extension ? (event) => {
@@ -86,19 +83,19 @@ export const PluginCatalogCard = ({
{extension.manifest.type}
</span>
) : null}
{extension && version ? <span className="text-xs text-slate-400">v{version}</span> : null}
{extension && version ? <span className="text-xs text-slate-500">v{version}</span> : null}
{sourceKey === "official" ? (
<span className="rounded-full bg-emerald-50 px-2 py-0.5 text-xs font-semibold text-emerald-700">
<span className="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-medium text-slate-700">
{t("plugins.marketplace.officialAutoUpdate")}
</span>
) : sourceKey ? (
<span className={`inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-xs ${sourceBadgeClassName(sourceKey)}`}>
<span className={`inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-xs ${sourceBadgeClassName}`}>
{sourceKey === "verified" ? <BadgeCheck className="h-3 w-3" /> : sourceKey === "github" ? <GitHubMark className="h-3 w-3" /> : null}
{t(`plugins.sources.${sourceKey}`)}
</span>
) : null}
{update ? (
<span className="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-700">
<span className="rounded-full bg-slate-950 px-2 py-0.5 text-xs font-medium text-slate-50">
{t("plugins.updates.available", { version: update.latestVersion })}
</span>
) : null}
@@ -116,7 +113,7 @@ export const PluginCatalogCard = ({
href={repositoryUrl}
label={t("plugins.marketplace.openRepository", { name })}
showTooltip={false}
className="h-7 w-7 justify-center rounded p-1 text-slate-400 hover:bg-slate-100 hover:text-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/70"
className="h-7 w-7 justify-center rounded p-1 text-slate-400 hover:bg-slate-100 hover:text-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400/40"
iconClassName="h-3.5 w-3.5"
/>
) : null}
@@ -37,7 +37,7 @@ const PluginSettingListDialog = ({ field }: { field: PluginSettingField }) => {
type="button"
variant="ghost"
size="sm"
className="-ml-2 mt-0.5 h-7 gap-0.5 px-2 text-xs text-emerald-700 hover:bg-emerald-50 hover:text-emerald-800"
className="-ml-2 mt-0.5 h-7 gap-0.5 px-2 text-xs text-slate-600 hover:bg-slate-100 hover:text-slate-950"
aria-haspopup="dialog"
>
{list.actionLabel ?? t("plugins.settings.viewList")}
@@ -304,7 +304,7 @@ export const PluginSettingsSection = ({ host, manifest }: { host: EdgeEverPlugin
return (
<section className="min-w-0" aria-labelledby={`${formId}-title`}>
<header className="border-b border-slate-200 pb-5">
<h3 id={`${formId}-title`} className="text-base font-semibold text-slate-900">{t("plugins.settings.title")}</h3>
<h3 id={`${formId}-title`} className="text-sm font-semibold text-slate-900">{t("plugins.settings.title")}</h3>
</header>
{loading ? <p className="py-8 text-sm text-slate-500" role="status">{t("common.loading")}</p> : loadError ? (
<div className="mt-5 grid justify-items-start gap-3 rounded-lg border border-rose-200 bg-rose-50 p-4">
@@ -173,15 +173,15 @@ const PluginDetailView = ({
<div className="flex items-start justify-between gap-4">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<h2 className="text-xl font-semibold text-slate-950">{name}</h2>
<h2 className="text-sm font-semibold text-slate-950">{name}</h2>
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-xs font-semibold uppercase tracking-wide text-slate-500">{manifest.type}</span>
{update ? (
<span className="rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-700">
<span className="rounded-full bg-slate-950 px-2 py-0.5 text-xs font-medium text-slate-50">
{t("plugins.updates.available", { version: update.latestVersion })}
</span>
) : null}
</div>
{description ? <p className="mt-2 max-w-3xl text-sm leading-6 text-slate-600">{description}</p> : null}
{description ? <p className="mt-1 max-w-3xl text-xs leading-5 text-slate-500">{description}</p> : null}
</div>
<Switch
aria-label={t("plugins.toggle", { name })}
@@ -224,7 +224,7 @@ const PluginDetailView = ({
</dl>
{extension.source.repositoryUrl ? (
<a className="inline-flex w-fit max-w-full items-center gap-2 text-sm text-slate-500 hover:text-emerald-700" href={extension.source.repositoryUrl} target="_blank" rel="noreferrer">
<a className="inline-flex w-fit max-w-full items-center gap-2 text-xs text-slate-500 hover:text-slate-950" href={extension.source.repositoryUrl} target="_blank" rel="noreferrer">
<GitHubMark className="h-4 w-4 shrink-0" />
<span className="truncate">{extension.source.repositoryUrl.replace("https://github.com/", "")}</span>
<ExternalLink className="h-3.5 w-3.5 shrink-0" />
@@ -400,7 +400,7 @@ export const PluginManagerCard = ({
<CardTitle className="flex min-w-0 items-center gap-2 text-sm">
<Puzzle className="h-4 w-4 shrink-0 text-slate-900" />
{selectedPluginId ? t("plugins.details.title") : t("plugins.title")}
<span className="inline-flex items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-2 py-0.5 text-xs font-semibold tracking-wide text-emerald-700">
<span className="inline-flex items-center rounded-full border border-emerald-200/80 bg-emerald-50 px-1.5 text-xs font-normal leading-5 text-emerald-700">
Beta
</span>
</CardTitle>
@@ -423,7 +423,7 @@ export const PluginManagerCard = ({
: t("plugins.updates.found", { count: lastManualCheckCount })}
</span>
{lastManualCheckCount === null && (updateQuery.data?.updates.length ?? 0) > 0 ? (
<span className="rounded-full bg-emerald-100 px-1.5 py-0.5 text-xs font-semibold text-emerald-700">
<span className="rounded-full bg-slate-950 px-1.5 py-0.5 text-xs font-semibold text-slate-50">
{updateQuery.data?.updates.length}
</span>
) : null}
@@ -495,6 +495,7 @@ export const PluginManagerCard = ({
value={manifestUrl}
onChange={(event) => setManifestUrl(event.target.value)}
placeholder={t("plugins.sourcePlaceholder")}
className="focus-visible:border-slate-400 focus-visible:ring-slate-400/25"
/>
<Button className="gap-1.5 sm:shrink-0" disabled={installing || !manifestUrl.trim()} onClick={() => void install()}>
<Download className="h-4 w-4" />