feat: add loading indicator

This commit is contained in:
Aarnav Tale 2024-05-11 23:07:24 -04:00
parent 6102fabfcb
commit f563335fab
No known key found for this signature in database
3 changed files with 42 additions and 8 deletions

View File

@ -1,7 +1,8 @@
import { NavLink } from '@remix-run/react' import { NavLink } from '@remix-run/react'
import clsx from 'clsx'
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
import { cn } from '~/utils/cn'
type Properties = { type Properties = {
readonly name: string; readonly name: string;
readonly to: string; readonly to: string;
@ -12,13 +13,20 @@ export default function TabLink({ name, to, icon }: Properties) {
return ( return (
<NavLink <NavLink
to={to} to={to}
className={({ isActive, isPending }) => clsx( prefetch='intent'
'flex items-center gap-x-2 p-2 border-b-2 text-md text-nowrap', className={({ isActive }) => cn(
isActive ? 'border-white' : 'border-transparent', 'border-b-2 py-1.5',
isPending && 'animate-pulse' isActive ? 'border-white' : 'border-transparent'
)} )}
> >
{icon} {name} <div
className={cn(
'flex items-center gap-x-2 px-2.5 py-1.5 text-md text-nowrap',
'hover:bg-ui-100/5 dark:hover:bg-ui-900/40 rounded-md'
)}
>
{icon} {name}
</div>
</NavLink> </NavLink>
) )
} }

View File

@ -1,8 +1,10 @@
import { type LoaderFunctionArgs, redirect } from '@remix-run/node' import { type LoaderFunctionArgs, redirect } from '@remix-run/node'
import { Outlet, useLoaderData } from '@remix-run/react' import { Outlet, useLoaderData, useNavigation } from '@remix-run/react'
import { ProgressBar } from 'react-aria-components'
import { ErrorPopup } from '~/components/Error' import { ErrorPopup } from '~/components/Error'
import Header from '~/components/Header' import Header from '~/components/Header'
import { cn } from '~/utils/cn'
import { getContext } from '~/utils/config' import { getContext } from '~/utils/config'
import { HeadscaleError, pull } from '~/utils/headscale' import { HeadscaleError, pull } from '~/utils/headscale'
import { destroySession, getSession } from '~/utils/sessions' import { destroySession, getSession } from '~/utils/sessions'
@ -40,11 +42,22 @@ export async function loader({ request }: LoaderFunctionArgs) {
export default function Layout() { export default function Layout() {
const data = useLoaderData<typeof loader>() const data = useLoaderData<typeof loader>()
const nav = useNavigation()
return ( return (
<> <>
<ProgressBar
aria-label='Loading...'
>
<div
className={cn(
'fixed top-0 left-0 z-50 w-1/2 h-1',
'bg-blue-500 dark:bg-blue-400 opacity-0',
nav.state === 'loading' && 'animate-loading opacity-100'
)}
/>
</ProgressBar>
<Header data={data}/> <Header data={data}/>
<main className='container mx-auto overscroll-contain mt-4 mb-24'> <main className='container mx-auto overscroll-contain mt-4 mb-24'>
<Outlet/> <Outlet/>
</main> </main>

View File

@ -24,6 +24,19 @@ export default {
colors: { colors: {
main: colors.slate, main: colors.slate,
ui: colors.neutral ui: colors.neutral
},
keyframes: {
loader: {
from: {
transform: 'translateX(-100%)'
},
to: {
transform: 'translateX(100%)'
}
}
},
animation: {
loading: 'loader 0.8s infinite ease-in-out'
} }
} }
}, },