94 行
3.3 KiB
TypeScript
94 行
3.3 KiB
TypeScript
import { useQuery } from '@tanstack/react-query'
|
|
import { Helmet } from 'react-helmet-async'
|
|
import { useParams, useSearchParams } from 'react-router-dom'
|
|
|
|
import PrefetchLink from '@/components/PrefetchLink'
|
|
import PageTitle from '@/components/common/PageTitle'
|
|
import MainArea from '@/components/layout/MainArea'
|
|
import { SITE_TITLE } from '@/config'
|
|
import { getHelpArticle, getHelpDiff, resolveHelpLanguage } from '@/lib/help'
|
|
import { localeLanguage } from '@/lib/locales'
|
|
import { useLocale } from '@/lib/useLocale'
|
|
import { useUITranslation } from '@/lib/useUITranslation'
|
|
import { helpKeys } from '@/lib/queryKeys'
|
|
import { cn } from '@/lib/utils'
|
|
import NotFound from '@/pages/NotFound'
|
|
|
|
import type { FC } from 'react'
|
|
|
|
const markers = { added: '+ ', removed: '- ', unchanged: ' ' }
|
|
|
|
|
|
const HelpDiffPage: FC = () => {
|
|
const { message, label } = useUITranslation ('help')
|
|
const locale = useLocale ()
|
|
const { identifier = '' } = useParams ()
|
|
const [searchParams] = useSearchParams ()
|
|
const from = searchParams.get ('from') ?? ''
|
|
const to = searchParams.get ('to') ?? ''
|
|
const { data: article } = useQuery ({
|
|
queryKey: helpKeys.article (identifier),
|
|
queryFn: () => getHelpArticle (identifier),
|
|
staleTime: Infinity })
|
|
const requestedLanguage = localeLanguage (locale)
|
|
const language = resolveHelpLanguage (article, requestedLanguage)
|
|
const validParams = Boolean (identifier && from && to)
|
|
&& searchParams.getAll ('from').length === 1
|
|
&& searchParams.getAll ('to').length === 1
|
|
const { data: diff, isLoading, isError } = useQuery ({
|
|
enabled: validParams && language != null,
|
|
queryKey: helpKeys.diff (identifier, requestedLanguage, from, to),
|
|
queryFn: () => getHelpDiff (identifier, requestedLanguage, from, to),
|
|
staleTime: Infinity })
|
|
|
|
if (!(validParams) || (article != null && language == null)
|
|
|| isError || (!(isLoading) && diff == null))
|
|
return <NotFound/>
|
|
|
|
const title = `${ diff?.to.title ?? identifier } (${ from } → ${ to })`
|
|
const path = `/help/${ encodeURIComponent (identifier) }`
|
|
|
|
return (
|
|
<MainArea className="min-w-0 max-w-full">
|
|
<Helmet>
|
|
<title>{message ('diffTitle', { title }).text} | {SITE_TITLE}</title>
|
|
</Helmet>
|
|
<PageTitle>{title}</PageTitle>
|
|
|
|
{diff
|
|
? (
|
|
<>
|
|
<div className="flex flex-wrap items-center gap-3">
|
|
<PrefetchLink to={`${ path }?edition=${ encodeURIComponent (from) }`}>
|
|
{diff.from.title} ({from})
|
|
</PrefetchLink>
|
|
<span>→</span>
|
|
<PrefetchLink to={`${ path }?edition=${ encodeURIComponent (to) }`}>
|
|
{diff.to.title} ({to})
|
|
</PrefetchLink>
|
|
</div>
|
|
<pre lang={requestedLanguage} className="mt-4 overflow-x-auto whitespace-pre">
|
|
<code>
|
|
{diff.lines.map ((line, index) => {
|
|
const colour = cn (
|
|
'block text-gray-900 dark:text-gray-100',
|
|
line.type === 'added' && 'bg-green-200 dark:bg-green-800',
|
|
line.type === 'added' && 'text-green-950 dark:text-green-50',
|
|
line.type === 'removed' && 'bg-red-200 dark:bg-red-800',
|
|
line.type === 'removed' && 'text-red-950 dark:text-red-50')
|
|
|
|
return (
|
|
<span key={index} className={colour}>
|
|
{markers[line.type]}{line.content.replace (/\r?\n$/, '')}
|
|
</span>)
|
|
})}
|
|
</code>
|
|
</pre>
|
|
</>)
|
|
: <div>{label ('common:loading')}</div>}
|
|
</MainArea>)
|
|
}
|
|
|
|
|
|
export default HelpDiffPage
|