feat: Update Button component with size prop
This commit is contained in:
parent
dcf128a2d8
commit
7c83d3b37e
@ -3,17 +3,24 @@ import clsx from "clsx";
|
|||||||
|
|
||||||
const variantStyles = {
|
const variantStyles = {
|
||||||
primary:
|
primary:
|
||||||
"rounded-full bg-violet-300 py-2 px-4 text-sm font-semibold text-slate-900 hover:bg-violet-200 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-300/50 active:bg-violet-500",
|
"bg-violet-300 font-semibold text-slate-900 hover:bg-violet-200 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-violet-300/50 active:bg-violet-500",
|
||||||
secondary:
|
secondary:
|
||||||
"rounded-full bg-slate-800 py-2 px-4 text-sm font-medium text-white hover:bg-slate-700 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 active:text-slate-400",
|
"bg-slate-800 font-medium text-white hover:bg-slate-700 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 active:text-slate-400",
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizeStyles = {
|
||||||
|
sm: "rounded-md py-1 px-2 text-xs",
|
||||||
|
md: "rounded-full py-2 px-4 text-sm",
|
||||||
|
lg: "rounded-full py-3 px-6 text-base",
|
||||||
};
|
};
|
||||||
|
|
||||||
type ButtonProps = {
|
type ButtonProps = {
|
||||||
variant?: keyof typeof variantStyles;
|
variant?: keyof typeof variantStyles;
|
||||||
|
size?: keyof typeof sizeStyles;
|
||||||
} & (React.ComponentPropsWithoutRef<typeof Link> | (React.ComponentPropsWithoutRef<"button"> & { href?: undefined }));
|
} & (React.ComponentPropsWithoutRef<typeof Link> | (React.ComponentPropsWithoutRef<"button"> & { href?: undefined }));
|
||||||
|
|
||||||
export function Button({ variant = "primary", className, ...props }: ButtonProps) {
|
export function Button({ variant = "primary", size = "md", className, ...props }: ButtonProps) {
|
||||||
className = clsx(variantStyles[variant], "cursor-pointer", className);
|
className = clsx(variantStyles[variant], sizeStyles[size], "cursor-pointer", className);
|
||||||
|
|
||||||
return typeof props.href === "undefined" ? (
|
return typeof props.href === "undefined" ? (
|
||||||
<button className={className} {...props} />
|
<button className={className} {...props} />
|
||||||
|
|||||||
52
app/components/syntax/CSRFence.tsx
Normal file
52
app/components/syntax/CSRFence.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { ClipboardDocumentIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { prismThemes } from "@/data/themes/prism";
|
||||||
|
import { Highlight } from "prism-react-renderer";
|
||||||
|
import { useTheme } from "@/hooks/useTheme";
|
||||||
|
import { Fragment, useMemo } from "react";
|
||||||
|
import { Button } from "./Button";
|
||||||
|
import Prism from "prismjs";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export default function CSRFence({ children, language }: { children: string; language: string }) {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
const prismTheme = useMemo(() => {
|
||||||
|
return prismThemes[theme];
|
||||||
|
}, [theme]);
|
||||||
|
|
||||||
|
const copyToClipboard = () => {
|
||||||
|
navigator.clipboard.writeText(children.trimEnd());
|
||||||
|
toast.success("Code copied to clipboard!");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
||||||
|
{({ className, style, tokens, getTokenProps }) => (
|
||||||
|
<pre className={className} style={style}>
|
||||||
|
<code>
|
||||||
|
{tokens.map((line, lineIndex) => (
|
||||||
|
<Fragment key={lineIndex}>
|
||||||
|
{line
|
||||||
|
.filter((token) => !token.empty)
|
||||||
|
.map((token, tokenIndex) => (
|
||||||
|
<span key={tokenIndex} {...getTokenProps({ token })} />
|
||||||
|
))}
|
||||||
|
{"\n"}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</Highlight>
|
||||||
|
<Button
|
||||||
|
className="absolute top-2 right-2 w-8 h-8 aspect-square opacity-0 group-hover:opacity-50 hover:opacity-100 transition-opacity"
|
||||||
|
size="sm"
|
||||||
|
variant="secondary"
|
||||||
|
onClick={copyToClipboard}
|
||||||
|
>
|
||||||
|
<ClipboardDocumentIcon className="w-full" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,17 +1,20 @@
|
|||||||
|
import { Highlight, Prism } from "prism-react-renderer";
|
||||||
import { prismThemes } from "@/data/themes/prism";
|
import { prismThemes } from "@/data/themes/prism";
|
||||||
import { Highlight } from "prism-react-renderer";
|
|
||||||
import { useTheme } from "@/hooks/useTheme";
|
import { useTheme } from "@/hooks/useTheme";
|
||||||
import { Fragment, useMemo } from "react";
|
import { Fragment, useMemo } from "react";
|
||||||
|
|
||||||
export function Fence({ children, language }: { children: string; language: string }) {
|
import { clientOnly } from "vike-react/clientOnly";
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
|
const CSRFence = clientOnly(() => import("./CSRFence"));
|
||||||
|
|
||||||
|
function SSRFence({ children, language }: { children: string; language: string }) {
|
||||||
|
const { theme } = useTheme();
|
||||||
const prismTheme = useMemo(() => {
|
const prismTheme = useMemo(() => {
|
||||||
return prismThemes[theme];
|
return prismThemes[theme];
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Highlight code={children.trimEnd()} language={language} theme={prismTheme}>
|
<Highlight code={children.trimEnd()} language={language} theme={prismTheme} prism={Prism}>
|
||||||
{({ className, style, tokens, getTokenProps }) => (
|
{({ className, style, tokens, getTokenProps }) => (
|
||||||
<pre className={className} style={style}>
|
<pre className={className} style={style}>
|
||||||
<code>
|
<code>
|
||||||
@ -31,3 +34,13 @@ export function Fence({ children, language }: { children: string; language: stri
|
|||||||
</Highlight>
|
</Highlight>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Fence({ children, language }: { children: string; language: string }) {
|
||||||
|
return (
|
||||||
|
<div className="relative group">
|
||||||
|
<CSRFence language={language} fallback={<SSRFence language={language} children={children} />}>
|
||||||
|
{children}
|
||||||
|
</CSRFence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import { fileURLToPath } from "node:url";
|
|||||||
import { dirname } from "node:path";
|
import { dirname } from "node:path";
|
||||||
import Fastify from "fastify";
|
import Fastify from "fastify";
|
||||||
|
|
||||||
|
import { Prism } from "prism-react-renderer";
|
||||||
|
(typeof global !== "undefined" ? global : window).Prism = Prism;
|
||||||
|
require("prismjs/components/prism-bash");
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
|||||||
@ -45,3 +45,11 @@ pre[class*="language-"] {
|
|||||||
.token.combinator {
|
.token.combinator {
|
||||||
color: var(--color-slate-400);
|
color: var(--color-slate-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prism-code {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code + .prism-code {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|||||||
@ -27,21 +27,25 @@
|
|||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prism-react-renderer": "^2.4.1",
|
"prism-react-renderer": "^2.4.1",
|
||||||
|
"prismjs": "^1.30.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-highlight-words": "^0.21.0",
|
"react-highlight-words": "^0.21.0",
|
||||||
|
"react-toastify": "^11.0.5",
|
||||||
"reading-time-estimator": "^1.12.0",
|
"reading-time-estimator": "^1.12.0",
|
||||||
"simple-functional-loader": "^1.2.1",
|
"simple-functional-loader": "^1.2.1",
|
||||||
"telefunc": "^0.1.87",
|
"telefunc": "^0.1.87",
|
||||||
"unplugin-fonts": "^1.3.1",
|
"unplugin-fonts": "^1.3.1",
|
||||||
"vike": "^0.4.224",
|
"vike": "^0.4.224",
|
||||||
"vike-react": "^0.5.13"
|
"vike-react": "^0.5.13",
|
||||||
|
"vite-plugin-prismjs": "^0.0.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.22.0",
|
"@eslint/js": "^9.22.0",
|
||||||
"@tailwindcss/vite": "^4.0.12",
|
"@tailwindcss/vite": "^4.0.12",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/node": "^18.19.76",
|
"@types/node": "^18.19.76",
|
||||||
|
"@types/prismjs": "^1.26.5",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@types/react-highlight-words": "^0.20.0",
|
"@types/react-highlight-words": "^0.20.0",
|
||||||
|
|||||||
51
app/pnpm-lock.yaml
generated
51
app/pnpm-lock.yaml
generated
@ -68,6 +68,9 @@ importers:
|
|||||||
prism-react-renderer:
|
prism-react-renderer:
|
||||||
specifier: ^2.4.1
|
specifier: ^2.4.1
|
||||||
version: 2.4.1(react@19.1.0)
|
version: 2.4.1(react@19.1.0)
|
||||||
|
prismjs:
|
||||||
|
specifier: ^1.30.0
|
||||||
|
version: 1.30.0
|
||||||
react:
|
react:
|
||||||
specifier: ^19.0.0
|
specifier: ^19.0.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
@ -77,6 +80,9 @@ importers:
|
|||||||
react-highlight-words:
|
react-highlight-words:
|
||||||
specifier: ^0.21.0
|
specifier: ^0.21.0
|
||||||
version: 0.21.0(react@19.1.0)
|
version: 0.21.0(react@19.1.0)
|
||||||
|
react-toastify:
|
||||||
|
specifier: ^11.0.5
|
||||||
|
version: 11.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
reading-time-estimator:
|
reading-time-estimator:
|
||||||
specifier: ^1.12.0
|
specifier: ^1.12.0
|
||||||
version: 1.12.0
|
version: 1.12.0
|
||||||
@ -95,6 +101,9 @@ importers:
|
|||||||
vike-react:
|
vike-react:
|
||||||
specifier: ^0.5.13
|
specifier: ^0.5.13
|
||||||
version: 0.5.13(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vike@0.4.228(react-streaming@0.3.50(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)))
|
version: 0.5.13(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vike@0.4.228(react-streaming@0.3.50(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(vite@6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)))
|
||||||
|
vite-plugin-prismjs:
|
||||||
|
specifier: ^0.0.11
|
||||||
|
version: 0.0.11(prismjs@1.30.0)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@eslint/js':
|
'@eslint/js':
|
||||||
specifier: ^9.22.0
|
specifier: ^9.22.0
|
||||||
@ -108,6 +117,9 @@ importers:
|
|||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^18.19.76
|
specifier: ^18.19.76
|
||||||
version: 18.19.86
|
version: 18.19.86
|
||||||
|
'@types/prismjs':
|
||||||
|
specifier: ^1.26.5
|
||||||
|
version: 1.26.5
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^19.0.10
|
specifier: ^19.0.10
|
||||||
version: 19.1.1
|
version: 19.1.1
|
||||||
@ -1237,6 +1249,11 @@ packages:
|
|||||||
avvio@9.1.0:
|
avvio@9.1.0:
|
||||||
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
|
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
|
||||||
|
|
||||||
|
babel-plugin-prismjs@2.1.0:
|
||||||
|
resolution: {integrity: sha512-ehzSKYfeAz4U78zi/sfwsjDPlq0LvDKxNefcZTJ/iKBu+plsHsLqZhUeGf1+82LAcA35UZGbU6ksEx2Utphc/g==}
|
||||||
|
peerDependencies:
|
||||||
|
prismjs: ^1.18.0
|
||||||
|
|
||||||
balanced-match@1.0.2:
|
balanced-match@1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
@ -2322,6 +2339,10 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '>=16.0.0'
|
react: '>=16.0.0'
|
||||||
|
|
||||||
|
prismjs@1.30.0:
|
||||||
|
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
process-warning@4.0.1:
|
process-warning@4.0.1:
|
||||||
resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
|
resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
|
||||||
|
|
||||||
@ -2368,6 +2389,12 @@ packages:
|
|||||||
react: '>=18'
|
react: '>=18'
|
||||||
react-dom: '>=18'
|
react-dom: '>=18'
|
||||||
|
|
||||||
|
react-toastify@11.0.5:
|
||||||
|
resolution: {integrity: sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^18 || ^19
|
||||||
|
react-dom: ^18 || ^19
|
||||||
|
|
||||||
react@19.1.0:
|
react@19.1.0:
|
||||||
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -2822,6 +2849,10 @@ packages:
|
|||||||
vite:
|
vite:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vite-plugin-prismjs@0.0.11:
|
||||||
|
resolution: {integrity: sha512-20NBQxg/zH+3FTrlU6BQTob720xkuXNYtrx7psAQ4E6pMcRDeLEK77QU9kXURU587+f2To7ASH1JVTGbXVV/vQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
vite@6.2.6:
|
vite@6.2.6:
|
||||||
resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==}
|
resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==}
|
||||||
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
|
||||||
@ -3911,6 +3942,10 @@ snapshots:
|
|||||||
'@fastify/error': 4.1.0
|
'@fastify/error': 4.1.0
|
||||||
fastq: 1.19.1
|
fastq: 1.19.1
|
||||||
|
|
||||||
|
babel-plugin-prismjs@2.1.0(prismjs@1.30.0):
|
||||||
|
dependencies:
|
||||||
|
prismjs: 1.30.0
|
||||||
|
|
||||||
balanced-match@1.0.2: {}
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
big.js@5.2.2: {}
|
big.js@5.2.2: {}
|
||||||
@ -5118,6 +5153,8 @@ snapshots:
|
|||||||
clsx: 2.1.1
|
clsx: 2.1.1
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
|
prismjs@1.30.0: {}
|
||||||
|
|
||||||
process-warning@4.0.1: {}
|
process-warning@4.0.1: {}
|
||||||
|
|
||||||
process-warning@5.0.0: {}
|
process-warning@5.0.0: {}
|
||||||
@ -5165,6 +5202,12 @@ snapshots:
|
|||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
|
react-toastify@11.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
clsx: 2.1.1
|
||||||
|
react: 19.1.0
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
react@19.1.0: {}
|
react@19.1.0: {}
|
||||||
|
|
||||||
read-pkg@3.0.0:
|
read-pkg@3.0.0:
|
||||||
@ -5693,6 +5736,14 @@ snapshots:
|
|||||||
react-streaming: 0.3.50(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
react-streaming: 0.3.50(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
vite: 6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)
|
vite: 6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3)
|
||||||
|
|
||||||
|
vite-plugin-prismjs@0.0.11(prismjs@1.30.0):
|
||||||
|
dependencies:
|
||||||
|
'@babel/core': 7.26.10
|
||||||
|
babel-plugin-prismjs: 2.1.0(prismjs@1.30.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- prismjs
|
||||||
|
- supports-color
|
||||||
|
|
||||||
vite@6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3):
|
vite@6.2.6(@types/node@18.19.86)(jiti@2.4.2)(lightningcss@1.29.2)(tsx@4.19.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.2
|
esbuild: 0.25.2
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import prismjsVitePlugin from "vite-plugin-prismjs";
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import Unfonts from "unplugin-fonts/vite";
|
import Unfonts from "unplugin-fonts/vite";
|
||||||
import { telefunc } from "telefunc/vite";
|
import { telefunc } from "telefunc/vite";
|
||||||
@ -7,6 +8,9 @@ import vike from "vike/plugin";
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
prismjsVitePlugin({
|
||||||
|
languages: ["javascript", "typescript", "tsx", "jsx", "css", "html", "bash"],
|
||||||
|
}),
|
||||||
Unfonts({
|
Unfonts({
|
||||||
fontsource: {
|
fontsource: {
|
||||||
families: ["Inter Variable", "Lexend Variable"],
|
families: ["Inter Variable", "Lexend Variable"],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user