feat: implement better ssr fallbacks
This commit is contained in:
parent
94174ebcce
commit
0ff9e6fdc3
@ -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>
|
||||||
|
|
||||||
|
|||||||
51
app/routes/_data.acls._index/fallback.tsx
Normal file
51
app/routes/_data.acls._index/fallback.tsx
Normal 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}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -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>
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user