From 31f9d2662290028f624479e3654b97b458d41d7d Mon Sep 17 00:00:00 2001 From: Mike Barkmin Date: Sun, 9 Oct 2022 11:24:04 +0200 Subject: [PATCH] expand with animation --- .changeset/four-snakes-kiss.md | 7 ++++ .changeset/polite-scissors-visit.md | 5 +++ packages/element-collapsible/package.json | 3 +- packages/element-collapsible/src/index.css | 11 +++-- packages/element-collapsible/src/index.tsx | 16 ++++--- pnpm-lock.yaml | 42 +++++++++++++++++++ templates/simple/package.json | 1 + templates/simple/src/colors.css | 2 +- .../simple/src/components/Navigation.tsx | 39 ++++++++++++----- templates/simple/src/styles.css | 12 ++++++ templates/simple/src/utils/navigation.ts | 1 + website/book/configuration/section.md | 1 + 12 files changed, 117 insertions(+), 23 deletions(-) create mode 100644 .changeset/four-snakes-kiss.md create mode 100644 .changeset/polite-scissors-visit.md diff --git a/.changeset/four-snakes-kiss.md b/.changeset/four-snakes-kiss.md new file mode 100644 index 00000000..611e604d --- /dev/null +++ b/.changeset/four-snakes-kiss.md @@ -0,0 +1,7 @@ +--- +"hyperbook-simple-template": minor +--- + +The sections can now be opened and closed. The active page will always +start opened. For each section you can overwrite the default expanded +state by adding `expanded: true` to the frontmatter of the section. diff --git a/.changeset/polite-scissors-visit.md b/.changeset/polite-scissors-visit.md new file mode 100644 index 00000000..9f4c6838 --- /dev/null +++ b/.changeset/polite-scissors-visit.md @@ -0,0 +1,5 @@ +--- +"@hyperbook/element-collapsible": minor +--- + +The Element Collapsible now has a little animation when opening and closing. diff --git a/packages/element-collapsible/package.json b/packages/element-collapsible/package.json index b3b6bfb6..fb8377a1 100644 --- a/packages/element-collapsible/package.json +++ b/packages/element-collapsible/package.json @@ -41,7 +41,8 @@ "dependencies": { "@hyperbook/provider": "workspace:*", "@hyperbook/store": "workspace:*", - "object-hash": "3.0.0" + "object-hash": "3.0.0", + "react-collapsed": "^3.4.0" }, "peerDependencies": { "react": "18.x", diff --git a/packages/element-collapsible/src/index.css b/packages/element-collapsible/src/index.css index 55d64770..dee1875c 100644 --- a/packages/element-collapsible/src/index.css +++ b/packages/element-collapsible/src/index.css @@ -9,6 +9,11 @@ padding: 8px 16px; transition: 0.3s; border-radius: 4px; + margin-bottom: 10px; +} + +.element-collapsible.button + .element-collapsible.content { + margin-top: -10px; } .element-collapsible.button.active { @@ -29,15 +34,9 @@ .element-collapsible.content { border-top: none; - max-height: 0; - overflow: hidden; margin-bottom: 10px; } -.element-collapsible.content.active { - max-height: 100%; -} - .element-collapsible .inner { border-style: solid; border-width: 1px; diff --git a/packages/element-collapsible/src/index.tsx b/packages/element-collapsible/src/index.tsx index 85efe7bd..edbb71ed 100644 --- a/packages/element-collapsible/src/index.tsx +++ b/packages/element-collapsible/src/index.tsx @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from "react-redux"; import { createSlice, PayloadAction } from "@hyperbook/store"; import { useActivePageId } from "@hyperbook/provider"; import "./index.css"; +import useCollapse from "react-collapsed"; type DirectiveCollapsibleProps = { children?: ReactNode; @@ -15,15 +16,18 @@ const DirectiveCollapsible: FC = ({ id, title, }) => { - const [activePageId] = useActivePageId(); - if (!id) { id = title; } + const [activePageId] = useActivePageId(); id = activePageId + "." + id; let active = useSelector(selectActive(id)); + const { getCollapseProps, getToggleProps } = useCollapse({ + isExpanded: active, + }); + const dispatch = useDispatch(); const toggleActive = () => { @@ -33,17 +37,19 @@ const DirectiveCollapsible: FC = ({ return ( <>
= ({ ); }; -type ElementCollapsibleState = Record; +type ElementCollapsibleState = Record; const initialState: ElementCollapsibleState = {}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 770a37d5..fadb52b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -133,11 +133,13 @@ importers: "@types/react-dom": 18.0.6 object-hash: 3.0.0 react: 18.2.0 + react-collapsed: ^3.4.0 react-dom: 18.2.0 dependencies: "@hyperbook/provider": link:../provider "@hyperbook/store": link:../store object-hash: 3.0.0 + react-collapsed: 3.4.0_biqbaboplfbrettd7655fr4n2y devDependencies: "@types/object-hash": 2.2.1 "@types/react": 18.0.21 @@ -569,6 +571,7 @@ importers: next: 12.3.1 next-remote-watch: 2.0.0 react: 18.2.0 + react-collapsed: ^3.4.0 react-dom: 18.2.0 react-icons: 4.4.0 react-redux: 8.0.4 @@ -597,6 +600,7 @@ importers: gray-matter: 4.0.3 next: 12.3.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 + react-collapsed: 3.4.0_biqbaboplfbrettd7655fr4n2y react-dom: 18.2.0_react@18.2.0 react-icons: 4.4.0_react@18.2.0 react-redux: 8.0.4_wr4jmv5xrjbe6vbq33me5wwo2a @@ -11514,6 +11518,13 @@ packages: } dev: true + /performance-now/2.1.0: + resolution: + { + integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, + } + dev: false + /picocolors/1.0.0: resolution: { @@ -11951,6 +11962,15 @@ packages: engines: { node: ">=10" } dev: true + /raf/3.4.1: + resolution: + { + integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==, + } + dependencies: + performance-now: 2.1.0 + dev: false + /randombytes/2.1.0: resolution: { @@ -12011,6 +12031,21 @@ packages: strip-json-comments: 2.0.1 dev: true + /react-collapsed/3.4.0_biqbaboplfbrettd7655fr4n2y: + resolution: + { + integrity: sha512-v/xsvxGb7bOGHb+zkAeSjb4VAP+P5CDyvhGkIqKwHuHDHCnEjnFFRHgfPz/y3N4mLsWyOZ1QWH27EDz5/mRHXQ==, + } + peerDependencies: + react: ">=16.8" + react-dom: ">=16.8" + dependencies: + raf: 3.4.1 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + tiny-warning: 1.0.3 + dev: false + /react-dom/18.2.0_react@18.2.0: resolution: { @@ -13876,6 +13911,13 @@ packages: setimmediate: 1.0.5 dev: true + /tiny-warning/1.0.3: + resolution: + { + integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==, + } + dev: false + /title-case/3.0.3: resolution: { diff --git a/templates/simple/package.json b/templates/simple/package.json index 8506d85e..918930be 100644 --- a/templates/simple/package.json +++ b/templates/simple/package.json @@ -29,6 +29,7 @@ "gray-matter": "4.0.3", "next": "12.3.1", "react": "18.2.0", + "react-collapsed": "^3.4.0", "react-dom": "18.2.0", "react-icons": "4.4.0", "react-redux": "8.0.4", diff --git a/templates/simple/src/colors.css b/templates/simple/src/colors.css index 2b605c53..51351ab1 100644 --- a/templates/simple/src/colors.css +++ b/templates/simple/src/colors.css @@ -84,7 +84,7 @@ header.inverted > .branding { border-color: var(--color-spacer); } -.section > .name.empty { +.section .name.empty { color: var(--color-text-deactivated); } diff --git a/templates/simple/src/components/Navigation.tsx b/templates/simple/src/components/Navigation.tsx index a2f7c92e..9d35ae58 100644 --- a/templates/simple/src/components/Navigation.tsx +++ b/templates/simple/src/components/Navigation.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import useCollapse from "react-collapsed"; import { Navigation as NavigationProps, Section as SectionProps, @@ -28,20 +29,38 @@ const Section = ({ href, pages, sections, + expanded, current, }: S) => { + const isActive = current?.href.startsWith(href); + const { getCollapseProps, getToggleProps, isExpanded } = useCollapse({ + defaultExpanded: isActive || expanded, + }); return (
- {virtual ? null : isEmpty ? ( - {name} - ) : ( - - - {name} - - - )} -
+
+ {virtual ? null : isEmpty ? ( + {name} + ) : ( + + {name} + + )} + +
+
{pages.length > 0 && (
    {pages diff --git a/templates/simple/src/styles.css b/templates/simple/src/styles.css index 7d31257b..b03bdc9b 100644 --- a/templates/simple/src/styles.css +++ b/templates/simple/src/styles.css @@ -255,6 +255,7 @@ nav li + li { } .section > .name { + display: flex; text-decoration: none; padding: 10px; border-width: 1px; @@ -263,6 +264,17 @@ nav li + li { user-select: none; } +.section > .name > .label { + flex: 1; +} + +.section > .name > .toggle { + text-align: right; + background: none; + border: none; + font-size: 13px; +} + .section .section { margin-left: 16px; margin-bottom: 0px; diff --git a/templates/simple/src/utils/navigation.ts b/templates/simple/src/utils/navigation.ts index d6fbcb5f..fdd45173 100644 --- a/templates/simple/src/utils/navigation.ts +++ b/templates/simple/src/utils/navigation.ts @@ -20,6 +20,7 @@ export type Page = { export type Section = Omit & { hide?: boolean; virtual?: boolean; + expanded?: boolean; pages: Page[]; // md-files sections: Section[]; // folders }; diff --git a/website/book/configuration/section.md b/website/book/configuration/section.md index 3ada6819..1949af3e 100644 --- a/website/book/configuration/section.md +++ b/website/book/configuration/section.md @@ -19,6 +19,7 @@ To summarize, here are the properties you can set in the frontmatter: | :------- | :--------------------------------------------------------------------------------------------------------------------- | | ... | Every Property from a [page](/configuration/page) | | virtual | Everything will appear on the same level as the parent. Be aware that the index property does not work across folders. | +| expanded | Defines whether the section is expanded on page load. | If the `index.md` file only contains a front matter and is otherwise empty, it will appear in the navigation as a non-clickable item.