Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/admin-navigation-icons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@emdash-cms/admin": patch
---

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.
61 changes: 31 additions & 30 deletions packages/admin/src/components/AdminCommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,21 @@ import type { MessageDescriptor } from "@lingui/core";
import { msg } from "@lingui/core/macro";
import { useLingui as useLinguiContext } from "@lingui/react";
import { useLingui } from "@lingui/react/macro";
import {
SquaresFour,
FileText,
Image,
Gear,
PuzzlePiece,
Upload,
Database,
List,
GridFour,
Users,
Stack,
MagnifyingGlass,
} from "@phosphor-icons/react";
import { Gear, Users, MagnifyingGlass } from "@phosphor-icons/react";
import { useQuery } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import * as React from "react";
import { useHotkeys } from "react-hotkeys-hook";

import { apiFetch, type AdminManifest } from "../lib/api/client.js";
import { useCurrentUser } from "../lib/api/current-user";
import { resolvePluginPageLabel } from "./Sidebar";
import {
ADMIN_NAV_ICONS,
getCollectionNavIcon,
getTaxonomyNavIcon,
resolveNavIcon,
} from "./admin-navigation-icons.js";
import { resolvePluginPageLabel } from "./Sidebar.js";

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

function buildNavItems(
export function buildNavItems(
manifest: CommandPaletteManifest,
userRole: number,
translateLabel: (id: string) => string,
Expand All @@ -136,7 +129,7 @@ function buildNavItems(
id: "dashboard",
title: msg`Dashboard`,
to: "/",
icon: SquaresFour,
icon: ADMIN_NAV_ICONS.dashboard,
keywords: ["home", "overview"],
},
];
Expand All @@ -148,7 +141,7 @@ function buildNavItems(
title: config.label,
to: "/content/$collection",
params: { collection: name },
icon: FileText,
icon: getCollectionNavIcon(name),
keywords: ["content", name],
});
}
Expand All @@ -159,38 +152,38 @@ function buildNavItems(
id: "media",
title: msg`Media Library`,
to: "/media",
icon: Image,
icon: ADMIN_NAV_ICONS.media,
keywords: ["images", "files", "uploads"],
},
{
id: "menus",
title: msg`Menus`,
to: "/menus",
icon: List,
icon: ADMIN_NAV_ICONS.menus,
minRole: ROLE_EDITOR,
keywords: ["navigation"],
},
{
id: "widgets",
title: msg`Widgets`,
to: "/widgets",
icon: GridFour,
icon: ADMIN_NAV_ICONS.widgets,
minRole: ROLE_EDITOR,
keywords: ["sidebar", "footer"],
},
{
id: "sections",
title: msg`Sections`,
to: "/sections",
icon: Stack,
icon: ADMIN_NAV_ICONS.sections,
minRole: ROLE_EDITOR,
keywords: ["page builder", "blocks"],
},
{
id: "content-types",
title: msg`Content Types`,
to: "/content-types",
icon: Database,
icon: ADMIN_NAV_ICONS.contentTypes,
minRole: ROLE_ADMIN,
keywords: ["schema", "collections"],
},
Expand All @@ -199,7 +192,7 @@ function buildNavItems(
title: msg`Categories`,
to: "/taxonomies/$taxonomy",
params: { taxonomy: "category" },
icon: FileText,
icon: getTaxonomyNavIcon("category"),
minRole: ROLE_EDITOR,
keywords: ["taxonomy"],
},
Expand All @@ -208,7 +201,7 @@ function buildNavItems(
title: msg`Tags`,
to: "/taxonomies/$taxonomy",
params: { taxonomy: "tag" },
icon: FileText,
icon: getTaxonomyNavIcon("tag"),
minRole: ROLE_EDITOR,
keywords: ["taxonomy"],
},
Expand All @@ -224,15 +217,15 @@ function buildNavItems(
id: "plugins",
title: msg`Plugins`,
to: "/plugins-manager",
icon: PuzzlePiece,
icon: ADMIN_NAV_ICONS.plugins,
minRole: ROLE_ADMIN,
keywords: ["extensions", "add-ons"],
},
{
id: "import",
title: msg`Import`,
to: "/import/wordpress",
icon: Upload,
icon: ADMIN_NAV_ICONS.import,
minRole: ROLE_ADMIN,
keywords: ["wordpress", "migrate"],
},
Expand Down Expand Up @@ -267,7 +260,7 @@ function buildNavItems(
id: `plugin-${pluginId}-${page.path}`,
title: label,
to: `/plugins/${pluginId}${page.path}`,
icon: PuzzlePiece,
icon: resolveNavIcon(page.icon),
keywords: ["plugin", pluginId],
});
}
Expand Down Expand Up @@ -350,7 +343,13 @@ export function AdminCommandPalette({ manifest }: AdminCommandPaletteProps) {
title: typeof item.title === "string" ? item.title : t(item.title),
to: item.to,
params: item.params,
icon: <item.icon className="h-4 w-4" />,
icon: (
<React.Suspense
fallback={<ADMIN_NAV_ICONS.plugins className="h-4 w-4" aria-hidden="true" />}
>
<item.icon className="h-4 w-4" />
</React.Suspense>
),
})),
});
}
Expand All @@ -366,7 +365,9 @@ export function AdminCommandPalette({ manifest }: AdminCommandPaletteProps) {
title: result.title || result.slug,
to: "/content/$collection/$id",
params: { collection: result.collection, id: result.id },
icon: <FileText className="h-4 w-4" />,
icon: React.createElement(getCollectionNavIcon(result.collection), {
className: "h-4 w-4",
}),
description: collectionLabel,
collection: result.collection,
};
Expand Down
4 changes: 2 additions & 2 deletions packages/admin/src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
CheckCircle,
PencilSimple,
CalendarBlank,
Image,
Users,
} from "@phosphor-icons/react";
import { useQuery } from "@tanstack/react-query";
Expand All @@ -19,6 +18,7 @@ import type { CollectionStats, DashboardStats, RecentItem } from "../lib/api/das
import { fetchDashboardStats } from "../lib/api/dashboard";
import { usePluginWidget } from "../lib/plugin-context";
import { formatRelativeTime } from "../lib/utils";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
import { ArrowNext } from "./ArrowIcons";
import { RouterLinkButton } from "./RouterLinkButton";
import { SandboxedPluginWidget } from "./SandboxedPluginWidget";
Expand Down Expand Up @@ -156,7 +156,7 @@ function SummaryMetrics({ stats, loading }: { stats?: DashboardStats; loading: b
]
: []),
{
icon: Image,
icon: ADMIN_NAV_ICONS.media,
label: plural(stats.mediaCount, { one: "Media file", other: "Media files" }),
value: stats.mediaCount,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/admin/src/components/MarketplaceBrowse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { msg, plural } from "@lingui/core/macro";
import { useLingui } from "@lingui/react/macro";
import {
MagnifyingGlass,
PuzzlePiece,
DownloadSimple,
ShieldCheck,
ShieldWarning,
Expand All @@ -29,6 +28,7 @@ import {
type MarketplaceSearchOpts,
} from "../lib/api/marketplace.js";
import { safeIconUrl } from "../lib/url.js";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";

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

Expand Down Expand Up @@ -169,7 +169,7 @@ export function MarketplaceBrowse({ installedPluginIds = new Set() }: Marketplac
<>
{plugins.length === 0 ? (
<div className="rounded-lg border bg-kumo-base p-8 text-center">
<PuzzlePiece className="mx-auto h-12 w-12 text-kumo-subtle" />
<ADMIN_NAV_ICONS.plugins className="mx-auto h-12 w-12 text-kumo-subtle" />
<h3 className="mt-4 text-lg font-medium">{t`No plugins found`}</h3>
<p className="mt-2 text-sm text-kumo-subtle">
{debouncedQuery
Expand Down
5 changes: 3 additions & 2 deletions packages/admin/src/components/MenuList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { Button, Dialog, Input, Toast } from "@cloudflare/kumo";
import { plural } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { useLingui } from "@lingui/react/macro";
import { Plus, Pencil, Trash, List as ListIcon } from "@phosphor-icons/react";
import { Plus, Pencil, Trash } from "@phosphor-icons/react";
import { X } from "@phosphor-icons/react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Link, useNavigate } from "@tanstack/react-router";
import * as React from "react";

import { fetchMenus, createMenu, deleteMenu } from "../lib/api";
import { fetchManifest } from "../lib/api/client.js";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
import { ConfirmDialog } from "./ConfirmDialog.js";
import { DialogError, getMutationError } from "./DialogError.js";
import { LocaleSwitcher, useI18nConfig } from "./LocaleSwitcher.js";
Expand Down Expand Up @@ -182,7 +183,7 @@ export function MenuList() {

{!menus || menus.length === 0 ? (
<div className="border rounded-lg p-12 text-center">
<ListIcon className="mx-auto h-12 w-12 text-kumo-subtle mb-4" />
<ADMIN_NAV_ICONS.menus className="mx-auto h-12 w-12 text-kumo-subtle mb-4" />
<h3 className="text-lg font-semibold mb-2">{t`No menus yet`}</h3>
<p className="text-kumo-subtle mb-4">{t`Create your first navigation menu to get started`}</p>
<Button icon={<Plus />} onClick={() => setIsCreateOpen(true)}>
Expand Down
6 changes: 3 additions & 3 deletions packages/admin/src/components/PluginManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Badge, Button, Checkbox, Switch, Toast } from "@cloudflare/kumo";
import { plural } from "@lingui/core/macro";
import { useLingui } from "@lingui/react/macro";
import {
PuzzlePiece,
Gear,
FileText,
SquaresFour,
Expand Down Expand Up @@ -47,6 +46,7 @@ import {
} from "../lib/api/registry.js";
import { safeIconUrl } from "../lib/url.js";
import { cn } from "../lib/utils";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
import { CaretNext } from "./ArrowIcons.js";
import { CapabilityConsentDialog } from "./CapabilityConsentDialog.js";
import { DialogError, getMutationError } from "./DialogError.js";
Expand Down Expand Up @@ -191,7 +191,7 @@ export function PluginManager({ manifest }: PluginManagerProps) {

{plugins?.length === 0 && (
<div className="rounded-lg border bg-kumo-base p-8 text-center">
<PuzzlePiece className="mx-auto h-12 w-12 text-kumo-subtle" />
<ADMIN_NAV_ICONS.plugins className="mx-auto h-12 w-12 text-kumo-subtle" />
<h3 className="mt-4 text-lg font-medium">{t`No plugins configured`}</h3>
<p className="mt-2 text-sm text-kumo-subtle">
{hasMarketplace ? (
Expand Down Expand Up @@ -340,7 +340,7 @@ function PluginCard({
plugin.enabled ? "bg-kumo-brand/10" : "bg-kumo-tint",
)}
>
<PuzzlePiece
<ADMIN_NAV_ICONS.plugins
className={cn("h-5 w-5", plugin.enabled ? "text-kumo-brand" : "text-kumo-subtle")}
/>
</div>
Expand Down
3 changes: 2 additions & 1 deletion packages/admin/src/components/Redirects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type {
UpdateRedirectInput,
} from "../lib/api/redirects.js";
import { cn } from "../lib/utils.js";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
import { ArrowNext } from "./ArrowIcons.js";
import { ConfirmDialog } from "./ConfirmDialog.js";
import { DialogError, getMutationError } from "./DialogError.js";
Expand Down Expand Up @@ -456,7 +457,7 @@ export function Redirects() {
<div className="py-12 text-center text-kumo-subtle">{t`Loading redirects...`}</div>
) : redirects.length === 0 ? (
<div className="py-12 text-center text-kumo-subtle">
<ArrowsLeftRight size={48} className="mx-auto mb-4 opacity-30" />
<ADMIN_NAV_ICONS.redirects size={48} className="mx-auto mb-4 opacity-30" />
<p className="text-lg font-medium">{t`No redirects yet`}</p>
<p className="text-sm mt-1">{t`Create redirect rules to manage URL changes.`}</p>
</div>
Expand Down
5 changes: 3 additions & 2 deletions packages/admin/src/components/RegistryBrowse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import { Badge, Input } from "@cloudflare/kumo";
import { useLingui } from "@lingui/react/macro";
import { MagnifyingGlass, PuzzlePiece, ShieldCheck } from "@phosphor-icons/react";
import { MagnifyingGlass, ShieldCheck } from "@phosphor-icons/react";
import { useInfiniteQuery } from "@tanstack/react-query";
import { Link } from "@tanstack/react-router";
import * as React from "react";
Expand All @@ -23,6 +23,7 @@ import {
type RegistryClientConfig,
type RegistryPackageView,
} from "../lib/api/registry.js";
import { ADMIN_NAV_ICONS } from "./admin-navigation-icons.js";
import { PublisherHandle, usePublisherHandle } from "./PublisherHandle.js";

export interface RegistryBrowseProps {
Expand Down Expand Up @@ -175,7 +176,7 @@ function RegistryPackageCard({ pkg, installed }: RegistryPackageCardProps) {
>
<div className="flex items-start gap-3">
<div className="mt-1 rounded-md bg-kumo-subtle p-2 text-kumo-subtle">
<PuzzlePiece className="h-5 w-5" />
<ADMIN_NAV_ICONS.plugins className="h-5 w-5" />
</div>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
Expand Down
7 changes: 4 additions & 3 deletions packages/admin/src/components/SectionPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

import { Button, Dialog, Input } from "@cloudflare/kumo";
import { useLingui } from "@lingui/react/macro";
import { MagnifyingGlass, Stack, FolderOpen } from "@phosphor-icons/react";
import { MagnifyingGlass, FolderOpen } from "@phosphor-icons/react";
import { X } from "@phosphor-icons/react";
import { useQuery } from "@tanstack/react-query";
import * as React from "react";

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

interface SectionPickerModalProps {
open: boolean;
Expand Down Expand Up @@ -53,7 +54,7 @@ export function SectionPickerModal({ open, onOpenChange, onSelect }: SectionPick
<Dialog className="p-6 max-w-3xl max-h-[80vh] flex flex-col" size="lg">
<div className="flex items-start justify-between gap-4 mb-4">
<Dialog.Title className="text-lg font-semibold leading-none tracking-tight flex items-center gap-2">
<Stack className="h-5 w-5" />
<ADMIN_NAV_ICONS.sections className="h-5 w-5" />
{t`Insert Section`}
</Dialog.Title>
<Dialog.Close
Expand Down Expand Up @@ -155,7 +156,7 @@ function SectionCard({ section, onSelect }: { section: Section; onSelect: () =>
className="w-full h-full object-cover"
/>
) : (
<Stack className="h-8 w-8 text-kumo-subtle" />
<ADMIN_NAV_ICONS.sections className="h-8 w-8 text-kumo-subtle" />
)}
</div>

Expand Down
Loading
Loading