canny-ui 1.0.0 → 2.0.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/dist/canny-ui.min.css +1 -1
- package/package.json +1 -1
- package/src/_utilities.scss +16 -0
- package/src/canny-ui.scss +3 -0
- package/src/components/_alerts.scss +177 -33
- package/src/components/_command-palette.scss +251 -0
- package/src/components/_datepicker.scss +511 -0
- package/src/components/_forms.scss +107 -21
- package/src/components/_navbar.scss +3 -3
- package/src/components/_sidebar.scss +56 -11
- package/src/components/_toast.scss +271 -0
- package/src/tokens/_semantic.scss +3 -1
- package/dist/canny-ui.css +0 -887
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
.cny-navbar-actions {
|
|
128
128
|
display: flex;
|
|
129
129
|
align-items: center;
|
|
130
|
-
gap:
|
|
130
|
+
gap: 6px;
|
|
131
131
|
margin-left: auto;
|
|
132
132
|
flex-shrink: 0;
|
|
133
133
|
}
|
|
@@ -135,8 +135,8 @@
|
|
|
135
135
|
.cny-navbar-divider {
|
|
136
136
|
width: 1px;
|
|
137
137
|
height: 20px;
|
|
138
|
-
background: var(--hairline-color);
|
|
139
|
-
margin: 0
|
|
138
|
+
background: linear-gradient(180deg, transparent, var(--hairline-strong, var(--hairline-color)), transparent);
|
|
139
|
+
margin: 0 4px;
|
|
140
140
|
flex-shrink: 0;
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
.cny-sidebar-section {
|
|
34
|
-
margin-bottom: $space-
|
|
34
|
+
margin-bottom: $space-5;
|
|
35
35
|
|
|
36
36
|
&:last-child {
|
|
37
37
|
margin-bottom: 0;
|
|
@@ -39,13 +39,26 @@
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
.cny-sidebar-title {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 8px;
|
|
42
45
|
font-size: 0.6875rem;
|
|
43
46
|
font-weight: 650;
|
|
44
|
-
letter-spacing: 0.
|
|
47
|
+
letter-spacing: 0.1em;
|
|
45
48
|
text-transform: uppercase;
|
|
46
49
|
color: var(--text-muted);
|
|
47
|
-
padding: 0
|
|
48
|
-
margin: 0 0
|
|
50
|
+
padding: 0 10px;
|
|
51
|
+
margin: 0 0 10px;
|
|
52
|
+
|
|
53
|
+
&::before {
|
|
54
|
+
content: '';
|
|
55
|
+
width: 3px;
|
|
56
|
+
height: 3px;
|
|
57
|
+
border-radius: 50%;
|
|
58
|
+
background: currentColor;
|
|
59
|
+
opacity: 0.55;
|
|
60
|
+
flex-shrink: 0;
|
|
61
|
+
}
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
.cny-sidebar-nav {
|
|
@@ -58,34 +71,44 @@
|
|
|
58
71
|
display: flex;
|
|
59
72
|
align-items: center;
|
|
60
73
|
gap: $space-2;
|
|
61
|
-
padding:
|
|
74
|
+
padding: 7px 10px;
|
|
62
75
|
border-radius: var(--radius-sm);
|
|
63
|
-
font-size: 0.
|
|
76
|
+
font-size: 0.8125rem;
|
|
64
77
|
color: var(--text-secondary);
|
|
65
78
|
text-decoration: none;
|
|
66
79
|
position: relative;
|
|
67
|
-
transition:
|
|
80
|
+
transition:
|
|
81
|
+
background-color 160ms ease,
|
|
82
|
+
color 160ms ease,
|
|
83
|
+
transform 160ms ease;
|
|
68
84
|
|
|
69
85
|
&:hover {
|
|
70
86
|
background: var(--bg-surface-low);
|
|
71
87
|
color: var(--text-primary);
|
|
72
88
|
}
|
|
73
89
|
|
|
90
|
+
&:active { transform: translateX(0.5px); }
|
|
91
|
+
|
|
74
92
|
&.active {
|
|
75
93
|
color: var(--color-primary);
|
|
76
94
|
font-weight: 550;
|
|
77
|
-
background:
|
|
95
|
+
background: linear-gradient(
|
|
96
|
+
90deg,
|
|
97
|
+
color-mix(in srgb, var(--color-primary) 13%, transparent),
|
|
98
|
+
color-mix(in srgb, var(--color-primary) 4%, transparent)
|
|
99
|
+
);
|
|
78
100
|
|
|
79
101
|
&::before {
|
|
80
102
|
content: '';
|
|
81
103
|
position: absolute;
|
|
82
|
-
left:
|
|
104
|
+
left: 0;
|
|
83
105
|
top: 50%;
|
|
84
106
|
transform: translateY(-50%);
|
|
85
|
-
width:
|
|
86
|
-
height:
|
|
107
|
+
width: 3px;
|
|
108
|
+
height: 14px;
|
|
87
109
|
background: var(--color-primary);
|
|
88
110
|
border-radius: 0 2px 2px 0;
|
|
111
|
+
box-shadow: 0 0 8px color-mix(in srgb, var(--color-primary) 50%, transparent);
|
|
89
112
|
}
|
|
90
113
|
}
|
|
91
114
|
|
|
@@ -104,6 +127,28 @@
|
|
|
104
127
|
|
|
105
128
|
.cny-sidebar-item-badge {
|
|
106
129
|
margin-left: auto;
|
|
130
|
+
font-size: 9.5px;
|
|
131
|
+
font-weight: 700;
|
|
132
|
+
letter-spacing: 0.04em;
|
|
133
|
+
padding: 1px 6px;
|
|
134
|
+
line-height: 1.4;
|
|
135
|
+
text-transform: lowercase;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Themed scrollbar for sidebar content
|
|
140
|
+
.cny-sidebar {
|
|
141
|
+
scrollbar-width: thin;
|
|
142
|
+
scrollbar-color: var(--border-color) transparent;
|
|
143
|
+
|
|
144
|
+
&::-webkit-scrollbar { width: 6px; }
|
|
145
|
+
&::-webkit-scrollbar-track { background: transparent; }
|
|
146
|
+
&::-webkit-scrollbar-thumb {
|
|
147
|
+
background: var(--border-color);
|
|
148
|
+
border-radius: 3px;
|
|
149
|
+
}
|
|
150
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
151
|
+
background: var(--border-color-strong);
|
|
107
152
|
}
|
|
108
153
|
}
|
|
109
154
|
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
@use '../tokens/primitives' as *;
|
|
2
|
+
|
|
3
|
+
// Toast / Snackbar — clean white card with a wavy SVG decoration peeking
|
|
4
|
+
// from the left edge in the variant accent color. Body stays neutral
|
|
5
|
+
// for readability; variant signal lives in the wave + icon chip + title.
|
|
6
|
+
|
|
7
|
+
@keyframes cny-toast-in-right {
|
|
8
|
+
from { opacity: 0; transform: translate(8px, 0); }
|
|
9
|
+
to { opacity: 1; transform: translate(0, 0); }
|
|
10
|
+
}
|
|
11
|
+
@keyframes cny-toast-in-left {
|
|
12
|
+
from { opacity: 0; transform: translate(-8px, 0); }
|
|
13
|
+
to { opacity: 1; transform: translate(0, 0); }
|
|
14
|
+
}
|
|
15
|
+
@keyframes cny-toast-in-top {
|
|
16
|
+
from { opacity: 0; transform: translate(0, -8px); }
|
|
17
|
+
to { opacity: 1; transform: translate(0, 0); }
|
|
18
|
+
}
|
|
19
|
+
@keyframes cny-toast-in-bottom {
|
|
20
|
+
from { opacity: 0; transform: translate(0, 10px) scale(0.985); }
|
|
21
|
+
to { opacity: 1; transform: translate(0, 0) scale(1); }
|
|
22
|
+
}
|
|
23
|
+
@keyframes cny-toast-out {
|
|
24
|
+
from { opacity: 1; transform: translate(0, 0); }
|
|
25
|
+
to { opacity: 0; transform: translate(0, -6px) scale(0.97); }
|
|
26
|
+
}
|
|
27
|
+
@keyframes cny-toast-spin {
|
|
28
|
+
to { transform: rotate(360deg); }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── Viewport ────────────────────────────────────────────────────
|
|
32
|
+
.cny-toast-viewport {
|
|
33
|
+
--cny-toast-offset: 1rem;
|
|
34
|
+
position: fixed;
|
|
35
|
+
z-index: 1100;
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
gap: 12px;
|
|
39
|
+
padding: 0;
|
|
40
|
+
margin: 0;
|
|
41
|
+
list-style: none;
|
|
42
|
+
pointer-events: none;
|
|
43
|
+
width: min(360px, calc(100vw - var(--cny-toast-offset) * 2));
|
|
44
|
+
|
|
45
|
+
> * { pointer-events: auto; }
|
|
46
|
+
|
|
47
|
+
&.pos-bottom-right { right: var(--cny-toast-offset); bottom: var(--cny-toast-offset); align-items: flex-end; }
|
|
48
|
+
&.pos-bottom-left { left: var(--cny-toast-offset); bottom: var(--cny-toast-offset); align-items: flex-start; }
|
|
49
|
+
&.pos-bottom-center {
|
|
50
|
+
left: 50%; bottom: var(--cny-toast-offset);
|
|
51
|
+
transform: translateX(-50%); align-items: center;
|
|
52
|
+
}
|
|
53
|
+
&.pos-top-right { right: var(--cny-toast-offset); top: var(--cny-toast-offset); align-items: flex-end; }
|
|
54
|
+
&.pos-top-left { left: var(--cny-toast-offset); top: var(--cny-toast-offset); align-items: flex-start; }
|
|
55
|
+
&.pos-top-center {
|
|
56
|
+
left: 50%; top: var(--cny-toast-offset);
|
|
57
|
+
transform: translateX(-50%); align-items: center;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Toast surface — flat white card ─────────────────────────────
|
|
62
|
+
.cny-toast {
|
|
63
|
+
--toast-accent: var(--color-primary);
|
|
64
|
+
|
|
65
|
+
position: relative;
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 14px;
|
|
69
|
+
width: min(360px, 100%);
|
|
70
|
+
// 80 px = one full wave cycle. Tall toasts repeat the wave, so this is
|
|
71
|
+
// a floor, not a clamp.
|
|
72
|
+
min-height: 80px;
|
|
73
|
+
padding: 14px 16px 14px 28px; // extra left to clear the tiled wave
|
|
74
|
+
background: var(--bg-surface-lowest);
|
|
75
|
+
color: var(--text-primary);
|
|
76
|
+
border: 1px solid color-mix(in srgb, var(--border-color) 60%, transparent);
|
|
77
|
+
border-radius: 10px;
|
|
78
|
+
box-shadow:
|
|
79
|
+
0 1px 2px rgba(15, 23, 42, 0.04),
|
|
80
|
+
0 8px 24px rgba(149, 157, 165, 0.18);
|
|
81
|
+
font-family: var(--font-body);
|
|
82
|
+
font-size: 0.875rem;
|
|
83
|
+
line-height: 1.5;
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
pointer-events: auto;
|
|
86
|
+
transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
|
87
|
+
box-shadow 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
88
|
+
animation: cny-toast-in-bottom 220ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
|
89
|
+
|
|
90
|
+
&:hover {
|
|
91
|
+
transform: translateY(-2px);
|
|
92
|
+
box-shadow:
|
|
93
|
+
0 1px 2px rgba(15, 23, 42, 0.04),
|
|
94
|
+
0 14px 32px rgba(149, 157, 165, 0.24);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Direction-aware entrance
|
|
98
|
+
.cny-toast-viewport.pos-bottom-right &,
|
|
99
|
+
.cny-toast-viewport.pos-top-right & { animation-name: cny-toast-in-right; }
|
|
100
|
+
.cny-toast-viewport.pos-bottom-left &,
|
|
101
|
+
.cny-toast-viewport.pos-top-left & { animation-name: cny-toast-in-left; }
|
|
102
|
+
.cny-toast-viewport.pos-top-center &,
|
|
103
|
+
.cny-toast-viewport.pos-top-right &,
|
|
104
|
+
.cny-toast-viewport.pos-top-left & { animation-name: cny-toast-in-top; }
|
|
105
|
+
|
|
106
|
+
&.is-exiting {
|
|
107
|
+
animation: cny-toast-out 200ms cubic-bezier(0.4, 0, 1, 1) both;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@media (prefers-reduced-motion: reduce) {
|
|
111
|
+
animation: none;
|
|
112
|
+
&.is-exiting { animation: none; opacity: 0; }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ── Variants — only --toast-accent shifts ──
|
|
116
|
+
&.success { --toast-accent: var(--color-success); }
|
|
117
|
+
&.info { --toast-accent: var(--color-info); }
|
|
118
|
+
&.warning { --toast-accent: var(--color-warning); }
|
|
119
|
+
&.danger { --toast-accent: var(--color-danger); }
|
|
120
|
+
&.loading { --toast-accent: var(--color-primary); }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ── Wave decoration on the left edge ─────────────────────────────
|
|
124
|
+
// Seamless vertical tile: full width at y=0 and y=80, single cubic dip in
|
|
125
|
+
// the middle. Both tile boundaries match at the right edge (x=80) so
|
|
126
|
+
// repeat-y has no discontinuity even on tall toasts. Path is filled (left
|
|
127
|
+
// half) for the colored strip, with the wave shape forming the inner edge.
|
|
128
|
+
.cny-toast::before {
|
|
129
|
+
content: '';
|
|
130
|
+
position: absolute;
|
|
131
|
+
left: 0;
|
|
132
|
+
top: 0;
|
|
133
|
+
bottom: 0;
|
|
134
|
+
width: 18px;
|
|
135
|
+
background-color: color-mix(in srgb, var(--toast-accent) 23%, transparent);
|
|
136
|
+
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80' preserveAspectRatio='none'><path d='M0,0 L80,0 C20,20 20,60 80,80 L0,80 Z'/></svg>");
|
|
137
|
+
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80' preserveAspectRatio='none'><path d='M0,0 L80,0 C20,20 20,60 80,80 L0,80 Z'/></svg>");
|
|
138
|
+
mask-repeat: repeat-y;
|
|
139
|
+
-webkit-mask-repeat: repeat-y;
|
|
140
|
+
mask-size: 18px 80px;
|
|
141
|
+
-webkit-mask-size: 18px 80px;
|
|
142
|
+
pointer-events: none;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── Icon chip — circular, filled tonal ──
|
|
146
|
+
.cny-toast-icon {
|
|
147
|
+
flex: none;
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
width: 36px;
|
|
152
|
+
height: 36px;
|
|
153
|
+
border-radius: 50%;
|
|
154
|
+
background: color-mix(in srgb, var(--toast-accent) 26%, transparent);
|
|
155
|
+
color: var(--toast-accent);
|
|
156
|
+
position: relative;
|
|
157
|
+
z-index: 1;
|
|
158
|
+
|
|
159
|
+
> svg {
|
|
160
|
+
width: 18px;
|
|
161
|
+
height: 18px;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.cny-toast-spin { animation: cny-toast-spin 1s linear infinite; }
|
|
166
|
+
@media (prefers-reduced-motion: reduce) { .cny-toast-spin { animation: none; } }
|
|
167
|
+
|
|
168
|
+
// ── Body ───────────────────────────────────────────────────────
|
|
169
|
+
.cny-toast-body {
|
|
170
|
+
flex: 1 1 auto;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
display: flex;
|
|
173
|
+
flex-direction: column;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
align-items: center;
|
|
176
|
+
text-align: center;
|
|
177
|
+
position: relative;
|
|
178
|
+
z-index: 1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.cny-toast-title {
|
|
182
|
+
font-weight: 700;
|
|
183
|
+
letter-spacing: -0.01em;
|
|
184
|
+
line-height: 1.25;
|
|
185
|
+
margin: 0;
|
|
186
|
+
color: var(--toast-accent);
|
|
187
|
+
font-size: 16px;
|
|
188
|
+
text-align: center;
|
|
189
|
+
cursor: default;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.cny-toast-description {
|
|
193
|
+
margin: 4px 0 0;
|
|
194
|
+
color: var(--text-muted);
|
|
195
|
+
font-size: 13.5px;
|
|
196
|
+
line-height: 1.45;
|
|
197
|
+
text-align: center;
|
|
198
|
+
cursor: default;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── Action slot ────────────────────────────────────────────────
|
|
202
|
+
.cny-toast-action {
|
|
203
|
+
flex: none;
|
|
204
|
+
display: inline-flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
align-self: center;
|
|
207
|
+
position: relative;
|
|
208
|
+
z-index: 1;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ── Close button ───────────────────────────────────────────────
|
|
212
|
+
.cny-toast-close {
|
|
213
|
+
flex: none;
|
|
214
|
+
display: inline-flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: center;
|
|
217
|
+
width: 26px;
|
|
218
|
+
height: 26px;
|
|
219
|
+
padding: 0;
|
|
220
|
+
background: transparent;
|
|
221
|
+
border: 0;
|
|
222
|
+
color: var(--text-muted);
|
|
223
|
+
cursor: pointer;
|
|
224
|
+
border-radius: var(--radius-sm);
|
|
225
|
+
transition: color 140ms ease, background-color 140ms ease, transform 140ms ease;
|
|
226
|
+
position: relative;
|
|
227
|
+
z-index: 1;
|
|
228
|
+
|
|
229
|
+
> svg { width: 16px; height: 16px; }
|
|
230
|
+
|
|
231
|
+
&:hover {
|
|
232
|
+
color: var(--text-primary);
|
|
233
|
+
background: color-mix(in srgb, var(--toast-accent) 8%, var(--bg-surface-low));
|
|
234
|
+
transform: scale(1.04);
|
|
235
|
+
}
|
|
236
|
+
&:active {
|
|
237
|
+
transform: scale(0.96);
|
|
238
|
+
}
|
|
239
|
+
&:focus-visible {
|
|
240
|
+
outline: 2px solid var(--toast-accent);
|
|
241
|
+
outline-offset: 2px;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── Mobile ─────────────────────────────────────────────────────
|
|
246
|
+
@media (max-width: 480px) {
|
|
247
|
+
.cny-toast-viewport {
|
|
248
|
+
--cny-toast-offset: 12px;
|
|
249
|
+
width: calc(100vw - var(--cny-toast-offset) * 2);
|
|
250
|
+
}
|
|
251
|
+
.cny-toast {
|
|
252
|
+
width: 100%;
|
|
253
|
+
min-height: 64px;
|
|
254
|
+
padding: 12px 14px 12px 26px;
|
|
255
|
+
gap: 12px;
|
|
256
|
+
border-radius: 9px;
|
|
257
|
+
}
|
|
258
|
+
.cny-toast::before {
|
|
259
|
+
width: 14px;
|
|
260
|
+
mask-size: 14px 64px;
|
|
261
|
+
-webkit-mask-size: 14px 64px;
|
|
262
|
+
}
|
|
263
|
+
.cny-toast-icon {
|
|
264
|
+
width: 32px;
|
|
265
|
+
height: 32px;
|
|
266
|
+
> svg { width: 16px; height: 16px; }
|
|
267
|
+
}
|
|
268
|
+
.cny-toast-title { font-size: 15px; }
|
|
269
|
+
.cny-toast-description { font-size: 12.5px; }
|
|
270
|
+
.cny-toast-close { width: 24px; height: 24px; > svg { width: 14px; height: 14px; } }
|
|
271
|
+
}
|
|
@@ -112,8 +112,10 @@
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
// ── Dark theme ──────────────────────────────────────────────────────────
|
|
115
|
+
// Auto-dark when the OS prefers dark, UNLESS .cny-light is explicitly set.
|
|
116
|
+
// Manual toggle classes (.cny-dark / .cny-light) always win over system preference.
|
|
115
117
|
@media (prefers-color-scheme: dark) {
|
|
116
|
-
:root {
|
|
118
|
+
:root:not(.cny-light) {
|
|
117
119
|
--bg-base: #{$zinc-950};
|
|
118
120
|
--bg-surface-low: #{$zinc-900};
|
|
119
121
|
--bg-surface-lowest: #{$zinc-800};
|