Files
kycnotme/web/src/layouts/BaseLayout.astro
2025-05-20 10:20:09 +00:00

130 lines
3.4 KiB
Plaintext

---
import AnnouncementBanner from '../components/AnnouncementBanner.astro'
import BaseHead from '../components/BaseHead.astro'
import Footer from '../components/Footer.astro'
import Header from '../components/Header.astro'
import { cn } from '../lib/cn'
import { prisma } from '../lib/prisma'
import type { AstroChildren } from '../lib/astro'
import type { ComponentProps } from 'astro/types'
import '@fontsource-variable/space-grotesk'
import '../styles/global.css'
type Props = ComponentProps<typeof BaseHead> & {
children: AstroChildren
errors?: string[]
success?: string[]
className?: {
body?: string
main?: string
footer?: string
}
showSplashText?: boolean
widthClassName?:
| 'container'
| 'max-w-none'
| 'max-w-screen-2xl'
| 'max-w-screen-lg'
| 'max-w-screen-md'
| 'max-w-screen-sm'
| 'max-w-screen-xl'
| 'max-w-screen-xs'
}
const {
errors = [],
success = [],
className,
widthClassName = 'max-w-screen-2xl',
showSplashText,
...baseHeadProps
} = Astro.props
const actualErrors = [...errors, ...Astro.locals.banners.errors]
const actualSuccess = [...success, ...Astro.locals.banners.successes]
const currentDate = new Date()
const announcement = await Astro.locals.banners.try(
'Unable to load announcements.',
() =>
prisma.announcement.findFirst({
where: {
isActive: true,
startDate: { lte: currentDate },
OR: [{ endDate: null }, { endDate: { gt: currentDate } }],
},
select: {
id: true,
content: true,
type: true,
link: true,
linkText: true,
startDate: true,
endDate: true,
isActive: true,
},
orderBy: [{ type: 'desc' }, { createdAt: 'desc' }],
}),
null
)
---
<html lang="en" transition:name="root" transition:animate="none">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<BaseHead {...baseHeadProps} />
</head>
<body class={cn('bg-night-700 text-day-300 flex min-h-dvh flex-col *:shrink-0', className?.body)}>
{announcement && <AnnouncementBanner announcement={announcement} transition:name="header-announcement" />}
<Header
classNames={{
nav: cn(
(widthClassName === 'max-w-none' || widthClassName === 'max-w-screen-2xl') && 'lg:px-8 2xl:px-12',
widthClassName
),
}}
showSplashText={showSplashText}
/>
{
actualSuccess.length > 0 && (
<ul class="container mx-auto my-4 space-y-4 px-4">
{actualSuccess.map((message) => (
<li class="font-title rounded-lg border border-green-500/30 bg-green-500/20 px-4 py-3 text-green-400">
{message}
</li>
))}
</ul>
)
}
{
actualErrors.length > 0 && (
<ul class="container mx-auto my-4 space-y-4 px-4">
{actualErrors.map((error) => (
<li class="font-title rounded-lg border border-red-500/30 bg-red-500/20 px-4 py-3 text-red-400">
{error}
</li>
))}
</ul>
)
}
<main
class={cn(
'container mx-auto mt-4 mb-12 grow px-4',
className?.main,
(widthClassName === 'max-w-none' || widthClassName === 'max-w-screen-2xl') && 'lg:px-8 2xl:px-12',
widthClassName
)}
>
<slot />
</main>
<Footer class={className?.footer} />
</body>
</html>