From ad77e9074ad9d28162c08d9a3e7a6ee1a5104545 Mon Sep 17 00:00:00 2001 From: Peter Hozak Date: Sun, 24 Nov 2024 17:19:22 +0100 Subject: [PATCH] support `/questions/1?list=1,2,3` manual list of ids --- README.md | 12 ------ .../ArticlesNav/ArticleNavManualList.tsx | 37 +++++++++++++++++++ app/components/ArticlesNav/articlenav.css | 7 ++++ app/routes/questions.$questionId.$.tsx | 21 +++++++---- 4 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 app/components/ArticlesNav/ArticleNavManualList.tsx diff --git a/README.md b/README.md index 4bfabdaf..542f525f 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,6 @@ Stampy UI is an interface for [aisafety.info](https://aisafety.info), a question Contributions are welcome, the code is released under the MIT License. If you'd like to join the [dev team](https://coda.io/d/AI-Safety-Info_dfau7sl2hmG/Dev-team_sulmV#_luYjG), drop by [our Discord](https://discord.com/invite/7wjJbFJnSN) and post in #stampy-dev! -## Supported URL parameters - -- state - controls which questions are displayed as collapsed / open / related, e.g. [aisafety.info/?state=6568\_](https://aisafety.info/?state=6568_) -- q (string) - search query for sharing direct link to search results (and not just link to 1 question), e.g. [aisafety.info/?q=alignment&limit=10](https://aisafety.info/?q=alignment&limit=10) - - limit (number, default 5) - how many results to show -- embed - show site without header/footer for embedding on other sites, see [embed-example.html](https://aisafety.info/embed-example.html) - - placeholder (string) - override `` of the search box - - theme (light|dark) - override CSS theme (if not provided, the embedded site will use `preferred-color-scheme` system setting) - - showInitial - show initial questions as well as the search bar - - onlyInitial - show only initial questions without the search bar - - showDetails - open question details (answers) directly instead of just links to aisafety.info - ## Stampy UI Development Setup 1. Requirements diff --git a/app/components/ArticlesNav/ArticleNavManualList.tsx b/app/components/ArticlesNav/ArticleNavManualList.tsx new file mode 100644 index 00000000..2183effa --- /dev/null +++ b/app/components/ArticlesNav/ArticleNavManualList.tsx @@ -0,0 +1,37 @@ +import {useMemo} from 'react' +import {Link} from '@remix-run/react' +import {questionUrl} from '~/routesMapper' +import './articlenav.css' +import {useOnSiteQuestions} from '~/hooks/useCachedObjects' +import type {Question} from '~/server-utils/stampy' + +export const ArticlesNavManualList = ({ + listOfIds, + current, +}: { + listOfIds: string[] + current: string +}) => { + const {items: onSiteQuestions} = useOnSiteQuestions() + const onSiteQuestionsMap = useMemo( + () => + (onSiteQuestions ?? []).reduce((acc: Record, q) => { + acc[q.pageid] = q + return acc + }, {}), + [onSiteQuestions] + ) + return ( +
+ {listOfIds.map((pageid) => ( +
+ + + {onSiteQuestionsMap[pageid]?.title ?? pageid} + + +
+ ))} +
+ ) +} diff --git a/app/components/ArticlesNav/articlenav.css b/app/components/ArticlesNav/articlenav.css index e33810c2..58c74052 100644 --- a/app/components/ArticlesNav/articlenav.css +++ b/app/components/ArticlesNav/articlenav.css @@ -29,6 +29,13 @@ padding: var(--spacing-8); cursor: pointer; } +.articles-title a { + flex: 1; +} +.mark-visited .articles-title:not(.selected) a:visited { + color: darkgray; +} + .article-selector .dropdown-icon, .articles-group .dropdown-icon { height: var(--spacing-12); diff --git a/app/routes/questions.$questionId.$.tsx b/app/routes/questions.$questionId.$.tsx index d739bbbf..390533e6 100644 --- a/app/routes/questions.$questionId.$.tsx +++ b/app/routes/questions.$questionId.$.tsx @@ -1,5 +1,5 @@ import {Suspense, useEffect, useState} from 'react' -import {useLocation} from 'react-router-dom' +import {useLocation, useSearchParams} from 'react-router-dom' import {Await, useLoaderData, useParams} from '@remix-run/react' import {defer, type LoaderFunctionArgs} from '@remix-run/cloudflare' import Page from '~/components/Page' @@ -16,6 +16,7 @@ import useOnSiteQuestions from '~/hooks/useOnSiteQuestions' import {useTags} from '~/hooks/useCachedObjects' import type {Question, Tag} from '~/server-utils/stampy' import {reloadInBackgroundIfNeeded} from '~/server-utils/kv-cache' +import {ArticlesNavManualList} from '~/components/ArticlesNav/ArticleNavManualList' export const LINK_WITHOUT_DETAILS_CLS = 'link-without-details' @@ -75,6 +76,7 @@ const updateFields = ( export default function RenderArticle() { const location = useLocation() + const [searchParams] = useSearchParams() const [showNav, setShowNav] = useState(false) // Used on mobile const params = useParams() const {items: onSiteQuestions} = useOnSiteQuestions() @@ -85,6 +87,7 @@ export default function RenderArticle() { const {toc, findSection, getArticle, getPath} = useToC() const section = findSection(location?.state?.section || pageid) const hideBannersIfSubsection = section?.children?.some((c) => c.pageid === pageid) + const manualListOfIds = searchParams.get('list')?.split(',') useEffect(() => { setShowNav(false) @@ -124,12 +127,16 @@ export default function RenderArticle() { ) )} - 0} - article={section} - path={getPath(pageid, section?.pageid)} - className={!showNav ? 'desktop-only bordered' : ''} - /> + {manualListOfIds ? ( + + ) : ( + 0} + article={section} + path={getPath(pageid, section?.pageid)} + className={!showNav ? 'desktop-only bordered' : ''} + /> + )}