Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/component-library/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const config: StorybookConfig = {
core: {
disableTelemetry: true,
},
staticDirs: ['./public'],
async viteFinal(config) {
const { mergeConfig } = await import('vite');

Expand Down
9 changes: 9 additions & 0 deletions packages/component-library/.storybook/public/_headers
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

# /assets folder contain processed assets with a file hash
# They are safe for immutable caching, as filename change when content change

/assets/*
Cache-Control: public
Cache-Control: max-age=365000000
Cache-Control: immutable

139 changes: 139 additions & 0 deletions packages/component-library/src/AlignedText.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import type { Meta, StoryObj } from '@storybook/react-vite';

import { AlignedText } from './AlignedText';

const meta = {
title: 'AlignedText',
component: AlignedText,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof AlignedText>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
left: 'Label',
right: 'Value',
style: { width: 300, display: 'flex' },
},
parameters: {
docs: {
description: {
story:
'AlignedText displays two pieces of content aligned on opposite sides.',
},
},
},
};

export const TruncateLeft: Story = {
args: {
left: 'This is a very long label that should be truncated on the left side',
right: '$100.00',
truncate: 'left',
style: { width: 250, display: 'flex' },
},
parameters: {
docs: {
description: {
story:
'When `truncate="left"`, the left content is truncated with ellipsis.',
},
},
},
};

export const TruncateRight: Story = {
args: {
left: 'Short Label',
right:
'This is a very long value that should be truncated on the right side',
truncate: 'right',
style: { width: 250, display: 'flex' },
},
parameters: {
docs: {
description: {
story:
'When `truncate="right"`, the right content is truncated with ellipsis.',
},
},
},
};

export const FinancialAmount: Story = {
args: {
left: 'Groceries',
right: '$1,234.56',
style: { width: 300, display: 'flex' },
rightStyle: { fontWeight: 'bold' },
},
parameters: {
docs: {
description: {
story:
'Example showing AlignedText used for displaying financial data.',
},
},
},
};

export const WithCustomStyles: Story = {
args: {
left: 'Category',
right: 'Amount',
style: {
width: 300,
padding: 10,
backgroundColor: '#f5f5f5',
borderRadius: 4,
display: 'flex',
},
leftStyle: { color: '#666', fontStyle: 'italic' },
rightStyle: { color: '#333', fontWeight: 'bold' },
},
};

export const MultipleRows: Story = {
args: {
left: 'Income',
right: '$5,000.00',
},
render: () => (
<div
style={{ width: 300, display: 'flex', flexDirection: 'column', gap: 8 }}
>
<AlignedText
left="Income"
right="$5,000.00"
rightStyle={{ color: 'green' }}
style={{ display: 'flex' }}
/>
<AlignedText
left="Expenses"
right="-$3,200.00"
rightStyle={{ color: 'red' }}
style={{ display: 'flex' }}
/>
<AlignedText
left="Balance"
right="$1,800.00"
style={{ borderTop: '1px solid #ccc', paddingTop: 8, display: 'flex' }}
rightStyle={{ fontWeight: 'bold' }}
/>
</div>
),
parameters: {
docs: {
description: {
story:
'Multiple AlignedText components stacked to create a summary view.',
},
},
},
};
111 changes: 111 additions & 0 deletions packages/component-library/src/Block.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type { Meta, StoryObj } from '@storybook/react-vite';

import { Block } from './Block';
import { theme } from './theme';

const meta = {
title: 'Block',
component: Block,
parameters: {
layout: 'centered',
},
} satisfies Meta<typeof Block>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
children: 'This is a Block component',
},
parameters: {
docs: {
description: {
story:
'Block is a basic div wrapper that accepts Emotion CSS styles via the `style` prop.',
},
},
},
tags: ['autodocs'],
};

export const WithStyles: Story = {
args: {
children: 'Styled Block',
style: {
padding: 20,
backgroundColor: theme.cardBackground,
borderRadius: 8,
border: `1px solid ${theme.cardBorder}`,
color: theme.pageText,
},
},
};

export const WithFlexLayout: Story = {
render: () => (
<Block
style={{
display: 'flex',
gap: 10,
padding: 15,
borderRadius: 4,
color: theme.pageText,
}}
>
<Block
style={{
padding: 10,
backgroundColor: theme.cardBackground,
borderRadius: 4,
border: `1px solid ${theme.cardBorder}`,
}}
>
Item 1
</Block>
<Block
style={{
padding: 10,
backgroundColor: theme.cardBackground,
borderRadius: 4,
border: `1px solid ${theme.cardBorder}`,
}}
>
Item 2
</Block>
<Block
style={{
padding: 10,
backgroundColor: theme.cardBackground,
borderRadius: 4,
border: `1px solid ${theme.cardBorder}`,
}}
>
Item 3
</Block>
</Block>
),
parameters: {
docs: {
description: {
story: 'Block components can be nested and styled with flexbox.',
},
},
},
};

export const AsContainer: Story = {
args: {
children: 'Container Block',
style: {
width: 300,
padding: 25,
textAlign: 'center',
backgroundColor: theme.cardBackground,
border: `2px dashed ${theme.cardBorder}`,
borderRadius: 8,
color: theme.pageText,
},
},
};
1 change: 0 additions & 1 deletion packages/component-library/src/Button.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export default meta;

type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
variant: 'primary',
Expand Down
82 changes: 82 additions & 0 deletions packages/component-library/src/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { styles } from '@actual-app/components/styles';
import type { Meta, StoryObj } from '@storybook/react-vite';

import { Card } from './Card';
import { Paragraph } from './Paragraph';
import { theme } from './theme';

const meta = {
title: 'Card',
component: Card,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof Card>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
children: 'Card content goes here',
style: {
padding: 20,
width: 300,
color: theme.pageText,
},
},
parameters: {
docs: {
description: {
story: `
Default Card component uses the following theme CSS variables:
- \`--color-cardBackground\`
- \`--color-cardBorder\`
`,
},
},
},
};

export const WithCustomContent: Story = {
args: {
style: {
padding: 20,
width: 300,
color: theme.pageText,
},
},
render: args => (
<Card {...args}>
<h3 style={{ ...styles.largeText }}>Card Title</h3>
<Paragraph style={{ margin: 0 }}>
This is a card with more complex content including a title and
paragraph.
</Paragraph>
</Card>
),
};

export const Narrow: Story = {
args: {
children: 'Narrow card',
style: {
padding: 15,
width: 150,
color: theme.pageText,
},
},
};

export const Wide: Story = {
args: {
children: 'Wide card with more content space',
style: {
padding: 25,
width: 500,
color: theme.pageText,
},
},
};
Loading
Loading