@krrli/cm-designsystem 1.1.0 → 1.19.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +422 -2
- package/dist/components/avatar/Avatar.d.ts +71 -0
- package/dist/components/avatar/Avatar.js +63 -0
- package/dist/components/branding/BrandingGallery.d.ts +1 -0
- package/dist/components/branding/BrandingGallery.js +139 -0
- package/dist/components/button/Button.d.ts +54 -0
- package/dist/components/button/Button.js +56 -0
- package/dist/components/button/Button.test.d.ts +1 -0
- package/dist/components/button/Button.test.js +30 -0
- package/dist/components/color/ColorDoc.d.ts +4 -0
- package/dist/components/color/ColorDoc.js +10 -0
- package/dist/components/file-upload/FileUpload.d.ts +83 -0
- package/dist/components/file-upload/FileUpload.js +70 -0
- package/dist/components/form/Form.d.ts +54 -0
- package/dist/components/form/Form.js +38 -0
- package/dist/components/icon-button/IconButton.d.ts +50 -0
- package/dist/components/icon-button/IconButton.js +22 -0
- package/dist/components/icon-button/IconButton.test.d.ts +1 -0
- package/dist/components/icon-button/IconButton.test.js +22 -0
- package/dist/components/icons/IconBase.d.ts +5 -0
- package/dist/components/icons/IconBase.js +9 -0
- package/dist/components/icons/generated/ArrowDown.d.ts +3 -0
- package/dist/components/icons/generated/ArrowDown.js +4 -0
- package/dist/components/icons/generated/ArrowLeft.d.ts +3 -0
- package/dist/components/icons/generated/ArrowLeft.js +4 -0
- package/dist/components/icons/generated/ArrowRight.d.ts +3 -0
- package/dist/components/icons/generated/ArrowRight.js +4 -0
- package/dist/components/icons/generated/ArrowUp.d.ts +3 -0
- package/dist/components/icons/generated/ArrowUp.js +4 -0
- package/dist/components/icons/generated/Calendar.d.ts +3 -0
- package/dist/components/icons/generated/Calendar.js +4 -0
- package/dist/components/icons/generated/Cancel.d.ts +3 -0
- package/dist/components/icons/generated/Cancel.js +4 -0
- package/dist/components/icons/generated/Checkmark.d.ts +3 -0
- package/dist/components/icons/generated/Checkmark.js +4 -0
- package/dist/components/icons/generated/Edit.d.ts +3 -0
- package/dist/components/icons/generated/Edit.js +4 -0
- package/dist/components/icons/generated/Eye.d.ts +3 -0
- package/dist/components/icons/generated/Eye.js +4 -0
- package/dist/components/icons/generated/Fullscreen.d.ts +3 -0
- package/dist/components/icons/generated/Fullscreen.js +4 -0
- package/dist/components/icons/generated/HeartFilled.d.ts +3 -0
- package/dist/components/icons/generated/HeartFilled.js +4 -0
- package/dist/components/icons/generated/HeartOutline.d.ts +3 -0
- package/dist/components/icons/generated/HeartOutline.js +4 -0
- package/dist/components/icons/generated/Location.d.ts +3 -0
- package/dist/components/icons/generated/Location.js +4 -0
- package/dist/components/icons/generated/LogOut.d.ts +3 -0
- package/dist/components/icons/generated/LogOut.js +4 -0
- package/dist/components/icons/generated/Mumble.d.ts +3 -0
- package/dist/components/icons/generated/Mumble.js +4 -0
- package/dist/components/icons/generated/Profile.d.ts +3 -0
- package/dist/components/icons/generated/Profile.js +4 -0
- package/dist/components/icons/generated/ReplyFilled.d.ts +3 -0
- package/dist/components/icons/generated/ReplyFilled.js +4 -0
- package/dist/components/icons/generated/ReplyOutline.d.ts +3 -0
- package/dist/components/icons/generated/ReplyOutline.js +4 -0
- package/dist/components/icons/generated/Repost.d.ts +3 -0
- package/dist/components/icons/generated/Repost.js +4 -0
- package/dist/components/icons/generated/Send.d.ts +3 -0
- package/dist/components/icons/generated/Send.js +4 -0
- package/dist/components/icons/generated/Settings.d.ts +3 -0
- package/dist/components/icons/generated/Settings.js +4 -0
- package/dist/components/icons/generated/Share.d.ts +3 -0
- package/dist/components/icons/generated/Share.js +4 -0
- package/dist/components/icons/generated/Time.d.ts +3 -0
- package/dist/components/icons/generated/Time.js +4 -0
- package/dist/components/icons/generated/Upload.d.ts +3 -0
- package/dist/components/icons/generated/Upload.js +4 -0
- package/dist/components/icons/generated/index.d.ts +24 -0
- package/dist/components/icons/generated/index.js +24 -0
- package/dist/components/index.d.ts +25 -0
- package/dist/components/index.js +25 -0
- package/dist/components/input/Input.d.ts +61 -0
- package/dist/components/input/Input.js +47 -0
- package/dist/components/like-toggle/LikeToggle.d.ts +97 -0
- package/dist/components/like-toggle/LikeToggle.js +185 -0
- package/dist/components/like-toggle/LikeToggle.test.d.ts +1 -0
- package/dist/components/like-toggle/LikeToggle.test.js +35 -0
- package/dist/components/modal/Modal.d.ts +75 -0
- package/dist/components/modal/Modal.js +63 -0
- package/dist/components/modal/Modal.test.d.ts +1 -0
- package/dist/components/modal/Modal.test.js +24 -0
- package/dist/components/navi-button/NaviButton.d.ts +26 -0
- package/dist/components/navi-button/NaviButton.js +29 -0
- package/dist/components/navi-button/NaviButton.test.d.ts +1 -0
- package/dist/components/navi-button/NaviButton.test.js +22 -0
- package/dist/components/navi-user-button/NaviUserButton.d.ts +26 -0
- package/dist/components/navi-user-button/NaviUserButton.js +29 -0
- package/dist/components/round-button/RoundButton.d.ts +25 -0
- package/dist/components/round-button/RoundButton.js +28 -0
- package/dist/components/round-button/RoundButton.test.d.ts +1 -0
- package/dist/components/round-button/RoundButton.test.js +21 -0
- package/dist/components/tabs/TabItem.d.ts +11 -0
- package/dist/components/tabs/TabItem.js +13 -0
- package/dist/components/tabs/Tabs.d.ts +67 -0
- package/dist/components/tabs/Tabs.js +67 -0
- package/dist/components/tabs/Tabs.test.d.ts +1 -0
- package/dist/components/tabs/Tabs.test.js +61 -0
- package/dist/components/text-link/TextLink.d.ts +9 -0
- package/dist/components/text-link/TextLink.js +15 -0
- package/dist/components/text-link/TextLink.test.d.ts +1 -0
- package/dist/components/text-link/TextLink.test.js +14 -0
- package/dist/components/textarea/Textarea.d.ts +48 -0
- package/dist/components/textarea/Textarea.js +46 -0
- package/dist/components/timed-button/TimedButton.d.ts +56 -0
- package/dist/components/timed-button/TimedButton.js +106 -0
- package/dist/components/timed-button/TimedButton.test.d.ts +1 -0
- package/dist/components/timed-button/TimedButton.test.js +35 -0
- package/dist/components/toggle/Toggle.d.ts +62 -0
- package/dist/components/toggle/Toggle.js +67 -0
- package/dist/components/toggle/Toggle.test.d.ts +1 -0
- package/dist/components/toggle/Toggle.test.js +93 -0
- package/dist/components/typography/Heading.d.ts +17 -0
- package/dist/components/typography/Heading.js +11 -0
- package/dist/components/typography/Label.d.ts +15 -0
- package/dist/components/typography/Label.js +7 -0
- package/dist/components/typography/Paragraph.d.ts +15 -0
- package/dist/components/typography/Paragraph.js +7 -0
- package/dist/components/typography/Placeholder.d.ts +13 -0
- package/dist/components/typography/Placeholder.js +7 -0
- package/dist/components/typography/ValidationMessage.d.ts +15 -0
- package/dist/components/typography/ValidationMessage.js +9 -0
- package/dist/components/typography/styles.d.ts +74 -0
- package/dist/components/typography/styles.js +52 -0
- package/dist/favicon.svg +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +7550 -0
- package/dist/index.js +2 -0
- package/dist/logo-inline-gradient.svg +43 -0
- package/dist/setupTests.d.ts +1 -0
- package/dist/setupTests.js +7 -0
- package/package.json +78 -33
- package/.github/CODEOWNERS +0 -7
- package/.github/semantic.yml +0 -24
- package/.github/workflows/publish-npm.yml +0 -29
- package/.github/workflows/storybook.yml +0 -44
- package/.releaserc.json +0 -9
- package/.storybook/main.ts +0 -19
- package/.storybook/preview.ts +0 -21
- package/.storybook/vitest.setup.ts +0 -7
- package/src/index.ts +0 -4
- package/stories/Button.stories.ts +0 -54
- package/stories/Button.tsx +0 -37
- package/stories/Button2.stories.ts +0 -54
- package/stories/Button2.tsx +0 -41
- package/stories/Configure.mdx +0 -364
- package/stories/Header.stories.ts +0 -34
- package/stories/Header.tsx +0 -56
- package/stories/Page.stories.ts +0 -33
- package/stories/Page.tsx +0 -73
- package/stories/assets/accessibility.png +0 -0
- package/stories/assets/accessibility.svg +0 -1
- package/stories/assets/addon-library.png +0 -0
- package/stories/assets/assets.png +0 -0
- package/stories/assets/avif-test-image.avif +0 -0
- package/stories/assets/context.png +0 -0
- package/stories/assets/discord.svg +0 -1
- package/stories/assets/docs.png +0 -0
- package/stories/assets/figma-plugin.png +0 -0
- package/stories/assets/github.svg +0 -1
- package/stories/assets/share.png +0 -0
- package/stories/assets/styling.png +0 -0
- package/stories/assets/testing.png +0 -0
- package/stories/assets/theming.png +0 -0
- package/stories/assets/tutorials.svg +0 -1
- package/stories/assets/youtube.svg +0 -1
- package/stories/button.css +0 -30
- package/stories/button2.css +0 -30
- package/stories/header.css +0 -32
- package/stories/page.css +0 -68
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -35
- package/vitest.shims.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,2 +1,422 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# CM Design System
|
|
2
|
+
|
|
3
|
+
A modern React component library built with TypeScript, Tailwind CSS, and Storybook.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Usage in Your Project](#usage-in-your-project)
|
|
8
|
+
- [Technical Stack](#technical-stack)
|
|
9
|
+
- [Development](#development)
|
|
10
|
+
- [Quick Start Development](#quick-start-development)
|
|
11
|
+
- [Quality Checks](#quality-checks)
|
|
12
|
+
- [Code Style](#code-style)
|
|
13
|
+
- [TypeScript Guidelines](#typescript-guidelines)
|
|
14
|
+
- [Project Structure](#project-structure)
|
|
15
|
+
- [Icon Generation](#icon-generation)
|
|
16
|
+
- [Visual Testing](#visual-testing)
|
|
17
|
+
- [Contributing](#contributing)
|
|
18
|
+
- [Continuous Integration](#continuous-integration)
|
|
19
|
+
- [EditorConfig & VS Code Settings](#editorconfig--vs-code-settings)
|
|
20
|
+
|
|
21
|
+
## Usage in Your Project
|
|
22
|
+
|
|
23
|
+
To use the components and styles in your project:
|
|
24
|
+
|
|
25
|
+
1. Install the package:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm i @krrli/cm-designsystem
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. Import the bundled CSS in your app entry (e.g., `main.tsx` or `App.tsx`):
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import "cm-designsystem/dist/cm-designsystem.css";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. Import and use components as needed:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { Button } from "cm-designsystem";
|
|
41
|
+
|
|
42
|
+
function App() {
|
|
43
|
+
return (
|
|
44
|
+
<Button label="Click me" intent="primary" size="md" onClick={() => {}} />
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Technical Stack
|
|
52
|
+
|
|
53
|
+
- React 19 with TypeScript
|
|
54
|
+
- Vite for fast development and building
|
|
55
|
+
- Tailwind CSS v4 for styling
|
|
56
|
+
- Storybook for component documentation
|
|
57
|
+
- Vitest for unit testing
|
|
58
|
+
- Playwright for visual regression testing
|
|
59
|
+
- Radix UI Primitives for accessible component primitives
|
|
60
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react) for Fast Refresh
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Development
|
|
65
|
+
|
|
66
|
+
### Quick Start Development
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Install dependencies
|
|
70
|
+
npm install
|
|
71
|
+
|
|
72
|
+
# Start Storybook development server
|
|
73
|
+
npm run storybook
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Storybook will be available at [http://localhost:6006](http://localhost:6006)
|
|
77
|
+
|
|
78
|
+
📚 View the deployed Storybook: [https://ost-cas-fea-25-26.github.io/cm-designsystem/](https://ost-cas-fea-25-26.github.io/cm-designsystem/?path=/docs/branding-assets--docs)
|
|
79
|
+
|
|
80
|
+
### Quality Checks
|
|
81
|
+
|
|
82
|
+
Run all quality checks before committing:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run preflight # Runs format, lint, type-check, test, and build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Individual commands:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Formatting
|
|
92
|
+
npm run format # Auto-format all files with Prettier
|
|
93
|
+
npm run format:check # Check formatting without making changes
|
|
94
|
+
|
|
95
|
+
# Linting
|
|
96
|
+
npm run lint # Check for linting errors
|
|
97
|
+
npm run lint:fix # Auto-fix linting errors where possible
|
|
98
|
+
|
|
99
|
+
# Type Checking
|
|
100
|
+
npx tsc -b --noEmit # Run TypeScript type checking
|
|
101
|
+
|
|
102
|
+
# Testing
|
|
103
|
+
npm test # Run unit tests with Vitest
|
|
104
|
+
|
|
105
|
+
# Building
|
|
106
|
+
npm run build # Build the project
|
|
107
|
+
npm run build-storybook # Build Storybook for production
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Code Style
|
|
111
|
+
|
|
112
|
+
We enforce consistent code style using automated tools:
|
|
113
|
+
|
|
114
|
+
Prettier Configuration:
|
|
115
|
+
|
|
116
|
+
- Uses double quotes
|
|
117
|
+
- 2-space indentation
|
|
118
|
+
- Semicolons required
|
|
119
|
+
- Line width: 80 characters
|
|
120
|
+
- Includes Tailwind CSS class sorting plugin
|
|
121
|
+
|
|
122
|
+
ESLint Configuration:
|
|
123
|
+
|
|
124
|
+
- TypeScript ESLint rules
|
|
125
|
+
- React and React Hooks best practices
|
|
126
|
+
- JSX Accessibility (a11y) rules
|
|
127
|
+
- Import sorting and organization
|
|
128
|
+
- Storybook rules
|
|
129
|
+
- Prettier integration (no conflicts)
|
|
130
|
+
|
|
131
|
+
### TypeScript Guidelines
|
|
132
|
+
|
|
133
|
+
We follow a consistent pattern for component type definitions:
|
|
134
|
+
|
|
135
|
+
Standard Component Pattern:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
139
|
+
|
|
140
|
+
// 1. Define styles with tailwind-variants
|
|
141
|
+
const buttonStyles = tv({
|
|
142
|
+
variants: {
|
|
143
|
+
intent: {
|
|
144
|
+
primary: ["bg-slate-600"],
|
|
145
|
+
secondary: ["bg-violet-600"],
|
|
146
|
+
},
|
|
147
|
+
size: {
|
|
148
|
+
md: ["pt-3", "pb-3"],
|
|
149
|
+
lg: ["pt-4", "pb-4"],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// 2. Extract variant types from styles
|
|
155
|
+
type ButtonVariants = VariantProps<typeof buttonStyles>;
|
|
156
|
+
|
|
157
|
+
// 3. Define specific union types for variant options
|
|
158
|
+
type ButtonIntent = "primary" | "secondary";
|
|
159
|
+
type ButtonSize = "md" | "lg";
|
|
160
|
+
|
|
161
|
+
// 4. Create component props interface extending variants
|
|
162
|
+
interface ButtonProps extends ButtonVariants {
|
|
163
|
+
label: string;
|
|
164
|
+
onClick: () => void;
|
|
165
|
+
className?: string;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
When to use `type` vs `interface`:
|
|
170
|
+
|
|
171
|
+
- `type`: For VariantProps, union types, and type aliases
|
|
172
|
+
- `interface`: For component props (always extends variants)
|
|
173
|
+
- `export`: Export interfaces for public component APIs
|
|
174
|
+
|
|
175
|
+
Best Practices:
|
|
176
|
+
|
|
177
|
+
- Always extend `VariantProps` for styled components
|
|
178
|
+
- Define union types for variant options to ensure type safety
|
|
179
|
+
- Export prop interfaces for components
|
|
180
|
+
- Use strict TypeScript (enabled by default)
|
|
181
|
+
|
|
182
|
+
### Project Structure
|
|
183
|
+
|
|
184
|
+
Components and their Storybook stories are co-located in the same folder for better organization:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
src/components/
|
|
188
|
+
├── button/
|
|
189
|
+
│ ├── Button.tsx # Component implementation
|
|
190
|
+
│ ├── Button.stories.tsx # Storybook stories
|
|
191
|
+
│ └── Button.test.tsx # Unit tests (if applicable)
|
|
192
|
+
├── avatar/
|
|
193
|
+
│ ├── Avatar.tsx
|
|
194
|
+
│ └── Avatar.stories.tsx
|
|
195
|
+
└── ...
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Benefits of co-location:
|
|
199
|
+
|
|
200
|
+
- ✅ Related files stay together
|
|
201
|
+
- ✅ Easier to find and maintain stories
|
|
202
|
+
- ✅ Clear 1:1 relationship between components and documentation
|
|
203
|
+
- ✅ Stories serve as living documentation and examples
|
|
204
|
+
|
|
205
|
+
Story file naming: Always use `ComponentName.stories.tsx` format for Storybook to auto-discover them.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Icon Generation
|
|
210
|
+
|
|
211
|
+
SVG icons are automatically converted to React components with proper accessibility support.
|
|
212
|
+
|
|
213
|
+
### Workflow
|
|
214
|
+
|
|
215
|
+
1. Add SVG files to `src/components/icons/svg/`
|
|
216
|
+
2. Optimize SVGs (optional but recommended):
|
|
217
|
+
```bash
|
|
218
|
+
npx svgo -f src/components/icons/svg
|
|
219
|
+
```
|
|
220
|
+
3. Generate React components:
|
|
221
|
+
```bash
|
|
222
|
+
npm run icons:generate
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Configuration
|
|
226
|
+
|
|
227
|
+
Edit `svg.config.json` to customize the generation process:
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"sourceDir": "src/components/icons/svg",
|
|
232
|
+
"outputDir": "src/components/icons/generated",
|
|
233
|
+
"baseComponentImport": {
|
|
234
|
+
"name": "IconBase",
|
|
235
|
+
"path": "../IconBase"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Usage Example
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
import { Calendar, LogOut } from "src/components/icons/generated";
|
|
244
|
+
|
|
245
|
+
export function Example() {
|
|
246
|
+
return (
|
|
247
|
+
<div className="flex gap-2 text-slate-600">
|
|
248
|
+
<Calendar />
|
|
249
|
+
<LogOut className="text-red-600" />
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
How it works:
|
|
256
|
+
|
|
257
|
+
- File names are converted to PascalCase (`log-out.svg` → `LogOut`)
|
|
258
|
+
- Fill colors are normalized to `currentColor` for theming
|
|
259
|
+
- All icons are wrapped in `IconBase` for accessibility
|
|
260
|
+
- A barrel export (`index.ts`) is generated automatically
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Visual Testing
|
|
265
|
+
|
|
266
|
+
We use Playwright for visual regression testing against Storybook. Tests run in Docker for consistent results across environments.
|
|
267
|
+
|
|
268
|
+
### Setup
|
|
269
|
+
|
|
270
|
+
Build the Docker image (first time only):
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npm run e2e:build
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Running Tests
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm run e2e:test # Run visual regression tests
|
|
280
|
+
npm run e2e:update # Update baseline snapshots
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Viewing Reports
|
|
284
|
+
|
|
285
|
+
View test reports locally:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
npx playwright show-report
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
GitHub Artifacts:
|
|
292
|
+
Test reports are uploaded as CI artifacts. Download and view them with:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
npx playwright show-report <path/to/extracted-artifact>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Configuration
|
|
299
|
+
|
|
300
|
+
- Docker: Tests run in containers for consistency across environments
|
|
301
|
+
- Network: Storybook accepts connections from `host.docker.internal`
|
|
302
|
+
- Tolerance: 1% pixel difference allowed (`maxDiffPixelRatio: 0.01`)
|
|
303
|
+
- Files: `playwright.config.ts` and `.storybook/main.ts`
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## Contributing
|
|
308
|
+
|
|
309
|
+
### Pull Request Process
|
|
310
|
+
|
|
311
|
+
1. Create a feature branch:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
git checkout -b feature/initials/your-feature-name
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Use format: `feature/<mm or ci>/<description>`
|
|
318
|
+
|
|
319
|
+
2. Make your changes and ensure quality:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
npm run preflight
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
3. Commit with conventional commits (see below)
|
|
326
|
+
|
|
327
|
+
4. Push to your feature branch:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
git push origin feature/initials/your-feature-name
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
5. Create a pull request to `main`
|
|
334
|
+
|
|
335
|
+
6. Wait for CI checks to pass
|
|
336
|
+
|
|
337
|
+
7. Request review from team members
|
|
338
|
+
|
|
339
|
+
8. Address feedback and merge
|
|
340
|
+
|
|
341
|
+
### Commit Messages
|
|
342
|
+
|
|
343
|
+
We use [Conventional Commits](https://www.conventionalcommits.org/) for consistent versioning and changelog generation.
|
|
344
|
+
|
|
345
|
+
Format:
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
<type>: <description>
|
|
349
|
+
|
|
350
|
+
[optional body]
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Types:
|
|
354
|
+
|
|
355
|
+
- `feat`: New feature
|
|
356
|
+
- `fix`: Bug fix
|
|
357
|
+
- `docs`: Documentation changes
|
|
358
|
+
- `style`: Code style/formatting (no logic change)
|
|
359
|
+
- `refactor`: Code refactoring (no feature/bug change)
|
|
360
|
+
- `test`: Adding or updating tests
|
|
361
|
+
- `chore`: Maintenance tasks (dependencies, config, etc.)
|
|
362
|
+
- `perf`: Performance improvements
|
|
363
|
+
|
|
364
|
+
Examples:
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
feat: add new Button variant
|
|
368
|
+
fix: correct Typography component spacing
|
|
369
|
+
docs: update README with visual testing guide
|
|
370
|
+
chore: update dependencies
|
|
371
|
+
test: add tests for TextLink component
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Continuous Integration
|
|
377
|
+
|
|
378
|
+
All pull requests are automatically validated through our CI pipeline.
|
|
379
|
+
|
|
380
|
+
### Required Checks
|
|
381
|
+
|
|
382
|
+
1. ✅ Format & Lint - Code must be properly formatted and pass linting
|
|
383
|
+
2. ✅ Type Check - No TypeScript errors
|
|
384
|
+
3. ✅ Tests - All unit tests must pass
|
|
385
|
+
4. ✅ Build - Project must build successfully
|
|
386
|
+
5. ✅ Build Storybook - Storybook must build successfully
|
|
387
|
+
6. ✅ Visual Tests - Playwright visual regression tests must pass
|
|
388
|
+
|
|
389
|
+
### Pipeline Triggers
|
|
390
|
+
|
|
391
|
+
- Pull requests to `main`
|
|
392
|
+
- Pushes to `main`
|
|
393
|
+
|
|
394
|
+
### Why No Pre-commit Hooks?
|
|
395
|
+
|
|
396
|
+
We intentionally don't use pre-commit hooks (like Husky):
|
|
397
|
+
|
|
398
|
+
- ✅ Quality checks in CI can't be bypassed
|
|
399
|
+
- ✅ Faster local development workflow
|
|
400
|
+
- ✅ CI is the single source of truth
|
|
401
|
+
|
|
402
|
+
Note: You're encouraged to run `npm run preflight` locally before pushing!
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## EditorConfig & VS Code Settings
|
|
407
|
+
|
|
408
|
+
This project uses a strict `.editorconfig` to ensure consistent code style across all editors and platforms. Most formatting rules (indentation, line endings, trailing whitespace, etc.) are enforced automatically if you have the [EditorConfig extension](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) installed in VS Code.
|
|
409
|
+
|
|
410
|
+
Additionally, the repository includes a `.vscode/settings.json` file to avoid conflicts between VS Code's built-in formatting and EditorConfig:
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"editor.formatOnSave": true,
|
|
415
|
+
"files.trimTrailingWhitespace": false,
|
|
416
|
+
"files.insertFinalNewline": false,
|
|
417
|
+
"files.eol": "\n"
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
- No further VS Code settings are required—just make sure the EditorConfig extension is enabled.
|
|
422
|
+
- These settings ensure that formatting is always consistent, regardless of individual developer/editor preferences.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type VariantProps } from "tailwind-variants";
|
|
2
|
+
declare const avatarStyles: import("tailwind-variants").TVReturnType<{
|
|
3
|
+
size: {
|
|
4
|
+
sm: {
|
|
5
|
+
avatar: string[];
|
|
6
|
+
};
|
|
7
|
+
md: {
|
|
8
|
+
avatar: string[];
|
|
9
|
+
};
|
|
10
|
+
lg: {
|
|
11
|
+
avatar: string[];
|
|
12
|
+
};
|
|
13
|
+
xl: {
|
|
14
|
+
avatar: string[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}, {
|
|
18
|
+
base: string[];
|
|
19
|
+
avatar: string[];
|
|
20
|
+
action: string[];
|
|
21
|
+
}, undefined, {
|
|
22
|
+
size: {
|
|
23
|
+
sm: {
|
|
24
|
+
avatar: string[];
|
|
25
|
+
};
|
|
26
|
+
md: {
|
|
27
|
+
avatar: string[];
|
|
28
|
+
};
|
|
29
|
+
lg: {
|
|
30
|
+
avatar: string[];
|
|
31
|
+
};
|
|
32
|
+
xl: {
|
|
33
|
+
avatar: string[];
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}, {
|
|
37
|
+
base: string[];
|
|
38
|
+
avatar: string[];
|
|
39
|
+
action: string[];
|
|
40
|
+
}, import("tailwind-variants").TVReturnType<{
|
|
41
|
+
size: {
|
|
42
|
+
sm: {
|
|
43
|
+
avatar: string[];
|
|
44
|
+
};
|
|
45
|
+
md: {
|
|
46
|
+
avatar: string[];
|
|
47
|
+
};
|
|
48
|
+
lg: {
|
|
49
|
+
avatar: string[];
|
|
50
|
+
};
|
|
51
|
+
xl: {
|
|
52
|
+
avatar: string[];
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
}, {
|
|
56
|
+
base: string[];
|
|
57
|
+
avatar: string[];
|
|
58
|
+
action: string[];
|
|
59
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
60
|
+
type AvatarVariants = VariantProps<typeof avatarStyles>;
|
|
61
|
+
type AvatarSize = "sm" | "md" | "lg" | "xl";
|
|
62
|
+
interface AvatarProps extends AvatarVariants {
|
|
63
|
+
label: string;
|
|
64
|
+
size: AvatarSize;
|
|
65
|
+
src: string;
|
|
66
|
+
children: React.ReactNode;
|
|
67
|
+
onClick?: () => void;
|
|
68
|
+
onActionClick?: () => void;
|
|
69
|
+
}
|
|
70
|
+
export declare const Avatar: (props: AvatarProps) => import("react/jsx-runtime").JSX.Element;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as RadixAvatar from "@radix-ui/react-avatar";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
import { Edit } from "../icons/generated";
|
|
5
|
+
import { RoundButton } from "../round-button/RoundButton";
|
|
6
|
+
const avatarStyles = tv({
|
|
7
|
+
slots: {
|
|
8
|
+
base: ["relative", "inline-block"],
|
|
9
|
+
avatar: [
|
|
10
|
+
"rounded-full",
|
|
11
|
+
"transition",
|
|
12
|
+
"duration-300",
|
|
13
|
+
"ease-in-out",
|
|
14
|
+
"min-w-10",
|
|
15
|
+
"min-h-10",
|
|
16
|
+
"flex",
|
|
17
|
+
"items-center",
|
|
18
|
+
"justify-center",
|
|
19
|
+
],
|
|
20
|
+
action: ["absolute", "bottom-2", "right-2"],
|
|
21
|
+
},
|
|
22
|
+
variants: {
|
|
23
|
+
size: {
|
|
24
|
+
sm: { avatar: ["w-10", "h-10", "hover:scale-105"] },
|
|
25
|
+
md: {
|
|
26
|
+
avatar: [
|
|
27
|
+
"w-16",
|
|
28
|
+
"h-16",
|
|
29
|
+
"border",
|
|
30
|
+
"border-solid",
|
|
31
|
+
"border-slate-100",
|
|
32
|
+
"border-6",
|
|
33
|
+
"hover:scale-105",
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
lg: {
|
|
37
|
+
avatar: [
|
|
38
|
+
"w-24",
|
|
39
|
+
"h-24",
|
|
40
|
+
"border",
|
|
41
|
+
"border-solid",
|
|
42
|
+
"border-slate-100",
|
|
43
|
+
"border-6",
|
|
44
|
+
"hover:scale-95",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
xl: {
|
|
48
|
+
avatar: [
|
|
49
|
+
"w-40",
|
|
50
|
+
"h-40",
|
|
51
|
+
"border",
|
|
52
|
+
"border-solid",
|
|
53
|
+
"border-slate-100",
|
|
54
|
+
"border-6",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
export const Avatar = (props) => {
|
|
61
|
+
const { base, avatar, action } = avatarStyles(props);
|
|
62
|
+
return (_jsxs(RadixAvatar.Root, { onClick: props.onClick, className: base(props), children: [_jsx(RadixAvatar.Image, { src: props.src, alt: props.label, className: avatar(props) }), props.size === "xl" && props.onActionClick && (_jsx("div", { className: action(props), children: _jsx(RoundButton, { intent: "primary", ariaLabel: `Edit ${props.label}`, onClick: props.onActionClick ?? (() => { }), children: _jsx(Edit, {}) }) })), _jsx(RadixAvatar.Fallback, { children: _jsx("div", { className: avatar(props), children: props.children }) })] }));
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BrandingGallery: React.FC;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import appIconGradient from "./app-icon-gradient.svg";
|
|
3
|
+
import appIconWhite from "./app-icon-white.svg";
|
|
4
|
+
import hoverLogo from "./hover-logo.svg";
|
|
5
|
+
import logoInlineGradient from "./logo-inline-gradient.svg";
|
|
6
|
+
import logoInlineViolet from "./logo-inline-violet.svg";
|
|
7
|
+
import logoInlineWhite from "./logo-inline-white.svg";
|
|
8
|
+
import logoStackedGradient from "./logo-stacked-gradient.svg";
|
|
9
|
+
import logoStackedViolet from "./logo-stacked-violet.svg";
|
|
10
|
+
import logoStackedWhite from "./logo-stacked-white.svg";
|
|
11
|
+
import superzeichen from "./superzeichen.svg";
|
|
12
|
+
const brandingAssets = {
|
|
13
|
+
"App Icons": [
|
|
14
|
+
{
|
|
15
|
+
name: "App Icon Gradient",
|
|
16
|
+
src: appIconGradient,
|
|
17
|
+
width: 64,
|
|
18
|
+
height: 64,
|
|
19
|
+
filename: "app-icon-gradient.svg",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "App Icon White",
|
|
23
|
+
src: appIconWhite,
|
|
24
|
+
width: 64,
|
|
25
|
+
height: 64,
|
|
26
|
+
filename: "app-icon-white.svg",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
Logos: [
|
|
30
|
+
{
|
|
31
|
+
name: "Logo Inline Gradient",
|
|
32
|
+
src: logoInlineGradient,
|
|
33
|
+
width: 335,
|
|
34
|
+
height: 64,
|
|
35
|
+
filename: "logo-inline-gradient.svg",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "Logo Inline Violet",
|
|
39
|
+
src: logoInlineViolet,
|
|
40
|
+
width: 335,
|
|
41
|
+
height: 64,
|
|
42
|
+
filename: "logo-inline-violet.svg",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Logo Inline White",
|
|
46
|
+
src: logoInlineWhite,
|
|
47
|
+
width: 335,
|
|
48
|
+
height: 64,
|
|
49
|
+
filename: "logo-inline-white.svg",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "Logo Stacked Gradient",
|
|
53
|
+
src: logoStackedGradient,
|
|
54
|
+
width: 210,
|
|
55
|
+
height: 80,
|
|
56
|
+
filename: "logo-stacked-gradient.svg",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "Logo Stacked Violet",
|
|
60
|
+
src: logoStackedViolet,
|
|
61
|
+
width: 210,
|
|
62
|
+
height: 80,
|
|
63
|
+
filename: "logo-stacked-violet.svg",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "Logo Stacked White",
|
|
67
|
+
src: logoStackedWhite,
|
|
68
|
+
width: 210,
|
|
69
|
+
height: 80,
|
|
70
|
+
filename: "logo-stacked-white.svg",
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
"Hover Logo": [
|
|
74
|
+
{
|
|
75
|
+
name: "Hover Logo",
|
|
76
|
+
src: hoverLogo,
|
|
77
|
+
width: 64,
|
|
78
|
+
height: 64,
|
|
79
|
+
filename: "hover-logo.svg",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
Superzeichen: [
|
|
83
|
+
{
|
|
84
|
+
name: "Superzeichen",
|
|
85
|
+
src: superzeichen,
|
|
86
|
+
width: 64,
|
|
87
|
+
height: 64,
|
|
88
|
+
filename: "superzeichen.svg",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
export const BrandingGallery = () => (_jsx("div", { children: Object.entries(brandingAssets).map(([category, assets]) => (_jsxs("div", { style: { marginBottom: 48 }, children: [_jsx("h2", { style: {
|
|
93
|
+
fontSize: 20,
|
|
94
|
+
fontWeight: 600,
|
|
95
|
+
marginBottom: 24,
|
|
96
|
+
marginTop: 0,
|
|
97
|
+
}, children: category }), _jsx("div", { style: {
|
|
98
|
+
display: "grid",
|
|
99
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
|
|
100
|
+
gap: 32,
|
|
101
|
+
padding: 4,
|
|
102
|
+
}, children: assets.map(({ name, src, width, height, filename }) => {
|
|
103
|
+
const isWhiteVariant = filename.includes("white") || filename.includes("hover");
|
|
104
|
+
return (_jsxs("div", { style: {
|
|
105
|
+
display: "flex",
|
|
106
|
+
flexDirection: "column",
|
|
107
|
+
alignItems: "center",
|
|
108
|
+
border: "1px solid #eee",
|
|
109
|
+
padding: 24,
|
|
110
|
+
borderRadius: 8,
|
|
111
|
+
backgroundColor: "#fafafa",
|
|
112
|
+
gap: 16,
|
|
113
|
+
}, children: [_jsx("div", { style: {
|
|
114
|
+
display: "flex",
|
|
115
|
+
alignItems: "center",
|
|
116
|
+
justifyContent: "center",
|
|
117
|
+
minHeight: 120,
|
|
118
|
+
width: "100%",
|
|
119
|
+
backgroundColor: isWhiteVariant ? "#7c3aed" : "transparent",
|
|
120
|
+
borderRadius: 4,
|
|
121
|
+
padding: isWhiteVariant ? 16 : 0,
|
|
122
|
+
}, children: _jsx("img", { src: src, alt: name, style: {
|
|
123
|
+
maxWidth: "100%",
|
|
124
|
+
height: "auto",
|
|
125
|
+
objectFit: "contain",
|
|
126
|
+
} }) }), _jsxs("div", { style: {
|
|
127
|
+
textAlign: "center",
|
|
128
|
+
width: "100%",
|
|
129
|
+
}, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 8 }, children: name }), _jsx("code", { style: {
|
|
130
|
+
fontSize: 11,
|
|
131
|
+
color: "#666",
|
|
132
|
+
display: "block",
|
|
133
|
+
marginBottom: 4,
|
|
134
|
+
}, children: filename }), _jsxs("code", { style: {
|
|
135
|
+
fontSize: 11,
|
|
136
|
+
color: "#666",
|
|
137
|
+
display: "block",
|
|
138
|
+
}, children: [width, " \u00D7 ", height] })] })] }, name));
|
|
139
|
+
}) })] }, category))) }));
|