feat(ui): enhance ModuleWrapper layout and add stories for testing

This commit is contained in:
melvinchia3636
2026-04-19 18:09:40 +08:00
parent 0aa2773028
commit 075ab0ddb2
2 changed files with 113 additions and 8 deletions

View File

@@ -0,0 +1,95 @@
import type { Meta, StoryObj } from '@storybook/react-vite'
import { ModuleHeader } from '@components/layout'
import { Box, Flex, Grid, Text } from '@components/primitives'
import ModuleWrapper from './index'
const meta = {
component: ModuleWrapper,
argTypes: {
children: { control: false }
}
} satisfies Meta<typeof ModuleWrapper>
export default meta
type Story = StoryObj<typeof meta>
// ─── Helpers ──────────────────────────────────────────────────────────────────
function StatCard({ label, value }: { label: string; value: string }) {
return (
<Box shadow bg={{ base: 'bg-50', dark: 'bg-900' }} p="lg" rounded="lg">
<Text color={{ base: 'bg-500', dark: 'bg-400' }} size="sm">
{label}
</Text>
<Text as="p" mt="xs" size="2xl" weight="bold">
{value}
</Text>
</Box>
)
}
function ContentCard({ title, body }: { title: string; body: string }) {
return (
<Box shadow bg={{ base: 'bg-50', dark: 'bg-900' }} p="lg" rounded="lg">
<Text as="h3" mb="xs" size="lg" weight="semibold">
{title}
</Text>
<Text color={{ base: 'bg-500', dark: 'bg-400' }} size="sm">
{body}
</Text>
</Box>
)
}
// ─── Stories ──────────────────────────────────────────────────────────────────
/**
* The default `ModuleWrapper` sets up the module header context, a scrollable
* content area, and proper padding. Pair it with `ModuleHeader` as the first
* child to render the icon, title, and description bar.
*/
export const Default: Story = {
args: {
children: <></>,
config: {
title: 'Demo Module',
icon: 'tabler:cube',
clearQueryOnUnmount: false
}
},
render: args => (
<Box height="100vh" minHeight="100vh" width="100%">
<ModuleWrapper {...args}>
<ModuleHeader />
<Grid columns="repeat(3, minmax(0, 1fr))" gap="md" mb="xl" width="100%">
<StatCard label="Total Items" value="1,284" />
<StatCard label="Active" value="847" />
<StatCard label="Completed" value="437" />
</Grid>
<Flex direction="column" gap="md" width="100%">
<ContentCard
body="Here is a brief summary of the first item in your module. It contains useful information."
title="First Entry"
/>
<ContentCard
body="This is the second entry in the list. Use this area to display relevant module data."
title="Second Entry"
/>
<ContentCard
body="A third entry demonstrating how the module content area scrolls naturally."
title="Third Entry"
/>
<ContentCard
body="Another entry to show padding and spacing consistency across the module body."
title="Fourth Entry"
/>
</Flex>
</ModuleWrapper>
</Box>
)
}

View File

@@ -7,8 +7,12 @@ import {
normalizeSubnamespace
} from 'shared'
import { Flex } from '@components/primitives'
import { Scrollbar } from '@components/utilities'
/**
* The wrapper component for all modules in the app. It provides the layout and context for the module header and sidebar, as well as handling query cleanup on unmount if specified. If being used within LifeForge instance, it will be automatically wrapped around the module content. Therefore, no explicit usage is needed in most cases.
*/
function ModuleWrapper({
children,
config: { title, icon, clearQueryOnUnmount = true }
@@ -38,14 +42,20 @@ function ModuleWrapper({
value={{ title: normalizeSubnamespace(title).replace('__', '$'), icon }}
>
<ModuleSidebarStateProvider>
<Scrollbar
className="no-overflow-x flex min-h-0 flex-col transition-all"
usePaddingRight={false}
>
<div className="flex w-full flex-1 flex-col px-4 pt-8 sm:px-12">
{children}
</div>
</Scrollbar>
<Flex asChild direction="column" minHeight="0">
<Scrollbar className="no-overflow-x" usePaddingRight={false}>
<Flex
direction="column"
flex="1"
overflowX="hidden"
pt="xl"
px={{ base: 'md', sm: '2xl' }}
width="100%"
>
{children}
</Flex>
</Scrollbar>
</Flex>
</ModuleSidebarStateProvider>
</ModuleHeaderStateProvider>
)