From df8a7f820de4daa3268cbcac6d8237c5636f931a Mon Sep 17 00:00:00 2001 From: DrMint <29893320+DrMint@users.noreply.github.com> Date: Fri, 10 Feb 2023 13:17:45 +0100 Subject: [PATCH] Fix subpanel closing on mobile+ improvements --- .vscode/settings.json | 3 +- package-lock.json | 42 +- package.json | 6 +- src/components/AppLayout.tsx | 109 ++-- .../Chronicles/ChroniclePreview.tsx | 13 +- src/components/Chronicles/ChroniclesList.tsx | 4 + src/components/Containers/ContentPanel.tsx | 16 +- src/components/Containers/DownPressable.tsx | 2 +- src/components/Containers/UpPressable.tsx | 5 +- src/components/Inputs/Button.tsx | 10 +- src/components/Inputs/Link.tsx | 7 +- src/components/Inputs/Select.tsx | 5 +- src/components/Inputs/Switch.tsx | 12 +- src/components/Markdown/Markdawn.tsx | 20 +- src/components/PanelComponents/NavOption.tsx | 2 +- src/components/Panels/MainPanel.tsx | 27 +- src/components/Panels/SearchPopup.tsx | 11 +- src/components/PostPage.tsx | 100 ++-- src/components/PreviewCard.tsx | 17 +- src/contexts/LightBoxProvider.tsx | 23 +- src/contexts/appLayout.ts | 31 -- src/contexts/atoms.ts | 40 +- src/contexts/localData.ts | 34 +- src/helpers/component.tsx | 16 +- src/helpers/others.ts | 14 + src/pages/_app.tsx | 4 +- src/pages/archives/videos/v/[uid].tsx | 12 +- src/pages/chronicles/[slug]/index.tsx | 43 +- src/pages/contents/[slug].tsx | 497 +++++++++--------- src/pages/contents/all.tsx | 10 +- src/pages/contents/folder/[slug].tsx | 10 +- src/pages/index.tsx | 4 +- src/pages/library/[slug]/index.tsx | 9 +- src/pages/library/[slug]/reader.tsx | 2 +- src/pages/wiki/[slug]/index.tsx | 4 +- src/styles/tippy.css | 4 +- 36 files changed, 627 insertions(+), 541 deletions(-) delete mode 100644 src/contexts/appLayout.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index ce0dc93..3747951 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "css.lint.unknownAtRules": "ignore", - "editor.rulers": [100] + "editor.rulers": [100], + "typescript.preferences.importModuleSpecifier": "non-relative" } diff --git a/package-lock.json b/package-lock.json index 2ff4a58..343de73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "cuid": "^2.1.8", "intl-messageformat": "^10.3.0", "isomorphic-dompurify": "^0.26.0", - "jotai": "^2.0.0", + "jotai": "^2.0.1", "markdown-to-jsx": "^7.1.9", "marked": "^4.2.12", "material-symbols": "^0.4.4", @@ -35,7 +35,7 @@ "turndown": "^7.1.1", "ua-parser-js": "^1.0.33", "usehooks-ts": "^2.9.1", - "zod": "^3.20.5" + "zod": "^3.20.6" }, "devDependencies": { "@digitak/esrun": "^3.2.19", @@ -60,7 +60,7 @@ "eslint-plugin-import": "^2.27.5", "graphql": "^16.6.0", "graphql-request": "^5.1.0", - "next-sitemap": "^3.1.50", + "next-sitemap": "^3.1.52", "prettier": "^2.8.4", "prettier-plugin-tailwindcss": "^0.2.2", "tailwindcss": "^3.2.6", @@ -7496,9 +7496,9 @@ } }, "node_modules/jotai": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.0.0.tgz", - "integrity": "sha512-04G0CRZQgp3xrFAezd6X14psZ2TRGekHeYMBcbDJ/BR8ZJQPS+j0YkMTxUxyG58HJnN2+adfj5sWQWoqgtp1XQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.0.1.tgz", + "integrity": "sha512-b/BpBFkv3nq8HgT6YX5h5/y9VfKIn9OL1dO6gd9bWTgKt6LLe24VIMURTDwSYS888XfubuRQlbepb5IQGAtmcQ==", "engines": { "node": ">=12.20.0" }, @@ -8150,9 +8150,9 @@ } }, "node_modules/next-sitemap": { - "version": "3.1.50", - "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-3.1.50.tgz", - "integrity": "sha512-BnxAbjOK1zVcYvpZ4sYfhPXcL3ajLh/AIJLR39YKrhFxrD92KkiAGuVaKhfpoQLUf+ldsGBkGpdml2N5Qdd1KA==", + "version": "3.1.52", + "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-3.1.52.tgz", + "integrity": "sha512-tY469i4QRV1PwM9BoL+HdKYBCJ83IQl3PmUNapG/Hxp0MIYIw1hINU8E+Edf5Kr8vHXfVzPqDoul/Abu2P0vkw==", "dev": true, "funding": [ { @@ -10741,9 +10741,9 @@ } }, "node_modules/zod": { - "version": "3.20.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.5.tgz", - "integrity": "sha512-BTAAliwfoB9dWf2hC+TXlyWKk/YTqRGZjHQR0WLC2A2pzierWo7KuQ1ebjS4SNaFaxg/lDItzl9/QTgLjcHbgw==", + "version": "3.20.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", + "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -16385,9 +16385,9 @@ "requires": {} }, "jotai": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.0.0.tgz", - "integrity": "sha512-04G0CRZQgp3xrFAezd6X14psZ2TRGekHeYMBcbDJ/BR8ZJQPS+j0YkMTxUxyG58HJnN2+adfj5sWQWoqgtp1XQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.0.1.tgz", + "integrity": "sha512-b/BpBFkv3nq8HgT6YX5h5/y9VfKIn9OL1dO6gd9bWTgKt6LLe24VIMURTDwSYS888XfubuRQlbepb5IQGAtmcQ==", "requires": {} }, "js-sdsl": { @@ -16871,9 +16871,9 @@ } }, "next-sitemap": { - "version": "3.1.50", - "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-3.1.50.tgz", - "integrity": "sha512-BnxAbjOK1zVcYvpZ4sYfhPXcL3ajLh/AIJLR39YKrhFxrD92KkiAGuVaKhfpoQLUf+ldsGBkGpdml2N5Qdd1KA==", + "version": "3.1.52", + "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-3.1.52.tgz", + "integrity": "sha512-tY469i4QRV1PwM9BoL+HdKYBCJ83IQl3PmUNapG/Hxp0MIYIw1hINU8E+Edf5Kr8vHXfVzPqDoul/Abu2P0vkw==", "dev": true, "requires": { "@corex/deepmerge": "^4.0.29", @@ -18719,9 +18719,9 @@ "dev": true }, "zod": { - "version": "3.20.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.5.tgz", - "integrity": "sha512-BTAAliwfoB9dWf2hC+TXlyWKk/YTqRGZjHQR0WLC2A2pzierWo7KuQ1ebjS4SNaFaxg/lDItzl9/QTgLjcHbgw==" + "version": "3.20.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", + "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==" } } } diff --git a/package.json b/package.json index 9ba26d9..eb2b0ea 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cuid": "^2.1.8", "intl-messageformat": "^10.3.0", "isomorphic-dompurify": "^0.26.0", - "jotai": "^2.0.0", + "jotai": "^2.0.1", "markdown-to-jsx": "^7.1.9", "marked": "^4.2.12", "material-symbols": "^0.4.4", @@ -47,7 +47,7 @@ "turndown": "^7.1.1", "ua-parser-js": "^1.0.33", "usehooks-ts": "^2.9.1", - "zod": "^3.20.5" + "zod": "^3.20.6" }, "devDependencies": { "@digitak/esrun": "^3.2.19", @@ -72,7 +72,7 @@ "eslint-plugin-import": "^2.27.5", "graphql": "^16.6.0", "graphql-request": "^5.1.0", - "next-sitemap": "^3.1.50", + "next-sitemap": "^3.1.52", "prettier": "^2.8.4", "prettier-plugin-tailwindcss": "^0.2.2", "tailwindcss": "^3.2.6", diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index 1dc8dc0..318ee8f 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -77,15 +77,19 @@ export const AppLayout = ({ }, }); - const turnSubIntoContent = isDefined(subPanel) && isUndefined(contentPanel); + const turnSubIntoContent = isDefined(subPanel) && isUndefined(contentPanel) && is1ColumnLayout; return (
+ {/* Content panel */} +
+ {isDefined(contentPanel) ? ( + contentPanel + ) : turnSubIntoContent ? ( + subPanel + ) : ( + + )} +
+ {/* Background when navbar is opened */}
@@ -140,57 +160,11 @@ export const AppLayout = ({ />
- {/* Content panel */} -
- {isDefined(contentPanel) ? ( - contentPanel - ) : ( - - )} -
- - {/* Sub panel */} - {isDefined(subPanel) && ( -
- {subPanel} -
- )} - - {/* Main panel */} -
- -
- {/* Navbar */}
)}
+ + {/* Sub panel */} + {isDefined(subPanel) && !turnSubIntoContent && ( +
+ {subPanel} +
+ )} + + {/* Main panel */} +
+ +
); }; diff --git a/src/components/Chronicles/ChroniclePreview.tsx b/src/components/Chronicles/ChroniclePreview.tsx index f718b55..aaea763 100644 --- a/src/components/Chronicles/ChroniclePreview.tsx +++ b/src/components/Chronicles/ChroniclePreview.tsx @@ -1,4 +1,4 @@ -import { useCallback } from "react"; +import { MouseEventHandler, useCallback } from "react"; import { DatePickerFragment } from "graphql/generated"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; @@ -17,12 +17,21 @@ interface Props { url: string; active?: boolean; disabled?: boolean; + onClick?: MouseEventHandler; } -export const ChroniclePreview = ({ date, url, title, active, disabled }: Props): JSX.Element => ( +export const ChroniclePreview = ({ + date, + url, + title, + active, + disabled, + onClick, +}: Props): JSX.Element => ( diff --git a/src/components/Chronicles/ChroniclesList.tsx b/src/components/Chronicles/ChroniclesList.tsx index 963083d..fbb6c47 100644 --- a/src/components/Chronicles/ChroniclesList.tsx +++ b/src/components/Chronicles/ChroniclesList.tsx @@ -8,6 +8,8 @@ import { Ico } from "components/Ico"; import { compareDate } from "helpers/date"; import { TranslatedProps } from "types/TranslatedProps"; import { useSmartLanguage } from "hooks/useSmartLanguage"; +import { useAtomSetter } from "helpers/atoms"; +import { atoms } from "contexts/atoms"; /* * ╭─────────────╮ @@ -25,6 +27,7 @@ interface Props { } const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element => { + const setSubPanelOpened = useAtomSetter(atoms.layout.subPanelOpened); const { value: isOpen, toggle: toggleOpen } = useBoolean( chronicles.some((chronicle) => chronicle.attributes?.slug === currentSlug) ); @@ -75,6 +78,7 @@ const ChroniclesList = ({ chronicles, currentSlug, title }: Props): JSX.Element "/#chronicle-", chronicle.attributes.slug )} + onClick={() => setSubPanelOpened(false)} /> )) : chronicle.attributes.translations.length > 0 && ( diff --git a/src/components/Containers/ContentPanel.tsx b/src/components/Containers/ContentPanel.tsx index add70a4..f46e805 100644 --- a/src/components/Containers/ContentPanel.tsx +++ b/src/components/Containers/ContentPanel.tsx @@ -19,6 +19,12 @@ export enum ContentPanelWidthSizes { Full = "full", } +const contentPanelWidthSizesToClassName: Record = { + default: "max-w-2xl", + large: "max-w-4xl", + full: "w-full", +}; + // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ export const ContentPanel = ({ @@ -31,13 +37,9 @@ export const ContentPanel = ({
{children} diff --git a/src/components/Containers/DownPressable.tsx b/src/components/Containers/DownPressable.tsx index 7852ffc..2c93946 100644 --- a/src/components/Containers/DownPressable.tsx +++ b/src/components/Containers/DownPressable.tsx @@ -14,7 +14,7 @@ interface Props { children: React.ReactNode; className?: string; onFocusChanged?: (isFocused: boolean) => void; - onClick?: MouseEventHandler; + onClick?: MouseEventHandler; } // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ diff --git a/src/components/Containers/UpPressable.tsx b/src/components/Containers/UpPressable.tsx index 75b6d5a..a9be0a9 100644 --- a/src/components/Containers/UpPressable.tsx +++ b/src/components/Containers/UpPressable.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { MouseEventHandler, useState } from "react"; import { Link } from "components/Inputs/Link"; import { cIf, cJoin } from "helpers/className"; @@ -8,6 +8,7 @@ interface Props { className?: string; noBackground?: boolean; disabled?: boolean; + onClick?: MouseEventHandler; } export const UpPressable = ({ @@ -16,12 +17,14 @@ export const UpPressable = ({ className, disabled = false, noBackground = false, + onClick, }: Props): JSX.Element => { const [isFocused, setFocused] = useState(false); return ( event.target.blur()} className={cJoin( `group grid cursor-pointer select-none grid-flow-col place-content-center - place-items-center gap-2 rounded-full border border-dark py-3 px-4 + place-items-center gap-2 rounded-full border border-dark leading-none text-dark transition-all`, - cIf(size === "small", "px-3 py-1 text-xs"), + cIf(size === "small", "px-3 py-1 text-xs", "py-3 px-4"), cIf(active, "!border-black bg-black !text-light drop-shadow-lg shadow-black"), cIf( disabled, @@ -74,16 +74,16 @@ export const Button = ({ {isDefined(badgeNumber) && (

{badgeNumber}

)} {isDefinedAndNotEmpty(icon) && ( ; + onClick?: MouseEventHandler; onFocusChanged?: (isFocused: boolean) => void; disabled?: boolean; linkStyled?: boolean; @@ -22,6 +22,7 @@ export const Link = ({ alwaysNewTab, disabled, linkStyled = false, + onClick, onFocusChanged, }: Props): JSX.Element => ( void; + onClick?: MouseEventHandler; } const LinkWrapper = ({ children, className, onFocusChanged, + onClick, alwaysNewTab = false, href, }: LinkWrapperProps & Wrapper) => ( @@ -65,6 +69,7 @@ const LinkWrapper = ({ className={className} target={alwaysNewTab ? "_blank" : "_self"} replace={href.startsWith("#")} + onClick={onClick} onMouseLeave={() => onFocusChanged?.(false)} onMouseDown={() => onFocusChanged?.(true)} onMouseUp={() => onFocusChanged?.(false)}> diff --git a/src/components/Inputs/Select.tsx b/src/components/Inputs/Select.tsx index 2c84120..fd61c54 100644 --- a/src/components/Inputs/Select.tsx +++ b/src/components/Inputs/Select.tsx @@ -58,13 +58,12 @@ export const Select = ({

diff --git a/src/components/Inputs/Switch.tsx b/src/components/Inputs/Switch.tsx index f7b1a7f..fd3a74d 100644 --- a/src/components/Inputs/Switch.tsx +++ b/src/components/Inputs/Switch.tsx @@ -21,10 +21,14 @@ export const Switch = ({ value, onClick, className, disabled = false }: Props):

{ diff --git a/src/components/Markdown/Markdawn.tsx b/src/components/Markdown/Markdawn.tsx index ca9ddea..67d85ce 100644 --- a/src/components/Markdown/Markdawn.tsx +++ b/src/components/Markdown/Markdawn.tsx @@ -1,5 +1,5 @@ import Markdown from "markdown-to-jsx"; -import React, { Fragment, useMemo } from "react"; +import React, { Fragment, MouseEventHandler, useMemo } from "react"; import ReactDOMServer from "react-dom/server"; import { HorizontalLine } from "components/HorizontalLine"; import { Img } from "components/Img"; @@ -218,13 +218,13 @@ export const Markdawn = ({ className, text: rawText }: MarkdawnProps): JSX.Eleme interface TableOfContentsProps { text: string; title?: string; - horizontalLine?: boolean; + onContentClicked?: MouseEventHandler; } export const TableOfContents = ({ text, title, - horizontalLine = false, + onContentClicked, }: TableOfContentsProps): JSX.Element => { const { format } = useFormat(); const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title); @@ -233,17 +233,20 @@ export const TableOfContents = ({ <> {toc.children.length > 0 && ( <> - {horizontalLine && }

{format("table_of_contents")}

- + {{toc.title}}

- +
)} @@ -334,12 +337,14 @@ interface LevelProps { tocchildren: TocInterface[]; parentNumbering: string; allowIntersection?: boolean; + onContentClicked?: MouseEventHandler; } const TocLevel = ({ tocchildren, parentNumbering, allowIntersection = true, + onContentClicked, }: LevelProps): JSX.Element => { const ids = useMemo(() => tocchildren.map((child) => child.slug), [tocchildren]); const currentIntersection = useIntersectionList(ids); @@ -354,7 +359,7 @@ const TocLevel = ({ cIf(allowIntersection && currentIntersection === childIndex, "text-dark") )}> {`${parentNumbering}${childIndex + 1}.`}{" "} - + {{child.title}} @@ -362,6 +367,7 @@ const TocLevel = ({ tocchildren={child.children} parentNumbering={`${parentNumbering}${childIndex + 1}.`} allowIntersection={allowIntersection && currentIntersection === childIndex} + onContentClicked={onContentClicked} /> ))} diff --git a/src/components/PanelComponents/NavOption.tsx b/src/components/PanelComponents/NavOption.tsx index 7c582d0..e8d20f3 100644 --- a/src/components/PanelComponents/NavOption.tsx +++ b/src/components/PanelComponents/NavOption.tsx @@ -23,7 +23,7 @@ interface Props { reduced?: boolean; active?: boolean; disabled?: boolean; - onClick?: MouseEventHandler; + onClick?: MouseEventHandler; } // ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ diff --git a/src/components/Panels/MainPanel.tsx b/src/components/Panels/MainPanel.tsx index 6d15879..bacb85a 100644 --- a/src/components/Panels/MainPanel.tsx +++ b/src/components/Panels/MainPanel.tsx @@ -1,3 +1,4 @@ +import { useCallback } from "react"; import { HorizontalLine } from "components/HorizontalLine"; import { Button } from "components/Inputs/Button"; import { NavOption } from "components/PanelComponents/NavOption"; @@ -21,6 +22,8 @@ export const MainPanel = (): JSX.Element => { const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout); const { format } = useFormat(); const [isMainPanelReduced, setMainPanelReduced] = useAtomPair(atoms.layout.mainPanelReduced); + const setMainPanelOpened = useAtomSetter(atoms.layout.mainPanelOpened); + const closeMainPanel = useCallback(() => setMainPanelOpened(false), [setMainPanelOpened]); const setSettingsOpened = useAtomSetter(atoms.layout.settingsOpened); const setSearchOpened = useAtomSetter(atoms.layout.searchOpened); @@ -53,7 +56,10 @@ export const MainPanel = (): JSX.Element => { )}
- + { placement={isMainPanelReduced ? "right" : "top"}>