a homebrewed DnD campaign based in the Honkai: Star Rail universe
hsr honkaistarrail dnd
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

redesign homepage

+426 -184
+3 -2
app/package.json
··· 8 8 "build": "vite build", 9 9 "preview": "vite preview", 10 10 "prepare": "svelte-kit sync || echo ''", 11 - "check": "svelte-kit sync && svelte-check", 12 - "check-watch": "svelte-kit sync && svelte-check --watch", 11 + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 12 + "check-watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 13 13 "storybook": "storybook dev -p 6006", 14 14 "build-storybook": "storybook build", 15 15 "chromatic": "chromatic --exit-zero-on-changes", ··· 43 43 "mode-watcher": "catalog:svelte", 44 44 "pg": "catalog:app", 45 45 "resend": "catalog:app", 46 + "svelte-crumbs": "catalog:svelte", 46 47 "sveltekit-superforms": "catalog:svelte", 47 48 "tailwind-merge": "catalog:tailwind", 48 49 "tailwind-variants": "catalog:tailwind",
+1 -6
app/src/app.html
··· 3 3 <head> 4 4 <meta charset="utf-8" /> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 - <link 7 - rel="prefetch" 8 - type="font/otf" 9 - as="font" 10 - href="%sveltekit.assets%/fonts/Hsr-Universal-Script.otf" 11 - /> 12 6 <link rel="icon" href="%sveltekit.assets%/favicons/favicon.svg" /> 13 7 <link rel="icon" href="%sveltekit.assets%/favicons/favicon.ico" /> 8 + <link rel="prefetch" type="font/otf" as="font" href="%sveltekit.assets%/fonts/Hsr-Universal-Script.otf" /> 14 9 <link type="image/png" sizes="16x16" rel="icon" href="%sveltekit.assets%/favicons/favicon-16x16.png" /> 15 10 <link type="image/png" sizes="32x32" rel="icon" href="%sveltekit.assets%/favicons/favicon-32x32.png" /> 16 11 <link type="image/png" sizes="192x192" rel="icon" href="%sveltekit.assets%/favicons/android-chrome-192x192.png" />
+3 -3
app/src/lib/ui-components/button/styles.ts
··· 10 10 'cursor-pointer', 11 11 'flex flex-row items-center justify-center gap-2', 12 12 'border', 13 - 'text-center', 13 + 'text-center text-sm', 14 14 'transition-colors', 15 15 'touch-manipulation', 16 16 ], 17 17 variants: { 18 18 isIconOnly: { 19 19 false: 'px-4 py-2', 20 - true: 'p-2', 20 + true: 'p-1', 21 21 }, 22 22 isRound: { 23 - true: 'rounded-lg', 23 + true: 'rounded-md', 24 24 }, 25 25 intent: { 26 26 primary: [
+1 -1
app/src/lib/ui-components/card/CardFooter.svelte
··· 13 13 base: [ 14 14 'mt-auto', 15 15 'flex flex-col gap-2', 16 - 'dark:bg-diagonal-lines text-zinc-700/15', 16 + 'dark:pattern-diagonal-lines text-zinc-700/15', 17 17 ], 18 18 }) 19 19 </script>
+9 -2
app/src/lib/ui-components/link/Link.svelte
··· 7 7 type LinkRootElement = Exclude<SvelteHTMLElements['a'], 'href'> 8 8 type LinkProps = WithElementRef<WithChildren<LinkRootElement>> & { 9 9 href: string, 10 + isUnderlined?: boolean, 10 11 } 11 12 12 13 let { 13 14 href, 15 + isUnderlined = false, 14 16 children, 15 17 class: className, 16 18 'data-slot': dataSlot = 'page-link', ··· 18 20 ...restProps 19 21 }: LinkProps = $props() 20 22 const link = tv({ 21 - base: 'text-hsr-gold underline', 23 + base: 'text-hsr-gold', 24 + variants: { 25 + isUnderlined: { 26 + true: 'underline', 27 + } 28 + } 22 29 }) 23 30 </script> 24 31 ··· 26 33 {href} 27 34 bind:this={ref} 28 35 data-slot={dataSlot} 29 - class={cn(link(), className)} 36 + class={cn(link({ isUnderlined }), className)} 30 37 {...restProps} 31 38 > 32 39 {@render children?.()}
+7 -10
app/src/lib/ui-components/menu/MenuContent.svelte
··· 1 1 <script lang="ts"> 2 2 import { DropdownMenu } from 'bits-ui' 3 - import type { DropdownMenuContentProps as BitsContentProps, WithChildren } from 'bits-ui' 4 - import { tv } from 'tailwind-variants' 3 + import { cn, tv } from 'tailwind-variants' 5 4 6 - type DropdownMenuContentRoot = BitsContentProps 7 - type DropdownMenuContentProps = WithChildren<DropdownMenuContentRoot> 8 - let { children }: DropdownMenuContentProps = $props() 5 + type MenuContentRoot = DropdownMenu.ContentProps 6 + type MenuContentProps = MenuContentRoot 7 + let { class: className, ...restProps }: MenuContentProps = $props() 9 8 10 9 const content = tv({ 11 10 base: [ 12 - 'flex flex-col p-2.5 mt-2 w-[230px]', 11 + 'flex flex-col p-2.5 mt-2 w-57.5', 13 12 'outline-hidden focus-visible:outline-hidden', 14 13 'bg-white dark:bg-hsr-dark', 15 14 'border rounded-lg', 16 15 'border-zinc-200 dark:border-zinc-800', 17 16 'shadow-zinc-200 dark:shadow-black shadow-2xl', 18 - 'font-sans text-md', 17 + 'font-sans text-sm', 19 18 ], 20 19 }) 21 20 </script> 22 21 23 - <DropdownMenu.Content class={content()}> 24 - {@render children?.()} 25 - </DropdownMenu.Content> 22 + <DropdownMenu.Content {...restProps} class={cn(content(), className)} />
+12 -39
app/src/lib/ui-components/menu/MenuItem.svelte
··· 1 1 <script lang="ts"> 2 - import { DropdownMenu, type DropdownMenuItemProps as BitsItemProps } from 'bits-ui' 2 + import { DropdownMenu } from 'bits-ui' 3 3 import { tv } from 'tailwind-variants' 4 4 5 5 const menuItem = tv({ 6 - base: 'cursor-pointer outline-hidden focus-visible:outline-hidden', 7 - variants: { 8 - isStyled: { 9 - true: [ 10 - 'flex flex-row gap-2 items-center p-1.5', 11 - 'rounded-md', 12 - 'transition-colors', 13 - 'hover:bg-stone-200', 14 - ], 15 - }, 16 - }, 6 + base: [ 7 + 'cursor-pointer outline-hidden focus-visible:outline-hidden', 8 + 'flex flex-row gap-2 items-center p-1.5', 9 + 'rounded-md', 10 + 'transition-colors', 11 + 'hover:bg-stone-200', 12 + ], 17 13 }) 18 14 19 - type DropdownMenuItemRootElement = BitsItemProps 20 - type DropdownMenuItemProps = DropdownMenuItemRootElement & { 21 - href?: URL | string, 22 - } 23 - let { children, href, ...props }: DropdownMenuItemProps = $props() 24 - 25 - const asHref = (url: URL | string): string => 26 - url instanceof URL 27 - ? url.toString() 28 - : url 15 + type MenuItemRootElement = DropdownMenu.ItemProps 16 + type MenuItemProps = MenuItemRootElement 17 + let { ...restProps }: MenuItemProps = $props() 29 18 </script> 30 19 31 - <DropdownMenu.Item 32 - {...props} 33 - class={[ 34 - menuItem({isStyled: href === undefined}) 35 - ]} 36 - > 37 - {#if href !== undefined} 38 - <a 39 - href={asHref(href)} 40 - class={menuItem({isStyled: true})} 41 - > 42 - {@render children?.()} 43 - </a> 44 - {:else} 45 - {@render children?.()} 46 - {/if} 47 - </DropdownMenu.Item> 20 + <DropdownMenu.Item {...restProps} class={menuItem()} />
+31
app/src/lib/ui-components/menu/MenuLinkItem.svelte
··· 1 + <script lang="ts"> 2 + import { DropdownMenu } from 'bits-ui' 3 + import { cn, tv } from 'tailwind-variants' 4 + 5 + const menuItemTv = tv({ 6 + slots: { 7 + root: 'cursor-pointer outline-hidden focus-visible:outline-hidden', 8 + item: [ 9 + 'flex flex-row gap-2 items-center p-1.5', 10 + 'rounded-md', 11 + 'transition-colors', 12 + 'hover:bg-stone-200', 13 + ] 14 + } 15 + }) 16 + const { root, item } = menuItemTv() 17 + 18 + type MenuItemRootElement = DropdownMenu.ItemProps 19 + type MenuItemProps = MenuItemRootElement & { 20 + href: URL | string, 21 + } 22 + 23 + let { children, href, ...restProps }: MenuItemProps = $props() 24 + const htmlHref = $derived.by(() => href instanceof URL ? href.toString() : href) 25 + </script> 26 + 27 + <DropdownMenu.Item {...restProps} class={root()}> 28 + <a href={htmlHref} class={item()}> 29 + {@render children?.()} 30 + </a> 31 + </DropdownMenu.Item>
+7 -9
app/src/lib/ui-components/menu/MenuTrigger.svelte
··· 1 1 <script lang="ts"> 2 2 import { DropdownMenu } from 'bits-ui' 3 - import type { DropdownMenuTriggerProps as BitsTriggerProps, WithChildren } from 'bits-ui' 4 - import { tv } from 'tailwind-variants' 3 + import type { WithChildren } from 'bits-ui' 4 + import { cn, tv } from 'tailwind-variants' 5 5 6 - type DropdownMenuTriggerRoot = BitsTriggerProps 7 - type DropdownMenuTriggerProps = WithChildren<DropdownMenuTriggerRoot> 8 - let { children }: DropdownMenuTriggerProps = $props() 6 + type MenuTriggerRoot = DropdownMenu.TriggerProps 7 + type MenuTriggerProps = WithChildren<MenuTriggerRoot> 8 + let { class: className, ...restProps }: MenuTriggerProps = $props() 9 9 10 10 const trigger = tv({ 11 11 base: [ 12 - 'flex flex-row justify-end w-[230px]', 12 + 'flex flex-row justify-end', 13 13 'outline-hidden focus-visible:outline-hidden', 14 14 ] 15 15 }) 16 16 </script> 17 17 18 - <DropdownMenu.Trigger class={trigger()}> 19 - {@render children?.()} 20 - </DropdownMenu.Trigger> 18 + <DropdownMenu.Trigger {...restProps} class={cn(trigger(), className)} />
+1
app/src/lib/ui-components/menu/exports.ts
··· 1 1 export { default as Content } from './MenuContent.svelte' 2 2 export { default as Item } from './MenuItem.svelte' 3 + export { default as LinkItem } from './MenuLinkItem.svelte' 3 4 export { default as Trigger } from './MenuTrigger.svelte'
+1 -1
app/src/lib/ui-components/text-input/TextAreaInput.svelte
··· 26 26 'p-2', 27 27 'bg-white dark:bg-hsr-dark', 28 28 'border border-zinc-300 dark:border-zinc-800', 29 - 'placeholder:text-zinc-700', 29 + 'placeholder:text-zinc-600', 30 30 'transition-colors', 31 31 'hover:border-hsr-gold/50', 32 32 'focus:outline-1 focus:outline-hsr-gold',
+1 -1
app/src/lib/ui-components/text-input/TextInput.svelte
··· 45 45 'appearance-none', 46 46 'w-full', 47 47 'focus:outline-none', 48 - 'placeholder:text-zinc-700', 48 + 'placeholder:text-zinc-600', 49 49 ], 50 50 }, 51 51 })
+1 -2
app/src/lib/ui-components/tooltip/Tooltip.svelte
··· 3 3 import type { Snippet } from 'svelte' 4 4 import { tv } from 'tailwind-variants' 5 5 6 - type TooltipRootProps = Tooltip.RootProps 7 - type TooltipProps = TooltipRootProps & { 6 + type TooltipProps = Tooltip.RootProps & { 8 7 trigger: Snippet 9 8 triggerProps?: Tooltip.TriggerProps 10 9 children?: Snippet
+1 -1
app/src/routes/(auth)/AuthFooter.svelte
··· 15 15 16 16 <Button intent="secondary" class="w-full -mt-3" {...googleProps}> 17 17 <GoogleIcon class="size-5 fill-hsr-dark dark:fill-white stroke-none" /> 18 - Sign in with Google 18 + Continue with Google 19 19 </Button>
+21
app/src/routes/+error.svelte
··· 1 + <script> 2 + import { page } from '$app/state' 3 + import { LinkButton } from '$ui/button' 4 + </script> 5 + 6 + <div class="mx-auto my-auto"> 7 + <div class="flex flex-col gap-8 -my-16"> 8 + <div class="flex flex-col gap-4"> 9 + <div> 10 + <div class="text-xs font-mono uppercase text-zinc-500">Error {page?.status}</div> 11 + <h2 class="text-2xl font-mono uppercase">404 Not Found</h2> 12 + </div> 13 + <p class="max-w-50ch italic text-pretty"> 14 + There are limitless, countless regions across the cosmos. 15 + Within one's lifetime, they may only experience at most a trillionth of the universe. 16 + This place is not one of them. 17 + </p> 18 + </div> 19 + <LinkButton intent="primary" href="/" class="self-end">Go back home</LinkButton> 20 + </div> 21 + </div>
+10 -45
app/src/routes/+layout.svelte
··· 1 1 <script lang="ts"> 2 - import HouseIcon from '@lucide/svelte/icons/house' 3 2 import LogInIcon from '@lucide/svelte/icons/log-in' 4 - import LogOutIcon from '@lucide/svelte/icons/log-out' 5 - import SettingsIcon from '@lucide/svelte/icons/settings' 6 - import UserIcon from '@lucide/svelte/icons/user' 7 3 import UserPlusIcon from '@lucide/svelte/icons/user-plus' 8 - import { DropdownMenu, Tooltip, type WithChildren } from 'bits-ui' 4 + import { Tooltip, type WithChildren } from 'bits-ui' 9 5 import { pageTitle } from '$lib/utils' 10 - import { Avatar } from '$ui/avatar' 11 6 import { LinkButton } from '$ui/button' 12 - import { Menu } from '$ui/menu' 13 7 import { Header } from '$ui/site' 14 - import { Separator } from '$ui/separator' 15 8 import type { LayoutProps } from './$types' 9 + import CreateMenu from './CreateMenu.svelte' 10 + import SignedInMenu from './SignedInMenu.svelte' 16 11 import './../styles/app.css' 17 12 import '@fontsource-variable/suse' 18 13 import '@fontsource-variable/suse/wght-italic.css' ··· 31 26 <meta name="theme-color" content="#151512" media="(prefers-color-scheme: dark)"> 32 27 </svelte:head> 33 28 34 - {#snippet loggedInDropdown(username: string, userId: string, src?: string)} 35 - <DropdownMenu.Root> 36 - <Menu.Trigger> 37 - <Avatar {username} {src} /> 38 - </Menu.Trigger> 39 - <DropdownMenu.Portal> 40 - <Menu.Content> 41 - <Menu.Item href={'/'}> 42 - <HouseIcon class="size-5" strokeWidth={1.5} /> 43 - Home 44 - </Menu.Item> 45 - <Menu.Item href={`/users/${username}`}> 46 - <UserIcon class="size-5" strokeWidth={1.5} /> 47 - Profile 48 - </Menu.Item> 49 - <Menu.Item href={'/characters/new'}> 50 - <UserPlusIcon class="size-5" strokeWidth={1.5} /> 51 - New Character 52 - </Menu.Item> 53 - <Menu.Item> 54 - <SettingsIcon class="size-5" strokeWidth={1.5} /> 55 - Settings 56 - </Menu.Item> 57 - <Separator class="my-2" /> 58 - <Menu.Item href={'/signout'}> 59 - <LogOutIcon class="size-5" strokeWidth={1.5} /> 60 - Sign Out 61 - </Menu.Item> 62 - </Menu.Content> 63 - </DropdownMenu.Portal> 64 - </DropdownMenu.Root> 65 - {/snippet} 66 - 67 29 <Tooltip.Provider> 68 30 <div class={["flex flex-col gap-4 h-screen"]}> 69 31 <Header> 70 32 {#if data.user !== undefined} 71 33 {@const user = data.user} 72 34 {@const profile = user.image as (string|undefined)} 73 - {@render loggedInDropdown(user.name, user.id, profile)} 35 + <div class="flex flex-row gap-4 items-center"> 36 + <CreateMenu /> 37 + <SignedInMenu username={user.name} src={profile} /> 38 + </div> 74 39 {:else} 75 - <div class="flex flex-row gap-2"> 40 + <div class="flex flex-row gap-2 items-center"> 76 41 <LinkButton href="/signin" intent="secondary"> 77 42 <LogInIcon class="size-5" /> 78 - Sign In 43 + Sign in 79 44 </LinkButton> 80 45 <LinkButton href="/signup" intent="primary"> 81 46 <UserPlusIcon class="size-5" /> 82 - Sign up 47 + Create account 83 48 </LinkButton> 84 49 </div> 85 50 {/if}
+79 -35
app/src/routes/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { PageLayout } from '$ui/site' 3 + import HomepageCard from './HomepageCard.svelte' 3 4 </script> 4 5 5 - {#snippet card(text: string, columns: 2|3)} 6 - <a 7 - href={`/${text.toLowerCase()}`} 8 - class={[ 9 - columns === 2 && 'col-span-2', 10 - columns === 3 && 'col-span-3', 11 - "relative flex group overflow-hidden", 12 - "p-4 border border-zinc-300 transition-colors", 13 - "hover:border-hsr-gold hover:bg-hsr-gold/15", 14 - ]} 15 - > 16 - <div class="absolute right-0 -mr-24 -mt-24"> 17 - <div class={[ 18 - "size-48 rounded-full", 19 - "border border-dotted border-zinc-300", 20 - "transition-all", 21 - "group-hover:animate-ping", 22 - "group-hover:border-hsr-gold", 23 - ]}></div> 24 - </div> 25 - <span class="z-1 flex flex-col justify-between gap-32 h-24"> 26 - <span class={[ 27 - "text-zinc-900 dark:text-zinc-300 text-xl small-caps", 28 - "group-hover:text-hsr-gold mt-auto", 29 - ]}>{text}</span> 30 - </span> 31 - </a> 32 - {/snippet} 33 - 34 6 <PageLayout direction="col" items="stretch" class="gap-18"> 35 7 <div class="flex flex-col gap-2 mt-12"> 36 8 <span class="font-sans italic text-zinc-300 dark:text-zinc-700"> ··· 42 14 it exists beyond all doubt. 43 15 </p> 44 16 </div> 45 - <div class="grid grid-cols-6 gap-4"> 46 - {@render card('Abilities', 2)} 47 - {@render card('Mechanics', 2)} 48 - {@render card('Equipment', 2)} 49 - {@render card('Species', 2)} 50 - {@render card('Enemies', 2)} 17 + <div class="grid grid-cols-8 gap-4"> 18 + <HomepageCard text={'Species'} entries={6}> 19 + {#snippet icon()} 20 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 106.72 94.52" width={96} height={96}> 21 + <path stroke-width={0} d="M53.36,92.81c-.7-5.49-3.82-23.14-16.17-35.49C22.41,42.54,0,40.98,0,40.98c0,0,1.56,22.41,16.35,37.19,13.7,13.7,33.94,16.05,36.83,16.32,0,.01,0,.03,0,.03,0,0,.07,0,.18-.01.11,0,.18.01.18.01,0,0,0-.02,0-.03,2.89-.27,23.13-2.62,36.83-16.32,14.78-14.78,16.35-37.19,16.35-37.19,0,0-22.41,1.56-37.19,16.35-12.34,12.34-15.47,29.99-16.17,35.49Z"/> 22 + <path stroke-width={0} d="M53.18,53.51s0,.03,0,.03c0,0,.07,0,.18-.01.11,0,.18.01.18.01,0,0,0-.02,0-.03,2.89-.27,23.13-2.62,36.83-16.32C105.15,22.41,106.72,0,106.72,0c0,0-22.41,1.56-37.19,16.35-12.34,12.34-15.47,29.99-16.17,35.49-.7-5.49-3.82-23.14-16.17-35.49C22.41,1.56,0,0,0,0c0,0,1.56,22.41,16.35,37.19,13.7,13.7,33.94,16.05,36.83,16.32Z"/> 23 + </svg> 24 + {/snippet} 25 + </HomepageCard> 26 + <HomepageCard text={'Character Origins'} entries={4} urlSlug={'/origins'}> 27 + {#snippet icon()} 28 + <svg 29 + xmlns="http://www.w3.org/2000/svg" 30 + viewBox="0 0 108.89 108.89" 31 + width={96} height={96} 32 + > 33 + <g> 34 + <path d="M92.94,15.95C82.67,5.66,68.99,0,54.45,0S26.23,5.66,15.95,15.95C5.66,26.23,0,39.9,0,54.45s5.66,28.21,15.95,38.5c10.28,10.28,23.96,15.95,38.5,15.95s28.22-5.66,38.5-15.95c10.28-10.28,15.95-23.96,15.95-38.5s-5.66-28.22-15.95-38.5ZM106.73,53.38h-.16c-6,0-10.99-4.44-11.93-10.37-1.62-10.13-5.4-19.44-11.03-26.95-.13-.17-.27-.34-.4-.51,1.39-.57,2.76-1.17,4.08-1.83,1.44,1.16,2.83,2.4,4.15,3.73,9.63,9.63,15.02,22.35,15.29,35.92ZM81.13,92.52c-2.68-.99-5.48-1.83-8.38-2.51,3.65-9.6,5.69-21.67,5.8-34.5h1.29c7.72,0,13.53,7.18,11.77,14.7-1.97,8.4-5.52,16.06-10.45,22.31h-.02ZM27.74,92.52c-4.94-6.25-8.49-13.91-10.46-22.31-1.76-7.52,4.05-14.69,11.77-14.69h1.29c.11,12.83,2.15,24.9,5.8,34.5-2.91.68-5.7,1.52-8.38,2.51h-.02ZM27.76,16.37c2.68.99,5.48,1.83,8.38,2.51-3.65,9.6-5.69,21.67-5.8,34.5h-1.29c-7.72,0-13.53-7.18-11.77-14.69,1.97-8.4,5.52-16.06,10.46-22.31h.02ZM32.48,55.57c5.46.27,10.56,2.49,14.46,6.39,4.15,4.15,6.44,9.68,6.44,15.55v10.47c-5.16.06-10.23.61-15.12,1.6-3.63-9.39-5.67-21.31-5.78-34.01ZM53.38,18.78c-4.89-.06-9.69-.57-14.32-1.49.02-.05.04-.12.07-.17,3.92-9.06,8.94-14.31,14.26-14.93v16.59ZM38.26,19.32c4.89,1,9.95,1.54,15.12,1.6v10.47c0,5.88-2.29,11.4-6.44,15.55-3.9,3.9-9,6.12-14.46,6.39.11-12.7,2.15-24.62,5.78-34.01ZM53.38,90.11v16.58c-5.31-.62-10.34-5.86-14.26-14.93-.02-.06-.04-.12-.07-.17,4.63-.92,9.43-1.42,14.33-1.48ZM55.51,90.11c4.89.06,9.69.57,14.33,1.48-.02.06-.04.12-.07.17-3.92,9.06-8.94,14.31-14.26,14.93v-16.58ZM70.63,89.58c-4.88-.99-9.95-1.54-15.12-1.6v-10.47c0-5.88,2.29-11.4,6.44-15.55,3.9-3.89,9-6.12,14.46-6.39-.11,12.7-2.15,24.62-5.78,34.01ZM61.95,46.94c-4.15-4.15-6.44-9.68-6.44-15.55v-10.47c5.16-.06,10.23-.61,15.12-1.6,3.63,9.39,5.67,21.31,5.78,34.01-5.46-.27-10.56-2.49-14.46-6.39ZM55.51,18.78V2.2c5.32.62,10.34,5.87,14.26,14.93.02.05.04.12.07.17-4.64.92-9.43,1.42-14.32,1.49ZM71.73,16.28c-2.5-5.79-5.5-10.14-8.78-12.88,6.16,1.84,11.88,5.66,16.75,11.24-2.47.88-5.05,1.63-7.73,2.24-.08-.19-.15-.41-.23-.6ZM37.16,16.28c-.08.19-.15.4-.23.6-2.67-.61-5.25-1.36-7.73-2.24,4.86-5.58,10.59-9.4,16.74-11.24-3.29,2.74-6.28,7.09-8.78,12.88ZM36.93,92.02c.08.19.15.41.23.6,2.5,5.79,5.49,10.14,8.78,12.88-6.16-1.83-11.88-5.66-16.75-11.24,2.48-.88,5.06-1.63,7.73-2.24ZM71.73,92.61c.08-.19.15-.4.23-.6,2.67.61,5.25,1.36,7.73,2.24-4.86,5.58-10.59,9.4-16.75,11.24,3.29-2.74,6.28-7.09,8.78-12.88ZM78.55,53.38c-.11-12.83-2.15-24.91-5.8-34.5,2.91-.68,5.7-1.52,8.38-2.51h.02c4.94,6.26,8.49,13.91,10.46,22.31,1.76,7.52-4.05,14.7-11.77,14.7h-1.29ZM85.39,12.26c-1.16.55-2.36,1.07-3.58,1.55-3.01-3.57-6.36-6.49-9.94-8.71,4.82,1.7,9.37,4.1,13.52,7.16ZM27.09,13.81c-1.22-.48-2.42-1-3.58-1.55,4.15-3.06,8.7-5.46,13.52-7.16-3.58,2.22-6.93,5.15-9.94,8.71ZM17.46,17.46c1.33-1.33,2.72-2.57,4.15-3.73,1.32.65,2.68,1.26,4.07,1.83-.13.17-.27.33-.4.51-5.63,7.51-9.41,16.82-11.03,26.95-.95,5.93-5.93,10.37-11.93,10.37h-.16c.27-13.57,5.67-26.29,15.3-35.92ZM2.16,55.51h.16c6,0,10.98,4.44,11.93,10.37,1.62,10.13,5.39,19.44,11.03,26.95.13.17.27.34.4.51-1.39.57-2.76,1.17-4.07,1.83-1.44-1.16-2.83-2.4-4.15-3.73-9.63-9.63-15.02-22.35-15.3-35.92ZM23.51,96.63c1.16-.55,2.36-1.07,3.58-1.55,3.01,3.57,6.35,6.49,9.94,8.71-4.81-1.7-9.36-4.1-13.52-7.16ZM81.81,95.08c1.22.48,2.42,1,3.58,1.55-4.15,3.06-8.7,5.46-13.52,7.16,3.58-2.22,6.93-5.15,9.94-8.71ZM91.44,91.44c-1.33,1.33-2.72,2.57-4.15,3.73-1.32-.65-2.68-1.26-4.08-1.83.13-.17.27-.33.4-.51,5.63-7.51,9.41-16.82,11.03-26.95.95-5.93,5.93-10.37,11.93-10.37h.16c-.27,13.57-5.67,26.29-15.29,35.92Z"/> 35 + </g> 36 + </svg> 37 + {/snippet} 38 + </HomepageCard> 39 + <HomepageCard text={'Classes'} entries={2}> 40 + {#snippet icon()} 41 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 111.03 105.21" width={96} height={96}> 42 + <path fill-rule="evenodd" d="M55.51,0C36.88,0,21.82,15.09,21.82,33.53c0,2.24.22,4.43.64,6.55,3.54-1.25,7.36-1.94,11.33-1.94,8.27,0,15.87,2.99,21.75,7.95,5.87-4.96,13.47-7.95,21.79-7.95,3.94,0,7.72.68,11.24,1.91.42-2.11.64-4.29.64-6.52C89.21,15.09,74.15,0,55.51,0ZM55.51,29.02c-5.21-2.69-10.91-4.32-16.8-5,3.38-5.76,9.65-9.7,16.8-9.7s13.52,3.94,16.8,9.7c-5.89.67-11.59,2.31-16.8,5Z"/> 43 + <path fill-rule="evenodd" d="M43.64,71.68c0-2.21.22-4.36.63-6.44-11.08-3.92-19.48-13.45-21.8-25.15C9.39,44.7,0,57.09,0,71.68c0,18.54,15.16,33.53,33.79,33.53,8.27,0,15.87-2.99,21.75-7.95-7.28-6.15-11.9-15.32-11.9-25.58ZM14.39,71.68c0-3.46.97-6.73,2.61-9.51,3.38,4.52,7.53,8.46,12.26,11.53.29,5.96,1.64,11.82,4.06,17.2-10.52-.29-18.92-8.74-18.92-19.22Z"/> 44 + <path fill-rule="evenodd" d="M66.85,65.21c.41,2.09.63,4.26.63,6.47,0,10.27-4.65,19.44-11.94,25.58,5.87,4.96,13.47,7.95,21.79,7.95,18.63,0,33.7-14.99,33.7-33.53,0-14.62-9.37-27.02-22.46-31.62-2.3,11.68-10.67,21.21-21.72,25.15ZM94.13,62.17c1.64,2.79,2.51,6.05,2.51,9.51,0,10.47-8.4,18.93-18.83,19.22,2.32-5.38,3.77-11.24,3.96-17.2,4.83-3.07,8.98-7.01,12.36-11.53Z"/> 45 + <path fill-rule="evenodd" d="M44.27,65.24c3.52,1.24,7.3,1.93,11.25,1.93s7.79-.69,11.34-1.96c-1.5-7.61-5.59-14.29-11.31-19.11-5.72,4.83-9.79,11.52-11.28,19.14Z"/> 46 + </svg> 47 + {/snippet} 48 + </HomepageCard> 49 + <HomepageCard text={'Abilities'} entries={152}> 50 + {#snippet icon()} 51 + <svg 52 + xmlns="http://www.w3.org/2000/svg" 53 + viewBox="0 0 117.19 108.89" 54 + height={96} 55 + > 56 + <path stroke-width={0} d="M102.88,20.08c-7.21,9.41-14.42,18.82-21.63,28.23.24.3.49.59.73.89,5.46-1.72,10.91-3.44,16.37-5.16.3.6.59,1.2.89,1.8-4.83,3.54-9.67,7.07-14.5,10.61.05.41.1.81.16,1.22,10.76,1.27,21.53,2.54,32.29,3.81,0,.64,0,1.27,0,1.91-11.46,1.8-22.92,3.6-35.43,5.56,4.72,4.49,8.72,8.28,12.71,12.08l-.84,1.46c-5.47-2.03-10.93-4.05-16.4-6.08-.28.29-.55.58-.83.87,6.15,10.22,12.29,20.45,18.44,30.67-.32.32-.63.63-.95.95-1.08-.66-2.3-1.17-3.23-2.01-9.27-8.38-18.47-16.83-27.74-25.21-3.83-3.46-5.08-3.38-8.93.13-8.97,8.17-17.91,16.36-26.9,24.5-1.11,1-2.41,1.79-4.22,2.24,5.03-10.99,11.99-20.82,17.68-31.34-.2-.28-.41-.56-.61-.84-5.5,2.03-11,4.07-16.51,6.1-.31-.47-.62-.94-.93-1.41,3.98-3.77,7.96-7.54,12.8-12.12-12.44-1.94-23.87-3.73-35.31-5.51,0-.55,0-1.1,0-1.64,10.48-2.5,21.46-2.05,32.39-5.2-4.83-3.57-9.66-7.15-14.49-10.72.2-.39.41-.78.61-1.18,5.78.05,10.88,3.39,17.67,4.54-7.1-10.71-15.35-19.37-21.85-29.23.42-.42.85-.84,1.27-1.26,9.14,6.9,18.29,13.81,27.43,20.71.34-.16.68-.32,1.03-.47-1.06-6.58-2.13-13.15-3.19-19.73.54-.21,1.09-.42,1.63-.63,2.96,5.27,5.92,10.54,8.88,15.81.4-.09.81-.19,1.21-.28L57.58,0c.63.01,1.26.03,1.89.04,1.65,11.39,3.31,22.79,4.96,34.18.42.07.84.13,1.26.2,2.93-5.27,5.87-10.54,8.8-15.81.55.18,1.11.36,1.66.54-1.06,6.58-2.13,13.17-3.19,19.75.28.21.56.41.84.62,9.23-6.93,18.47-13.86,27.7-20.79.45.45.91.9,1.36,1.35ZM58.67,73.02c8.31-.03,15.12-6.71,15.16-14.87.04-8.29-6.94-15.3-15.26-15.33-8.31-.03-15.27,6.91-15.28,15.24-.01,8.41,6.75,14.98,15.38,14.96Z"/> 57 + </svg> 58 + {/snippet} 59 + </HomepageCard> 60 + <HomepageCard text={'Feats'} entries={23}> 61 + {#snippet icon()} 62 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.57 108.89" width={96} height={96}> 63 + <path d="M95.67,41.98c-5.42,0-9.99,3.63-11.43,8.59-.39,1.35-1.62,2.29-3.02,2.29h-12.08c-4.52,0-6.78-5.47-3.59-8.66l8.36-8.36c1-1,2.53-1.2,3.76-.52,4.52,2.49,10.32,1.82,14.15-2.01,4.8-4.8,4.65-12.68-.47-17.29-4.61-4.15-11.83-3.99-16.27.34-3.93,3.84-4.63,9.7-2.12,14.27.68,1.23.47,2.76-.52,3.75l-8.97,8.97c-3.2,3.2-8.66.93-8.66-3.59v-13.4c0-1.41.93-2.63,2.28-3.02,5.04-1.46,8.7-6.14,8.59-11.67-.12-6.17-5.1-11.33-11.26-11.65-6.87-.36-12.56,5.1-12.56,11.89,0,5.42,3.63,9.99,8.59,11.43,1.35.39,2.29,1.62,2.29,3.02v13.4c0,4.52-5.47,6.78-8.66,3.59l-8.97-8.97c-.99-.99-1.2-2.52-.52-3.75,2.52-4.57,1.82-10.43-2.12-14.27-4.44-4.33-11.65-4.49-16.27-.34-5.11,4.6-5.27,12.48-.47,17.29,3.83,3.83,9.63,4.5,14.15,2.01,1.23-.68,2.76-.48,3.76.52l8.36,8.36c3.2,3.2.93,8.66-3.59,8.66h-12.07c-1.41,0-2.63-.94-3.02-2.29-1.44-4.96-6.01-8.59-11.43-8.59C5.12,41.98-.35,47.66.02,54.53c.32,6.16,5.48,11.14,11.65,11.26,5.53.11,10.22-3.55,11.68-8.59.39-1.35,1.62-2.28,3.02-2.28h13.18c4.52,0,6.78,5.47,3.59,8.66l-9.47,9.47c-1,1-2.53,1.2-3.76.52-4.52-2.49-10.32-1.82-14.15,2.01-4.8,4.8-4.65,12.68.47,17.29,4.61,4.15,11.82,3.99,16.27-.34,3.93-3.84,4.64-9.7,2.12-14.27-.68-1.23-.47-2.76.52-3.75l8.97-8.97c3.2-3.2,8.66-.93,8.66,3.59v13.4c0,1.41-.94,2.63-2.29,3.02-4.96,1.44-8.59,6.01-8.59,11.43,0,6.79,5.68,12.25,12.56,11.89,6.16-.33,11.14-5.48,11.26-11.65.11-5.53-3.56-10.22-8.59-11.67-1.35-.39-2.28-1.62-2.28-3.02v-13.4c0-4.52,5.47-6.78,8.66-3.59l8.97,8.97c.99.99,1.2,2.52.52,3.75-2.52,4.57-1.82,10.43,2.12,14.27,4.44,4.33,11.66,4.49,16.27.34,5.11-4.6,5.27-12.48.47-17.29-3.83-3.83-9.63-4.5-14.15-2.01-1.23.68-2.76.48-3.76-.52l-9.47-9.47c-3.2-3.2-.93-8.66,3.59-8.66h13.2c1.4,0,2.63.93,3.02,2.28,1.46,5.04,6.14,8.7,11.68,8.59,6.17-.12,11.32-5.1,11.65-11.26.36-6.87-5.1-12.55-11.89-12.55Z"/> 64 + </svg> 65 + {/snippet} 66 + </HomepageCard> 67 + <HomepageCard text={'Equipment'} entries={75}> 68 + {#snippet icon()} 69 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.21 108.89" width={96} height={96}> 70 + <path stroke-width={0} d="M53.71.72c-1.64-.96-3.66-.96-5.3,0l-25.19,14.74,49.26,28.78v58.27l25.13-14.7c1.61-.94,2.6-2.66,2.6-4.53V27.93L53.71.72Z"/> 71 + <path stroke-width={0} d="M23.27,30.91L0,44.28l36.57,21.36v43.25l23.22-13.35c1.19-.7,1.93-1.98,1.93-3.36v-41.08L27.2,30.91c-1.21-.71-2.72-.71-3.93,0Z"/> 72 + <polygon stroke-width={0} points="25.5 100.82 25.5 71.64 .56 86.23 25.5 100.82"/> 73 + </svg> 74 + {/snippet} 75 + </HomepageCard> 76 + <HomepageCard text={'Enemies'} entries={24}> 77 + {#snippet icon()} 78 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120.02 60.51" width={96} height={96}> 79 + <path stroke-width={0} d="M37.42,59.78C21.88,54.19,8.8,44.08,0,30.68,9.89,16.69,19.7,7.83,40.16.68c-20.74,11.74-22.35,45.43-2.74,59.1Z"/> 80 + <path stroke-width={0} d="M120.02,30.68c-8.57,13.46-23.87,25-39.57,29.83,20.97-13.56,19.23-49.05-2.88-60.51,15.12,2.85,36.71,19.75,42.45,30.68Z"/> 81 + <path stroke-width={0} d="M37.42,59.78C21.88,54.2,8.79,44.08,0,30.68,9.89,16.69,19.71,7.83,40.16.68c-20.74,11.74-22.35,45.43-2.74,59.1Z"/> 82 + <polygon stroke-width={0} points="65.91 38.82 67.95 55.13 60.01 40.73 52.07 55.13 54.11 38.81 39.22 45.8 50.45 33.79 34.31 30.68 50.45 27.57 39.22 15.57 54.11 22.55 52.07 6.23 60.01 20.63 67.95 6.23 65.91 22.55 80.8 15.57 69.57 27.57 85.71 30.68 69.57 33.79 80.8 45.8 65.91 38.82"/> 83 + <path stroke-width={0} d="M120.02,30.68c-8.57,13.46-23.87,25-39.57,29.83,20.97-13.56,19.23-49.05-2.88-60.51,15.11,2.85,36.71,19.75,42.45,30.68Z"/> 84 + <polygon stroke-width={0} points="80.8 45.8 65.91 38.82 67.95 55.13 60.01 40.73 52.07 55.13 54.11 38.81 39.22 45.8 50.45 33.79 34.31 30.68 50.45 27.57 39.22 15.57 54.11 22.55 52.07 6.23 60.01 20.63 67.95 6.23 65.91 22.55 80.8 15.57 69.57 27.57 85.71 30.68 69.57 33.79 80.8 45.8"/> 85 + </svg> 86 + {/snippet} 87 + </HomepageCard> 88 + <HomepageCard text={'Animals'} entries={17}> 89 + {#snippet icon()} 90 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 113.78 86.52" width={96} height={96}> 91 + <path fill-rule="evenodd" stroke-width={0} d="M56.82,39.62c.36-.11.65-.36.81-.7,2.67-5.78,6.91-12.31,12.35-18.67C82.98,5.07,97.97-3.41,103.48,1.3c5.39,4.61-.33,20.17-12.77,35.07,12.91.72,22.34,4.78,23.03,10.74.84,7.16-11.19,14.66-27.83,17.93,5.47,8.6,7.01,16.89,3.22,20.13-4.69,4.01-15.76-1.23-24.74-11.71-2.11-2.46-3.92-5-5.38-7.48l-.21-.19c-1.43-1.29-3.63-1.15-4.88.31h0c-1.45,2.45-3.24,4.94-5.31,7.36-8.98,10.48-20.05,15.72-24.74,11.71-3.81-3.26-2.23-11.63,3.31-20.27C10.9,61.56-.79,54.17.04,47.11c.68-5.83,9.7-9.83,22.16-10.69C9.72,21.51,3.99,5.92,9.38,1.3c5.5-4.71,20.5,3.77,33.5,18.95,5.44,6.35,9.67,12.87,12.34,18.65.28.61.96.92,1.59.72h0Z"/> 92 + </svg> 93 + {/snippet} 94 + </HomepageCard> 51 95 </div> 52 96 </PageLayout>
+24
app/src/routes/CreateMenu.svelte
··· 1 + <script lang="ts"> 2 + import PlusIcon from '@lucide/svelte/icons/plus' 3 + import { Button } from '$ui/button' 4 + import { Menu } from '$ui/menu' 5 + import { DropdownMenu } from 'bits-ui' 6 + </script> 7 + 8 + <DropdownMenu.Root> 9 + <Menu.Trigger> 10 + {#snippet child({ props })} 11 + <Button {...props} intent="secondary"> 12 + <PlusIcon class="size-5" strokeWidth={1.5} /> 13 + New 14 + </Button> 15 + {/snippet} 16 + </Menu.Trigger> 17 + <DropdownMenu.Portal> 18 + <Menu.Content align="end" sideOffset={4}> 19 + <Menu.LinkItem href={'/campaigns/new'}>New Campaign</Menu.LinkItem> 20 + <Menu.LinkItem href={'/characters/new'}>New Character</Menu.LinkItem> 21 + <Menu.LinkItem href={'/species/new'}>New Species</Menu.LinkItem> 22 + </Menu.Content> 23 + </DropdownMenu.Portal> 24 + </DropdownMenu.Root>
+70
app/src/routes/HomepageCard.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte' 3 + 4 + type Props = { 5 + text: string, 6 + entries?: number, 7 + urlSlug?: string, 8 + icon?: Snippet, 9 + } 10 + let { text, entries, urlSlug, icon }: Props = $props() 11 + const usableSlug = $derived.by(() => { 12 + return !urlSlug ? `/${text.toLowerCase()}` : urlSlug 13 + }) 14 + </script> 15 + 16 + <a 17 + href={usableSlug} 18 + class={[ 19 + "min-h-36", 20 + "col-span-2", 21 + "relative flex flex-row items-end group overflow-clip", 22 + "p-4 border border-stone-200 transition-colors", 23 + "rounded-tr-xl", 24 + "hover:border-hsr-gold hover:bg-hsr-gold/15", 25 + "pattern-diagonal-lines bg-pattern-sm", 26 + "text-stone-50 hover:text-hsr-gold/25", 27 + ]} 28 + > 29 + <div class={[ 30 + "absolute -bottom-4.5 -right-4.5", 31 + "fill-stone-100 group-hover:fill-hsr-gold", 32 + "transition-colors", 33 + ]}> 34 + {@render icon?.()} 35 + </div> 36 + <div class="absolute top-4 left-4" aria-hidden={true}> 37 + <div class="h-0.5 w-4 bg-stone-100 group-hover:bg-stone-500"></div> 38 + </div> 39 + <div class="absolute top-4 right-4 flex flex-row gap-2" aria-hidden={true}> 40 + <div class="bg-stone-100 group-hover:bg-stone-500 bg-grid bg-pattern-md h-0.5 w-2"></div> 41 + <div class="bg-stone-100 group-hover:bg-stone-500 bg-grid bg-pattern-md h-0.5 w-5"></div> 42 + <div class="bg-stone-100 group-hover:bg-stone-500 bg-grid bg-pattern-md h-0.5 w-20 rounded-tr-xl"></div> 43 + </div> 44 + <div class="z-1 flex items-end"> 45 + <div class="flex flex-col leading-tight"> 46 + <div class={[ 47 + "font-script uppercase text-xs select-none", 48 + "text-stone-400 group-hover:text-hsr-gold", 49 + ]}>{text}</div> 50 + <div class="flex flex-row gap-4 items-center justify-between"> 51 + <span class={[ 52 + "text-zinc-900 dark:text-zinc-300", 53 + "text-xl font-sans", 54 + "group-hover:text-hsr-gold mt-auto", 55 + ]}>{text}</span> 56 + {#if entries}{@render entryCount(entries)}{/if} 57 + </div> 58 + </div> 59 + </div> 60 + </a> 61 + 62 + {#snippet entryCount(entryCount: number)} 63 + <div class={[ 64 + "bg-stone-500 py-0.5 px-1 rounded-xs", 65 + "text-xs text-white group-hover:text-white", 66 + "font-mono small-caps" 67 + ]}> 68 + {entryCount} entries 69 + </div> 70 + {/snippet}
+43
app/src/routes/SignedInMenu.svelte
··· 1 + <script lang="ts"> 2 + import HouseIcon from '@lucide/svelte/icons/house' 3 + import LogOutIcon from '@lucide/svelte/icons/log-out' 4 + import SettingsIcon from '@lucide/svelte/icons/settings' 5 + import UserIcon from '@lucide/svelte/icons/user' 6 + import { Avatar } from '$ui/avatar' 7 + import { Menu } from '$ui/menu' 8 + import { Separator } from '$ui/separator' 9 + import { DropdownMenu } from 'bits-ui' 10 + 11 + type Props = { 12 + username: string, 13 + src?: string, 14 + } 15 + let { username, src }: Props = $props() 16 + </script> 17 + 18 + <DropdownMenu.Root> 19 + <Menu.Trigger> 20 + <Avatar {username} {src} /> 21 + </Menu.Trigger> 22 + <DropdownMenu.Portal> 23 + <Menu.Content align="end" sideOffset={4}> 24 + <Menu.LinkItem href={'/'}> 25 + <HouseIcon class="size-5" strokeWidth={1.5} /> 26 + Home 27 + </Menu.LinkItem> 28 + <Menu.LinkItem href={`/users/${username}`}> 29 + <UserIcon class="size-5" strokeWidth={1.5} /> 30 + Profile 31 + </Menu.LinkItem> 32 + <Menu.LinkItem href={'/settings'}> 33 + <SettingsIcon class="size-5" strokeWidth={1.5} /> 34 + Settings 35 + </Menu.LinkItem> 36 + <Separator class="my-2" /> 37 + <Menu.LinkItem href={'/signout'}> 38 + <LogOutIcon class="size-5" strokeWidth={1.5} /> 39 + Sign Out 40 + </Menu.LinkItem> 41 + </Menu.Content> 42 + </DropdownMenu.Portal> 43 + </DropdownMenu.Root>
+10
app/src/routes/campaigns/new/+page.server.ts
··· 1 + import { pageTitle } from '$lib/utils' 2 + import type { PageServerLoad } from './$types' 3 + 4 + export const load: PageServerLoad = async () => { 5 + return { 6 + meta: { 7 + pageTitle: pageTitle('Create a new campaign'), 8 + }, 9 + } 10 + }
+40
app/src/routes/campaigns/new/+page.svelte
··· 1 + <script lang="ts"> 2 + import { Button } from '$ui/button' 3 + import { Field } from '$ui/field' 4 + import { Heading, HeadingGroup, SubHeading } from '$ui/heading' 5 + import { PageLayout } from '$ui/site' 6 + import { TextAreaInput, TextInput } from '$ui/text-input' 7 + import type { PageProps } from './$types' 8 + 9 + let { data }: PageProps = $props() 10 + const { meta: { pageTitle } } = $derived(data) 11 + </script> 12 + 13 + <svelte:head> 14 + <title>{pageTitle}</title> 15 + </svelte:head> 16 + 17 + <PageLayout display="flex" direction="col" class="gap-8 mx-auto" items="stretch"> 18 + <HeadingGroup> 19 + <Heading level={1}>Create a new campaign</Heading> 20 + <SubHeading isScript>Create a new campaign</SubHeading> 21 + </HeadingGroup> 22 + <form class="flex flex-col items-start gap-10 min-w-2xl"> 23 + <Field.Root class="w-20ch"> 24 + <Field.Label>Campaign name</Field.Label> 25 + <TextInput 26 + name="name" 27 + maxlength={20} /> 28 + </Field.Root> 29 + <Field.Root> 30 + <Field.Label>Campaign description</Field.Label> 31 + <TextAreaInput 32 + name="description" 33 + rows={7} 34 + resizable /> 35 + </Field.Root> 36 + <Button type="submit" intent="primary"> 37 + Create campaign 38 + </Button> 39 + </form> 40 + </PageLayout>
-20
app/src/routes/species/+page.svelte
··· 7 7 8 8 </div> 9 9 </PageLayout> 10 - 11 - <!-- <SpeciesCard name="Halovian"> 12 - <p>Humanoid species with angelic features that follow Xipe, the Aeon of Harmony. 13 - They're known to be naturally charming and intelligent, with some capable of using their charisma 14 - to influence societies at the national level. They are the artists that many love, including singers, dancers, and actors.</p> 15 - </SpeciesCard> 16 - <SpeciesCard name="Vidyadhara"> 17 - <p>Human hybrids with draconic features, known to be able to live up to 700 years. 18 - They are thought to be descendants of the aeon who had departed this universe; Long the Permanence.</p> 19 - </SpeciesCard> 20 - <SpeciesCard name="Foxian"> 21 - <LoremIpsum 22 - wordsPerSentence={{min: 10, max: 20}} 23 - sentencesPerParagraph={{min: 1, max: 2}} 24 - generate={['sentences', 2]} /> 25 - </SpeciesCard> 26 - <SpeciesCard name="Intellitron"> 27 - <p>Intellitrons are intelligent mechanic lifeforms, capable of forming their own thoughts and deductive reasoning. 28 - They have robust pattern recognition skills, and many are curious about worlds beyond their own.</p> 29 - </SpeciesCard> -->
+1 -1
app/src/routes/species/new/+page.svelte
··· 31 31 <Heading level={1}>Register a new species</Heading> 32 32 <SubHeading isScript>Register a new species</SubHeading> 33 33 </HeadingGroup> 34 - <form class="flex flex-col items-start gap-10 max-w-100ch"> 34 + <form class="flex flex-col items-start gap-10"> 35 35 <Field.Root> 36 36 <Field.Label>Species name</Field.Label> 37 37 <TextInput
app/src/routes/users/settings/+page.svelte app/src/routes/settings/+page.svelte
+22 -1
app/src/styles/utilities.css
··· 43 43 } 44 44 45 45 /** background */ 46 - @utility bg-diagonal-lines { 46 + @utility pattern-grid { 47 + background-image: 48 + linear-gradient(currentColor 1px, transparent 1px), 49 + linear-gradient(to right, currentColor 1px, transparent 1px); 50 + } 51 + 52 + @utility pattern-diagonal-lines { 47 53 background-image: repeating-linear-gradient( 48 54 -45deg, 49 55 currentColor 0, ··· 51 57 transparent 0, 52 58 transparent 50% 53 59 ); 60 + } 61 + 62 + @utility bg-pattern-sm { 54 63 background-size: 10px 10px; 55 64 } 65 + 66 + @utility bg-pattern-md { 67 + background-size: 25px 25px; 68 + } 69 + 70 + @utility bg-pattern-lg { 71 + background-size: 50px 50px; 72 + } 73 + 74 + @utility bg-pattern-xl { 75 + background-size: 100px 100px; 76 + }
+8
app/svelte.config.js
··· 12 12 preprocess: [vitePreprocess()], 13 13 compilerOptions: { 14 14 preserveComments: false, 15 + experimental: { 16 + // required by svelte-crumbs 17 + async: true, 18 + }, 15 19 }, 16 20 kit: { 17 21 adapter: adapter({ ··· 26 30 $patterns: 'src/lib/ui-patterns', 27 31 $server: 'src/lib/server', 28 32 $story: '.storybook/', 33 + }, 34 + experimental: { 35 + // required by svelte-crumbs 36 + remoteFunctions: true, 29 37 }, 30 38 }, 31 39 extensions: ['.svelte'],
-4
app/tsconfig.json
··· 1 1 { 2 2 "extends": "./.svelte-kit/tsconfig.json", 3 - "exclude": [ 4 - "**/node_modules/*", 5 - "**/.svelte-kit/*" 6 - ], 7 3 "compilerOptions": { 8 4 "allowJs": true, 9 5 "checkJs": true,
+17
pnpm-lock.yaml
··· 132 132 svelte-check: 133 133 specifier: ^4.4.4 134 134 version: 4.4.4 135 + svelte-crumbs: 136 + specifier: ^1.3.0 137 + version: 1.3.0 135 138 sveltekit-superforms: 136 139 specifier: ^2.30.0 137 140 version: 2.30.0 ··· 325 328 resend: 326 329 specifier: catalog:app 327 330 version: 6.9.3 331 + svelte-crumbs: 332 + specifier: catalog:svelte 333 + version: 1.3.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7) 328 334 sveltekit-superforms: 329 335 specifier: catalog:svelte 330 336 version: 2.30.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(@types/json-schema@7.0.15)(svelte@5.53.7)(typescript@5.9.3) ··· 4462 4468 svelte: ^4.0.0 || ^5.0.0-next.0 4463 4469 typescript: '>=5.0.0' 4464 4470 4471 + svelte-crumbs@1.3.0: 4472 + resolution: {integrity: sha512-+D+8TWRkZqgZGp/s07CGCKhU0HzM/08WXo+2gq/OCWsZdwxAVabS9UBHb84IZpT2RQqF4erwAKt7nw7Ype8UPQ==} 4473 + peerDependencies: 4474 + '@sveltejs/kit': ^2.0.0 4475 + svelte: ^5.0.0 4476 + 4465 4477 svelte-eslint-parser@1.6.0: 4466 4478 resolution: {integrity: sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw==} 4467 4479 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.30.3} ··· 8550 8562 typescript: 5.9.3 8551 8563 transitivePeerDependencies: 8552 8564 - picomatch 8565 + 8566 + svelte-crumbs@1.3.0(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7): 8567 + dependencies: 8568 + '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@2.6.1)(lightningcss@1.31.1)) 8569 + svelte: 5.53.7 8553 8570 8554 8571 svelte-eslint-parser@1.6.0(svelte@5.53.7): 8555 8572 dependencies:
+2 -1
pnpm-workspace.yaml
··· 4 4 5 5 catalogs: 6 6 app: 7 - '@better-auth/drizzle-adapter': '^1.5.4' 7 + '@better-auth/drizzle-adapter': ^1.5.4 8 8 '@fontsource-variable/fraunces': ^5.2.9 9 9 '@fontsource-variable/suse': ^5.2.9 10 10 '@fontsource-variable/suse-mono': ^5.2.1 ··· 48 48 mode-watcher: ^1.1.0 49 49 svelte: ^5.53.6 50 50 svelte-check: ^4.4.4 51 + svelte-crumbs: ^1.3.0 51 52 sveltekit-superforms: ^2.30.0 52 53 vitest-browser-svelte: ^2.0.2 53 54 tailwind: