From cb2029ea972942120ea3f0d5ae9466a3c17baa4b Mon Sep 17 00:00:00 2001
From: Z8MB1E
Date: Tue, 18 Aug 2026 02:05:36 -0400
Subject: [PATCH] feat(command-palette): register page-specific commands across
UI
Wire CommandPalette/Provider into the frontend layout and add Cmd+K
hint in the SiteHeader. Register context-aware commands for banking,
helpdesk, mission RSVP, locker, shipments, and market pages.
Also removes the locker search's duplicate Cmd+K listener (now handled
globally), renames its button to 'Search Locker', and cleans up a
flappy page parenthetical.
---
src/app/(frontend)/flappy/page.tsx | 2 +-
src/app/(frontend)/layout.tsx | 45 +++++++++++-----
src/components/frontend/SiteHeader.tsx | 5 ++
.../frontend/banking/BankingOverview.tsx | 25 +++++++--
.../frontend/helpdesk/TicketsView.tsx | 17 ++++++-
.../intelligence/MissionAttendance.tsx | 34 +++++++++++++
.../frontend/locker/LockerSearch.tsx | 18 +------
src/components/frontend/locker/LockerView.tsx | 13 +++++
.../frontend/logistics/ShipmentsList.tsx | 51 +++++++++++++++++++
src/components/frontend/market/MarketView.tsx | 22 +++++++-
src/payload-types.ts | 2 +
11 files changed, 196 insertions(+), 38 deletions(-)
diff --git a/src/app/(frontend)/flappy/page.tsx b/src/app/(frontend)/flappy/page.tsx
index f181efc..bf484f2 100644
--- a/src/app/(frontend)/flappy/page.tsx
+++ b/src/app/(frontend)/flappy/page.tsx
@@ -52,7 +52,7 @@ export default async function FlappyPage() {
Flight Simulator
- An unofficial side activity. (Definitely not Flappy Bird.) Earn 1 XP per 15 obstacles
+ An unofficial side activity. Earn 1 XP per 15 obstacles
passed in a single run.
diff --git a/src/app/(frontend)/layout.tsx b/src/app/(frontend)/layout.tsx
index 3edb259..5bf69a7 100644
--- a/src/app/(frontend)/layout.tsx
+++ b/src/app/(frontend)/layout.tsx
@@ -14,6 +14,9 @@ import { ShipmentToasts } from "@/components/frontend/logistics/ShipmentToasts";
import { GameTickRealtime } from "@/components/frontend/realtime/GameTickRealtime";
import { LandingPage } from "@/components/frontend/LandingPage";
import { Toaster } from "@/components/ui/sonner";
+import { CommandPalette } from "@/components/command-palette/CommandPalette";
+import { CommandPaletteProvider } from "@/components/command-palette/CommandPaletteContext";
+import { KeyboardShortcutsProvider } from "@/components/command-palette/KeyboardShortcutsProvider";
// Skip static prerendering of this layout (and all pages under (frontend)/).
// The layout calls `getPayload()` at render time to resolve the current user,
@@ -93,22 +96,36 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
{user ? (
-
-
-
- {children}
-
+ >
+
+
+
+
+ {children}
+
+
+
+
) : (
diff --git a/src/components/frontend/SiteHeader.tsx b/src/components/frontend/SiteHeader.tsx
index 5a9555f..469552a 100644
--- a/src/components/frontend/SiteHeader.tsx
+++ b/src/components/frontend/SiteHeader.tsx
@@ -1,12 +1,17 @@
import { SidebarTrigger } from "@/components/ui/sidebar";
import { Separator } from "@/components/ui/separator";
import { NotificationsBell } from "@/components/frontend/notifications/NotificationsBell";
+import { Command } from "lucide-react";
export const SiteHeader = () => {
return (
+
+
+ K
+
diff --git a/src/components/frontend/banking/BankingOverview.tsx b/src/components/frontend/banking/BankingOverview.tsx
index 65cb9a2..fc415b3 100644
--- a/src/components/frontend/banking/BankingOverview.tsx
+++ b/src/components/frontend/banking/BankingOverview.tsx
@@ -1,14 +1,15 @@
"use client";
-import type { ReactNode } from "react";
+import { useState, type ReactNode } from "react";
import type { BankAccount, BankTransaction, Resource } from "@/payload-types";
-import { LandmarkIcon } from "lucide-react";
+import { LandmarkIcon, PlusIcon } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { AccountCard } from "@/components/frontend/banking/AccountCard";
import { CreateAccountDialog } from "@/components/frontend/banking/CreateAccountDialog";
import { WalletHero } from "@/components/frontend/banking/WalletHero";
import { ActivityFeed } from "@/components/frontend/banking/ActivityFeed";
import { currencyLabel, formatAmount } from "@/lib/banking/format";
+import { usePageCommands } from "@/components/command-palette/CommandPaletteContext";
interface BankingOverviewProps {
accounts: BankAccount[];
@@ -55,6 +56,19 @@ export function BankingOverview({
isManager,
factions,
}: BankingOverviewProps) {
+ const [createAccountOpen, setCreateAccountOpen] = useState(false);
+
+ usePageCommands([
+ {
+ id: "banking:create-account",
+ group: "Banking",
+ label: "Create Bank Account",
+ icon: PlusIcon,
+ keywords: ["new", "account", "bank"],
+ onSelect: () => setCreateAccountOpen(true),
+ },
+ ]);
+
const treasury = accounts.filter((a) => a.accountType === "treasury");
const factionAccounts = accounts.filter((a) => a.accountType === "faction");
const personal = accounts.filter((a) => a.accountType === "personal");
@@ -129,7 +143,12 @@ export function BankingOverview({
{visibleAccountsCount}
-
+
{visibleAccountsCount === 0 ? (
diff --git a/src/components/frontend/helpdesk/TicketsView.tsx b/src/components/frontend/helpdesk/TicketsView.tsx
index 19aae39..9572937 100644
--- a/src/components/frontend/helpdesk/TicketsView.tsx
+++ b/src/components/frontend/helpdesk/TicketsView.tsx
@@ -10,8 +10,9 @@ import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { CreateTicketDialog } from "@/components/frontend/helpdesk/CreateTicketDialog";
import { TicketCard } from "@/components/frontend/helpdesk/TicketCard";
import { CLOSING_STATUSES, STATUS_STYLES, type TicketStatus } from "@/lib/tickets/ticketMeta";
-import { InboxIcon, SearchIcon } from "lucide-react";
+import { InboxIcon, PlusIcon, SearchIcon } from "lucide-react";
import { cn } from "@/lib/utils";
+import { usePageCommands } from "@/components/command-palette/CommandPaletteContext";
type TicketFilter = "all" | "open" | "resolved" | "closed" | "unassigned";
@@ -56,6 +57,18 @@ function isUnassignedTicket(ticket: Ticket): boolean {
export function TicketsView({ tickets, currentUserId: _currentUserId, isStaff }: TicketsViewProps) {
const [activeFilter, setActiveFilter] = useState("all");
const [search, setSearch] = useState("");
+ const [createOpen, setCreateOpen] = useState(false);
+
+ usePageCommands([
+ {
+ id: "helpdesk:create-ticket",
+ group: "Helpdesk",
+ label: "Create Support Ticket",
+ icon: PlusIcon,
+ keywords: ["help", "support", "new", "ticket"],
+ onSelect: () => setCreateOpen(true),
+ },
+ ]);
const counts = useMemo>(
() => ({
@@ -132,7 +145,7 @@ export function TicketsView({ tickets, currentUserId: _currentUserId, isStaff }:
: "Keep an eye on your open requests."}