@club-employes/utopia
Version:
🎨 Modern Vue 3 design system with multi-brand theming, design tokens, and 30+ components. Supports Club Employés & Gifteo brands with light/dark modes.
358 lines (272 loc) • 9.14 kB
Markdown
[](https://www.npmjs.com/package/@club-employes/utopia)
[](https://opensource.org/licenses/MIT)
[](https://vuejs.org/)
[](https://www.typescriptlang.org/)
> **Modern Vue 3 design system** with multi-brand theming, design tokens, and 30+ production-ready components. Built for **Club Employés** & **Gifteo** with full TypeScript support.
- 🧩 **30+ Vue 3 Components** - Atoms, Molecules, Organisms, Layouts
- 🎨 **Multi-brand Theming** - Club Employés & Gifteo brands
- 🌙 **Dark Mode Support** - Light/dark variants for all themes
- 🎯 **Design Tokens** - CSS variables generated with Style Dictionary
- 📱 **Responsive** - Mobile-first approach with breakpoint utilities
- ♿ **Accessible** - WCAG 2.1 AA compliant components
- 🔧 **TypeScript** - Full type definitions included
- 🚀 **Tree Shakeable** - Import only what you need
- 📦 **Zero Config** - Works out of the box
```vue
<template>
<ThemeProvider :theme="clubEmployesLight">
<div class="app">
<Button variant="primary" size="medium" @click="handleClick">
Get Started
</Button>
<Card variant="elevated">
<Icon name="heart" size="large" />
<h2>Welcome to Utopia</h2>
<p>Modern design system for Vue 3</p>
</Card>
</div>
</ThemeProvider>
</template>
<script setup lang="ts">
import {
Button,
Card,
Icon,
ThemeProvider,
clubEmployesLight
} from '@club-employes/utopia'
import '@club-employes/utopia/styles'
const handleClick = () => {
console.log('Button clicked!')
}
</script>
```
```javascript
// Import all styles (recommended)
import '@club-employes/utopia/styles'
// Or import specific theme tokens
import '@club-employes/utopia/tokens/club-employes/light'
import '@club-employes/utopia/tokens/gifteo/dark'
```
```javascript
import {
clubEmployesLight, // Club Employés light theme
clubEmployesDark, // Club Employés dark theme
gifteoLight, // Gifteo light theme
gifteoDark // Gifteo dark theme
} from '@club-employes/utopia'
```
- **Button** - Interactive buttons with variants
- **Icon** - 1200+ Lucide icons
- **Logo** - Multi-brand logos
- **Badge** - Status indicators
- **Card** - Content containers
- **Input** - Form controls
- **Checkbox** - Boolean inputs
- **Switch** - Toggle controls
- **SearchBox** - Search input with icon
- **InputSelect** - Dropdown with filtering
- **DataTable** - Advanced data tables
- **Header** - Navigation headers
- **Menu** - Sidebar navigation
- **DefaultLayout** - Main application layout
```javascript
import { useTheme, useFavicon, useScrollShadows } from '@club-employes/utopia'
// Theme management
const { theme, setTheme } = useTheme()
setTheme('club-employes', 'dark')
// Dynamic favicon
const { setFavicon } = useFavicon()
// Scroll shadows
const { shadowTop, shadowBottom } = useScrollShadows(containerRef)
```
All components use CSS custom properties (design tokens):
```css
.my-component {
/* Colors */
background: var(--utopia-color-surface);
color: var(--utopia-color-text-primary);
/* Spacing */
padding: var(--utopia-space-md);
margin: var(--utopia-space-lg);
/* Typography */
font-family: var(--utopia-font-family);
font-size: var(--utopia-font-size-base);
/* Borders */
border-radius: var(--utopia-radius-md);
border: 1px solid var(--utopia-color-border);
}
```
```vue
<template>
<div>
<ThemeProvider :theme="currentTheme">
<Button @click="toggleTheme">
Switch to {{ isDark ? 'Light' : 'Dark' }} Mode
</Button>
<YourApp />
</ThemeProvider>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import {
ThemeProvider,
clubEmployesLight,
clubEmployesDark
} from '@club-employes/utopia'
const isDark = ref(false)
const currentTheme = computed(() =>
isDark.value ? clubEmployesDark : clubEmployesLight
)
const toggleTheme = () => {
isDark.value = !isDark.value
}
</script>
```
For multi-tenant applications with different domains, you can initialize the theme **before** Vue mounts to prevent Flash of Unstyled Content (FOUC):
```typescript
// main.ts
import { createApp } from 'vue'
import { initializeTheme } from '@club-employes/utopia'
import '@club-employes/utopia/styles'
import App from './App.vue'
// Detect theme from domain
function getThemeFromDomain(): string {
const hostname = window.location.hostname
if (hostname.includes('gifteo')) {
return 'gifteo-light'
}
if (hostname.includes('club-employes')) {
return 'club-employes-light'
}
return 'club-employes-light' // Default
}
// Initialize theme BEFORE creating Vue app
async function bootstrap() {
const themeName = getThemeFromDomain()
try {
await initializeTheme(themeName)
console.log('✅ Theme initialized:', themeName)
} catch (error) {
console.error('❌ Failed to initialize theme:', error)
}
// Create Vue app (no FOUC!)
const app = createApp(App)
app.mount('#app')
}
bootstrap()
```
> 📖 **[See full documentation](./THEME_INITIALIZATION.md)** for advanced patterns and examples.
```javascript
// Main export
import { Button, Icon, ThemeProvider } from '@club-employes/utopia'
// Styles
import '@club-employes/utopia/styles'
// Specific theme tokens
import '@club-employes/utopia/tokens/club-employes/light'
import '@club-employes/utopia/tokens/club-employes/dark'
import '@club-employes/utopia/tokens/gifteo/light'
import '@club-employes/utopia/tokens/gifteo/dark'
// Icons list (JSON)
import iconsList from '@club-employes/utopia/icons'
```
```vue
<script setup lang="ts">
import { ThemeProvider } from '@club-employes/utopia'
const customTheme = {
colors: {
primary: '#your-brand-color',
secondary: '#your-secondary-color'
},
// ... other theme properties
}
</script>
```
```javascript
// Import only what you need
import { Button } from '@club-employes/utopia/components/Button'
import { Icon } from '@club-employes/utopia/components/Icon'
```
Components are mobile-first and responsive by default:
```vue
<template>
<Button
size="small" <!-- Mobile -->
:size-md="'medium'" <!-- Tablet -->
:size-lg="'large'" <!-- Desktop -->
>
Responsive Button
</Button>
</template>
```
All components follow WCAG 2.1 AA guidelines:
- ✅ Keyboard navigation
- ✅ Screen reader support
- ✅ High contrast modes
- ✅ Focus management
- ✅ ARIA attributes
Full TypeScript definitions are **automatically generated** from source code via `vite-plugin-dts`:
```typescript
import type { ButtonProps, IconProps, ThemeConfig } from '@club-employes/utopia'
const buttonProps: ButtonProps = {
variant: 'primary',
size: 'medium',
disabled: false
}
```
**How it works:**
- ✅ Component props are defined in local `types.ts` files (source of truth)
- ✅ Types are automatically compiled to `dist/index.d.ts` during build
- ✅ Full IntelliSense and autocompletion support
- ✅ No manual type definitions needed
- **Full package**: ~150KB (minified + gzipped)
- **Single component**: ~5-15KB (tree-shaken)
- **Tokens only**: ~10KB (CSS variables)
- ✅ Chrome 90+
- ✅ Firefox 88+
- ✅ Safari 14+
- ✅ Edge 90+
- 📖 **[Complete Documentation](https://ds-utopia.vercel.app/)** - Interactive examples and guides
- 🎨 **[Storybook](https://main--673cf2b1e9d0b7c5f2b7b7e7.chromatic.com/)** - Component stories and visual tests
- 🐙 **[GitHub Repository](https://github.com/club-employes/ds)** - Source code and issues
- 📦 **[NPM Package](https://www.npmjs.com/package/@club-employes/utopia)** - Package details
We welcome contributions! Please see our [Contributing Guide](https://github.com/club-employes/ds/blob/main/CONTRIBUTING.md).
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests and documentation
5. Submit a pull request
MIT © [Club Employés](https://github.com/club-employes)
---
<div align="center">
**Made with ❤️ by the Club Employés team**
[](https://ds-utopia.vercel.app/) • [GitHub](https://github.com/club-employes/ds) • [NPM](https://www.npmjs.com/package/@club-employes/utopia)
</div>