@vadem/ui 0.1.0 → 0.2.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.
@@ -0,0 +1,604 @@
1
+ /* Schedule - spec: specs/schedule.md */
2
+ @layer vd.components {
3
+ .vd-schedule {
4
+ --vd-schedule-gap: var(--vd-space-3);
5
+ --vd-schedule-border: var(--vd-color-border);
6
+ --vd-schedule-bg: var(--vd-color-surface);
7
+ --vd-schedule-muted: var(--vd-color-text-muted);
8
+ --vd-schedule-radius: var(--vd-radius-surface);
9
+ --vd-schedule-cell-height: 7rem;
10
+ --vd-schedule-hour-height: 3rem;
11
+ --vd-schedule-gutter: 3.5rem;
12
+ --vd-schedule-max-height: 36rem;
13
+ --vd-schedule-agenda-time: 9rem;
14
+ --vd-schedule-now-size: var(--vd-space-0-5);
15
+ --vd-schedule-event-radius: var(--vd-radius-sm);
16
+ --vd-schedule-today-bg: var(--vd-color-action);
17
+ --vd-schedule-today-fg: var(--vd-color-on-action);
18
+ --vd-schedule-now: var(--vd-color-danger);
19
+ --vd-schedule-marker: var(--vd-color-focus);
20
+
21
+ display: grid;
22
+ gap: var(--vd-schedule-gap);
23
+ min-inline-size: 0;
24
+ color: var(--vd-color-text);
25
+ container-type: inline-size;
26
+ }
27
+
28
+ /* ------------------------------------------------------------- toolbar */
29
+
30
+ .vd-schedule__toolbar {
31
+ display: flex;
32
+ flex-wrap: wrap;
33
+ align-items: center;
34
+ justify-content: space-between;
35
+ gap: var(--vd-space-2) var(--vd-space-4);
36
+ }
37
+
38
+ .vd-schedule__nav,
39
+ .vd-schedule__views {
40
+ display: flex;
41
+ flex-wrap: wrap;
42
+ align-items: center;
43
+ gap: var(--vd-space-1);
44
+ }
45
+
46
+ .vd-schedule__title {
47
+ margin: 0;
48
+ margin-inline-start: var(--vd-space-2);
49
+ font-size: var(--vd-text-lg);
50
+ font-weight: var(--vd-weight-semibold);
51
+ }
52
+
53
+ .vd-schedule__title::first-letter {
54
+ text-transform: uppercase;
55
+ }
56
+
57
+ /* ---------------------------------------------------------- event chips */
58
+
59
+ .vd-schedule__event,
60
+ .vd-schedule__block,
61
+ .vd-schedule__agenda-event {
62
+ --vd-schedule-event-bg: var(--vd-color-action-subtle);
63
+ --vd-schedule-event-fg: var(--vd-color-text);
64
+ --vd-schedule-event-edge: var(--vd-color-action);
65
+ }
66
+
67
+ [data-color='success'] {
68
+ --vd-schedule-event-bg: var(--vd-color-success-subtle);
69
+ --vd-schedule-event-edge: var(--vd-color-success);
70
+ }
71
+ [data-color='warning'] {
72
+ --vd-schedule-event-bg: var(--vd-color-warning-subtle);
73
+ --vd-schedule-event-edge: var(--vd-color-warning);
74
+ }
75
+ [data-color='danger'] {
76
+ --vd-schedule-event-bg: var(--vd-color-danger-subtle);
77
+ --vd-schedule-event-edge: var(--vd-color-danger);
78
+ }
79
+ [data-color='info'] {
80
+ --vd-schedule-event-bg: var(--vd-color-info-subtle);
81
+ --vd-schedule-event-edge: var(--vd-color-info);
82
+ }
83
+ [data-color='neutral'] {
84
+ --vd-schedule-event-bg: var(--vd-color-surface-raised);
85
+ --vd-schedule-event-edge: var(--vd-color-border-strong);
86
+ }
87
+
88
+ .vd-schedule__event,
89
+ .vd-schedule__block {
90
+ display: flex;
91
+ gap: var(--vd-space-1);
92
+ min-inline-size: 0;
93
+ margin: 0;
94
+ padding: var(--vd-space-1) var(--vd-space-2);
95
+ border: 0;
96
+ border-inline-start: var(--vd-space-1) solid var(--vd-schedule-event-edge);
97
+ border-radius: var(--vd-schedule-event-radius);
98
+ background: var(--vd-schedule-event-bg);
99
+ color: var(--vd-schedule-event-fg);
100
+ font: inherit;
101
+ font-size: var(--vd-text-xs);
102
+ line-height: var(--vd-leading-snug);
103
+ text-align: start;
104
+ cursor: pointer;
105
+ }
106
+
107
+ .vd-schedule__event {
108
+ inline-size: 100%;
109
+ align-items: baseline;
110
+ white-space: nowrap;
111
+ }
112
+
113
+ .vd-schedule__event .vd-schedule__name {
114
+ overflow: hidden;
115
+ text-overflow: ellipsis;
116
+ }
117
+
118
+ .vd-schedule__time {
119
+ color: var(--vd-schedule-muted);
120
+ font-variant-numeric: tabular-nums;
121
+ }
122
+
123
+ .vd-schedule__name {
124
+ min-inline-size: 0;
125
+ font-weight: var(--vd-weight-medium);
126
+ }
127
+
128
+ @media (hover: hover) {
129
+ .vd-schedule__event:hover,
130
+ .vd-schedule__block:hover,
131
+ .vd-schedule__agenda-event:hover {
132
+ background: color-mix(
133
+ in oklch,
134
+ var(--vd-schedule-event-bg),
135
+ var(--vd-schedule-event-edge) 14%
136
+ );
137
+ }
138
+ }
139
+
140
+ .vd-schedule button:focus-visible {
141
+ outline: var(--vd-focus-ring-width) solid var(--vd-color-focus);
142
+ outline-offset: var(--vd-focus-ring-offset);
143
+ }
144
+
145
+ [data-dragging].vd-schedule__event,
146
+ [data-dragging].vd-schedule__block {
147
+ opacity: var(--vd-opacity-disabled);
148
+ }
149
+
150
+ .vd-schedule[data-state='dragging'] {
151
+ cursor: grabbing;
152
+ }
153
+
154
+ /* ---------------------------------------------------------------- month */
155
+
156
+ .vd-schedule__month {
157
+ inline-size: 100%;
158
+ table-layout: fixed;
159
+ border-collapse: separate;
160
+ border-spacing: 0;
161
+ border: var(--vd-border-width) solid var(--vd-schedule-border);
162
+ border-radius: var(--vd-schedule-radius);
163
+ background: var(--vd-schedule-bg);
164
+ overflow: hidden;
165
+ }
166
+
167
+ .vd-schedule__month th {
168
+ padding: var(--vd-space-2);
169
+ border-block-end: var(--vd-border-width) solid var(--vd-schedule-border);
170
+ color: var(--vd-schedule-muted);
171
+ font-family: var(--vd-font-mono);
172
+ font-size: var(--vd-text-xs);
173
+ font-weight: var(--vd-weight-medium);
174
+ letter-spacing: var(--vd-tracking-caps);
175
+ text-align: start;
176
+ text-transform: uppercase;
177
+ }
178
+
179
+ .vd-schedule__month abbr {
180
+ text-decoration: none;
181
+ }
182
+
183
+ .vd-schedule__cell {
184
+ min-inline-size: 0;
185
+ overflow: hidden;
186
+ block-size: var(--vd-schedule-cell-height);
187
+ padding: var(--vd-space-1);
188
+ border-block-end: var(--vd-border-width) solid var(--vd-schedule-border);
189
+ border-inline-end: var(--vd-border-width) solid var(--vd-schedule-border);
190
+ vertical-align: top;
191
+ }
192
+
193
+ .vd-schedule__month tr > .vd-schedule__cell:last-child {
194
+ border-inline-end: 0;
195
+ }
196
+
197
+ .vd-schedule__month tbody tr:last-child > .vd-schedule__cell {
198
+ border-block-end: 0;
199
+ }
200
+
201
+ .vd-schedule__cell[data-outside] {
202
+ background: var(--vd-color-surface-sunken);
203
+ }
204
+
205
+ .vd-schedule__cell[data-outside] .vd-schedule__day {
206
+ color: var(--vd-schedule-muted);
207
+ }
208
+
209
+ .vd-schedule__cell[data-drop-target],
210
+ .vd-schedule__allday-cell[data-drop-target] {
211
+ outline: var(--vd-focus-ring-width) solid var(--vd-schedule-marker);
212
+ outline-offset: calc(-1 * var(--vd-focus-ring-width));
213
+ }
214
+
215
+ .vd-schedule__day {
216
+ display: inline-grid;
217
+ place-items: center;
218
+ min-inline-size: var(--vd-control-height-sm);
219
+ block-size: var(--vd-control-height-sm);
220
+ margin: 0;
221
+ padding-inline: var(--vd-space-1);
222
+ border: 0;
223
+ border-radius: var(--vd-radius-pill);
224
+ background: transparent;
225
+ color: inherit;
226
+ font: inherit;
227
+ font-size: var(--vd-text-sm);
228
+ font-variant-numeric: tabular-nums;
229
+ cursor: pointer;
230
+ }
231
+
232
+ @media (hover: hover) {
233
+ .vd-schedule__day:hover {
234
+ background: var(--vd-color-action-subtle);
235
+ }
236
+ }
237
+
238
+ .vd-schedule__day[aria-current='date'] {
239
+ background: var(--vd-schedule-today-bg);
240
+ color: var(--vd-schedule-today-fg);
241
+ font-weight: var(--vd-weight-semibold);
242
+ }
243
+
244
+ .vd-schedule__chips {
245
+ display: grid;
246
+ /* Chips shrink to the cell: long titles end with an ellipsis, never spill into the next day. */
247
+ grid-template-columns: minmax(0, 1fr);
248
+ gap: var(--vd-space-0-5);
249
+ margin: var(--vd-space-1) 0 0;
250
+ padding: 0;
251
+ list-style: none;
252
+ }
253
+
254
+ .vd-schedule__more {
255
+ margin: 0;
256
+ padding: 0 var(--vd-space-2);
257
+ border: 0;
258
+ background: transparent;
259
+ color: var(--vd-schedule-muted);
260
+ font: inherit;
261
+ font-size: var(--vd-text-xs);
262
+ font-weight: var(--vd-weight-medium);
263
+ cursor: pointer;
264
+ }
265
+
266
+ @media (hover: hover) {
267
+ .vd-schedule__more:hover {
268
+ color: var(--vd-color-text);
269
+ text-decoration: underline;
270
+ }
271
+ }
272
+
273
+ /* ---------------------------------------------------------------- agenda */
274
+
275
+ .vd-schedule__agenda {
276
+ display: grid;
277
+ gap: var(--vd-space-4);
278
+ }
279
+
280
+ .vd-schedule__agenda-day {
281
+ display: grid;
282
+ gap: var(--vd-space-2);
283
+ }
284
+
285
+ .vd-schedule__agenda-date {
286
+ margin: 0;
287
+ padding-block-end: var(--vd-space-1);
288
+ border-block-end: var(--vd-border-width) solid var(--vd-schedule-border);
289
+ font-weight: var(--vd-weight-semibold);
290
+ }
291
+
292
+ .vd-schedule__agenda-date[data-today] {
293
+ color: var(--vd-color-text-accent);
294
+ }
295
+
296
+ .vd-schedule__agenda-list {
297
+ display: grid;
298
+ gap: var(--vd-space-1);
299
+ margin: 0;
300
+ padding: 0;
301
+ list-style: none;
302
+ }
303
+
304
+ .vd-schedule__agenda-event {
305
+ display: grid;
306
+ grid-template-columns: var(--vd-schedule-agenda-time) minmax(0, 1fr);
307
+ gap: var(--vd-space-3);
308
+ inline-size: 100%;
309
+ margin: 0;
310
+ padding: var(--vd-space-2) var(--vd-space-3);
311
+ border: 0;
312
+ border-inline-start: var(--vd-space-1) solid var(--vd-schedule-event-edge);
313
+ border-radius: var(--vd-schedule-event-radius);
314
+ background: var(--vd-schedule-event-bg);
315
+ color: inherit;
316
+ font: inherit;
317
+ text-align: start;
318
+ cursor: pointer;
319
+ }
320
+
321
+ .vd-schedule__agenda-time {
322
+ color: var(--vd-schedule-muted);
323
+ font-size: var(--vd-text-sm);
324
+ font-variant-numeric: tabular-nums;
325
+ }
326
+
327
+ .vd-schedule__agenda-event .vd-schedule__name {
328
+ overflow-wrap: anywhere;
329
+ }
330
+
331
+ .vd-schedule__empty,
332
+ .vd-schedule__invalid {
333
+ margin: 0;
334
+ padding: var(--vd-space-6);
335
+ border: var(--vd-border-width) dashed var(--vd-schedule-border);
336
+ border-radius: var(--vd-schedule-radius);
337
+ color: var(--vd-schedule-muted);
338
+ text-align: center;
339
+ }
340
+
341
+ /* ------------------------------------------------------------ time grid */
342
+
343
+ .vd-schedule__timegrid {
344
+ --vd-schedule-columns: var(--vd-schedule-gutter) repeat(var(--vd-schedule-days), minmax(0, 1fr));
345
+ border: var(--vd-border-width) solid var(--vd-schedule-border);
346
+ border-radius: var(--vd-schedule-radius);
347
+ background: var(--vd-schedule-bg);
348
+ overflow: hidden;
349
+ }
350
+
351
+ .vd-schedule__head,
352
+ .vd-schedule__allday,
353
+ .vd-schedule__grid {
354
+ display: grid;
355
+ grid-template-columns: var(--vd-schedule-columns);
356
+ }
357
+
358
+ .vd-schedule__colhead {
359
+ display: grid;
360
+ justify-items: center;
361
+ margin: 0;
362
+ padding: var(--vd-space-2) var(--vd-space-1);
363
+ border: 0;
364
+ border-inline-start: var(--vd-border-width) solid var(--vd-schedule-border);
365
+ background: transparent;
366
+ color: inherit;
367
+ font: inherit;
368
+ cursor: pointer;
369
+ }
370
+
371
+ @media (hover: hover) {
372
+ .vd-schedule__colhead:hover {
373
+ background: var(--vd-color-action-subtle);
374
+ }
375
+ }
376
+
377
+ .vd-schedule__weekday {
378
+ color: var(--vd-schedule-muted);
379
+ font-family: var(--vd-font-mono);
380
+ font-size: var(--vd-text-xs);
381
+ letter-spacing: var(--vd-tracking-caps);
382
+ text-transform: uppercase;
383
+ }
384
+
385
+ .vd-schedule__date {
386
+ font-size: var(--vd-text-lg);
387
+ font-weight: var(--vd-weight-semibold);
388
+ font-variant-numeric: tabular-nums;
389
+ }
390
+
391
+ .vd-schedule__colhead[data-today] .vd-schedule__date {
392
+ color: var(--vd-color-text-accent);
393
+ }
394
+
395
+ .vd-schedule__allday {
396
+ border-block: var(--vd-border-width) solid var(--vd-schedule-border);
397
+ }
398
+
399
+ .vd-schedule__allday-label {
400
+ align-self: center;
401
+ padding-inline: var(--vd-space-1);
402
+ color: var(--vd-schedule-muted);
403
+ font-size: var(--vd-text-xs);
404
+ text-align: end;
405
+ }
406
+
407
+ .vd-schedule__allday-cell {
408
+ display: grid;
409
+ align-content: start;
410
+ gap: var(--vd-space-0-5);
411
+ min-block-size: var(--vd-control-height-md);
412
+ padding: var(--vd-space-1);
413
+ border-inline-start: var(--vd-border-width) solid var(--vd-schedule-border);
414
+ }
415
+
416
+ .vd-schedule__scroll {
417
+ max-block-size: var(--vd-schedule-max-height);
418
+ overflow-y: auto;
419
+ overscroll-behavior: contain;
420
+ }
421
+
422
+ .vd-schedule__grid {
423
+ position: relative;
424
+ block-size: calc(var(--vd-schedule-hours) * var(--vd-schedule-hour-height));
425
+ }
426
+
427
+ .vd-schedule__hours {
428
+ display: grid;
429
+ grid-auto-rows: var(--vd-schedule-hour-height);
430
+ }
431
+
432
+ .vd-schedule__hour {
433
+ padding-inline: var(--vd-space-1);
434
+ color: var(--vd-schedule-muted);
435
+ font-size: var(--vd-text-xs);
436
+ font-variant-numeric: tabular-nums;
437
+ text-align: end;
438
+ translate: 0 calc(-0.5lh);
439
+ }
440
+
441
+ .vd-schedule__hour:first-child {
442
+ translate: none;
443
+ }
444
+
445
+ .vd-schedule__column {
446
+ position: relative;
447
+ border-inline-start: var(--vd-border-width) solid var(--vd-schedule-border);
448
+ /* Hour lines and fainter half-hour lines. */
449
+ background-image:
450
+ linear-gradient(var(--vd-schedule-border) var(--vd-border-width), transparent 0),
451
+ linear-gradient(
452
+ color-mix(in oklch, var(--vd-schedule-border) 45%, transparent) var(--vd-border-width),
453
+ transparent 0
454
+ );
455
+ background-size:
456
+ 100% var(--vd-schedule-hour-height),
457
+ 100% calc(var(--vd-schedule-hour-height) / 2);
458
+ }
459
+
460
+ .vd-schedule__column[data-today] {
461
+ background-color: color-mix(in oklch, var(--vd-color-action-subtle) 35%, transparent);
462
+ }
463
+
464
+ .vd-schedule__block {
465
+ position: absolute;
466
+ inset-block-start: calc(var(--vd-schedule-top) * var(--vd-schedule-hour-height) / 60);
467
+ inset-inline-start: calc(100% * var(--vd-schedule-col) / var(--vd-schedule-cols));
468
+ inline-size: calc(100% / var(--vd-schedule-cols) - var(--vd-space-0-5));
469
+ block-size: calc(
470
+ var(--vd-schedule-span) * var(--vd-schedule-hour-height) / 60 - var(--vd-space-0-5)
471
+ );
472
+ flex-direction: column;
473
+ overflow: hidden;
474
+ box-shadow: var(--vd-shadow-sm);
475
+ }
476
+
477
+ .vd-schedule__block[data-short] {
478
+ white-space: nowrap;
479
+ }
480
+
481
+ .vd-schedule__block[data-short] .vd-schedule__name {
482
+ overflow: hidden;
483
+ text-overflow: ellipsis;
484
+ }
485
+
486
+ .vd-schedule__block[data-short] .vd-schedule__time {
487
+ display: none;
488
+ }
489
+
490
+ .vd-schedule__block[data-clipped-start] {
491
+ border-start-start-radius: 0;
492
+ border-start-end-radius: 0;
493
+ }
494
+
495
+ .vd-schedule__block[data-clipped-end] {
496
+ border-end-start-radius: 0;
497
+ border-end-end-radius: 0;
498
+ }
499
+
500
+ .vd-schedule__block .vd-schedule__name {
501
+ overflow-wrap: break-word;
502
+ hyphens: auto;
503
+ }
504
+
505
+ .vd-schedule__resize {
506
+ position: absolute;
507
+ inset-inline: 0;
508
+ inset-block-end: 0;
509
+ block-size: var(--vd-space-2);
510
+ cursor: ns-resize;
511
+ }
512
+
513
+ .vd-schedule__preview {
514
+ position: absolute;
515
+ inset-inline: 0;
516
+ inset-block-start: calc(var(--vd-schedule-top) * var(--vd-schedule-hour-height) / 60);
517
+ block-size: calc(var(--vd-schedule-span) * var(--vd-schedule-hour-height) / 60);
518
+ padding: var(--vd-space-1) var(--vd-space-2);
519
+ border: var(--vd-focus-ring-width) dashed var(--vd-schedule-marker);
520
+ border-radius: var(--vd-schedule-event-radius);
521
+ color: var(--vd-schedule-marker);
522
+ font-size: var(--vd-text-xs);
523
+ font-variant-numeric: tabular-nums;
524
+ pointer-events: none;
525
+ }
526
+
527
+ .vd-schedule__now {
528
+ position: absolute;
529
+ inset-inline: 0;
530
+ inset-block-start: calc(var(--vd-schedule-top) * var(--vd-schedule-hour-height) / 60);
531
+ block-size: var(--vd-schedule-now-size);
532
+ background: var(--vd-schedule-now);
533
+ pointer-events: none;
534
+ }
535
+
536
+ .vd-schedule__now::before {
537
+ content: '';
538
+ position: absolute;
539
+ inset-inline-start: calc(-1 * var(--vd-space-1));
540
+ inset-block-start: 50%;
541
+ inline-size: var(--vd-space-2);
542
+ block-size: var(--vd-space-2);
543
+ border-radius: var(--vd-radius-pill);
544
+ background: var(--vd-schedule-now);
545
+ translate: 0 -50%;
546
+ }
547
+
548
+ .vd-schedule__dot {
549
+ display: none;
550
+ }
551
+
552
+ /* Narrow month: days show a dot instead of unreadable chips; a day opens the day view. */
553
+ @container (width < 36rem) {
554
+ .vd-schedule__chips {
555
+ display: none;
556
+ }
557
+ .vd-schedule__cell {
558
+ block-size: auto;
559
+ text-align: center;
560
+ }
561
+ .vd-schedule__day {
562
+ position: relative;
563
+ }
564
+ .vd-schedule__dot {
565
+ display: block;
566
+ position: absolute;
567
+ inset-block-end: calc(-1 * var(--vd-space-1));
568
+ inset-inline-start: 50%;
569
+ inline-size: var(--vd-space-1);
570
+ block-size: var(--vd-space-1);
571
+ border-radius: var(--vd-radius-pill);
572
+ background: var(--vd-color-action);
573
+ /* Logical centring (translate is physical and would drift in RTL). */
574
+ margin-inline-start: calc(var(--vd-space-1) / -2);
575
+ }
576
+ .vd-schedule__day[aria-current='date'] .vd-schedule__dot {
577
+ background: var(--vd-schedule-today-bg);
578
+ }
579
+ }
580
+
581
+ /* Narrow containers: agenda stacks the time over the title. */
582
+ @container (width < 40rem) {
583
+ .vd-schedule__agenda-event {
584
+ grid-template-columns: minmax(0, 1fr);
585
+ gap: 0;
586
+ }
587
+ }
588
+
589
+ @media (forced-colors: active) {
590
+ .vd-schedule__event,
591
+ .vd-schedule__block,
592
+ .vd-schedule__agenda-event {
593
+ border: var(--vd-border-width) solid CanvasText;
594
+ border-inline-start-width: var(--vd-space-1);
595
+ }
596
+ .vd-schedule__day[aria-current='date'] {
597
+ outline: var(--vd-border-width) solid Highlight;
598
+ }
599
+ .vd-schedule__now,
600
+ .vd-schedule__now::before {
601
+ background: Highlight;
602
+ }
603
+ }
604
+ }