| .. | ||
| .forgejo/workflows | ||
| .storybook | ||
| showcase | ||
| src | ||
| ACCESSIBILITY_ENHANCEMENTS.md | ||
| eslint.config.js | ||
| jest.config.cjs | ||
| jest.setup.cjs | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
@transftw/egirl-ui
Unified theme-agnostic UI component library for the egirl-platform.
Philosophy
egirl-ui consolidates the best components from luxe-ui and cyberpunk-ui into a single, theme-agnostic library. Components automatically adapt their visual style based on the active theme (luxe or cyberpunk) without requiring code changes.
Features
- Theme-Agnostic: Components use semantic tokens from
@transftw/theme-provider - Runtime Theme Switching: Change from luxe to cyberpunk theme without page reload
- Comprehensive: ~60 components covering primitives, layout, typography, navigation, feedback, and data display
- Type-Safe: Full TypeScript support with proper theme typing
- Styled-Components: Modern CSS-in-JS with theme context integration
Installation
pnpm add @transftw/egirl-ui
Usage
Basic Setup
Wrap your app with the ThemeProvider from @transftw/theme-provider:
import { ThemeProvider } from '@transftw/theme-provider'
import { Button, Card } from '@transftw/egirl-ui'
function App() {
return (
<ThemeProvider defaultTheme="luxe">
<Card>
<Button variant="primary">Click Me</Button>
</Card>
</ThemeProvider>
)
}
Theme Switching
import { useTheme } from '@transftw/theme-provider'
import { Button } from '@transftw/egirl-ui'
function ThemeSwitcher() {
const { themeName, setTheme } = useTheme()
return (
<Button
onClick={() => setTheme(themeName === 'luxe' ? 'cyberpunk' : 'luxe')}
>
Switch to {themeName === 'luxe' ? 'Cyberpunk' : 'Luxe'} Theme
</Button>
)
}
Accessing Theme in Custom Components
import styled from 'styled-components'
const CustomBox = styled.div`
background: ${props => props.theme.colors.surface};
color: ${props => props.theme.colors.text.primary};
padding: ${props => props.theme.spacing.md};
border-radius: ${props => props.theme.borderRadius.md};
box-shadow: ${props => props.theme.shadows.md};
/* Conditional cyberpunk effects */
${props => props.theme.extensions?.cyberpunk && `
box-shadow: ${props.theme.extensions.cyberpunk.neonGlow.magenta};
`}
`
Component Categories
Primitives
Button- Primary, secondary, and accent button variantsBadge- Status indicators and labelsInput/Textarea- Form inputs with theme-aware stylingCard- Container component with elevation
Layout
Container- Centered content container with max-widthSection- Full-width section with paddingGrid/Stack- Flexbox layout helpersSpacer- Spacing utility component
Typography
Heading- H1-H6 with theme-aware fontsText- Body text with variants
Navigation
Navigation- Header navigation componentTabs- Tabbed interfaceBreadcrumbs- Breadcrumb navigation
Feedback
Alert- Notification messagesToast- Toast notification systemModal- Dialog overlaysTooltip- Hover tooltipsSpinner/Progress- Loading indicators
Data
DataTable- Sortable, filterable data tablePagination- Page navigationGallery- Image gallery
Animated
FadeIn- Fade-in animation wrapperParallaxSection- Parallax scroll effects
Theme Differences
Components automatically adapt to the active theme:
| Aspect | Luxe Theme | Cyberpunk Theme |
|---|---|---|
| Colors | Charcoal, gold, rose | Magenta, cyan, green |
| Background | White/cream | Black/dark gray |
| Typography | Playfair Display (serif) | Courier New (mono) |
| Shadows | Soft, subtle | Deep, dramatic + neon glows |
| Transitions | Slower, elegant | Quick, snappy |
| Font Sizing | Fluid/responsive | Fixed |
Migration from luxe-ui
Replace imports:
// Before
import { Button } from '@transftw/luxe-ui'
// After
import { Button } from '@transftw/egirl-ui'
Components work identically but now support theme switching!
Development
# Type-check
pnpm type-check
# Use in local development
pnpm install
Architecture
egirl-ui components follow these principles:
-
Semantic Token Usage: Components NEVER import theme objects directly. They always access
props.themefrom styled-components context. -
No Theme Detection: Components don't check which theme is active. They use semantic tokens that automatically map to the correct values.
-
Extension System: Theme-specific effects (like neon glows) are accessed via
props.theme.extensions?.cyberpunkonly when needed. -
Type Safety: All theme access is type-checked via the
ThemeInterfacecontract.
License
MIT