mirror of
https://github.com/fosrl/pangolin.git
synced 2026-07-15 02:01:55 +02:00
💄 update command bar UI
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
CommandBarNavSection,
|
||||||
|
SidebarNavSection
|
||||||
|
} from "@app/app/navigation";
|
||||||
import {
|
import {
|
||||||
CommandDialog,
|
CommandDialog,
|
||||||
CommandEmpty,
|
CommandEmpty,
|
||||||
@@ -9,13 +13,9 @@ import {
|
|||||||
CommandList,
|
CommandList,
|
||||||
CommandSeparator
|
CommandSeparator
|
||||||
} from "@app/components/ui/command";
|
} from "@app/components/ui/command";
|
||||||
import type {
|
import { cn } from "@app/lib/cn";
|
||||||
CommandBarNavSection,
|
|
||||||
SidebarNavSection
|
|
||||||
} from "@app/app/navigation";
|
|
||||||
import { Badge } from "@app/components/ui/badge";
|
|
||||||
import { ListUserOrgsResponse } from "@server/routers/org";
|
import { ListUserOrgsResponse } from "@server/routers/org";
|
||||||
import { Loader2 } from "lucide-react";
|
import { useTranslations } from "next-intl";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
@@ -25,13 +25,10 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState
|
useState
|
||||||
} from "react";
|
} from "react";
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
import { useCommandPaletteActions } from "./useCommandPaletteActions";
|
import { useCommandPaletteActions } from "./useCommandPaletteActions";
|
||||||
import { useCommandPaletteNavigation } from "./useCommandPaletteNavigation";
|
import { useCommandPaletteNavigation } from "./useCommandPaletteNavigation";
|
||||||
import { useCommandPaletteOrganizations } from "./useCommandPaletteOrganizations";
|
|
||||||
import { useCommandPaletteSearch } from "./useCommandPaletteSearch";
|
import { useCommandPaletteSearch } from "./useCommandPaletteSearch";
|
||||||
import { useUserContext } from "@app/hooks/useUserContext";
|
import { search } from "jmespath";
|
||||||
import { cn } from "@app/lib/cn";
|
|
||||||
|
|
||||||
type CommandPaletteProps = {
|
type CommandPaletteProps = {
|
||||||
orgId?: string;
|
orgId?: string;
|
||||||
@@ -52,14 +49,16 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
const { open, setOpen } = useCommandPalette();
|
const { open, setOpen } = useCommandPalette();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
const isActionMode = search.startsWith(">");
|
||||||
|
|
||||||
const navigationGroups = useCommandPaletteNavigation(navItems);
|
const navigationGroups = useCommandPaletteNavigation(navItems);
|
||||||
// const organizations = useCommandPaletteOrganizations(orgs);
|
// const organizations = useCommandPaletteOrganizations(orgs);
|
||||||
const actions = useCommandPaletteActions(orgId, orgs);
|
const actions = useCommandPaletteActions(orgId, orgs);
|
||||||
const { shouldSearch, sites, resources, users, machineClients, isLoading } =
|
const { shouldSearch, sites, resources, users, machineClients, isLoading } =
|
||||||
useCommandPaletteSearch({
|
useCommandPaletteSearch({
|
||||||
orgId,
|
orgId,
|
||||||
query: search,
|
query: search.substring(1),
|
||||||
enabled: open
|
enabled: open && isActionMode
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleOpenChange = useCallback(
|
const handleOpenChange = useCallback(
|
||||||
@@ -96,9 +95,24 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
className="max-w-2xl **:data-[slot=command-input-wrapper]:h-15"
|
className="max-w-2xl **:data-[slot=command-input-wrapper]:h-15"
|
||||||
commandProps={{
|
commandProps={{
|
||||||
loop: true,
|
loop: true,
|
||||||
filter(value, search) {
|
filter(value, query) {
|
||||||
if (value.toLowerCase().includes(search.toLowerCase()))
|
let search = query;
|
||||||
|
if (query.startsWith(">")) {
|
||||||
|
search = query.substring(1);
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
search,
|
||||||
|
value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
value
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(search.trim().toLowerCase())
|
||||||
|
) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -107,8 +121,9 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
placeholder={t("commandPaletteSearchPlaceholder")}
|
placeholder={t("commandPaletteSearchPlaceholder")}
|
||||||
value={search}
|
value={search}
|
||||||
onValueChange={setSearch}
|
onValueChange={setSearch}
|
||||||
|
// isLoading
|
||||||
/>
|
/>
|
||||||
<CommandList className="max-h-118 min-h-0 h-auto scroll-pb-2.5 scroll-pt-2">
|
<CommandList className="max-h-118 min-h-0 h-(--cmdk-list-height) scroll-pb-2.5 scroll-pt-2 transition-[height] duration-250 ease-in-out">
|
||||||
<CommandEmpty>{t("commandPaletteNoResults")}</CommandEmpty>
|
<CommandEmpty>{t("commandPaletteNoResults")}</CommandEmpty>
|
||||||
|
|
||||||
<CommandGroup
|
<CommandGroup
|
||||||
@@ -116,33 +131,42 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
className="[&_[cmdk-group-heading]]:text-sm"
|
className="[&_[cmdk-group-heading]]:text-sm"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{navigationGroups.map((group, groupIndex) => (
|
{!isActionMode &&
|
||||||
<React.Fragment key={group.heading}>
|
navigationGroups.map((group, groupIndex) => {
|
||||||
{groupIndex > 0 && <CommandSeparator />}
|
console.log({
|
||||||
<CommandGroup
|
groupIndex,
|
||||||
heading={group.heading}
|
groupHeading: group.heading
|
||||||
className={cn(
|
});
|
||||||
"[&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-sm pb-2.5",
|
return (
|
||||||
groupIndex > 0 &&
|
<React.Fragment key={group.heading}>
|
||||||
"[&_[cmdk-group-heading]]:pt-3"
|
{groupIndex > 0 && <CommandSeparator />}
|
||||||
)}
|
<CommandGroup
|
||||||
>
|
heading={group.heading}
|
||||||
{group.items.map((item, itemIndex) => (
|
className={cn(
|
||||||
<CommandItem
|
"[&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-sm pb-2.5",
|
||||||
key={item.id}
|
groupIndex > 0 &&
|
||||||
value={`${item.title} ${group.heading}`}
|
"[&_[cmdk-group-heading]]:pt-3"
|
||||||
onSelect={() =>
|
)}
|
||||||
runCommand(() => router.push(item.href))
|
|
||||||
}
|
|
||||||
className="h-9"
|
|
||||||
>
|
>
|
||||||
{item.icon}
|
{group.items.map((item) => (
|
||||||
<span>{item.title}</span>
|
<CommandItem
|
||||||
</CommandItem>
|
key={item.id}
|
||||||
))}
|
value={`${item.title} ${group.heading}`}
|
||||||
</CommandGroup>
|
onSelect={() =>
|
||||||
</React.Fragment>
|
runCommand(() =>
|
||||||
))}
|
router.push(item.href)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="h-9"
|
||||||
|
>
|
||||||
|
{item.icon}
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
{/* {organizations.length > 1 && (
|
{/* {organizations.length > 1 && (
|
||||||
<>
|
<>
|
||||||
@@ -282,7 +306,7 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
</>
|
</>
|
||||||
)} */}
|
)} */}
|
||||||
|
|
||||||
{/* {actions.length > 0 && (
|
{isActionMode && actions.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<CommandSeparator />
|
<CommandSeparator />
|
||||||
<CommandGroup
|
<CommandGroup
|
||||||
@@ -309,7 +333,7 @@ export function CommandPalette({ orgId, orgs, navItems }: CommandPaletteProps) {
|
|||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
</>
|
</>
|
||||||
)} */}
|
)}
|
||||||
</CommandList>
|
</CommandList>
|
||||||
</CommandDialog>
|
</CommandDialog>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Command as CommandPrimitive } from "cmdk";
|
import { Command as CommandPrimitive } from "cmdk";
|
||||||
import { SearchIcon } from "lucide-react";
|
import { LoaderIcon, SearchIcon } from "lucide-react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -68,14 +68,21 @@ function CommandDialog({
|
|||||||
|
|
||||||
function CommandInput({
|
function CommandInput({
|
||||||
className,
|
className,
|
||||||
|
isLoading,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
}: React.ComponentProps<typeof CommandPrimitive.Input> & {
|
||||||
|
isLoading?: boolean;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="command-input-wrapper"
|
data-slot="command-input-wrapper"
|
||||||
className="flex h-9 items-center gap-2 border-b px-3"
|
className="flex h-9 items-center gap-2 border-b px-3"
|
||||||
>
|
>
|
||||||
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
{isLoading ? (
|
||||||
|
<LoaderIcon className="animate-spin size-4 shrink-0 opacity-50" />
|
||||||
|
) : (
|
||||||
|
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
||||||
|
)}
|
||||||
<CommandPrimitive.Input
|
<CommandPrimitive.Input
|
||||||
data-slot="command-input"
|
data-slot="command-input"
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
Reference in New Issue
Block a user