mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
feat(web): add search button to sidebar header + restore turbo globalEnv
Add a visible search trigger button next to the create-issue button in the sidebar header, improving search discoverability (previously only accessible via ⌘K). Search dialog open state is shared via a Zustand store so both the button and keyboard shortcut work. Also restores turbo.json globalEnv config (FRONTEND_PORT, etc.) that was accidentally dropped during the monorepo extraction, fixing worktree port conflicts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
SquarePen,
|
||||
CircleUser,
|
||||
FolderKanban,
|
||||
Search,
|
||||
} from "lucide-react";
|
||||
import { WorkspaceAvatar } from "@multica/views/workspace/workspace-avatar";
|
||||
import { useIssueDraftStore } from "@multica/core/issues/stores/draft-store";
|
||||
@@ -49,6 +50,7 @@ import { inboxKeys, deduplicateInboxItems } from "@multica/core/inbox/queries";
|
||||
import { api } from "@/platform/api";
|
||||
import { useModalStore } from "@multica/core/modals";
|
||||
import { useMyRuntimesNeedUpdate } from "@multica/core/runtimes/hooks";
|
||||
import { useSearchStore } from "@/features/search";
|
||||
|
||||
const primaryNav = [
|
||||
{ href: "/inbox", label: "Inbox", icon: Inbox },
|
||||
@@ -172,16 +174,27 @@ export function AppSidebar() {
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
className="relative flex h-7 w-7 items-center justify-center rounded-lg bg-background text-foreground shadow-sm hover:bg-accent"
|
||||
onClick={() => useModalStore.getState().open("create-issue")}
|
||||
>
|
||||
<SquarePen className="size-3.5" />
|
||||
<DraftDot />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">New issue</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="flex items-center gap-1">
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
className="flex h-7 w-7 items-center justify-center rounded-lg bg-secondary text-muted-foreground hover:bg-secondary/80 hover:text-secondary-foreground"
|
||||
onClick={() => useSearchStore.getState().setOpen(true)}
|
||||
>
|
||||
<Search className="size-3.5" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Search workspace (⌘K)</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
className="relative flex h-7 w-7 items-center justify-center rounded-lg bg-background text-foreground shadow-sm hover:bg-accent"
|
||||
onClick={() => useModalStore.getState().open("create-issue")}
|
||||
>
|
||||
<SquarePen className="size-3.5" />
|
||||
<DraftDot />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">New issue</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarHeader>
|
||||
|
||||
|
||||
@@ -15,10 +15,12 @@ import {
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from "@multica/ui/components/ui/dialog";
|
||||
import { useSearchStore } from "../stores/search-store";
|
||||
|
||||
export function SearchCommand() {
|
||||
const router = useRouter();
|
||||
const [open, setOpen] = useState(false);
|
||||
const open = useSearchStore((s) => s.open);
|
||||
const setOpen = useSearchStore((s) => s.setOpen);
|
||||
const [query, setQuery] = useState("");
|
||||
const [results, setResults] = useState<SearchIssueResult[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -30,7 +32,7 @@ export function SearchCommand() {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
||||
e.preventDefault();
|
||||
setOpen((prev) => !prev);
|
||||
useSearchStore.getState().toggle();
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
@@ -186,8 +188,9 @@ export function SearchCommand() {
|
||||
)}
|
||||
|
||||
{!isLoading && !query.trim() && (
|
||||
<div className="py-10 text-center text-sm text-muted-foreground">
|
||||
Type to search issues...
|
||||
<div className="flex flex-col items-center gap-2 py-10 text-sm text-muted-foreground">
|
||||
<span>Type to search issues...</span>
|
||||
<span className="text-xs">Press <kbd className="rounded bg-muted px-1.5 py-0.5 font-medium">⌘K</kbd> to open this anytime</span>
|
||||
</div>
|
||||
)}
|
||||
</CommandPrimitive.List>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export { SearchCommand } from "./components/search-command";
|
||||
export { useSearchStore } from "./stores/search-store";
|
||||
|
||||
15
apps/web/features/search/stores/search-store.ts
Normal file
15
apps/web/features/search/stores/search-store.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { create } from "zustand";
|
||||
|
||||
interface SearchStore {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
toggle: () => void;
|
||||
}
|
||||
|
||||
export const useSearchStore = create<SearchStore>((set) => ({
|
||||
open: false,
|
||||
setOpen: (open) => set({ open }),
|
||||
toggle: () => set((s) => ({ open: !s.open })),
|
||||
}));
|
||||
12
turbo.json
12
turbo.json
@@ -1,5 +1,17 @@
|
||||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"globalEnv": [
|
||||
"DATABASE_URL",
|
||||
"PORT",
|
||||
"FRONTEND_PORT",
|
||||
"FRONTEND_ORIGIN",
|
||||
"NEXT_PUBLIC_API_URL",
|
||||
"NEXT_PUBLIC_WS_URL",
|
||||
"MULTICA_SERVER_URL",
|
||||
"COMPOSE_PROJECT_NAME",
|
||||
"POSTGRES_DB",
|
||||
"POSTGRES_PORT"
|
||||
],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
|
||||
Reference in New Issue
Block a user