diff --git a/client/components/edit-document/document.module.css b/client/components/edit-document/document.module.css index 135f89c..98b9e9b 100644 --- a/client/components/edit-document/document.module.css +++ b/client/components/edit-document/document.module.css @@ -1,41 +1,48 @@ +.card { + max-width: var(--main-content); + margin: var(--gap) auto; + padding: 2; + border: 1px solid var(--light-gray); +} + .input { - background: #efefef; + background: #efefef; } .descriptionContainer { - display: flex; - flex-direction: column; - min-height: 400px; - overflow: auto; + display: flex; + flex-direction: column; + min-height: 400px; + overflow: auto; } .fileNameContainer { - display: flex; - justify-content: space-between; - align-items: center; - height: 36px; + display: flex; + justify-content: space-between; + align-items: center; + height: 36px; } .fileNameContainer { - display: flex; - align-content: center; + display: flex; + align-content: center; } .fileNameContainer > div { - /* Override geist-ui styling */ - margin: 0 !important; + /* Override geist-ui styling */ + margin: 0 !important; } .textarea { - height: 100%; + height: 100%; } .actionWrapper { - position: relative; - z-index: 1; + position: relative; + z-index: 1; } .actionWrapper .actions { - position: absolute; - right: 0; + position: absolute; + right: 0; } diff --git a/client/components/edit-document/formatting-icons/index.tsx b/client/components/edit-document/formatting-icons/index.tsx index 1ef79c8..5224466 100644 --- a/client/components/edit-document/formatting-icons/index.tsx +++ b/client/components/edit-document/formatting-icons/index.tsx @@ -34,9 +34,6 @@ const FormattingIcons = ({ textareaRef, setText }: { textareaRef?: RefObject void } -const DownloadButton = ({ rawLink }: { rawLink?: string }) => { - return (
- - - -
) -} - - const Document = ({ remove, title, content, setTitle, setContent, initialTab = 'edit', skeleton, handleOnContentChange }: Props) => { const codeEditorRef = useRef(null) const [tab, setTab] = useState(initialTab) @@ -98,7 +70,7 @@ const Document = ({ remove, title, content, setTitle, setContent, initialTab = ' return ( <> - +
- +
- - +
) } diff --git a/client/lib/hooks/use-debounce.ts b/client/lib/hooks/use-debounce.ts new file mode 100644 index 0000000..ed3e522 --- /dev/null +++ b/client/lib/hooks/use-debounce.ts @@ -0,0 +1,18 @@ +// useDebounce.js +import { useState, useEffect } from 'react'; + +export default function useDebounce(value: any, delay: number) { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +} diff --git a/client/lib/render-markdown.tsx b/client/lib/render-markdown.tsx index 4ddaebf..0e1d79b 100644 --- a/client/lib/render-markdown.tsx +++ b/client/lib/render-markdown.tsx @@ -1,7 +1,18 @@ -import { marked } from 'marked' +import { marked, Lexer } from 'marked' import Highlight, { defaultProps, Language, } from 'prism-react-renderer' import { renderToStaticMarkup } from 'react-dom/server' + + +// image sizes. DDoS Safe? +const imageSizeLink = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?(?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/; +//@ts-ignore +Lexer.rules.inline.normal.link = imageSizeLink; +//@ts-ignore +Lexer.rules.inline.gfm.link = imageSizeLink; +//@ts-ignore +Lexer.rules.inline.breaks.link = imageSizeLink; + //@ts-ignore delete defaultProps.theme // import linkStyles from '../components/link/link.module.css' diff --git a/client/package.json b/client/package.json index 68b3ff4..42b9303 100644 --- a/client/package.json +++ b/client/package.json @@ -19,6 +19,7 @@ "cookie": "^0.4.2", "dotenv": "^16.0.0", "js-cookie": "^3.0.1", + "lodash.debounce": "^4.0.8", "marked": "^4.0.12", "next": "^12.1.1-canary.15", "postcss": "^8.4.12", diff --git a/client/pages/_app.tsx b/client/pages/_app.tsx index 2a11ca6..2013345 100644 --- a/client/pages/_app.tsx +++ b/client/pages/_app.tsx @@ -18,7 +18,7 @@ function MyApp({ Component, pageProps }: AppProps) { const skeletonHighlightColor = 'var(--lighter-gray)' return ( - <> +
@@ -33,13 +33,13 @@ function MyApp({ Component, pageProps }: AppProps) { Drift - + - +
) } diff --git a/client/styles/globals.css b/client/styles/globals.css index 3a5cf48..bc983b3 100644 --- a/client/styles/globals.css +++ b/client/styles/globals.css @@ -3,122 +3,145 @@ @import "./inter.css"; :root { - /* Spacing */ - --gap-quarter: 0.25rem; - --gap-half: 0.5rem; - --gap: 1rem; - --gap-double: 2rem; - --small-gap: 4rem; - --big-gap: 4rem; - --main-content: 55rem; - --radius: 8px; - --inline-radius: 5px; + /* Spacing */ + --gap-quarter: 0.25rem; + --gap-half: 0.5rem; + --gap: 1rem; + --gap-double: 2rem; + --small-gap: 4rem; + --big-gap: 4rem; + --main-content: 55rem; + --radius: 8px; + --inline-radius: 5px; - /* Typography */ - --font-sans: "Inter", -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; - --font-mono: ui-monospace, "SFMono-Regular", "Consolas", "Liberation Mono", - "Menlo", monospace; + /* Typography */ + --font-sans: "Inter", -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, + Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + --font-mono: ui-monospace, "SFMono-Regular", "Consolas", "Liberation Mono", + "Menlo", monospace; - /* Transitions */ - --transition: 0.1s ease-in-out; - --transition-slow: 0.3s ease-in-out; + /* Transitions */ + --transition: 0.1s ease-in-out; + --transition-slow: 0.3s ease-in-out; - --page-nav-height: 64px; - --token: #999; - --comment: #999; - --keyword: #fff; - --name: #fff; - --highlight: #2e2e2e; + --page-nav-height: 64px; + --token: #999; + --comment: #999; + --keyword: #fff; + --name: #fff; + --highlight: #2e2e2e; + + /* Dark Mode Colors */ + --bg: #131415; + --fg: #fafbfc; + --gray: #666; + --light-gray: #444; + --lighter-gray: #222; + --lightest-gray: #1a1a1a; + --article-color: #eaeaea; + --header-bg: rgba(19, 20, 21, 0.45); + --gray-alpha: rgba(255, 255, 255, 0.5); + --selection: rgba(255, 255, 255, 0.99); } [data-theme="light"] { - --token: #666; - --comment: #999; - --keyword: #000; - --name: #333; - --highlight: #eaeaea; + --token: #666; + --comment: #999; + --keyword: #000; + --name: #333; + --highlight: #eaeaea; + + --bg: #fff; + --fg: #000; + --gray: #888; + --light-gray: #dedede; + --lighter-gray: #f5f5f5; + --lightest-gray: #fafafa; + --article-color: #212121; + --header-bg: rgba(255, 255, 255, 0.8); + --gray-alpha: rgba(19, 20, 21, 0.5); + --selection: rgba(0, 0, 0, 0.99); } * { - box-sizing: border-box; + box-sizing: border-box; } ::selection { - text-shadow: none; - background: var(--selection); + text-shadow: none; + background: var(--selection); } html, body { - padding: 0; - margin: 0; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + padding: 0; + margin: 0; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } body { - min-height: 100vh; - font-family: var(--font-sans); - display: flex; - flex-direction: column; + min-height: 100vh; + font-family: var(--font-sans); + display: flex; + flex-direction: column; } p, li { - letter-spacing: -0.33px; - font-size: 1.125rem; + letter-spacing: -0.33px; + font-size: 1.125rem; } blockquote { - font-style: italic; - margin: 0; - padding-left: 1rem; - border-left: 3px solid var(--light-gray); + font-style: italic; + margin: 0; + padding-left: 1rem; + border-left: 3px solid var(--light-gray); } a.reset { - outline: none; - text-decoration: none; + outline: none; + text-decoration: none; } pre, 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; + font-family: var(--font-sans); + font-size: 1rem; + padding: 2px 7px; + font-weight: 600; + background: var(--lighter-gray); + border-radius: 5px; } @media print { - :root { - --bg: #fff; - --fg: #000; - --gray: #888; - --light-gray: #dedede; - --lighter-gray: #f5f5f5; - --lightest-gray: #fafafa; - --article-color: #212121; - --header-bg: rgba(255, 255, 255, 0.8); - --gray-alpha: rgba(19, 20, 21, 0.5); - --selection: rgba(0, 0, 0, 0.99); + :root { + --bg: #fff; + --fg: #000; + --gray: #888; + --light-gray: #dedede; + --lighter-gray: #f5f5f5; + --lightest-gray: #fafafa; + --article-color: #212121; + --header-bg: rgba(255, 255, 255, 0.8); + --gray-alpha: rgba(19, 20, 21, 0.5); + --selection: rgba(0, 0, 0, 0.99); - --token: #666; - --comment: #999; - --keyword: #000; - --name: #333; - --highlight: #eaeaea; - } + --token: #666; + --comment: #999; + --keyword: #000; + --name: #333; + --highlight: #eaeaea; + } - * { - text-shadow: none !important; - } + * { + text-shadow: none !important; + } } diff --git a/client/styles/markdown.css b/client/styles/markdown.css index 670d20d..b95ae64 100644 --- a/client/styles/markdown.css +++ b/client/styles/markdown.css @@ -1,129 +1,125 @@ article { - max-width: var(--main-content); - margin: 0 auto; - line-height: 1.9; + max-width: var(--main-content); + margin: 0 auto; + line-height: 1.9; } article > * + * { - margin-top: 2em; + margin-top: 2em; } article img { - max-width: 100%; - /* width: var(--main-content); */ - width: auto; - margin: auto; - display: block; - border-radius: var(--radius); + max-width: 100%; + margin: auto; } article [id]::before { - content: ""; - display: block; - height: 70px; - margin-top: -70px; - visibility: hidden; + content: ""; + display: block; + height: 70px; + margin-top: -70px; + visibility: hidden; } /* Lists */ article ul { - padding: 0; - list-style-position: inside; - list-style-type: circle; + padding: 0; + list-style-position: inside; + list-style-type: circle; } article ol { - padding: 0; - list-style-position: inside; + padding: 0; + list-style-position: inside; } article ul li.reset { - display: flex; - align-items: flex-start; + display: flex; + align-items: flex-start; - list-style-type: none; - margin-left: -0.5rem; + list-style-type: none; + margin-left: -0.5rem; } article ul li.reset .check { - display: flex; - align-items: center; - margin-right: 0.51rem; + display: flex; + align-items: center; + margin-right: 0.51rem; } /* Checkbox */ input[type="checkbox"] { - vertical-align: middle; - appearance: none; - display: inline-block; - background-origin: border-box; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - background-color: var(--bg); - color: var(--fg); - border: 1px solid var(--fg); - border-radius: 3px; + vertical-align: middle; + appearance: none; + display: inline-block; + background-origin: border-box; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + background-color: var(--bg); + color: var(--fg); + border: 1px solid var(--fg); + border-radius: 3px; } input[type="checkbox"]:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='black' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293z'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='black' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293z'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; } html[data-theme="light"] input[type="checkbox"]:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293z'/%3e%3c/svg%3e"); + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M5.707 7.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L7 8.586 5.707 7.293z'/%3e%3c/svg%3e"); } input[type="checkbox"]:focus { - outline: none; - border-color: var(--fg); + outline: none; + border-color: var(--fg); } /* Code Snippets */ .token-line:not(:last-child) { - min-height: 1.4rem; + min-height: 1.4rem; } article *:not(pre) > code { - font-weight: 500; - font-family: var(--font-sans); + font-weight: 500; + font-family: var(--font-sans); } article li > p { - font-family: var(--font-mono); - display: inline-block; + font-family: var(--font-mono); + display: inline-block; } article pre { - overflow-x: auto; - border-radius: var(--inline-radius); - line-height: 1.8; - padding: 1rem; - font-size: 0.875rem; + overflow-x: auto; + border-radius: var(--inline-radius); + line-height: 1.8; + padding: 1rem; + font-size: 0.875rem; } /* Linkable Headers */ .header-link { - color: inherit; - text-decoration: none; + color: inherit; + text-decoration: none; } .header-link::after { - opacity: 0; - content: "#"; - margin-left: var(--gap-half); + opacity: 0; + content: "#"; + margin-left: var(--gap-half); } .header-link:hover::after { - opacity: 1; + opacity: 1; } diff --git a/client/yarn.lock b/client/yarn.lock index 80eced4..145dc56 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2278,6 +2278,11 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"