a tool for shared writing and social publishing
1"use client";
2import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
3import { theme } from "tailwind.config";
4import { NestedCardThemeProvider } from "./ThemeManager/ThemeProvider";
5import { PopoverArrow } from "./Icons/PopoverArrow";
6import { PopoverOpenContext } from "./Popover/PopoverContext";
7import { useState } from "react";
8
9export const Menu = (props: {
10 open?: boolean;
11 trigger: React.ReactNode;
12 children: React.ReactNode;
13 align?: "start" | "end" | "center" | undefined;
14 alignOffset?: number;
15 side?: "top" | "bottom" | "right" | "left" | undefined;
16 background?: string;
17 border?: string;
18 className?: string;
19 onOpenChange?: (o: boolean) => void;
20 asChild?: boolean;
21}) => {
22 let [open, setOpen] = useState(props.open || false);
23
24 return (
25 <DropdownMenu.Root
26 onOpenChange={(o) => {
27 setOpen(o);
28 props.onOpenChange?.(o);
29 }}
30 open={props.open}
31 >
32 <PopoverOpenContext value={open}>
33 <DropdownMenu.Trigger asChild={props.asChild}>
34 {props.trigger}
35 </DropdownMenu.Trigger>
36 <DropdownMenu.Portal>
37 <NestedCardThemeProvider>
38 <DropdownMenu.Content
39 side={props.side ? props.side : "bottom"}
40 align={props.align ? props.align : "center"}
41 alignOffset={props.alignOffset ? props.alignOffset : undefined}
42 sideOffset={4}
43 collisionPadding={16}
44 className={`
45 dropdownMenu z-20 p-1
46 flex flex-col gap-0.5
47 bg-bg-page
48 border border-border rounded-md shadow-md
49 ${props.className}`}
50 >
51 {props.children}
52 <DropdownMenu.Arrow
53 asChild
54 width={16}
55 height={8}
56 viewBox="0 0 16 8"
57 >
58 <PopoverArrow
59 arrowFill={
60 props.background
61 ? props.background
62 : theme.colors["bg-page"]
63 }
64 arrowStroke={
65 props.border ? props.border : theme.colors["border"]
66 }
67 />
68 </DropdownMenu.Arrow>
69 </DropdownMenu.Content>
70 </NestedCardThemeProvider>
71 </DropdownMenu.Portal>
72 </PopoverOpenContext>
73 </DropdownMenu.Root>
74 );
75};
76
77export const MenuItem = (props: {
78 children?: React.ReactNode;
79 className?: string;
80 onSelect: (e: Event) => void;
81 id?: string;
82}) => {
83 return (
84 <DropdownMenu.Item
85 id={props.id}
86 onSelect={(event) => {
87 props.onSelect(event);
88 }}
89 className={`
90 menuItem
91 ${props.className}
92 `}
93 >
94 {props.children}
95 </DropdownMenu.Item>
96 );
97};