aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-02-15 16:03:24 +0000
committerMohamedBassem <me@mbassem.com>2024-02-15 16:03:24 +0000
commit97d18d7ac3bc6ab4f40618e74f021ee63a4cf7b6 (patch)
tree1baa3a602da8c2a67b6c4807dcc27c329a2351c4 /packages
parent25d399c1abbccc28a899ef43a3c945a86f680af9 (diff)
downloadkarakeep-97d18d7ac3bc6ab4f40618e74f021ee63a4cf7b6.tar.zst
ui: Usage images for link cards
Diffstat (limited to 'packages')
-rw-r--r--packages/web/app/dashboard/bookmarks/components/LinkCard.tsx68
-rw-r--r--packages/web/app/dashboard/error.tsx10
-rw-r--r--packages/web/app/dashboard/not-found.tsx10
-rw-r--r--packages/web/components/ui/imageCard.tsx46
4 files changed, 83 insertions, 51 deletions
diff --git a/packages/web/app/dashboard/bookmarks/components/LinkCard.tsx b/packages/web/app/dashboard/bookmarks/components/LinkCard.tsx
index 00e4ef26..7413c2fe 100644
--- a/packages/web/app/dashboard/bookmarks/components/LinkCard.tsx
+++ b/packages/web/app/dashboard/bookmarks/components/LinkCard.tsx
@@ -1,7 +1,9 @@
import { Badge } from "@/components/ui/badge";
import {
ImageCard,
+ ImageCardBanner,
ImageCardBody,
+ ImageCardContent,
ImageCardFooter,
ImageCardTitle,
} from "@/components/ui/imageCard";
@@ -13,40 +15,56 @@ export default function LinkCard({ bookmark }: { bookmark: ZBookmark }) {
const link = bookmark.content;
const parsedUrl = new URL(link.url);
+ // A dummy white pixel for when there's no image.
+ // TODO: Better handling for cards with no images
+ const image =
+ link.imageUrl ??
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P///38ACfsD/QVDRcoAAAAASUVORK5CYII=";
+
return (
<ImageCard
className={
"border-grey-100 border bg-gray-50 duration-300 ease-in hover:border-blue-300 hover:transition-all"
}
- image={link?.imageUrl ?? undefined}
>
- <ImageCardTitle>
- <Link className="line-clamp-2" href={link.url}>
- {link?.title ?? parsedUrl.host}
- </Link>
- </ImageCardTitle>
- <ImageCardBody className="overflow-clip py-2">
- {bookmark.tags.map((t) => (
- <Link key={t.id} href={`/dashboard/tags/${t.name}`}>
- <Badge
- variant="default"
- className="bg-gray-300 text-gray-500 hover:text-white"
- >
- #{t.name}
- </Badge>
+ <Link href={link.url}>
+ <ImageCardBanner src={image} />
+ </Link>
+ <ImageCardContent>
+ <ImageCardTitle>
+ <Link className="line-clamp-2" href={link.url}>
+ {link?.title ?? parsedUrl.host}
</Link>
- ))}
- </ImageCardBody>
- <ImageCardFooter>
- <div className="flex justify-between text-gray-500">
- <div className="my-auto">
- <Link className="line-clamp-1 hover:text-black" href={link.url}>
- {parsedUrl.host}
+ </ImageCardTitle>
+ {/* There's a hack here. Every tag has the full hight of the container itself. That why, when we enable flex-wrap,
+ the overflowed don't show up. */}
+ <ImageCardBody className="flex h-full flex-wrap space-x-1 overflow-hidden">
+ {bookmark.tags.map((t) => (
+ <Link
+ className="flex h-full flex-col justify-end"
+ key={t.id}
+ href={`/dashboard/tags/${t.name}`}
+ >
+ <Badge
+ variant="default"
+ className="text-nowrap bg-gray-300 text-gray-500 hover:text-white"
+ >
+ #{t.name}
+ </Badge>
</Link>
+ ))}
+ </ImageCardBody>
+ <ImageCardFooter>
+ <div className="flex justify-between text-gray-500">
+ <div className="my-auto">
+ <Link className="line-clamp-1 hover:text-black" href={link.url}>
+ {parsedUrl.host}
+ </Link>
+ </div>
+ <BookmarkOptions bookmark={bookmark} />
</div>
- <BookmarkOptions bookmark={bookmark} />
- </div>
- </ImageCardFooter>
+ </ImageCardFooter>
+ </ImageCardContent>
</ImageCard>
);
}
diff --git a/packages/web/app/dashboard/error.tsx b/packages/web/app/dashboard/error.tsx
index 2bba0e98..556e59a3 100644
--- a/packages/web/app/dashboard/error.tsx
+++ b/packages/web/app/dashboard/error.tsx
@@ -1,9 +1,9 @@
"use client";
export default function Error() {
- return (
- <div className="flex size-full">
- <div className="m-auto text-3xl">Something went wrong</div>
- </div>
- );
+ return (
+ <div className="flex size-full">
+ <div className="m-auto text-3xl">Something went wrong</div>
+ </div>
+ );
}
diff --git a/packages/web/app/dashboard/not-found.tsx b/packages/web/app/dashboard/not-found.tsx
index abd1ebae..64df220c 100644
--- a/packages/web/app/dashboard/not-found.tsx
+++ b/packages/web/app/dashboard/not-found.tsx
@@ -1,7 +1,7 @@
export default function NotFound() {
- return (
- <div className="flex size-full">
- <div className="m-auto text-3xl">Not Found :(</div>
- </div>
- );
+ return (
+ <div className="flex size-full">
+ <div className="m-auto text-3xl">Not Found :(</div>
+ </div>
+ );
}
diff --git a/packages/web/components/ui/imageCard.tsx b/packages/web/components/ui/imageCard.tsx
index dae7da3f..f10ebdb5 100644
--- a/packages/web/components/ui/imageCard.tsx
+++ b/packages/web/components/ui/imageCard.tsx
@@ -3,51 +3,65 @@ import * as React from "react";
import { cn } from "@/lib/utils";
export function ImageCard({
- children,
- image,
className,
...props
-}: React.HTMLAttributes<HTMLDivElement> & { image?: string }) {
+}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("h-96 overflow-hidden rounded-lg shadow-md", className)}
{...props}
- >
- <div
- className="h-3/5 bg-cover bg-center"
- style={{
- backgroundImage: image ? `url(${image})` : undefined,
- }}
- ></div>
- <div className="flex h-2/5 flex-col p-2">{children}</div>
- </div>
+ />
);
}
-export function ImageCardTitle({
+export function ImageCardBanner({
+ className,
+ ...props
+}: React.ImgHTMLAttributes<HTMLImageElement>) {
+ return (
+ // eslint-disable-next-line @next/next/no-img-element
+ <img
+ className={cn("h-56 min-h-56 w-full object-cover", className)}
+ alt="card banner"
+ {...props}
+ />
+ );
+}
+
+export function ImageCardContent({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
- className={cn("order-first flex-none text-lg font-bold", className)}
+ className={cn(
+ "flex h-40 min-h-40 flex-col justify-between p-2",
+ className,
+ )}
{...props}
/>
);
}
-export function ImageCardBody({
+export function ImageCardTitle({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
- className={cn("order-1 grow text-lg font-bold", className)}
+ className={cn("order-first flex-none text-lg font-bold", className)}
{...props}
/>
);
}
+export function ImageCardBody({
+ className,
+ ...props
+}: React.HTMLAttributes<HTMLDivElement>) {
+ return <div className={cn("order-1", className)} {...props} />;
+}
+
export function ImageCardFooter({
className,
...props