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.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..a22c71a 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 { themes, useThemeContext } from '../theme'; -import { Doc, DocsStructure } from '../types/types'; +import { useState } from 'react'; +import { themes, useThemeContext } from '../context/theme'; +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/Page.tsx b/src/app/components/Page.tsx index bd5c5b4..98408e3 100644 --- a/src/app/components/Page.tsx +++ b/src/app/components/Page.tsx @@ -1,6 +1,8 @@ 'use client'; -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,6 +19,41 @@ export default function Page({ const { theme } = useThemeContext(); const themeStyles = themes[theme]; + const { setSection } = useSectionContext(); + + useEffect(() => { + const titles = + document.querySelectorAll( + 'article:nth-child(1) > h1' + ); + + const observer = new IntersectionObserver( + entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + setSection(entry.target.id); + history.pushState( + null, + '', + `#${entry.target.id}` + ); + } + }); + }, + { + root: null, + rootMargin: '-10% 0% -70% 0%', + threshold: 1, + } + ); + + titles.forEach(title => observer.observe(title)); + + return () => { + titles.forEach(title => observer.unobserve(title)); + }; + }, [setSection]); + return (
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..e6ff1a6 --- /dev/null +++ b/src/app/components/SectionDropdown.tsx @@ -0,0 +1,61 @@ +import { useSectionContext } from '../context/section'; +import { Doc, DocsStructure } from '../types/types'; +import { toKebabCase } from '../utils/stringUtils'; +import styles from './SectionDropdown.module.css'; + +export default function SectionDropdown({ + version, +}: { + version: DocsStructure; +}) { + const { section, setSection } = useSectionContext(); + const handleSelectChange = (e: any) => { + setSection(e.target.value); + location.hash = e.target.value; + }; + + const getAllDocs = (docs: Doc[]) => { + let result: Doc[] = []; + + docs.forEach(doc => { + result.push(doc); + + if (doc.children && doc.children.length > 0) { + result = result.concat(getAllDocs(doc.children)); + } + }); + + return result; + }; + + const docs = getAllDocs(version.docs); + + return ( + + ); +} diff --git a/src/app/components/SideBar.tsx b/src/app/components/SideBar.tsx index aebe64c..2f681c2 100644 --- a/src/app/components/SideBar.tsx +++ b/src/app/components/SideBar.tsx @@ -2,8 +2,9 @@ import Link from 'next/link.js'; import { useState } from 'react'; -import { useThemeContext } from '../theme'; -import { Doc, DocsStructure } from '../types/types.js'; +import { useThemeContext } from '../context/theme'; +import { Doc, DocsStructure } from '../types/types'; +import { toKebabCase } from '../utils/stringUtils'; import styles from './SideBar.module.css'; function TreeNode({ doc }: { doc: Doc }) { @@ -19,9 +20,7 @@ function TreeNode({ doc }: { doc: Doc }) {
{doc.copy ? ( {doc.title} @@ -66,9 +65,7 @@ function TreeNode({ doc }: { doc: Doc }) {
) : doc.copy ? ( {doc.title} diff --git a/src/app/context/section.tsx b/src/app/context/section.tsx new file mode 100644 index 0000000..2bd8a0d --- /dev/null +++ b/src/app/context/section.tsx @@ -0,0 +1,29 @@ +'use client'; + +import { + ReactNode, + createContext, + useContext, + useState, +} from 'react'; + +const SectionContext = createContext({}); + +export const SectionContextProvider = ({ + children, +}: { + children: ReactNode; +}) => { + const [section, setSection] = useState('introduction'); + + return ( + + {children} + + ); +}; + +export const useSectionContext: any = () => + useContext(SectionContext); diff --git a/src/app/theme.tsx b/src/app/context/theme.tsx similarity index 100% rename from src/app/theme.tsx rename to src/app/context/theme.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8ef781a..5424df7 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,8 @@ import { Analytics } from '@vercel/analytics/react'; import { ReactNode } from 'react'; +import { SectionContextProvider } from './context/section'; +import { ThemeContextProvider } from './context/theme'; import './globals.css'; -import { ThemeContextProvider } from './theme'; export const metadata = { title: 'Onspring API Docs', @@ -30,7 +31,9 @@ export default function RootLayout({ - {children} + + {children} + diff --git a/src/app/utils/stringUtils.ts b/src/app/utils/stringUtils.ts new file mode 100644 index 0000000..33e83b7 --- /dev/null +++ b/src/app/utils/stringUtils.ts @@ -0,0 +1,3 @@ +export function toKebabCase(str: string): string { + return str.replaceAll(' ', '-').toLowerCase(); +} 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.