From 38212dcde99fad25ff221a7f0387a541541769a6 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Thu, 27 Apr 2023 06:22:37 -0500 Subject: [PATCH 1/5] chore: refactor to move section dropdown to separate component --- src/app/components/NavBar.module.css | 22 ------- src/app/components/NavBar.tsx | 60 +------------------ src/app/components/SectionDropdown.module.css | 21 +++++++ src/app/components/SectionDropdown.tsx | 58 ++++++++++++++++++ 4 files changed, 82 insertions(+), 79 deletions(-) create mode 100644 src/app/components/SectionDropdown.module.css create mode 100644 src/app/components/SectionDropdown.tsx diff --git a/src/app/components/NavBar.module.css b/src/app/components/NavBar.module.css index 00bcdef..3a44ffb 100644 --- a/src/app/components/NavBar.module.css +++ b/src/app/components/NavBar.module.css @@ -77,28 +77,6 @@ } } -.dropdownSelect { - color: #64adac; - background-color: inherit; - border: none; - border-radius: 5px; - cursor: pointer; - font-size: 1rem; - font-weight: bold; - padding: 0 1rem; -} - -.dropdownSelect:focus-visible { - outline: none; -} - -.selectItem { - color: #64adac; - cursor: pointer; - font-weight: bold; - margin: 1rem; -} - .navbarToggle { cursor: pointer; display: none; diff --git a/src/app/components/NavBar.tsx b/src/app/components/NavBar.tsx index b31fd32..b728ed0 100644 --- a/src/app/components/NavBar.tsx +++ b/src/app/components/NavBar.tsx @@ -1,10 +1,11 @@ 'use client'; import Link from 'next/link'; -import { Fragment, useState } from 'react'; +import { useState } from 'react'; import { themes, useThemeContext } from '../theme'; -import { Doc, DocsStructure } from '../types/types'; +import { DocsStructure } from '../types/types'; import styles from './NavBar.module.css'; +import SectionDropdown from './SectionDropdown'; function VersionsDropdown({ version, @@ -94,61 +95,6 @@ function VersionsDropdown({ ); } -function SectionDropdownGroup({ doc }: { doc: Doc }) { - return ( - - {doc.copy && doc.example && ( - - )} - {doc.children && doc.children.length > 0 && ( - - {doc.children.map(child => ( - - ))} - - )} - - ); -} - -function SectionDropdown({ - version, -}: { - version: DocsStructure; -}) { - const handleSelectChange = (e: any) => { - const selectedOption = e.target.value; - location.hash = selectedOption - .replaceAll(' ', '-') - .toLowerCase(); - }; - - return ( - - ); -} - export default function NavBar({ version, }: { diff --git a/src/app/components/SectionDropdown.module.css b/src/app/components/SectionDropdown.module.css new file mode 100644 index 0000000..6893287 --- /dev/null +++ b/src/app/components/SectionDropdown.module.css @@ -0,0 +1,21 @@ +.dropdownSelect { + color: #64adac; + background-color: inherit; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 1rem; + font-weight: bold; + padding: 0 1rem; +} + +.dropdownSelect:focus-visible { + outline: none; +} + +.selectItem { + color: #64adac; + cursor: pointer; + font-weight: bold; + margin: 1rem; +} \ No newline at end of file diff --git a/src/app/components/SectionDropdown.tsx b/src/app/components/SectionDropdown.tsx new file mode 100644 index 0000000..f188cd3 --- /dev/null +++ b/src/app/components/SectionDropdown.tsx @@ -0,0 +1,58 @@ +import { Fragment } from 'react'; +import { Doc, DocsStructure } from '../types/types'; +import styles from './SectionDropdown.module.css'; + +function SectionDropdownGroup({ doc }: { doc: Doc }) { + return ( + + {doc.copy && doc.example && ( + + )} + {doc.children && doc.children.length > 0 && ( + + {doc.children.map(child => ( + + ))} + + )} + + ); +} + +export default function SectionDropdown({ + version, +}: { + version: DocsStructure; +}) { + const handleSelectChange = (e: any) => { + const selectedOption = e.target.value; + location.hash = selectedOption + .replaceAll(' ', '-') + .toLowerCase(); + }; + + return ( + + ); +} From 6dc5c67d8b53a1ea8eadccaaf4cebcc515781663 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Thu, 27 Apr 2023 06:25:29 -0500 Subject: [PATCH 2/5] chore: rename section dropdown group to section dropdown option --- src/app/components/SectionDropdown.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/components/SectionDropdown.tsx b/src/app/components/SectionDropdown.tsx index f188cd3..e31e155 100644 --- a/src/app/components/SectionDropdown.tsx +++ b/src/app/components/SectionDropdown.tsx @@ -2,7 +2,7 @@ import { Fragment } from 'react'; import { Doc, DocsStructure } from '../types/types'; import styles from './SectionDropdown.module.css'; -function SectionDropdownGroup({ doc }: { doc: Doc }) { +function SectionDropdownOption({ doc }: { doc: Doc }) { return ( {doc.copy && doc.example && ( @@ -50,7 +50,10 @@ export default function SectionDropdown({ > {version.docs.map(doc => { return ( - + ); })} From 7cb9cf24f736d8c857c4d818a5e2c039a5ad3d7e Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Thu, 27 Apr 2023 07:54:36 -0500 Subject: [PATCH 3/5] feat: add observer to page component --- src/app/components/Page.tsx | 33 ++++++++++++++++++++- src/docs/version_002/authentication/copy.md | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/app/components/Page.tsx b/src/app/components/Page.tsx index bd5c5b4..1ce34c2 100644 --- a/src/app/components/Page.tsx +++ b/src/app/components/Page.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useEffect, useRef, useState } from 'react'; import { themes, useThemeContext } from '../theme'; import { DocSection, DocsStructure } from '../types/types'; import Main from './Main'; @@ -16,11 +17,41 @@ export default function Page({ }) { const { theme } = useThemeContext(); const themeStyles = themes[theme]; + const docRef = useRef(null); + const [currentSection, setCurrentSection] = useState(''); + + useEffect(() => { + const titles = + document.querySelectorAll( + '.section-title' + ); + + const observer = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + setCurrentSection(entry.target.id); + } + }); + }, + { + root: null, + rootMargin: '-10% 0% -80% 0%', + threshold: 1, + } + ); + + titles.forEach(title => observer.observe(title)); + + return () => { + titles.forEach(title => observer.unobserve(title)); + }; + }, []); return (
-
+
diff --git a/src/docs/version_002/authentication/copy.md b/src/docs/version_002/authentication/copy.md index 7b5c9e5..0650998 100644 --- a/src/docs/version_002/authentication/copy.md +++ b/src/docs/version_002/authentication/copy.md @@ -1,4 +1,4 @@ -# Authentication {% #authentication %} +# Authentication {% #authentication .section-title %} The Onpsring API uses API keys to authenticate requests. These keys are specific to a given Onspring instance. You can view and manage your API keys from within your instance. From dfb50ca6bab339e3a283d5bcd18e1ca52e06dd8b Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Thu, 27 Apr 2023 16:03:27 -0500 Subject: [PATCH 4/5] Feat: Sync Navbar Section Dropdown Added section context that can be set when section heading scrolls into browser viewport and it's value can be used to set the current value of the navbar dropdown. Added kebab case utility method for converting title to element id. --- src/app/components/Main.tsx | 2 +- src/app/components/NavBar.tsx | 2 +- src/app/components/Page.tsx | 24 +++++++++++++-------- src/app/components/SectionDropdown.tsx | 12 +++++++---- src/app/components/SideBar.tsx | 13 +++++------- src/app/context/section.tsx | 29 ++++++++++++++++++++++++++ src/app/{ => context}/theme.tsx | 0 src/app/layout.tsx | 7 +++++-- src/app/utils/stringUtils.ts | 3 +++ 9 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 src/app/context/section.tsx rename src/app/{ => context}/theme.tsx (100%) create mode 100644 src/app/utils/stringUtils.ts diff --git a/src/app/components/Main.tsx b/src/app/components/Main.tsx index 6f97a05..d2e00aa 100644 --- a/src/app/components/Main.tsx +++ b/src/app/components/Main.tsx @@ -1,7 +1,7 @@ 'use client'; import { Fragment } from 'react'; -import { themes, useThemeContext } from '../theme'; +import { themes, useThemeContext } from '../context/theme'; import { DocSection } from '../types/types'; import styles from './Main.module.css'; import Section from './Section'; diff --git a/src/app/components/NavBar.tsx b/src/app/components/NavBar.tsx index b728ed0..a22c71a 100644 --- a/src/app/components/NavBar.tsx +++ b/src/app/components/NavBar.tsx @@ -2,7 +2,7 @@ import Link from 'next/link'; import { useState } from 'react'; -import { themes, useThemeContext } from '../theme'; +import { themes, useThemeContext } from '../context/theme'; import { DocsStructure } from '../types/types'; import styles from './NavBar.module.css'; import SectionDropdown from './SectionDropdown'; diff --git a/src/app/components/Page.tsx b/src/app/components/Page.tsx index 1ce34c2..98408e3 100644 --- a/src/app/components/Page.tsx +++ b/src/app/components/Page.tsx @@ -1,7 +1,8 @@ 'use client'; -import { useEffect, useRef, useState } from 'react'; -import { themes, useThemeContext } from '../theme'; +import { useEffect } from 'react'; +import { useSectionContext } from '../context/section'; +import { themes, useThemeContext } from '../context/theme'; import { DocSection, DocsStructure } from '../types/types'; import Main from './Main'; import NavBar from './NavBar'; @@ -17,26 +18,31 @@ export default function Page({ }) { const { theme } = useThemeContext(); const themeStyles = themes[theme]; - const docRef = useRef(null); - const [currentSection, setCurrentSection] = useState(''); + + const { setSection } = useSectionContext(); useEffect(() => { const titles = document.querySelectorAll( - '.section-title' + 'article:nth-child(1) > h1' ); const observer = new IntersectionObserver( entries => { entries.forEach(entry => { if (entry.isIntersecting) { - setCurrentSection(entry.target.id); + setSection(entry.target.id); + history.pushState( + null, + '', + `#${entry.target.id}` + ); } }); }, { root: null, - rootMargin: '-10% 0% -80% 0%', + rootMargin: '-10% 0% -70% 0%', threshold: 1, } ); @@ -46,12 +52,12 @@ export default function Page({ return () => { titles.forEach(title => observer.unobserve(title)); }; - }, []); + }, [setSection]); return (
-
+
diff --git a/src/app/components/SectionDropdown.tsx b/src/app/components/SectionDropdown.tsx index e31e155..83c430d 100644 --- a/src/app/components/SectionDropdown.tsx +++ b/src/app/components/SectionDropdown.tsx @@ -1,5 +1,7 @@ import { Fragment } from 'react'; +import { useSectionContext } from '../context/section'; import { Doc, DocsStructure } from '../types/types'; +import { toKebabCase } from '../utils/stringUtils'; import styles from './SectionDropdown.module.css'; function SectionDropdownOption({ doc }: { doc: Doc }) { @@ -9,6 +11,7 @@ function SectionDropdownOption({ doc }: { doc: Doc }) { @@ -17,6 +20,7 @@ function SectionDropdownOption({ doc }: { doc: Doc }) { {doc.children.map(child => (