your personal website on atproto - mirror blento.app
at fix-cached-posts 87 lines 2.2 kB view raw
1<script lang="ts"> 2 import { cn } from '@foxui/core'; 3 import type { Editor, Range } from '@tiptap/core'; 4 import Icon from '../Icon.svelte'; 5 import type { RichTextTypes } from '..'; 6 7 type Props = { 8 items: { 9 value: RichTextTypes; 10 label: string; 11 command: ({ editor, range }: { editor: Editor; range: Range }) => void; 12 }[]; 13 range: Range; 14 editor: Editor; 15 active?: number; 16 }; 17 18 let { items, range, editor, active = 0 }: Props = $props(); 19 20 let activeIndex = $state(0); 21 22 export function setItems(value: any[]) { 23 items = value; 24 } 25 26 export function setRange(value: Range) { 27 range = value; 28 } 29 30 export function onKeyDown(event: KeyboardEvent) { 31 if (event.repeat) { 32 return false; 33 } 34 switch (event.key) { 35 case 'ArrowUp': { 36 if (activeIndex <= 0) { 37 activeIndex = items.length - 1; 38 } else { 39 activeIndex--; 40 } 41 return true; 42 } 43 case 'ArrowDown': { 44 if (activeIndex >= items.length - 1) { 45 activeIndex = 0; 46 } else { 47 activeIndex++; 48 } 49 return true; 50 } 51 case 'Enter': { 52 const selected = items[activeIndex]; 53 54 if (selected) { 55 selected.command({ editor, range }); 56 return true; 57 } 58 } 59 } 60 61 return false; 62 } 63</script> 64 65<menu 66 class={cn( 67 'bg-base-50/50 border-base-500/20 overflow-hidden rounded-2xl border shadow-lg backdrop-blur-xl', 68 'dark:bg-base-900/50 dark:border-base-500/10', 69 'motion-safe:animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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', 70 'divide-base-300/30 dark:divide-base-800 divide-y text-sm' 71 )} 72> 73 {#each items as item, index (item.value)} 74 <button 75 onclick={() => item.command({ editor, range })} 76 class={cn( 77 'text-base-900 dark:text-base-200 group relative isolate flex w-full min-w-28 cursor-pointer items-center gap-3 px-3 py-2 font-medium [&_svg]:size-3.5', 78 activeIndex === index 79 ? 'text-accent-700 dark:text-accent-400 bg-accent-500/10' 80 : 'hover:bg-accent-500/10' 81 )} 82 > 83 <Icon name={item.value} /> 84 {item.label} 85 </button> 86 {/each} 87</menu>