feat: implement better ssr fallbacks

This commit is contained in:
Aarnav Tale 2024-04-17 17:42:44 -04:00
parent 94174ebcce
commit 0ff9e6fdc3
No known key found for this signature in database
4 changed files with 100 additions and 33 deletions

View File

@ -11,6 +11,8 @@ import { toast } from 'react-hot-toast/headless'
import Button from '~/components/Button' import Button from '~/components/Button'
import Spinner from '~/components/Spinner' import Spinner from '~/components/Spinner'
import Fallback from './fallback'
type EditorProperties = { type EditorProperties = {
readonly acl: string; readonly acl: string;
readonly setAcl: (acl: string) => void; readonly setAcl: (acl: string) => void;
@ -25,6 +27,8 @@ type EditorProperties = {
export default function Editor({ data, acl, setAcl, mode }: EditorProperties) { export default function Editor({ data, acl, setAcl, mode }: EditorProperties) {
const [light, setLight] = useState(false) const [light, setLight] = useState(false)
const [loading, setLoading] = useState(true)
const fetcher = useFetcher() const fetcher = useFetcher()
const aclType = useMemo(() => data.aclType === 'json' ? json() : yaml(), [data.aclType]) const aclType = useMemo(() => data.aclType === 'json' ? json() : yaml(), [data.aclType])
@ -35,6 +39,9 @@ export default function Editor({ data, acl, setAcl, mode }: EditorProperties) {
theme.addEventListener('change', theme => { theme.addEventListener('change', theme => {
setLight(theme.matches) setLight(theme.matches)
}) })
// Prevents the FOUC
setLoading(false)
}, []) }, [])
return ( return (
@ -44,38 +51,42 @@ export default function Editor({ data, acl, setAcl, mode }: EditorProperties) {
'rounded-b-lg rounded-tr-lg mb-2 overflow-hidden' 'rounded-b-lg rounded-tr-lg mb-2 overflow-hidden'
)} )}
> >
{mode === 'edit' ? ( {loading ? (
<CodeMirror <Fallback acl={acl} where='client'/>
value={acl}
maxHeight='calc(100vh - 20rem)'
theme={light ? githubLight : githubDark}
extensions={[aclType]}
readOnly={!data.hasAclWrite}
onChange={value => {
setAcl(value)
}}
/>
) : ( ) : (
<div mode === 'edit' ? (
className='overflow-y-scroll' <CodeMirror
style={{ height: 'calc(100vh - 20rem)' }} value={acl}
> className='h-editor text-sm'
<CodeMirrorMerge
theme={light ? githubLight : githubDark} theme={light ? githubLight : githubDark}
orientation='a-b' extensions={[aclType]}
readOnly={!data.hasAclWrite}
onChange={value => {
setAcl(value)
}}
/>
) : (
<div
className='overflow-y-scroll'
style={{ height: 'calc(100vh - 20rem)' }}
> >
<CodeMirrorMerge.Original <CodeMirrorMerge
readOnly theme={light ? githubLight : githubDark}
value={data.currentAcl} orientation='a-b'
extensions={[aclType]} >
/> <CodeMirrorMerge.Original
<CodeMirrorMerge.Modified readOnly
readOnly value={data.currentAcl}
value={acl} extensions={[aclType]}
extensions={[aclType]} />
/> <CodeMirrorMerge.Modified
</CodeMirrorMerge> readOnly
</div> value={acl}
extensions={[aclType]}
/>
</CodeMirrorMerge>
</div>
)
)} )}
</div> </div>

View File

@ -0,0 +1,51 @@
import clsx from 'clsx'
import Button from '~/components/Button'
type FallbackProperties = {
readonly acl: string;
readonly where: 'client' | 'server';
}
export default function Fallback({ acl, where }: FallbackProperties) {
return (
<>
<div className={clsx(
where === 'server' ? 'mb-2 overflow-hidden rounded-tr-lg rounded-b-lg' : '',
where === 'server' ? 'border border-gray-200 dark:border-gray-700' : ''
)}
>
<textarea
readOnly
className={clsx(
'w-full h-editor font-mono resize-none',
'text-sm text-gray-600 dark:text-gray-300',
'pl-10 pt-1 leading-snug'
)}
value={acl}
/>
</div>
{where === 'server' ? (
<>
<Button
disabled
variant='emphasized'
className='text-sm w-fit mr-2'
>
Save
</Button>
<Button
disabled
variant='emphasized'
className={clsx(
'text-sm w-fit bg-gray-100 dark:bg-transparent',
'border border-gray-200 dark:border-gray-700'
)}
>
Discard Changes
</Button>
</>
) : undefined}
</>
)
}

View File

@ -13,6 +13,7 @@ import { sighupHeadscale } from '~/utils/docker'
import { getSession } from '~/utils/sessions' import { getSession } from '~/utils/sessions'
import Editor from './editor' import Editor from './editor'
import Fallback from './fallback'
export async function loader() { export async function loader() {
const context = await getContext() const context = await getContext()
@ -146,14 +147,14 @@ export default function Page() {
</Tab.List> </Tab.List>
<Tab.Panels> <Tab.Panels>
<Tab.Panel> <Tab.Panel>
<ClientOnly> <ClientOnly fallback={<Fallback acl={acl} where='server'/>}>
{() => ( {() => (
<Editor data={data} acl={acl} setAcl={setAcl} mode='edit'/> <Editor data={data} acl={acl} setAcl={setAcl} mode='edit'/>
)} )}
</ClientOnly> </ClientOnly>
</Tab.Panel> </Tab.Panel>
<Tab.Panel> <Tab.Panel>
<ClientOnly> <ClientOnly fallback={<Fallback acl={acl} where='server'/>}>
{() => ( {() => (
<Editor data={data} acl={acl} setAcl={setAcl} mode='diff'/> <Editor data={data} acl={acl} setAcl={setAcl} mode='diff'/>
)} )}
@ -170,7 +171,7 @@ export default function Page() {
<CubeTransparentIcon className='w-24 h-24 text-gray-300 dark:text-gray-500'/> <CubeTransparentIcon className='w-24 h-24 text-gray-300 dark:text-gray-500'/>
<p className='w-1/2 text-center mt-4'> <p className='w-1/2 text-center mt-4'>
The Preview rules is very much still a work in progress. The Preview rules is very much still a work in progress.
It's a bit complicated to implement right now but hopefully it will be available soon. It is a bit complicated to implement right now but hopefully it will be available soon.
</p> </p>
</div> </div>
</Tab.Panel> </Tab.Panel>

View File

@ -3,7 +3,11 @@ import type { Config } from 'tailwindcss'
export default { export default {
content: ['./app/**/*.{js,jsx,ts,tsx}'], content: ['./app/**/*.{js,jsx,ts,tsx}'],
theme: { theme: {
extend: {} extend: {
height: {
editor: 'calc(100vh - 20rem)'
}
}
}, },
plugins: [] plugins: []
} satisfies Config } satisfies Config