refactor getting html for files and previews
This commit is contained in:
parent
c41cf7c5ef
commit
ecd4521403
13 changed files with 70 additions and 1088 deletions
|
@ -1,7 +1,7 @@
|
||||||
import { memo, useEffect, useState } from "react"
|
import { memo, useEffect, useState } from "react"
|
||||||
import styles from "./preview.module.css"
|
import styles from "./preview.module.css"
|
||||||
import "@styles/markdown.css"
|
import "@styles/markdown.css"
|
||||||
import "./marked.css"
|
import "@styles/syntax.css"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
height?: number | string
|
height?: number | string
|
||||||
|
@ -20,35 +20,34 @@ const MarkdownPreview = ({
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true)
|
const [isLoading, setIsLoading] = useState<boolean>(true)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchPost() {
|
async function fetchPost() {
|
||||||
if (fileId) {
|
// POST to avoid query string length limit
|
||||||
const resp = await fetch(`/api/file/html/${fileId}`, {
|
const method = fileId ? "GET" : "POST"
|
||||||
method: "GET"
|
const path = fileId ? `/api/file/html/${fileId}` : "/api/file/get-html"
|
||||||
})
|
const body = fileId
|
||||||
if (resp.ok) {
|
? undefined
|
||||||
const res = await resp.text()
|
: JSON.stringify({
|
||||||
setPreview(res)
|
title: title || "",
|
||||||
setIsLoading(false)
|
content: initial
|
||||||
}
|
})
|
||||||
} else if (content) {
|
|
||||||
const urlQuery = new URLSearchParams({
|
|
||||||
title: title || "",
|
|
||||||
content
|
|
||||||
})
|
|
||||||
|
|
||||||
const resp = await fetch(`/api/file/get-html?${urlQuery}`, {
|
const resp = await fetch(path, {
|
||||||
method: "GET"
|
method: method,
|
||||||
})
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body
|
||||||
|
})
|
||||||
|
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
const res = await resp.text()
|
const res = await resp.text()
|
||||||
setPreview(res)
|
setPreview(res)
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
fetchPost()
|
fetchPost()
|
||||||
}, [content, fileId, title])
|
}, [initial, fileId, title])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
@ -60,7 +59,7 @@ const MarkdownPreview = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MarkdownPreview
|
export default memo(MarkdownPreview)
|
||||||
|
|
||||||
export const StaticPreview = ({
|
export const StaticPreview = ({
|
||||||
content,
|
content,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,6 @@ const getPost = async (id: string) => {
|
||||||
const post = await getPostById(id, true)
|
const post = await getPostById(id, true)
|
||||||
const user = await getCurrentUser()
|
const user = await getCurrentUser()
|
||||||
|
|
||||||
console.log("post is", post)
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return notFound()
|
return notFound()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
@import "./syntax.css";
|
|
||||||
@import "./inter.css";
|
@import "./inter.css";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
@ -71,7 +70,7 @@
|
||||||
--article-color: #212121;
|
--article-color: #212121;
|
||||||
--header-bg: rgba(255, 255, 255, 0.8);
|
--header-bg: rgba(255, 255, 255, 0.8);
|
||||||
--gray-alpha: rgba(19, 20, 21, 0.5);
|
--gray-alpha: rgba(19, 20, 21, 0.5);
|
||||||
--selection: rgba(0, 0, 0, 0.99);
|
--selection: var(0, 0, 0, .6);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
@ -80,7 +79,8 @@
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
background: var(--selection);
|
background: var(--fg) !important;
|
||||||
|
color: var(--bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
.keyword {
|
.keyword {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--keyword);
|
color: var(--darker-gray);
|
||||||
}
|
}
|
||||||
|
|
||||||
.token.operator,
|
.token.operator,
|
||||||
.token.punctuation,
|
.token.punctuation,
|
||||||
.token.string,
|
|
||||||
.token.number,
|
|
||||||
.token.builtin,
|
.token.builtin,
|
||||||
.token.variable {
|
.token.variable {
|
||||||
color: var(--token);
|
color: var(--token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.token.string,
|
||||||
|
.token.number,
|
||||||
|
.token.boolean {
|
||||||
|
color: var(--darker-gray);
|
||||||
|
}
|
||||||
|
|
||||||
.token.comment {
|
.token.comment {
|
||||||
color: var(--comment);
|
color: var(--comment);
|
||||||
}
|
}
|
||||||
|
@ -22,3 +26,4 @@
|
||||||
.token.attr-name {
|
.token.attr-name {
|
||||||
color: var(--name);
|
color: var(--name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,8 @@ export const codeFileExtensions = [
|
||||||
"cxx",
|
"cxx",
|
||||||
"go",
|
"go",
|
||||||
"h",
|
"h",
|
||||||
|
"m",
|
||||||
|
"ha",
|
||||||
"hpp",
|
"hpp",
|
||||||
"htm",
|
"htm",
|
||||||
"html",
|
"html",
|
||||||
|
@ -93,6 +95,7 @@ export const codeFileExtensions = [
|
||||||
"rb",
|
"rb",
|
||||||
"rs",
|
"rs",
|
||||||
"s",
|
"s",
|
||||||
|
"sh",
|
||||||
"sass",
|
"sass",
|
||||||
"scala",
|
"scala",
|
||||||
"scss",
|
"scss",
|
||||||
|
@ -109,7 +112,8 @@ export const codeFileExtensions = [
|
||||||
"xml",
|
"xml",
|
||||||
"y",
|
"y",
|
||||||
"yaml",
|
"yaml",
|
||||||
"zig"
|
"fish",
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
export const allowedFileExtensions = [
|
export const allowedFileExtensions = [
|
||||||
|
|
|
@ -26,20 +26,16 @@ export async function getHtmlFromFile({
|
||||||
}
|
}
|
||||||
const type = fileType()
|
const type = fileType()
|
||||||
let contentToRender: string = content || ""
|
let contentToRender: string = content || ""
|
||||||
|
|
||||||
if (!renderAsMarkdown.includes(type)) {
|
if (!renderAsMarkdown.includes(type)) {
|
||||||
contentToRender = `
|
contentToRender = `
|
||||||
|
|
||||||
~~~${type}
|
~~~${type}
|
||||||
${content}
|
${content}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
`
|
`
|
||||||
} else {
|
} else {
|
||||||
contentToRender = "\n" + content
|
contentToRender = "\n" + content
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = markdown(contentToRender, {
|
const html = markdown(contentToRender)
|
||||||
})
|
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"@mdx-js/react": "^2.1.5",
|
"@mdx-js/react": "^2.1.5",
|
||||||
"@next-auth/prisma-adapter": "^1.0.5",
|
"@next-auth/prisma-adapter": "^1.0.5",
|
||||||
"@prisma/client": "^4.6.1",
|
"@prisma/client": "^4.6.1",
|
||||||
|
"@types/prismjs": "^1.26.0",
|
||||||
"@wcj/markdown-to-html": "^2.1.2",
|
"@wcj/markdown-to-html": "^2.1.2",
|
||||||
"bcrypt": "^5.1.0",
|
"bcrypt": "^5.1.0",
|
||||||
"client-zip": "2.2.1",
|
"client-zip": "2.2.1",
|
||||||
|
@ -33,6 +34,7 @@
|
||||||
"next-mdx-remote": "^4.2.0",
|
"next-mdx-remote": "^4.2.0",
|
||||||
"next-themes": "npm:@wits/next-themes@0.2.7",
|
"next-themes": "npm:@wits/next-themes@0.2.7",
|
||||||
"prism-react-renderer": "^1.3.5",
|
"prism-react-renderer": "^1.3.5",
|
||||||
|
"prismjs": "^1.29.0",
|
||||||
"rc-table": "7.24.1",
|
"rc-table": "7.24.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-datepicker": "4.8.0",
|
"react-datepicker": "4.8.0",
|
||||||
|
|
|
@ -1,47 +1,28 @@
|
||||||
import { withMethods } from "@lib/api-middleware/with-methods"
|
import { withMethods } from "@lib/api-middleware/with-methods"
|
||||||
import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file"
|
import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file"
|
||||||
import { parseQueryParam } from "@lib/server/parse-query-param"
|
import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||||
import { prisma } from "@lib/server/prisma"
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
export default withMethods(
|
export default withMethods(
|
||||||
["GET"],
|
["POST"],
|
||||||
async (req: NextApiRequest, res: NextApiResponse) => {
|
async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const query = req.query
|
const body = req.body
|
||||||
const fileId = parseQueryParam(query.fileId)
|
const content = parseQueryParam(body.content)
|
||||||
const content = parseQueryParam(query.content)
|
const title = parseQueryParam(body.title) || "Untitled"
|
||||||
const title = parseQueryParam(query.title) || "Untitled"
|
|
||||||
|
|
||||||
if (fileId && (content || title)) {
|
if (!content || !title) {
|
||||||
return res.status(400).json({ error: "Too many arguments" })
|
return res.status(400).json({ error: "Missing arguments" })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileId) {
|
const renderedHTML = await getHtmlFromFile({
|
||||||
const file = await prisma.file.findUnique({
|
title,
|
||||||
where: {
|
content
|
||||||
id: fileId
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!file) {
|
res.setHeader("Content-Type", "text/plain")
|
||||||
return res.status(404).json({ error: "File not found" })
|
res.setHeader("Cache-Control", "public, max-age=4800")
|
||||||
}
|
res.status(200).write(renderedHTML)
|
||||||
|
res.end()
|
||||||
return res.json(file.html)
|
return
|
||||||
} else {
|
|
||||||
if (!content || !title) {
|
|
||||||
return res.status(400).json({ error: "Missing arguments" })
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderedHTML = await getHtmlFromFile({
|
|
||||||
title,
|
|
||||||
content
|
|
||||||
})
|
|
||||||
|
|
||||||
res.setHeader("Content-Type", "text/plain")
|
|
||||||
res.status(200).write(renderedHTML)
|
|
||||||
res.end()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
import { prisma } from "@lib/server/prisma"
|
import { prisma } from "@lib/server/prisma"
|
||||||
import { parseQueryParam } from "@lib/server/parse-query-param"
|
import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||||
|
import { withMethods } from "@lib/api-middleware/with-methods"
|
||||||
|
|
||||||
const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
|
const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
const file = await prisma.file.findUnique({
|
const file = await prisma.file.findUnique({
|
||||||
|
@ -17,6 +18,6 @@ const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
res.setHeader("Cache-Control", "public, max-age=4800")
|
res.setHeader("Cache-Control", "public, max-age=4800")
|
||||||
res.status(200).write(file.html)
|
res.status(200).write(file.html)
|
||||||
res.end()
|
res.end()
|
||||||
|
|
||||||
}
|
}
|
||||||
export default getRawFile
|
|
||||||
|
export default withMethods(["GET"], getRawFile)
|
||||||
|
|
|
@ -17,7 +17,6 @@ async function handleGet(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
const id = parseQueryParam(req.query.id)
|
const id = parseQueryParam(req.query.id)
|
||||||
const files = req.query.files ? parseQueryParam(req.query.files) : true
|
const files = req.query.files ? parseQueryParam(req.query.files) : true
|
||||||
|
|
||||||
console.log("post id is", id)
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return res.status(400).json({ error: "Missing id" })
|
return res.status(400).json({ error: "Missing id" })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// a nextjs api handerl
|
// a nextjs api handerl
|
||||||
|
|
||||||
import config from "@lib/config"
|
import config from "@lib/config"
|
||||||
import { getHtmlFromMarkdown } from "@lib/remark-plugins"
|
|
||||||
import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file"
|
import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file"
|
||||||
import markdown from "@wcj/markdown-to-html"
|
|
||||||
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ specifiers:
|
||||||
'@types/jsonwebtoken': ^8.5.9
|
'@types/jsonwebtoken': ^8.5.9
|
||||||
'@types/marked': ^4.0.7
|
'@types/marked': ^4.0.7
|
||||||
'@types/node': 17.0.23
|
'@types/node': 17.0.23
|
||||||
|
'@types/prismjs': ^1.26.0
|
||||||
'@types/react': 18.0.9
|
'@types/react': 18.0.9
|
||||||
'@types/react-datepicker': 4.4.1
|
'@types/react-datepicker': 4.4.1
|
||||||
'@types/react-dom': 18.0.3
|
'@types/react-dom': 18.0.3
|
||||||
|
@ -38,6 +39,7 @@ specifiers:
|
||||||
prettier: 2.6.2
|
prettier: 2.6.2
|
||||||
prism-react-renderer: ^1.3.5
|
prism-react-renderer: ^1.3.5
|
||||||
prisma: ^4.6.1
|
prisma: ^4.6.1
|
||||||
|
prismjs: ^1.29.0
|
||||||
rc-table: 7.24.1
|
rc-table: 7.24.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-datepicker: 4.8.0
|
react-datepicker: 4.8.0
|
||||||
|
@ -71,6 +73,7 @@ dependencies:
|
||||||
'@mdx-js/react': 2.1.5_react@18.2.0
|
'@mdx-js/react': 2.1.5_react@18.2.0
|
||||||
'@next-auth/prisma-adapter': 1.0.5_2pl3b2nwmjya7el2zbe6cwkney
|
'@next-auth/prisma-adapter': 1.0.5_2pl3b2nwmjya7el2zbe6cwkney
|
||||||
'@prisma/client': 4.6.1_prisma@4.6.1
|
'@prisma/client': 4.6.1_prisma@4.6.1
|
||||||
|
'@types/prismjs': 1.26.0
|
||||||
'@wcj/markdown-to-html': 2.1.2
|
'@wcj/markdown-to-html': 2.1.2
|
||||||
bcrypt: 5.1.0
|
bcrypt: 5.1.0
|
||||||
client-zip: 2.2.1
|
client-zip: 2.2.1
|
||||||
|
@ -85,6 +88,7 @@ dependencies:
|
||||||
next-mdx-remote: 4.2.0_biqbaboplfbrettd7655fr4n2y
|
next-mdx-remote: 4.2.0_biqbaboplfbrettd7655fr4n2y
|
||||||
next-themes: /@wits/next-themes/0.2.7_hsmqkug4agizydugca45idewda
|
next-themes: /@wits/next-themes/0.2.7_hsmqkug4agizydugca45idewda
|
||||||
prism-react-renderer: 1.3.5_react@18.2.0
|
prism-react-renderer: 1.3.5_react@18.2.0
|
||||||
|
prismjs: 1.29.0
|
||||||
rc-table: 7.24.1_biqbaboplfbrettd7655fr4n2y
|
rc-table: 7.24.1_biqbaboplfbrettd7655fr4n2y
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-datepicker: 4.8.0_biqbaboplfbrettd7655fr4n2y
|
react-datepicker: 4.8.0_biqbaboplfbrettd7655fr4n2y
|
||||||
|
@ -4381,6 +4385,11 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/engines': 4.6.1
|
'@prisma/engines': 4.6.1
|
||||||
|
|
||||||
|
/prismjs/1.29.0:
|
||||||
|
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/process-nextick-args/2.0.1:
|
/process-nextick-args/2.0.1:
|
||||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
Loading…
Reference in a new issue