chore: server-and-serverless template
This commit is contained in:
103
apps/app/src/components/AppShell.tsx
Normal file
103
apps/app/src/components/AppShell.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import {
|
||||
AppShell as MantineAppShell,
|
||||
Box,
|
||||
Button,
|
||||
Group,
|
||||
NavLink,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
} from '@pikku/mantine/core'
|
||||
import { Link, Outlet } from '@tanstack/react-router'
|
||||
import { asI18n } from '@pikku/react'
|
||||
import { useState } from 'react'
|
||||
import { m } from '@/i18n/messages'
|
||||
import { useLocale } from '@/i18n/config'
|
||||
import { usePikkuQuery } from '@project/functions-sdk/pikku/api.gen'
|
||||
import { signOut } from '@/lib/auth'
|
||||
import { LanguageSelector } from './LanguageSelector'
|
||||
import { ThemeSelector } from './ThemeSelector'
|
||||
|
||||
export function AppShell() {
|
||||
useLocale()
|
||||
const session = usePikkuQuery('getSession', {})
|
||||
const [isSigningOut, setIsSigningOut] = useState(false)
|
||||
|
||||
return (
|
||||
<MantineAppShell
|
||||
header={{ height: 88 }}
|
||||
navbar={{ width: 250, breakpoint: 'sm' }}
|
||||
padding="lg"
|
||||
styles={{
|
||||
main: {
|
||||
background:
|
||||
'radial-gradient(circle at top left, rgba(96, 165, 250, 0.12), transparent 26%), linear-gradient(180deg, #10203a 0%, #07111e 56%, #040913 100%)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MantineAppShell.Header px="lg" py="md">
|
||||
<Group justify="space-between" align="center" h="100%">
|
||||
<div>
|
||||
<Text tt="uppercase" fw={700} fz="xs" c="blue.3" style={{ letterSpacing: '0.18em' }}>
|
||||
{m.app_shell__eyebrow()}
|
||||
</Text>
|
||||
<Title order={2}>{m.app_shell__title()}</Title>
|
||||
</div>
|
||||
<Group gap="md">
|
||||
<LanguageSelector />
|
||||
<ThemeSelector />
|
||||
<Box
|
||||
px="md"
|
||||
py="xs"
|
||||
style={{
|
||||
border: '1px solid var(--mantine-color-dark-4)',
|
||||
borderRadius: '1rem',
|
||||
background: 'rgba(255,255,255,0.03)',
|
||||
}}
|
||||
>
|
||||
<Text size="xs" c="dimmed">
|
||||
{session.data?.name ? asI18n(session.data.name) : m.app_shell__signed_in()}
|
||||
</Text>
|
||||
<Text fw={600}>
|
||||
{session.data?.email ? asI18n(session.data.email) : m.common__loading()}
|
||||
</Text>
|
||||
</Box>
|
||||
<Button
|
||||
variant="light"
|
||||
radius="md"
|
||||
loading={isSigningOut}
|
||||
onClick={async () => {
|
||||
setIsSigningOut(true)
|
||||
try {
|
||||
await signOut()
|
||||
window.location.href = '/login'
|
||||
} finally {
|
||||
setIsSigningOut(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{m.app_shell__sign_out()}
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
</MantineAppShell.Header>
|
||||
|
||||
<MantineAppShell.Navbar p="md">
|
||||
<Stack gap="xs">
|
||||
<NavLink
|
||||
component={Link}
|
||||
to="/app"
|
||||
label={m.app_shell__nav__message()}
|
||||
description={m.app_shell__nav__message_description()}
|
||||
variant="filled"
|
||||
activeOptions={{ exact: true }}
|
||||
/>
|
||||
</Stack>
|
||||
</MantineAppShell.Navbar>
|
||||
|
||||
<MantineAppShell.Main>
|
||||
<Outlet />
|
||||
</MantineAppShell.Main>
|
||||
</MantineAppShell>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user