v1.5 - history and timeline as well as many datastructure updates added, polished, fixes
This commit is contained in:
parent
1f0aa3078f
commit
1d84400aef
63 changed files with 7927 additions and 208 deletions
91
src/components/PageState.tsx
Normal file
91
src/components/PageState.tsx
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* ═══════════════════════════════════════════════════════════════
|
||||
PAGE STATE
|
||||
|
||||
The three ways a detail page can fail to be a detail page. All
|
||||
four of them need the same thing, and it should be the same thing
|
||||
— a visitor who hits a dead retreat link and a dead chapter link
|
||||
shouldn't get two different pages.
|
||||
|
||||
Rendered inside PageShell so the chrome doesn't flicker in and
|
||||
out between loading and loaded.
|
||||
|
||||
A 404 gets no retry button: the slug doesn't exist and trying
|
||||
again won't change that. Anything else does, because a dropped
|
||||
connection is the usual cause and one tap fixes it.
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
import { Link } from 'react-router-dom'
|
||||
import PageShell from './PageShell.tsx'
|
||||
|
||||
const TEAL = '#138ba0'
|
||||
const BODY = '#4a6b72'
|
||||
|
||||
export default function PageState({
|
||||
loading,
|
||||
error,
|
||||
notFound,
|
||||
onRetry,
|
||||
noun,
|
||||
backTo,
|
||||
backLabel,
|
||||
}: {
|
||||
loading: boolean
|
||||
error: string | null
|
||||
notFound: boolean
|
||||
onRetry: () => void
|
||||
/** Lowercase, as it appears mid-sentence: "retreat", "chapter". */
|
||||
noun: string
|
||||
backTo: string
|
||||
backLabel: string
|
||||
}) {
|
||||
let title: string
|
||||
let content: React.ReactNode
|
||||
|
||||
if (notFound) {
|
||||
title = 'Not found'
|
||||
content = (
|
||||
<div className="max-w-6xl mx-auto px-6">
|
||||
<p style={{ color: BODY }}>
|
||||
There’s no {noun} at this address. It may have been renamed, or taken
|
||||
down.
|
||||
</p>
|
||||
<Link
|
||||
to={backTo}
|
||||
className="mt-4 inline-block rounded-full border px-4 py-1.5 text-sm font-medium transition-colors hover:bg-[#eef9fb]"
|
||||
style={{ borderColor: TEAL, color: TEAL }}
|
||||
>
|
||||
{backLabel}
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
} else if (error) {
|
||||
title = 'Something went wrong'
|
||||
content = (
|
||||
<div className="max-w-6xl mx-auto px-6">
|
||||
<p style={{ color: '#b3261e' }}>Couldn’t load this {noun}. {error}</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="mt-3 rounded-full border px-4 py-1.5 text-sm font-medium transition-colors hover:bg-[#eef9fb]"
|
||||
style={{ borderColor: TEAL, color: TEAL }}
|
||||
>
|
||||
Try again
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
title = 'Loading…'
|
||||
content = (
|
||||
<p className="max-w-6xl mx-auto px-6" style={{ color: BODY }} role="status">
|
||||
Loading this {noun}…
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<PageShell
|
||||
title={title}
|
||||
sections={[{ id: 'status', title: '', accent: TEAL, background: '#ffffff', content }]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue