@saasicat/ui-vue 0.18.0 → 0.18.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/ui-vue",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Vue 3 components, resource clients and composables for the SuperAdmin UI shell. Provides boot and manifest loaders, navigation, actions and standard pages.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -53,7 +53,7 @@
53
53
  "src"
54
54
  ],
55
55
  "dependencies": {
56
- "@saasicat/types": "^0.18.0"
56
+ "@saasicat/types": "^0.18.1"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "pinia": "^2.0.0 || ^3.0.0",
@@ -481,44 +481,27 @@ async function doSubmit(code: string): Promise<void> {
481
481
  }
482
482
  </script>
483
483
 
484
+ <style src="./pilot-dialog.css" scoped></style>
485
+
484
486
  <style scoped>
485
487
  .pl-dlg {
486
488
  width: 760px;
487
489
  max-width: 96vw;
488
490
  }
489
- .pl-dlg__head {
490
- display: flex;
491
- align-items: flex-start;
492
- gap: 16px;
493
- padding: 18px 22px 14px;
494
- border-bottom: 1px solid var(--sa-border, #e2e8f0);
495
- }
496
- .pl-dlg__title {
497
- font-family: var(--sa-font-head, system-ui, sans-serif);
498
- font-weight: 700;
499
- font-size: 17px;
500
- color: var(--sa-heading, #0f172a);
501
- letter-spacing: -0.015em;
502
- }
491
+
503
492
  .pl-dlg__sub {
504
493
  font-size: 12.5px;
505
494
  color: var(--sa-muted, #64748b);
506
495
  margin-top: 3px;
507
496
  line-height: 1.4;
508
497
  }
509
- .pl-dlg__close {
510
- margin-left: auto;
511
- }
498
+
512
499
  .pl-dlg__body {
513
500
  padding: 20px 22px;
514
501
  max-height: 72vh;
515
502
  overflow-y: auto;
516
503
  }
517
- .pl-dlg__foot {
518
- border-top: 1px solid var(--sa-border, #e2e8f0);
519
- background: #fbfbfd;
520
- padding: 12px 18px;
521
- }
504
+
522
505
  .pl-foot-hint {
523
506
  margin-right: auto;
524
507
  display: inline-flex;
@@ -535,53 +518,23 @@ async function doSubmit(code: string): Promise<void> {
535
518
  .pl-section {
536
519
  margin-bottom: 20px;
537
520
  }
538
- .pl-section:last-of-type {
539
- margin-bottom: 4px;
540
- }
541
- .pl-section__head {
542
- display: flex;
543
- align-items: flex-start;
544
- gap: 12px;
545
- margin-bottom: 12px;
546
- padding-bottom: 10px;
547
- border-bottom: 1px solid #f1f5f9;
548
- }
549
- .pl-section__num {
550
- width: 24px;
551
- height: 24px;
552
- background: #eff6ff;
553
- color: #1d4ed8;
554
- border-radius: 50%;
555
- font: 700 12px var(--sa-font-body, system-ui, sans-serif);
556
- display: grid;
557
- place-items: center;
558
- flex: 0 0 auto;
559
- }
560
- .pl-section__title {
561
- font-size: 13.5px;
562
- font-weight: 700;
563
- color: var(--sa-heading, #0f172a);
564
- letter-spacing: -0.005em;
565
- }
566
- .pl-section__sub {
567
- font-size: 11.5px;
568
- color: #94a3b8;
569
- margin-top: 2px;
570
- }
571
521
 
572
522
  .pl-grid {
573
523
  display: grid;
574
524
  grid-template-columns: 1fr 1fr;
575
525
  gap: 12px 14px;
576
526
  }
527
+
577
528
  .pl-field {
578
529
  display: flex;
579
530
  flex-direction: column;
580
531
  gap: 5px;
581
532
  }
533
+
582
534
  .pl-field--full {
583
535
  grid-column: 1 / -1;
584
536
  }
537
+
585
538
  .pl-field label {
586
539
  font: 600 11px var(--sa-font-body, system-ui, sans-serif);
587
540
  letter-spacing: 0.04em;
@@ -591,6 +544,7 @@ async function doSubmit(code: string): Promise<void> {
591
544
  align-items: baseline;
592
545
  gap: 6px;
593
546
  }
547
+
594
548
  .pl-field__hint {
595
549
  font-weight: 500;
596
550
  text-transform: none;
@@ -598,34 +552,20 @@ async function doSubmit(code: string): Promise<void> {
598
552
  color: #94a3b8;
599
553
  font-size: 11px;
600
554
  }
555
+
601
556
  .pl-field__error {
602
557
  font-size: 11.5px;
603
558
  color: #b91c1c;
604
559
  }
605
560
 
606
- .pl-input {
607
- width: 100%;
608
- padding: 9px 12px;
609
- background: #fff;
610
- border: 1px solid var(--sa-border, #e2e8f0);
611
- border-radius: 8px;
612
- font: 13px var(--sa-font-body, system-ui, sans-serif);
613
- color: var(--sa-body, #1e293b);
614
- outline: 0;
615
- transition:
616
- border-color 0.12s,
617
- box-shadow 0.12s;
618
- }
619
- .pl-input:focus {
620
- border-color: var(--sa-primary, #3f6bff);
621
- box-shadow: 0 0 0 3px rgba(63, 107, 255, 0.12);
622
- }
623
561
  .pl-input--invalid {
624
562
  border-color: #fca5a5;
625
563
  }
564
+
626
565
  .pl-input::placeholder {
627
566
  color: #cbd5e1;
628
567
  }
568
+
629
569
  .pl-textarea {
630
570
  resize: vertical;
631
571
  min-height: 64px;
@@ -640,6 +580,7 @@ async function doSubmit(code: string): Promise<void> {
640
580
  border-radius: 8px;
641
581
  overflow: hidden;
642
582
  }
583
+
643
584
  .pl-slug-input__prefix {
644
585
  padding: 9px 12px;
645
586
  background: #f8fafc;
@@ -648,128 +589,14 @@ async function doSubmit(code: string): Promise<void> {
648
589
  border-right: 1px solid var(--sa-border, #e2e8f0);
649
590
  white-space: nowrap;
650
591
  }
592
+
651
593
  .pl-input--flush {
652
594
  border: 0 !important;
653
595
  border-radius: 0 !important;
654
596
  box-shadow: none !important;
655
597
  }
598
+
656
599
  .pl-input--flush:focus {
657
600
  box-shadow: none !important;
658
601
  }
659
-
660
- .pl-plan-select {
661
- display: flex;
662
- flex-direction: column;
663
- gap: 5px;
664
- }
665
- .pl-plan-opt {
666
- display: flex;
667
- align-items: center;
668
- gap: 10px;
669
- padding: 8px 11px;
670
- background: #fff;
671
- border: 1px solid var(--sa-border, #e2e8f0);
672
- border-radius: 8px;
673
- cursor: pointer;
674
- text-align: left;
675
- font-family: var(--sa-font-body, system-ui, sans-serif);
676
- transition:
677
- border-color 0.12s,
678
- background 0.12s;
679
- }
680
- .pl-plan-opt:hover {
681
- border-color: #93c5fd;
682
- background: #fafbff;
683
- }
684
- .pl-plan-opt--active {
685
- border-color: var(--sa-primary, #2563eb);
686
- background: #eff6ff;
687
- box-shadow: 0 0 0 1px var(--sa-primary, #2563eb) inset;
688
- }
689
- .pl-plan-opt__dot {
690
- width: 10px;
691
- height: 10px;
692
- border-radius: 50%;
693
- flex: 0 0 auto;
694
- }
695
- .pl-plan-opt__text {
696
- display: flex;
697
- flex-direction: column;
698
- flex: 1;
699
- min-width: 0;
700
- }
701
- .pl-plan-opt__key {
702
- font: 700 11px var(--sa-font-mono, ui-monospace, monospace);
703
- letter-spacing: 0.05em;
704
- color: var(--sa-heading, #0f172a);
705
- }
706
- .pl-plan-opt__label {
707
- font-size: 11px;
708
- color: var(--sa-muted, #64748b);
709
- margin-top: 1px;
710
- }
711
- .pl-plan-opt__check {
712
- color: #1d4ed8;
713
- }
714
-
715
- .pl-end-row {
716
- display: flex;
717
- align-items: center;
718
- gap: 6px;
719
- }
720
- .pl-end-row .pl-input {
721
- flex: 1;
722
- }
723
- .pl-btn-mini {
724
- display: inline-flex;
725
- align-items: center;
726
- gap: 4px;
727
- padding: 7px 10px;
728
- background: #fff;
729
- border: 1px solid var(--sa-border, #e2e8f0);
730
- border-radius: 7px;
731
- color: var(--sa-muted-dark, #475569);
732
- font: 500 11.5px var(--sa-font-body, system-ui, sans-serif);
733
- cursor: pointer;
734
- white-space: nowrap;
735
- }
736
- .pl-btn-mini:hover {
737
- background: #f8fafc;
738
- border-color: #cbd5e1;
739
- }
740
- .pl-end-presets {
741
- display: flex;
742
- flex-wrap: wrap;
743
- gap: 5px;
744
- margin-top: 5px;
745
- }
746
- .pl-preset-btn {
747
- padding: 4px 9px;
748
- background: #fff;
749
- border: 1px dashed #cbd5e1;
750
- border-radius: 999px;
751
- font: 600 11px var(--sa-font-body, system-ui, sans-serif);
752
- color: var(--sa-muted-dark, #475569);
753
- cursor: pointer;
754
- transition:
755
- background 0.12s,
756
- border-color 0.12s,
757
- color 0.12s;
758
- }
759
- .pl-preset-btn:hover {
760
- background: #eff6ff;
761
- border-color: #93c5fd;
762
- border-style: solid;
763
- color: #1d4ed8;
764
- }
765
-
766
- .pl-error {
767
- background: #fef2f2;
768
- border: 1px solid #fecaca;
769
- color: #b91c1c;
770
- font-size: 13px;
771
- margin: 12px 0 0;
772
- padding: 8px 12px;
773
- border-radius: 8px;
774
- }
775
602
  </style>
@@ -4,18 +4,18 @@
4
4
  @update:model-value="emit('update:modelValue', $event)"
5
5
  persistent
6
6
  >
7
- <q-card class="ple-dlg">
8
- <q-card-section class="ple-dlg__head">
7
+ <q-card class="pl-dlg">
8
+ <q-card-section class="pl-dlg__head">
9
9
  <div>
10
- <div class="ple-dlg__title">{{ msg.editDialog.title }}</div>
11
- <div class="ple-dlg__sub" v-if="row">
10
+ <div class="pl-dlg__title">{{ msg.editDialog.title }}</div>
11
+ <div class="pl-dlg__sub" v-if="row">
12
12
  <strong>{{ row.tenant.name }}</strong>
13
- <span class="ple-dlg__sep">·</span>
13
+ <span class="pl-dlg__sep">·</span>
14
14
  <code>{{ row.tenant.slug }}</code>
15
15
  </div>
16
16
  </div>
17
17
  <q-btn
18
- class="ple-dlg__close"
18
+ class="pl-dlg__close"
19
19
  flat
20
20
  dense
21
21
  round
@@ -25,62 +25,62 @@
25
25
  />
26
26
  </q-card-section>
27
27
 
28
- <q-card-section class="ple-dlg__body">
28
+ <q-card-section class="pl-dlg__body">
29
29
  <!-- Section 1: Plan -->
30
- <section class="ple-section">
31
- <header class="ple-section__head">
32
- <span class="ple-section__num">1</span>
30
+ <section class="pl-section">
31
+ <header class="pl-section__head">
32
+ <span class="pl-section__num">1</span>
33
33
  <div>
34
- <div class="ple-section__title">{{ msg.form.planLabel }}</div>
35
- <div class="ple-section__sub">{{ msg.editDialog.sectionPlanSub }}</div>
34
+ <div class="pl-section__title">{{ msg.form.planLabel }}</div>
35
+ <div class="pl-section__sub">{{ msg.editDialog.sectionPlanSub }}</div>
36
36
  </div>
37
37
  </header>
38
- <div class="ple-plan-select">
38
+ <div class="pl-plan-select">
39
39
  <button
40
40
  v-for="p in effectivePlanOptions"
41
41
  :key="p.value"
42
42
  type="button"
43
- class="ple-plan-opt"
44
- :class="{ 'ple-plan-opt--active': form.plan === p.value }"
43
+ class="pl-plan-opt"
44
+ :class="{ 'pl-plan-opt--active': form.plan === p.value }"
45
45
  @click="form.plan = p.value"
46
46
  >
47
47
  <span
48
- class="ple-plan-opt__dot"
48
+ class="pl-plan-opt__dot"
49
49
  :style="{ background: p.color ?? '#94a3b8' }"
50
50
  />
51
- <div class="ple-plan-opt__text">
52
- <span class="ple-plan-opt__key">{{ p.value }}</span>
53
- <span class="ple-plan-opt__label">{{ p.label }}</span>
51
+ <div class="pl-plan-opt__text">
52
+ <span class="pl-plan-opt__key">{{ p.value }}</span>
53
+ <span class="pl-plan-opt__label">{{ p.label }}</span>
54
54
  </div>
55
55
  <q-icon
56
56
  v-if="form.plan === p.value"
57
57
  name="check"
58
58
  size="16px"
59
- class="ple-plan-opt__check"
59
+ class="pl-plan-opt__check"
60
60
  />
61
61
  </button>
62
62
  </div>
63
63
  </section>
64
64
 
65
65
  <!-- Section 2: End date -->
66
- <section class="ple-section">
67
- <header class="ple-section__head">
68
- <span class="ple-section__num">2</span>
66
+ <section class="pl-section">
67
+ <header class="pl-section__head">
68
+ <span class="pl-section__num">2</span>
69
69
  <div>
70
- <div class="ple-section__title">
70
+ <div class="pl-section__title">
71
71
  {{ msg.editDialog.sectionEndDate }}
72
72
  </div>
73
- <div class="ple-section__sub">
73
+ <div class="pl-section__sub">
74
74
  {{ msg.editDialog.sectionEndDateSub }}
75
75
  </div>
76
76
  </div>
77
77
  </header>
78
- <div class="ple-end-row">
79
- <input v-model="form.endsAt" class="ple-input" type="date" />
78
+ <div class="pl-end-row">
79
+ <input v-model="form.endsAt" class="pl-input" type="date" />
80
80
  <button
81
81
  v-if="form.endsAt"
82
82
  type="button"
83
- class="ple-btn-mini"
83
+ class="pl-btn-mini"
84
84
  :title="msg.editDialog.clearDateTitle"
85
85
  @click="form.endsAt = ''"
86
86
  >
@@ -88,12 +88,12 @@
88
88
  {{ common.unlimited }}
89
89
  </button>
90
90
  </div>
91
- <div class="ple-end-presets">
91
+ <div class="pl-end-presets">
92
92
  <button
93
93
  v-for="p in presetEnds"
94
94
  :key="p.days"
95
95
  type="button"
96
- class="ple-preset-btn"
96
+ class="pl-preset-btn"
97
97
  @click="setEndsAtDays(p.days)"
98
98
  >
99
99
  +{{ p.label }}
@@ -102,26 +102,26 @@
102
102
  </section>
103
103
 
104
104
  <!-- Section 3: Note -->
105
- <section class="ple-section">
106
- <header class="ple-section__head">
107
- <span class="ple-section__num">3</span>
105
+ <section class="pl-section">
106
+ <header class="pl-section__head">
107
+ <span class="pl-section__num">3</span>
108
108
  <div>
109
- <div class="ple-section__title">{{ msg.editDialog.sectionNote }}</div>
110
- <div class="ple-section__sub">{{ msg.editDialog.sectionNoteSub }}</div>
109
+ <div class="pl-section__title">{{ msg.editDialog.sectionNote }}</div>
110
+ <div class="pl-section__sub">{{ msg.editDialog.sectionNoteSub }}</div>
111
111
  </div>
112
112
  </header>
113
113
  <textarea
114
114
  v-model="form.note"
115
- class="ple-input ple-textarea"
115
+ class="pl-input pl-textarea"
116
116
  rows="3"
117
117
  :placeholder="notePlaceholder"
118
118
  />
119
119
  </section>
120
120
 
121
- <p v-if="error" class="ple-error">{{ error }}</p>
121
+ <p v-if="error" class="pl-error">{{ error }}</p>
122
122
  </q-card-section>
123
123
 
124
- <q-card-actions align="right" class="ple-dlg__foot">
124
+ <q-card-actions align="right" class="pl-dlg__foot">
125
125
  <q-btn flat :label="common.cancel" v-close-popup :disable="loading" />
126
126
  <q-btn
127
127
  unelevated
@@ -329,35 +329,26 @@ async function doSubmit(code: string): Promise<void> {
329
329
  }
330
330
  </script>
331
331
 
332
+ <style src="./pilot-dialog.css" scoped></style>
333
+
332
334
  <style scoped>
333
- .ple-dlg {
335
+ .pl-dlg {
334
336
  width: 640px;
335
337
  max-width: 96vw;
336
338
  }
337
- .ple-dlg__head {
338
- display: flex;
339
- align-items: flex-start;
340
- gap: 16px;
341
- padding: 18px 22px 14px;
342
- border-bottom: 1px solid var(--sa-border, #e2e8f0);
343
- }
344
- .ple-dlg__title {
345
- font-family: var(--sa-font-head, system-ui, sans-serif);
346
- font-weight: 700;
347
- font-size: 17px;
348
- color: var(--sa-heading, #0f172a);
349
- letter-spacing: -0.015em;
350
- }
351
- .ple-dlg__sub {
339
+
340
+ .pl-dlg__sub {
352
341
  font-size: 12.5px;
353
342
  color: var(--sa-muted, #64748b);
354
343
  margin-top: 3px;
355
344
  }
356
- .ple-dlg__sep {
345
+
346
+ .pl-dlg__sep {
357
347
  color: #cbd5e1;
358
348
  margin: 0 6px;
359
349
  }
360
- .ple-dlg__sub code {
350
+
351
+ .pl-dlg__sub code {
361
352
  font-family: var(--sa-font-mono, ui-monospace, monospace);
362
353
  background: #f1f5f9;
363
354
  color: var(--sa-muted-dark, #475569);
@@ -365,190 +356,17 @@ async function doSubmit(code: string): Promise<void> {
365
356
  border-radius: 4px;
366
357
  font-size: 11.5px;
367
358
  }
368
- .ple-dlg__close {
369
- margin-left: auto;
370
- }
371
- .ple-dlg__body {
359
+
360
+ .pl-dlg__body {
372
361
  padding: 20px 22px;
373
362
  }
374
- .ple-dlg__foot {
375
- border-top: 1px solid var(--sa-border, #e2e8f0);
376
- background: #fbfbfd;
377
- padding: 12px 18px;
378
- }
379
363
 
380
- .ple-section {
364
+ .pl-section {
381
365
  margin-bottom: 18px;
382
366
  }
383
- .ple-section:last-of-type {
384
- margin-bottom: 4px;
385
- }
386
- .ple-section__head {
387
- display: flex;
388
- align-items: flex-start;
389
- gap: 12px;
390
- margin-bottom: 12px;
391
- padding-bottom: 10px;
392
- border-bottom: 1px solid #f1f5f9;
393
- }
394
- .ple-section__num {
395
- width: 24px;
396
- height: 24px;
397
- background: #eff6ff;
398
- color: #1d4ed8;
399
- border-radius: 50%;
400
- font: 700 12px var(--sa-font-body, system-ui, sans-serif);
401
- display: grid;
402
- place-items: center;
403
- flex: 0 0 auto;
404
- }
405
- .ple-section__title {
406
- font-size: 13.5px;
407
- font-weight: 700;
408
- color: var(--sa-heading, #0f172a);
409
- letter-spacing: -0.005em;
410
- }
411
- .ple-section__sub {
412
- font-size: 11.5px;
413
- color: #94a3b8;
414
- margin-top: 2px;
415
- }
416
367
 
417
- .ple-input {
418
- width: 100%;
419
- padding: 9px 12px;
420
- background: #fff;
421
- border: 1px solid var(--sa-border, #e2e8f0);
422
- border-radius: 8px;
423
- font: 13px var(--sa-font-body, system-ui, sans-serif);
424
- color: var(--sa-body, #1e293b);
425
- outline: 0;
426
- transition:
427
- border-color 0.12s,
428
- box-shadow 0.12s;
429
- }
430
- .ple-input:focus {
431
- border-color: var(--sa-primary, #3f6bff);
432
- box-shadow: 0 0 0 3px rgba(63, 107, 255, 0.12);
433
- }
434
- .ple-textarea {
368
+ .pl-textarea {
435
369
  resize: vertical;
436
370
  min-height: 64px;
437
371
  }
438
-
439
- .ple-plan-select {
440
- display: flex;
441
- flex-direction: column;
442
- gap: 5px;
443
- }
444
- .ple-plan-opt {
445
- display: flex;
446
- align-items: center;
447
- gap: 10px;
448
- padding: 8px 11px;
449
- background: #fff;
450
- border: 1px solid var(--sa-border, #e2e8f0);
451
- border-radius: 8px;
452
- cursor: pointer;
453
- text-align: left;
454
- font-family: var(--sa-font-body, system-ui, sans-serif);
455
- transition:
456
- border-color 0.12s,
457
- background 0.12s;
458
- }
459
- .ple-plan-opt:hover {
460
- border-color: #93c5fd;
461
- background: #fafbff;
462
- }
463
- .ple-plan-opt--active {
464
- border-color: var(--sa-primary, #2563eb);
465
- background: #eff6ff;
466
- box-shadow: 0 0 0 1px var(--sa-primary, #2563eb) inset;
467
- }
468
- .ple-plan-opt__dot {
469
- width: 10px;
470
- height: 10px;
471
- border-radius: 50%;
472
- flex: 0 0 auto;
473
- }
474
- .ple-plan-opt__text {
475
- display: flex;
476
- flex-direction: column;
477
- flex: 1;
478
- min-width: 0;
479
- }
480
- .ple-plan-opt__key {
481
- font: 700 11px var(--sa-font-mono, ui-monospace, monospace);
482
- letter-spacing: 0.05em;
483
- color: var(--sa-heading, #0f172a);
484
- }
485
- .ple-plan-opt__label {
486
- font-size: 11px;
487
- color: var(--sa-muted, #64748b);
488
- margin-top: 1px;
489
- }
490
- .ple-plan-opt__check {
491
- color: #1d4ed8;
492
- }
493
-
494
- .ple-end-row {
495
- display: flex;
496
- align-items: center;
497
- gap: 6px;
498
- }
499
- .ple-end-row .ple-input {
500
- flex: 1;
501
- }
502
- .ple-btn-mini {
503
- display: inline-flex;
504
- align-items: center;
505
- gap: 4px;
506
- padding: 7px 10px;
507
- background: #fff;
508
- border: 1px solid var(--sa-border, #e2e8f0);
509
- border-radius: 7px;
510
- color: var(--sa-muted-dark, #475569);
511
- font: 500 11.5px var(--sa-font-body, system-ui, sans-serif);
512
- cursor: pointer;
513
- white-space: nowrap;
514
- }
515
- .ple-btn-mini:hover {
516
- background: #f8fafc;
517
- border-color: #cbd5e1;
518
- }
519
- .ple-end-presets {
520
- display: flex;
521
- flex-wrap: wrap;
522
- gap: 5px;
523
- margin-top: 5px;
524
- }
525
- .ple-preset-btn {
526
- padding: 4px 9px;
527
- background: #fff;
528
- border: 1px dashed #cbd5e1;
529
- border-radius: 999px;
530
- font: 600 11px var(--sa-font-body, system-ui, sans-serif);
531
- color: var(--sa-muted-dark, #475569);
532
- cursor: pointer;
533
- transition:
534
- background 0.12s,
535
- border-color 0.12s,
536
- color 0.12s;
537
- }
538
- .ple-preset-btn:hover {
539
- background: #eff6ff;
540
- border-color: #93c5fd;
541
- border-style: solid;
542
- color: #1d4ed8;
543
- }
544
-
545
- .ple-error {
546
- background: #fef2f2;
547
- border: 1px solid #fecaca;
548
- color: #b91c1c;
549
- font-size: 13px;
550
- margin: 12px 0 0;
551
- padding: 8px 12px;
552
- border-radius: 8px;
553
- }
554
372
  </style>