Skip to content

Commit f961f6e

Browse files
Update admin navigation icon vocabulary (#2151)
* Update admin icon vocabulary * Refine admin icon overrides * Optimize admin icon lookup
1 parent 751c9d7 commit f961f6e

16 files changed

Lines changed: 394 additions & 214 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@emdash-cms/admin": patch
3+
---
4+
5+
Updates admin icons so pages, posts, media, comments, menus, redirects, widgets, sections, taxonomies, bylines, imports, and plugins are easier to distinguish across navigation and related views.

packages/admin/src/components/AdminCommandPalette.tsx

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,21 @@ import type { MessageDescriptor } from "@lingui/core";
1010
import { msg } from "@lingui/core/macro";
1111
import { useLingui as useLinguiContext } from "@lingui/react";
1212
import { useLingui } from "@lingui/react/macro";
13-
import {
14-
SquaresFour,
15-
FileText,
16-
Image,
17-
Gear,
18-
PuzzlePiece,
19-
Upload,
20-
Database,
21-
List,
22-
GridFour,
23-
Users,
24-
Stack,
25-
MagnifyingGlass,
26-
} from "@phosphor-icons/react";
13+
import { Gear, Users, MagnifyingGlass } from "@phosphor-icons/react";
2714
import { useQuery } from "@tanstack/react-query";
2815
import { useNavigate } from "@tanstack/react-router";
2916
import * as React from "react";
3017
import { useHotkeys } from "react-hotkeys-hook";
3118

3219
import { apiFetch, type AdminManifest } from "../lib/api/client.js";
3320
import { useCurrentUser } from "../lib/api/current-user";
34-
import { resolvePluginPageLabel } from "./Sidebar";
21+
import {
22+
ADMIN_NAV_ICONS,
23+
getCollectionNavIcon,
24+
getTaxonomyNavIcon,
25+
resolveNavIcon,
26+
} from "./admin-navigation-icons.js";
27+
import { resolvePluginPageLabel } from "./Sidebar.js";
3528

3629
/** Subset of manifest fields used by the palette (matches `Shell` props shape). */
3730
type CommandPaletteManifest = {
@@ -126,7 +119,7 @@ async function searchContent(query: string): Promise<SearchResponse> {
126119
return body.data;
127120
}
128121

129-
function buildNavItems(
122+
export function buildNavItems(
130123
manifest: CommandPaletteManifest,
131124
userRole: number,
132125
translateLabel: (id: string) => string,
@@ -136,7 +129,7 @@ function buildNavItems(
136129
id: "dashboard",
137130
title: msg`Dashboard`,
138131
to: "/",
139-
icon: SquaresFour,
132+
icon: ADMIN_NAV_ICONS.dashboard,
140133
keywords: ["home", "overview"],
141134
},
142135
];
@@ -148,7 +141,7 @@ function buildNavItems(
148141
title: config.label,
149142
to: "/content/$collection",
150143
params: { collection: name },
151-
icon: FileText,
144+
icon: getCollectionNavIcon(name),
152145
keywords: ["content", name],
153146
});
154147
}
@@ -159,38 +152,38 @@ function buildNavItems(
159152
id: "media",
160153
title: msg`Media Library`,
161154
to: "/media",
162-
icon: Image,
155+
icon: ADMIN_NAV_ICONS.media,
163156
keywords: ["images", "files", "uploads"],
164157
},
165158
{
166159
id: "menus",
167160
title: msg`Menus`,
168161
to: "/menus",
169-
icon: List,
162+
icon: ADMIN_NAV_ICONS.menus,
170163
minRole: ROLE_EDITOR,
171164
keywords: ["navigation"],
172165
},
173166
{
174167
id: "widgets",
175168
title: msg`Widgets`,
176169
to: "/widgets",
177-
icon: GridFour,
170+
icon: ADMIN_NAV_ICONS.widgets,
178171
minRole: ROLE_EDITOR,
179172
keywords: ["sidebar", "footer"],
180173
},
181174
{
182175
id: "sections",
183176
title: msg`Sections`,
184177
to: "/sections",
185-
icon: Stack,
178+
icon: ADMIN_NAV_ICONS.sections,
186179
minRole: ROLE_EDITOR,
187180
keywords: ["page builder", "blocks"],
188181
},
189182
{
190183
id: "content-types",
191184
title: msg`Content Types`,
192185
to: "/content-types",
193-
icon: Database,
186+
icon: ADMIN_NAV_ICONS.contentTypes,
194187
minRole: ROLE_ADMIN,
195188
keywords: ["schema", "collections"],
196189
},
@@ -199,7 +192,7 @@ function buildNavItems(
199192
title: msg`Categories`,
200193
to: "/taxonomies/$taxonomy",
201194
params: { taxonomy: "category" },
202-
icon: FileText,
195+
icon: getTaxonomyNavIcon("category"),
203196
minRole: ROLE_EDITOR,
204197
keywords: ["taxonomy"],
205198
},
@@ -208,7 +201,7 @@ function buildNavItems(
208201
title: msg`Tags`,
209202
to: "/taxonomies/$taxonomy",
210203
params: { taxonomy: "tag" },
211-
icon: FileText,
204+
icon: getTaxonomyNavIcon("tag"),
212205
minRole: ROLE_EDITOR,
213206
keywords: ["taxonomy"],
214207
},
@@ -224,15 +217,15 @@ function buildNavItems(
224217
id: "plugins",
225218
title: msg`Plugins`,
226219
to: "/plugins-manager",
227-
icon: PuzzlePiece,
220+
icon: ADMIN_NAV_ICONS.plugins,
228221
minRole: ROLE_ADMIN,
229222
keywords: ["extensions", "add-ons"],
230223
},
231224
{
232225
id: "import",
233226
title: msg`Import`,
234227
to: "/import/wordpress",
235-
icon: Upload,
228+
icon: ADMIN_NAV_ICONS.import,
236229
minRole: ROLE_ADMIN,
237230
keywords: ["wordpress", "migrate"],
238231
},
@@ -267,7 +260,7 @@ function buildNavItems(
267260
id: `plugin-${pluginId}-${page.path}`,
268261
title: label,
269262
to: `/plugins/${pluginId}${page.path}`,
270-
icon: PuzzlePiece,
263+
icon: resolveNavIcon(page.icon),
271264
keywords: ["plugin", pluginId],
272265
});
273266
}
@@ -350,7 +343,13 @@ export function AdminCommandPalette({ manifest }: AdminCommandPaletteProps) {
350343
title: typeof item.title === "string" ? item.title : t(item.title),
351344
to: item.to,
352345
params: item.params,
353-
icon: <item.icon className="h-4 w-4" />,
346+
icon: (
347+
<React.Suspense
348+
fallback={<ADMIN_NAV_ICONS.plugins className="h-4 w-4" aria-hidden="true" />}
349+
>
350+
<item.icon className="h-4 w-4" />
351+
</React.Suspense>
352+
),
354353
})),
355354
});
356355
}
@@ -366,7 +365,9 @@ export function AdminCommandPalette({ manifest }: AdminCommandPaletteProps) {
366365
title: result.title || result.slug,
367366
to: "/content/$collection/$id",
368367
params: { collection: result.collection, id: result.id },
369-
icon: <FileText className="h-4 w-4" />,
368+
icon: React.createElement(getCollectionNavIcon(result.collection), {
369+
className: "h-4 w-4",
370+
}),
370371
description: collectionLabel,
371372
collection: result.collection,
372373
};

packages/admin/src/components/Dashboard.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
CheckCircle,
99
PencilSimple,
1010
CalendarBlank,
11-
Image,
1211
Users,
1312
} from "@phosphor-icons/react";
1413
import { useQuery } from "@tanstack/react-query";
@@ -19,6 +18,7 @@ import type { CollectionStats, DashboardStats, RecentItem } from "../lib/api/das
1918
import { fetchDashboardStats } from "../lib/api/dashboard";
2019
import { usePluginWidget } from "../lib/plugin-context";
2120
import { formatRelativeTime } from "../lib/utils";
21+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
2222
import { ArrowNext } from "./ArrowIcons";
2323
import { RouterLinkButton } from "./RouterLinkButton";
2424
import { SandboxedPluginWidget } from "./SandboxedPluginWidget";
@@ -156,7 +156,7 @@ function SummaryMetrics({ stats, loading }: { stats?: DashboardStats; loading: b
156156
]
157157
: []),
158158
{
159-
icon: Image,
159+
icon: ADMIN_NAV_ICONS.media,
160160
label: plural(stats.mediaCount, { one: "Media file", other: "Media files" }),
161161
value: stats.mediaCount,
162162
},

packages/admin/src/components/MarketplaceBrowse.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { msg, plural } from "@lingui/core/macro";
1111
import { useLingui } from "@lingui/react/macro";
1212
import {
1313
MagnifyingGlass,
14-
PuzzlePiece,
1514
DownloadSimple,
1615
ShieldCheck,
1716
ShieldWarning,
@@ -29,6 +28,7 @@ import {
2928
type MarketplaceSearchOpts,
3029
} from "../lib/api/marketplace.js";
3130
import { safeIconUrl } from "../lib/url.js";
31+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
3232

3333
type SortOption = "installs" | "updated" | "created" | "name";
3434

@@ -169,7 +169,7 @@ export function MarketplaceBrowse({ installedPluginIds = new Set() }: Marketplac
169169
<>
170170
{plugins.length === 0 ? (
171171
<div className="rounded-lg border bg-kumo-base p-8 text-center">
172-
<PuzzlePiece className="mx-auto h-12 w-12 text-kumo-subtle" />
172+
<ADMIN_NAV_ICONS.plugins className="mx-auto h-12 w-12 text-kumo-subtle" />
173173
<h3 className="mt-4 text-lg font-medium">{t`No plugins found`}</h3>
174174
<p className="mt-2 text-sm text-kumo-subtle">
175175
{debouncedQuery

packages/admin/src/components/MenuList.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import { Button, Dialog, Input, Toast } from "@cloudflare/kumo";
88
import { plural } from "@lingui/core/macro";
99
import { Trans } from "@lingui/react/macro";
1010
import { useLingui } from "@lingui/react/macro";
11-
import { Plus, Pencil, Trash, List as ListIcon } from "@phosphor-icons/react";
11+
import { Plus, Pencil, Trash } from "@phosphor-icons/react";
1212
import { X } from "@phosphor-icons/react";
1313
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
1414
import { Link, useNavigate } from "@tanstack/react-router";
1515
import * as React from "react";
1616

1717
import { fetchMenus, createMenu, deleteMenu } from "../lib/api";
1818
import { fetchManifest } from "../lib/api/client.js";
19+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
1920
import { ConfirmDialog } from "./ConfirmDialog.js";
2021
import { DialogError, getMutationError } from "./DialogError.js";
2122
import { LocaleSwitcher, useI18nConfig } from "./LocaleSwitcher.js";
@@ -182,7 +183,7 @@ export function MenuList() {
182183

183184
{!menus || menus.length === 0 ? (
184185
<div className="border rounded-lg p-12 text-center">
185-
<ListIcon className="mx-auto h-12 w-12 text-kumo-subtle mb-4" />
186+
<ADMIN_NAV_ICONS.menus className="mx-auto h-12 w-12 text-kumo-subtle mb-4" />
186187
<h3 className="text-lg font-semibold mb-2">{t`No menus yet`}</h3>
187188
<p className="text-kumo-subtle mb-4">{t`Create your first navigation menu to get started`}</p>
188189
<Button icon={<Plus />} onClick={() => setIsCreateOpen(true)}>

packages/admin/src/components/PluginManager.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { Badge, Button, Checkbox, Switch, Toast } from "@cloudflare/kumo";
1010
import { plural } from "@lingui/core/macro";
1111
import { useLingui } from "@lingui/react/macro";
1212
import {
13-
PuzzlePiece,
1413
Gear,
1514
FileText,
1615
SquaresFour,
@@ -47,6 +46,7 @@ import {
4746
} from "../lib/api/registry.js";
4847
import { safeIconUrl } from "../lib/url.js";
4948
import { cn } from "../lib/utils";
49+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
5050
import { CaretNext } from "./ArrowIcons.js";
5151
import { CapabilityConsentDialog } from "./CapabilityConsentDialog.js";
5252
import { DialogError, getMutationError } from "./DialogError.js";
@@ -191,7 +191,7 @@ export function PluginManager({ manifest }: PluginManagerProps) {
191191

192192
{plugins?.length === 0 && (
193193
<div className="rounded-lg border bg-kumo-base p-8 text-center">
194-
<PuzzlePiece className="mx-auto h-12 w-12 text-kumo-subtle" />
194+
<ADMIN_NAV_ICONS.plugins className="mx-auto h-12 w-12 text-kumo-subtle" />
195195
<h3 className="mt-4 text-lg font-medium">{t`No plugins configured`}</h3>
196196
<p className="mt-2 text-sm text-kumo-subtle">
197197
{hasMarketplace ? (
@@ -340,7 +340,7 @@ function PluginCard({
340340
plugin.enabled ? "bg-kumo-brand/10" : "bg-kumo-tint",
341341
)}
342342
>
343-
<PuzzlePiece
343+
<ADMIN_NAV_ICONS.plugins
344344
className={cn("h-5 w-5", plugin.enabled ? "text-kumo-brand" : "text-kumo-subtle")}
345345
/>
346346
</div>

packages/admin/src/components/Redirects.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import type {
2727
UpdateRedirectInput,
2828
} from "../lib/api/redirects.js";
2929
import { cn } from "../lib/utils.js";
30+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
3031
import { ArrowNext } from "./ArrowIcons.js";
3132
import { ConfirmDialog } from "./ConfirmDialog.js";
3233
import { DialogError, getMutationError } from "./DialogError.js";
@@ -456,7 +457,7 @@ export function Redirects() {
456457
<div className="py-12 text-center text-kumo-subtle">{t`Loading redirects...`}</div>
457458
) : redirects.length === 0 ? (
458459
<div className="py-12 text-center text-kumo-subtle">
459-
<ArrowsLeftRight size={48} className="mx-auto mb-4 opacity-30" />
460+
<ADMIN_NAV_ICONS.redirects size={48} className="mx-auto mb-4 opacity-30" />
460461
<p className="text-lg font-medium">{t`No redirects yet`}</p>
461462
<p className="text-sm mt-1">{t`Create redirect rules to manage URL changes.`}</p>
462463
</div>

packages/admin/src/components/RegistryBrowse.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import { Badge, Input } from "@cloudflare/kumo";
1515
import { useLingui } from "@lingui/react/macro";
16-
import { MagnifyingGlass, PuzzlePiece, ShieldCheck } from "@phosphor-icons/react";
16+
import { MagnifyingGlass, ShieldCheck } from "@phosphor-icons/react";
1717
import { useInfiniteQuery } from "@tanstack/react-query";
1818
import { Link } from "@tanstack/react-router";
1919
import * as React from "react";
@@ -23,6 +23,7 @@ import {
2323
type RegistryClientConfig,
2424
type RegistryPackageView,
2525
} from "../lib/api/registry.js";
26+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
2627
import { PublisherHandle, usePublisherHandle } from "./PublisherHandle.js";
2728

2829
export interface RegistryBrowseProps {
@@ -175,7 +176,7 @@ function RegistryPackageCard({ pkg, installed }: RegistryPackageCardProps) {
175176
>
176177
<div className="flex items-start gap-3">
177178
<div className="mt-1 rounded-md bg-kumo-subtle p-2 text-kumo-subtle">
178-
<PuzzlePiece className="h-5 w-5" />
179+
<ADMIN_NAV_ICONS.plugins className="h-5 w-5" />
179180
</div>
180181
<div className="min-w-0 flex-1">
181182
<div className="flex items-center gap-2">

packages/admin/src/components/SectionPickerModal.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
import { Button, Dialog, Input } from "@cloudflare/kumo";
88
import { useLingui } from "@lingui/react/macro";
9-
import { MagnifyingGlass, Stack, FolderOpen } from "@phosphor-icons/react";
9+
import { MagnifyingGlass, FolderOpen } from "@phosphor-icons/react";
1010
import { X } from "@phosphor-icons/react";
1111
import { useQuery } from "@tanstack/react-query";
1212
import * as React from "react";
1313

1414
import { fetchSections, type Section } from "../lib/api";
1515
import { useDebouncedValue } from "../lib/hooks";
1616
import { cn } from "../lib/utils";
17+
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
1718

1819
interface SectionPickerModalProps {
1920
open: boolean;
@@ -53,7 +54,7 @@ export function SectionPickerModal({ open, onOpenChange, onSelect }: SectionPick
5354
<Dialog className="p-6 max-w-3xl max-h-[80vh] flex flex-col" size="lg">
5455
<div className="flex items-start justify-between gap-4 mb-4">
5556
<Dialog.Title className="text-lg font-semibold leading-none tracking-tight flex items-center gap-2">
56-
<Stack className="h-5 w-5" />
57+
<ADMIN_NAV_ICONS.sections className="h-5 w-5" />
5758
{t`Insert Section`}
5859
</Dialog.Title>
5960
<Dialog.Close
@@ -155,7 +156,7 @@ function SectionCard({ section, onSelect }: { section: Section; onSelect: () =>
155156
className="w-full h-full object-cover"
156157
/>
157158
) : (
158-
<Stack className="h-8 w-8 text-kumo-subtle" />
159+
<ADMIN_NAV_ICONS.sections className="h-8 w-8 text-kumo-subtle" />
159160
)}
160161
</div>
161162

0 commit comments

Comments
 (0)