client: add next-themes support for CSS variables
This commit is contained in:
parent
186d536175
commit
6045200ac4
17 changed files with 146 additions and 254 deletions
25
client/components/app/index.tsx
Normal file
25
client/components/app/index.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { GeistProvider, CssBaseline } from "@geist-ui/core"
|
||||||
|
import type { NextComponentType, NextPageContext } from "next"
|
||||||
|
import { SkeletonTheme } from "react-loading-skeleton"
|
||||||
|
import { useTheme } from 'next-themes'
|
||||||
|
const App = ({
|
||||||
|
Component,
|
||||||
|
pageProps,
|
||||||
|
}: {
|
||||||
|
Component: NextComponentType<NextPageContext, any, any>
|
||||||
|
pageProps: any
|
||||||
|
}) => {
|
||||||
|
const skeletonBaseColor = 'var(--light-gray)'
|
||||||
|
const skeletonHighlightColor = 'var(--lighter-gray)'
|
||||||
|
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
return (<GeistProvider themeType={theme}>
|
||||||
|
<SkeletonTheme baseColor={skeletonBaseColor} highlightColor={skeletonHighlightColor}>
|
||||||
|
<CssBaseline />
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</SkeletonTheme>
|
||||||
|
</GeistProvider>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
|
@ -16,15 +16,6 @@
|
||||||
height: var(--input-height);
|
height: var(--input-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
--input-height: 2.5rem;
|
|
||||||
--input-border: 1px solid var(--light-gray);
|
|
||||||
--input-border-focus: 1px solid var(--gray);
|
|
||||||
--input-border-error: 1px solid var(--red);
|
|
||||||
--input-bg: var(--bg);
|
|
||||||
--input-fg: var(--fg);
|
|
||||||
--input-placeholder-fg: var(--light-gray); */
|
|
||||||
|
|
||||||
.button:hover,
|
.button:hover,
|
||||||
.button:focus {
|
.button:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import MoonIcon from '@geist-ui/icons/moon'
|
import MoonIcon from '@geist-ui/icons/moon'
|
||||||
import SunIcon from '@geist-ui/icons/sun'
|
import SunIcon from '@geist-ui/icons/sun'
|
||||||
// import { useAllThemes, useTheme } from '@geist-ui/core'
|
// import { useAllThemes, useTheme } from '@geist-ui/core'
|
||||||
import styles from './header.module.css'
|
import styles from './header.module.css'
|
||||||
import { ThemeProps } from '@lib/types'
|
|
||||||
import { Select } from '@geist-ui/core'
|
import { Select } from '@geist-ui/core'
|
||||||
|
import { useTheme } from 'next-themes'
|
||||||
|
|
||||||
const Controls = ({ changeTheme, theme }: ThemeProps) => {
|
const Controls = () => {
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
const { theme, setTheme } = useTheme()
|
||||||
|
useEffect(() => setMounted(true), [])
|
||||||
|
if (!mounted) return null
|
||||||
const switchThemes = () => {
|
const switchThemes = () => {
|
||||||
changeTheme()
|
if (theme === 'dark') {
|
||||||
|
setTheme('light')
|
||||||
|
} else {
|
||||||
|
setTheme('dark')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -16,7 +16,7 @@ import NewIcon from '@geist-ui/icons/plusCircle';
|
||||||
import YourIcon from '@geist-ui/icons/list'
|
import YourIcon from '@geist-ui/icons/list'
|
||||||
import MoonIcon from '@geist-ui/icons/moon';
|
import MoonIcon from '@geist-ui/icons/moon';
|
||||||
import SunIcon from '@geist-ui/icons/sun';
|
import SunIcon from '@geist-ui/icons/sun';
|
||||||
import useTheme from "@lib/hooks/use-theme";
|
import { useTheme } from "next-themes"
|
||||||
import { Button } from "@geist-ui/core";
|
import { Button } from "@geist-ui/core";
|
||||||
|
|
||||||
type Tab = {
|
type Tab = {
|
||||||
|
@ -37,7 +37,7 @@ const Header = () => {
|
||||||
const isMobile = useMediaQuery('xs', { match: 'down' })
|
const isMobile = useMediaQuery('xs', { match: 'down' })
|
||||||
const { signedIn: isSignedIn, signout } = useSignedIn()
|
const { signedIn: isSignedIn, signout } = useSignedIn()
|
||||||
const [pages, setPages] = useState<Tab[]>([])
|
const [pages, setPages] = useState<Tab[]>([])
|
||||||
const { changeTheme, theme } = useTheme()
|
const { setTheme, theme } = useTheme()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setBodyHidden(expanded)
|
setBodyHidden(expanded)
|
||||||
}, [expanded, setBodyHidden])
|
}, [expanded, setBodyHidden])
|
||||||
|
@ -60,9 +60,8 @@ const Header = () => {
|
||||||
{
|
{
|
||||||
name: isMobile ? "Change theme" : "",
|
name: isMobile ? "Change theme" : "",
|
||||||
onClick: function () {
|
onClick: function () {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined')
|
||||||
changeTheme();
|
setTheme(theme === 'light' ? 'dark' : 'light');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
icon: theme === 'light' ? <MoonIcon /> : <SunIcon />,
|
icon: theme === 'light' ? <MoonIcon /> : <SunIcon />,
|
||||||
condition: true,
|
condition: true,
|
||||||
|
@ -73,9 +72,9 @@ const Header = () => {
|
||||||
if (isSignedIn)
|
if (isSignedIn)
|
||||||
setPages([
|
setPages([
|
||||||
{
|
{
|
||||||
name: 'home',
|
name: 'new',
|
||||||
icon: <HomeIcon />,
|
icon: <NewIcon />,
|
||||||
value: 'home',
|
value: 'new',
|
||||||
href: '/'
|
href: '/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -116,58 +115,7 @@ const Header = () => {
|
||||||
])
|
])
|
||||||
// TODO: investigate deps causing infinite loop
|
// TODO: investigate deps causing infinite loop
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [changeTheme, isMobile, isSignedIn, theme])
|
}, [isMobile, isSignedIn, theme])
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// const pageList: Tab[] = [
|
|
||||||
// {
|
|
||||||
// name: "Home",
|
|
||||||
// href: "/",
|
|
||||||
// icon: <HomeIcon />,
|
|
||||||
// condition: !isSignedIn,
|
|
||||||
// value: "home"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "New",
|
|
||||||
// href: "/new",
|
|
||||||
// icon: <NewIcon />,
|
|
||||||
// condition: isSignedIn,
|
|
||||||
// value: "new"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "Yours",
|
|
||||||
// href: "/mine",
|
|
||||||
// icon: <YourIcon />,
|
|
||||||
// condition: isSignedIn,
|
|
||||||
// value: "mine"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "Sign out",
|
|
||||||
// href: "/signout",
|
|
||||||
// icon: <SignOutIcon />,
|
|
||||||
// condition: isSignedIn,
|
|
||||||
// value: "signout"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "Sign in",
|
|
||||||
// href: "/signin",
|
|
||||||
// icon: <SignInIcon />,
|
|
||||||
// condition: !isSignedIn,
|
|
||||||
// value: "signin"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "Sign up",
|
|
||||||
// href: "/signup",
|
|
||||||
// icon: <SignUpIcon />,
|
|
||||||
// condition: !isSignedIn,
|
|
||||||
// value: "signup"
|
|
||||||
// },
|
|
||||||
|
|
||||||
// ]
|
|
||||||
|
|
||||||
// setPages(pageList.filter(page => page.condition))
|
|
||||||
// }, [changeTheme, isMobile, isSignedIn, theme])
|
|
||||||
|
|
||||||
|
|
||||||
const onTabChange = useCallback((tab: string) => {
|
const onTabChange = useCallback((tab: string) => {
|
||||||
if (typeof window === 'undefined') return
|
if (typeof window === 'undefined') return
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import useTheme from "@lib/hooks/use-theme"
|
|
||||||
import { memo, useEffect, useState } from "react"
|
import { memo, useEffect, useState } from "react"
|
||||||
import styles from './preview.module.css'
|
import styles from './preview.module.css'
|
||||||
|
|
||||||
|
@ -13,17 +12,14 @@ type Props = {
|
||||||
const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => {
|
const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => {
|
||||||
const [preview, setPreview] = useState<string>(content || "")
|
const [preview, setPreview] = useState<string>(content || "")
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true)
|
const [isLoading, setIsLoading] = useState<boolean>(true)
|
||||||
const { theme } = useTheme()
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchPost() {
|
async function fetchPost() {
|
||||||
if (fileId) {
|
if (fileId) {
|
||||||
const resp = await fetch(`/server-api/files/html/${fileId}`, {
|
const resp = await fetch(`/server-api/files/html/${fileId}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
})
|
})
|
||||||
console.log(resp)
|
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
const res = await resp.text()
|
const res = await resp.text()
|
||||||
console.log(res)
|
|
||||||
setPreview(res)
|
setPreview(res)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,11 +75,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdownPreview h5 {
|
.markdownPreview h5 {
|
||||||
font-size: 0.875rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdownPreview h6 {
|
.markdownPreview h6 {
|
||||||
font-size: 0.75rem;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdownPreview ul {
|
.markdownPreview ul {
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
import remarkGfm from "remark-gfm"
|
|
||||||
import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/prism-async-light';
|
|
||||||
import rehypeSlug from 'rehype-slug'
|
|
||||||
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
|
|
||||||
import rehypeRaw from 'rehype-raw'
|
|
||||||
|
|
||||||
// @ts-ignore because of no types in remark-a11y-emoji
|
|
||||||
// import a11yEmoji from '@fec/remark-a11y-emoji';
|
|
||||||
|
|
||||||
import styles from './preview.module.css'
|
|
||||||
import dark from 'react-syntax-highlighter/dist/cjs/styles/prism/vsc-dark-plus'
|
|
||||||
import light from 'react-syntax-highlighter/dist/cjs/styles/prism/vs'
|
|
||||||
import useSharedState from "@lib/hooks/use-shared-state";
|
|
||||||
import ReactMarkdown from "react-markdown";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
content: string | undefined
|
|
||||||
height: number | string
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReactMarkdownPreview = ({ content, height }: Props) => {
|
|
||||||
const [themeType] = useSharedState<string>('theme')
|
|
||||||
|
|
||||||
return (<div style={{ height }}>
|
|
||||||
<ReactMarkdown className={styles.markdownPreview}
|
|
||||||
remarkPlugins={[remarkGfm]}
|
|
||||||
rehypePlugins={[rehypeSlug, [rehypeAutolinkHeadings, { behavior: 'wrap' }], rehypeRaw]}
|
|
||||||
components={{
|
|
||||||
code({ node, inline, className, children, ...props }) {
|
|
||||||
const match = /language-(\w+)/.exec(className || '')
|
|
||||||
return !inline && match ? (
|
|
||||||
<SyntaxHighlighter
|
|
||||||
lineNumberStyle={{
|
|
||||||
minWidth: "2.25rem"
|
|
||||||
}}
|
|
||||||
customStyle={{
|
|
||||||
padding: 0,
|
|
||||||
margin: 0,
|
|
||||||
background: 'transparent'
|
|
||||||
}}
|
|
||||||
codeTagProps={{
|
|
||||||
style: { background: 'transparent', color: 'inherit' }
|
|
||||||
}}
|
|
||||||
style={themeType === 'dark' ? dark : light}
|
|
||||||
showLineNumbers={true}
|
|
||||||
language={match[1]}
|
|
||||||
PreTag="div"
|
|
||||||
{...props}
|
|
||||||
>{String(children).replace(/\n$/, '')}</SyntaxHighlighter>
|
|
||||||
) : (
|
|
||||||
<code className={className} {...props}>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
{content || ""}
|
|
||||||
</ReactMarkdown></div>)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default ReactMarkdownPreview
|
|
|
@ -1,18 +1,18 @@
|
||||||
// useDebounce.js
|
// useDebounce.js
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from "react"
|
||||||
|
|
||||||
export default function useDebounce(value: any, delay: number) {
|
export default function useDebounce(value: any, delay: number) {
|
||||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
const [debouncedValue, setDebouncedValue] = useState(value)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = setTimeout(() => {
|
const handler = setTimeout(() => {
|
||||||
setDebouncedValue(value);
|
setDebouncedValue(value)
|
||||||
}, delay);
|
}, delay)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(handler);
|
clearTimeout(handler)
|
||||||
};
|
}
|
||||||
}, [value, delay]);
|
}, [value, delay])
|
||||||
|
|
||||||
return debouncedValue;
|
return debouncedValue
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { useCallback, useEffect } from "react"
|
|
||||||
import useSharedState from "./use-shared-state"
|
|
||||||
|
|
||||||
const useTheme = () => {
|
|
||||||
const isClient = typeof window === "object"
|
|
||||||
const [themeType, setThemeType] = useSharedState<string>("theme", "light")
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isClient) return
|
|
||||||
const storedTheme = localStorage.getItem("drift-theme")
|
|
||||||
if (storedTheme) {
|
|
||||||
setThemeType(storedTheme)
|
|
||||||
}
|
|
||||||
}, [isClient, setThemeType])
|
|
||||||
|
|
||||||
const changeTheme = useCallback(() => {
|
|
||||||
setThemeType((last) => {
|
|
||||||
const newTheme = last === "dark" ? "light" : "dark"
|
|
||||||
localStorage.setItem("drift-theme", newTheme)
|
|
||||||
return newTheme
|
|
||||||
})
|
|
||||||
}, [setThemeType])
|
|
||||||
|
|
||||||
return { theme: themeType, changeTheme }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useTheme
|
|
|
@ -60,20 +60,20 @@ renderer.listitem = (text, task, checked) => {
|
||||||
return `<li>${text}</li>`
|
return `<li>${text}</li>`
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.code = (code: string, language: string) => {
|
// renderer.code = (code: string, language: string) => {
|
||||||
return renderToStaticMarkup(
|
// return renderToStaticMarkup(
|
||||||
<pre>
|
// <pre>
|
||||||
{/* {title && <code>{title} </code>} */}
|
// {/* {title && <code>{title} </code>} */}
|
||||||
{/* {language && title && <code style={{}}> {language} </code>} */}
|
// {/* {language && title && <code style={{}}> {language} </code>} */}
|
||||||
<Code
|
// <Code
|
||||||
language={language}
|
// language={language}
|
||||||
// title={title}
|
// // title={title}
|
||||||
code={code}
|
// code={code}
|
||||||
// highlight={highlight}
|
// // highlight={highlight}
|
||||||
/>
|
// />
|
||||||
</pre>
|
// </pre>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
gfm: true,
|
gfm: true,
|
||||||
|
@ -95,8 +95,7 @@ const Code = ({ code, language, highlight, title, ...props }: {
|
||||||
if (!language)
|
if (!language)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<code {...props} dangerouslySetInnerHTML={{ __html: code }
|
<code {...props} dangerouslySetInnerHTML={{ __html: code }} />
|
||||||
} />
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
5
client/lib/types.d.ts
vendored
5
client/lib/types.d.ts
vendored
|
@ -1,10 +1,5 @@
|
||||||
export type PostVisibility = "unlisted" | "private" | "public" | "protected"
|
export type PostVisibility = "unlisted" | "private" | "public" | "protected"
|
||||||
|
|
||||||
export type ThemeProps = {
|
|
||||||
theme: "light" | "dark" | string
|
|
||||||
changeTheme: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Document = {
|
export type Document = {
|
||||||
title: string
|
title: string
|
||||||
content: string
|
content: string
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"marked": "^4.0.12",
|
"marked": "^4.0.12",
|
||||||
"next": "^12.1.1-canary.15",
|
"next": "^12.1.1-canary.15",
|
||||||
|
"next-themes": "^0.1.1",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
"postcss-hover-media-feature": "^1.0.2",
|
"postcss-hover-media-feature": "^1.0.2",
|
||||||
|
|
|
@ -4,8 +4,10 @@ import type { AppProps as NextAppProps } from "next/app";
|
||||||
import 'react-loading-skeleton/dist/skeleton.css'
|
import 'react-loading-skeleton/dist/skeleton.css'
|
||||||
import { SkeletonTheme } from 'react-loading-skeleton';
|
import { SkeletonTheme } from 'react-loading-skeleton';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import useTheme from '@lib/hooks/use-theme';
|
import { CssBaseline, GeistProvider, Themes } from '@geist-ui/core';
|
||||||
import { CssBaseline, GeistProvider } from '@geist-ui/core';
|
import { useTheme, ThemeProvider } from 'next-themes'
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import App from '@components/app';
|
||||||
|
|
||||||
type AppProps<P = any> = {
|
type AppProps<P = any> = {
|
||||||
pageProps: P;
|
pageProps: P;
|
||||||
|
@ -13,12 +15,8 @@ type AppProps<P = any> = {
|
||||||
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
const { theme } = useTheme()
|
|
||||||
const skeletonBaseColor = 'var(--light-gray)'
|
|
||||||
const skeletonHighlightColor = 'var(--lighter-gray)'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-theme={theme}>
|
<div>
|
||||||
<Head>
|
<Head>
|
||||||
<meta charSet="utf-8" />
|
<meta charSet="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
@ -33,12 +31,9 @@ function MyApp({ Component, pageProps }: AppProps) {
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
<title>Drift</title>
|
<title>Drift</title>
|
||||||
</Head>
|
</Head>
|
||||||
<GeistProvider themeType={theme}>
|
<ThemeProvider defaultTheme="system">
|
||||||
<SkeletonTheme baseColor={skeletonBaseColor} highlightColor={skeletonHighlightColor}>
|
<App Component={Component} pageProps={pageProps} />
|
||||||
<CssBaseline />
|
</ThemeProvider>
|
||||||
<Component {...pageProps} />
|
|
||||||
</SkeletonTheme>
|
|
||||||
</GeistProvider>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ const renderMarkdown: NextApiHandler = async (req, res) => {
|
||||||
}
|
}
|
||||||
const type = fileType()
|
const type = fileType()
|
||||||
let contentToRender: string = content || ""
|
let contentToRender: string = content || ""
|
||||||
|
|
||||||
if (!renderAsMarkdown.includes(type)) {
|
if (!renderAsMarkdown.includes(type)) {
|
||||||
contentToRender = `~~~${type}
|
contentToRender = `~~~${type}
|
||||||
${content}
|
${content}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
--highlight: #2e2e2e;
|
--highlight: #2e2e2e;
|
||||||
|
|
||||||
/* Dark Mode Colors */
|
/* Dark Mode Colors */
|
||||||
--bg: #131415;
|
--bg: #0e0e0e;
|
||||||
--fg: #fafbfc;
|
--fg: #fafbfc;
|
||||||
--gray: #666;
|
--gray: #666;
|
||||||
--light-gray: #444;
|
--light-gray: #444;
|
||||||
|
@ -94,10 +94,34 @@ body {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
p,
|
p {
|
||||||
li {
|
overflow-wrap: break-word;
|
||||||
letter-spacing: -0.33px;
|
hyphens: auto;
|
||||||
font-size: 1.125rem;
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
picture,
|
||||||
|
video,
|
||||||
|
canvas,
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
picture,
|
||||||
|
video,
|
||||||
|
canvas,
|
||||||
|
svg {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
|
@ -117,15 +141,6 @@ code {
|
||||||
font-family: var(--font-mono) !important;
|
font-family: var(--font-mono) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbd {
|
|
||||||
font-family: var(--font-sans);
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: 2px 7px;
|
|
||||||
font-weight: 600;
|
|
||||||
background: var(--lighter-gray);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
:root {
|
:root {
|
||||||
--bg: #fff;
|
--bg: #fff;
|
||||||
|
@ -150,3 +165,8 @@ kbd {
|
||||||
text-shadow: none !important;
|
text-shadow: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#root,
|
||||||
|
#__next {
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
|
@ -2893,6 +2893,11 @@ needle@^2.5.2:
|
||||||
iconv-lite "^0.4.4"
|
iconv-lite "^0.4.4"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
|
|
||||||
|
next-themes@^0.1.1:
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.1.1.tgz#122113a458bf1d1be5ffed66778ab924c106f82a"
|
||||||
|
integrity sha512-Iqxt6rhS/KfK/iHJ0tfFjTcdLEAI0AgwFuAFrMwLOPK5e+MI3I+fzyvBoS+VaOS+NldUiazurhgwYhrfV0VXsQ==
|
||||||
|
|
||||||
next-unused@^0.0.6:
|
next-unused@^0.0.6:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/next-unused/-/next-unused-0.0.6.tgz#dbefa300bf5586e33d5bfde909130fb19ab04a64"
|
resolved "https://registry.yarnpkg.com/next-unused/-/next-unused-0.0.6.tgz#dbefa300bf5586e33d5bfde909130fb19ab04a64"
|
||||||
|
|
|
@ -42,7 +42,6 @@ files.get("/html/:id", async (req, res, next) => {
|
||||||
return res.status(404).json({ error: "File not found" })
|
return res.status(404).json({ error: "File not found" })
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(file.html)
|
|
||||||
res.setHeader('Content-Type', 'text/plain')
|
res.setHeader('Content-Type', 'text/plain')
|
||||||
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)
|
||||||
|
|
Loading…
Reference in a new issue