use prismjs
This commit is contained in:
parent
23f92dabc9
commit
00df250ff5
|
|
@ -37,6 +37,7 @@
|
|||
"nanoid": "^3.3.3",
|
||||
"next": "^12.1.6",
|
||||
"pica": "^9.0.1",
|
||||
"prismjs": "^1.28.0",
|
||||
"react": "^18.1.0",
|
||||
"react-avatar-editor": "^12.0.0",
|
||||
"react-dom": "^18.1.0",
|
||||
|
|
@ -44,7 +45,6 @@
|
|||
"react-hot-toast": "^2.2.0",
|
||||
"react-query": "^3.39.0",
|
||||
"react-sortablejs": "^6.1.1",
|
||||
"shiki": "^0.10.1",
|
||||
"sortablejs": "^1.15.0",
|
||||
"ua-parser-js": "^1.0.2",
|
||||
"uuid": "^8.3.2",
|
||||
|
|
@ -58,6 +58,7 @@
|
|||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/node": "^17.0.31",
|
||||
"@types/pica": "^9.0.0",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/react": "^18.0.9",
|
||||
"@types/react-avatar-editor": "^12.0.0",
|
||||
"@types/react-dom": "^18.0.3",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ specifiers:
|
|||
'@types/markdown-it': ^12.2.3
|
||||
'@types/node': ^17.0.31
|
||||
'@types/pica': ^9.0.0
|
||||
'@types/prismjs': ^1.26.0
|
||||
'@types/react': ^18.0.9
|
||||
'@types/react-avatar-editor': ^12.0.0
|
||||
'@types/react-dom': ^18.0.3
|
||||
|
|
@ -44,6 +45,7 @@ specifiers:
|
|||
pica: ^9.0.1
|
||||
postcss-import: ^14.1.0
|
||||
prisma: ^3.14.0
|
||||
prismjs: ^1.28.0
|
||||
react: ^18.1.0
|
||||
react-avatar-editor: ^12.0.0
|
||||
react-dom: ^18.1.0
|
||||
|
|
@ -51,7 +53,6 @@ specifiers:
|
|||
react-hot-toast: ^2.2.0
|
||||
react-query: ^3.39.0
|
||||
react-sortablejs: ^6.1.1
|
||||
shiki: ^0.10.1
|
||||
sortablejs: ^1.15.0
|
||||
tailwindcss: ^3.0.24
|
||||
typescript: ^4.5.5
|
||||
|
|
@ -88,6 +89,7 @@ dependencies:
|
|||
nanoid: 3.3.4
|
||||
next: 12.1.6_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
pica: 9.0.1
|
||||
prismjs: 1.28.0
|
||||
react: 18.1.0
|
||||
react-avatar-editor: 12.0.0_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
|
|
@ -95,7 +97,6 @@ dependencies:
|
|||
react-hot-toast: 2.2.0_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
react-query: 3.39.0_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
react-sortablejs: 6.1.1_kjz72dk5lh6hp4ogspefhm7r2u
|
||||
shiki: 0.10.1
|
||||
sortablejs: 1.15.0
|
||||
ua-parser-js: 1.0.2
|
||||
uuid: 8.3.2
|
||||
|
|
@ -109,6 +110,7 @@ devDependencies:
|
|||
'@types/markdown-it': 12.2.3
|
||||
'@types/node': 17.0.31
|
||||
'@types/pica': 9.0.0
|
||||
'@types/prismjs': 1.26.0
|
||||
'@types/react': 18.0.9
|
||||
'@types/react-avatar-editor': 12.0.0
|
||||
'@types/react-dom': 18.0.3
|
||||
|
|
@ -1659,6 +1661,10 @@ packages:
|
|||
resolution: {integrity: sha512-RyIhhyESvtvUdAviCqpk8fmNHNdSCMQB4ZVyPJLoNndRC8Jml/3zfC0RisHIuGFziM9+vGJ2/1nWXoTwAkVE2Q==}
|
||||
dev: true
|
||||
|
||||
/@types/prismjs/1.26.0:
|
||||
resolution: {integrity: sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==}
|
||||
dev: true
|
||||
|
||||
/@types/prop-types/15.7.5:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: true
|
||||
|
|
@ -3087,10 +3093,6 @@ packages:
|
|||
minimist: 1.2.6
|
||||
dev: true
|
||||
|
||||
/jsonc-parser/3.0.0:
|
||||
resolution: {integrity: sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==}
|
||||
dev: false
|
||||
|
||||
/jsx-ast-utils/3.3.0:
|
||||
resolution: {integrity: sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
|
@ -3591,6 +3593,11 @@ packages:
|
|||
'@prisma/engines': 3.14.0-36.2b0c12756921c891fec4f68d9444e18c7d5d4a6a
|
||||
dev: true
|
||||
|
||||
/prismjs/1.28.0:
|
||||
resolution: {integrity: sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/prop-types/15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
dependencies:
|
||||
|
|
@ -3830,14 +3837,6 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/shiki/0.10.1:
|
||||
resolution: {integrity: sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==}
|
||||
dependencies:
|
||||
jsonc-parser: 3.0.0
|
||||
vscode-oniguruma: 1.6.2
|
||||
vscode-textmate: 5.2.0
|
||||
dev: false
|
||||
|
||||
/side-channel/1.0.4:
|
||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||
dependencies:
|
||||
|
|
@ -4109,14 +4108,6 @@ packages:
|
|||
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
|
||||
dev: true
|
||||
|
||||
/vscode-oniguruma/1.6.2:
|
||||
resolution: {integrity: sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==}
|
||||
dev: false
|
||||
|
||||
/vscode-textmate/5.2.0:
|
||||
resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==}
|
||||
dev: false
|
||||
|
||||
/w3c-keyname/2.2.4:
|
||||
resolution: {integrity: sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==}
|
||||
dev: false
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const Input = forwardRef<HTMLInputElement, Props>(function Input(
|
|||
return (
|
||||
<div>
|
||||
{label && (
|
||||
<label className="label" htmlFor={inputProps.id}>
|
||||
<label className="form-label" htmlFor={inputProps.id}>
|
||||
{label}
|
||||
</label>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
.code {
|
||||
@apply my-5;
|
||||
@apply relative;
|
||||
color: var(--code-fg);
|
||||
}
|
||||
|
||||
.code pre {
|
||||
@apply p-5;
|
||||
@apply rounded-lg;
|
||||
@apply whitespace-pre-wrap;
|
||||
@apply whitespace-pre;
|
||||
@apply font-mono;
|
||||
background-color: var(--code-bg);
|
||||
}
|
||||
|
||||
.code:before {
|
||||
content: attr(data-lang);
|
||||
color: var(--lang-color);
|
||||
@apply absolute;
|
||||
@apply right-3;
|
||||
@apply top-2;
|
||||
@apply text-zinc-500;
|
||||
@apply text-xs;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@
|
|||
@import "./tailwind.css";
|
||||
@import "./prose.css";
|
||||
@import "./code.css";
|
||||
@import "./prism-dark.css";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
/** based on prism tomorror */
|
||||
|
||||
.code {
|
||||
--lang-color: #8d8c8c;
|
||||
--code-bg: #2d2d2d;
|
||||
--code-fg: #ccc;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.block-comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.token.tag,
|
||||
.token.attr-name,
|
||||
.token.namespace,
|
||||
.token.deleted {
|
||||
color: #e2777a;
|
||||
}
|
||||
|
||||
.token.function-name {
|
||||
color: #6196cc;
|
||||
}
|
||||
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.function {
|
||||
color: #f08d49;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.class-name,
|
||||
.token.constant,
|
||||
.token.symbol {
|
||||
color: #f8c555;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.important,
|
||||
.token.atrule,
|
||||
.token.keyword,
|
||||
.token.builtin {
|
||||
color: #cc99cd;
|
||||
}
|
||||
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.attr-value,
|
||||
.token.regex,
|
||||
.token.variable {
|
||||
color: #7ec699;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url {
|
||||
color: #67cdcc;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.token.inserted {
|
||||
color: green;
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ textarea.input {
|
|||
@apply px-3;
|
||||
}
|
||||
|
||||
.label {
|
||||
.form-label {
|
||||
@apply block;
|
||||
@apply mb-2;
|
||||
@apply text-sm;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import Markdown from "markdown-it"
|
||||
import * as shiki from "shiki"
|
||||
import Prism from "prismjs"
|
||||
import loadLanguages from "prismjs/components/index"
|
||||
import { getUserContentsUrl } from "./user-contents"
|
||||
|
||||
const isExternLink = (url: string) => /^https?:\/\//.test(url)
|
||||
|
|
@ -20,20 +21,18 @@ const handleImages = (md: Markdown) => {
|
|||
}
|
||||
}
|
||||
|
||||
const codeBlock = (
|
||||
md: Markdown,
|
||||
{ highlighter }: { highlighter: shiki.Highlighter }
|
||||
) => {
|
||||
const theme = highlighter.getTheme()
|
||||
const languages = highlighter.getLoadedLanguages()
|
||||
|
||||
const codeBlock = (md: Markdown) => {
|
||||
const highlight = (code: string, lang: string) => {
|
||||
if (!languages.includes(lang as any)) {
|
||||
return `<pre style="background-color:${theme.bg};color:${
|
||||
theme.fg
|
||||
};"><code>${md.utils.escapeHtml(code)}</code></pre>`
|
||||
if (lang === "vue" || lang === "svelte") {
|
||||
lang = "html"
|
||||
}
|
||||
return highlighter.codeToHtml(code, { lang })
|
||||
loadLanguages(lang)
|
||||
const grammer = Prism.languages[lang]
|
||||
const html = grammer
|
||||
? `<pre><code>${Prism.highlight(code, grammer, lang)}</code></pre>`
|
||||
: `<pre><code>${md.utils.escapeHtml(code)}</code></pre>`
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
||||
|
|
@ -44,16 +43,13 @@ const codeBlock = (
|
|||
}
|
||||
|
||||
export const renderPageContent = async (content: string) => {
|
||||
const highlighter = await shiki.getHighlighter({
|
||||
theme: "vitesse-dark",
|
||||
})
|
||||
const md = new Markdown({
|
||||
html: false,
|
||||
linkify: true,
|
||||
})
|
||||
|
||||
md.use(handleImages)
|
||||
md.use(codeBlock, { highlighter })
|
||||
md.use(codeBlock)
|
||||
|
||||
const html = md.render(content)
|
||||
return { html }
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default function AccountProfilePage() {
|
|||
<SettingsLayout title="Account" type="account">
|
||||
{viewer.data && (
|
||||
<div>
|
||||
<label className="label">Profile Picture</label>
|
||||
<label className="form-label">Profile Picture</label>
|
||||
<AvatarForm filename={viewer.data.avatar} name={viewer.data.name} />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export default function SiteSettingsGeneralPage() {
|
|||
<SettingsLayout title="Site Settings" type="site">
|
||||
{site && (
|
||||
<div>
|
||||
<label className="label">Icon</label>
|
||||
<label className="form-label">Icon</label>
|
||||
<AvatarForm
|
||||
site={site.id}
|
||||
name={site.name}
|
||||
|
|
@ -69,7 +69,7 @@ export default function SiteSettingsGeneralPage() {
|
|||
<Input required label="Name" id="name" {...form.register("name")} />
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<label htmlFor="description" className="label">
|
||||
<label htmlFor="description" className="form-label">
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
|
|
|
|||
Loading…
Reference in New Issue