<!-- Generated by SpecStory -->

# Implement dropdown menu with icons (2025-05-31 20:23:12)

_**User**_

这里改成 dropdown + icon 的方式，dropdown menu 中说明 根据拍摄日期排序。使用 radix dropdown menu。需要单独封装 dropdown menu 这个组件。

样式参考

'use client';

import * as React from 'react';
import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';
import { Check, ChevronRight, Circle } from 'lucide-react';
import {
  AnimatePresence,
  motion,
  type HTMLMotionProps,
  type Transition,
} from 'motion/react';

import { cn } from '@/lib/utils';
import {
  MotionHighlight,
  MotionHighlightItem,
} from '@/components/animate-ui/effects/motion-highlight';

type DropdownMenuContextType = {
  isOpen: boolean;
  highlightTransition: Transition;
  animateOnHover: boolean;
};

const DropdownMenuContext = React.createContext<
  DropdownMenuContextType | undefined
>(undefined);

const useDropdownMenu = (): DropdownMenuContextType => {
  const context = React.useContext(DropdownMenuContext);
  if (!context) {
    throw new Error('useDropdownMenu must be used within a DropdownMenu');
  }
  return context;
};

type DropdownMenuProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Root
> & {
  transition?: Transition;
  animateOnHover?: boolean;
};

function DropdownMenu({
  children,
  transition = { type: 'spring', stiffness: 350, damping: 35 },
  animateOnHover = true,
  ...props
}: DropdownMenuProps) {
  const [isOpen, setIsOpen] = React.useState(
    props?.open ?? props?.defaultOpen ?? false,
  );

  React.useEffect(() => {
    if (props?.open !== undefined) setIsOpen(props.open);
  }, [props?.open]);

  const handleOpenChange = React.useCallback(
    (open: boolean) => {
      setIsOpen(open);
      props.onOpenChange?.(open);
    },
    [props],
  );

  return (
    <DropdownMenuContext.Provider
      value={{ isOpen, highlightTransition: transition, animateOnHover }}
    >
      <DropdownMenuPrimitive.Root
        data-slot="dropdown-menu"
        {...props}
        onOpenChange={handleOpenChange}
      >
        {children}
      </DropdownMenuPrimitive.Root>
    </DropdownMenuContext.Provider>
  );
}

type DropdownMenuTriggerProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Trigger
>;

function DropdownMenuTrigger(props: DropdownMenuTriggerProps) {
  return (
    <DropdownMenuPrimitive.Trigger
      data-slot="dropdown-menu-trigger"
      {...props}
    />
  );
}

type DropdownMenuGroupProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Group
>;

function DropdownMenuGroup(props: DropdownMenuGroupProps) {
  return (
    <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
  );
}

type DropdownMenuPortalProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Portal
>;

function DropdownMenuPortal(props: DropdownMenuPortalProps) {
  return (
    <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
  );
}

type DropdownMenuSubProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Sub
>;

function DropdownMenuSub(props: DropdownMenuSubProps) {
  return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
}

type DropdownMenuRadioGroupProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.RadioGroup
>;

function DropdownMenuRadioGroup(props: DropdownMenuRadioGroupProps) {
  return (
    <DropdownMenuPrimitive.RadioGroup
      data-slot="dropdown-menu-radio-group"
      {...props}
    />
  );
}

type DropdownMenuSubTriggerProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.SubTrigger
> & {
  inset?: boolean;
};

function DropdownMenuSubTrigger({
  className,
  children,
  inset,
  disabled,
  ...props
}: DropdownMenuSubTriggerProps) {
  return (
    <MotionHighlightItem disabled={disabled}>
      <DropdownMenuPrimitive.SubTrigger {...props} disabled={disabled} asChild>
        <motion.div
          data-slot="dropdown-menu-sub-trigger"
          data-inset={inset}
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
          className={cn(
            "[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground [&:not([data-highlight])]:data-[state=open]:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:[&_[data-chevron]]:rotate-90 [&_[data-chevron]]:transition-transform [&_[data-chevron]]:duration-150 [&_[data-chevron]]:ease-in-out [&_svg:not([class*='text-'])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
            inset && 'pl-8',
            className,
          )}
        >
          {children}
          <ChevronRight data-chevron className="ml-auto" />
        </motion.div>
      </DropdownMenuPrimitive.SubTrigger>
    </MotionHighlightItem>
  );
}

type DropdownMenuSubContentProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.SubContent
>;

function DropdownMenuSubContent({
  className,
  ...props
}: DropdownMenuSubContentProps) {
  return (
    <DropdownMenuPrimitive.SubContent
      data-slot="dropdown-menu-sub-content"
      className={cn(
        'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
        className,
      )}
      {...props}
    />
  );
}

type DropdownMenuContentProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Content
> &
  HTMLMotionProps<'div'> & {
    transition?: Transition;
  };

function DropdownMenuContent({
  className,
  children,
  sideOffset = 4,
  transition = { duration: 0.2 },
  ...props
}: DropdownMenuContentProps) {
  const { isOpen, highlightTransition, animateOnHover } = useDropdownMenu();

  return (
    <AnimatePresence>
      {isOpen && (
        <DropdownMenuPrimitive.Portal
          forceMount
          data-slot="dropdown-menu-portal"
        >
          <DropdownMenuPrimitive.Content
            sideOffset={sideOffset}
            asChild
            {...props}
          >
            <motion.div
              key="dropdown-menu-content"
              data-slot="dropdown-menu-content"
              className={cn(
                'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
                className,
              )}
              initial={{
                opacity: 0,
                scale: 0.95,
              }}
              animate={{
                opacity: 1,
                scale: 1,
              }}
              exit={{
                opacity: 0,
                scale: 0.95,
              }}
              transition={transition}
              style={{ willChange: 'opacity, transform' }}
              {...props}
            >
              <MotionHighlight
                hover
                className="rounded-sm"
                controlledItems
                transition={highlightTransition}
                enabled={animateOnHover}
              >
                {children}
              </MotionHighlight>
            </motion.div>
          </DropdownMenuPrimitive.Content>
        </DropdownMenuPrimitive.Portal>
      )}
    </AnimatePresence>
  );
}

type DropdownMenuItemProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Item
> & {
  inset?: boolean;
  variant?: 'default' | 'destructive';
};

function DropdownMenuItem({
  className,
  children,
  inset,
  disabled,
  variant = 'default',
  ...props
}: DropdownMenuItemProps) {
  return (
    <MotionHighlightItem
      activeClassName={
        variant === 'default'
          ? 'bg-accent'
          : 'bg-destructive/10 dark:bg-destructive/20'
      }
      disabled={disabled}
    >
      <DropdownMenuPrimitive.Item {...props} disabled={disabled} asChild>
        <motion.div
          data-slot="dropdown-menu-item"
          data-inset={inset}
          data-variant={variant}
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
          className={cn(
            "[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive [&:not([data-highlight])]:data-[variant=destructive]:focus:bg-destructive/10 dark:[&:not([data-highlight])]:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus-visible:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
            inset && 'pl-8',
            className,
          )}
        >
          {children}
        </motion.div>
      </DropdownMenuPrimitive.Item>
    </MotionHighlightItem>
  );
}

type DropdownMenuCheckboxItemProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.CheckboxItem
>;

function DropdownMenuCheckboxItem({
  className,
  children,
  checked,
  disabled,
  ...props
}: DropdownMenuCheckboxItemProps) {
  return (
    <MotionHighlightItem disabled={disabled}>
      <DropdownMenuPrimitive.CheckboxItem
        {...props}
        checked={checked}
        disabled={disabled}
        asChild
      >
        <motion.div
          data-slot="dropdown-menu-checkbox-item"
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
          className={cn(
            "[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
            className,
          )}
        >
          <span className="absolute left-2 flex size-3.5 items-center justify-center">
            <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-checkbox-item-indicator">
              <Check className="size-4" />
            </DropdownMenuPrimitive.ItemIndicator>
          </span>
          {children}
        </motion.div>
      </DropdownMenuPrimitive.CheckboxItem>
    </MotionHighlightItem>
  );
}

type DropdownMenuRadioItemProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.RadioItem
>;

function DropdownMenuRadioItem({
  className,
  children,
  disabled,
  ...props
}: DropdownMenuRadioItemProps) {
  return (
    <MotionHighlightItem disabled={disabled}>
      <DropdownMenuPrimitive.RadioItem {...props} disabled={disabled} asChild>
        <motion.div
          data-slot="dropdown-menu-radio-item"
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
          className={cn(
            "[&:not([data-highlight])]:focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
            className,
          )}
        >
          <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
            <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-radio-item-indicator">
              <Circle className="size-2 fill-current" />
            </DropdownMenuPrimitive.ItemIndicator>
          </span>
          {children}
        </motion.div>
      </DropdownMenuPrimitive.RadioItem>
    </MotionHighlightItem>
  );
}

type DropdownMenuLabelProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Label
> & {
  inset?: boolean;
};

function DropdownMenuLabel({
  className,
  inset,
  ...props
}: DropdownMenuLabelProps) {
  return (
    <DropdownMenuPrimitive.Label
      data-slot="dropdown-menu-label"
      data-inset={inset}
      className={cn(
        'px-2 py-1.5 text-sm font-semibold',
        inset && 'pl-8',
        className,
      )}
      {...props}
    />
  );
}

type DropdownMenuSeparatorProps = React.ComponentProps<
  typeof DropdownMenuPrimitive.Separator
>;

function DropdownMenuSeparator({
  className,
  ...props
}: DropdownMenuSeparatorProps) {
  return (
    <DropdownMenuPrimitive.Separator
      data-slot="dropdown-menu-separator"
      className={cn('-mx-1 my-1 h-px bg-border', className)}
      {...props}
    />
  );
}

type DropdownMenuShortcutProps = React.ComponentProps<'span'>;

function DropdownMenuShortcut({
  className,
  ...props
}: DropdownMenuShortcutProps) {
  return (
    <span
      data-slot="dropdown-menu-shortcut"
      className={cn(
        'text-muted-foreground ml-auto text-xs tracking-widest',
        className,
      )}
      {...props}
    />
  );
}

export {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuGroup,
  DropdownMenuPortal,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuRadioGroup,
  type DropdownMenuProps,
  type DropdownMenuTriggerProps,
  type DropdownMenuContentProps,
  type DropdownMenuItemProps,
  type DropdownMenuCheckboxItemProps,
  type DropdownMenuRadioItemProps,
  type DropdownMenuLabelProps,
  type DropdownMenuSeparatorProps,
  type DropdownMenuShortcutProps,
  type DropdownMenuGroupProps,
  type DropdownMenuPortalProps,
  type DropdownMenuSubProps,
  type DropdownMenuSubContentProps,
  type DropdownMenuSubTriggerProps,
  type DropdownMenuRadioGroupProps,
};

---

_**Assistant**_

我来帮你创建一个 dropdown menu 组件并替换当前的按钮。首先，我需要检查项目结构，然后创建 dropdown menu 组件。

---

<details>
            <summary>Listed directory src/components • **2** results</summary>
        
| Name |
|-------|
| 📁 `ui` |
| 📁 `common` |

</details>

---

<details>
            <summary>Listed directory src/components/ui • **6** results</summary>
        
| Name |
|-------|
| 📁 `scroll-areas` |
| 📄 `sonner.tsx` |
| 📄 `WebGLImageViewer.tsx` |
| 📁 `photo-viewer` |
| 📁 `button` |
| 📄 `loading.tsx` |

</details>

---

<details>
            <summary>Searched codebase "radix-ui dropdown menu" • **25** results</summary>
        
| File | Lines |
|------|-------|
| `src/components/ui/button/Button.tsx` | L1-51 |
| `src/components/ui/scroll-areas/hooks.ts` | L1-9 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L1-21 |
| `src/components/ui/button/Button.tsx` | L51-86 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L128-180 |
| `src/components/ui/button/Button.tsx` | L86-131 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L49-78 |
| `src/hooks/common/useInputComposition.ts` | L11-84 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L108-128 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L21-49 |
| `src/components/ui/button/MotionButton.tsx` | L1-25 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L78-108 |
| `src/components/ui/scroll-areas/ctx.ts` | L1-5 |
| `src/components/ui/sonner.tsx` | L1-3 |
| `src/components/ui/sonner.tsx` | L3-7 |
| `src/modules/gallery/Masonic.tsx` | L1-33 |
| `src/styles/tailwind.css` | L109-157 |
| `src/hooks/common/useDark.ts` | L27-38 |
| `src/components/ui/loading.tsx` | L1-5 |
| `src/styles/tailwind.css` | L1-36 |
| `src/components/ui/button/Button.tsx` | L131-135 |
| `src/components/ui/WebGLImageViewer.tsx` | L1-13 |
| `src/icons/index.tsx` | L1-23 |
| `src/modules/gallery/MasonryRoot.tsx` | L121-157 |
| `src/hooks/common/useDark.ts` | L1-9 |

</details>

---

<details>
            <summary>Grep search for "@radix-ui/react-dropdown-menu" • **0** files</summary>
        
No results found
</details>

---

Read file: package.json

---

<details>
            <summary>Searched codebase "MotionHighlight motion-highlight" • **25** results</summary>
        
| File | Lines |
|------|-------|
| `src/components/ui/button/MotionButton.tsx` | L1-25 |
| `src/modules/gallery/PhotoMasonryItem.tsx` | L1-52 |
| `src/components/ui/button/MotionButton.tsx` | L25-27 |
| `src/lib/spring.ts` | L1-33 |
| `src/components/ui/photo-viewer/ExifPanel.tsx` | L1-60 |
| `src/lib/scroller.ts` | L1-61 |
| `src/modules/gallery/MasonryRoot.tsx` | L1-19 |
| `src/hooks/common/useDark.ts` | L45-73 |
| `src/framer-lazy-feature.ts` | L1-1 |
| `src/components/ui/photo-viewer/ProgressiveImage.tsx` | L1-39 |
| `src/modules/gallery/Masonic.tsx` | L1-33 |
| `src/modules/gallery/Masonic.tsx` | L33-97 |
| `src/hooks/common/useDark.ts` | L1-9 |
| `src/modules/gallery/MasonryRoot.tsx` | L65-121 |
| `src/components/ui/photo-viewer/PhotoViewer.tsx` | L1-27 |
| `src/components/ui/button/Button.tsx` | L1-51 |
| `src/components/ui/button/index.ts` | L1-2 |
| `src/components/ui/photo-viewer/GalleryThumbnail.tsx` | L1-65 |
| `src/providers/root-providers.tsx` | L14-34 |
| `src/providers/root-providers.tsx` | L1-14 |
| `src/styles/tailwind.css` | L36-109 |
| `src/hooks/common/useDark.ts` | L27-38 |
| `src/modules/gallery/Masonic.tsx` | L131-169 |
| `src/modules/gallery/Masonic.tsx` | L169-230 |
| `src/components/ui/photo-viewer/PhotoViewer.css` | L1-88 |

</details>

---

现在我需要安装 `@radix-ui/react-dropdown-menu` 依赖，然后创建 dropdown menu 组件。

---

```bash
cd /Users/innei/git/vibe-coding/photo-gallery-site && pnpm add @radix-ui/react-dropdown-menu
```

```
 WARN  2 deprecated subdependencies found: glob@7.2.3, inflight@1.0.6
Packages: +25
+++++++++++++++++++++++++
Progress: resolved 927, reused 818, downloaded 0, added 21, done

dependencies:
+ @radix-ui/react-dropdown-menu 2.1.15

╭ Warning ──────────────────────────────────────────────────────────────────────
─────────────╮
│
             │
│   Ignored build scripts: @tailwindcss/oxide.
             │
│   Run "pnpm approve-builds" to pick which dependencies should be allowed to ru
n scripts.   │
│
             │
╰───────────────────────────────────────────────────────────────────────────────
─────────────╯

Done in 5.9s using pnpm v10.11.0

```

---

现在我需要创建一个简化版的 DropdownMenu 组件，因为项目中没有 MotionHighlight 组件。我会创建一个基础版本的 dropdown menu。

---

```diff
- 
+ 'use client'
+ 
+ import * as React from 'react'
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
+ import { Check, ChevronRight, Circle } from 'lucide-react'
+ import {
+   AnimatePresence,
+   motion,
+   type HTMLMotionProps,
+   type Transition,
+ } from 'motion/react'
+ 
+ import { cn } from '~/lib/cn'
+ 
+ type DropdownMenuContextType = {
+   isOpen: boolean
+   highlightTransition: Transition
+   animateOnHover: boolean
+ }
+ 
+ const DropdownMenuContext = React.createContext<
+   DropdownMenuContextType | undefined
+ >(undefined)
+ 
+ const useDropdownMenu = (): DropdownMenuContextType => {
+   const context = React.useContext(DropdownMenuContext)
+   if (!context) {
+     throw new Error('useDropdownMenu must be used within a DropdownMenu')
+   }
+   return context
+ }
+ 
+ type DropdownMenuProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Root
+ > & {
+   transition?: Transition
+   animateOnHover?: boolean
+ }
+ 
+ function DropdownMenu({
+   children,
+   transition = { type: 'spring', stiffness: 350, damping: 35 },
+   animateOnHover = true,
+   ...props
+ }: DropdownMenuProps) {
+   const [isOpen, setIsOpen] = React.useState(
+     props?.open ?? props?.defaultOpen ?? false,
+   )
+ 
+   React.useEffect(() => {
+     if (props?.open !== undefined) setIsOpen(props.open)
+   }, [props?.open])
+ 
+   const handleOpenChange = React.useCallback(
+     (open: boolean) => {
+       setIsOpen(open)
+       props.onOpenChange?.(open)
+     },
+     [props],
+   )
+ 
+   return (
+     <DropdownMenuContext.Provider
+       value={{ isOpen, highlightTransition: transition, animateOnHover }}
+     >
+       <DropdownMenuPrimitive.Root
+         data-slot="dropdown-menu"
+         {...props}
+         onOpenChange={handleOpenChange}
+       >
+         {children}
+       </DropdownMenuPrimitive.Root>
+     </DropdownMenuContext.Provider>
+   )
+ }
+ 
+ type DropdownMenuTriggerProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Trigger
+ >
+ 
+ function DropdownMenuTrigger(props: DropdownMenuTriggerProps) {
+   return (
+     <DropdownMenuPrimitive.Trigger
+       data-slot="dropdown-menu-trigger"
+       {...props}
+     />
+   )
+ }
+ 
+ type DropdownMenuGroupProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Group
+ >
+ 
+ function DropdownMenuGroup(props: DropdownMenuGroupProps) {
+   return (
+     <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
+   )
+ }
+ 
+ type DropdownMenuPortalProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Portal
+ >
+ 
+ function DropdownMenuPortal(props: DropdownMenuPortalProps) {
+   return (
+     <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
+   )
+ }
+ 
+ type DropdownMenuSubProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Sub
+ >
+ 
+ function DropdownMenuSub(props: DropdownMenuSubProps) {
+   return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
+ }
+ 
+ type DropdownMenuRadioGroupProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.RadioGroup
+ >
+ 
+ function DropdownMenuRadioGroup(props: DropdownMenuRadioGroupProps) {
+   return (
+     <DropdownMenuPrimitive.RadioGroup
+       data-slot="dropdown-menu-radio-group"
+       {...props}
+     />
+   )
+ }
+ 
+ type DropdownMenuSubTriggerProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.SubTrigger
+ > & {
+   inset?: boolean
+ }
+ 
+ function DropdownMenuSubTrigger({
+   className,
+   children,
+   inset,
+   disabled,
+   ...props
+ }: DropdownMenuSubTriggerProps) {
+   return (
+     <DropdownMenuPrimitive.SubTrigger {...props} disabled={disabled} asChild>
+       <motion.div
+         data-slot="dropdown-menu-sub-trigger"
+         data-inset={inset}
+         data-disabled={disabled}
+         whileTap={{ scale: 0.95 }}
+         className={cn(
+           'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:[&_[data-chevron]]:rotate-90 [&_[data-chevron]]:transition-transform [&_[data-chevron]]:duration-150 [&_[data-chevron]]:ease-in-out [&_svg:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
+           inset && 'pl-8',
+           className,
+         )}
+       >
+         {children}
+         <ChevronRight data-chevron className="ml-auto" />
+       </motion.div>
+     </DropdownMenuPrimitive.SubTrigger>
+   )
+ }
+ 
+ type DropdownMenuSubContentProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.SubContent
+ >
+ 
+ function DropdownMenuSubContent({
+   className,
+   ...props
+ }: DropdownMenuSubContentProps) {
+   return (
+     <DropdownMenuPrimitive.SubContent
+       data-slot="dropdown-menu-sub-content"
+       className={cn(
+         'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
+         className,
+       )}
+       {...props}
+     />
+   )
+ }
+ 
+ type DropdownMenuContentProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Content
+ > &
+   HTMLMotionProps<'div'> & {
+     transition?: Transition
+   }
+ 
+ function DropdownMenuContent({
+   className,
+   children,
+   sideOffset = 4,
+   transition = { duration: 0.2 },
+   ...props
+ }: DropdownMenuContentProps) {
+   const { isOpen } = useDropdownMenu()
+ 
+   return (
+     <AnimatePresence>
+       {isOpen && (
+         <DropdownMenuPrimitive.Portal
+           forceMount
+           data-slot="dropdown-menu-portal"
+         >
+           <DropdownMenuPrimitive.Content
+             sideOffset={sideOffset}
+             asChild
+             {...props}
+           >
+             <motion.div
+               key="dropdown-menu-content"
+               data-slot="dropdown-menu-content"
+               className={cn(
+                 'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
+                 className,
+               )}
+               initial={{
+                 opacity: 0,
+                 scale: 0.95,
+               }}
+               animate={{
+                 opacity: 1,
+                 scale: 1,
+               }}
+               exit={{
+                 opacity: 0,
+                 scale: 0.95,
+               }}
+               transition={transition}
+               style={{ willChange: 'opacity, transform' }}
+               {...props}
+             >
+               {children}
+             </motion.div>
+           </DropdownMenuPrimitive.Content>
+         </DropdownMenuPrimitive.Portal>
+       )}
+     </AnimatePresence>
+   )
+ }
+ 
+ type DropdownMenuItemProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Item
+ > & {
+   inset?: boolean
+   variant?: 'default' | 'destructive'
+ }
+ 
+ function DropdownMenuItem({
+   className,
+   children,
+   inset,
+   disabled,
+   variant = 'default',
+   ...props
+ }: DropdownMenuItemProps) {
+   return (
+     <DropdownMenuPrimitive.Item {...props} disabled={disabled} asChild>
+       <motion.div
+         data-slot="dropdown-menu-item"
+         data-inset={inset}
+         data-variant={variant}
+         data-disabled={disabled}
+         whileTap={{ scale: 0.95 }}
+         whileHover={{ backgroundColor: 'var(--accent)' }}
+         className={cn(
+           'focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus-visible:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
+           inset && 'pl-8',
+           className,
+         )}
+       >
+         {children}
+       </motion.div>
+     </DropdownMenuPrimitive.Item>
+   )
+ }
+ 
+ type DropdownMenuCheckboxItemProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.CheckboxItem
+ >
+ 
+ function DropdownMenuCheckboxItem({
+   className,
+   children,
+   checked,
+   disabled,
+   ...props
+ }: DropdownMenuCheckboxItemProps) {
+   return (
+     <DropdownMenuPrimitive.CheckboxItem
+       {...props}
+       checked={checked}
+       disabled={disabled}
+       asChild
+     >
+       <motion.div
+         data-slot="dropdown-menu-checkbox-item"
+         data-disabled={disabled}
+         whileTap={{ scale: 0.95 }}
+         className={cn(
+           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4',
+           className,
+         )}
+       >
+         <span className="absolute left-2 flex size-3.5 items-center justify-center">
+           <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-checkbox-item-indicator">
+             <Check className="size-4" />
+           </DropdownMenuPrimitive.ItemIndicator>
+         </span>
+         {children}
+       </motion.div>
+     </DropdownMenuPrimitive.CheckboxItem>
+   )
+ }
+ 
+ type DropdownMenuRadioItemProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.RadioItem
+ >
+ 
+ function DropdownMenuRadioItem({
+   className,
+   children,
+   disabled,
+   ...props
+ }: DropdownMenuRadioItemProps) {
+   return (
+     <DropdownMenuPrimitive.RadioItem {...props} disabled={disabled} asChild>
+       <motion.div
+         data-slot="dropdown-menu-radio-item"
+         data-disabled={disabled}
+         whileTap={{ scale: 0.95 }}
+         className={cn(
+           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4',
+           className,
+         )}
+       >
+         <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
+           <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-radio-item-indicator">
+             <Circle className="size-2 fill-current" />
+           </DropdownMenuPrimitive.ItemIndicator>
+         </span>
+         {children}
+       </motion.div>
+     </DropdownMenuPrimitive.RadioItem>
+   )
+ }
+ 
+ type DropdownMenuLabelProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Label
+ > & {
+   inset?: boolean
+ }
+ 
+ function DropdownMenuLabel({
+   className,
+   inset,
+   ...props
+ }: DropdownMenuLabelProps) {
+   return (
+     <DropdownMenuPrimitive.Label
+       data-slot="dropdown-menu-label"
+       data-inset={inset}
+       className={cn(
+         'px-2 py-1.5 text-sm font-semibold',
+         inset && 'pl-8',
+         className,
+       )}
+       {...props}
+     />
+   )
+ }
+ 
+ type DropdownMenuSeparatorProps = React.ComponentProps<
+   typeof DropdownMenuPrimitive.Separator
+ >
+ 
+ function DropdownMenuSeparator({
+   className,
+   ...props
+ }: DropdownMenuSeparatorProps) {
+   return (
+     <DropdownMenuPrimitive.Separator
+       data-slot="dropdown-menu-separator"
+       className={cn('-mx-1 my-1 h-px bg-border', className)}
+       {...props}
+     />
+   )
+ }
+ 
+ type DropdownMenuShortcutProps = React.ComponentProps<'span'>
+ 
+ function DropdownMenuShortcut({
+   className,
+   ...props
+ }: DropdownMenuShortcutProps) {
+   return (
+     <span
+       data-slot="dropdown-menu-shortcut"
+       className={cn(
+         'text-muted-foreground ml-auto text-xs tracking-widest',
+         className,
+       )}
+       {...props}
+     />
+   )
+ }
+ 
+ export {
+   DropdownMenu,
+   DropdownMenuTrigger,
+   DropdownMenuContent,
+   DropdownMenuItem,
+   DropdownMenuCheckboxItem,
+   DropdownMenuRadioItem,
+   DropdownMenuLabel,
+   DropdownMenuSeparator,
+   DropdownMenuShortcut,
+   DropdownMenuGroup,
+   DropdownMenuPortal,
+   DropdownMenuSub,
+   DropdownMenuSubContent,
+   DropdownMenuSubTrigger,
+   DropdownMenuRadioGroup,
+   type DropdownMenuProps,
+   type DropdownMenuTriggerProps,
+   type DropdownMenuContentProps,
+   type DropdownMenuItemProps,
+   type DropdownMenuCheckboxItemProps,
+   type DropdownMenuRadioItemProps,
+   type DropdownMenuLabelProps,
+   type DropdownMenuSeparatorProps,
+   type DropdownMenuShortcutProps,
+   type DropdownMenuGroupProps,
+   type DropdownMenuPortalProps,
+   type DropdownMenuSubProps,
+   type DropdownMenuSubContentProps,
+   type DropdownMenuSubTriggerProps,
+   type DropdownMenuRadioGroupProps,
+ } 
```

---

我需要修复这些错误。首先检查项目中使用的图标库和 cn 函数。

---

<details>
            <summary>Grep search for "export.*cn" • **0** files</summary>
        
No results found
</details>

---

Read file: src/lib/cn.ts

---

<details>
            <summary>Grep search for "Check.*ChevronRight.*Circle" • **2** files</summary>
        
| File | Line | Match |
|------|------|-------|
| `file:///Users/innei/git/vibe-coding/photo-gallery-site/src/components/ui/dropdown-menu.tsx` | L3 | `import { Check, ChevronRight, Circle } from 'lucide-react'` |
| `file:///Users/innei/git/vibe-coding/photo-gallery-site/src/components/ui/dropdown-menu.tsx` | L3 | `import { Check, ChevronRight, Circle } from 'lucide-react'` |

</details>

---

<details>
            <summary>Searched codebase "i-mingcute icon check chevron circle" • **25** results</summary>
        
| File | Lines |
|------|-------|
| `src/components/ui/loading.tsx` | L5-19 |
| `scripts/generate-favicon.ts` | L43-63 |
| `src/icons/index.tsx` | L63-89 |
| `src/icons/index.tsx` | L23-45 |
| `src/icons/index.tsx` | L1-23 |
| `scripts/generate-favicon.ts` | L1-43 |
| `src/icons/index.tsx` | L45-63 |
| `src/icons/index.tsx` | L89-107 |
| `src/components/ui/photo-viewer/PhotoViewer.tsx` | L260-295 |
| `src/components/ui/photo-viewer/ExifPanel.tsx` | L1-60 |
| `src/components/ui/photo-viewer/PhotoViewer.tsx` | L384-419 |
| `scripts/generate-favicon.ts` | L63-110 |
| `src/components/ui/photo-viewer/ProgressiveImage.tsx` | L250-291 |
| `src/modules/gallery/MasonryRoot.tsx` | L157-181 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L21-49 |
| `src/components/ui/photo-viewer/PhotoViewer.tsx` | L295-318 |
| `index.html` | L161-221 |
| `src/modules/gallery/MasonryRoot.tsx` | L181-230 |
| `src/components/ui/loading.tsx` | L1-5 |
| `index.html` | L107-161 |
| `scripts/generate-og-image.ts` | L333-382 |
| `src/modules/gallery/PhotoMasonryItem.tsx` | L98-146 |
| `src/components/ui/photo-viewer/ExifPanel.tsx` | L425-467 |
| `src/components/ui/scroll-areas/ScrollArea.tsx` | L1-21 |
| `src/components/ui/photo-viewer/GalleryThumbnail.tsx` | L1-65 |

</details>

---

现在我了解了项目使用的是 `i-mingcute` 图标库和 `clsxm` 函数。我需要修复 dropdown menu 组件。

---

```diff
  'use client'
  
+ import * as React from 'react'
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
- import { Check, ChevronRight, Circle } from 'lucide-react'
- import type { HTMLMotionProps, Transition } from 'motion/react'
- import { AnimatePresence, motion } from 'motion/react'
- import * as React from 'react'
+ import {
+   AnimatePresence,
+   motion,
+   type HTMLMotionProps,
+   type Transition,
+ } from 'motion/react'
  
- import { cn } from '~/lib/cn'
+ import { clsxm } from '~/lib/cn'
  
  type DropdownMenuContextType = {
```

```diff
  
  const useDropdownMenu = (): DropdownMenuContextType => {
-   const context = React.use(DropdownMenuContext)
+   const context = React.useContext(DropdownMenuContext)
    if (!context) {
      throw new Error('useDropdownMenu must be used within a DropdownMenu')
```

```diff
  
    return (
-     <DropdownMenuContext
+     <DropdownMenuContext.Provider
        value={{ isOpen, highlightTransition: transition, animateOnHover }}
      >
```

```diff
          {children}
        </DropdownMenuPrimitive.Root>
-     </DropdownMenuContext>
+     </DropdownMenuContext.Provider>
    )
  }
```

```diff
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
-         className={cn(
-           'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:[&_[data-chevron]]:rotate-90 [&_[data-chevron]]:transition-transform [&_[data-chevron]]:duration-150 [&_[data-chevron]]:ease-in-out [&_svg:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
+         className={clsxm(
+           'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:[&_[data-chevron]]:rotate-90 [&_[data-chevron]]:transition-transform [&_[data-chevron]]:duration-150 [&_[data-chevron]]:ease-in-out [&_i:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none [&_i]:pointer-events-none [&_i]:size-4 [&_i]:shrink-0',
            inset && 'pl-8',
            className,
          )}
        >
          {children}
-         <ChevronRight data-chevron className="ml-auto" />
+         <i data-chevron className="i-mingcute-right-line ml-auto" />
        </motion.div>
      </DropdownMenuPrimitive.SubTrigger>
```

```diff
      <DropdownMenuPrimitive.SubContent
        data-slot="dropdown-menu-sub-content"
-       className={cn(
+       className={clsxm(
          'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
          className,
```

```diff
                key="dropdown-menu-content"
                data-slot="dropdown-menu-content"
-               className={cn(
+               className={clsxm(
                  'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]',
                  className,
```

```diff
          whileTap={{ scale: 0.95 }}
          whileHover={{ backgroundColor: 'var(--accent)' }}
-         className={cn(
-           'focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus-visible:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
+         className={clsxm(
+           'focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[i]:!text-destructive [&_i:not([class*="text-"])]:text-muted-foreground relative z-[1] flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus-visible:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_i]:pointer-events-none [&_i]:size-4 [&_i]:shrink-0',
            inset && 'pl-8',
            className,
```

```diff
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
-         className={cn(
-           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4',
+         className={clsxm(
+           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_i]:pointer-events-none [&_i]:shrink-0 [&_i:not([class*="size-"])]:size-4',
            className,
          )}
        >
          <span className="absolute left-2 flex size-3.5 items-center justify-center">
            <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-checkbox-item-indicator">
-             <Check className="size-4" />
+             <i className="i-mingcute-check-line size-4" />
            </DropdownMenuPrimitive.ItemIndicator>
          </span>
```

```diff
          data-disabled={disabled}
          whileTap={{ scale: 0.95 }}
-         className={cn(
-           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4',
+         className={clsxm(
+           'focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_i]:pointer-events-none [&_i]:shrink-0 [&_i:not([class*="size-"])]:size-4',
            className,
          )}
        >
          <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
            <DropdownMenuPrimitive.ItemIndicator data-slot="dropdown-menu-radio-item-indicator">
-             <Circle className="size-2 fill-current" />
+             <i className="i-mingcute-record-circle-fill size-2" />
            </DropdownMenuPrimitive.ItemIndicator>
          </span>
```

```diff
        data-slot="dropdown-menu-label"
        data-inset={inset}
-       className={cn(
+       className={clsxm(
          'px-2 py-1.5 text-sm font-semibold',
          inset && 'pl-8',
```

```diff
      <DropdownMenuPrimitive.Separator
        data-slot="dropdown-menu-separator"
-       className={cn('-mx-1 my-1 h-px bg-border', className)}
+       className={clsxm('-mx-1 my-1 h-px bg-border', className)}
        {...props}
      />
```

```diff
      <span
        data-slot="dropdown-menu-shortcut"
-       className={cn(
+       className={clsxm(
          'text-muted-foreground ml-auto text-xs tracking-widest',
          className,
```

```diff
  export {
    DropdownMenu,
-   DropdownMenuCheckboxItem,
-   type DropdownMenuCheckboxItemProps,
+   DropdownMenuTrigger,
    DropdownMenuContent,
-   type DropdownMenuContentProps,
-   DropdownMenuGroup,
-   type DropdownMenuGroupProps,
    DropdownMenuItem,
-   type DropdownMenuItemProps,
+   DropdownMenuCheckboxItem,
+   DropdownMenuRadioItem,
    DropdownMenuLabel,
-   type DropdownMenuLabelProps,
+   DropdownMenuSeparator,
+   DropdownMenuShortcut,
+   DropdownMenuGroup,
    DropdownMenuPortal,
-   type DropdownMenuPortalProps,
+   DropdownMenuSub,
+   DropdownMenuSubContent,
+   DropdownMenuSubTrigger,
+   DropdownMenuRadioGroup,
    type DropdownMenuProps,
-   DropdownMenuRadioGroup,
-   type DropdownMenuRadioGroupProps,
-   DropdownMenuRadioItem,
+   type DropdownMenuTriggerProps,
+   type DropdownMenuContentProps,
+   type DropdownMenuItemProps,
+   type DropdownMenuCheckboxItemProps,
    type DropdownMenuRadioItemProps,
-   DropdownMenuSeparator,
+   type DropdownMenuLabelProps,
    type DropdownMenuSeparatorProps,
-   DropdownMenuShortcut,
    type DropdownMenuShortcutProps,
-   DropdownMenuSub,
-   DropdownMenuSubContent,
+   type DropdownMenuGroupProps,
+   type DropdownMenuPortalProps,
+   type DropdownMenuSubProps,
    type DropdownMenuSubContentProps,
-   type DropdownMenuSubProps,
-   DropdownMenuSubTrigger,
    type DropdownMenuSubTriggerProps,
-   DropdownMenuTrigger,
-   type DropdownMenuTriggerProps,
+   type DropdownMenuRadioGroupProps,
  }
  
```

---

现在我需要修改 MasonryRoot.tsx 文件，将原来的按钮替换为 dropdown menu。

---

```diff
  import { gallerySettingAtom } from '~/atoms/app'
  import { Button } from '~/components/ui/button'
+ import {
+   DropdownMenu,
+   DropdownMenuContent,
+   DropdownMenuItem,
+   DropdownMenuLabel,
+   DropdownMenuSeparator,
+   DropdownMenuTrigger,
+ } from '~/components/ui/dropdown-menu'
  import { photoLoader } from '~/data/photos'
  import { usePhotos, usePhotoViewer } from '~/hooks/usePhotoViewer'
```

```diff
    const [gallerySetting, setGallerySetting] = useAtom(gallerySettingAtom)
  
-   const toggleSortOrder = () => {
+   const setSortOrder = (order: 'asc' | 'desc') => {
      setGallerySetting({
        ...gallerySetting,
-       sortOrder: gallerySetting.sortOrder === 'asc' ? 'desc' : 'asc',
+       sortOrder: order,
      })
    }
```

```diff
                  <i className="i-mingcute-github-line size-4" />
                </Button>
-               <Button
-                 variant="ghost"
-                 className="rounded-full px-4 py-2 bg-fill"
-                 onClick={toggleSortOrder}
-               >
-                 <i
-                   className={clsx(
-                     'size-4 mr-2 transition-transform duration-200',
-                     gallerySetting.sortOrder === 'asc'
-                       ? 'i-mingcute-sort-ascending-line'
-                       : 'i-mingcute-sort-descending-line',
-                   )}
-                 />
-                 <span className="text-sm font-medium">
-                   {gallerySetting.sortOrder === 'asc' ? '升序' : '降序'}
-                 </span>
-               </Button>
+               
+               <DropdownMenu>
+                 <DropdownMenuTrigger asChild>
+                   <Button
+                     variant="ghost"
+                     className="rounded-full px-4 py-2 bg-fill hover:bg-fill-hover transition-colors"
+                   >
+                     <i className="i-mingcute-sort-line size-4 mr-2" />
+                     <span className="text-sm font-medium">排序</span>
+                     <i className="i-mingcute-down-line size-3 ml-1 opacity-60" />
+                   </Button>
+                 </DropdownMenuTrigger>
+                 <DropdownMenuContent align="end" className="w-48">
+                   <DropdownMenuLabel>根据拍摄日期排序</DropdownMenuLabel>
+                   <DropdownMenuSeparator />
+                   <DropdownMenuItem
+                     onClick={() => setSortOrder('desc')}
+                     className={gallerySetting.sortOrder === 'desc' ? 'bg-accent/10' : ''}
+                   >
+                     <i className="i-mingcute-sort-descending-line size-4 mr-2" />
+                     <span>最新优先</span>
+                     {gallerySetting.sortOrder === 'desc' && (
+                       <i className="i-mingcute-check-line size-4 ml-auto text-accent" />
+                     )}
+                   </DropdownMenuItem>
+                   <DropdownMenuItem
+                     onClick={() => setSortOrder('asc')}
+                     className={gallerySetting.sortOrder === 'asc' ? 'bg-accent/10' : ''}
+                   >
+                     <i className="i-mingcute-sort-ascending-line size-4 mr-2" />
+                     <span>最早优先</span>
+                     {gallerySetting.sortOrder === 'asc' && (
+                       <i className="i-mingcute-check-line size-4 ml-auto text-accent" />
+                     )}
+                   </DropdownMenuItem>
+                 </DropdownMenuContent>
+               </DropdownMenu>
              </div>
            </div>
```

---

现在我需要检查是否有任何错误，并确保所有必要的变量都已定义。

---

<details>
            <summary>Grep search for "BUILT_DATE" • **0** files</summary>
        
No results found
</details>

---

<details>
            <summary>Searched codebase "BUILT_DATE build date" • **24** results</summary>
        
| File | Lines |
|------|-------|
| `vite.config.ts` | L1-46 |
| `src/modules/gallery/MasonryRoot.tsx` | L230-257 |
| `scripts/build-manifest.ts` | L495-558 |
| `src/global.d.ts` | L1-30 |
| `scripts/build-manifest.ts` | L333-396 |
| `scripts/build-manifest.ts` | L139-153 |
| `scripts/build-manifest.ts` | L42-84 |
| `scripts/build-manifest.ts` | L462-495 |
| `src/components/ui/photo-viewer/ExifPanel.tsx` | L848-859 |
| `scripts/build-manifest.ts` | L90-109 |
| `plugins/og-image-plugin.ts` | L12-51 |
| `scripts/build-manifest.ts` | L782-849 |
| `scripts/photo-loader.ts` | L51-53 |
| `scripts/build-manifest.ts` | L558-581 |
| `scripts/build-manifest.ts` | L283-333 |
| `scripts/generate-og-image.ts` | L1-23 |
| `package.json` | L1-24 |
| `scripts/build-manifest.ts` | L1-41 |
| `src/data/photos-manifest.json` | L460-533 |
| `src/data/photos-manifest.json` | L3033-3104 |
| `src/data/photos-manifest.json` | L957-1030 |
| `scripts/build-manifest.ts` | L396-462 |
| `scripts/photo-loader.ts` | L21-51 |
| `src/data/photos-manifest.json` | L139-210 |

</details>

---

很好，我看到 `BUILT_DATE` 已经在 `vite.config.ts` 中定义了，并且在 `global.d.ts` 中有类型声明。现在让我检查一下代码是否有任何编译错误。

---

```bash
pnpm run lint
```

```

> photo-gallery-site@0.0.1 lint /Users/innei/git/vibe-coding/photo-gallery-site
> eslint --fix


/Users/innei/git/vibe-coding/photo-gallery-site/src/atoms/route.ts
  34:70  warning  React Hook useMemo was passed a dependency list that is not an array literal. This means we can't 
statically verify whether you've passed the correct dependencies
         react-hooks/exhaustive-deps
  34:70  warning  React Hook useMemo has a missing dependency: 'selector'. Either include it or remove the dependenc
y array. If 'selector' changes too often, find the parent component that defines it and wrap that definition in useC
allback  react-hooks/exhaustive-deps

/Users/innei/git/vibe-coding/photo-gallery-site/src/components/ui/WebGLImageViewer.tsx
  1359:6   warning  React Hook useEffect has a missing dependency: 'debug'. Either include it or remove the dependen
cy array
                                           react-hooks/exhaustive-deps
  1411:57  warning  Conditionally rendered text nodes with siblings (elements or nodes), when rendered as a direct c
hild of a JSX element, should be wrapped in an element (for example, a <span>) to prevent Google Translate causing a
 browser error while manipulating the DOM  react-google-translate/no-conditional-text-nodes-with-siblings
  1411:59  warning  Text nodes which are preceded by a conditional expression, when rendered as a direct child of a 
JSX element, should be wrapped in an element (for example, a <span>) to prevent Google Translate causing a browser e
rror while manipulating the DOM            react-google-translate/no-conditional-text-nodes-with-siblings
  1412:43  warning  Conditionally rendered text nodes with siblings (elements or nodes), when rendered as a direct c
hild of a JSX element, should be wrapped in an element (for example, a <span>) to prevent Google Translate causing a
 browser error while manipulating the DOM  react-google-translate/no-conditional-text-nodes-with-siblings
  1414:64  warning  Conditionally rendered text nodes with siblings (elements or nodes), when rendered as a direct c
hild of a JSX element, should be wrapped in an element (for example, a <span>) to prevent Google Translate causing a
 browser error while manipulating the DOM  react-google-translate/no-conditional-text-nodes-with-siblings

/Users/innei/git/vibe-coding/photo-gallery-site/src/components/ui/button/Button.tsx
  135:36  warning  Fast refresh only works when a file only exports components. Use a new file to share constants or
 functions between components  react-refresh/only-export-components

/Users/innei/git/vibe-coding/photo-gallery-site/src/components/ui/dropdown-menu.tsx
   37:16  warning  A/an 'object expression' as default prop. This could lead to potential infinite render loop in Re
act. Use a variable instead of 'object expression'                          @eslint-react/no-unstable-default-props
   59:14  warning  A/an 'object expression' passed as the value prop to the context provider should not be construct
ed. It will change on every render. Consider wrapping it in a useMemo hook  @eslint-react/no-unstable-context-value
  190:16  warning  A/an 'object expression' as default prop. This could lead to potential infinite render loop in Re
act. Use a variable instead of 'object expression'                          @eslint-react/no-unstable-default-props 
/Users/innei/git/vibe-coding/photo-gallery-site/src/hooks/common/useTitle.ts
  11:40  warning  The ref value 'currentTitleRef.current' will likely have changed by the time this effect cleanup f
unction runs. If this ref points to a node rendered by React, copy 'currentTitleRef.current' to a variable inside th
e effect, and use that variable in the cleanup function  react-hooks/exhaustive-deps

/Users/innei/git/vibe-coding/photo-gallery-site/src/lib/jotai.ts
  33:46  warning  React Hook useCallback was passed a dependency list that is not an array literal. This means we ca
n't statically verify whether you've passed the correct dependencies
             react-hooks/exhaustive-deps
  33:46  warning  React Hook useCallback has a missing dependency: 'selector'. Either include it or remove the depen
dency array. If 'selector' changes too often, find the parent component that defines it and wrap that definition in
useCallback  react-hooks/exhaustive-deps

/Users/innei/git/vibe-coding/photo-gallery-site/src/lib/scroller.ts
  80:5  warning  Assignment to function parameter 'el'  no-param-reassign

✖ 15 problems (0 errors, 15 warnings)


```

---

很好！没有错误，只有一些警告。现在让我修复 dropdown menu 组件中的一些警告，然后测试一下功能。

---

```diff
  
  const useDropdownMenu = (): DropdownMenuContextType => {
-   const context = React.use(DropdownMenuContext)
+   const context = React.useContext(DropdownMenuContext)
    if (!context) {
      throw new Error('useDropdownMenu must be used within a DropdownMenu')
    }
    return context
  }
+ 
+ const defaultTransition: Transition = { type: 'spring', stiffness: 350, damping: 35 }
+ const defaultContentTransition: Transition = { duration: 0.2 }
  
  type DropdownMenuProps = React.ComponentProps<
```

```diff
  function DropdownMenu({
    children,
-   transition = { type: 'spring', stiffness: 350, damping: 35 },
+   transition = defaultTransition,
    animateOnHover = true,
    ...props
```

```diff
      [props],
    )
+ 
+   const contextValue = React.useMemo(
+     () => ({ isOpen, highlightTransition: transition, animateOnHover }),
+     [isOpen, transition, animateOnHover]
+   )
  
    return (
-     <DropdownMenuContext
-       value={{ isOpen, highlightTransition: transition, animateOnHover }}
-     >
+     <DropdownMenuContext.Provider value={contextValue}>
        <DropdownMenuPrimitive.Root
          data-slot="dropdown-menu"
```

```diff
          {children}
        </DropdownMenuPrimitive.Root>
-     </DropdownMenuContext>
+     </DropdownMenuContext.Provider>
    )
  }
```

```diff
    children,
    sideOffset = 4,
-   transition = { duration: 0.2 },
+   transition = defaultContentTransition,
    ...props
  }: DropdownMenuContentProps) {
```

---

现在让我运行开发服务器来测试新的 dropdown menu 功能。

---

```bash
pnpm dev
```

---

让我检查一下开发服务器是否正常启动。

---

```bash
curl -s http://localhost:5173 | head -20
```

```
<!doctype html>
<html lang="en" data-theme="dark">
  <head><script type="module">
/* eslint-disable */
'use client';  ;(function(){    if (typeof globalThis === 'undefined' || globalThis.__code_inspector_console) {

 return;    };    var path = "data-insp-path";    globalThis.__code_inspector_console = true;    var wrappers = [
   {        type: 'error',        origin: console.error,      },      {        type: 'warn',        origin: console.
warn,      },    ];    wrappers.forEach(wrapper => {      console[wrapper.type] = function () {        var args = Ar
ray.prototype.slice.call(arguments) || [];        var hasVueWarning = typeof args[0] === 'string' && args[0].indexOf
(path) !== -1; /* compatible for vue warning */        if (hasVueWarning) {          return;        }        var has
NextWarning = typeof args[1] === 'string' && args[1].indexOf(path) !== -1; /* compatible for nextjs hydrate */
  if (hasNextWarning) {          return;        }        var hasNextWarningV15 = typeof args[2] === 'string' && args
[2].indexOf(path) !== -1; /* compatible for nextjs(v15.0.0+) hydrate */        if (hasNextWarningV15) {          ret
urn;        }        wrapper.origin.apply(null, args);      };    });  })();  ;(function (){  if (typeof window !==
'undefined') {    if (!document.documentElement.querySelector('code-inspector-component')) {      (function($,y){typ
eof exports=="object"&&typeof module!="undefined"?y(exports):typeof define=="function"&&define.amd?define(["exports"
],y):y(($=typeof globalThis!="undefined"?globalThis:$||self).vueInspectorClient={})})(this,function($){"use strict";
var mt=Object.freeze,bt=Object.defineProperty,nn=Object.defineProperties;var on=Object.getOwnPropertyDescriptors;var
 vt=Object.getOwnPropertySymbols;var rn=Object.prototype.hasOwnProperty,sn=Object.prototype.propertyIsEnumerable;var
 A=Math.pow,yt=($,y,E)=>y in $?bt($,y,{enumerable:!0,configurable:!0,writable:!0,value:E}):$[y]=E,W=($,y)=>{for(var
E in y||(y={}))rn.call(y,E)&&yt($,E,y[E]);if(vt)for(var E of vt(y))sn.call(y,E)&&yt($,E,y[E]);return $},ie=($,y)=>nn
($,on(y));var Y=($,y)=>mt(bt($,"raw",{value:mt(y||$.slice())})),wt=($,y,E)=>new Promise((F,q)=>{var re=M=>{try{N(E.n
ext(M))}catch(R){q(R)}},se=M=>{try{N(E.throw(M))}catch(R){q(R)}},N=M=>M.done?F(M.value):Promise.resolve(M.value).the
n(re,se);N((E=E.apply($,y)).next())});var $t,_t,Et,xt,At;const y=window,E=y.ShadowRoot&&(y.ShadyCSS===void 0||y.Shad
yCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,F=Symbol(),q=new
WeakMap;let re=class{constructor(i,e,n){if(this._$cssResult$=!0,n!==F)throw Error("CSSResult is not constructable. U
se `unsafeCSS` or `css` instead.");this.cssText=i,this.t=e}get styleSheet(){let i=this.o;const e=this.t;if(E&&i===vo
id 0){const n=e!==void 0&&e.length===1;n&&(i=q.get(e)),i===void 0&&((this.o=i=new CSSStyleSheet).replaceSync(this.cs
sText),n&&q.set(e,i))}return i}toString(){return this.cssText}};const se=E?i=>i:i=>i instanceof CSSStyleSheet?(e=>{l
et n="";for(const s of e.cssRules)n+=s.cssText;return(s=>new re(typeof s=="string"?s:s+"",void 0,F))(n)})(i):i;var N
;const M=window,R=M.trustedTypes,kt=R?R.emptyScript:"",je=M.reactiveElementPolyfillSupport,ge={toAttribute(i,e){swit
ch(e){case Boolean:i=i?kt:null;break;case Object:case Array:i=i==null?i:JSON.stringify(i)}return i},fromAttribute(i,
e){let n=i;switch(e){case Boolean:n=i!==null;break;case Number:n=i===null?null:Number(i);break;case Object:case Arra
y:try{n=JSON.parse(i)}catch(s){n=null}}return n}},De=(i,e)=>e!==i&&(e==e||i==i),fe={attribute:!0,type:String,convert
er:ge,reflect:!1,hasChanged:De};let U=class extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdat
ePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(i){var e;this.finalize(),((e=this.h)!==
null&&e!==void 0?e:this.h=[]).push(i)}static get observedAttributes(){this.finalize();const i=[];return this.element
Properties.forEach((e,n)=>{const s=this._$Ep(n,e);s!==void 0&&(this._$Ev.set(s,n),i.push(s))}),i}static createProper
ty(i,e=fe){if(e.state&&(e.attribute=!1),this.finalize(),this.elementProperties.set(i,e),!e.noAccessor&&!this.prototy
pe.hasOwnProperty(i)){const n=typeof i=="symbol"?Symbol():"__"+i,s=this.getPropertyDescriptor(i,n,e);s!==void 0&&Obj
ect.defineProperty(this.prototype,i,s)}}static getPropertyDescriptor(i,e,n){return{get(){return this[e]},set(s){cons
t t=this[i];this[e]=s,this.requestUpdate(i,t,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(i){return
this.elementProperties.get(i)||fe}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;c
onst i=Object.getPrototypeOf(this);if(i.finalize(),i.h!==void 0&&(this.h=[...i.h]),this.elementProperties=new Map(i.
elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const e=this.properties,n=[...Object.getOwnP
ropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const s of n)this.createProperty(s,e[s])}return this.element
Styles=this.finalizeStyles(this.styles),!0}static finalizeStyles(i){const e=[];if(Array.isArray(i)){const n=new Set(
i.flat(1/0).reverse());for(const s of n)e.unshift(se(s))}else i!==void 0&&e.push(se(i));return e}static _$Ep(i,e){co
nst n=e.attribute;return n===!1?void 0:typeof n=="string"?n:typeof i=="string"?i.toLowerCase():void 0}u(){var i;this
._$E_=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$Eg(),this.requestUpdate(),(i=this.constructor.h
)===null||i===void 0||i.forEach(e=>e(this))}addController(i){var e,n;((e=this._$ES)!==null&&e!==void 0?e:this._$ES=[
]).push(i),this.renderRoot!==void 0&&this.isConnected&&((n=i.hostConnected)===null||n===void 0||n.call(i))}removeCon
troller(i){var e;(e=this._$ES)===null||e===void 0||e.splice(this._$ES.indexOf(i)>>>0,1)}_$Eg(){this.constructor.elem
entProperties.forEach((i,e)=>{this.hasOwnProperty(e)&&(this._$Ei.set(e,this[e]),delete this[e])})}createRenderRoot()
{var i;const e=(i=this.shadowRoot)!==null&&i!==void 0?i:this.attachShadow(this.constructor.shadowRootOptions);return
((n,s)=>{E?n.adoptedStyleSheets=s.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet):s.forEach(t=>{const o=document.c
reateElement("style"),r=y.litNonce;r!==void 0&&o.setAttribute("nonce",r),o.textContent=t.cssText,n.appendChild(o)})}
)(e,this.constructor.elementStyles),e}connectedCallback(){var i;this.renderRoot===void 0&&(this.renderRoot=this.crea
teRenderRoot()),this.enableUpdating(!0),(i=this._$ES)===null||i===void 0||i.forEach(e=>{var n;return(n=e.hostConnect
ed)===null||n===void 0?void 0:n.call(e)})}enableUpdating(i){}disconnectedCallback(){var i;(i=this._$ES)===null||i===
void 0||i.forEach(e=>{var n;return(n=e.hostDisconnected)===null||n===void 0?void 0:n.call(e)})}attributeChangedCallb
ack(i,e,n){this._$AK(i,n)}_$EO(i,e,n=fe){var s;const t=this.constructor._$Ep(i,n);if(t!==void 0&&n.reflect===!0){con
st o=(((s=n.converter)===null||s===void 0?void 0:s.toAttribute)!==void 0?n.converter:ge).toAttribute(e,n.type);this.
_$El=i,o==null?this.removeAttribute(t):this.setAttribute(t,o),this._$El=null}}_$AK(i,e){var n;const s=this.construct
or,t=s._$Ev.get(i);if(t!==void 0&&this._$El!==t){const o=s.getPropertyOptions(t),r=typeof o.converter=="function"?{f
romAttribute:o.converter}:((n=o.converter)===null||n===void 0?void 0:n.fromAttribute)!==void 0?o.converter:ge;this._
$El=t,this[t]=r.fromAttribute(e,o.type),this._$El=null}}requestUpdate(i,e,n){let s=!0;i!==void 0&&(((n=n||this.const
ructor.getPropertyOptions(i)).hasChanged||De)(this[i],e)?(this._$AL.has(i)||this._$AL.set(i,e),n.reflect===!0&&this.
_$El!==i&&(this._$EC===void 0&&(this._$EC=new Map),this._$EC.set(i,n))):s=!1),!this.isUpdatePending&&s&&(this._$E_=t
his._$Ej())}_$Ej(){return wt(this,null,function*(){this.isUpdatePending=!0;try{yield this._$E_}catch(e){Promise.reje
ct(e)}const i=this.scheduleUpdate();return i!=null&&(yield i),!this.isUpdatePending})}scheduleUpdate(){return this.p
erformUpdate()}performUpdate(){var i;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach((
s,t)=>this[t]=s),this._$Ei=void 0);let e=!1;const n=this._$AL;try{e=this.shouldUpdate(n),e?(this.willUpdate(n),(i=th
is._$ES)===null||i===void 0||i.forEach(s=>{var t;return(t=s.hostUpdate)===null||t===void 0?void 0:t.call(s)}),this.u
pdate(n)):this._$Ek()}catch(s){throw e=!1,this._$Ek(),s}e&&this._$AE(n)}willUpdate(i){}_$AE(i){var e;(e=this._$ES)==
=null||e===void 0||e.forEach(n=>{var s;return(s=n.hostUpdated)===null||s===void 0?void 0:s.call(n)}),this.hasUpdated
||(this.hasUpdated=!0,this.firstUpdated(i)),this.updated(i)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get upd
ateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(i){return!0}update(i
){this._$EC!==void 0&&(this._$EC.forEach((e,n)=>this._$EO(n,this[n],e)),this._$EC=void 0),this._$Ek()}updated(i){}fi
rstUpdated(i){}};var me;U.finalized=!0,U.elementProperties=new Map,U.elementStyles=[],U.shadowRootOptions={mode:"ope
n"},je==null||je({ReactiveElement:U}),((N=M.reactiveElementVersions)!==null&&N!==void 0?N:M.reactiveElementVersions=
[]).push("1.6.1");const le=window,V=le.trustedTypes,Le=V?V.createPolicy("lit-html",{createHTML:i=>i}):void 0,O="lit$
".concat((Math.random()+"").slice(9),"$"),Re="?"+O,Ct="<".concat(Re,">"),I=document,G=(i="")=>I.createComment(i),X=i
=>i===null||typeof i!="object"&&typeof i!="function",Ue=Array.isArray,Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|
(\/?$))/g,Ve=/-->/g,Ie=/>/g,j=RegExp(">|[       \n\f\r](?:([^\\s\"'>=/]+)([     \n\f\r]*=[      \n\f\r]*(?:[^   \n\f
\r\"'`<>=]|(\"|')|))|$)","g"),Be=/'/g,ze=/"/g,He=/^(?:script|style|textarea|title)$/i,ae=(i=>(e,...n)=>({_$litType$:
i,strings:e,values:n}))(1),D=Symbol.for("lit-noChange"),k=Symbol.for("lit-nothing"),Ke=new WeakMap,B=I.createTreeWal
ker(I,129,null,!1),St=(i,e)=>{const n=i.length-1,s=[];let t,o=e===2?"<svg>":"",r=Z;for(let a=0;a<n;a++){const c=i[a]
;let h,d,p=-1,u=0;for(;u<c.length&&(r.lastIndex=u,d=r.exec(c),d!==null);)u=r.lastIndex,r===Z?d[1]==="!--"?r=Ve:d[1]!
==void 0?r=Ie:d[2]!==void 0?(He.test(d[2])&&(t=RegExp("</"+d[2],"g")),r=j):d[3]!==void 0&&(r=j):r===j?d[0]===">"?(r=
t!=null?t:Z,p=-1):d[1]===void 0?p=-2:(p=r.lastIndex-d[2].length,h=d[1],r=d[3]===void 0?j:d[3]==='"'?ze:Be):r===ze||r
===Be?r=j:r===Ve||r===Ie?r=Z:(r=j,t=void 0);const g=r===j&&i[a+1].startsWith("/>")?" ":"";o+=r===Z?c+Ct:p>=0?(s.push
(h),c.slice(0,p)+"$lit$"+c.slice(p)+O+g):c+O+(p===-2?(s.push(void 0),a):g)}const l=o+(i[n]||"<?>")+(e===2?"</svg>":"
");if(!Array.isArray(i)||!i.hasOwnProperty("raw"))throw Error("invalid template strings array");return[Le!==void 0?L
e.createHTML(l):l,s]};class J{constructor({strings:e,_$litType$:n},s){let t;this.parts=[];let o=0,r=0;const l=e.leng
th-1,a=this.parts,[c,h]=St(e,n);if(this.el=J.createElement(c,s),B.currentNode=this.el.content,n===2){const d=this.el
.content,p=d.firstChild;p.remove(),d.append(...p.childNodes)}for(;(t=B.nextNode())!==null&&a.length<l;){if(t.nodeTyp
e===1){if(t.hasAttributes()){const d=[];for(const p of t.getAttributeNames())if(p.endsWith("$lit$")||p.startsWith(O)
){const u=h[r++];if(d.push(p),u!==void 0){const g=t.getAttribute(u.toLowerCase()+"$lit$").split(O),f=/([.?@])?(.*)/.
exec(u);a.push({type:1,index:o,name:f[2],strings:g,ctor:f[1]==="."?Pt:f[1]==="?"?Tt:f[1]==="@"?Nt:ce})}else a.push({
type:6,index:o})}for(const p of d)t.removeAttribute(p)}if(He.test(t.tagName)){const d=t.textContent.split(O),p=d.len
gth-1;if(p>0){t.textContent=V?V.emptyScript:"";for(let u=0;u<p;u++)t.append(d[u],G()),B.nextNode(),a.push({type:2,in
dex:++o});t.append(d[p],G())}}}else if(t.nodeType===8)if(t.data===Re)a.push({type:2,index:o});else{let d=-1;for(;(d=
t.data.indexOf(O,d+1))!==-1;)a.push({type:7,index:o}),d+=O.length-1}o++}}static createElement(e,n){const s=I.createE
lement("template");return s.innerHTML=e,s}}function z(i,e,n=i,s){var t,o,r,l;if(e===D)return e;let a=s!==void 0?(t=n
._$Co)===null||t===void 0?void 0:t[s]:n._$Cl;const c=X(e)?void 0:e._$litDirective$;return(a==null?void 0:a.construct
or)!==c&&((o=a==null?void 0:a._$AO)===null||o===void 0||o.call(a,!1),c===void 0?a=void 0:(a=new c(i),a._$AT(i,n,s)),
s!==void 0?((r=(l=n)._$Co)!==null&&r!==void 0?r:l._$Co=[])[s]=a:n._$Cl=a),a!==void 0&&(e=z(i,a._$AS(i,e.values),a,s)
),e}class Mt{constructor(e,n){this.u=[],this._$AN=void 0,this._$AD=e,this._$AM=n}get parentNode(){return this._$AM.p
arentNode}get _$AU(){return this._$AM._$AU}v(e){var n;const{el:{content:s},parts:t}=this._$AD,o=((n=e==null?void 0:e
.creationScope)!==null&&n!==void 0?n:I).importNode(s,!0);B.currentNode=o;let r=B.nextNode(),l=0,a=0,c=t[0];for(;c!==
void 0;){if(l===c.index){let h;c.type===2?h=new Q(r,r.nextSibling,this,e):c.type===1?h=new c.ctor(r,c.name,c.strings
,this,e):c.type===6&&(h=new jt(r,this,e)),this.u.push(h),c=t[++a]}l!==(c==null?void 0:c.index)&&(r=B.nextNode(),l++)
}return o}p(e){let n=0;for(const s of this.u)s!==void 0&&(s.strings!==void 0?(s._$AI(e,s,n),n+=s.strings.length-2):s
._$AI(e[n])),n++}}class Q{constructor(e,n,s,t){var o;this.type=2,this._$AH=k,this._$AN=void 0,this._$AA=e,this._$AB=
n,this._$AM=s,this.options=t,this._$Cm=(o=t==null?void 0:t.isConnected)===null||o===void 0||o}get _$AU(){var e,n;ret
urn(n=(e=this._$AM)===null||e===void 0?void 0:e._$AU)!==null&&n!==void 0?n:this._$Cm}get parentNode(){let e=this._$A
A.parentNode;const n=this._$AM;return n!==void 0&&e.nodeType===11&&(e=n.parentNode),e}get startNode(){return this._$
AA}get endNode(){return this._$AB}_$AI(e,n=this){e=z(this,e,n),X(e)?e===k||e==null||e===""?(this._$AH!==k&&this._$AR
(),this._$AH=k):e!==this._$AH&&e!==D&&this.g(e):e._$litType$!==void 0?this.$(e):e.nodeType!==void 0?this.T(e):(s=>Ue
(s)||typeof(s==null?void 0:s[Symbol.iterator])=="function")(e)?this.k(e):this.g(e)}O(e,n=this._$AB){return this._$AA
.parentNode.insertBefore(e,n)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}g(e){this._$AH!==k&&X(this._$AH)
?this._$AA.nextSibling.data=e:this.T(I.createTextNode(e)),this._$AH=e}$(e){var n;const{values:s,_$litType$:t}=e,o=ty
peof t=="number"?this._$AC(e):(t.el===void 0&&(t.el=J.createElement(t.h,this.options)),t);if(((n=this._$AH)===null||
n===void 0?void 0:n._$AD)===o)this._$AH.p(s);else{const r=new Mt(o,this),l=r.v(this.options);r.p(s),this.T(l),this._
$AH=r}}_$AC(e){let n=Ke.get(e.strings);return n===void 0&&Ke.set(e.strings,n=new J(e)),n}k(e){Ue(this._$AH)||(this._
$AH=[],this._$AR());const n=this._$AH;let s,t=0;for(const o of e)t===n.length?n.push(s=new Q(this.O(G()),this.O(G())
,this,this.options)):s=n[t],s._$AI(o),t++;t<n.length&&(this._$AR(s&&s._$AB.nextSibling,t),n.length=t)}_$AR(e=this._$
AA.nextSibling,n){var s;for((s=this._$AP)===null||s===void 0||s.call(this,!1,!0,n);e&&e!==this._$AB;){const t=e.next
Sibling;e.remove(),e=t}}setConnected(e){var n;this._$AM===void 0&&(this._$Cm=e,(n=this._$AP)===null||n===void 0||n.c
all(this,e))}}class ce{constructor(e,n,s,t,o){this.type=1,this._$AH=k,this._$AN=void 0,this.element=e,this.name=n,th
is._$AM=t,this.options=o,s.length>2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings
=s):this._$AH=k}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,n=this,s,t){const
o=this.strings;let r=!1;if(o===void 0)e=z(this,e,n,0),r=!X(e)||e!==this._$AH&&e!==D,r&&(this._$AH=e);else{const l=e;
let a,c;for(e=o[0],a=0;a<o.length-1;a++)c=z(this,l[s+a],n,a),c===D&&(c=this._$AH[a]),r||(r=!X(c)||c!==this._$AH[a]),
c===k?e=k:e!==k&&(e+=(c!=null?c:"")+o[a+1]),this._$AH[a]=c}r&&!t&&this.j(e)}j(e){e===k?this.element.removeAttribute(
this.name):this.element.setAttribute(this.name,e!=null?e:"")}}class Pt extends ce{constructor(){super(...arguments),
this.type=3}j(e){this.element[this.name]=e===k?void 0:e}}const Ot=V?V.emptyScript:"";class Tt extends ce{constructor
(){super(...arguments),this.type=4}j(e){e&&e!==k?this.element.setAttribute(this.name,Ot):this.element.removeAttribut
e(this.name)}}class Nt extends ce{constructor(e,n,s,t,o){super(e,n,s,t,o),this.type=5}_$AI(e,n=this){var s;if((e=(s=
z(this,e,n,0))!==null&&s!==void 0?s:k)===D)return;const t=this._$AH,o=e===k&&t!==k||e.capture!==t.capture||e.once!==
t.once||e.passive!==t.passive,r=e!==k&&(t===k||o);o&&this.element.removeEventListener(this.name,this,t),r&&this.elem
ent.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){var n,s;typeof this._$AH=="function"?this._$AH.cal
l((s=(n=this.options)===null||n===void 0?void 0:n.host)!==null&&s!==void 0?s:this.element,e):this._$AH.handleEvent(e
)}}class jt{constructor(e,n,s){this.element=e,this.type=6,this._$AN=void 0,this._$AM=n,this.options=s}get _$AU(){ret
urn this._$AM._$AU}_$AI(e){z(this,e)}}const We=le.litHtmlPolyfillSupport;We==null||We(J,Q),((me=le.litHtmlVersions)!
==null&&me!==void 0?me:le.litHtmlVersions=[]).push("2.6.1");var ve,ye;class ee extends U{constructor(){super(...argu
ments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){var e,n;const s=super.createRenderRoot();r
eturn(e=(n=this.renderOptions).renderBefore)!==null&&e!==void 0||(n.renderBefore=s.firstChild),s}update(e){const n=t
his.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((s,t,o)=>
{var r,l;const a=(r=o==null?void 0:o.renderBefore)!==null&&r!==void 0?r:t;let c=a._$litPart$;if(c===void 0){const h=
(l=o==null?void 0:o.renderBefore)!==null&&l!==void 0?l:null;a._$litPart$=c=new Q(t.insertBefore(G(),h),h,void 0,o!=n
ull?o:{})}return c._$AI(s),c})(n,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallba
ck(),(e=this._$Do)===null||e===void 0||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),
(e=this._$Do)===null||e===void 0||e.setConnected(!1)}render(){return D}}ee.finalized=!0,ee._$litElement$=!0,(ve=glob
alThis.litElementHydrateSupport)===null||ve===void 0||ve.call(globalThis,{LitElement:ee});const Ye=globalThis.litEle
mentPolyfillSupport;Ye==null||Ye({LitElement:ee}),((ye=globalThis.litElementVersions)!==null&&ye!==void 0?ye:globalT
his.litElementVersions=[]).push("3.2.2");const Dt=(i,e)=>e.kind==="method"&&e.descriptor&&!("value"in e.descriptor)?
ie(W({},e),{finisher(n){n.createProperty(e.key,i)}}):{kind:"field",key:Symbol(),placement:"own",descriptor:{},origin
alKey:e.key,initializer(){typeof e.initializer=="function"&&(this[e.key]=e.initializer.call(this))},finisher(n){n.cr
eateProperty(e.key,i)}};function P(i){return(e,n)=>n!==void 0?((s,t,o)=>{t.constructor.createProperty(o,s)})(i,e,n):
Dt(i,e)}function C(i){return P(ie(W({},i),{state:!0}))}function Fe(i,e){return(({finisher:n,descriptor:s})=>(t,o)=>{
var r;if(o===void 0){const l=(r=t.originalKey)!==null&&r!==void 0?r:t.key,a=s!=null?{kind:"method",placement:"protot
ype",key:l,descriptor:s(t.key)}:ie(W({},t),{key:l});return n!=null&&(a.finisher=function(c){n(c,l)}),a}{const l=t.co
nstructor;s!==void 0&&Object.defineProperty(t,o,s(o)),n==null||n(l,o)}})({descriptor:n=>{const s={get(){var t,o;retu
rn(o=(t=this.renderRoot)===null||t===void 0?void 0:t.querySelector(i))!==null&&o!==void 0?o:null},enumerable:!0,conf
igurable:!0};if(e){const t=typeof n=="symbol"?Symbol():"__"+n;s.get=function(){var o,r;return this[t]===void 0&&(thi
s[t]=(r=(o=this.renderRoot)===null||o===void 0?void 0:o.querySelector(i))!==null&&r!==void 0?r:null),this[t]}}return
 s}})}var be;(be=window.HTMLSlotElement)===null||be===void 0||be.prototype.assignedElements;const Lt=1;let Rt=class{
constructor(i){}get _$AU(){return this._$AM._$AU}_$AT(i,e,n){this._$Ct=i,this._$AM=e,this._$Ci=n}_$AS(i,e){return th
is.update(i,e)}update(i,e){return this.render(...e)}};const L=(i=>(...e)=>({_$litDirective$:i,values:e}))(class exte
nds Rt{constructor(i){var e;if(super(i),i.type!==Lt||i.name!=="style"||((e=i.strings)===null||e===void 0?void 0:e.le
ngth)>2)throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the
 attribute.")}render(i){return Object.keys(i).reduce((e,n)=>{const s=i[n];return s==null?e:e+"".concat(n=n.replace(/
(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g,"-<head>").toLowerCase(),":").concat(s,";")},"")}update(i,[e]){const{style:n}=i.e
lement;if(this.vt===void 0){this.vt=new Set;for(const s in e)this.vt.add(s);return this.render(e)}this.vt.forEach(s=
>{e[s]==null&&(this.vt.delete(s),s.includes("-")?n.removeProperty(s):n[s]="")});for(const s in e){const t=e[s];t!=nu
ll&&(this.vt.add(s),s.includes("-")?n.setProperty(s,t):n[s]=t)}return D}}),H="data-insp-path",Ut=Object.freeze(Objec
t.defineProperty({__proto__:null,default:{}},Symbol.toStringTag,{value:"Module"}));function Vt(i){if(i.__esModule)re
turn i;var e=i.default;if(typeof e=="function"){var n=function s(){if(this instanceof s){var t=[null];return t.push.
apply(t,arguments),new(Function.bind.apply(e,t))}return e.apply(this,arguments)};n.prototype=e.prototype}else n={};r
eturn Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(i).forEach(function(s){var t=Object.getOwnPropert
yDescriptor(i,s);Object.defineProperty(n,s,t.get?t:{enumerable:!0,get:function(){return i[s]}})}),n}var qe,Ge,we,Xe,
$e,Ze,Je,Qe,et={exports:{}};function tt(){if(Xe)return we;Xe=1;const i=Ge?qe:(Ge=1,qe={aliceblue:[240,248,255],antiq
uewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,
228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywo
od:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerb
lue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139
],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,10
7],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,
0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslateg
rey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgra
y:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forest
green:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[2
18,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hot
pink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230
,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcora
l:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,2
38,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightsk
yblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyell
ow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediu
maquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[
60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred
:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajo
white:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0]
,orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,23
8,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,
203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybro
wn:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagree
n:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90
,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,1
80],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,1
30,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]
}),e={};for(const t of Object.keys(i))e[i[t]]=t;const n={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"}
,hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:
"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels
:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3
,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};we=n;for(con
st t of Object.keys(n)){if(!("channels"in n[t]))throw new Error("missing channels property: "+t);if(!("labels"in n[t
]))throw new Error("missing channel labels property: "+t);if(n[t].labels.length!==n[t].channels)throw new Error("cha
nnel and label counts mismatch: "+t);const{channels:o,labels:r}=n[t];delete n[t].channels,delete n[t].labels,Object.
defineProperty(n[t],"channels",{value:o}),Object.defineProperty(n[t],"labels",{value:r})}function s(t,o){return A(t[
0]-o[0],2)+A(t[1]-o[1],2)+A(t[2]-o[2],2)}return n.rgb.hsl=function(t){const o=t[0]/255,r=t[1]/255,l=t[2]/255,a=Math.
min(o,r,l),c=Math.max(o,r,l),h=c-a;let d,p;c===a?d=0:o===c?d=(r-l)/h:r===c?d=2+(l-o)/h:l===c&&(d=4+(o-r)/h),d=Math.m
in(60*d,360),d<0&&(d+=360);const u=(a+c)/2;return p=c===a?0:u<=.5?h/(c+a):h/(2-c-a),[d,100*p,100*u]},n.rgb.hsv=funct
ion(t){let o,r,l,a,c;const h=t[0]/255,d=t[1]/255,p=t[2]/255,u=Math.max(h,d,p),g=u-Math.min(h,d,p),f=function(m){retu
rn(u-m)/6/g+.5};return g===0?(a=0,c=0):(c=g/u,o=f(h),r=f(d),l=f(p),h===u?a=l-r:d===u?a=1/3+o-l:p===u&&(a=2/3+r-o),a<
0?a+=1:a>1&&(a-=1)),[360*a,100*c,100*u]},n.rgb.hwb=function(t){const o=t[0],r=t[1];let l=t[2];const a=n.rgb.hsl(t)[0
],c=1/255*Math.min(o,Math.min(r,l));return l=1-1/255*Math.max(o,Math.max(r,l)),[a,100*c,100*l]},n.rgb.cmyk=function(
t){const o=t[0]/255,r=t[1]/255,l=t[2]/255,a=Math.min(1-o,1-r,1-l);return[100*((1-o-a)/(1-a)||0),100*((1-r-a)/(1-a)||
0),100*((1-l-a)/(1-a)||0),100*a]},n.rgb.keyword=function(t){const o=e[t];if(o)return o;let r,l=1/0;for(const a of Ob
ject.keys(i)){const c=s(t,i[a]);c<l&&(l=c,r=a)}return r},n.keyword.rgb=function(t){return i[t]},n.rgb.xyz=function(t
){let o=t[0]/255,r=t[1]/255,l=t[2]/255;return o=o>.04045?A((o+.055)/1.055,2.4):o/12.92,r=r>.04045?A((r+.055)/1.055,2
.4):r/12.92,l=l>.04045?A((l+.055)/1.055,2.4):l/12.92,[100*(.4124*o+.3576*r+.1805*l),100*(.2126*o+.7152*r+.0722*l),10
0*(.0193*o+.1192*r+.9505*l)]},n.rgb.lab=function(t){const o=n.rgb.xyz(t);let r=o[0],l=o[1],a=o[2];return r/=95.047,l
/=100,a/=108.883,r=r>.008856?A(r,1/3):7.787*r+16/116,l=l>.008856?A(l,1/3):7.787*l+16/116,a=a>.008856?A(a,1/3):7.787*
a+16/116,[116*l-16,500*(r-l),200*(l-a)]},n.hsl.rgb=function(t){const o=t[0]/360,r=t[1]/100,l=t[2]/100;let a,c,h;if(r
===0)return h=255*l,[h,h,h];a=l<.5?l*(1+r):l+r-l*r;const d=2*l-a,p=[0,0,0];for(let u=0;u<3;u++)c=o+1/3*-(u-1),c<0&&c
++,c>1&&c--,h=6*c<1?d+6*(a-d)*c:2*c<1?a:3*c<2?d+(a-d)*(2/3-c)*6:d,p[u]=255*h;return p},n.hsl.hsv=function(t){const o
=t[0];let r=t[1]/100,l=t[2]/100,a=r;const c=Math.max(l,.01);return l*=2,r*=l<=1?l:2-l,a*=c<=1?c:2-c,[o,100*(l===0?2*
a/(c+a):2*r/(l+r)),100*((l+r)/2)]},n.hsv.rgb=function(t){const o=t[0]/60,r=t[1]/100;let l=t[2]/100;const a=Math.floo
r(o)%6,c=o-Math.floor(o),h=255*l*(1-r),d=255*l*(1-r*c),p=255*l*(1-r*(1-c));switch(l*=255,a){case 0:return[l,p,h];cas
e 1:return[d,l,h];case 2:return[h,l,p];case 3:return[h,d,l];case 4:return[p,h,l];case 5:return[l,h,d]}},n.hsv.hsl=fu
nction(t){const o=t[0],r=t[1]/100,l=t[2]/100,a=Math.max(l,.01);let c,h;h=(2-r)*l;const d=(2-r)*a;return c=r*a,c/=d<=
1?d:2-d,c=c||0,h/=2,[o,100*c,100*h]},n.hwb.rgb=function(t){const o=t[0]/360;let r=t[1]/100,l=t[2]/100;const a=r+l;le
t c;a>1&&(r/=a,l/=a);const h=Math.floor(6*o),d=1-l;c=6*o-h,1&h&&(c=1-c);const p=r+c*(d-r);let u,g,f;switch(h){defaul
t:case 6:case 0:u=d,g=p,f=r;break;case 1:u=p,g=d,f=r;break;case 2:u=r,g=d,f=p;break;case 3:u=r,g=p,f=d;break;case 4:
u=p,g=r,f=d;break;case 5:u=d,g=r,f=p}return[255*u,255*g,255*f]},n.cmyk.rgb=function(t){const o=t[0]/100,r=t[1]/100,l
=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,o*(1-a)+a)),255*(1-Math.min(1,r*(1-a)+a)),255*(1-Math.min(1,l*(1-a)+a)
)]},n.xyz.rgb=function(t){const o=t[0]/100,r=t[1]/100,l=t[2]/100;let a,c,h;return a=3.2406*o+-1.5372*r+-.4986*l,c=-.
9689*o+1.8758*r+.0415*l,h=.0557*o+-.204*r+1.057*l,a=a>.0031308?1.055*A(a,1/2.4)-.055:12.92*a,c=c>.0031308?1.055*A(c,
1/2.4)-.055:12.92*c,h=h>.0031308?1.055*A(h,1/2.4)-.055:12.92*h,a=Math.min(Math.max(0,a),1),c=Math.min(Math.max(0,c),
1),h=Math.min(Math.max(0,h),1),[255*a,255*c,255*h]},n.xyz.lab=function(t){let o=t[0],r=t[1],l=t[2];return o/=95.047,
r/=100,l/=108.883,o=o>.008856?A(o,1/3):7.787*o+16/116,r=r>.008856?A(r,1/3):7.787*r+16/116,l=l>.008856?A(l,1/3):7.787
*l+16/116,[116*r-16,500*(o-r),200*(r-l)]},n.lab.xyz=function(t){let o,r,l;r=(t[0]+16)/116,o=t[1]/500+r,l=r-t[2]/200;
const a=A(r,3),c=A(o,3),h=A(l,3);return r=a>.008856?a:(r-16/116)/7.787,o=c>.008856?c:(o-16/116)/7.787,l=h>.008856?h:
(l-16/116)/7.787,o*=95.047,r*=100,l*=108.883,[o,r,l]},n.lab.lch=function(t){const o=t[0],r=t[1],l=t[2];let a;return
a=360*Math.atan2(l,r)/2/Math.PI,a<0&&(a+=360),[o,Math.sqrt(r*r+l*l),a]},n.lch.lab=function(t){const o=t[0],r=t[1],l=
t[2]/360*2*Math.PI;return[o,r*Math.cos(l),r*Math.sin(l)]},n.rgb.ansi16=function(t,o=null){const[r,l,a]=t;let c=o===n
ull?n.rgb.hsv(t)[2]:o;if(c=Math.round(c/50),c===0)return 30;let h=30+(Math.round(a/255)<<2|Math.round(l/255)<<1|Math
.round(r/255));return c===2&&(h+=60),h},n.hsv.ansi16=function(t){return n.rgb.ansi16(n.hsv.rgb(t),t[2])},n.rgb.ansi2
56=function(t){const o=t[0],r=t[1],l=t[2];return o===r&&r===l?o<8?16:o>248?231:Math.round((o-8)/247*24)+232:16+36*Ma
th.round(o/255*5)+6*Math.round(r/255*5)+Math.round(l/255*5)},n.ansi16.rgb=function(t){let o=t%10;if(o===0||o===7)ret
urn t>50&&(o+=3.5),o=o/10.5*255,[o,o,o];const r=.5*(1+~~(t>50));return[(1&o)*r*255,(o>>1&1)*r*255,(o>>2&1)*r*255]},n
.ansi256.rgb=function(t){if(t>=232){const r=10*(t-232)+8;return[r,r,r]}let o;return t-=16,[Math.floor(t/36)/5*255,Ma
th.floor((o=t%36)/6)/5*255,o%6/5*255]},n.rgb.hex=function(t){const o=(((255&Math.round(t[0]))<<16)+((255&Math.round(
t[1]))<<8)+(255&Math.round(t[2]))).toString(16).toUpperCase();return"000000".substring(o.length)+o},n.hex.rgb=functi
on(t){const o=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!o)return[0,0,0];let r=o[0];o[0].length===3&&(r=r.
split("").map(a=>a+a).join(""));const l=parseInt(r,16);return[l>>16&255,l>>8&255,255&l]},n.rgb.hcg=function(t){const
 o=t[0]/255,r=t[1]/255,l=t[2]/255,a=Math.max(Math.max(o,r),l),c=Math.min(Math.min(o,r),l),h=a-c;let d,p;return d=h<1
?c/(1-h):0,p=h<=0?0:a===o?(r-l)/h%6:a===r?2+(l-o)/h:4+(o-r)/h,p/=6,p%=1,[360*p,100*h,100*d]},n.hsl.hcg=function(t){c
onst o=t[1]/100,r=t[2]/100,l=r<.5?2*o*r:2*o*(1-r);let a=0;return l<1&&(a=(r-.5*l)/(1-l)),[t[0],100*l,100*a]},n.hsv.h
cg=function(t){const o=t[1]/100,r=t[2]/100,l=o*r;let a=0;return l<1&&(a=(r-l)/(1-l)),[t[0],100*l,100*a]},n.hcg.rgb=f
unction(t){const o=t[0]/360,r=t[1]/100,l=t[2]/100;if(r===0)return[255*l,255*l,255*l];const a=[0,0,0],c=o%1*6,h=c%1,d
=1-h;let p=0;switch(Math.floor(c)){case 0:a[0]=1,a[1]=h,a[2]=0;break;case 1:a[0]=d,a[1]=1,a[2]=0;break;case 2:a[0]=0
,a[1]=1,a[2]=h;break;case 3:a[0]=0,a[1]=d,a[2]=1;break;case 4:a[0]=h,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=
d}return p=(1-r)*l,[255*(r*a[0]+p),255*(r*a[1]+p),255*(r*a[2]+p)]},n.hcg.hsv=function(t){const o=t[1]/100,r=o+t[2]/1
00*(1-o);let l=0;return r>0&&(l=o/r),[t[0],100*l,100*r]},n.hcg.hsl=function(t){const o=t[1]/100,r=t[2]/100*(1-o)+.5*
o;let l=0;return r>0&&r<.5?l=o/(2*r):r>=.5&&r<1&&(l=o/(2*(1-r))),[t[0],100*l,100*r]},n.hcg.hwb=function(t){const o=t
[1]/100,r=o+t[2]/100*(1-o);return[t[0],100*(r-o),100*(1-r)]},n.hwb.hcg=function(t){const o=t[1]/100,r=1-t[2]/100,l=r
-o;let a=0;return l<1&&(a=(r-l)/(1-l)),[t[0],100*l,100*a]},n.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*
255,t[2]/65535*255]},n.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]},n.gray.rgb=functi
on(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]},n.gray.hsl=function(t){return[0,0,t[0]]},n.gray.hsv=n.gray.hsl
,n.gray.hwb=function(t){return[0,100,t[0]]},n.gray.cmyk=function(t){return[0,0,0,t[0]]},n.gray.lab=function(t){retur
n[t[0],0,0]},n.gray.hex=function(t){const o=255&Math.round(t[0]/100*255),r=((o<<16)+(o<<8)+o).toString(16).toUpperCa
se();return"000000".substring(r.length)+r},n.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]},we}function It
(){if(Ze)return $e;Ze=1;const i=tt();function e(t){const o=function(){const l={},a=Object.keys(i);for(let c=a.length
,h=0;h<c;h++)l[a[h]]={distance:-1,parent:null};return l}(),r=[t];for(o[t].distance=0;r.length;){const l=r.pop(),a=Ob
ject.keys(i[l]);for(let c=a.length,h=0;h<c;h++){const d=a[h],p=o[d];p.distance===-1&&(p.distance=o[l].distance+1,p.p
arent=l,r.unshift(d))}}return o}function n(t,o){return function(r){return o(t(r))}}function s(t,o){const r=[o[t].par
ent,t];let l=i[o[t].parent][t],a=o[t].parent;for(;o[a].parent;)r.unshift(o[a].parent),l=n(i[o[a].parent][a],l),a=o[a
].parent;return l.conversion=r,l}return $e=function(t){const o=e(t),r={},l=Object.keys(o);for(let a=l.length,c=0;c<a
;c++){const h=l[c];o[h].parent!==null&&(r[h]=s(h,o))}return r},$e}function Bt(){if(Qe)return Je;Qe=1;const i=tt(),e=
It(),n={};return Object.keys(i).forEach(s=>{n[s]={},Object.defineProperty(n[s],"channels",{value:i[s].channels}),Obj
ect.defineProperty(n[s],"labels",{value:i[s].labels});const t=e(s);Object.keys(t).forEach(o=>{const r=t[o];n[s][o]=f
unction(l){const a=function(...c){const h=c[0];if(h==null)return h;h.length>1&&(c=h);const d=l(c);if(typeof d=="obje
ct")for(let p=d.length,u=0;u<p;u++)d[u]=Math.round(d[u]);return d};return"conversion"in l&&(a.conversion=l.conversio
n),a}(r),n[s][o].raw=function(l){const a=function(...c){const h=c[0];return h==null?h:(h.length>1&&(c=h),l(c))};retu
rn"conversion"in l&&(a.conversion=l.conversion),a}(r)})}),Je=n}(function(i){const e=(c,h)=>(...d)=>"\x1B[".concat(c(
...d)+h,"m"),n=(c,h)=>(...d)=>{const p=c(...d);return"\x1B[".concat(38+h,";5;").concat(p,"m")},s=(c,h)=>(...d)=>{con
st p=c(...d);return"\x1B[".concat(38+h,";2;").concat(p[0],";").concat(p[1],";").concat(p[2],"m")},t=c=>c,o=(c,h,d)=>
[c,h,d],r=(c,h,d)=>{Object.defineProperty(c,h,{get:()=>{const p=d();return Object.defineProperty(c,h,{value:p,enumer
able:!0,configurable:!0}),p},enumerable:!0,configurable:!0})};let l;const a=(c,h,d,p)=>{l===void 0&&(l=Bt());const u
=p?10:0,g={};for(const[f,m]of Object.entries(l)){const w=f==="ansi16"?"ansi":f;f===h?g[w]=c(d,u):typeof m=="object"&
&(g[w]=c(m[h],u))}return g};Object.defineProperty(i,"exports",{enumerable:!0,get:function(){const c=new Map,h={modif
ier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9
,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:
[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBri
ght:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:
[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],
bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],
bgWhiteBright:[107,49]}};h.color.gray=h.color.blackBright,h.bgColor.bgGray=h.bgColor.bgBlackBright,h.color.grey=h.co
lor.blackBright,h.bgColor.bgGrey=h.bgColor.bgBlackBright;for(const[d,p]of Object.entries(h)){for(const[u,g]of Object
.entries(p))h[u]={open:"\x1B[".concat(g[0],"m"),close:"\x1B[".concat(g[1],"m")},p[u]=h[u],c.set(g[0],g[1]);Object.de
fineProperty(h,d,{value:p,enumerable:!1})}return Object.defineProperty(h,"codes",{value:c,enumerable:!1}),h.color.cl
ose="\x1B[39m",h.bgColor.close="\x1B[49m",r(h.color,"ansi",()=>a(e,"ansi16",t,!1)),r(h.color,"ansi256",()=>a(n,"ansi
256",t,!1)),r(h.color,"ansi16m",()=>a(s,"rgb",o,!1)),r(h.bgColor,"ansi",()=>a(e,"ansi16",t,!0)),r(h.bgColor,"ansi256
",()=>a(n,"ansi256",t,!0)),r(h.bgColor,"ansi16m",()=>a(s,"rgb",o,!0)),h}})})(et);var _e,nt,zt={stringReplaceAll:(i,e
,n)=>{let s=i.indexOf(e);if(s===-1)return i;const t=e.length;let o=0,r="";do r+=i.substr(o,s-o)+e+n,o=s+t,s=i.indexO
f(e,o);while(s!==-1);return r+=i.substr(o),r},stringEncaseCRLFWithFirstIndex:(i,e,n,s)=>{let t=0,o="";do{const r=i[s
-1]==="\r";o+=i.substr(t,(r?s-1:s)-t)+e+(r?"\r\n":"\n")+n,t=s+1,s=i.indexOf("\n",t)}while(s!==-1);return o+=i.substr
(t),o}};const te=et.exports,{stdout:Ee,stderr:xe}={stdout:!1,stderr:!1},{stringReplaceAll:Ht,stringEncaseCRLFWithFir
stIndex:Kt}=zt,{isArray:he}=Array,ot=["ansi","ansi","ansi256","ansi16m"],K=Object.create(null);class Wt{constructor(
e){return it(e)}}const it=i=>{const e={};return((n,s={})=>{if(s.level&&!(Number.isInteger(s.level)&&s.level>=0&&s.le
vel<=3))throw new Error("The `level` option should be an integer from 0 to 3");const t=Ee?Ee.level:0;n.level=s.level
===void 0?t:s.level})(e,i),e.template=(...n)=>lt(e.template,...n),Object.setPrototypeOf(e,de.prototype),Object.setPr
ototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new c
halk.Instance()` instead.")},e.template.Instance=Wt,e.template};function de(i){return it(i)}for(const[i,e]of Object.
entries(te))K[i]={get(){const n=pe(this,Ae(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(
this,i,{value:n}),n}};K.visible={get(){const i=pe(this,this._styler,!0);return Object.defineProperty(this,"visible",
{value:i}),i}};const rt=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(const i of rt)K[i]={get(){con
st{level:e}=this;return function(...n){const s=Ae(te.color[ot[e]][i](...n),te.color.close,this._styler);return pe(th
is,s,this._isEmpty)}}};for(const i of rt)K["bg"+i[0].toUpperCase()+i.slice(1)]={get(){const{level:e}=this;return fun
ction(...n){const s=Ae(te.bgColor[ot[e]][i](...n),te.bgColor.close,this._styler);return pe(this,s,this._isEmpty)}}};
const Yt=Object.defineProperties(()=>{},ie(W({},K),{level:{enumerable:!0,get(){return this._generator.level},set(i){
this._generator.level=i}}})),Ae=(i,e,n)=>{let s,t;return n===void 0?(s=i,t=e):(s=n.openAll+i,t=e+n.closeAll),{open:i
,close:e,openAll:s,closeAll:t,parent:n}},pe=(i,e,n)=>{const s=(...t)=>he(t[0])&&he(t[0].raw)?st(s,lt(s,...t)):st(s,t
.length===1?""+t[0]:t.join(" "));return Object.setPrototypeOf(s,Yt),s._generator=i,s._styler=e,s._isEmpty=n,s},st=(i
,e)=>{if(i.level<=0||!e)return i._isEmpty?"":e;let n=i._styler;if(n===void 0)return e;const{openAll:s,closeAll:t}=n;
if(e.indexOf("\x1B")!==-1)for(;n!==void 0;)e=Ht(e,n.close,n.open),n=n.parent;const o=e.indexOf("\n");return o!==-1&&
(e=Kt(e,t,s,o)),s+e+t};let ke;const lt=(i,...e)=>{const[n]=e;if(!he(n)||!he(n.raw))return e.join(" ");const s=e.slic
e(1),t=[n.raw[0]];for(let o=1;o<n.length;o++)t.push(String(s[o-1]).replace(/[{}\\]/g,"\\<head>"),String(n.raw[o]));r
eturn ke===void 0&&(ke=function(){if(nt)return _e;nt=1;const o=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.
))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,r=/(?:^|\.)(\
w+)(?:\(([^)]*)\))?/g,l=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,a=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\
])/gi,c=new Map([["n","\n"],["r","\r"],["t","   "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1
B"],["a","\x07"]]);function h(g){const f=g[0]==="u",m=g[1]==="{";return f&&!m&&g.length===5||g[0]==="x"&&g.length===
3?String.fromCharCode(parseInt(g.slice(1),16)):f&&m?String.fromCodePoint(parseInt(g.slice(2,-1),16)):c.get(g)||g}fun
ction d(g,f){const m=[],w=f.trim().split(/\s*,\s*/g);let _;for(const S of w){const ne=Number(S);if(Number.isNaN(ne))
{if(!(_=S.match(l)))throw new Error("Invalid Chalk template style argument: ".concat(S," (in style '").concat(g,"')"
));m.push(_[2].replace(a,(gt,oe,Ne)=>oe?h(oe):Ne))}else m.push(ne)}return m}function p(g){r.lastIndex=0;const f=[];l
et m;for(;(m=r.exec(g))!==null;){const w=m[1];if(m[2]){const _=d(w,m[2]);f.push([w].concat(_))}else f.push([w])}retu
rn f}function u(g,f){const m={};for(const _ of f)for(const S of _.styles)m[S[0]]=_.inverse?null:S.slice(1);let w=g;f
or(const[_,S]of Object.entries(m))if(Array.isArray(S)){if(!(_ in w))throw new Error("Unknown Chalk style: ".concat(_
));w=S.length>0?w[_](...S):w[_]}return w}return _e=(g,f)=>{const m=[],w=[];let _=[];if(f.replace(o,(S,ne,gt,oe,Ne,tn
)=>{if(ne)_.push(h(ne));else if(oe){const ft=_.join("");_=[],w.push(m.length===0?ft:u(g,m)(ft)),m.push({inverse:gt,s
tyles:p(oe)})}else if(Ne){if(m.length===0)throw new Error("Found extraneous } in Chalk template literal");w.push(u(g
,m)(_.join(""))),_=[],m.pop()}else _.push(tn)}),w.push(_.join("")),m.length>0){const S="Chalk template literal is mi
ssing ".concat(m.length," closing bracket").concat(m.length===1?"":"s"," (`}`)");throw new Error(S)}return w.join(""
)},_e}()),ke(i,t.join(""))};Object.defineProperties(de.prototype,K);const Ce=de();Ce.supportsColor=Ee,Ce.stderr=de({
level:xe?xe.level:0}),Ce.stderr.supportsColor=xe;var T={exports:{}};const ue=Vt(Ut),Se=ue,Me=ue,Ft=ue,qt=ue,Pe="16.4
.5",Gt=/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`
|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;function Oe(i){console.log("[dotenv@".concat(Pe,"][DEBUG] ").concat(i))}function a
t(i){return i&&i.DOTENV_KEY&&i.DOTENV_KEY.length>0?i.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.lengt
h>0?process.env.DOTENV_KEY:""}function Xt(i,e){let n;try{n=new URL(e)}catch(l){if(l.code==="ERR_INVALID_URL"){const
a=new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault
/.env.vault?environment=development");throw a.code="INVALID_DOTENV_KEY",a}throw l}const s=n.password;if(!s){const l=
new Error("INVALID_DOTENV_KEY: Missing key part");throw l.code="INVALID_DOTENV_KEY",l}const t=n.searchParams.get("en
vironment");if(!t){const l=new Error("INVALID_DOTENV_KEY: Missing environment part");throw l.code="INVALID_DOTENV_KE
Y",l}const o="DOTENV_VAULT_".concat(t.toUpperCase()),r=i.parsed[o];if(!r){const l=new Error("NOT_FOUND_DOTENV_ENVIRO
NMENT: Cannot locate environment ".concat(o," in your .env.vault file."));throw l.code="NOT_FOUND_DOTENV_ENVIRONMENT
",l}return{ciphertext:r,key:s}}function ct(i){let e=null;if(i&&i.path&&i.path.length>0)if(Array.isArray(i.path))for(
const n of i.path)Se.existsSync(n)&&(e=n.endsWith(".vault")?n:"".concat(n,".vault"));else e=i.path.endsWith(".vault"
)?i.path:"".concat(i.path,".vault");else e=Me.resolve(process.cwd(),".env.vault");return Se.existsSync(e)?e:null}fun
ction ht(i){return i[0]==="~"?Me.join(Ft.homedir(),i.slice(1)):i}const x={configDotenv:function(i){const e=Me.resolv
e(process.cwd(),".env");let n="utf8";const s=!!(i&&i.debug);i&&i.encoding?n=i.encoding:s&&Oe("No encoding is specifi
ed. UTF-8 is used by default");let t,o=[e];if(i&&i.path)if(Array.isArray(i.path)){o=[];for(const a of i.path)o.push(
ht(a))}else o=[ht(i.path)];const r={};for(const a of o)try{const c=x.parse(Se.readFileSync(a,{encoding:n}));x.popula
te(r,c,i)}catch(c){s&&Oe("Failed to load ".concat(a," ").concat(c.message)),t=c}let l=process.env;return i&&i.proces
sEnv!=null&&(l=i.processEnv),x.populate(l,r,i),t?{parsed:r,error:t}:{parsed:r}},_configVault:function(i){var e;e="Lo
ading env from encrypted .env.vault",console.log("[dotenv@".concat(Pe,"][INFO] ").concat(e));const n=x._parseVault(i
);let s=process.env;return i&&i.processEnv!=null&&(s=i.processEnv),x.populate(s,n,i),{parsed:n}},_parseVault:functio
n(i){const e=ct(i),n=x.configDotenv({path:e});if(!n.parsed){const r=new Error("MISSING_DATA: Cannot parse ".concat(e
," for an unknown reason"));throw r.code="MISSING_DATA",r}const s=at(i).split(","),t=s.length;let o;for(let r=0;r<t;
r++)try{const l=Xt(n,s[r].trim());o=x.decrypt(l.ciphertext,l.key);break}catch(l){if(r+1>=t)throw l}return x.parse(o)
},config:function(i){if(at(i).length===0)return x.configDotenv(i);const e=ct(i);return e?x._configVault(i):(n="You s
et DOTENV_KEY but you are missing a .env.vault file at ".concat(e,". Did you forget to build it?"),console.log("[dot
env@".concat(Pe,"][WARN] ").concat(n)),x.configDotenv(i));var n},decrypt:function(i,e){const n=Buffer.from(e.slice(-
64),"hex");let s=Buffer.from(i,"base64");const t=s.subarray(0,12),o=s.subarray(-16);s=s.subarray(12,-16);try{const r
=qt.createDecipheriv("aes-256-gcm",n,t);return r.setAuthTag(o),"".concat(r.update(s)).concat(r.final())}catch(r){con
st l=r instanceof RangeError,a=r.message==="Invalid key length",c=r.message==="Unsupported state or unable to authen
ticate data";if(l||a){const h=new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");throw h.code=
"INVALID_DOTENV_KEY",h}if(c){const h=new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");throw h.code="DECR
YPTION_FAILED",h}throw r}},parse:function(i){const e={};let n,s=i.toString();for(s=s.replace(/\r\n?/gm,"\n");(n=Gt.e
xec(s))!=null;){const t=n[1];let o=n[2]||"";o=o.trim();const r=o[0];o=o.replace(/^(['"`])([\s\S]*)\1$/gm,"$2"),r==='
"'&&(o=o.replace(/\\n/g,"\n"),o=o.replace(/\\r/g,"\r")),e[t]=o}return e},populate:function(i,e,n={}){const s=!!(n&&n
.debug),t=!!(n&&n.override);if(typeof e!="object"){const o=new Error("OBJECT_REQUIRED: Please check the processEnv a
rgument being passed to populate");throw o.code="OBJECT_REQUIRED",o}for(const o of Object.keys(e))Object.prototype.h
asOwnProperty.call(i,o)?(t===!0&&(i[o]=e[o]),s&&Oe(t===!0?'"'.concat(o,'" is already defined and WAS overwritten'):'
"'.concat(o,'" is already defined and was NOT overwritten'))):i[o]=e[o]}};T.exports.configDotenv=x.configDotenv,T.ex
ports._configVault=x._configVault,T.exports._parseVault=x._parseVault,T.exports.config=x.config,T.exports.decrypt=x.
decrypt,T.exports.parse=x.parse,T.exports.populate=x.populate,T.exports=x;const dt="{file}",pt="{line}",ut="{column}
";var Zt=Object.defineProperty,Jt=Object.getOwnPropertyDescriptor,b=(i,e,n,s)=>{for(var t,o=s>1?void 0:s?Jt(e,n):e,r
=i.length-1;r>=0;r--)(t=i[r])&&(o=(s?t(e,n,o):t(o))||o);return s&&o&&Zt(e,n,o),o};const Te="__code-inspector-unique-
id",Qt={ctrlKey:"^control",altKey:"⌥option",metaKey:"⌘command",shiftKey:"shift"},en={ctrlKey:"Ctrl",altKey:"Alt",met
aKey:"⊞Windows",shiftKey:"Shift"};class v extends ee{constructor(){super(...arguments),this.hotKeys="shiftKey,altKey
",this.port=5678,this.showSwitch=!1,this.autoToggle=!1,this.hideConsole=!1,this.locate=!0,this.copy=!1,this.ip="loca
lhost",this.position={top:0,right:0,bottom:0,left:0,padding:{top:0,right:0,bottom:0,left:0},border:{top:0,right:0,bo
ttom:0,left:0},margin:{top:0,right:0,bottom:0,left:0}},this.element={name:"",line:0,column:0,path:""},this.infoClass
Name={vertical:"",horizon:""},this.infoWidth="300px",this.show=!1,this.showLayerPanel=!1,this.layerPanelPosition={},
this.elementTree=[],this.dragging=!1,this.mousePosition={baseX:0,baseY:0,moveX:0,moveY:0},this.open=!1,this.moved=!1
,this.hoverSwitch=!1,this.preUserSelect="",this.sendType="xhr",this.isTracking=e=>this.hotKeys&&this.hotKeys.split("
,").every(n=>e[n.trim()]),this.getDomPropertyValue=(e,n)=>{const s=window.getComputedStyle(e);return Number(s.getPro
pertyValue(n).replace("px",""))},this.renderCover=e=>{const{top:n,right:s,bottom:t,left:o}=e.getBoundingClientRect()
;this.position={top:n,right:s,bottom:t,left:o,border:{top:this.getDomPropertyValue(e,"border-top-width"),right:this.
getDomPropertyValue(e,"border-right-width"),bottom:this.getDomPropertyValue(e,"border-bottom-width"),left:this.getDo
mPropertyValue(e,"border-left-width")},padding:{top:this.getDomPropertyValue(e,"padding-top"),right:this.getDomPrope
rtyValue(e,"padding-right"),bottom:this.getDomPropertyValue(e,"padding-bottom"),left:this.getDomPropertyValue(e,"pad
ding-left")},margin:{top:this.getDomPropertyValue(e,"margin-top"),right:this.getDomPropertyValue(e,"margin-right"),b
ottom:this.getDomPropertyValue(e,"margin-bottom"),left:this.getDomPropertyValue(e,"margin-left")}};const r=document.
documentElement.clientHeight,l=document.documentElement.clientWidth,a=r-t-this.getDomPropertyValue(e,"margin-bottom"
),c=l-s-this.getDomPropertyValue(e,"margin-right"),h=n-this.getDomPropertyValue(e,"margin-top"),d=o-this.getDomPrope
rtyValue(e,"margin-left");this.infoClassName={vertical:h>a?h<100?"element-info-top-inner":"element-info-top":a<100?"
element-info-bottom-inner":"element-info-bottom",horizon:d>=c?"element-info-right":"element-info-left"},this.infoWid
th=Math.max(s-o+this.getDomPropertyValue(e,"margin-right")+this.getDomPropertyValue(e,"margin-left"),Math.min(300,Ma
th.max(d,c)))+"px",this.addGlobalCursorStyle(),this.preUserSelect||(this.preUserSelect=getComputedStyle(document.bod
y).userSelect),document.body.style.userSelect="none";let p=e.getAttribute(H)||e[H]||"";!p&&e.getAttribute("data-astr
o-source-file")&&(p="".concat(e.getAttribute("data-astro-source-file"),":").concat(e.getAttribute("data-astro-source
-loc"),":").concat(e.tagName.toLowerCase()));const u=p.split(":"),g=u[u.length-1],f=Number(u[u.length-2]),m=Number(u
[u.length-3]),w=u.slice(0,u.length-3).join(":");this.element={name:g,path:w,line:m,column:f},this.show=!0},this.remo
veCover=()=>{this.show=!1,this.removeGlobalCursorStyle(),document.body.style.userSelect=this.preUserSelect,this.preU
serSelect=""},this.renderLayerPanel=(e,{x:n,y:s})=>{const t=document.documentElement.clientWidth-n,o=document.docume
ntElement.clientHeight-s;let r={};t<300?r.right=t+"px":r.left=n+"px",o<400?r.bottom=o+"px":r.top=s+"px",this.layerPa
nelPosition=r,this.elementTree=e,this.showLayerPanel=!0},this.removeLayerPanel=()=>{this.showLayerPanel=!1,this.elem
entTree=[]},this.addGlobalCursorStyle=()=>{if(!document.getElementById(Te)){const e=document.createElement("style");
e.setAttribute("id",Te),e.innerText="body * {\n        cursor: pointer !important;\n      }",document.body.appendChi
ld(e)}},this.removeGlobalCursorStyle=()=>{const e=document.getElementById(Te);e&&e.remove()},this.sendXHR=()=>{const
 e=encodeURIComponent(this.element.path),n="http://".concat(this.ip,":").concat(this.port,"/?file=").concat(e,"&line
=").concat(this.element.line,"&column=").concat(this.element.column),s=new XMLHttpRequest;s.open("GET",n,!0),s.send(
),s.addEventListener("error",()=>{this.sendType="img",this.sendImg()})},this.sendImg=()=>{const e=encodeURIComponent
(this.element.path),n="http://".concat(this.ip,":").concat(this.port,"/?file=").concat(e,"&line=").concat(this.eleme
nt.line,"&column=").concat(this.element.column);document.createElement("img").src=n},this.trackCode=()=>{if(this.loc
ate&&(this.sendType==="xhr"?this.sendXHR():this.sendImg()),this.copy){const e=function(n,s,t,o){let r="".concat(n,":
").concat(s,":").concat(t);if(typeof o=="string")r=o.replace(dt,n).replace(pt,s.toString()).replace(ut,t.toString())
;else if(o instanceof Array)return o.map(l=>l.replace(dt,n).replace(pt,s.toString()).replace(ut,t.toString()));retur
n[r]}(this.element.path,String(this.element.line),String(this.element.column),this.copy);this.copyToClipboard(e[0])}
},this.moveSwitch=e=>{if(e.composedPath().includes(this)?this.hoverSwitch=!0:this.hoverSwitch=!1,this.dragging)retur
n this.moved=!0,this.inspectorSwitchRef.style.left=this.mousePosition.baseX+(this.getMousePosition(e).x-this.mousePo
sition.moveX)+"px",void(this.inspectorSwitchRef.style.top=this.mousePosition.baseY+(this.getMousePosition(e).y-this.
mousePosition.moveY)+"px")},this.isSamePositionNode=(e,n)=>{const s=e.getBoundingClientRect(),t=n.getBoundingClientR
ect();return s.top===t.top&&s.left===t.left&&s.right===t.right&&s.bottom===t.bottom},this.handleMouseMove=e=>{if((th
is.isTracking(e)&&!this.dragging||this.open)&&!this.hoverSwitch){const n=e.composedPath();let s;for(let t=0;t<n.leng
th;t++){const o=n[t];if((o.hasAttribute&&o.hasAttribute(H)||o[H])&&(s?this.isSamePositionNode(s,o)&&(s=o):s=o),o.has
Attribute&&o.hasAttribute("data-astro-source-file")){s=o;break}}s?this.renderCover(s):this.removeCover()}else this.r
emoveCover()},this.handleMouseClick=e=>{(this.isTracking(e)||this.open)&&this.show&&(e.stopPropagation(),e.preventDe
fault(),this.trackCode(),this.removeCover(),this.autoToggle&&(this.open=!1)),setTimeout(()=>{this.removeLayerPanel()
})},this.handleContextMenu=e=>{if((this.isTracking(e)&&!this.dragging||this.open)&&!this.hoverSwitch){e.preventDefau
lt();const n=e.composedPath(),s=this.generateNodeTree(n);this.renderLayerPanel(s,{x:e.pageX,y:e.pageY})}},this.gener
ateNodeTree=e=>{let n=null,s=[];for(let t=0;t<e.length;t++){const o=this.parseNode(e[t]);o.isTrackNode&&(n&&n.rect!=
=o.rect?n.path!==o.path&&(s.push(n),n=o):n=o)}return n&&s.push(n),s},this.parseNode=e=>{var p,u,g,f;let n=((p=e.getA
ttribute)==null?void 0:p.call(e,H))||e[H]||"";if(!n&&((u=e.getAttribute)!=null&&u.call(e,"data-astro-source-file"))&
&(n="".concat((g=e.getAttribute)==null?void 0:g.call(e,"data-astro-source-file"),":").concat((f=e.getAttribute)==nul
l?void 0:f.call(e,"data-astro-source-loc"),":").concat(e.tagName.toLowerCase())),!n)return{isTrackNode:!1};const s=n
.split(":"),t=s[s.length-1],o=Number(s[s.length-2]),r=Number(s[s.length-3]),l=s.slice(0,s.length-3).join(":"),{top:a
,right:c,bottom:h,left:d}=e.getBoundingClientRect();return{isTrackNode:!0,isAstroNode:!!e.getAttribute("data-astro-s
ource-file"),originNode:e,rect:"".concat(a,",").concat(c,",").concat(h,",").concat(d),name:t,path:l,line:r,column:o}
},this.handlePointerDown=e=>{let n=!1,s=e.target;for(;s;){if(s.disabled){n=!0;break}s=s.parentElement}n&&(this.isTra
cking(e)||this.open)&&this.show&&(e.stopPropagation(),e.preventDefault(),this.trackCode(),this.removeCover(),this.au
toToggle&&(this.open=!1))},this.handleKeyUp=e=>{this.isTracking(e)||this.open||this.removeCover()},this.printTip=()=
>{const e=navigator.userAgent.toLowerCase(),n=["windows","win32","wow32","win64","wow64"].some(r=>e.toUpperCase().ma
tch(r.toUpperCase()))?en:Qt,s=this.hotKeys.split(",").map(r=>"%c"+n[r.trim()]),t=2*s.length+1,o=Array(t).fill("").ma
p((r,l)=>l%2==0?"color: #42b983; font-family: PingFang SC;":"color: #006aff; font-weight: bold; font-family: PingFan
g SC;");console.log("%c[code-inspector-plugin]%c同时按住 ".concat(s.join(" %c+ "),"%c 时启用功能(点击页面元素可定位 至编辑器源代码)"),"color:
 #006aff; font-weight: bolder;",...o)},this.getMousePosition=e=>{var n,s;return{x:e instanceof MouseEvent?e.pageX:(n
=e.touches[0])==null?void 0:n.pageX,y:e instanceof MouseEvent?e.pageY:(s=e.touches[0])==null?void 0:s.pageY}},this.r
ecordMousePosition=e=>{this.mousePosition={baseX:this.inspectorSwitchRef.offsetLeft,baseY:this.inspectorSwitchRef.of
fsetTop,moveX:this.getMousePosition(e).x,moveY:this.getMousePosition(e).y},this.dragging=!0,e.preventDefault()},this
.handleMouseUp=e=>{this.hoverSwitch=!1,this.dragging&&(this.dragging=!1,e instanceof TouchEvent&&this.switch(e))},th
is.switch=e=>{this.moved||(this.open=!this.open,e.preventDefault(),e.stopPropagation()),this.moved=!1},this.handleLa
yerPanelClick=e=>{var o,r,l;const n=e.target;if(!((o=n==null?void 0:n.classList)!=null&&o.contains("inspector-layer"
))||!((r=n==null?void 0:n.dataset)!=null&&r.index))return;e.stopPropagation();const s=+n.dataset.index,t=(l=this.ele
mentTree)==null?void 0:l[s];t&&(this.element={name:t.name,column:t.column,line:t.line,path:t.path},this.trackCode(),
this.removeLayerPanel())}}copyToClipboard(e){var n;if(typeof((n=navigator==null?void 0:navigator.clipboard)==null?vo
id 0:n.writeText)=="function")navigator.clipboard.writeText(e);else{const s=document.createElement("textarea");s.val
ue=e,document.body.appendChild(s),s.select(),document.execCommand("copy"),document.body.removeChild(s)}}firstUpdated
(){this.hideConsole||this.printTip(),window.addEventListener("mousemove",this.handleMouseMove,!0),window.addEventLis
tener("touchmove",this.handleMouseMove,!0),window.addEventListener("mousemove",this.moveSwitch,!0),window.addEventLi
stener("touchmove",this.moveSwitch,!0),window.addEventListener("click",this.handleMouseClick,!0),window.addEventList
ener("pointerdown",this.handlePointerDown,!0),window.addEventListener("keyup",this.handleKeyUp,!0),window.addEventLi
stener("mouseleave",this.removeCover,!0),window.addEventListener("mouseup",this.handleMouseUp,!0),window.addEventLis
tener("touchend",this.handleMouseUp,!0),window.addEventListener("contextmenu",this.handleContextMenu,!0),this.inspec
torSwitchRef.addEventListener("mousedown",this.recordMousePosition),this.inspectorSwitchRef.addEventListener("touchs
tart",this.recordMousePosition),this.inspectorSwitchRef.addEventListener("click",this.switch),this.inspectorLayersRe
f.addEventListener("click",this.handleLayerPanelClick)}disconnectedCallback(){window.removeEventListener("mousemove"
,this.handleMouseMove,!0),window.removeEventListener("touchmove",this.handleMouseMove,!0),window.removeEventListener
("mousemove",this.moveSwitch,!0),window.removeEventListener("touchmove",this.moveSwitch,!0),window.removeEventListen
er("click",this.handleMouseClick,!0),window.removeEventListener("pointerdown",this.handlePointerDown,!0),window.remo
veEventListener("keyup",this.handleKeyUp,!0),window.removeEventListener("mouseleave",this.removeCover,!0),window.rem
oveEventListener("mouseup",this.handleMouseUp,!0),window.removeEventListener("touchend",this.handleMouseUp,!0),windo
w.removeEventListener("contextmenu",this.handleContextMenu,!0),this.inspectorSwitchRef&&(this.inspectorSwitchRef.rem
oveEventListener("mousedown",this.recordMousePosition),this.inspectorSwitchRef.removeEventListener("touchstart",this
.recordMousePosition),this.inspectorSwitchRef.removeEventListener("click",this.switch)),this.inspectorLayersRef&&thi
s.inspectorLayersRef.removeEventListener("click",this.handleLayerPanelClick)}render(){const e={display:this.show?"bl
ock":"none",top:this.position.top-this.position.margin.top+"px",left:this.position.left-this.position.margin.left+"p
x",height:"".concat(this.position.bottom-this.position.top+this.position.margin.bottom+this.position.margin.top,"px"
),width:"".concat(this.position.right-this.position.left+this.position.margin.right+this.position.margin.left,"px")}
,n={borderTopWidth:"".concat(this.position.margin.top,"px"),borderRightWidth:"".concat(this.position.margin.right,"p
x"),borderBottomWidth:"".concat(this.position.margin.bottom,"px"),borderLeftWidth:"".concat(this.position.margin.lef
t,"px")},s={borderTopWidth:"".concat(this.position.border.top,"px"),borderRightWidth:"".concat(this.position.border.
right,"px"),borderBottomWidth:"".concat(this.position.border.bottom,"px"),borderLeftWidth:"".concat(this.position.bo
rder.left,"px")},t={borderTopWidth:"".concat(this.position.padding.top,"px"),borderRightWidth:"".concat(this.positio
n.padding.right,"px"),borderBottomWidth:"".concat(this.position.padding.bottom,"px"),borderLeftWidth:"".concat(this.
position.padding.left,"px")},o=W({display:this.showLayerPanel?"block":"none"},this.layerPanelPosition);return ae(xt|
|(xt=Y(['\n      <div\n        class="code-inspector-container"\n        id="code-inspector-container"\n        styl
e=','\n      >\n        <div class="margin-overlay" style=','>\n          <div class="border-overlay" style=','>\n
          <div class="padding-overlay" style=','>\n              <div class="content-overlay"></div>\n            </
div>\n          </div>\n        </div>\n        <div\n          id="element-info"\n          class="element-info ',"
 ",'"\n          style=','\n        >\n          <div class="element-info-content">\n            <div class="name-li
ne">\n              <div class="element-name">\n                <span class="element-title">&lt;','&gt;</span>\n
            <span class="element-tip">click to open IDE</span>\n              </div>\n            </div>\n
  <div class="path-line">','</div>\n          </div>\n        </div>\n      </div>\n      <div\n        id="inspecto
r-switch"\n        class="inspector-switch '," ",'"\n        style=',"\n      >\n        ",'\n      </div>\n      <d
iv id="inspector-layers" style=',">\n        ","\n      </div>"])),L(e),L(n),L(s),L(t),this.infoClassName.vertical,t
his.infoClassName.horizon,L({width:this.infoWidth}),this.element.name,this.element.path,this.open?"active-inspector-
switch":"",this.moved?"move-inspector-switch":"",L({display:this.showSwitch?"flex":"none"}),this.open?ae($t||($t=Y([
'\n              <svg\n                t="1677801709811"\n                class="icon"\n                viewBox="0 0
 1024 1024"\n                version="1.1"\n                xmlns="http://www.w3.org/2000/svg"\n                p-id
="1110"\n                xmlns:xlink="http://www.w3.org/1999/xlink"\n                width="1em"\n                he
ight="1em"\n              >\n                <path\n                  d="M546.56 704H128c-19.2 0-32-12.8-32-32V256h7
04v194.56c10.928 1.552 21.648 3.76 32 6.832V128c0-35.2-28.8-64-64-64H128C92.8 64 64 92.8 64 128v544c0 35.2 28.8 64 6
4 64h425.392a221.936 221.936 0 0 1-6.848-32zM96 128c0-19.2 12.8-32 32-32h640c19.2 0 32 12.8 32 32v96H96V128z"\n
             fill="#34495E"\n                  p-id="1111"\n                ></path>\n                <path\n
           d="M416 160m-32 0a32 32 0 1 0 64 0 32 32 0 1 0-64 0Z"\n                  fill="#00B42A"\n
  p-id="1112"\n                ></path>\n                <path\n                  d="M288 160m-32 0a32 32 0 1 0 64 0
 32 32 0 1 0-64 0Z"\n                  fill="#F7BA1E"\n                  p-id="1113"\n                ></path>\n
            <path\n                  d="M160 160m-32 0a32 32 0 1 0 64 0 32 32 0 1 0-64 0Z"\n                  fill="
#F53F3F"\n                  p-id="1114"\n                ></path>\n                <path\n                  d="M382.
848 658.928l99.376-370.88 30.912 8.272-99.36 370.88zM318.368 319.2L160 477.6l158.4 158.4 22.64-22.624-135.792-135.77
6 135.776-135.776zM768 480c-13.088 0-25.888 1.344-38.24 3.84l6.24-6.24-158.4-158.4-22.64 22.624 135.792 135.776-135.
776 135.776 22.656 22.624 2.208-2.224a190.768 190.768 0 0 0 30.928 148.08l-116.672 116.656c-10.24 10.24-10.24 26.896
 0 37.136l27.76 27.76c5.12 5.12 11.84 7.68 18.56 7.68s13.456-2.56 18.56-7.68l120.992-120.96A190.56 190.56 0 0 0 768
864c105.872 0 192-86.128 192-192s-86.128-192-192-192z m-159.12 193.136c0-88.224 71.776-160 160-160 10.656 0 21.04 1.
152 31.12 3.152V672c0 19.2-12.8 32-32 32h-156a160.144 160.144 0 0 1-3.12-30.864z m-68.464 263.584l-19.632-19.632 110
.336-110.336c6.464 6.656 13.392 12.848 20.752 18.528l-111.456 111.44z m228.464-103.584c-65.92 0-122.576-40.096-147.0
56-97.136H768c35.2 0 64-28.8 64-64v-145.776c56.896 24.544 96.88 81.12 96.88 146.912 0 88.224-71.776 160-160 160z"\n
                 fill="#006AFF"\n                  p-id="1115"\n                ></path>\n                <path\n
               d="M864.576 672c0 52.928-43.072 96-96 96v32a128 128 0 0 0 128-128h-32z"\n                  fill="#344
95E"\n                  p-id="1116"\n                ></path>\n              </svg>\n            ']))):ae(_t||(_t=Y(
['<svg\n              t="1677801709811"\n              class="icon"\n              viewBox="0 0 1024 1024"\n
      version="1.1"\n              xmlns="http://www.w3.org/2000/svg"\n              p-id="1110"\n              xmln
s:xlink="http://www.w3.org/1999/xlink"\n              width="1em"\n              height="1em"\n            >\n
        <path\n                d="M546.56 704H128c-19.2 0-32-12.8-32-32V256h704v194.56c10.928 1.552 21.648 3.76 32 6
.832V128c0-35.2-28.8-64-64-64H128C92.8 64 64 92.8 64 128v544c0 35.2 28.8 64 64 64h425.392a221.936 221.936 0 0 1-6.84
8-32zM96 128c0-19.2 12.8-32 32-32h640c19.2 0 32 12.8 32 32v96H96V128z"\n                fill="currentColor"\n
         p-id="1111"\n              ></path>\n              <path\n                d="M416 160m-32 0a32 32 0 1 0 64
0 32 32 0 1 0-64 0Z"\n                fill="currentColor"\n                p-id="1112"\n              ></path>\n
          <path\n                d="M288 160m-32 0a32 32 0 1 0 64 0 32 32 0 1 0-64 0Z"\n                fill="curren
tColor"\n                p-id="1113"\n              ></path>\n              <path\n                d="M160 160m-32 0
a32 32 0 1 0 64 0 32 32 0 1 0-64 0Z"\n                fill="currentColor"\n                p-id="1114"\n
  ></path>\n              <path\n                d="M382.848 658.928l99.376-370.88 30.912 8.272-99.36 370.88zM318.36
8 319.2L160 477.6l158.4 158.4 22.64-22.624-135.792-135.776 135.776-135.776zM768 480c-13.088 0-25.888 1.344-38.24 3.8
4l6.24-6.24-158.4-158.4-22.64 22.624 135.792 135.776-135.776 135.776 22.656 22.624 2.208-2.224a190.768 190.768 0 0 0
 30.928 148.08l-116.672 116.656c-10.24 10.24-10.24 26.896 0 37.136l27.76 27.76c5.12 5.12 11.84 7.68 18.56 7.68s13.45
6-2.56 18.56-7.68l120.992-120.96A190.56 190.56 0 0 0 768 864c105.872 0 192-86.128 192-192s-86.128-192-192-192z m-159
.12 193.136c0-88.224 71.776-160 160-160 10.656 0 21.04 1.152 31.12 3.152V672c0 19.2-12.8 32-32 32h-156a160.144 160.1
44 0 0 1-3.12-30.864z m-68.464 263.584l-19.632-19.632 110.336-110.336c6.464 6.656 13.392 12.848 20.752 18.528l-111.4
56 111.44z m228.464-103.584c-65.92 0-122.576-40.096-147.056-97.136H768c35.2 0 64-28.8 64-64v-145.776c56.896 24.544 9
6.88 81.12 96.88 146.912 0 88.224-71.776 160-160 160z"\n                fill="currentColor"\n                p-id="1
115"\n              ></path>\n              <path\n                d="M864.576 672c0 52.928-43.072 96-96 96v32a128 1
28 0 0 0 128-128h-32z"\n                fill="currentColor"\n                p-id="1116"\n              ></path>\n
          </svg>']))),L(o),this.elementTree.map((r,l)=>ae(Et||(Et=Y(['<div class="inspector-layer" data-index=','>\n
          <div class="name-line">\n            <div class="element-name">\n              <span class="element-title"
>&lt;','&gt;</span>\n              <span class="element-tip">click to open IDE</span>\n            </div>\n
 </div>\n          <div class="path-line">',"</div>\n        </div>\n      "])),l,r.name,r.path)))}}v.styles=((i,...
e)=>{const n=i.length===1?i[0]:e.reduce((s,t,o)=>s+(r=>{if(r._$cssResult$===!0)return r.cssText;if(typeof r=="number
")return r;throw Error("Value passed to 'css' function must be a 'css' function result: "+r+". Use 'unsafeCSS' to pa
ss non-literal values, but take care to ensure page security.")})(t)+i[o+1],i[0]);return new re(n,i,F)})(At||(At=Y([
"\n    .code-inspector-container {\n      position: fixed;\n      pointer-events: none;\n      z-index: 999999999999
9;\n      font-family: 'PingFang SC';\n      .margin-overlay {\n        position: absolute;\n        inset: 0;\n
    border-style: solid;\n        border-color: rgba(255, 155, 0, 0.3);\n        .border-overlay {\n          positi
on: absolute;\n          inset: 0;\n          border-style: solid;\n          border-color: rgba(255, 200, 50, 0.3);
\n          .padding-overlay {\n            position: absolute;\n            inset: 0;\n            border-style: so
lid;\n            border-color: rgba(77, 200, 0, 0.3);\n            .content-overlay {\n              position: abso
lute;\n              inset: 0;\n              background: rgba(120, 170, 210, 0.7);\n            }\n          }\n
     }\n      }\n    }\n    .element-info {\n      position: absolute;\n    }\n    .element-info-content, #inspector
-layers {\n      max-width: 100%;\n      font-size: 12px;\n      color: #000;\n      background-color: #fff;\n
word-break: break-all;\n      box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);\n      box-sizing: border-box;\n      paddin
g: 4px 8px;\n      border-radius: 4px;\n    }\n    .element-info-top {\n      top: -4px;\n      transform: translate
Y(-100%);\n    }\n    .element-info-bottom {\n      top: calc(100% + 4px);\n    }\n    .element-info-top-inner {\n
    top: 4px;\n    }\n    .element-info-bottom-inner {\n      bottom: 4px;\n    }\n    .element-info-left {\n      l
eft: 0;\n      display: flex;\n      justify-content: flex-start;\n    }\n    .element-info-right {\n      right: 0;
\n      display: flex;\n      justify-content: flex-end;\n    }\n    .element-name .element-title {\n      color: co
ral;\n      font-weight: bold;\n    }\n    .element-name .element-tip {\n      color: #006aff;\n    }\n    .path-lin
e {\n      color: #333;\n      line-height: 12px;\n      margin-top: 4px;\n    }\n    .inspector-switch {\n      pos
ition: fixed;\n      z-index: 9999999999999;\n      top: 50%;\n      right: 24px;\n      font-size: 22px;\n      tra
nsform: translateY(-100%);\n      display: flex;\n      align-items: center;\n      justify-content: center;\n
background-color: rgba(255, 255, 255, 0.8);\n      color: #555;\n      height: 32px;\n      width: 32px;\n      bord
er-radius: 50%;\n      box-shadow: 0px 1px 2px -2px rgba(0, 0, 0, 0.2),\n        0px 3px 6px 0px rgba(0, 0, 0, 0.16)
,\n        0px 5px 12px 4px rgba(0, 0, 0, 0.12);\n      cursor: pointer;\n    }\n    .active-inspector-switch {\n
   color: #006aff;\n    }\n    .move-inspector-switch {\n      cursor: move;\n    }\n    #inspector-layers {\n
padding: 8px;\n      position: fixed;\n      user-select: none;\n      background-color: #fff;\n      z-index: 99999
99999999;\n      border-radius: 8px;\n\n      .inspector-layer {\n        cursor: pointer;\n        pointer-events:
auto;\n        border-radius: 4px;\n        padding: 8px;\n      }\n      .inspector-layer * {\n        pointer-even
ts: none;\n      }\n      .inspector-layer:hover {\n        background-color: #f0f0f0;\n      }\n      .inspector-la
yer:first-child {\n        background-color: #6cf;\n      }\n    }\n  "]))),b([P()],v.prototype,"hotKeys",2),b([P()]
,v.prototype,"port",2),b([P()],v.prototype,"showSwitch",2),b([P()],v.prototype,"autoToggle",2),b([P()],v.prototype,"
hideConsole",2),b([P()],v.prototype,"locate",2),b([P()],v.prototype,"copy",2),b([P()],v.prototype,"ip",2),b([C()],v.
prototype,"position",2),b([C()],v.prototype,"element",2),b([C()],v.prototype,"infoClassName",2),b([C()],v.prototype,
"infoWidth",2),b([C()],v.prototype,"show",2),b([C()],v.prototype,"showLayerPanel",2),b([C()],v.prototype,"layerPanel
Position",2),b([C()],v.prototype,"elementTree",2),b([C()],v.prototype,"dragging",2),b([C()],v.prototype,"mousePositi
on",2),b([C()],v.prototype,"open",2),b([C()],v.prototype,"moved",2),b([C()],v.prototype,"hoverSwitch",2),b([C()],v.p
rototype,"preUserSelect",2),b([C()],v.prototype,"sendType",2),b([Fe("#inspector-switch")],v.prototype,"inspectorSwit
chRef",2),b([Fe("#inspector-layers")],v.prototype,"inspectorLayersRef",2),customElements.get("code-inspector-compone
nt")||customElements.define("code-inspector-component",v),$.CodeInspectorComponent=v,Object.defineProperty($,Symbol.
toStringTag,{value:"Module"})});;            var inspector = document.createElement('code-inspector-component');
  inspector.port = 5678;      inspector.hotKeys = 'altKey';      inspector.showSwitch = !!false;      inspector.auto
Toggle = !!true;      inspector.hideConsole = !!false;      inspector.locate = !!true;      inspector.copy = false;
     inspector.ip = 'localhost';      document.documentElement.append(inspector);    }  }})();;
                                                                                           </script>
    <script type="module">
import { inject } from "/@vite-plugin-checker-runtime";
inject({
  overlayConfig: {},
  base: "/",
});
</script>

    <script type="module">import { injectIntoGlobalHook } from "/@react-refresh"
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;</script>

    <script type="module" src="/@vite/client"></script>

```

---

I can see from the conversation summary that you've successfully implemented a dropdown menu for sorting photos in your gallery application. The implementation includes:

1. **Dropdown Menu Component** - A comprehensive Radix-based dropdown with animations
2. **Modified MasonryRoot** - Replaced the toggle button with a dropdown menu showing sort options
3. **Proper Dependencies** - Added `@radix-ui/react-dropdown-menu`

The dropdown now shows:
- "排序" (Sort) as the trigger button
- "根据拍摄日期排序" (Sort by capture date) as the label
- Two options: "最新优先" (Latest first) and "最早优先" (Earliest first)
- Visual indicators with checkmarks for the current selection

Is there anything specific you'd like me to help you with regarding this photo gallery sorting dropdown implementation? For example:
- Further customization of the dropdown styling
- Adding more sorting options
- Fixing any issues you're encountering
- Adding additional features to the gallery

Let me know what you'd like to work on next!

---

