Skip to content

Commit

Permalink
Merge pull request #552 from StampyAI/multiple-articles
Browse files Browse the repository at this point in the history
Handle articles in multiple sections
  • Loading branch information
mruwnik authored Mar 15, 2024
2 parents c3c1022 + 0a4a047 commit 2a5551b
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 14 deletions.
12 changes: 9 additions & 3 deletions app/components/Article/KeepGoing/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useLocation} from 'react-router-dom'
import Button from '~/components/Button'
import ListTable from '~/components/Table'
import {ArrowRight} from '~/components/icons-generated'
Expand All @@ -24,7 +25,11 @@ const NextArticle = ({section, next, first}: NextArticleProps) =>
</div>
<div className={`${styles.container} flex-container bordered ${styles.flex_dynamic}`}>
<div className="vertically-centered white default-bold">{next.title}</div>
<Button action={questionUrl(next)} className="vertically-centered primary-alt">
<Button
action={questionUrl(next)}
className="vertically-centered primary-alt"
props={{state: {section: section?.pageid}}}
>
{first ? 'Start' : 'Next'}
<ArrowRight />
</Button>
Expand All @@ -33,9 +38,10 @@ const NextArticle = ({section, next, first}: NextArticleProps) =>
)

export const KeepGoing = ({pageid, relatedQuestions}: Question) => {
const location = useLocation()
const {findSection, getArticle, getNext} = useToC()
const section = findSection(pageid)
const next = getNext(pageid)
const section = findSection(location?.state?.section || pageid)
const next = getNext(pageid, section?.pageid)
const hasRelated = relatedQuestions && relatedQuestions.length > 0
const skipNext = nonContinueSections.includes(section?.pageid || '')

Expand Down
21 changes: 18 additions & 3 deletions app/components/ArticlesDropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ export const ArticlesDropdown = ({toc, categories}: ArticlesDropdownProps) => {
const hide = () => setShown(true)
useEffect(() => setShown(false), [shown])
const mobile = useIsMobile()
const Link = ({to, text, className}: {to: string; text: string; className?: string}) => (
const Link = ({
to,
text,
pageid,
className,
}: {
to: string
text: string
pageid?: string
className?: string
}) => (
<div className={'articles-dropdown-entry ' + (className || '')}>
<LinkElem to={to} onClick={hide}>
<LinkElem to={to} onClick={hide} state={{section: pageid}}>
{text}
</LinkElem>
</div>
Expand All @@ -44,7 +54,12 @@ export const ArticlesDropdown = ({toc, categories}: ArticlesDropdownProps) => {
{toc
.filter((item) => item.category === category)
.map((item: TOCItem) => (
<Link key={`${item.pageid}-${item.title}`} to={questionUrl(item)} text={item.title} />
<Link
key={`${item.pageid}-${item.title}`}
to={questionUrl(item)}
text={item.title}
pageid={item.pageid}
/>
))}
</div>
)
Expand Down
8 changes: 7 additions & 1 deletion app/components/ArticlesNav/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ const Title = ({article, path, current}: Article) => {

return (
<summary className={'articles-title ' + classes}>
{!article.hasText ? article.title : <Link to={questionUrl(article)}>{article.title}</Link>}
{!article.hasText ? (
article.title
) : (
<Link to={questionUrl(article)} state={{section: path && path[0]}}>
{article.title}
</Link>
)}
{!isHeader && <DropdownIcon article={article} path={path} />}
</summary>
)
Expand Down
28 changes: 23 additions & 5 deletions app/hooks/useToC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,29 @@ const useToC = () => {
}

const findSection = (pageid: string): TOCItem | undefined => {
return (toc || []).filter(checkPath(pageid))[0]
const checker = checkPath(pageid)
// Articles can be in multiple sections, or even be sections. It's assumed here that
// the highest level usage should be used, so assuming article "ABC", with the following
// paths:
// * ["123", "432", "ABC"]
// * ["123", "ABC"]
// * ["324", "ABC"]
// * ["ABC"]
// Then that the shorter the path, the better
return (toc || [])
.filter(checker)
.sort((a, b) => (checker(a)?.length || 20) - (checker(b)?.length || 20))[0]
}

const getPath = (pageid: string) => {
const getPath = (pageid: string, sectionId?: string) => {
if (!toc || toc.length === 0) return undefined
return toc.map(checkPath(pageid)).filter(identity)[0]
const paths = toc.map(checkPath(pageid)).filter(identity)

if (sectionId) return paths.filter((p) => p && p[0] === sectionId)[0]
return paths[0]
}

const getNext = (pageid: string): TOCItem | undefined => {
const getNext = (pageid: string, sectionId?: string): TOCItem | undefined => {
type NextItem = {
current?: string
next?: TOCItem
Expand All @@ -47,7 +61,11 @@ const useToC = () => {
return {current: previous}
}

return toc?.map((section) => findNext('', section).next).filter(identity)[0]
// Assume that next articles must always be in the same section
return toc
?.filter(({pageid}) => pageid === sectionId)
.map((section) => findNext('', section).next)
.filter(identity)[0]
}

return {
Expand Down
5 changes: 3 additions & 2 deletions app/routes/questions.$questionId.$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default function RenderArticle() {
const pageid = params.questionId ?? '😱'
const {data, tags} = useLoaderData<typeof loader>()
const {findSection, getArticle, getPath} = useToC()
const section = findSection(pageid)
const section = findSection(location?.state?.section || pageid)

useEffect(() => {
const getGlossary = async () => {
Expand Down Expand Up @@ -119,11 +119,12 @@ export default function RenderArticle() {
<ChevronRight className="dropdown-icon active" />
</Button>
)}

{section && (
<ArticlesNav
current={pageid}
article={section}
path={getPath(pageid)}
path={getPath(pageid, section?.pageid)}
className={!showNav ? 'desktop-only bordered' : ''}
/>
)}
Expand Down

0 comments on commit 2a5551b

Please sign in to comment.