Feature: Plugin system, site search, notifications, webhooks, caching & loading states
Local Build and Deploy / deploy (push) Successful in 1m2s
Local Build and Deploy / deploy (push) Successful in 1m2s
- Plugin/module system with registry, hooks for admin nav/permissions/i18n - Example Games plugin demonstrating the plugin system - Site-wide search with Cmd+K command palette (cmdk-based) - Real-time notification system (SSE + Redis pub/sub) - Extensible webhook system with admin management UI - Caching strategy: tiered data cache (unstable_cache + Redis) - Theme import/export as JSON - Loading states (spinner/skeleton) for all public pages - Mobile responsive fixes (admin dashboard, guilds page) - Webhooks admin page under Settings hub
This commit is contained in:
1 parent
09f1bc2bd6
commit
98d2b92218
85 files changed
+1889
-7
No files matched your search
+45
-1
@@ -8,6 +8,7 @@ import {
|
||||
LayoutDashboard,
|
||||
Monitor,
|
||||
Newspaper,
|
||||
Puzzle,
|
||||
Radio,
|
||||
Settings,
|
||||
Shield,
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
Users,
|
||||
Wrench,
|
||||
} from "lucide-react";
|
||||
import { pluginRegistry } from "@/lib/plugins";
|
||||
|
||||
export interface AdminHubTab {
|
||||
href: string;
|
||||
@@ -267,6 +269,7 @@ export const ADMIN_HUBS: AdminHubDefinition[] = [
|
||||
"/admin/emulator",
|
||||
"/admin/email-templates",
|
||||
"/admin/housekeeping",
|
||||
"/admin/webhooks",
|
||||
],
|
||||
tabs: [
|
||||
{ href: "/admin/settings", labelKey: "cms" },
|
||||
@@ -276,6 +279,7 @@ export const ADMIN_HUBS: AdminHubDefinition[] = [
|
||||
{ href: "/admin/emulator", labelKey: "emulator" },
|
||||
{ href: "/admin/email-templates", labelKey: "email" },
|
||||
{ href: "/admin/housekeeping", labelKey: "housekeeping" },
|
||||
{ href: "/admin/webhooks", labelKey: "webhooks" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -331,14 +335,54 @@ export const ADMIN_HUBS: AdminHubDefinition[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export function allHubs(): AdminHubDefinition[] {
|
||||
const pluginHubs: AdminHubDefinition[] = pluginRegistry.getHubs().map((h) => ({
|
||||
id: h.id,
|
||||
titleKey: h.titleKey,
|
||||
subtitleKey: h.subtitleKey,
|
||||
icon: h.icon,
|
||||
prefixes: h.prefixes,
|
||||
tabs: h.tabs.map((t) => ({
|
||||
href: t.href,
|
||||
labelKey: t.labelKey,
|
||||
match: t.match,
|
||||
group: t.group,
|
||||
})),
|
||||
}));
|
||||
return [...ADMIN_HUBS, ...pluginHubs];
|
||||
}
|
||||
|
||||
export function findAdminHub(pathname: string): AdminHubDefinition | null {
|
||||
const hubs = allHubs();
|
||||
return (
|
||||
ADMIN_HUBS.find((hub) =>
|
||||
hubs.find((hub) =>
|
||||
hub.prefixes.some((p) => pathname === p || pathname.startsWith(`${p}/`)),
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
export function allNavGroups(): AdminNavGroup[] {
|
||||
const pluginGroups: AdminNavGroup[] = pluginRegistry.getNavGroups().map((g) => ({
|
||||
labelKey: g.labelKey,
|
||||
icon: g.icon,
|
||||
items: g.items.map((item) => ({
|
||||
href: item.href,
|
||||
labelKey: item.labelKey,
|
||||
icon: item.icon,
|
||||
matchPrefixes: item.matchPrefixes,
|
||||
})),
|
||||
}));
|
||||
if (pluginGroups.length === 0) return ADMIN_NAV_GROUPS;
|
||||
return [
|
||||
...ADMIN_NAV_GROUPS,
|
||||
{
|
||||
labelKey: "plugins",
|
||||
icon: Puzzle,
|
||||
items: pluginGroups.flatMap((g) => g.items),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function hubPrefixes(id: string): string[] {
|
||||
return ADMIN_HUBS.find((h) => h.id === id)?.prefixes ?? [];
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user