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<HTM const newText = `${before}**${selectedText}**${after}` setText(newText) - - // TODO; fails because settext async - textareaRef.current.setSelectionRange(before.length + 2, before.length + 2 + selectedText.length) } }, [setText, textareaRef]) @@ -50,8 +47,6 @@ const FormattingIcons = ({ textareaRef, setText }: { textareaRef?: RefObject<HTM const selectedText = text.substring(selectionStart, selectionEnd) const newText = `${before}*${selectedText}*${after}` setText(newText) - textareaRef.current.focus() - textareaRef.current.setSelectionRange(before.length + 1, before.length + 1 + selectedText.length) } }, [setText, textareaRef]) @@ -71,8 +66,6 @@ const FormattingIcons = ({ textareaRef, setText }: { textareaRef?: RefObject<HTM } const newText = `${before}${formattedText}${after}` setText(newText) - textareaRef.current.focus() - textareaRef.current.setSelectionRange(before.length + 1, before.length + 1 + selectedText.length) } }, [setText, textareaRef]) @@ -92,8 +85,6 @@ const FormattingIcons = ({ textareaRef, setText }: { textareaRef?: RefObject<HTM } const newText = `${before}${formattedText}${after}` setText(newText) - textareaRef.current.focus() - textareaRef.current.setSelectionRange(before.length + 1, before.length + 1 + selectedText.length) } }, [setText, textareaRef]) diff --git a/client/components/edit-document/index.tsx b/client/components/edit-document/index.tsx index 0bd2ff1..5999094 100644 --- a/client/components/edit-document/index.tsx +++ b/client/components/edit-document/index.tsx @@ -23,34 +23,6 @@ type Props = { remove?: () => void } -const DownloadButton = ({ rawLink }: { rawLink?: string }) => { - return (<div className={styles.actionWrapper}> - <ButtonGroup className={styles.actions}> - <Tooltip text="Download"> - <a href={`${rawLink}?download=true`} target="_blank" rel="noopener noreferrer"> - <Button - scale={2 / 3} px={0.6} - icon={<Download />} - auto - aria-label="Download" - /> - </a> - </Tooltip> - <Tooltip text="Open raw in new tab"> - <a href={rawLink} target="_blank" rel="noopener noreferrer"> - <Button - scale={2 / 3} px={0.6} - icon={<ExternalLink />} - auto - aria-label="Open raw file in new tab" - /> - </a> - </Tooltip> - </ButtonGroup> - </div>) -} - - const Document = ({ remove, title, content, setTitle, setContent, initialTab = 'edit', skeleton, handleOnContentChange }: Props) => { const codeEditorRef = useRef<HTMLTextAreaElement>(null) const [tab, setTab] = useState(initialTab) @@ -98,7 +70,7 @@ const Document = ({ remove, title, content, setTitle, setContent, initialTab = ' return ( <> <Spacer height={1} /> - <Card marginBottom={'var(--gap)'} marginTop={'var(--gap)'} style={{ maxWidth: 'var(--main-content)', margin: "0 auto" }}> + <div className={styles.card}> <div className={styles.fileNameContainer}> <Input placeholder="MyFile.md" @@ -138,8 +110,7 @@ const Document = ({ remove, title, content, setTitle, setContent, initialTab = ' </Tabs> </div > - </Card > - <Spacer height={1} /> + </div > </> ) } diff --git a/client/components/post-list/list-item.tsx b/client/components/post-list/list-item.tsx index d35bae1..2eef160 100644 --- a/client/components/post-list/list-item.tsx +++ b/client/components/post-list/list-item.tsx @@ -47,7 +47,7 @@ const ListItem = ({ post }: { post: any }) => { <Divider h="1px" my={0} /> - <Card.Content > + <Card.Content> {post.files.map((file: any) => { return <FilenameInput key={file.id} title={file.title} /> })} diff --git a/client/components/preview/index.tsx b/client/components/preview/index.tsx index c179ad0..f301264 100644 --- a/client/components/preview/index.tsx +++ b/client/components/preview/index.tsx @@ -49,7 +49,7 @@ const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => { fetchPost() }, [content, fileId, title]) return (<> - {isLoading ? <div>Loading...</div> : <article data-theme={theme} className={styles.markdownPreview} dangerouslySetInnerHTML={{ __html: preview }} style={{ + {isLoading ? <div>Loading...</div> : <article className={styles.markdownPreview} dangerouslySetInnerHTML={{ __html: preview }} style={{ height }} />} </>) diff --git a/client/components/preview/preview.module.css b/client/components/preview/preview.module.css index 7287dd4..fe50d74 100644 --- a/client/components/preview/preview.module.css +++ b/client/components/preview/preview.module.css @@ -1,12 +1,12 @@ .markdownPreview pre { - border-radius: 3px; - font-family: "Courier New", Courier, monospace; - font-size: 14px; - line-height: 1.42857143; - margin: 0; - padding: 10px; - white-space: pre-wrap; - word-wrap: break-word; + border-radius: 3px; + font-family: "Courier New", Courier, monospace; + font-size: 14px; + line-height: 1.42857143; + margin: 0; + padding: 10px; + white-space: pre-wrap; + word-wrap: break-word; } .markdownPreview h1, @@ -15,8 +15,8 @@ .markdownPreview h4, .markdownPreview h5, .markdownPreview h6 { - margin-top: 0; - margin-bottom: 0.5rem; + margin-top: 0; + margin-bottom: 0.5rem; } /* Auto-linked headers */ @@ -26,7 +26,7 @@ .markdownPreview h4 a, .markdownPreview h5 a, .markdownPreview h6 a { - color: inherit; + color: inherit; } /* Auto-linked headers */ @@ -36,53 +36,58 @@ .markdownPreview h4 a:hover::after, .markdownPreview h5 a:hover::after, .markdownPreview h6 a:hover::after { - content: "#"; - font-size: 0.7em; - margin-left: 0.25em; - font-weight: normal; - filter: opacity(0.5); + content: "#"; + font-size: 0.7em; + margin-left: 0.25em; + font-weight: normal; + filter: opacity(0.5); } .markdownPreview h1 { - font-size: 2rem; + font-size: 2rem; } .markdownPreview h2 { - font-size: 1.5rem; + font-size: 1.5rem; } .markdownPreview h3 { - font-size: 1.25rem; + font-size: 1.25rem; } .markdownPreview h4 { - font-size: 1rem; + font-size: 1rem; } .markdownPreview h5 { - font-size: 0.875rem; + font-size: 0.875rem; } .markdownPreview h6 { - font-size: 0.75rem; + font-size: 0.75rem; } .markdownPreview ul { - list-style: inside; + list-style: inside; } .markdownPreview ul li::before { - content: ""; + content: ""; } .markdownPreview code { - border-radius: 3px; - white-space: pre-wrap; - word-wrap: break-word; - color: inherit !important; + border-radius: 3px; + white-space: pre-wrap; + word-wrap: break-word; + color: inherit !important; } .markdownPreview code::before, .markdownPreview code::after { - content: ""; + content: ""; +} + +.markdownPreview img { + max-width: 100%; + max-height: 350px; } diff --git a/client/components/view-document/document.module.css b/client/components/view-document/document.module.css index 135f89c..f62781c 100644 --- a/client/components/view-document/document.module.css +++ b/client/components/view-document/document.module.css @@ -1,41 +1,40 @@ -.input { - background: #efefef; +.card { + margin: var(--gap) auto; + padding: var(--gap); + border: 1px solid var(--light-gray); + border-radius: var(--radius); } .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; -} - -.textarea { - height: 100%; + /* Override geist-ui styling */ + margin: 0 !important; } .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/view-document/index.tsx b/client/components/view-document/index.tsx index 213f51e..9c21957 100644 --- a/client/components/view-document/index.tsx +++ b/client/components/view-document/index.tsx @@ -84,7 +84,7 @@ const Document = ({ content, title, initialTab = 'edit', skeleton, id }: Props) return ( <> <Spacer height={1} /> - <Card marginBottom={'var(--gap)'} marginTop={'var(--gap)'} style={{ maxWidth: 980, margin: "0 auto" }}> + <div className={styles.card}> <div className={styles.fileNameContainer}> <Input value={title} @@ -121,8 +121,7 @@ const Document = ({ content, title, initialTab = 'edit', skeleton, id }: Props) </Tabs> </div > - </Card > - <Spacer height={1} /> + </div > </> ) } 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 ( - <> + <div data-theme={theme}> <Head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> @@ -33,13 +33,13 @@ function MyApp({ Component, pageProps }: AppProps) { <meta name="theme-color" content="#ffffff" /> <title>Drift</title> </Head> - <GeistProvider themeType={theme} > + <GeistProvider themeType={theme}> <SkeletonTheme baseColor={skeletonBaseColor} highlightColor={skeletonHighlightColor}> <CssBaseline /> <Component {...pageProps} /> </SkeletonTheme> </GeistProvider> - </> + </div> ) } 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"