css-is-awesome 1.1.0
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/AGENTS.md +343 -0
- package/CHANGELOG.md +1036 -0
- package/CLAUDE.md +9 -0
- package/CONTRACT.md +580 -0
- package/GEMINI.md +9 -0
- package/LICENSE +21 -0
- package/LICENSE-third-party +88 -0
- package/MIGRATION.md +312 -0
- package/README.md +380 -0
- package/ROADMAP.md +714 -0
- package/THEMING.md +290 -0
- package/THREE-TIERS.md +158 -0
- package/VERSIONING.md +200 -0
- package/_index.scss +34 -0
- package/api.scss +16 -0
- package/bin/README.md +57 -0
- package/bin/cia.cjs +114 -0
- package/bin/migrate-bootstrap.cjs +427 -0
- package/bin/migrate-tailwind.cjs +832 -0
- package/css-is-awesome.instructions.md +533 -0
- package/dist/css-is-awesome.core.css +598 -0
- package/dist/css-is-awesome.core.min.css +1 -0
- package/dist/css-is-awesome.css +3733 -0
- package/dist/css-is-awesome.min.css +1 -0
- package/dist/css-is-awesome.utilities.css +2445 -0
- package/dist/css-is-awesome.utilities.min.css +1 -0
- package/dist/tokens.css +508 -0
- package/dist/tokens.d.ts +266 -0
- package/dist/tokens.min.css +1 -0
- package/figma-tokens/README.md +57 -0
- package/figma-tokens/primitives-brand.scss +121 -0
- package/figma-tokens/semantic-dark.scss +61 -0
- package/figma-tokens/semantic-light.scss +61 -0
- package/figma-tokens/tokens.json +144 -0
- package/llm.txt +183 -0
- package/mcp/server.cjs +1495 -0
- package/package.json +199 -0
- package/public/icons/README.md +278 -0
- package/public/icons/arrow-right.svg +4 -0
- package/public/icons/check.svg +4 -0
- package/public/icons/chevron-down.svg +4 -0
- package/public/icons/close.svg +4 -0
- package/public/icons/core/arrow-down.svg +13 -0
- package/public/icons/core/arrow-left.svg +13 -0
- package/public/icons/core/arrow-right.svg +13 -0
- package/public/icons/core/arrow-up.svg +13 -0
- package/public/icons/core/bell.svg +13 -0
- package/public/icons/core/calendar.svg +15 -0
- package/public/icons/core/check.svg +12 -0
- package/public/icons/core/chevron-down.svg +12 -0
- package/public/icons/core/chevron-left.svg +12 -0
- package/public/icons/core/chevron-right.svg +12 -0
- package/public/icons/core/chevron-up.svg +12 -0
- package/public/icons/core/clock.svg +13 -0
- package/public/icons/core/close.svg +13 -0
- package/public/icons/core/copy.svg +13 -0
- package/public/icons/core/download.svg +14 -0
- package/public/icons/core/edit.svg +13 -0
- package/public/icons/core/error.svg +14 -0
- package/public/icons/core/external-link.svg +14 -0
- package/public/icons/core/eye-off.svg +15 -0
- package/public/icons/core/eye.svg +13 -0
- package/public/icons/core/filter.svg +12 -0
- package/public/icons/core/heart.svg +12 -0
- package/public/icons/core/help.svg +14 -0
- package/public/icons/core/home.svg +13 -0
- package/public/icons/core/info.svg +14 -0
- package/public/icons/core/loading.svg +12 -0
- package/public/icons/core/lock.svg +13 -0
- package/public/icons/core/mail.svg +13 -0
- package/public/icons/core/menu.svg +14 -0
- package/public/icons/core/message.svg +12 -0
- package/public/icons/core/minus.svg +12 -0
- package/public/icons/core/more-horizontal.svg +14 -0
- package/public/icons/core/pause.svg +13 -0
- package/public/icons/core/play.svg +12 -0
- package/public/icons/core/plus.svg +13 -0
- package/public/icons/core/refresh.svg +15 -0
- package/public/icons/core/save.svg +14 -0
- package/public/icons/core/search.svg +13 -0
- package/public/icons/core/settings.svg +13 -0
- package/public/icons/core/share.svg +14 -0
- package/public/icons/core/sort.svg +15 -0
- package/public/icons/core/star.svg +12 -0
- package/public/icons/core/success.svg +13 -0
- package/public/icons/core/trash.svg +16 -0
- package/public/icons/core/unlock.svg +13 -0
- package/public/icons/core/upload.svg +14 -0
- package/public/icons/core/user.svg +13 -0
- package/public/icons/core/users.svg +15 -0
- package/public/icons/core/warning.svg +14 -0
- package/public/icons/download.svg +4 -0
- package/public/icons/edit.svg +4 -0
- package/public/icons/menu.svg +4 -0
- package/public/icons/search.svg +4 -0
- package/public/theme.css +4179 -0
- package/public/themes/README.md +102 -0
- package/public/themes/boilerplate/theme.css +154 -0
- package/public/themes/boilerplate-dark/theme.css +171 -0
- package/public/themes/boilerplate-light/theme.css +171 -0
- package/public/themes/cupertino/theme.css +165 -0
- package/public/themes/cupertino-dark/theme.css +200 -0
- package/public/themes/cupertino-light/theme.css +227 -0
- package/public/themes/glass/theme.css +190 -0
- package/public/themes/glass-dark/theme.css +201 -0
- package/public/themes/glass-light/theme.css +229 -0
- package/public/themes/graphite/theme.css +155 -0
- package/public/themes/graphite-dark/theme.css +223 -0
- package/public/themes/graphite-light/theme.css +191 -0
- package/public/themes/press/theme.css +189 -0
- package/public/themes/press-dark/theme.css +199 -0
- package/public/themes/press-light/theme.css +235 -0
- package/public/themes/prism/theme.css +159 -0
- package/public/themes/prism-dark/theme.css +185 -0
- package/public/themes/prism-light/theme.css +188 -0
- package/public/themes/sketchbook/theme.css +152 -0
- package/public/themes/sketchbook-dark/theme.css +194 -0
- package/public/themes/sketchbook-light/theme.css +188 -0
- package/public/themes/terminal/theme.css +159 -0
- package/public/themes/terminal-dark/theme.css +229 -0
- package/public/themes/terminal-light/theme.css +152 -0
- package/scripts/README.md +70 -0
- package/scripts/icon-contract.json +67 -0
- package/scripts/icon-validator.js +205 -0
- package/scripts/prepare-dist.mjs +65 -0
- package/scripts/theme-a11y.js +415 -0
- package/scripts/theme-contract.json +171 -0
- package/scripts/theme-validator.js +674 -0
- package/scss/README.md +55 -0
- package/scss/_animations-utilities.scss +107 -0
- package/scss/_animations.scss +248 -0
- package/scss/_app-styles.scss +15 -0
- package/scss/_generator.scss +174 -0
- package/scss/_icons.scss +475 -0
- package/scss/_index.scss +17 -0
- package/scss/_layout.scss +597 -0
- package/scss/_mixins.scss +1036 -0
- package/scss/_system.scss +291 -0
- package/scss/_utilities.scss +377 -0
- package/scss/api.scss +61 -0
- package/scss/components/_accordion.scss +72 -0
- package/scss/components/_buttons.scss +171 -0
- package/scss/components/_copy-button.scss +69 -0
- package/scss/components/_data.scss +190 -0
- package/scss/components/_feedback.scss +197 -0
- package/scss/components/_forms.scss +272 -0
- package/scss/components/_index.scss +17 -0
- package/scss/components/_navigation.scss +186 -0
- package/scss/components/_overlay.scss +259 -0
- package/scss/components/_stepper.scss +159 -0
- package/scss/components/_tabs.scss +72 -0
- package/scss/core.scss +54 -0
- package/scss/examples/_theming.scss +107 -0
- package/scss/examples/_usage.scss +317 -0
- package/scss/main.scss +64 -0
- package/scss/recipes/README.md +110 -0
- package/scss/recipes/_bare-tags.scss +232 -0
- package/scss/recipes/_recipe-template.md +119 -0
- package/scss/recipes/combobox.md +509 -0
- package/scss/recipes/dialog.md +265 -0
- package/scss/recipes/print-to-pdf.md +263 -0
- package/scss/theme/README.md +67 -0
- package/scss/theme/_brand.scss +18 -0
- package/scss/theme/_colors-dark.scss +68 -0
- package/scss/theme/_colors-light.scss +70 -0
- package/scss/theme/_components.scss +94 -0
- package/scss/theme/_icons.scss +104 -0
- package/scss/theme/_index.scss +62 -0
- package/scss/theme/_shadows.scss +65 -0
- package/scss/theme/_shape.scss +13 -0
- package/scss/theme/_typography.scss +9 -0
- package/scss/theme/registry.json +447 -0
- package/scss/themes/boilerplate-dark.scss +212 -0
- package/scss/themes/boilerplate-light.scss +209 -0
- package/scss/themes/boilerplate.scss +181 -0
- package/scss/themes/cupertino-dark.scss +238 -0
- package/scss/themes/cupertino-light.scss +266 -0
- package/scss/themes/cupertino.scss +194 -0
- package/scss/themes/glass-dark.scss +238 -0
- package/scss/themes/glass-light.scss +266 -0
- package/scss/themes/glass.scss +220 -0
- package/scss/themes/graphite-dark.scss +260 -0
- package/scss/themes/graphite-light.scss +228 -0
- package/scss/themes/graphite.scss +182 -0
- package/scss/themes/press-dark.scss +237 -0
- package/scss/themes/press-light.scss +273 -0
- package/scss/themes/press.scss +241 -0
- package/scss/themes/prism-dark.scss +217 -0
- package/scss/themes/prism-light.scss +220 -0
- package/scss/themes/prism.scss +190 -0
- package/scss/themes/sketchbook-dark.scss +231 -0
- package/scss/themes/sketchbook-light.scss +231 -0
- package/scss/themes/sketchbook.scss +178 -0
- package/scss/themes/terminal-dark.scss +267 -0
- package/scss/themes/terminal-light.scss +175 -0
- package/scss/themes/terminal.scss +185 -0
- package/scss/tokens.scss +23 -0
- package/scss/utilities-only.scss +4 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// EXAMPLES - Icon Systems + Core Mixins
|
|
3
|
+
// ============================================================================
|
|
4
|
+
@use '../mixins' as m;
|
|
5
|
+
@use '../icons' as i;
|
|
6
|
+
@use '../theme' as t;
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// SVG ICONS - Folder Based (No Config Needed!)
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Just drop .svg files into your $icon-path folder
|
|
12
|
+
// Filename = icon name
|
|
13
|
+
//
|
|
14
|
+
// Folder: /assets/icons/
|
|
15
|
+
// arrow.svg → @include i.svg(arrow)
|
|
16
|
+
// search.svg → @include i.svg(search)
|
|
17
|
+
// my-custom.svg → @include i.svg(my-custom)
|
|
18
|
+
//
|
|
19
|
+
// That's it. No map to update. Just add files and rebuild.
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
// Basic icons - uses filename directly
|
|
23
|
+
.icon-search { @include i.svg(search); }
|
|
24
|
+
.icon-arrow { @include i.svg(arrow); }
|
|
25
|
+
.icon-menu { @include i.svg(menu, 28px); }
|
|
26
|
+
.icon-close { @include i.svg(close, 20px, m.color(text-muted)); }
|
|
27
|
+
|
|
28
|
+
// Custom size and color
|
|
29
|
+
.icon-large { @include i.svg(settings, 48px, m.color(brand-primary)); }
|
|
30
|
+
|
|
31
|
+
// Multi-color SVG (as background, not colorable)
|
|
32
|
+
.logo { @include i.svg-bg(logo, 120px); }
|
|
33
|
+
|
|
34
|
+
// Icon with text (buttons, links)
|
|
35
|
+
.btn-download { @include i.svg-text(download); }
|
|
36
|
+
.btn-next { @include i.svg-text(arrow-right, $position: after); }
|
|
37
|
+
|
|
38
|
+
// ALIASING (optional - only when filename ≠ desired name)
|
|
39
|
+
// In _theme.scss:
|
|
40
|
+
// $icon-svg-alias: (
|
|
41
|
+
// delete: 'trash', // @include i.svg(delete) → uses trash.svg
|
|
42
|
+
// close: 'x', // @include i.svg(close) → uses x.svg
|
|
43
|
+
// );
|
|
44
|
+
//
|
|
45
|
+
// Most of the time you don't need aliases.
|
|
46
|
+
// Just name your SVG files what you want to call them.
|
|
47
|
+
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// FONT AWESOME ICONS
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Configure $fa-path and $icon-fa-map in _theme.scss
|
|
52
|
+
// Load fonts with @include i.fa-load; in main.scss (if self-hosting)
|
|
53
|
+
|
|
54
|
+
// Basic FA icon (use inside ::before or ::after)
|
|
55
|
+
.fa-example::before {
|
|
56
|
+
@include i.fa(check);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// With size
|
|
60
|
+
.fa-large::before {
|
|
61
|
+
@include i.fa(star, solid, 24px);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Different styles
|
|
65
|
+
.fa-outline::before {
|
|
66
|
+
@include i.fa(heart, regular); // Outline style
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.fa-brand::before {
|
|
70
|
+
@include i.fa(github, brands); // Brand icon
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// FA as standalone element
|
|
74
|
+
.icon-user { @include i.fa-icon(user); }
|
|
75
|
+
.icon-bell { @include i.fa-icon(bell, 20px); }
|
|
76
|
+
.icon-warning { @include i.fa-icon(warning, 24px, solid, m.color(warning-default)); }
|
|
77
|
+
|
|
78
|
+
// FA icon with text (buttons, links)
|
|
79
|
+
.btn-save { @include i.fa-text(save); }
|
|
80
|
+
.btn-external { @include i.fa-text(external, $position: after); }
|
|
81
|
+
.btn-delete { @include i.fa-text(delete, $size: 0.875em, $gap: 0.5em); }
|
|
82
|
+
|
|
83
|
+
// Spinning loader
|
|
84
|
+
.loading { @include i.fa-spin(spinner); }
|
|
85
|
+
.loading-large { @include i.fa-spin(spinner, 32px); }
|
|
86
|
+
|
|
87
|
+
// Adding custom FA icons:
|
|
88
|
+
// 1. Find unicode at https://fontawesome.com/search
|
|
89
|
+
// 2. Add to $icon-fa-map in _theme.scss:
|
|
90
|
+
// my-icon: '\f123',
|
|
91
|
+
// 3. Use it:
|
|
92
|
+
// @include i.fa(my-icon);
|
|
93
|
+
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// REAL COMPONENT EXAMPLES
|
|
96
|
+
// ============================================================================
|
|
97
|
+
|
|
98
|
+
// Button with SVG icon
|
|
99
|
+
.btn-primary {
|
|
100
|
+
@include m.btn-base;
|
|
101
|
+
@include i.svg-text(arrow-right, $position: after);
|
|
102
|
+
background: m.color(brand-primary);
|
|
103
|
+
color: m.color(text-inverse);
|
|
104
|
+
|
|
105
|
+
&:hover { background: m.color(brand-primary-hover); }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Button with FA icon
|
|
109
|
+
.btn-secondary {
|
|
110
|
+
@include m.btn-base;
|
|
111
|
+
@include i.fa-text(download);
|
|
112
|
+
background: transparent;
|
|
113
|
+
@include m.border;
|
|
114
|
+
|
|
115
|
+
&:hover { background: m.color(interactive-hover); }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Icon-only button (SVG)
|
|
119
|
+
.btn-icon {
|
|
120
|
+
@include m.button-reset;
|
|
121
|
+
@include m.flex($justify: center);
|
|
122
|
+
@include i.svg(close, 20px);
|
|
123
|
+
width: 40px;
|
|
124
|
+
height: 40px;
|
|
125
|
+
border-radius: m.radius(full);
|
|
126
|
+
@include m.transition(background-color);
|
|
127
|
+
|
|
128
|
+
&:hover { background: m.color(interactive-hover); }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Icon-only button (FA)
|
|
132
|
+
.btn-icon-fa {
|
|
133
|
+
@include m.button-reset;
|
|
134
|
+
@include m.flex($justify: center);
|
|
135
|
+
@include i.fa-icon(settings, 20px);
|
|
136
|
+
width: 40px;
|
|
137
|
+
height: 40px;
|
|
138
|
+
border-radius: m.radius(full);
|
|
139
|
+
@include m.transition(background-color);
|
|
140
|
+
|
|
141
|
+
&:hover { background: m.color(interactive-hover); }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Alert with FA icon — single-class router pattern (no BEM modifiers).
|
|
145
|
+
// Variant lives in the class name, not as a `--modifier`. The base mixin
|
|
146
|
+
// stays a base; status-specific styling is its own standalone class.
|
|
147
|
+
.alert {
|
|
148
|
+
@include m.card-base($p: sm);
|
|
149
|
+
@include m.flex($gap: sm);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.alert-info {
|
|
153
|
+
background: m.color(info-subtle);
|
|
154
|
+
@include m.border(3px, solid, info-default, left);
|
|
155
|
+
|
|
156
|
+
&::before {
|
|
157
|
+
@include i.fa(info, solid, 1.25em);
|
|
158
|
+
color: m.color(info-default);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.alert-success {
|
|
163
|
+
background: m.color(success-subtle);
|
|
164
|
+
@include m.border(3px, solid, success-default, left);
|
|
165
|
+
|
|
166
|
+
&::before {
|
|
167
|
+
@include i.fa(check, solid, 1.25em);
|
|
168
|
+
color: m.color(success-default);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.alert-warning {
|
|
173
|
+
background: m.color(warning-subtle);
|
|
174
|
+
@include m.border(3px, solid, warning-default, left);
|
|
175
|
+
|
|
176
|
+
&::before {
|
|
177
|
+
@include i.fa(warning, solid, 1.25em);
|
|
178
|
+
color: m.color(warning-default);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.alert-error {
|
|
183
|
+
background: m.color(error-subtle);
|
|
184
|
+
@include m.border(3px, solid, error-default, left);
|
|
185
|
+
|
|
186
|
+
&::before {
|
|
187
|
+
@include i.fa(error, solid, 1.25em);
|
|
188
|
+
color: m.color(error-default);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Input with icon
|
|
193
|
+
.input-search {
|
|
194
|
+
position: relative;
|
|
195
|
+
|
|
196
|
+
input {
|
|
197
|
+
@include m.input-base;
|
|
198
|
+
padding-left: m.space(xl);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
&::before {
|
|
202
|
+
content: '';
|
|
203
|
+
position: absolute;
|
|
204
|
+
left: m.space(sm);
|
|
205
|
+
top: 50%;
|
|
206
|
+
transform: translateY(-50%);
|
|
207
|
+
@include i.svg(search, 20px);
|
|
208
|
+
color: m.color(text-muted);
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Navbar with icons — single-class child elements, not BEM `__element`.
|
|
214
|
+
// Author-side code names its own classes (`navbar-logo`, `navbar-menu-btn`).
|
|
215
|
+
.navbar {
|
|
216
|
+
@include m.flex($justify: between);
|
|
217
|
+
@include m.pad-y(sm);
|
|
218
|
+
@include m.pad-x(md);
|
|
219
|
+
@include m.border(1px, solid, border-default, bottom);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.navbar-logo {
|
|
223
|
+
@include i.svg-bg(logo, 32px);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.navbar-menu-btn {
|
|
227
|
+
@include m.button-reset;
|
|
228
|
+
@include i.svg(menu, 24px);
|
|
229
|
+
|
|
230
|
+
@include m.tablet {
|
|
231
|
+
display: none;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Social links with FA brands
|
|
236
|
+
.social-links {
|
|
237
|
+
@include m.flex($gap: md);
|
|
238
|
+
|
|
239
|
+
a {
|
|
240
|
+
@include m.button-reset;
|
|
241
|
+
color: m.color(text-secondary);
|
|
242
|
+
@include m.hover(color, m.color(text-primary));
|
|
243
|
+
|
|
244
|
+
&.github::before { @include i.fa(github, brands, 24px); }
|
|
245
|
+
&.twitter::before { @include i.fa(twitter, brands, 24px); }
|
|
246
|
+
&.linkedin::before { @include i.fa(linkedin, brands, 24px); }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// CORE MIXINS EXAMPLES
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
// Font - tokens or values
|
|
255
|
+
.heading { @include m.font(bold, xl, tight); }
|
|
256
|
+
.body { @include m.font(reg, base, normal); }
|
|
257
|
+
.custom { @include m.font(semibold, 1.5rem, 1.4, -0.01em); }
|
|
258
|
+
|
|
259
|
+
// Spacing
|
|
260
|
+
.section {
|
|
261
|
+
@include m.pad(lg);
|
|
262
|
+
@include m.flex($direction: column, $gap: md);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Borders
|
|
266
|
+
.bordered { @include m.border; }
|
|
267
|
+
.underlined { @include m.border(2px, solid, brand-primary, bottom); }
|
|
268
|
+
|
|
269
|
+
// Breakpoints
|
|
270
|
+
.responsive {
|
|
271
|
+
@include m.mobile-only { font-size: 14px; }
|
|
272
|
+
@include m.tablet { font-size: 16px; }
|
|
273
|
+
@include m.desktop { font-size: 18px; }
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Component bases
|
|
277
|
+
.btn { @include m.btn-base; }
|
|
278
|
+
.card { @include m.card-base; }
|
|
279
|
+
.input { @include m.input-base; }
|
|
280
|
+
.badge { @include m.badge-base; }
|
|
281
|
+
|
|
282
|
+
// ============================================================================
|
|
283
|
+
// CHEAT SHEET
|
|
284
|
+
// ============================================================================
|
|
285
|
+
|
|
286
|
+
/*
|
|
287
|
+
SVG ICONS (folder-based):
|
|
288
|
+
1. Drop file in /assets/icons/ folder
|
|
289
|
+
2. Use filename as icon name:
|
|
290
|
+
arrow.svg → @include i.svg(arrow)
|
|
291
|
+
|
|
292
|
+
@include i.svg(name, size?, color?)
|
|
293
|
+
@include i.svg-bg(name, size?) → Multi-color SVGs
|
|
294
|
+
@include i.svg-text(name, size?, gap?, position?)
|
|
295
|
+
|
|
296
|
+
Optional alias (in _theme.scss):
|
|
297
|
+
$icon-svg-alias: (delete: 'trash') → delete uses trash.svg
|
|
298
|
+
|
|
299
|
+
FONT AWESOME:
|
|
300
|
+
@include i.fa(name, style?, size?) → Inside ::before/::after
|
|
301
|
+
@include i.fa-icon(name, size?, style?, color?)
|
|
302
|
+
@include i.fa-text(name, size?, gap?, style?, position?)
|
|
303
|
+
@include i.fa-spin(name, size?, style?)
|
|
304
|
+
@include i.fa-load → Load fonts (self-hosted)
|
|
305
|
+
|
|
306
|
+
FA STYLES:
|
|
307
|
+
solid → Filled (default)
|
|
308
|
+
regular → Outline
|
|
309
|
+
brands → Logos (github, twitter)
|
|
310
|
+
|
|
311
|
+
CORE MIXINS:
|
|
312
|
+
m.color(name) m.space(n) m.radius(size)
|
|
313
|
+
m.font(type, ...) m.border(...) m.elevation(level)
|
|
314
|
+
m.transition(...) m.flex($justify, $gap, $direction, ...)
|
|
315
|
+
m.pad(size) m.pad-asym(y, x)
|
|
316
|
+
m.btn-base(...) m.card-base(...) m.input-base(...)
|
|
317
|
+
*/
|
package/scss/main.scss
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// MAIN - Entry Point
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// This generates the actual CSS output.
|
|
5
|
+
// Import this once at your app's root.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
@use './generator';
|
|
8
|
+
@use './mixins' as m;
|
|
9
|
+
@use './animations';
|
|
10
|
+
@use './animations-utilities';
|
|
11
|
+
@use './utilities';
|
|
12
|
+
|
|
13
|
+
// ----------------------------------------------------------------------------
|
|
14
|
+
// GENERATE CSS VARIABLES
|
|
15
|
+
// ----------------------------------------------------------------------------
|
|
16
|
+
@include generator.generate-theme;
|
|
17
|
+
|
|
18
|
+
// ----------------------------------------------------------------------------
|
|
19
|
+
// BASE STYLES (Optional - include what you need)
|
|
20
|
+
// ----------------------------------------------------------------------------
|
|
21
|
+
*,
|
|
22
|
+
*::before,
|
|
23
|
+
*::after {
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
html {
|
|
28
|
+
-webkit-font-smoothing: antialiased;
|
|
29
|
+
-moz-osx-font-smoothing: grayscale;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
body {
|
|
33
|
+
margin: 0;
|
|
34
|
+
font-family: m.font-family(primary);
|
|
35
|
+
font-size: m.font-size(base);
|
|
36
|
+
line-height: m.line-height(normal);
|
|
37
|
+
color: m.color(text-primary);
|
|
38
|
+
background: m.color(surface-default);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Resets
|
|
42
|
+
@include m.header-reset;
|
|
43
|
+
@include m.form-reset;
|
|
44
|
+
|
|
45
|
+
// Links
|
|
46
|
+
a {
|
|
47
|
+
color: m.color(text-link);
|
|
48
|
+
text-decoration: none;
|
|
49
|
+
@include m.transition(color);
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
color: m.color(text-link-hover);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Focus visible
|
|
57
|
+
:focus-visible {
|
|
58
|
+
outline: 2px solid m.color(border-focus);
|
|
59
|
+
outline-offset: 2px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
:focus:not(:focus-visible) {
|
|
63
|
+
outline: none;
|
|
64
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# cia Recipes — Format + Authoring Guide
|
|
2
|
+
|
|
3
|
+
Recipes are cia's framework-agnostic patterns for building components. Each recipe is a single markdown file under `scss/recipes/`. Recipes ship in the npm package and are exposed to AI agents via the MCP server (`list_recipes`, `get_recipe`, `assemble_prompt`).
|
|
4
|
+
|
|
5
|
+
> **The recipe IS the deliverable.** cia does not ship a component library. Recipes give consumers (and AI agents) the pattern — they generate or copy the component in their own framework + selector vocabulary.
|
|
6
|
+
|
|
7
|
+
## File naming
|
|
8
|
+
|
|
9
|
+
- **Real recipes:** `<slug>.md` — kebab-case slug becomes the URL at `/docs/recipes/<slug>` and the MCP `get_recipe(slug)` key
|
|
10
|
+
- **Template / not-renderable:** `_<name>.md` — underscore prefix; catalog page + MCP loader skip these
|
|
11
|
+
|
|
12
|
+
## Required frontmatter
|
|
13
|
+
|
|
14
|
+
Every recipe begins with YAML frontmatter:
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
---
|
|
18
|
+
name: dialog
|
|
19
|
+
description: Accessible modal dialog built on <dialog>.
|
|
20
|
+
category: overlay
|
|
21
|
+
complexity: medium
|
|
22
|
+
cia-version: ">=1.0.0"
|
|
23
|
+
---
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Field | Type | Notes |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `name` | string | Must match the filename slug |
|
|
29
|
+
| `description` | string | One sentence — what this recipe builds, no more |
|
|
30
|
+
| `category` | enum | One of: `overlay`, `input`, `data`, `navigation`, `feedback`, `layout`, `auth` |
|
|
31
|
+
| `complexity` | enum | One of: `simple`, `medium`, `complex` |
|
|
32
|
+
| `cia-version` | semver range | Minimum cia version this recipe targets |
|
|
33
|
+
|
|
34
|
+
## Required H2 sections (in this order)
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
## Use this when
|
|
38
|
+
## Structure (raw HTML)
|
|
39
|
+
## Styling (cia mixins)
|
|
40
|
+
## Interactivity
|
|
41
|
+
## A11y checklist
|
|
42
|
+
## Framework examples
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each section's purpose:
|
|
46
|
+
|
|
47
|
+
- **Use this when** — 1-3 sentences describing the consumer scenario. If the reader's situation doesn't match, they should bail and look elsewhere.
|
|
48
|
+
- **Structure (raw HTML)** — the markup with `data-cia-recipe` / `data-slot` attributes. Framework-agnostic; consumer adapts to JSX / template / Svelte syntax.
|
|
49
|
+
- **Styling (cia mixins)** — SCSS using `cia.X` mixin calls against consumer-chosen class names, opened with `@use 'css-is-awesome/api' as cia;` (see [Import convention](#import-convention)). Show the minimum to make it work; cross-link to mixin docs for parameter detail.
|
|
50
|
+
- **Interactivity** — native browser behavior first (`<dialog>.showModal()`, popover API, etc.). JS only where the native primitive can't do the job.
|
|
51
|
+
- **A11y checklist** — concrete, testable items. Each item references the WCAG SC or ARIA pattern it satisfies.
|
|
52
|
+
- **Framework examples** — minimum **4 subsections**: React, Vue, Svelte, vanilla (Web Component preferred for vanilla). Each is runnable code, not pseudocode.
|
|
53
|
+
|
|
54
|
+
## Optional H2 sections
|
|
55
|
+
|
|
56
|
+
- **Variants** — common adaptations (size, density, position). One sub-block per variant with the styling delta.
|
|
57
|
+
- **Pitfalls** — known gotchas (SSR, browser compat, focus management edge cases). One bullet per pitfall.
|
|
58
|
+
- **Related recipes** — cross-link to other recipes in the catalog.
|
|
59
|
+
|
|
60
|
+
## Import convention
|
|
61
|
+
|
|
62
|
+
**Two imports, two jobs.** A recipe's `scss` blocks are component-level styling, so they open with the **zero-emit authoring barrel**:
|
|
63
|
+
|
|
64
|
+
```scss
|
|
65
|
+
@use 'css-is-awesome/api' as cia;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`/api` forwards the entire mixin + function API and emits **zero CSS** until a mixin is called, which makes it safe inside a `.module.scss` under Next.js CSS Modules pure mode.
|
|
69
|
+
|
|
70
|
+
- ❌ **Never** `@use 'css-is-awesome'` in a component styling block. That is the emitting bundle — it prints `:root` tokens, resets and base rules, and a top-level `:root` is a hard build error in CSS Modules pure mode.
|
|
71
|
+
- ✅ `@use 'css-is-awesome'` is only correct in a **root/global** stylesheet, where the tokens are emitted exactly once. If a recipe demonstrates a global stylesheet, label the block with a filename comment (`// app/globals.scss`) so the reader can tell which half of the model they're looking at.
|
|
72
|
+
- Some mixins emit at the root themselves — `cia.print-base` emits a `:root` block plus `@page`. They are still imported from `/api`; what changes is *placement*. Say in prose that they belong at the top level of a global stylesheet, never in a component module. See [`print-to-pdf.md`](./print-to-pdf.md) for the worked example.
|
|
73
|
+
- Recipes stay on `/api` on every toolchain, Turbopack included — the barrel works there. Setup notes for Next.js live in the root [`README.md`](../../README.md).
|
|
74
|
+
|
|
75
|
+
## Code-block standards
|
|
76
|
+
|
|
77
|
+
- Fenced blocks with language tag — `html`, `scss`, `tsx`, `vue`, `svelte`, `js`
|
|
78
|
+
- Component styling blocks open with `@use 'css-is-awesome/api' as cia;` — see [Import convention](#import-convention)
|
|
79
|
+
- Use the cia mixin API verbatim — never inline raw token values
|
|
80
|
+
- Class names in examples use the convention `my-<thing>` (signals "your selector here") — never `cia-<thing>` (that prefix is library-owned)
|
|
81
|
+
- Each framework example targets a single component, not a full app
|
|
82
|
+
|
|
83
|
+
## Forbidden in recipes
|
|
84
|
+
|
|
85
|
+
- ❌ `@use 'css-is-awesome'` (the emitting bundle) in a component styling block — use `css-is-awesome/api`, see [Import convention](#import-convention)
|
|
86
|
+
- ❌ `cia-` class names (that prefix belongs to the library, not consumer code)
|
|
87
|
+
- ❌ BEM (`__element` / `--modifier`) — see [`feedback_no_bem.md`](../../README.md) project rule
|
|
88
|
+
- ❌ Hard-coded `#hex`, `1rem`, `8px` — use `m.color()`, `m.space()`, `m.radius()`
|
|
89
|
+
- ❌ Inline `style=""` for **appearance** — colour, spacing, type, borders. That defeats the cia mixin pitch, and a reader copying it learns the wrong lesson.
|
|
90
|
+
- ✅ Allowed for **structural layout-neutralising** only, where an element is required by the HTML contract but must not create a box. The canonical case is `<form method="dialog" style="display: contents">` in `dialog.md`: the form has to wrap the buttons for dialog-close to work, but it must not become a layout box. There is no token or mixin involved and no appearance is being set. `validate-recipes` warns on every inline `style=` so each one stays a conscious decision.
|
|
91
|
+
- ❌ Pseudo-code framework examples ("// import your stuff here")
|
|
92
|
+
|
|
93
|
+
## How a recipe gets rendered + consumed
|
|
94
|
+
|
|
95
|
+
- **Humans:** The cia website's `/docs/recipes/[slug]` page reads `scss/recipes/<slug>.md`, parses the markdown, renders with syntax highlighting + copy buttons. Catalog page at `/docs/recipes` lists every recipe filtered by category + complexity.
|
|
96
|
+
- **AI agents:** The MCP server exposes `list_recipes`, `get_recipe(slug)`, and `assemble_prompt({ intent: "recipe:<slug>" })`. AI reads the recipe + relevant mixin signatures and generates the consumer's component in their stack.
|
|
97
|
+
|
|
98
|
+
## Validation
|
|
99
|
+
|
|
100
|
+
`npm run validate-recipes` (US-01.1.3 in v1.0 EPIC-01) walks `scss/recipes/*.md`, checks frontmatter against the schema, asserts required H2s exist, and verifies no forbidden patterns appear. Wired into CI for v1.0.
|
|
101
|
+
|
|
102
|
+
## Template
|
|
103
|
+
|
|
104
|
+
Copy `_recipe-template.md` to `<your-slug>.md` and fill in. The template includes every required section with comments explaining what to write.
|
|
105
|
+
|
|
106
|
+
## Where to read next
|
|
107
|
+
|
|
108
|
+
- [`_recipe-template.md`](./_recipe-template.md) — copyable stub
|
|
109
|
+
- [`dialog.md`](./dialog.md) — first shipped recipe; reference example
|
|
110
|
+
- [`../../roadmap/epics/v1-0/EPIC-01-recipes-book.md`](../../roadmap/epics/v1-0/EPIC-01-recipes-book.md) — v1.0 backlog for the first 5 recipes + catalog + MCP exposure
|