This commit is contained in:
Chris Wanstrath 2025-11-29 22:38:15 -08:00
parent 67fae70c83
commit 6c3b3e80b0
16 changed files with 436 additions and 170 deletions

View File

@ -1,6 +1,46 @@
# 🐺 howl
Howl is a fork of `werewolf-ui`, without any Tailwind.
Howl is a fork of `werewolf-ui`, without any Tailwind. A minimal, zero-dependency React component library.
## Installation
```bash
bun install howl
```
## Usage
```tsx
import { Button, VStack, Text } from "howl"
function App() {
return (
<VStack>
<Text>Hello, world!</Text>
<Button>Click me</Button>
</VStack>
)
}
```
## Components
- **Avatar** - Profile image component
- **Box** - Container components (Box, RedBox, GreenBox, BlueBox, GrayBox)
- **Button** - Button component
- **Divider** - Horizontal divider
- **Grid** - Grid layout
- **Icon** - Icon display using lucide-static
- **IconLink** - Icon with link functionality
- **Image** - Image component
- **Input** - Text input field
- **Placeholder** - Placeholder component
- **Section** - Section container
- **Select** - Dropdown select input
- **Stack** - Layout components (VStack, HStack)
- **Text** - Text components (H1, H2, H3, H4, H5, Text, SmallText)
## Development
```bash
bun install

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2, Text } from "./text"
import "hono/jsx"
import type { FC, JSX } from "hono/jsx"
import { VStack, HStack } from "./stack"
@ -32,17 +34,17 @@ export const Test = () => {
]
return (
<VStack gap={8} style={{ padding: "24px" }}>
<Section>
{/* Size variations */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Size Variations</h2>
<H2>Size Variations</H2>
<HStack gap={4}>
{[24, 32, 48, 64, 96].map((size) => (
<VStack key={size} h="center" gap={2}>
<Avatar src={sampleImages[0]!} size={size} alt="Sample" />
<p style={{ fontSize: "14px" }}>
<Text>
{size}x{size}
</p>
</Text>
</VStack>
))}
</HStack>
@ -50,27 +52,27 @@ export const Test = () => {
{/* Rounded vs Square */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Rounded vs Square</h2>
<H2>Rounded vs Square</H2>
<HStack gap={6}>
<VStack h="center" gap={2}>
<Avatar src={sampleImages[0]!} size={64} alt="Sample" />
<p style={{ fontSize: "14px" }}>Square</p>
<Text>Square</Text>
</VStack>
<VStack h="center" gap={2}>
<Avatar src={sampleImages[0]!} size={64} rounded alt="Sample" />
<p style={{ fontSize: "14px" }}>Rounded</p>
<Text>Rounded</Text>
</VStack>
</HStack>
</VStack>
{/* Different images */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Different Images</h2>
<H2>Different Images</H2>
<HStack gap={4}>
{sampleImages.map((src, index) => (
<VStack key={src} h="center" gap={2}>
<Avatar src={src} size={64} rounded alt={`Sample ${index + 1}`} />
<p style={{ fontSize: "14px" }}>Image {index + 1}</p>
<Text>Image {index + 1}</Text>
</VStack>
))}
</HStack>
@ -78,7 +80,7 @@ export const Test = () => {
{/* Custom styles */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>With Custom Styles</h2>
<H2>With Custom Styles</H2>
<HStack gap={6}>
<VStack h="center" gap={2}>
<Avatar
@ -88,7 +90,7 @@ export const Test = () => {
style={{ border: "4px solid #3b82f6" }}
alt="With border"
/>
<p style={{ fontSize: "14px" }}>With Border</p>
<Text>With Border</Text>
</VStack>
<VStack h="center" gap={2}>
<Avatar
@ -98,7 +100,7 @@ export const Test = () => {
style={{ boxShadow: "0 10px 15px rgba(0, 0, 0, 0.3)" }}
alt="With shadow"
/>
<p style={{ fontSize: "14px" }}>With Shadow</p>
<Text>With Shadow</Text>
</VStack>
<VStack h="center" gap={2}>
<Avatar
@ -108,10 +110,10 @@ export const Test = () => {
style={{ border: "4px solid #22c55e", boxShadow: "0 10px 15px rgba(0, 0, 0, 0.3)" }}
alt="Border + shadow"
/>
<p style={{ fontSize: "14px" }}>Border + Shadow</p>
<Text>Border + Shadow</Text>
</VStack>
</HStack>
</VStack>
</VStack>
</Section>
)
}

84
src/box.tsx Normal file
View File

@ -0,0 +1,84 @@
import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
type BoxProps = PropsWithChildren & {
bg?: string
color?: string
p?: number
style?: JSX.CSSProperties
}
export const Box: FC<BoxProps> = ({ children, bg, color, p, style }) => {
const boxStyle: JSX.CSSProperties = {
backgroundColor: bg,
color: color,
padding: p ? `${p}px` : undefined,
...style,
}
return <div style={boxStyle}>{children}</div>
}
// Common demo box colors
export const RedBox: FC<PropsWithChildren> = ({ children }) => (
<Box bg="#ef4444" p={4} style={{ textAlign: "center" }}>
{children}
</Box>
)
export const GreenBox: FC<PropsWithChildren> = ({ children }) => (
<Box bg="#22c55e" p={4} style={{ textAlign: "center" }}>
{children}
</Box>
)
export const BlueBox: FC<PropsWithChildren> = ({ children }) => (
<Box bg="#3b82f6" p={4} style={{ textAlign: "center" }}>
{children}
</Box>
)
export const GrayBox: FC<PropsWithChildren & { style?: JSX.CSSProperties }> = ({ children, style }) => (
<Box bg="#f3f4f6" p={16} style={style}>
{children}
</Box>
)
export const Test = () => {
return (
<div style={{ display: "flex", flexDirection: "column", gap: "32px", padding: "24px" }}>
<div>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Box Component</h2>
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
<Box bg="#3b82f6" color="#ffffff" p={16}>
Basic Box with custom background and text color
</Box>
<Box p={8} style={{ border: "2px solid #d1d5db", borderRadius: "8px" }}>
Box with padding and border
</Box>
</div>
</div>
<div>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Color Variants</h2>
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
<RedBox>Red Box</RedBox>
<GreenBox>Green Box</GreenBox>
<BlueBox>Blue Box</BlueBox>
<GrayBox>Gray Box</GrayBox>
</div>
</div>
<div>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Nested Boxes</h2>
<Box bg="#f3f4f6" p={16}>
<Box bg="#e5e7eb" p={12}>
<Box bg="#d1d5db" p={8}>
Nested boxes demonstration
</Box>
</Box>
</Box>
</div>
</div>
)
}

View File

@ -1,6 +1,8 @@
import "hono/jsx"
import type { JSX, FC } from "hono/jsx"
import { VStack, HStack } from "./stack"
import { Section } from "./section"
import { H2 } from "./text"
export type ButtonProps = JSX.IntrinsicElements["button"] & {
variant?: "primary" | "secondary" | "outline" | "ghost" | "destructive"
@ -68,7 +70,7 @@ export const Button: FC<ButtonProps> = (props) => {
...baseStyles,
...variantStyles[variant],
...sizeStyles[size],
...(style || {}),
...(style as JSX.CSSProperties),
}
return <button {...buttonProps} style={combinedStyles} />
@ -76,10 +78,10 @@ export const Button: FC<ButtonProps> = (props) => {
export const Test = () => {
return (
<VStack gap={8} style={{ padding: "24px" }}>
<Section>
{/* Variants */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Button Variants</h2>
<H2>Button Variants</H2>
<HStack gap={4}>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
@ -91,7 +93,7 @@ export const Test = () => {
{/* Sizes */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Button Sizes</h2>
<H2>Button Sizes</H2>
<HStack gap={4} v="end">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
@ -101,7 +103,7 @@ export const Test = () => {
{/* With custom content */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Custom Content</h2>
<H2>Custom Content</H2>
<HStack gap={4}>
<Button variant="primary">
<span>🚀</span>
@ -116,7 +118,7 @@ export const Test = () => {
{/* Native attributes work */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Native Attributes</h2>
<H2>Native Attributes</H2>
<HStack gap={4}>
<Button onClick={() => alert("Clicked!")} variant="primary">
Click Me
@ -129,6 +131,6 @@ export const Test = () => {
</Button>
</HStack>
</VStack>
</VStack>
</Section>
)
}

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2 } from "./text"
import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
import { VStack } from "./stack"
@ -41,8 +43,8 @@ export const Divider: FC<DividerProps> = ({ children, style }) => {
export const Test = () => {
return (
<VStack gap={4} style={{ padding: "16px", maxWidth: "448px" }}>
<h2 style={{ fontSize: "18px", fontWeight: "bold" }}>Divider Examples</h2>
<Section gap={4} maxWidth="448px" style={{ padding: "16px" }}>
<H2>Divider Examples</H2>
<VStack gap={0}>
<p>Would you like to continue</p>
@ -56,6 +58,6 @@ export const Test = () => {
<Divider />
<p>So cool, so straight!</p>
</VStack>
</VStack>
</Section>
)
}

View File

@ -3,6 +3,8 @@ import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
import { VStack } from "./stack"
import { Button } from "./button"
import { Section } from "./section"
import { H2, H3 } from "./text"
type GridProps = PropsWithChildren & {
cols?: GridCols
@ -69,13 +71,13 @@ const justifyItemsMap = {
export const Test = () => {
return (
<VStack gap={4} style={{ padding: "16px" }}>
<Section gap={4} style={{ padding: "16px" }}>
<VStack gap={6}>
<h2 style={{ fontSize: "18px", fontWeight: "bold" }}>Grid Examples</h2>
<H2>Grid Examples</H2>
{/* Simple 3-column grid */}
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>Simple 3 columns: cols=3</h3>
<H3>Simple 3 columns: cols=3</H3>
<Grid cols={3} gap={4}>
<div style={{ backgroundColor: "#fecaca", padding: "16px", textAlign: "center" }}>Item 1</div>
<div style={{ backgroundColor: "#bbf7d0", padding: "16px", textAlign: "center" }}>Item 2</div>
@ -88,9 +90,7 @@ export const Test = () => {
{/* Responsive grid */}
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>
Responsive: cols=&#123;sm: 1, md: 2, lg: 3&#125;
</h3>
<H3>Responsive: cols=&#123;sm: 1, md: 2, lg: 3&#125;</H3>
<Grid cols={{ sm: 1, md: 2, lg: 3 }} gap={4}>
<div style={{ backgroundColor: "#fecaca", padding: "16px", textAlign: "center" }}>Card 1</div>
<div style={{ backgroundColor: "#bbf7d0", padding: "16px", textAlign: "center" }}>Card 2</div>
@ -101,9 +101,7 @@ export const Test = () => {
{/* More responsive examples */}
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>
More responsive: cols=&#123;sm: 2, lg: 4, xl: 6&#125;
</h3>
<H3>More responsive: cols=&#123;sm: 2, lg: 4, xl: 6&#125;</H3>
<Grid cols={{ sm: 2, lg: 4, xl: 6 }} gap={4}>
<div style={{ backgroundColor: "#fecaca", padding: "16px", textAlign: "center" }}>Item A</div>
<div style={{ backgroundColor: "#bbf7d0", padding: "16px", textAlign: "center" }}>Item B</div>
@ -116,7 +114,7 @@ export const Test = () => {
{/* Payment method example */}
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>Payment buttons example</h3>
<H3>Payment buttons example</H3>
<Grid cols={3} gap={4}>
<Button variant="outline" style={{ height: "80px", flexDirection: "column" }}>
<div style={{ fontSize: "24px" }}>💳</div>
@ -135,9 +133,7 @@ export const Test = () => {
{/* Alignment examples */}
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>
Alignment: v="center" h="center"
</h3>
<H3>Alignment: v="center" h="center"</H3>
<Grid cols={3} gap={4} v="center" h="center" style={{ height: "128px", backgroundColor: "#f3f4f6" }}>
<div style={{ backgroundColor: "#fecaca", padding: "8px" }}>Item 1</div>
<div style={{ backgroundColor: "#bbf7d0", padding: "8px" }}>Item 2</div>
@ -146,13 +142,13 @@ export const Test = () => {
</VStack>
<VStack gap={2}>
<h3 style={{ fontSize: "16px", fontWeight: "600" }}>Alignment: v="start" h="end"</h3>
<H3>Alignment: v="start" h="end"</H3>
<Grid cols={2} gap={4} v="start" h="end" style={{ height: "96px", backgroundColor: "#f3f4f6" }}>
<div style={{ backgroundColor: "#e9d5ff", padding: "8px" }}>Left</div>
<div style={{ backgroundColor: "#fed7aa", padding: "8px" }}>Right</div>
</Grid>
</VStack>
</VStack>
</VStack>
</Section>
)
}

View File

@ -2,7 +2,9 @@ import "hono/jsx"
import type { FC, JSX } from "hono/jsx"
import * as icons from "lucide-static"
import { Grid } from "./grid"
import { VStack, HStack } from "./stack"
import { VStack } from "./stack"
import { Section } from "./section"
import { H2, Text } from "./text"
export type IconName = keyof typeof icons
@ -69,100 +71,100 @@ export const IconLink: FC<IconLinkProps> = (props) => {
export const Test = () => {
return (
<div style={{ padding: "24px" }}>
<Section>
{/* === ICON TESTS === */}
{/* Size variations */}
<div style={{ marginBottom: "32px" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Icon Size Variations</h2>
<VStack gap={4}>
<H2>Icon Size Variations</H2>
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
{([3, 4, 5, 6, 8, 10, 12, 16] as const).map((size) => (
<div key={size} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }}>
<VStack h="center" gap={2} key={size}>
<Icon name="Heart" size={size} />
<p style={{ fontSize: "14px" }}>{size}</p>
</div>
<Text>{size}</Text>
</VStack>
))}
</div>
</div>
</VStack>
{/* Styling with CSS classes */}
<div style={{ marginBottom: "32px" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Styling with CSS Classes</h2>
<VStack gap={4}>
<H2>Styling with CSS Classes</H2>
<Grid cols={5} gap={6}>
<VStack h="center" gap={2}>
<Icon name="Star" size={12} />
<p style={{ fontSize: "14px" }}>Default</p>
<Text>Default</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Star" size={12} style={{ color: "#3b82f6" }} />
<p style={{ fontSize: "14px" }}>Blue Color</p>
<Text>Blue Color</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Star" size={12} class="stroke-1" />
<p style={{ fontSize: "14px" }}>Thin Stroke</p>
<Text>Thin Stroke</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Star" size={12} style={{ color: "#fbbf24", fill: "currentColor", stroke: "none" }} />
<p style={{ fontSize: "14px" }}>Filled</p>
<Text>Filled</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Star" size={12} style={{ color: "#a855f7", transition: "color 0.2s" }} />
<p style={{ fontSize: "14px" }}>Hover Effect</p>
<Text>Hover Effect</Text>
</VStack>
</Grid>
</div>
</VStack>
{/* Advanced styling */}
<div style={{ marginBottom: "32px" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Advanced Styling</h2>
<VStack gap={4}>
<H2>Advanced Styling</H2>
<Grid cols={4} gap={6}>
<VStack h="center" gap={2}>
<Icon name="Heart" size={12} style={{ color: "#ef4444", fill: "currentColor", stroke: "none" }} />
<p style={{ fontSize: "14px" }}>Filled Heart</p>
<Text>Filled Heart</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Shield" size={12} style={{ color: "#16a34a", strokeWidth: "2" }} />
<p style={{ fontSize: "14px" }}>Thick Stroke</p>
<Text>Thick Stroke</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Sun" size={12} style={{ color: "#eab308" }} />
<p style={{ fontSize: "14px" }}>Sun Icon</p>
<Text>Sun Icon</Text>
</VStack>
<VStack h="center" gap={2}>
<Icon name="Zap" size={12} style={{ color: "#60a5fa", filter: "drop-shadow(0 4px 6px rgba(0,0,0,0.3))" }} />
<p style={{ fontSize: "14px" }}>Drop Shadow</p>
<Text>Drop Shadow</Text>
</VStack>
</Grid>
</div>
</VStack>
{/* === ICON LINK TESTS === */}
{/* Basic icon links */}
<div style={{ marginBottom: "32px" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Icon Links</h2>
<VStack gap={4}>
<H2>Icon Links</H2>
<div style={{ display: "flex", gap: "24px" }}>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }}>
<VStack h="center" gap={2}>
<IconLink name="Home" size={8} href="/" />
<p style={{ fontSize: "14px" }}>Home Link</p>
</div>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }}>
<Text>Home Link</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink name="ExternalLink" size={8} href="https://example.com" target="_blank" />
<p style={{ fontSize: "14px" }}>External Link</p>
</div>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }}>
<Text>External Link</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink name="Mail" size={8} href="mailto:hello@example.com" />
<p style={{ fontSize: "14px" }}>Email Link</p>
</div>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "8px" }}>
<Text>Email Link</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink name="Phone" size={8} href="tel:+1234567890" />
<p style={{ fontSize: "14px" }}>Phone Link</p>
</div>
<Text>Phone Link</Text>
</VStack>
</div>
</div>
</VStack>
{/* Styled icon links */}
<div>
<h2 style={{ fontSize: "20px", fontWeight: "bold", marginBottom: "16px" }}>Styled Icon Links</h2>
<VStack gap={4}>
<H2>Styled Icon Links</H2>
<Grid cols={4} gap={6}>
<VStack h="center" gap={2}>
<IconLink
@ -176,7 +178,7 @@ export const Test = () => {
borderRadius: "8px",
}}
/>
<p style={{ fontSize: "14px" }}>Button Style</p>
<Text>Button Style</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink
@ -189,19 +191,19 @@ export const Test = () => {
borderRadius: "9999px",
}}
/>
<p style={{ fontSize: "14px" }}>Circle Border</p>
<Text>Circle Border</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink name="Heart" size={8} href="#" style={{ color: "#ef4444" }} />
<p style={{ fontSize: "14px" }}>Red Heart</p>
<Text>Red Heart</Text>
</VStack>
<VStack h="center" gap={2}>
<IconLink name="Star" size={8} href="#" style={{ color: "#fbbf24", fill: "currentColor" }} />
<p style={{ fontSize: "14px" }}>Filled Star</p>
<Text>Filled Star</Text>
</VStack>
</Grid>
</div>
</div>
</VStack>
</Section>
)
}

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2, H3, H4, H5, Text, SmallText } from "./text"
import "hono/jsx"
import type { FC, JSX } from "hono/jsx"
import { VStack, HStack } from "./stack"
@ -32,38 +34,38 @@ export const Test = () => {
]
return (
<VStack gap={8} style={{ padding: "24px" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Image Examples</h2>
<Section>
<H2>Image Examples</H2>
{/* Size variations */}
<VStack gap={4}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>Size Variations</h3>
<H3>Size Variations</H3>
<HStack gap={4} wrap>
<VStack h="center" gap={2}>
<Image src={sampleImages[0]!} width={64} height={64} objectFit="cover" alt="64x64" />
<p style={{ fontSize: "14px" }}>64x64</p>
<Text>64x64</Text>
</VStack>
<VStack h="center" gap={2}>
<Image src={sampleImages[0]!} width={96} height={96} objectFit="cover" alt="96x96" />
<p style={{ fontSize: "14px" }}>96x96</p>
<Text>96x96</Text>
</VStack>
<VStack h="center" gap={2}>
<Image src={sampleImages[0]!} width={128} height={128} objectFit="cover" alt="128x128" />
<p style={{ fontSize: "14px" }}>128x128</p>
<Text>128x128</Text>
</VStack>
<VStack h="center" gap={2}>
<Image src={sampleImages[0]!} width={192} height={128} objectFit="cover" alt="192x128" />
<p style={{ fontSize: "14px" }}>192x128</p>
<Text>192x128</Text>
</VStack>
</HStack>
</VStack>
{/* Object fit variations */}
<VStack gap={4}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>Object Fit Variations</h3>
<p style={{ fontSize: "14px", color: "#6b7280" }}>
<H3>Object Fit Variations</H3>
<Text>
Same image with different object-fit values
</p>
</Text>
<HStack gap={6} wrap>
<VStack h="center" gap={2}>
<Image
@ -74,7 +76,7 @@ export const Test = () => {
style={{ border: "1px solid black" }}
alt="Object cover"
/>
<p style={{ fontSize: "14px" }}>object-fit: cover</p>
<Text>object-fit: cover</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -85,7 +87,7 @@ export const Test = () => {
style={{ border: "1px solid black", backgroundColor: "#f3f4f6" }}
alt="Object contain"
/>
<p style={{ fontSize: "14px" }}>object-fit: contain</p>
<Text>object-fit: contain</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -96,7 +98,7 @@ export const Test = () => {
style={{ border: "1px solid black" }}
alt="Object fill"
/>
<p style={{ fontSize: "14px" }}>object-fit: fill</p>
<Text>object-fit: fill</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -107,7 +109,7 @@ export const Test = () => {
style={{ border: "1px solid black", backgroundColor: "#f3f4f6" }}
alt="Object scale-down"
/>
<p style={{ fontSize: "14px" }}>object-fit: scale-down</p>
<Text>object-fit: scale-down</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -118,14 +120,14 @@ export const Test = () => {
style={{ border: "1px solid black", backgroundColor: "#f3f4f6" }}
alt="Object none"
/>
<p style={{ fontSize: "14px" }}>object-fit: none</p>
<Text>object-fit: none</Text>
</VStack>
</HStack>
</VStack>
{/* Styling examples */}
<VStack gap={4}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>Styling Examples</h3>
<H3>Styling Examples</H3>
<HStack gap={6} wrap>
<VStack h="center" gap={2}>
<Image
@ -136,7 +138,7 @@ export const Test = () => {
style={{ borderRadius: "8px", border: "4px solid #3b82f6" }}
alt="Rounded with border"
/>
<p style={{ fontSize: "14px" }}>Rounded + Border</p>
<Text>Rounded + Border</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -147,7 +149,7 @@ export const Test = () => {
style={{ boxShadow: "0 10px 15px rgba(0, 0, 0, 0.3)" }}
alt="With shadow"
/>
<p style={{ fontSize: "14px" }}>With Shadow</p>
<Text>With Shadow</Text>
</VStack>
<VStack h="center" gap={2}>
<Image
@ -162,18 +164,18 @@ export const Test = () => {
}}
alt="Circular with effects"
/>
<p style={{ fontSize: "14px" }}>Circular + Effects</p>
<Text>Circular + Effects</Text>
</VStack>
</HStack>
</VStack>
{/* Common use cases */}
<VStack gap={6}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>Common Use Cases</h3>
<H3>Common Use Cases</H3>
{/* Avatar */}
<VStack gap={2}>
<h4 style={{ fontWeight: "500" }}>Avatar</h4>
<H4>Avatar</H4>
<Image
src={sampleImages[0]!}
width={48}
@ -186,19 +188,19 @@ export const Test = () => {
{/* Card image */}
<VStack gap={2} style={{ maxWidth: "384px" }}>
<h4 style={{ fontWeight: "500" }}>Card Image</h4>
<H4>Card Image</H4>
<VStack gap={0} style={{ border: "1px solid #d1d5db", borderRadius: "8px", overflow: "hidden" }}>
<Image src={sampleImages[1]!} width={384} height={192} objectFit="cover" alt="Card image" />
<VStack gap={1} style={{ padding: "16px" }}>
<h5 style={{ fontWeight: "500" }}>Card Title</h5>
<p style={{ fontSize: "14px", color: "#6b7280" }}>Card description goes here</p>
<H5>Card Title</H5>
<Text>Card description goes here</Text>
</VStack>
</VStack>
</VStack>
{/* Gallery grid */}
<VStack gap={2}>
<h4 style={{ fontWeight: "500" }}>Gallery Grid</h4>
<H4>Gallery Grid</H4>
<Grid cols={3} gap={2}>
{sampleImages.map((src, i) => (
<Image
@ -214,6 +216,6 @@ export const Test = () => {
</Grid>
</VStack>
</VStack>
</VStack>
</Section>
)
}

View File

@ -25,4 +25,10 @@ export type { SelectProps, SelectOption } from "./select"
export { Placeholder } from "./placeholder"
export { default as PlaceholderDefault } from "./placeholder"
export { H1, H2, H3, H4, H5, Text, SmallText } from "./text"
export { Box, RedBox, GreenBox, BlueBox, GrayBox } from "./box"
export { Section } from "./section"
export type { TailwindSize } from "./types"

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2, H3, H4, H5, Text, SmallText } from "./text"
import "hono/jsx"
import type { JSX, FC } from "hono/jsx"
import { VStack, HStack } from "./stack"
@ -18,7 +20,7 @@ export const Input: FC<InputProps> = (props) => {
backgroundColor: "white",
fontSize: "14px",
outline: "none",
...style,
...(style as JSX.CSSProperties),
}
if (!children) {
@ -69,10 +71,10 @@ export const Input: FC<InputProps> = (props) => {
export const Test = () => {
return (
<VStack gap={8} style={{ padding: "24px", maxWidth: "448px" }}>
<Section maxWidth="448px">
{/* Basic inputs */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Basic Inputs</h2>
<H2>Basic Inputs</H2>
<VStack gap={4}>
<Input placeholder="Enter your name" />
<Input type="email" placeholder="Enter your email" />
@ -82,7 +84,7 @@ export const Test = () => {
{/* Custom styling */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Custom Styling</h2>
<H2>Custom Styling</H2>
<VStack gap={4}>
<Input style={{ height: "32px", fontSize: "12px" }} placeholder="Small input" />
<Input placeholder="Default input" />
@ -92,7 +94,7 @@ export const Test = () => {
{/* With values */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>With Values</h2>
<H2>With Values</H2>
<VStack gap={4}>
<Input value="John Doe" placeholder="Name" />
<Input type="email" value="john@example.com" placeholder="Email" />
@ -101,7 +103,7 @@ export const Test = () => {
{/* Disabled state */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Disabled State</h2>
<H2>Disabled State</H2>
<VStack gap={4}>
<Input disabled placeholder="Disabled input" style={{ opacity: 0.5, cursor: "not-allowed" }} />
<Input disabled value="Disabled with value" style={{ opacity: 0.5, cursor: "not-allowed" }} />
@ -110,7 +112,7 @@ export const Test = () => {
{/* Label above */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Above</h2>
<H2>Label Above</H2>
<VStack gap={4}>
<Input placeholder="Enter your name">Name</Input>
<Input type="email" placeholder="Enter your email">
@ -124,7 +126,7 @@ export const Test = () => {
{/* Label to the left */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Left</h2>
<H2>Label Left</H2>
<VStack gap={4}>
<Input labelPosition="left" placeholder="Enter your name">
Name
@ -140,7 +142,7 @@ export const Test = () => {
{/* Label to the right */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Right</h2>
<H2>Label Right</H2>
<VStack gap={4}>
<Input labelPosition="right" placeholder="Enter your name">
Name
@ -156,7 +158,7 @@ export const Test = () => {
{/* Horizontal layout */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Horizontal Layout</h2>
<H2>Horizontal Layout</H2>
<HStack gap={4}>
<Input placeholder="First name">First</Input>
<Input placeholder="Last name">Last</Input>
@ -166,7 +168,7 @@ export const Test = () => {
{/* Custom styling */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Custom Input Styling</h2>
<H2>Custom Input Styling</H2>
<VStack gap={4}>
<Input style={{ borderColor: "#93c5fd" }} placeholder="Custom styled input">
<span style={{ color: "#2563eb", fontWeight: "bold" }}>Custom Label</span>

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2, H3, H4, H5, Text, SmallText } from "./text"
import "hono/jsx"
import { Avatar } from "./avatar"
import type { AvatarProps } from "./avatar"
@ -34,19 +36,19 @@ export const Placeholder = {
export const Test = () => {
return (
<VStack gap={8} style={{ padding: "24px" }}>
<Section>
{/* === AVATAR TESTS === */}
{/* Show all available avatar styles */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>
<H2>
All Avatar Styles ({allStyles.length} total)
</h2>
</H2>
<Grid cols={10} gap={3}>
{allStyles.map((style) => (
<VStack h="center" gap={1} key={style}>
<Placeholder.Avatar type={style} size={48} />
<p style={{ fontSize: "12px", fontWeight: "500" }}>{style}</p>
<SmallText style={{ fontWeight: "500" }}>{style}</Text>
</VStack>
))}
</Grid>
@ -54,12 +56,12 @@ export const Test = () => {
{/* Avatar size variations */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Avatar Size Variations</h2>
<H2>Avatar Size Variations</H2>
<HStack gap={4}>
{[24, 32, 48, 64].map((size) => (
<VStack h="center" gap={2} key={size}>
<Placeholder.Avatar size={size} />
<p style={{ fontSize: "14px" }}>{size}px</p>
<Text>{size}px</Text>
</VStack>
))}
</HStack>
@ -67,41 +69,41 @@ export const Test = () => {
{/* Avatar styling combinations */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Avatar Styling Options</h2>
<H2>Avatar Styling Options</H2>
<HStack gap={6}>
<VStack h="center" gap={2}>
<Placeholder.Avatar rounded size={64} />
<p style={{ fontSize: "14px" }}>Rounded + Background</p>
<Text>Rounded + Background</Text>
</VStack>
<VStack h="center" gap={2}>
<div style={{ backgroundColor: "#e5e7eb", padding: "8px" }}>
<Placeholder.Avatar rounded transparent size={64} />
</div>
<p style={{ fontSize: "14px" }}>Rounded + Transparent</p>
<Text>Rounded + Transparent</Text>
</VStack>
<VStack h="center" gap={2}>
<Placeholder.Avatar size={64} />
<p style={{ fontSize: "14px" }}>Square + Background</p>
<Text>Square + Background</Text>
</VStack>
<VStack h="center" gap={2}>
<div style={{ backgroundColor: "#e5e7eb", padding: "8px" }}>
<Placeholder.Avatar transparent size={64} />
</div>
<p style={{ fontSize: "14px" }}>Square + Transparent</p>
<Text>Square + Transparent</Text>
</VStack>
</HStack>
</VStack>
{/* Avatar seed variations */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>
<H2>
Avatar Seeds (Same Style, Different People)
</h2>
</H2>
<HStack gap={4}>
{["alice", "bob", "charlie", "diana"].map((seed) => (
<VStack h="center" gap={2} key={seed}>
<Placeholder.Avatar seed={seed} size={64} />
<p style={{ fontSize: "14px" }}>"{seed}"</p>
<Text>"{seed}"</Text>
</VStack>
))}
</HStack>
@ -109,11 +111,11 @@ export const Test = () => {
{/* === IMAGE TESTS === */}
<VStack gap={6}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Placeholder Images</h2>
<H2>Placeholder Images</H2>
{/* Size variations */}
<VStack gap={3}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>Size Variations</h3>
<H3>Size Variations</H3>
<HStack gap={4}>
{[
{ width: 100, height: 100 },
@ -123,9 +125,9 @@ export const Test = () => {
].map(({ width, height }) => (
<VStack h="center" gap={2} key={`${width}x${height}`}>
<Placeholder.Image width={width} height={height} seed={1} />
<p style={{ fontSize: "14px" }}>
<Text>
{width}×{height}
</p>
</Text>
</VStack>
))}
</HStack>
@ -133,14 +135,14 @@ export const Test = () => {
{/* Different seeds - show variety */}
<VStack gap={3}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>
<H3>
Different Images (Different Seeds)
</h3>
</H3>
<HStack gap={4}>
{[1, 2, 3, 4, 5].map((seed) => (
<VStack h="center" gap={2} key={seed}>
<Placeholder.Image width={150} height={150} seed={seed} />
<p style={{ fontSize: "14px" }}>Seed {seed}</p>
<Text>Seed {seed}</Text>
</VStack>
))}
</HStack>
@ -148,7 +150,7 @@ export const Test = () => {
{/* With custom styles */}
<VStack gap={3}>
<h3 style={{ fontSize: "18px", fontWeight: "600" }}>With Custom Styles</h3>
<H3>With Custom Styles</H3>
<HStack gap={6}>
<VStack h="center" gap={2}>
<Placeholder.Image
@ -158,7 +160,7 @@ export const Test = () => {
objectFit="cover"
style={{ borderRadius: "8px", border: "4px solid #3b82f6" }}
/>
<p style={{ fontSize: "14px" }}>Rounded + Border</p>
<Text>Rounded + Border</Text>
</VStack>
<VStack h="center" gap={2}>
<Placeholder.Image
@ -168,7 +170,7 @@ export const Test = () => {
objectFit="cover"
style={{ boxShadow: "0 10px 15px rgba(0, 0, 0, 0.3)" }}
/>
<p style={{ fontSize: "14px" }}>With Shadow</p>
<Text>With Shadow</Text>
</VStack>
<VStack h="center" gap={2}>
<Placeholder.Image
@ -182,7 +184,7 @@ export const Test = () => {
boxShadow: "0 10px 15px rgba(0, 0, 0, 0.3)",
}}
/>
<p style={{ fontSize: "14px" }}>Circular + Effects</p>
<Text>Circular + Effects</Text>
</VStack>
</HStack>
</VStack>

48
src/section.tsx Normal file
View File

@ -0,0 +1,48 @@
import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
import { VStack } from "./stack"
import type { TailwindSize } from "./types"
type SectionProps = PropsWithChildren & {
gap?: TailwindSize
maxWidth?: string
style?: JSX.CSSProperties
}
export const Section: FC<SectionProps> = ({ children, gap = 8, maxWidth, style }) => {
return (
<VStack gap={gap} style={{ padding: "24px", maxWidth, ...style }}>
{children}
</VStack>
)
}
export const Test = () => {
return (
<div>
<Section>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Default Section</h2>
<p>This is a section with default gap (8)</p>
<p>It has padding and vertical spacing between children</p>
</Section>
<Section gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Compact Section</h2>
<p>This section has a smaller gap (4)</p>
<p>Items are closer together</p>
</Section>
<Section gap={12}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Spacious Section</h2>
<p>This section has a larger gap (12)</p>
<p>Items have more breathing room</p>
</Section>
<Section maxWidth="600px" style={{ backgroundColor: "#f3f4f6" }}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Constrained Width Section</h2>
<p>This section has a max width of 600px and a gray background</p>
<p>Good for centering content on wide screens</p>
</Section>
</div>
)
}

View File

@ -1,3 +1,5 @@
import { Section } from "./section"
import { H2, H3, H4, H5, Text, SmallText } from "./text"
import "hono/jsx"
import type { JSX, FC } from "hono/jsx"
import { VStack, HStack } from "./stack"
@ -158,10 +160,10 @@ export const Test = () => {
]
return (
<VStack gap={8} style={{ padding: "24px", maxWidth: "448px" }}>
<Section maxWidth="448px">
{/* Basic selects */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Basic Selects</h2>
<H2>Basic Selects</H2>
<VStack gap={4}>
<Select options={months} placeholder="Select month" />
<Select options={years} placeholder="Select year" />
@ -171,7 +173,7 @@ export const Test = () => {
{/* With values */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>With Values</h2>
<H2>With Values</H2>
<VStack gap={4}>
<Select options={months} value="03" />
<Select options={years} value="2025" />
@ -180,7 +182,7 @@ export const Test = () => {
{/* Disabled state */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Disabled State</h2>
<H2>Disabled State</H2>
<VStack gap={4}>
<Select
options={months}
@ -194,7 +196,7 @@ export const Test = () => {
{/* Custom styling */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Custom Styling</h2>
<H2>Custom Styling</H2>
<VStack gap={4}>
<Select options={countries} style={{ borderColor: "#93c5fd" }} placeholder="Custom styled select" />
<Select options={months} style={{ height: "32px", fontSize: "12px" }} placeholder="Small select" />
@ -203,7 +205,7 @@ export const Test = () => {
{/* Label above */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Above</h2>
<H2>Label Above</H2>
<VStack gap={4}>
<Select options={months} placeholder="Select month">
Birth Month
@ -219,7 +221,7 @@ export const Test = () => {
{/* Label to the left */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Left</h2>
<H2>Label Left</H2>
<VStack gap={4}>
<Select labelPosition="left" options={months} placeholder="Select month">
Month
@ -235,7 +237,7 @@ export const Test = () => {
{/* Label to the right */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Label Right</h2>
<H2>Label Right</H2>
<VStack gap={4}>
<Select labelPosition="right" options={months} placeholder="Select month">
Month
@ -248,7 +250,7 @@ export const Test = () => {
{/* Horizontal layout (like card form) */}
<VStack gap={4}>
<h2 style={{ fontSize: "20px", fontWeight: "bold" }}>Horizontal Layout</h2>
<H2>Horizontal Layout</H2>
<HStack gap={4}>
<Select options={months} placeholder="MM">
Expires
@ -258,6 +260,6 @@ export const Test = () => {
</Select>
</HStack>
</VStack>
</VStack>
</Section>
)
}

View File

@ -2,6 +2,9 @@ import type { TailwindSize } from "./types"
import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
import { Grid } from "./grid"
import { Section } from "./section"
import { H2 } from "./text"
import { RedBox, GreenBox, BlueBox } from "./box"
export const VStack: FC<VStackProps> = (props) => {
return (
@ -64,10 +67,10 @@ export const Test = () => {
const crossAxisOpts: CrossAxisOpts[] = ["start", "center", "end", "stretch", "baseline"]
return (
<VStack gap={8} style={{ padding: "16px" }}>
<Section gap={8} style={{ padding: "16px" }}>
{/* HStack layout matrix */}
<VStack gap={2}>
<h2 style={{ fontSize: "18px", fontWeight: "bold" }}>HStack Layout</h2>
<H2>HStack Layout</H2>
<div style={{ overflowX: "auto" }}>
<Grid cols={7} gap={1} style={{ gridTemplateColumns: "auto repeat(6, 1fr)" }}>
{/* Header row: blank + h labels */}
@ -90,9 +93,9 @@ export const Test = () => {
v={v}
style={{ backgroundColor: "#f3f4f6", padding: "8px", height: "96px", border: "1px solid #9ca3af" }}
>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#ef4444" }}>Aa</div>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#22c55e" }}>Aa</div>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#3b82f6" }}>Aa</div>
<RedBox>Aa</RedBox>
<GreenBox>Aa</GreenBox>
<BlueBox>Aa</BlueBox>
</HStack>
)),
])}
@ -102,7 +105,7 @@ export const Test = () => {
{/* VStack layout matrix */}
<VStack gap={2}>
<h2 style={{ fontSize: "18px", fontWeight: "bold" }}>VStack Layout</h2>
<H2>VStack Layout</H2>
<div style={{ overflowX: "auto" }}>
<Grid cols={6} gap={1} style={{ gridTemplateColumns: "auto repeat(5, 1fr)" }}>
{/* Header row: blank + h labels */}
@ -125,16 +128,16 @@ export const Test = () => {
h={h}
style={{ backgroundColor: "#f3f4f6", padding: "8px", height: "168px", border: "1px solid #9ca3af" }}
>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#ef4444" }}>Aa</div>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#22c55e" }}>Aa</div>
<div style={{ textAlign: "center", padding: "4px", backgroundColor: "#3b82f6" }}>Aa</div>
<RedBox>Aa</RedBox>
<GreenBox>Aa</GreenBox>
<BlueBox>Aa</BlueBox>
</VStack>
)),
])}
</Grid>
</div>
</VStack>
</VStack>
</Section>
)
}

73
src/text.tsx Normal file
View File

@ -0,0 +1,73 @@
import "hono/jsx"
import type { FC, PropsWithChildren, JSX } from "hono/jsx"
type TextProps = PropsWithChildren & {
style?: JSX.CSSProperties
}
export const H1: FC<TextProps> = ({ children, style }) => (
<h1 style={{ fontSize: "24px", fontWeight: "bold", ...style }}>{children}</h1>
)
export const H2: FC<TextProps> = ({ children, style }) => (
<h2 style={{ fontSize: "20px", fontWeight: "bold", ...style }}>{children}</h2>
)
export const H3: FC<TextProps> = ({ children, style }) => (
<h3 style={{ fontSize: "18px", fontWeight: "600", ...style }}>{children}</h3>
)
export const H4: FC<TextProps> = ({ children, style }) => (
<h4 style={{ fontSize: "16px", fontWeight: "600", ...style }}>{children}</h4>
)
export const H5: FC<TextProps> = ({ children, style }) => (
<h5 style={{ fontSize: "14px", fontWeight: "500", ...style }}>{children}</h5>
)
export const Text: FC<TextProps> = ({ children, style }) => (
<p style={{ fontSize: "14px", ...style }}>{children}</p>
)
export const SmallText: FC<TextProps> = ({ children, style }) => (
<p style={{ fontSize: "12px", ...style }}>{children}</p>
)
export const Test = () => {
return (
<div style={{ padding: "24px", display: "flex", flexDirection: "column", gap: "32px" }}>
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
<H1>Heading 1 (24px, bold)</H1>
<H2>Heading 2 (20px, bold)</H2>
<H3>Heading 3 (18px, semibold)</H3>
<H4>Heading 4 (16px, semibold)</H4>
<H5>Heading 5 (14px, medium)</H5>
<Text>Regular text (14px)</Text>
<SmallText>Small text (12px)</SmallText>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
<H2>Custom Styling</H2>
<Text style={{ color: "#3b82f6" }}>Blue text with custom color</Text>
<Text style={{ fontWeight: "bold", fontStyle: "italic" }}>Bold italic text</Text>
<SmallText style={{ color: "#ef4444", textTransform: "uppercase" }}>
Red uppercase small text
</SmallText>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: "8px", maxWidth: "600px" }}>
<H2>Typography Example</H2>
<H3>Article Title</H3>
<Text>
This is a paragraph of regular text. It demonstrates how the Text component can be used for body
content in articles, blog posts, or any other long-form content.
</Text>
<Text>
Multiple paragraphs can be stacked together to create readable content with consistent styling
throughout your application.
</Text>
<SmallText style={{ color: "#64748b" }}>Last updated: Today</SmallText>
</div>
</div>
)
}

View File

@ -25,8 +25,8 @@ app.get('/', c => {
})
function testFiles(): string[] {
return readdirSync('./test')
.filter(x => x.endsWith('.tsx') && !x.startsWith('server'))
return readdirSync('./src')
.filter(x => x.endsWith('.tsx') && !x.startsWith('index'))
.map(x => x.replace('.tsx', ''))
.sort()
}