feat(codebase): add syntax highlighting via react-syntax-highlighter with vs-dark-plus theme to the file viewer
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
"use client";
|
||||
|
||||
/**
|
||||
* Read-only file viewer that pulls a file's content from Gitea via
|
||||
* `GET /api/projects/[projectId]/file?path=…`. No syntax highlight
|
||||
* yet — just monospaced text. Phase 2 can swap in Shiki/Prism if
|
||||
* the founders ever read enough code here to need it.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Loader2, AlertCircle, FileText } from "lucide-react";
|
||||
import { Loader2, AlertCircle, FileText, Copy, Check } from "lucide-react";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import { THEME } from "@/components/project/dashboard-ui";
|
||||
|
||||
interface GiteaFileViewerProps {
|
||||
projectId: string;
|
||||
@@ -29,6 +25,15 @@ export function GiteaFileViewer({ projectId, path }: GiteaFileViewerProps) {
|
||||
const [content, setContent] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const copyCode = () => {
|
||||
if (content) {
|
||||
navigator.clipboard.writeText(content);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!path) {
|
||||
@@ -46,16 +51,16 @@ export function GiteaFileViewer({ projectId, path }: GiteaFileViewerProps) {
|
||||
fetch(`/api/projects/${projectId}/file?path=${encodeURIComponent(path)}`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then(async r => {
|
||||
.then(async (r) => {
|
||||
const data = (await r.json()) as ApiResponse;
|
||||
if (!r.ok) throw new Error(data.error || `HTTP ${r.status}`);
|
||||
if (data.type !== "file") throw new Error("Not a file");
|
||||
return data.content ?? "";
|
||||
})
|
||||
.then(c => {
|
||||
.then((c) => {
|
||||
if (!cancelled) setContent(c);
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
if (!cancelled) setError(err.message || "Failed to load file");
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -70,7 +75,7 @@ export function GiteaFileViewer({ projectId, path }: GiteaFileViewerProps) {
|
||||
if (!path) {
|
||||
return (
|
||||
<Centered>
|
||||
<FileText size={18} style={{ color: INK.muted }} />
|
||||
<FileText size={18} style={{ color: THEME.muted }} />
|
||||
<span>Pick a file from the codebase to preview it here.</span>
|
||||
</Centered>
|
||||
);
|
||||
@@ -79,7 +84,11 @@ export function GiteaFileViewer({ projectId, path }: GiteaFileViewerProps) {
|
||||
if (loading) {
|
||||
return (
|
||||
<Centered>
|
||||
<Loader2 size={14} className="animate-spin" style={{ color: INK.muted }} />
|
||||
<Loader2
|
||||
size={14}
|
||||
className="animate-spin"
|
||||
style={{ color: THEME.muted }}
|
||||
/>
|
||||
<span>Loading {basename(path)}…</span>
|
||||
</Centered>
|
||||
);
|
||||
@@ -88,17 +97,105 @@ export function GiteaFileViewer({ projectId, path }: GiteaFileViewerProps) {
|
||||
if (error) {
|
||||
return (
|
||||
<Centered>
|
||||
<AlertCircle size={14} style={{ color: INK.muted }} />
|
||||
<span>{error}</span>
|
||||
<AlertCircle size={14} style={{ color: THEME.danger }} />
|
||||
<span style={{ color: THEME.danger }}>{error}</span>
|
||||
</Centered>
|
||||
);
|
||||
}
|
||||
|
||||
const extension = path.split(".").pop() || "text";
|
||||
const languageMap: Record<string, string> = {
|
||||
js: "javascript",
|
||||
jsx: "jsx",
|
||||
ts: "typescript",
|
||||
tsx: "tsx",
|
||||
json: "json",
|
||||
html: "html",
|
||||
css: "css",
|
||||
scss: "scss",
|
||||
md: "markdown",
|
||||
sh: "bash",
|
||||
yml: "yaml",
|
||||
yaml: "yaml",
|
||||
sql: "sql",
|
||||
py: "python",
|
||||
rs: "rust",
|
||||
go: "go",
|
||||
};
|
||||
const language = languageMap[extension] || "text";
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: 0,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
padding: "8px 12px",
|
||||
background: "#1e1e1e",
|
||||
borderTopLeftRadius: THEME.radiusSm,
|
||||
borderTopRightRadius: THEME.radiusSm,
|
||||
borderBottom: "1px solid #333",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "0.8rem",
|
||||
color: "#a1a1aa",
|
||||
fontFamily: "ui-monospace, monospace",
|
||||
}}
|
||||
>
|
||||
{basename(path)}
|
||||
</div>
|
||||
<button
|
||||
onClick={copyCode}
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 6,
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
color: copied ? "#10b981" : "#a1a1aa",
|
||||
fontSize: "0.75rem",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{copied ? <Check size={13} /> : <Copy size={13} />}
|
||||
{copied ? "Copied" : "Copy"}
|
||||
</button>
|
||||
</div>
|
||||
<div style={wrap}>
|
||||
<pre style={pre}>
|
||||
<code>{content}</code>
|
||||
</pre>
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={vscDarkPlus}
|
||||
customStyle={{
|
||||
margin: 0,
|
||||
padding: "16px",
|
||||
background: "#1e1e1e",
|
||||
fontSize: "0.8rem",
|
||||
fontFamily:
|
||||
"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
||||
flex: 1,
|
||||
}}
|
||||
showLineNumbers={true}
|
||||
lineNumberStyle={{
|
||||
minWidth: "3em",
|
||||
paddingRight: "1em",
|
||||
color: "#6e7681",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{content || ""}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -109,36 +206,29 @@ function basename(p: string) {
|
||||
|
||||
function Centered({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div style={{
|
||||
flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
|
||||
gap: 10, color: INK.mid, fontSize: "0.85rem", padding: "32px 16px", textAlign: "center",
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 10,
|
||||
color: THEME.mid,
|
||||
fontSize: "0.85rem",
|
||||
padding: "32px 16px",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const INK = {
|
||||
ink: "#1a1a1a",
|
||||
mid: "#5f5e5a",
|
||||
muted: "#a09a90",
|
||||
border: "#e8e4dc",
|
||||
} as const;
|
||||
|
||||
const wrap: React.CSSProperties = {
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflow: "auto",
|
||||
margin: "-4px -10px",
|
||||
};
|
||||
|
||||
const pre: React.CSSProperties = {
|
||||
margin: 0,
|
||||
padding: "8px 10px",
|
||||
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
||||
fontSize: "0.78rem",
|
||||
lineHeight: 1.55,
|
||||
color: INK.ink,
|
||||
whiteSpace: "pre",
|
||||
tabSize: 2,
|
||||
background: "#1e1e1e",
|
||||
borderBottomLeftRadius: THEME.radiusSm,
|
||||
borderBottomRightRadius: THEME.radiusSm,
|
||||
};
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sonner": "^2.0.7",
|
||||
"ssh2": "^1.17.0",
|
||||
@@ -87,6 +88,7 @@
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/ssh2": "^1.15.5",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.0.1",
|
||||
|
||||
99
vibn-frontend/pnpm-lock.yaml
generated
99
vibn-frontend/pnpm-lock.yaml
generated
@@ -143,6 +143,9 @@ importers:
|
||||
react-markdown:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0(@types/react@19.2.16)(react@19.2.7)
|
||||
react-syntax-highlighter:
|
||||
specifier: ^16.1.1
|
||||
version: 16.1.1(react@19.2.7)
|
||||
remark-gfm:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
@@ -189,6 +192,9 @@ importers:
|
||||
'@types/react-dom':
|
||||
specifier: ^19
|
||||
version: 19.2.3(@types/react@19.2.16)
|
||||
'@types/react-syntax-highlighter':
|
||||
specifier: ^15.5.13
|
||||
version: 15.5.13
|
||||
'@types/ssh2':
|
||||
specifier: ^1.15.5
|
||||
version: 1.15.5
|
||||
@@ -2794,6 +2800,9 @@ packages:
|
||||
'@types/pg@8.20.0':
|
||||
resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==}
|
||||
|
||||
'@types/prismjs@1.26.6':
|
||||
resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==}
|
||||
|
||||
'@types/qs@6.15.1':
|
||||
resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==}
|
||||
|
||||
@@ -2805,6 +2814,9 @@ packages:
|
||||
peerDependencies:
|
||||
'@types/react': ^19.2.0
|
||||
|
||||
'@types/react-syntax-highlighter@15.5.13':
|
||||
resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==}
|
||||
|
||||
'@types/react@19.2.16':
|
||||
resolution: {integrity: sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==}
|
||||
|
||||
@@ -4080,6 +4092,9 @@ packages:
|
||||
fastq@1.20.1:
|
||||
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
|
||||
|
||||
fault@1.0.4:
|
||||
resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==}
|
||||
|
||||
faye-websocket@0.11.4:
|
||||
resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
@@ -4173,6 +4188,10 @@ packages:
|
||||
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
format@0.2.2:
|
||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
@@ -4364,18 +4383,30 @@ packages:
|
||||
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hast-util-parse-selector@4.0.0:
|
||||
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
|
||||
|
||||
hast-util-whitespace@3.0.0:
|
||||
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
|
||||
|
||||
hastscript@9.0.1:
|
||||
resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
|
||||
|
||||
hermes-estree@0.25.1:
|
||||
resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
|
||||
|
||||
hermes-parser@0.25.1:
|
||||
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
|
||||
|
||||
highlight.js@10.7.3:
|
||||
resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
|
||||
|
||||
highlightjs-vue@1.0.0:
|
||||
resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==}
|
||||
|
||||
hono@4.12.23:
|
||||
resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
@@ -4907,6 +4938,9 @@ packages:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
|
||||
lowlight@1.20.0:
|
||||
resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==}
|
||||
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
@@ -5827,6 +5861,10 @@ packages:
|
||||
engines: {node: '>=16.13'}
|
||||
hasBin: true
|
||||
|
||||
prismjs@1.30.0:
|
||||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
progress@2.0.3:
|
||||
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
@@ -5939,6 +5977,12 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-syntax-highlighter@16.1.1:
|
||||
resolution: {integrity: sha512-PjVawBGy80C6YbC5DDZJeUjBmC7skaoEUdvfFQediQHgCL7aKyVHe57SaJGfQsloGDac+gCpTfRdtxzWWKmCXA==}
|
||||
engines: {node: '>= 16.20.2'}
|
||||
peerDependencies:
|
||||
react: '>= 0.14.0'
|
||||
|
||||
react-textarea-autosize@8.5.9:
|
||||
resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -5961,6 +6005,9 @@ packages:
|
||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
refractor@5.0.0:
|
||||
resolution: {integrity: sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==}
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -9603,6 +9650,8 @@ snapshots:
|
||||
pg-protocol: 1.14.0
|
||||
pg-types: 2.2.0
|
||||
|
||||
'@types/prismjs@1.26.6': {}
|
||||
|
||||
'@types/qs@6.15.1': {}
|
||||
|
||||
'@types/range-parser@1.2.7': {}
|
||||
@@ -9611,6 +9660,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/react': 19.2.16
|
||||
|
||||
'@types/react-syntax-highlighter@15.5.13':
|
||||
dependencies:
|
||||
'@types/react': 19.2.16
|
||||
|
||||
'@types/react@19.2.16':
|
||||
dependencies:
|
||||
csstype: 3.2.3
|
||||
@@ -11169,6 +11222,10 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fault@1.0.4:
|
||||
dependencies:
|
||||
format: 0.2.2
|
||||
|
||||
faye-websocket@0.11.4:
|
||||
dependencies:
|
||||
websocket-driver: 0.7.4
|
||||
@@ -11315,6 +11372,8 @@ snapshots:
|
||||
hasown: 2.0.4
|
||||
mime-types: 2.1.35
|
||||
|
||||
format@0.2.2: {}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
@@ -11548,6 +11607,10 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hast-util-parse-selector@4.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.9
|
||||
@@ -11572,12 +11635,24 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
hastscript@9.0.1:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
comma-separated-tokens: 2.0.3
|
||||
hast-util-parse-selector: 4.0.0
|
||||
property-information: 7.2.0
|
||||
space-separated-tokens: 2.0.2
|
||||
|
||||
hermes-estree@0.25.1: {}
|
||||
|
||||
hermes-parser@0.25.1:
|
||||
dependencies:
|
||||
hermes-estree: 0.25.1
|
||||
|
||||
highlight.js@10.7.3: {}
|
||||
|
||||
highlightjs-vue@1.0.0: {}
|
||||
|
||||
hono@4.12.23: {}
|
||||
|
||||
html-entities@2.6.0: {}
|
||||
@@ -12080,6 +12155,11 @@ snapshots:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
|
||||
lowlight@1.20.0:
|
||||
dependencies:
|
||||
fault: 1.0.4
|
||||
highlight.js: 10.7.3
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
lru-cache@11.5.1: {}
|
||||
@@ -13521,6 +13601,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
prismjs@1.30.0: {}
|
||||
|
||||
progress@2.0.3: {}
|
||||
|
||||
prop-types@15.8.1:
|
||||
@@ -13701,6 +13783,16 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.16
|
||||
|
||||
react-syntax-highlighter@16.1.1(react@19.2.7):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
highlight.js: 10.7.3
|
||||
highlightjs-vue: 1.0.0
|
||||
lowlight: 1.20.0
|
||||
prismjs: 1.30.0
|
||||
react: 19.2.7
|
||||
refractor: 5.0.0
|
||||
|
||||
react-textarea-autosize@8.5.9(@types/react@19.2.16)(react@19.2.7):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.7
|
||||
@@ -13731,6 +13823,13 @@ snapshots:
|
||||
get-proto: 1.0.1
|
||||
which-builtin-type: 1.2.1
|
||||
|
||||
refractor@5.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/prismjs': 1.26.6
|
||||
hastscript: 9.0.1
|
||||
parse-entities: 4.0.2
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
dependencies:
|
||||
call-bind: 1.0.9
|
||||
|
||||
Reference in New Issue
Block a user