Skip to content

Commit fb6f559

Browse files
authored
Merge pull request #20 from cocdeshijie/dev
Image Lightbox and Friend Link Card
2 parents 0450304 + e378c97 commit fb6f559

File tree

4 files changed

+153
-2
lines changed

4 files changed

+153
-2
lines changed

components/mdx/MDXComponents.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
"use client";
22

33
import Link from "next/link";
4+
import * as Dialog from '@radix-ui/react-dialog';
5+
import { AnimatePresence, motion } from "framer-motion";
6+
import { cn } from "@/lib/utils";
7+
import { useState } from "react";
8+
49

510
function a({ href, children }: React.HTMLProps<HTMLAnchorElement>) {
611
if (href && href.startsWith('/')) {
@@ -28,7 +33,44 @@ function ul({ children, className }: React.HTMLProps<HTMLUListElement>) {
2833
return <ul style={style}>{children}</ul>;
2934
}
3035

36+
function Img({ src, alt }: React.HTMLProps<HTMLImageElement>) {
37+
const [imageOpen, setImageOpen] = useState(false)
38+
39+
return (
40+
<Dialog.Root onOpenChange={(open) => setImageOpen(open)}>
41+
<Dialog.Trigger className="flex items-center justify-center h-full mx-auto">
42+
<img src={src} alt={alt} className="cursor-pointer rounded-lg"/>
43+
</Dialog.Trigger>
44+
<AnimatePresence>
45+
{imageOpen ? (
46+
<Dialog.Portal forceMount>
47+
<motion.div
48+
onClick={() => setImageOpen(false)} // close on click
49+
initial={{ opacity: 0, scale: 0.9 }}
50+
animate={{ opacity: 1, scale: 1 }}
51+
exit={{ opacity: 0, scale: 0.9 }}
52+
transition={{ ease: "easeOut", duration: 0.15 }}
53+
className={cn(
54+
"fixed z-40 inset-0 flex items-center justify-center",
55+
"bg-slate-800/50"
56+
)}
57+
>
58+
<Dialog.Content className="md:p-16">
59+
<img src={src} alt={alt} className="z-50 max-h-full max-w-full"/>
60+
</Dialog.Content>
61+
</motion.div>
62+
</Dialog.Portal>
63+
) : null}
64+
</AnimatePresence>
65+
</Dialog.Root>
66+
);
67+
}
68+
69+
const img = Img;
70+
71+
3172
export const MDXComponents = {
3273
a,
33-
ul
74+
ul,
75+
img
3476
}

components/mdx/MDXStyles.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export default function MDXStyles({ children }: MDXStylesProps) {
2020
"prose-hr:border-slate-700 dark:prose-hr:border-slate-300",
2121
"prose-th:border-secondary_color/75 dark:prose-th:border-secondary_color-dark/75 prose-th:border-b-2 prose-th:font-bold",
2222
"prose-td:border-secondary_color/50 dark:prose-td:border-secondary_color-dark/50 prose-td:border-b",
23-
"prose-img:mx-auto"
2423
)}
2524
>
2625
{children}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"use client";
2+
3+
import { cn } from "@/lib/utils";
4+
import { RiExternalLinkLine } from "react-icons/ri";
5+
import React, { ReactNode, Children, useState, useEffect } from 'react';
6+
7+
type LinkCardProps = {
8+
link: string;
9+
profile: string;
10+
title: string;
11+
description: string;
12+
author: string;
13+
}
14+
15+
export function FriendLinkCard({ link, profile, title, description, author }: LinkCardProps) {
16+
const [hover, setHover] = useState(false);
17+
18+
return (
19+
<div onMouseEnter={() => setHover(true)}
20+
onMouseLeave={() => setHover(false)}
21+
onClick={() => window.open(link, '_blank')}
22+
style={hover ? {cursor: 'pointer'} : {}}
23+
className={cn(
24+
"flex p-2 mx-auto rounded-xl not-prose",
25+
"w-full h-full duration-500",
26+
"backdrop-blur-2xl overflow-hidden bg-slate-50/50 dark:bg-gray-800/70",
27+
{"shadow-lg shadow-primary_color/50 dark:shadow-primary_color-dark/30": hover}
28+
)}>
29+
<div className={"h-32 pr-4 flex-1 flex flex-col space-y-2"}>
30+
<div className={"line-clamp-2 font-bold text-base"}>
31+
{title}
32+
</div>
33+
<p className={"line-clamp-2 md:line-clamp-3 font-light text-sm"}>
34+
{description}
35+
</p>
36+
<p className={"line-clamp-1 font-thin text-xs"}>
37+
{link}
38+
</p>
39+
</div>
40+
<div className={"h-32 w-32 flex items-center"}>
41+
<img className={"h-max w-max mx-auto rounded-lg"}
42+
alt={"Profile image"}
43+
src={profile}/>
44+
</div>
45+
<div className={"absolute top-2 right-2"}>
46+
<RiExternalLinkLine className={cn(
47+
hover ? "text-primary_color dark:text-primary_color-dark" : "",
48+
"duration-500"
49+
)}/>
50+
</div>
51+
</div>
52+
)
53+
}
54+
55+
type RandomFriendLinkCardsProps = {
56+
children: ReactNode[];
57+
};
58+
59+
export function RandomFriendLinkCards({ children }: RandomFriendLinkCardsProps) {
60+
const [randomizedChildren, setRandomizedChildren] = useState<ReactNode[]>([]);
61+
62+
useEffect(() => {
63+
const shuffled = Children.toArray(children).sort(() => 0.5 - Math.random());
64+
setRandomizedChildren(shuffled);
65+
}, [children]);
66+
67+
return (
68+
<div className="space-y-4 md:space-y-0 md:grid md:grid-cols-2 gap-4">
69+
{randomizedChildren}
70+
</div>
71+
);
72+
}

content/pages/link-card.mdx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,46 @@ import LinkCard from "../../content-components/link-card/LinkCard";
88
<LinkCard link={"https://github.com"}/>
99
```
1010

11+
The Link Card component only requires the link to a website. It will retrieve the title, description and Open Graph image automatically.
12+
1113
import LinkCard from "../../content-components/link-card/LinkCard";
1214

1315
<LinkCard link={"https://github.com"}/>
1416

1517

18+
```mdx /content/pages/link-card.mdx
19+
import { FriendLinkCard, RandomFriendLinkCards } from "../../content-components/link-card/FriendLinkCard";
20+
21+
<RandomFriendLinkCards>
22+
<FriendLinkCard link={"https://next-sakurairo.qwq.xyz"}
23+
profile={"https://next-sakurairo.qwq.xyz/img.png"}
24+
title={"Next Sakurairo の Site"}
25+
description={"A blog built with Next.js, Tailwind CSS, Radix UI, Framer Motion, and ContentLayer with MDX."}
26+
author={"cocdeshijie"}/>
27+
28+
<FriendLinkCard link={"https://qwq.xyz"}
29+
profile={"https://qwq.xyz/cocdeshijie.gif"}
30+
title={"cocdeshijie の Blog"}
31+
description={"qwq~"}
32+
author={"cocdeshijie"}/>
33+
</RandomFriendLinkCards>
34+
```
35+
36+
The Friend Link Card component needs to be used as children of RandomFriendLinkCards.
37+
38+
import { FriendLinkCard, RandomFriendLinkCards } from "../../content-components/link-card/FriendLinkCard";
39+
40+
<RandomFriendLinkCards>
41+
<FriendLinkCard link={"https://next-sakurairo.qwq.xyz"}
42+
profile={"https://next-sakurairo.qwq.xyz/img.png"}
43+
title={"Next Sakurairo の Site"}
44+
description={"A blog built with Next.js, Tailwind CSS, Radix UI, Framer Motion, and ContentLayer with MDX."}
45+
author={"cocdeshijie"}/>
46+
47+
<FriendLinkCard link={"https://qwq.xyz"}
48+
profile={"https://qwq.xyz/cocdeshijie.gif"}
49+
title={"cocdeshijie の Blog"}
50+
description={"qwq~"}
51+
author={"cocdeshijie"}/>
52+
</RandomFriendLinkCards>
53+

0 commit comments

Comments
 (0)