forked from
pds.ls/pdsls
this repo has no description
1import { A } from "@solidjs/router";
2import {
3 Accessor,
4 createContext,
5 createSignal,
6 JSX,
7 onCleanup,
8 onMount,
9 Setter,
10 Show,
11 useContext,
12} from "solid-js";
13import { addToClipboard } from "../utils/copy";
14
15const MenuContext = createContext<{
16 showMenu: Accessor<boolean>;
17 setShowMenu: Setter<boolean>;
18}>();
19
20export const MenuProvider = (props: { children?: JSX.Element }) => {
21 const [showMenu, setShowMenu] = createSignal(false);
22 const value = { showMenu, setShowMenu };
23
24 return <MenuContext.Provider value={value}>{props.children}</MenuContext.Provider>;
25};
26
27export const CopyMenu = (props: { copyContent: string; label: string; icon?: string }) => {
28 const ctx = useContext(MenuContext);
29
30 return (
31 <button
32 onClick={() => {
33 addToClipboard(props.copyContent);
34 ctx?.setShowMenu(false);
35 }}
36 class="flex items-center gap-1.5 rounded-lg p-1 whitespace-nowrap hover:bg-neutral-200/50 active:bg-neutral-200/50 dark:hover:bg-neutral-700 dark:active:bg-neutral-700"
37 >
38 <Show when={props.icon}>
39 <span class={"iconify shrink-0 " + props.icon}></span>
40 </Show>
41 <span class="whitespace-nowrap">{props.label}</span>
42 </button>
43 );
44};
45
46export const NavMenu = (props: { href: string; label: string; icon: string; newTab?: boolean }) => {
47 const ctx = useContext(MenuContext);
48
49 return (
50 <A
51 href={props.href}
52 onClick={() => ctx?.setShowMenu(false)}
53 class="flex items-center gap-1.5 rounded-lg p-1 hover:bg-neutral-200/50 active:bg-neutral-200/50 dark:hover:bg-neutral-700 dark:active:bg-neutral-700"
54 target={props.newTab ? "_blank" : undefined}
55 >
56 <span class={"iconify shrink-0 " + props.icon}></span>
57 <span class="whitespace-nowrap">{props.label}</span>
58 </A>
59 );
60};
61
62export const DropdownMenu = (props: {
63 icon: string;
64 buttonClass?: string;
65 menuClass?: string;
66 children?: JSX.Element;
67}) => {
68 const ctx = useContext(MenuContext);
69 const [menu, setMenu] = createSignal<HTMLDivElement>();
70 const [menuButton, setMenuButton] = createSignal<HTMLButtonElement>();
71
72 const clickEvent = (event: MouseEvent) => {
73 const target = event.target as Node;
74 if (!menuButton()?.contains(target) && !menu()?.contains(target)) ctx?.setShowMenu(false);
75 };
76
77 onMount(() => window.addEventListener("click", clickEvent));
78 onCleanup(() => window.removeEventListener("click", clickEvent));
79
80 return (
81 <div class="relative">
82 <button
83 class={
84 "flex items-center hover:bg-neutral-200 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-700 " +
85 props.buttonClass
86 }
87 ref={setMenuButton}
88 onClick={() => ctx?.setShowMenu(!ctx?.showMenu())}
89 >
90 <span class={"iconify " + props.icon}></span>
91 </button>
92 <Show when={ctx?.showMenu()}>
93 <div
94 ref={setMenu}
95 class={
96 "dark:bg-dark-300 dark:shadow-dark-800 absolute right-0 z-20 flex flex-col rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 shadow-md dark:border-neutral-700 " +
97 props.menuClass
98 }
99 >
100 {props.children}
101 </div>
102 </Show>
103 </div>
104 );
105};