diff options
| author | yxshv <[email protected]> | 2024-04-13 12:37:15 +0530 |
|---|---|---|
| committer | yxshv <[email protected]> | 2024-04-13 12:37:15 +0530 |
| commit | cd71d6b4f99c09eb4608eb59026bf884c7cc6acf (patch) | |
| tree | 2b97210b0dfa77d6346c32e9c086f9c583f20282 | |
| parent | new route /spaces (diff) | |
| download | supermemory-cd71d6b4f99c09eb4608eb59026bf884c7cc6acf.tar.xz supermemory-cd71d6b4f99c09eb4608eb59026bf884c7cc6acf.zip | |
fix dialog to add spaces
| -rw-r--r-- | apps/extension/package.json | 1 | ||||
| -rw-r--r-- | apps/extension/pnpm-lock.yaml | 135 | ||||
| -rw-r--r-- | apps/extension/src/SideBar.tsx | 55 | ||||
| -rw-r--r-- | apps/extension/src/background.ts | 35 | ||||
| -rw-r--r-- | apps/extension/src/components/FilterCombobox.tsx | 149 | ||||
| -rw-r--r-- | apps/extension/src/components/ui/dropdown-menu.tsx | 198 | ||||
| -rw-r--r-- | apps/web/src/app/api/spaces/route.ts | 9 | ||||
| -rw-r--r-- | apps/web/src/app/page.tsx | 5 | ||||
| -rw-r--r-- | apps/web/src/server/db/test.ts | 10 | ||||
| -rw-r--r-- | apps/web/types/memory.tsx | 7 |
10 files changed, 456 insertions, 148 deletions
diff --git a/apps/extension/package.json b/apps/extension/package.json index 4c12ef20..a7f34ea6 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7", "cmdk": "^1.0.0", diff --git a/apps/extension/pnpm-lock.yaml b/apps/extension/pnpm-lock.yaml index e61391eb..ad6c187d 100644 --- a/apps/extension/pnpm-lock.yaml +++ b/apps/extension/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: '@radix-ui/react-dialog': specifier: ^1.0.5 version: 1.0.5(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-dropdown-menu': + specifier: ^2.0.6 + version: 2.0.6(@types/[email protected])(@types/[email protected])([email protected])([email protected]) '@radix-ui/react-popover': specifier: ^1.0.7 version: 1.0.7(@types/[email protected])(@types/[email protected])([email protected])([email protected]) @@ -668,6 +671,30 @@ packages: react-dom: 18.2.0([email protected]) dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-context': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-primitive': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-slot': 1.0.2(@types/[email protected])([email protected]) + '@types/react': 18.2.75 + '@types/react-dom': 18.2.24 + react: 18.2.0 + react-dom: 18.2.0([email protected]) + dev: false + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -730,6 +757,20 @@ packages: react-remove-scroll: 2.5.5(@types/[email protected])([email protected]) dev: false + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@types/react': 18.2.75 + react: 18.2.0 + dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} peerDependencies: @@ -755,6 +796,33 @@ packages: react-dom: 18.2.0([email protected]) dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): + resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-context': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-id': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-menu': 2.0.6(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-primitive': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/[email protected])([email protected]) + '@types/react': 18.2.75 + '@types/react-dom': 18.2.24 + react: 18.2.0 + react-dom: 18.2.0([email protected]) + dev: false + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: @@ -807,6 +875,44 @@ packages: react: 18.2.0 dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): + resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-compose-refs': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-context': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-direction': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-focus-guards': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-focus-scope': 1.0.4(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-id': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-popper': 1.1.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-portal': 1.0.4(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-presence': 1.0.1(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-primitive': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-roving-focus': 1.0.4(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-slot': 1.0.2(@types/[email protected])([email protected]) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/[email protected])([email protected]) + '@types/react': 18.2.75 + '@types/react-dom': 18.2.24 + aria-hidden: 1.2.4 + react: 18.2.0 + react-dom: 18.2.0([email protected]) + react-remove-scroll: 2.5.5(@types/[email protected])([email protected]) + dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==} peerDependencies: @@ -936,6 +1042,35 @@ packages: react-dom: 18.2.0([email protected]) dev: false + /@radix-ui/[email protected](@types/[email protected])(@types/[email protected])([email protected])([email protected]): + resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-compose-refs': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-context': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-direction': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-id': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-primitive': 1.0.3(@types/[email protected])(@types/[email protected])([email protected])([email protected]) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/[email protected])([email protected]) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/[email protected])([email protected]) + '@types/react': 18.2.75 + '@types/react-dom': 18.2.24 + react: 18.2.0 + react-dom: 18.2.0([email protected]) + dev: false + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: diff --git a/apps/extension/src/SideBar.tsx b/apps/extension/src/SideBar.tsx index 890619ca..38b43a30 100644 --- a/apps/extension/src/SideBar.tsx +++ b/apps/extension/src/SideBar.tsx @@ -18,8 +18,9 @@ import { DialogFooter, DialogClose, } from "./components/ui/dialog"; +import { Space } from "./types/memory"; -function sendUrlToAPI() { +function sendUrlToAPI(spaces: number[]) { // get the current URL const url = window.location.href; @@ -46,11 +47,14 @@ function SideBar() { // } // }); + const [savedWebsites, setSavedWebsites] = useState<string[]>([]); const [isSendingData, setIsSendingData] = useState(false); - const [selectedSpaces, setSelectedSpaces] = useState<number[]>([0, 1]); + const [loading, setLoading] = useState(false) + const [spaces, setSpaces] = useState<Space[]>(); + const [selectedSpaces, setSelectedSpaces] = useState<number[]>([]); interface TweetData { tweetText: string; @@ -60,6 +64,15 @@ function SideBar() { time: string; } + const fetchSpaces = async () => { + setLoading(true) + chrome.runtime.sendMessage({ type: "fetchSpaces" }, (resp) => { + console.log(resp) + setSpaces(resp) + setLoading(false) + }); + } + const fetchBookmarks = () => { const tweets: TweetData[] = []; // Initialize an empty array to hold all tweet elements @@ -205,7 +218,7 @@ function SideBar() { ) : ( <></> )} - <Dialog> + <Dialog onOpenChange={open => open === true && fetchSpaces()}> <Tooltip delayDuration={300}> <TooltipTrigger className="anycontext-bg-transparent @@ -215,15 +228,7 @@ function SideBar() { <DialogTrigger asChild> <button onClick={() => { - sendUrlToAPI(); - setIsSendingData(true); - setTimeout(() => { - setIsSendingData(false); - setSavedWebsites([ - ...savedWebsites, - window.location.href, - ]); - }, 1000); + return; }} disabled={savedWebsites.includes(window.location.href)} className="anycontext-open-button disabled:anycontext-opacity-30 anycontext-bg-transparent @@ -276,23 +281,27 @@ function SideBar() { </DialogHeader> <FilterSpaces + loading={loading} className="anycontext-mr-auto" selectedSpaces={selectedSpaces} setSelectedSpaces={setSelectedSpaces} name={"Add to Spaces"} - spaces={[ - { - name: "cool tech", - id: 0, - }, - { - name: "cool libs", - id: 1, - }, - ]} + spaces={spaces ?? []} /> <DialogFooter className="anycontext-w-full anycontext-text-sm"> - <DialogClose>Add</DialogClose> + <DialogClose + onClick={() => { + sendUrlToAPI(selectedSpaces); + setIsSendingData(true); + setTimeout(() => { + setIsSendingData(false); + setSavedWebsites([ + ...savedWebsites, + window.location.href, + ]); + }, 1000); + }} + >Add</DialogClose> <DialogClose>Cancel</DialogClose> </DialogFooter> </DialogContent> diff --git a/apps/extension/src/background.ts b/apps/extension/src/background.ts index b3030e74..523a34e8 100644 --- a/apps/extension/src/background.ts +++ b/apps/extension/src/background.ts @@ -1,4 +1,5 @@ import { getEnv } from "./util"; +import { Space } from "./types/memory" const backendUrl = getEnv() === "development" @@ -37,8 +38,10 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { return true; } else if (request.type === "urlChange") { + const content = request.content; const url = request.url; + const spaces = request.spaces (async () => { chrome.storage.local.get(["jwt"], ({ jwt }) => { @@ -51,10 +54,40 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { headers: { Authorization: `Bearer ${jwt}`, }, - body: JSON.stringify({ pageContent: content, url }), + body: JSON.stringify({ pageContent: content, url, spaces }), }).then((ers) => console.log(ers.status)); }); })(); + } else if (request.type === "fetchSpaces") { + + const run = () => chrome.storage.local.get(["jwt"], async ({ jwt }) => { + if (!jwt) { + console.error("No JWT found"); + return; + } + const resp = await fetch(`${backendUrl}/api/spaces`, { + headers: { + Authorization: `Bearer ${jwt}`, + }, + }) + + const data: { + message: "OK" | string; + data: Space[] | undefined; + } = await resp.json(); + + if (data.message === "OK" && data.data) { + sendResponse(data.data) + } + + }); + + run() + + + return true; + + } else if (request.type === "queryApi") { const input = request.input; const jwt = request.jwt; diff --git a/apps/extension/src/components/FilterCombobox.tsx b/apps/extension/src/components/FilterCombobox.tsx index f6215c03..1ff49d38 100644 --- a/apps/extension/src/components/FilterCombobox.tsx +++ b/apps/extension/src/components/FilterCombobox.tsx @@ -1,152 +1,67 @@ import * as React from "react"; -import { Check, ChevronsUpDown, X } from "lucide-react"; - -import { cn } from "../lib/utils"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from "../components/ui/command"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "../components/ui/popover"; +import { PlusCircleIcon, X } from "lucide-react"; import { Space } from "../types/memory"; +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem } from "./ui/dropdown-menu"; +import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"; export interface Props extends React.ButtonHTMLAttributes<HTMLButtonElement> { - side?: "top" | "bottom"; - align?: "end" | "start" | "center"; - onClose?: () => void; selectedSpaces: number[]; setSelectedSpaces: ( spaces: number[] | ((prev: number[]) => number[]), ) => void; name: string; spaces: Space[]; + loading: boolean; } export function FilterSpaces({ - className, - side = "bottom", - align = "center", - onClose, + loading, selectedSpaces, setSelectedSpaces, - name, spaces, - ...props }: Props) { - const [open, setOpen] = React.useState(false); console.log(selectedSpaces, spaces); - const sortedSpaces = spaces.sort(({ id: a }, { id: b }) => - selectedSpaces.includes(a) && !selectedSpaces.includes(b) - ? -1 - : selectedSpaces.includes(b) && !selectedSpaces.includes(a) - ? 1 - : 0, - ); + const filteredSpaces = spaces.filter(space => selectedSpaces.includes(space.id)) + const leftSpaces = spaces.filter(space => !selectedSpaces.includes(space.id)) - React.useEffect(() => { - if (!open) { - onClose?.(); - } - }, [open]); + if (loading) { + return "Loading..." + } return ( <div className="anycontext-flex anycontext-flex-wrap anycontext-gap-1 anycontext-text-sm anycontext-"> - {selectedSpaces.map((spaceid) => { - const space = spaces.find((s) => s.id === spaceid)!; - return <SpaceItem {...space} key={spaceid} onRemove={() => {}} />; - })} + {filteredSpaces.length < 1 && "Add to a space"} + {filteredSpaces.map((space) => ( + <SpaceItem {...space} key={space.id} onRemove={() => setSelectedSpaces(prev => prev.filter(s => s !== space.id))} /> + ))} + {leftSpaces.length > 0 && ( + <DropdownMenu> + <DropdownMenuTrigger className="anycontext-rounded-full"> + <PlusCircleIcon className="anycontext-w-5 anycontext-h-5 [--anycontext-icon-stroke:white] dark:[--anycontext-icon-stroke:black]" stroke='var(--anycontext-icon-stroke)' fill='currentColor' /> + </DropdownMenuTrigger> + <DropdownMenuContent> + {leftSpaces.map(space => ( + <> + {loading && "Loading..."} + <DropdownMenuItem onClick={() => setSelectedSpaces(prev => [...prev, space.id])}> + {space.name} + </DropdownMenuItem> + </> + ))} + </DropdownMenuContent> + </DropdownMenu> + )} </div> ); - return ( - <Popover open={open} onOpenChange={setOpen}> - <PopoverTrigger asChild> - <button - type={undefined} - data-state-on={open} - className={cn( - "anycontext-combobox-button anycontext-w-fit", - className, - )} - {...props} - > - {name} - <ChevronsUpDown className="anycontext-h-4 anycontext-w-4" /> - <div - data-state-on={selectedSpaces.length > 0} - className="on:anycontext-flex anycontext-text-rgray-11 anycontext-border-rgray-6 anycontext-bg-rgray-2 anycontext-absolute anycontext-left-0 anycontext-top-0 anycontext-hidden anycontext-aspect-[1] anycontext-h-4 anycontext-w-4 anycontext--translate-x-1/3 anycontext--translate-y-1/3 anycontext-items-center anycontext-justify-center anycontext-rounded-full anycontext-border anycontext-text-center anycontext-text-[9px]" - > - {selectedSpaces.length} - </div> - </button> - </PopoverTrigger> - <PopoverContent - onCloseAutoFocus={(e) => e.preventDefault()} - align={align} - side={side} - className="anycontext-w-[200px] anycontext-p-0" - > - <Command - filter={(val, search) => - spaces - .find((s) => s.id.toString() === val) - ?.name.toLowerCase() - .includes(search.toLowerCase().trim()) - ? 1 - : 0 - } - > - <CommandInput placeholder="Filter spaces..." /> - <CommandList asChild> - <div> - <CommandEmpty>Nothing found</CommandEmpty> - <CommandGroup> - {sortedSpaces.map((space) => ( - <CommandItem - key={space.id} - value={space.id.toString()} - onSelect={(val) => { - setSelectedSpaces((prev: number[]) => - prev.includes(parseInt(val)) - ? prev.filter((v) => v !== parseInt(val)) - : [...prev, parseInt(val)], - ); - }} - asChild - > - <div className="anycontext-text-black/90 dark:anycontext-text-white/90"> - {space.name} - <Check - data-state-on={selectedSpaces.includes(space.id)} - className={cn( - "on:anycontext-opacity-100 anycontext-ml-auto anycontext-h-4 anycontext-w-4 anycontext-opacity-0", - )} - /> - </div> - </CommandItem> - ))} - </CommandGroup> - </div> - </CommandList> - </Command> - </PopoverContent> - </Popover> - ); } function SpaceItem({ name, onRemove }: { onRemove: () => void } & Space) { return ( <div className="anycontext-flex anycontext-justify-center anycontext-items-center anycontext-gap-2 anycontext-p-1 anycontext-pl-2 anycontext-pr-3 anycontext-rounded-full anycontext-bg-black/5 dark:anycontext-bg-white/5 anycontext-border-white/20 dark:anycontext-border-black/20 border"> - <button className="anycontext-flex hover:anycontext-bg-transparent anycontext-justify-center anycontext-scale-110 anycontext-items-center focus-visible:anycontext-outline-none anycontext-rounded-full anycontext-w-3 anycontext-bg-black/5 dark:anycontext-bg-white/5 anycontext-h-3 anycontext-text-transparent hover:anycontext-text-black dark:hover:anycontext-text-white"> + <button onClick={onRemove} className="anycontext-flex hover:anycontext-bg-transparent anycontext-justify-center anycontext-scale-110 anycontext-items-center focus-visible:anycontext-outline-none anycontext-rounded-full anycontext-w-3 anycontext-bg-black/5 dark:anycontext-bg-white/5 anycontext-h-3 anycontext-text-transparent hover:anycontext-text-black dark:hover:anycontext-text-white"> <X className="anycontext-w-3 anycontext-h-3" /> </button> {name} diff --git a/apps/extension/src/components/ui/dropdown-menu.tsx b/apps/extension/src/components/ui/dropdown-menu.tsx new file mode 100644 index 00000000..2e9a95b8 --- /dev/null +++ b/apps/extension/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,198 @@ +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "../../lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + <DropdownMenuPrimitive.SubTrigger + ref={ref} + className={cn( + "anycontext-flex anycontext-cursor-default anycontext-select-none anycontext-items-center anycontext-rounded-sm anycontext-px-2 anycontext-py-1.5 anycontext-text-sm anycontext-outline-none focus:anycontext-bg-stone-100 data-[state=open]:anycontext-bg-stone-100 dark:focus:anycontext-bg-stone-800 dark:data-[state=open]:anycontext-bg-stone-800", + inset && "anycontext-pl-8", + className + )} + {...props} + > + {children} + <ChevronRight className="anycontext-ml-auto anycontext-h-4 anycontext-w-4" /> + </DropdownMenuPrimitive.SubTrigger> +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> +>(({ className, ...props }, ref) => ( + <DropdownMenuPrimitive.SubContent + ref={ref} + className={cn( + "anycontext-z-50 anycontext-min-w-[8rem] anycontext-overflow-hidden anycontext-rounded-md anycontext-border anycontext-border-stone-200 anycontext-bg-white anycontext-p-1 anycontext-text-stone-950 anycontext-shadow-lg data-[state=open]:anycontext-animate-in data-[state=closed]:anycontext-animate-out data-[state=closed]:anycontext-fade-out-0 data-[state=open]:anycontext-fade-in-0 data-[state=closed]:anycontext-zoom-out-95 data-[state=open]:anycontext-zoom-in-95 data-[side=bottom]:anycontext-slide-in-from-top-2 data-[side=left]:anycontext-slide-in-from-right-2 data-[side=right]:anycontext-slide-in-from-left-2 data-[side=top]:anycontext-slide-in-from-bottom-2 dark:anycontext-border-stone-800 dark:anycontext-bg-stone-950 dark:anycontext-text-stone-50", + className + )} + {...props} + /> +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.Content>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> +>(({ className, sideOffset = 4, ...props }, ref) => ( + <DropdownMenuPrimitive.Portal> + <DropdownMenuPrimitive.Content + ref={ref} + sideOffset={sideOffset} + className={cn( + "anycontext-z-50 anycontext-min-w-[8rem] anycontext-overflow-hidden anycontext-rounded-md anycontext-border anycontext-border-stone-200 anycontext-bg-white anycontext-p-1 anycontext-text-stone-950 anycontext-shadow-md data-[state=open]:anycontext-animate-in data-[state=closed]:anycontext-animate-out data-[state=closed]:anycontext-fade-out-0 data-[state=open]:anycontext-fade-in-0 data-[state=closed]:anycontext-zoom-out-95 data-[state=open]:anycontext-zoom-in-95 data-[side=bottom]:anycontext-slide-in-from-top-2 data-[side=left]:anycontext-slide-in-from-right-2 data-[side=right]:anycontext-slide-in-from-left-2 data-[side=top]:anycontext-slide-in-from-bottom-2 dark:anycontext-border-stone-800 dark:anycontext-bg-stone-950 dark:anycontext-text-stone-50", + className + )} + {...props} + /> + </DropdownMenuPrimitive.Portal> +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.Item>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + <DropdownMenuPrimitive.Item + ref={ref} + className={cn( + "anycontext-relative anycontext-flex anycontext-cursor-default anycontext-select-none anycontext-items-center anycontext-rounded-sm anycontext-px-2 anycontext-py-1.5 anycontext-text-sm anycontext-outline-none anycontext-transition-colors focus:anycontext-bg-stone-100 focus:anycontext-text-stone-900 data-[disabled]:anycontext-pointer-events-none data-[disabled]:anycontext-opacity-50 dark:focus:anycontext-bg-stone-800 dark:focus:anycontext-text-stone-50", + inset && "anycontext-pl-8", + className + )} + {...props} + /> +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> +>(({ className, children, checked, ...props }, ref) => ( + <DropdownMenuPrimitive.CheckboxItem + ref={ref} + className={cn( + "anycontext-relative anycontext-flex anycontext-cursor-default anycontext-select-none anycontext-items-center anycontext-rounded-sm anycontext-py-1.5 anycontext-pl-8 anycontext-pr-2 anycontext-text-sm anycontext-outline-none anycontext-transition-colors focus:anycontext-bg-stone-100 focus:anycontext-text-stone-900 data-[disabled]:anycontext-pointer-events-none data-[disabled]:anycontext-opacity-50 dark:focus:anycontext-bg-stone-800 dark:focus:anycontext-text-stone-50", + className + )} + checked={checked} + {...props} + > + <span className="anycontext-absolute anycontext-left-2 anycontext-flex anycontext-h-3.5 anycontext-w-3.5 anycontext-items-center anycontext-justify-center"> + <DropdownMenuPrimitive.ItemIndicator> + <Check className="anycontext-h-4 anycontext-w-4" /> + </DropdownMenuPrimitive.ItemIndicator> + </span> + {children} + </DropdownMenuPrimitive.CheckboxItem> +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> +>(({ className, children, ...props }, ref) => ( + <DropdownMenuPrimitive.RadioItem + ref={ref} + className={cn( + "anycontext-relative anycontext-flex anycontext-cursor-default anycontext-select-none anycontext-items-center anycontext-rounded-sm anycontext-py-1.5 anycontext-pl-8 anycontext-pr-2 anycontext-text-sm anycontext-outline-none anycontext-transition-colors focus:anycontext-bg-stone-100 focus:anycontext-text-stone-900 data-[disabled]:anycontext-pointer-events-none data-[disabled]:anycontext-opacity-50 dark:focus:anycontext-bg-stone-800 dark:focus:anycontext-text-stone-50", + className + )} + {...props} + > + <span className="anycontext-absolute anycontext-left-2 anycontext-flex anycontext-h-3.5 anycontext-w-3.5 anycontext-items-center anycontext-justify-center"> + <DropdownMenuPrimitive.ItemIndicator> + <Circle className="anycontext-h-2 anycontext-w-2 anycontext-fill-current" /> + </DropdownMenuPrimitive.ItemIndicator> + </span> + {children} + </DropdownMenuPrimitive.RadioItem> +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.Label>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + <DropdownMenuPrimitive.Label + ref={ref} + className={cn( + "anycontext-px-2 anycontext-py-1.5 anycontext-text-sm anycontext-font-semibold", + inset && "anycontext-pl-8", + className + )} + {...props} + /> +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef<typeof DropdownMenuPrimitive.Separator>, + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> +>(({ className, ...props }, ref) => ( + <DropdownMenuPrimitive.Separator + ref={ref} + className={cn("anycontext--mx-1 anycontext-my-1 anycontext-h-px anycontext-bg-stone-100 dark:anycontext-bg-stone-800", className)} + {...props} + /> +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes<HTMLSpanElement>) => { + return ( + <span + className={cn("anycontext-ml-auto anycontext-text-xs anycontext-tracking-widest anycontext-opacity-60", className)} + {...props} + /> + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/apps/web/src/app/api/spaces/route.ts b/apps/web/src/app/api/spaces/route.ts index 1e1aeba7..d6cc096b 100644 --- a/apps/web/src/app/api/spaces/route.ts +++ b/apps/web/src/app/api/spaces/route.ts @@ -3,6 +3,8 @@ import { sessions, space, users } from "@/server/db/schema"; import { eq } from "drizzle-orm"; import { NextRequest, NextResponse } from "next/server"; +export const runtime = "edge" + export async function GET(req: NextRequest) { const token = @@ -33,6 +35,7 @@ export async function GET(req: NextRequest) { .from(sessions) .where(eq(sessions.sessionToken, token!)); + if (!sessionData || sessionData.length === 0) { return new Response( JSON.stringify({ message: "Invalid Key, session not found." }), @@ -55,12 +58,14 @@ export async function GET(req: NextRequest) { const user = userData[0] - const spaces = await db .select() .from(space) .where(eq(space.user, user.id)) - .all() + .all(); + + + console.log('data', spaces) return NextResponse.json({ message: "OK", diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 419daa5a..1cbe6217 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -56,7 +56,10 @@ export default async function Home() { const collectedSpaces = await db .select() .from(space) - .where(and(eq(space.user, userData.id), not(eq(space.name, "none")))); + .where(eq(space.user, userData.id)) + .all(); + + console.log(collectedSpaces) // Fetch only first 3 content of each spaces let contents: (typeof storedContent.$inferSelect)[] = []; diff --git a/apps/web/src/server/db/test.ts b/apps/web/src/server/db/test.ts new file mode 100644 index 00000000..9cb8f2b5 --- /dev/null +++ b/apps/web/src/server/db/test.ts @@ -0,0 +1,10 @@ +import { db } from "." +import { space, user } from "./schema" + +const user = await db.select(user).all() + +await db.insert(space).values([ + { + + } +]) diff --git a/apps/web/types/memory.tsx b/apps/web/types/memory.tsx index ff0dc94c..287f763c 100644 --- a/apps/web/types/memory.tsx +++ b/apps/web/types/memory.tsx @@ -5,7 +5,7 @@ import { storedContent, StoredContent, } from "@/server/db/schema"; -import { asc, and, eq, inArray, notExists } from "drizzle-orm"; +import { asc, and, eq, inArray, notExists, sql, exists } from "drizzle-orm"; export async function fetchContentForSpace( spaceId: number, @@ -19,9 +19,8 @@ export async function fetchContentForSpace( .select() .from(storedContent) .where( - inArray( - storedContent.id, - db.select().from(space).where(eq(space.id, spaceId)), + exists( + db.select().from(contentToSpace).where(and(eq(contentToSpace.spaceId, spaceId), eq(contentToSpace.contentId, storedContent.id))), ), ).orderBy(asc(storedContent.title)) |