Skip to content

Commit

Permalink
Merge branch 'master' into stampy-redesign
Browse files Browse the repository at this point in the history
  • Loading branch information
mruwnik committed Apr 3, 2024
2 parents 380a14e + 4aecbf9 commit ab15416
Show file tree
Hide file tree
Showing 23 changed files with 99 additions and 443 deletions.
2 changes: 1 addition & 1 deletion app/components/Article/Contents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const glossaryInjecter = (pageid: string, glossary: Glossary) => {
return (html: string) =>
Object.values(glossary)
.filter((item) => item.pageid != pageid)
.sort((a, b) => b.alias.length - a.alias.length)
.sort((a, b) => (b.alias?.length ?? 0) - (a.alias?.length ?? 0))
.reduce((html, {term, alias}) => {
const match = new RegExp(`(^|[^\\w-])(${alias})($|[^\\w-])`, 'i')
if (!seen.has(term) && html.search(match) >= 0) {
Expand Down
10 changes: 4 additions & 6 deletions app/components/Article/FeedbackForm/feedbackForm.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.feedback-container {
max-width: 384px;
padding: var(--spacing-32);
}
.select-option {
Expand All @@ -13,7 +14,6 @@
}

.feedback-form {
width: 100%;
position: relative;
color: var(--colors-cool-grey-600);
z-index: 2;
Expand Down Expand Up @@ -42,18 +42,16 @@
.action-feedback-text {
display: none;
position: absolute;
left: 180px;
text-wrap: nowrap;
top: 13px;
transform: translate(-1vw, var(--spacing-56));
}
.action-feedback-text.show {
display: block;
}
.composite-button > .feedback-form {
position: absolute;
left: 90px;
top: -350px;
display: none;
transform: translate(-9vw, var(--spacing-56));
margin: var(--spacing-24);
}
.composite-button > .feedback-form.show {
display: block;
Expand Down
26 changes: 3 additions & 23 deletions app/components/Article/FeedbackForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,20 @@ import Button from '~/components/Button'
import './feedbackForm.css'

export interface FeedbackFormProps {
/**
* Article ID
*/
pageid: string
/**
* Class name
*/
className?: string
/**
* onBlur
*/
onClose?: () => void
onBlur?: () => void
/**
* onFocus
*/
onFocus?: () => void
/**
* Has Options
*/
hasOptions?: boolean
/**
* onSubmit
*/
onSubmit?: () => void
}
const FeedbackForm = ({
pageid,
className = 'feedback-form',
onClose,
onBlur,
onFocus,
hasOptions = true,
onSubmit,
}: FeedbackFormProps) => {
// to be implemented.
const [selected, setSelected] = React.useState<string>()
Expand Down Expand Up @@ -79,9 +61,7 @@ const FeedbackForm = ({
)

const handleSubmit = () => {
if (onSubmit) {
onSubmit()
}
onClose && onClose()
}

return (
Expand Down
16 changes: 12 additions & 4 deletions app/components/Article/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const ArticleFooter = (question: Question) => {
return () => clearInterval(timeoutId)
}, [showFeedbackForm, isFormFocused])

React.useEffect(() => {
const timeout = setInterval(() => setShowFeedback(false), 6000)
return () => clearInterval(timeout)
}, [showFeedback])

return (
!isLoading(question) && (
<div className="footer-comtainer padding-bottom-40">
Expand Down Expand Up @@ -63,18 +68,21 @@ const ArticleFooter = (question: Question) => {
pageid={question.pageid}
showText={true}
actionType={ActionType.UNHELPFUL}
onSuccess={() => setShowFeedbackForm(true)}
onClick={() => setShowFeedbackForm(true)}
/>
<span className={['action-feedback-text', showFeedback ? 'show' : ''].join(' ')}>
<div className={['action-feedback-text', showFeedback ? 'show' : ''].join(' ')}>
Thanks for your feedback!
</span>
</div>
<FeedbackForm
pageid={question.pageid}
className={['feedback-form', showFeedbackForm ? 'show' : ''].join(' ')}
onClose={() => {
setShowFeedback(true)
setShowFeedbackForm(false)
}}
onBlur={() => setIsFormFocused(false)}
onFocus={() => setIsFormFocused(true)}
hasOptions={false}
onSubmit={() => setShowFeedbackForm(false)}
/>
</CompositeButton>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/components/ArticlesDropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {useState, useEffect} from 'react'
import {Link as LinkElem} from '@remix-run/react'
import type {Tag} from '~/server-utils/stampy'
import {TOCItem, Category, ADVANCED, INTRODUCTORY} from '~/routes/questions.toc'
import {sortFuncs} from '~/routes/tags.$'
import {sortFuncs} from '~/routes/categories.$'
import {questionUrl, tagsUrl, tagUrl} from '~/routesMapper'
import Button from '~/components/Button'
import './dropdown.css'
Expand Down
10 changes: 10 additions & 0 deletions app/components/ArticlesNav/menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@
cursor: pointer;
}

/*
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary#default_style
"For Webkit-based browsers, such as Safari, it is possible to control the icon display
through the non-standard CSS pseudo-element ::-webkit-details-marker.
To remove the disclosure triangle, use summary::-webkit-details-marker { display: none }."
*/
.articles-group details summary::-webkit-details-marker {
display: none;
}

.articles-dropdown {
padding-left: var(--spacing-40);
}
Expand Down
16 changes: 8 additions & 8 deletions app/components/ContentBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const ContentBoxMain = () => (
action={questionUrl({pageid: '9OGZ'})}
actionTitle={
<>
<span className="default-bold">Start reading</span>
<span className="default-bold">Start here</span>
<ArrowRight />
</>
}
Expand All @@ -62,23 +62,23 @@ export const ContentBoxMain = () => (
)

export const ContentBoxSecond = () => {
const article = {pageid: '9TDI', title: 'Not convinced? Explore the arguments.'}
const article = {pageid: '9TDI', title: 'Objections and responses'}
return (
<ContentBox
title="Not convinced?"
title="Objections and responses"
action={questionUrl(article)}
actionTitle="Explore the arguments"
actionTitle="Explore the debate"
>
<ListTable
sameTab
elements={[
{title: 'What are the main sources of AI existential risk?', pageid: '8503'},
{title: 'Why can’t we just use Asimov’s Three Laws of Robotics?', pageid: '6224'},
{
title: 'Do people seriously worry about existential risk from AI?',
pageid: '6953',
title: 'Why would misaligned AI pose a threat that we can’t deal with?',
pageid: 'MNAK',
className: 'desktop-only',
},
{title: 'Why would an AI do bad things?', pageid: '2400'},
{title: 'Isn’t the real concern with AI something else?', pageid: '1001'},
]}
/>
</ContentBox>
Expand Down
4 changes: 2 additions & 2 deletions app/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export const FooterBar: FunctionComponent = () => {
<a href="/">AISafety.info</a>
</p>
<div>
We’re a global team of specialists supported by volunteers from various backgrounds who
are concerned about the possibility of human extinction from future AI.
We’re a global team of specialists and volunteers from various backgrounds who want to
ensure that the effects of future AI are beneficial rather than catastrophic.
</div>
</div>

Expand Down
1 change: 0 additions & 1 deletion app/components/Grid/grid.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
text-align: left;
padding: var(--spacing-40);
width: 21.46vw;
height: 21.46vw;
min-width: var(--spacing-288);
min-height: var(--spacing-288);
text-decoration: none;
Expand Down
2 changes: 1 addition & 1 deletion app/hooks/useCachedObjects.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useEffect, useState, createContext, useContext, ReactElement} from 'react'
import type {Tag, Glossary} from '~/server-utils/stampy'
import {fetchTags} from '~/routes/tags.all'
import {fetchTags} from '~/routes/categories.all'
import {fetchTOC, TOCItem} from '~/routes/questions.toc'
import {fetchGlossary} from '~/routes/questions.glossary'

Expand Down
1 change: 1 addition & 0 deletions app/newRoot.css
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ ol {
}
} /* end mobile */
p,
textarea,
button {
font-family: Poppins;
}
Expand Down
19 changes: 11 additions & 8 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import newStyles from '~/newRoot.css'
import Error from '~/components/Error'
import Page from '~/components/Page'
import {CachedObjectsProvider} from '~/hooks/useCachedObjects'
import {questionsOnPage} from '~/hooks/stateModifiers'
import {useTheme} from '~/hooks/theme'
import {loadQuestionDetail} from '~/server-utils/stampy'

Expand Down Expand Up @@ -47,15 +46,16 @@ const makeSocialPreviewText = (
*/
const fetchQuestion = async (request: Request) => {
const url = new URL(request.url)
const questions = questionsOnPage(url.searchParams.get('state') || '')

if (questions.length != 1) return null

const {data} = await loadQuestionDetail(request, questions[0][0])
return data
const [path, pageid] = url.pathname.slice(1).split('/') || []
if (path === 'questions') {
const {data} = await loadQuestionDetail(request, pageid)
return data
}
return null
}

const TITLE = 'Stampy'
const TITLE = 'AISafety.info'
const DESCRIPTION = 'AI Safety FAQ'
const twitterCreator = '@stampyai'
export const meta: MetaFunction<typeof loader> = ({data = {} as any}) => {
Expand Down Expand Up @@ -97,7 +97,10 @@ export const loader = async ({request}: Parameters<LoaderFunction>[0]) => {
const embed = !!request.url.match(/embed/)
const showSearch = !request.url.match(/onlyInitial/)

const question = await fetchQuestion(request)
const question = await fetchQuestion(request).catch((e) => {
console.error('\n\nUnexpected error in loader\n', e)
return null
})

return {
question,
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function App() {
return (
<Page>
<div className="page-body">
<h1 className="padding-bottom-80 padding-top-56">Answers on all things AI safety</h1>
<h1 className="padding-bottom-80 padding-top-56">Your guide to AI safety</h1>

<ContentBoxMain />
<ContentBoxSecond />
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion app/routes/tags.$.tsx → app/routes/categories.$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {useState, useEffect} from 'react'
import {useLoaderData} from '@remix-run/react'
import Page from '~/components/Page'
import ListTable from '~/components/Table'
import {loader} from '~/routes/tags.all'
import {loader} from '~/routes/categories.all'
import {CategoriesNav} from '~/components/CategoriesNav/Menu'
import type {Tag as TagType} from '~/server-utils/stampy'
import useIsMobile from '~/hooks/isMobile'
Expand Down
File renamed without changes.
File renamed without changes.
47 changes: 18 additions & 29 deletions app/routes/questions.$questionId.$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,17 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
}

try {
const dataPromise = loadQuestionDetail(request, questionId)
.then(({data}) => data)
.catch(raise500)
const dataPromise = loadQuestionDetail(request, questionId).catch(raise500)
const tagsPromise = loadTags(request)
.then(({data}) => data)
.catch(raise500)
return defer({data: dataPromise, tags: tagsPromise})
return defer({question: dataPromise, tags: tagsPromise})
} catch (error: unknown) {
const msg = `No question found with ID ${questionId}. Please go to <a href="https://discord.com/invite/Bt8PaRTDQC">Discord</a> and report where you found this link.`
throw new Response(msg, {status: 404})
}
}

export function fetchQuestion(pageid: string) {
const url = `/questions/${encodeURIComponent(pageid)}`
return fetch(url)
.then(async (response) => {
const json: Awaited<ReturnType<typeof loadQuestionDetail>> = await response.json()
if ('error' in json) console.error(json.error)
const {data, timestamp} = json

reloadInBackgroundIfNeeded(url, timestamp)

return data
})
.catch((e) => {
throw raise500(e)
})
}

const dummyQuestion = (title: string | undefined) =>
({
text: 'Loading...',
Expand All @@ -80,7 +61,7 @@ export default function RenderArticle() {
const [showNav, setShowNav] = useState(false) // Used on mobile
const params = useParams()
const pageid = params.questionId ?? '😱'
const {data, tags} = useLoaderData<typeof loader>()
const {question, tags} = useLoaderData<typeof loader>()
const {findSection, getArticle, getPath} = useToC()
const section = findSection(location?.state?.section || pageid)

Expand All @@ -96,6 +77,14 @@ export default function RenderArticle() {
setShowNav(false)
}, [location.key])

useEffect(() => {
question.then((val) => {
const {data: question, timestamp} = val as {data: Question; timestamp: string}
reloadInBackgroundIfNeeded(location.pathname, timestamp)
if (question.title) document.title = question.title
})
}, [question, location])

return (
<Page modal={showNav}>
<div className={`article-container ${showNav ? 'no-padding' : ''}`}>
Expand All @@ -112,7 +101,7 @@ export default function RenderArticle() {
</div>
) : (
<Button
className="mobile-only article-selector large-reading"
className="mobile-only article-selector large-reading black"
action={() => setShowNav(true)}
>
{getArticle(pageid)?.title}
Expand All @@ -138,18 +127,18 @@ export default function RenderArticle() {
/>
}
>
<Await resolve={Promise.all([data, tags])}>
{([resolvedValue, tags]) => {
if (resolvedValue instanceof Response) {
return <Error error={resolvedValue} />
} else if (!(resolvedValue as any)?.pageid) {
<Await resolve={Promise.all([question, tags])}>
{([resolvedQuestion, resolvedTags]) => {
if (resolvedQuestion instanceof Response || !('data' in resolvedQuestion)) {
return <Error error={resolvedQuestion} />
} else if (!resolvedQuestion.data.pageid) {
return (
<Error error={{statusText: 'Could not fetch question', status: 'emptyArticle'}} />
)
} else {
return (
<Article
question={updateTags(resolvedValue as Question, tags as Tag[])}
question={updateTags(resolvedQuestion.data as Question, resolvedTags as Tag[])}
glossary={glossary}
className={showNav ? 'desktop-only' : ''}
/>
Expand Down
Loading

0 comments on commit ab15416

Please sign in to comment.