diff options
| author | MohamedBassem <me@mbassem.com> | 2024-02-07 22:12:18 +0000 |
|---|---|---|
| committer | MohamedBassem <me@mbassem.com> | 2024-02-07 22:12:18 +0000 |
| commit | cdc05f85a6dc676e8af1227a56f65d6452488d82 (patch) | |
| tree | b3d1e133d5435e129637067749d0b7e6e55b6c01 | |
| parent | 8970b3a5375ccfd9b41c8a08722a2fc6bbbe3af9 (diff) | |
| download | karakeep-cdc05f85a6dc676e8af1227a56f65d6452488d82.tar.zst | |
[feature] Render tags in the link card
| -rw-r--r-- | web/app/bookmarks/components/LinkCard.tsx | 9 | ||||
| -rw-r--r-- | web/app/bookmarks/page.tsx | 5 | ||||
| -rw-r--r-- | web/app/layout.tsx | 4 | ||||
| -rw-r--r-- | web/components/ui/badge.tsx | 36 | ||||
| -rw-r--r-- | web/lib/api.ts | 12 | ||||
| -rw-r--r-- | web/lib/services/links.ts | 65 | ||||
| -rw-r--r-- | web/lib/types/api/links.ts | 2 | ||||
| -rw-r--r-- | web/lib/types/api/tags.ts | 6 |
8 files changed, 106 insertions, 33 deletions
diff --git a/web/app/bookmarks/components/LinkCard.tsx b/web/app/bookmarks/components/LinkCard.tsx index 907acd19..da59d9da 100644 --- a/web/app/bookmarks/components/LinkCard.tsx +++ b/web/app/bookmarks/components/LinkCard.tsx @@ -1,5 +1,6 @@ "use client"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -73,7 +74,13 @@ export default function LinkCard({ link }: { link: ZBookmarkedLink }) { {link.details?.title ?? parsedUrl.host} </Link> </ImageCardTitle> - <ImageCardBody /> + <ImageCardBody className="py-2 overflow-clip"> + {link.tags.map((t) => ( + <Badge variant="default" className="bg-gray-300 text-gray-500" key={t.id}> + #{t.name} + </Badge> + ))} + </ImageCardBody> <ImageCardFooter> <div className="flex justify-between text-gray-500"> <div className="my-auto"> diff --git a/web/app/bookmarks/page.tsx b/web/app/bookmarks/page.tsx index f0efa2e4..89a26122 100644 --- a/web/app/bookmarks/page.tsx +++ b/web/app/bookmarks/page.tsx @@ -1,5 +1,10 @@ import AddLink from "./components/AddLink"; import LinksGrid from "./components/LinksGrid"; +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Remember - Bookmarks", +}; export default async function Bookmarks() { return ( diff --git a/web/app/layout.tsx b/web/app/layout.tsx index a6543b1c..a2d34046 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -7,8 +7,8 @@ import { Toaster } from "@/components/ui/toaster"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Remember", + description: "Your AI powered second brain", }; export default function RootLayout({ diff --git a/web/components/ui/badge.tsx b/web/components/ui/badge.tsx new file mode 100644 index 00000000..d3d5d604 --- /dev/null +++ b/web/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +export interface BadgeProps + extends React.HTMLAttributes<HTMLDivElement>, + VariantProps<typeof badgeVariants> {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( + <div className={cn(badgeVariants({ variant }), className)} {...props} /> + ); +} + +export { Badge, badgeVariants }; diff --git a/web/lib/api.ts b/web/lib/api.ts index 2304826b..56686cde 100644 --- a/web/lib/api.ts +++ b/web/lib/api.ts @@ -15,18 +15,6 @@ export type FetchError = { message?: string; }; -async function doRequest<Schema extends ZodTypeAny>( - _path: string, - respSchema: Schema, - _opts: RequestInit | undefined, -): Promise<[z.infer<typeof respSchema>, undefined] | [undefined, FetchError]>; - -async function doRequest<_Schema>( - _path: string, - _respSchema: undefined, - _opts: RequestInit | undefined, -): Promise<[undefined, undefined] | [undefined, FetchError]>; - type InputSchema<T> = T extends ZodTypeAny ? T : undefined; async function doRequest<T>( diff --git a/web/lib/services/links.ts b/web/lib/services/links.ts index dbcbe9c4..d273b118 100644 --- a/web/lib/services/links.ts +++ b/web/lib/services/links.ts @@ -1,5 +1,43 @@ import { LinkCrawlerQueue } from "@remember/shared/queues"; import prisma from "@remember/db"; +import { ZBookmarkedLink } from "@/lib/types/api/links"; + +const defaultLinkFields = { + id: true, + url: true, + createdAt: true, + details: { + select: { + title: true, + description: true, + imageUrl: true, + favicon: true, + }, + }, + tags: { + include: { + tag: true, + }, + }, +}; + +async function dummyPrismaReturnType() { + return await prisma.bookmarkedLink.findFirstOrThrow({ + select: defaultLinkFields, + }); +} + +function toZodSchema( + link: Awaited<ReturnType<typeof dummyPrismaReturnType>>, +): ZBookmarkedLink { + return { + id: link.id, + url: link.url, + createdAt: link.createdAt, + details: link.details, + tags: link.tags.map((t) => t.tag), + }; +} export async function unbookmarkLink(linkId: string, userId: string) { await prisma.bookmarkedLink.delete({ @@ -16,6 +54,7 @@ export async function bookmarkLink(url: string, userId: string) { url, userId, }, + select: defaultLinkFields, }); // Enqueue crawling request @@ -24,26 +63,16 @@ export async function bookmarkLink(url: string, userId: string) { url: link.url, }); - return link; + return toZodSchema(link); } export async function getLinks(userId: string) { - return await prisma.bookmarkedLink.findMany({ - where: { - userId, - }, - select: { - id: true, - url: true, - createdAt: true, - details: { - select: { - title: true, - description: true, - imageUrl: true, - favicon: true, - }, + return ( + await prisma.bookmarkedLink.findMany({ + where: { + userId, }, - }, - }); + select: defaultLinkFields, + }) + ).map(toZodSchema); } diff --git a/web/lib/types/api/links.ts b/web/lib/types/api/links.ts index 644589b4..f84445f6 100644 --- a/web/lib/types/api/links.ts +++ b/web/lib/types/api/links.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { zBookmarkTagSchema } from "@/lib/types/api/tags"; export const zBookmarkedLinkSchema = z.object({ id: z.string(), @@ -13,6 +14,7 @@ export const zBookmarkedLinkSchema = z.object({ favicon: z.string().url().nullish(), }) .nullish(), + tags: z.array(zBookmarkTagSchema), }); export type ZBookmarkedLink = z.infer<typeof zBookmarkedLinkSchema>; diff --git a/web/lib/types/api/tags.ts b/web/lib/types/api/tags.ts new file mode 100644 index 00000000..f2d2bc18 --- /dev/null +++ b/web/lib/types/api/tags.ts @@ -0,0 +1,6 @@ +import { z } from "zod"; + +export const zBookmarkTagSchema = z.object({ + id: z.string(), + name: z.string(), +}); |
