@7365admin1/layer-common 3.2.2-staging.86 → 3.2.2-staging.88

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.
@@ -398,6 +398,21 @@
398
398
  background: var(--hover);
399
399
  }
400
400
 
401
+ /**
402
+ * The grouped list (`TableHygiene`) draws its own rows instead of a <table>,
403
+ * so it cannot inherit the two rules above. Its group header takes the header
404
+ * row's surface and its rows the card's - replacing the literal
405
+ * `grey-lighten-4` and `white` that painted the whole list near-white on a
406
+ * dark card.
407
+ */
408
+ .table-card__group {
409
+ background: var(--thead);
410
+ }
411
+
412
+ .table-card__row {
413
+ background: var(--card);
414
+ }
415
+
401
416
  /* ------------------------------------------------------------------ */
402
417
  /* Empty state, in-card search, buttons and in-card tabs. */
403
418
  /* ------------------------------------------------------------------ */
@@ -33,7 +33,7 @@
33
33
  <template #extension>
34
34
  <v-row no-gutters class="w-100 d-flex flex-column">
35
35
  <v-card
36
- class="w-100 px-3 d-flex align-center ga-5 py-2"
36
+ class="w-100 filter-bar d-flex align-center ga-5"
37
37
  flat
38
38
  :height="60"
39
39
  >
@@ -80,7 +80,11 @@
80
80
  </div>
81
81
  </template>
82
82
  <template #item.status="{ value }">
83
- <v-chip class="text-capitalize">{{ value || "No Status" }}</v-chip>
83
+ <StatusChip
84
+ class="text-capitalize"
85
+ :status="value"
86
+ :label="value || 'No Status'"
87
+ />
84
88
  </template>
85
89
  </TableMain></v-col
86
90
  >
@@ -49,10 +49,8 @@
49
49
  <!-- Primary action -->
50
50
  <v-btn
51
51
  v-if="canCreateArea"
52
- class="text-none mr-3"
53
- rounded="pill"
54
- variant="tonal"
55
- size="large"
52
+ class="text-none mr-3 screen-btn-primary"
53
+ variant="flat"
56
54
  @click="onCreateItem"
57
55
  >
58
56
  {{ createLabel }}
@@ -63,10 +61,8 @@
63
61
  <template #activator="{ props: t }">
64
62
  <v-btn
65
63
  v-bind="t"
66
- class="ma-1"
67
- variant="tonal"
68
- size="large"
69
- rounded="pill"
64
+ class="ma-1 screen-icon-btn"
65
+ variant="flat"
70
66
  href="/files/area-sample-data.xlsx"
71
67
  target="_blank"
72
68
  download
@@ -81,10 +77,8 @@
81
77
  <template #activator="{ props: t }">
82
78
  <v-btn
83
79
  v-bind="t"
84
- class="ma-1"
85
- variant="tonal"
86
- size="large"
87
- rounded="pill"
80
+ class="ma-1 screen-icon-btn"
81
+ variant="flat"
88
82
  @click="onImportData"
89
83
  >
90
84
  <v-icon>mdi-upload</v-icon>
@@ -97,10 +91,8 @@
97
91
  <template #activator="{ props: t }">
98
92
  <v-btn
99
93
  v-bind="t"
100
- class="ma-1"
101
- variant="tonal"
102
- size="large"
103
- rounded="pill"
94
+ class="ma-1 screen-icon-btn"
95
+ variant="flat"
104
96
  @click="handleDownloadExcel"
105
97
  :loading="isDownloading"
106
98
  >
@@ -114,7 +106,7 @@
114
106
 
115
107
  <v-spacer />
116
108
 
117
- <v-col cols="auto">
109
+ <v-col cols="auto" class="filter-field">
118
110
  <v-text-field
119
111
  v-model="searchInput"
120
112
  density="compact"
@@ -1,14 +1,12 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
3
  <v-col cols="12">
4
- <v-card
5
- width="100%"
6
- variant="outlined"
7
- border="thin"
8
- rounded="lg"
9
- :loading="false"
10
- >
11
- <v-toolbar density="compact" color="grey-lighten-4">
4
+ <v-card width="100%" variant="flat" class="table-card" :loading="false">
5
+ <v-toolbar
6
+ density="compact"
7
+ color="transparent"
8
+ class="table-card__toolbar"
9
+ >
12
10
  <template #prepend>
13
11
  <v-btn fab icon density="comfortable">
14
12
  <v-icon>mdi-refresh</v-icon>
@@ -16,7 +14,7 @@
16
14
  </template>
17
15
  <template #append>
18
16
  <v-row no-gutters justify="end" align="center">
19
- <span class="mr-2 text-caption text-fontgray">
17
+ <span class="mr-2 table-card__range">
20
18
  {{ pageRange }}
21
19
  </span>
22
20
  <local-pagination v-model="page" :length="pages" />
@@ -38,7 +36,7 @@
38
36
  <span class="text-caption font-weight-bold text-capitalize">
39
37
  permissions
40
38
  </span>
41
- <v-chip>{{ value.length }}</v-chip>
39
+ <StatusChip :dot="false" tone="neutral" :label="`${value.length}`" />
42
40
  </template>
43
41
 
44
42
  <template #item.nature="{ item }">
@@ -632,7 +632,7 @@ onUnmounted(() => {
632
632
  .page-wrap {
633
633
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
634
634
  font-size: 14px;
635
- color: #111827;
635
+ color: var(--text);
636
636
  background: transparent;
637
637
  }
638
638
 
@@ -651,9 +651,9 @@ onUnmounted(() => {
651
651
  gap: 12px;
652
652
  }
653
653
  .btn-invite {
654
- background: #fff;
655
- color: #111827;
656
- border: 1px solid #D1D5DB;
654
+ background: var(--card);
655
+ color: var(--text);
656
+ border: 1px solid var(--border);
657
657
  border-radius: 24px;
658
658
  padding: 10px 22px;
659
659
  font-size: 14px;
@@ -662,7 +662,7 @@ onUnmounted(() => {
662
662
  white-space: nowrap;
663
663
  transition: background 0.15s;
664
664
  }
665
- .btn-invite:hover { background: #F9FAFB; }
665
+ .btn-invite:hover { background: var(--hover); }
666
666
 
667
667
  .search-wrap {
668
668
  position: relative;
@@ -672,16 +672,16 @@ onUnmounted(() => {
672
672
  .search-input {
673
673
  width: 100%;
674
674
  height: 36px;
675
- border: 1px solid #E5E7EB;
675
+ border: 1px solid var(--border);
676
676
  border-radius: 8px;
677
677
  padding: 0 34px 0 12px;
678
678
  font-size: 13px;
679
- color: #111827;
680
- background: #fff;
679
+ color: var(--text);
680
+ background: var(--card);
681
681
  outline: none;
682
682
  }
683
- .search-input:focus { border-color: #9CA3AF; }
684
- .search-input::placeholder { color: #9CA3AF; }
683
+ .search-input:focus { border-color: var(--muted); }
684
+ .search-input::placeholder { color: var(--muted); }
685
685
  .search-icon {
686
686
  position: absolute;
687
687
  right: 12px;
@@ -698,13 +698,13 @@ onUnmounted(() => {
698
698
  transform: translateY(-50%);
699
699
  border: none;
700
700
  background: transparent;
701
- color: #9CA3AF;
701
+ color: var(--muted);
702
702
  font-size: 16px;
703
703
  cursor: pointer;
704
704
  line-height: 1;
705
705
  padding: 0;
706
706
  }
707
- .clear-btn:hover { color: #374151; }
707
+ .clear-btn:hover { color: var(--text2); }
708
708
 
709
709
  .filter-wrap {
710
710
  display: flex;
@@ -721,8 +721,8 @@ onUnmounted(() => {
721
721
  top: -8px;
722
722
  left: 9px;
723
723
  font-size: 10px;
724
- color: #6B7280;
725
- background: #fff;
724
+ color: var(--muted);
725
+ background: var(--card);
726
726
  padding: 0 3px;
727
727
  pointer-events: none;
728
728
  z-index: 1;
@@ -730,18 +730,18 @@ onUnmounted(() => {
730
730
  }
731
731
  .filter-field select {
732
732
  height: 36px;
733
- border: 1px solid #E5E7EB;
733
+ border: 1px solid var(--border);
734
734
  border-radius: 8px;
735
735
  padding: 0 28px 0 10px;
736
736
  font-size: 13px;
737
- color: #111827;
738
- background: #fff;
737
+ color: var(--text);
738
+ background: var(--card);
739
739
  appearance: none;
740
740
  cursor: pointer;
741
741
  outline: none;
742
742
  min-width: 110px;
743
743
  }
744
- .filter-field select:focus { border-color: #9CA3AF; }
744
+ .filter-field select:focus { border-color: var(--muted); }
745
745
  .chevron {
746
746
  position: absolute;
747
747
  right: 9px;
@@ -755,8 +755,8 @@ onUnmounted(() => {
755
755
  /* ===== TABLE CARD ===== */
756
756
  .table-card {
757
757
  margin: 12px 0 0 0;
758
- background: #fff;
759
- border: 1px solid #E5E7EB;
758
+ background: var(--card);
759
+ border: 1px solid var(--border);
760
760
  border-radius: 10px;
761
761
  overflow: hidden;
762
762
  }
@@ -767,8 +767,8 @@ onUnmounted(() => {
767
767
  align-items: center;
768
768
  justify-content: space-between;
769
769
  padding: 6px 12px;
770
- background: #fff;
771
- border-bottom: 1px solid #F3F4F6;
770
+ background: var(--card);
771
+ border-bottom: 1px solid var(--hover);
772
772
  }
773
773
  .toolbar-left { display: flex; align-items: center; }
774
774
  .toolbar-right { display: flex; align-items: center; gap: 6px; }
@@ -777,7 +777,7 @@ onUnmounted(() => {
777
777
  background: none;
778
778
  border: none;
779
779
  cursor: pointer;
780
- color: #6B7280;
780
+ color: var(--muted);
781
781
  width: 28px;
782
782
  height: 28px;
783
783
  border-radius: 6px;
@@ -786,14 +786,14 @@ onUnmounted(() => {
786
786
  justify-content: center;
787
787
  transition: background 0.15s;
788
788
  }
789
- .refresh-btn:hover { background: #F3F4F6; }
789
+ .refresh-btn:hover { background: var(--hover); }
790
790
  .refresh-btn.spinning svg { animation: spin 0.8s linear infinite; }
791
791
  @keyframes spin { to { transform: rotate(360deg); } }
792
792
 
793
- .page-range-text { font-size: 12px; color: #6B7280; }
793
+ .page-range-text { font-size: 12px; color: var(--muted); }
794
794
  .page-btn {
795
795
  background: none;
796
- border: 1px solid #E5E7EB;
796
+ border: 1px solid var(--border);
797
797
  border-radius: 5px;
798
798
  width: 24px;
799
799
  height: 24px;
@@ -801,22 +801,22 @@ onUnmounted(() => {
801
801
  align-items: center;
802
802
  justify-content: center;
803
803
  cursor: pointer;
804
- color: #374151;
804
+ color: var(--text2);
805
805
  transition: background 0.1s;
806
806
  }
807
- .page-btn:hover:not(:disabled) { background: #F3F4F6; }
807
+ .page-btn:hover:not(:disabled) { background: var(--hover); }
808
808
  .page-btn:disabled { opacity: 0.35; cursor: not-allowed; }
809
809
 
810
810
  /* ===== TABS ===== */
811
811
  .tabs-row {
812
812
  display: flex;
813
- border-bottom: 1px solid #E5E7EB;
813
+ border-bottom: 1px solid var(--border);
814
814
  padding: 0 16px;
815
815
  }
816
816
  .tab {
817
817
  padding: 10px 14px;
818
818
  font-size: 13px;
819
- color: #6B7280;
819
+ color: var(--muted);
820
820
  background: none;
821
821
  border: none;
822
822
  border-bottom: 2px solid transparent;
@@ -824,15 +824,15 @@ onUnmounted(() => {
824
824
  margin-bottom: -1px;
825
825
  transition: color 0.15s, border-color 0.15s;
826
826
  }
827
- .tab:hover { color: #374151; }
828
- .tab.active { color: #111827; border-bottom-color: #111827; font-weight: 500; }
827
+ .tab:hover { color: var(--text2); }
828
+ .tab.active { color: var(--text); border-bottom-color: var(--text); font-weight: 500; }
829
829
 
830
830
  /* ===== LOADING BAR ===== */
831
- .loading-bar { height: 2px; background: #F3F4F6; overflow: hidden; }
831
+ .loading-bar { height: 2px; background: var(--hover); overflow: hidden; }
832
832
  .loading-bar-fill {
833
833
  height: 100%;
834
834
  width: 35%;
835
- background: #6B7280;
835
+ background: var(--muted);
836
836
  animation: slide 1.1s ease-in-out infinite;
837
837
  }
838
838
  @keyframes slide {
@@ -848,34 +848,34 @@ thead th {
848
848
  text-align: left;
849
849
  font-weight: 600;
850
850
  font-size: 13px;
851
- color: #374151;
852
- border-bottom: 1px solid #E5E7EB;
851
+ color: var(--text2);
852
+ border-bottom: 1px solid var(--border);
853
853
  white-space: nowrap;
854
- background: #fff;
854
+ background: var(--card);
855
855
  }
856
- tbody tr { border-bottom: 1px solid #F3F4F6; transition: background 0.1s; }
856
+ tbody tr { border-bottom: 1px solid var(--hover); transition: background 0.1s; }
857
857
  tbody tr:last-child { border-bottom: none; }
858
- tbody tr:hover { background: #FAFAFA; }
858
+ tbody tr:hover { background: var(--thead); }
859
859
  tbody td { padding: 14px 16px; vertical-align: middle; }
860
860
 
861
- .empty { text-align: center; color: #9CA3AF; padding: 48px 0 !important; }
862
- .td-name { font-weight: 500; color: #111827; }
863
- .td-muted { color: #6B7280; font-size: 13px; }
861
+ .empty { text-align: center; color: var(--muted); padding: 48px 0 !important; }
862
+ .td-name { font-weight: 500; color: var(--text); }
863
+ .td-muted { color: var(--muted); font-size: 13px; }
864
864
 
865
865
  .sites-badge {
866
866
  display: inline-block;
867
- background: #F3F4F6;
867
+ background: var(--hover);
868
868
  border-radius: 20px;
869
869
  padding: 3px 12px;
870
870
  font-size: 12px;
871
- color: #374151;
871
+ color: var(--text2);
872
872
  }
873
873
  .date-cell {
874
874
  display: inline-flex;
875
875
  align-items: center;
876
876
  gap: 5px;
877
877
  font-size: 13px;
878
- color: #374151;
878
+ color: var(--text2);
879
879
  }
880
880
 
881
881
  /* ===== STATUS CHIPS ===== */
@@ -889,12 +889,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
889
889
  font-weight: 500;
890
890
  }
891
891
  .status-chip::before { content: ''; width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
892
- .status-chip.active { background: #D1FAE5; color: #065F46; }
893
- .status-chip.active::before { background: #10B981; }
894
- .status-chip.suspended { background: #FEE2E2; color: #991B1B; }
895
- .status-chip.suspended::before { background: #EF4444; }
896
- .status-chip.pending { background: #FEF9C3; color: #854D0E; }
897
- .status-chip.pending::before { background: #EAB308; }
892
+ .status-chip.active { background: var(--ok-bg); color: var(--ok); }
893
+ .status-chip.active::before { background: currentColor; }
894
+ .status-chip.suspended { background: var(--err-bg); color: var(--err); }
895
+ .status-chip.suspended::before { background: currentColor; }
896
+ .status-chip.pending { background: var(--warn-bg); color: var(--warn); }
897
+ .status-chip.pending::before { background: currentColor; }
898
898
 
899
899
  /* ===== ACTION MENU ===== */
900
900
  .action-wrap { position: relative; }
@@ -907,16 +907,16 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
907
907
  border-radius: 6px;
908
908
  padding: 6px 8px;
909
909
  cursor: pointer;
910
- color: #9CA3AF;
910
+ color: var(--muted);
911
911
  transition: background 0.15s;
912
912
  }
913
- .dots-btn:hover { background: #F3F4F6; color: #374151; }
913
+ .dots-btn:hover { background: var(--hover); color: var(--text2); }
914
914
  .dots-btn span { display: block; width: 4px; height: 4px; border-radius: 50%; background: currentColor; }
915
915
 
916
916
  .dropdown {
917
917
  position: fixed;
918
- background: #fff;
919
- border: 1px solid #E5E7EB;
918
+ background: var(--card);
919
+ border: 1px solid var(--border);
920
920
  border-radius: 8px;
921
921
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
922
922
  min-width: 130px;
@@ -932,12 +932,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
932
932
  background: none;
933
933
  border: none;
934
934
  cursor: pointer;
935
- color: #374151;
935
+ color: var(--text2);
936
936
  transition: background 0.1s;
937
937
  }
938
- .dd-item:hover { background: #F9FAFB; }
939
- .dd-item.danger { color: #DC2626; }
940
- .dd-item.danger:hover { background: #FEF2F2; }
938
+ .dd-item:hover { background: var(--hover); }
939
+ .dd-item.danger { color: var(--err); }
940
+ .dd-item.danger:hover { background: var(--err-bg); }
941
941
 
942
942
  .cancel-btn {
943
943
  display: inline-flex;
@@ -945,27 +945,27 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
945
945
  gap: 6px;
946
946
  padding: 5px 12px;
947
947
  font-size: 12px;
948
- color: #DC2626;
949
- background: #FEF2F2;
950
- border: 1px solid #FECACA;
948
+ color: var(--err);
949
+ background: var(--err-bg);
950
+ border: 1px solid var(--err-bg);
951
951
  border-radius: 6px;
952
952
  cursor: pointer;
953
953
  transition: background 0.15s;
954
954
  }
955
- .cancel-btn:hover { background: #FEE2E2; }
955
+ .cancel-btn:hover { background: var(--err-bg); }
956
956
  .cancel-btn:disabled { opacity: 0.5; cursor: not-allowed; }
957
957
  .spinner {
958
958
  display: inline-block;
959
959
  width: 11px;
960
960
  height: 11px;
961
- border: 1.5px solid #FECACA;
962
- border-top-color: #DC2626;
961
+ border: 1.5px solid var(--err-bg);
962
+ border-top-color: var(--err);
963
963
  border-radius: 50%;
964
964
  animation: spin 0.7s linear infinite;
965
965
  }
966
966
  .spinner-light {
967
967
  border: 1.5px solid rgba(255,255,255,0.5);
968
- border-top-color: #fff;
968
+ border-top-color: var(--card);
969
969
  }
970
970
 
971
971
  .client-detail {
@@ -982,7 +982,7 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
982
982
  z-index: 1000;
983
983
  }
984
984
  .dialog-box {
985
- background: #fff;
985
+ background: var(--card);
986
986
  border-radius: 12px;
987
987
  max-width: 500px;
988
988
  width: 90%;
@@ -992,7 +992,7 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
992
992
 
993
993
  /* ===== SUSPEND CONFIRMATION DIALOG ===== */
994
994
  .confirm-box {
995
- background: #fff;
995
+ background: var(--card);
996
996
  border-radius: 12px;
997
997
  max-width: 380px;
998
998
  width: 90%;
@@ -1002,12 +1002,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1002
1002
  .confirm-title {
1003
1003
  font-size: 16px;
1004
1004
  font-weight: 600;
1005
- color: #111827;
1005
+ color: var(--text);
1006
1006
  margin-bottom: 8px;
1007
1007
  }
1008
1008
  .confirm-text {
1009
1009
  font-size: 13.5px;
1010
- color: #4B5563;
1010
+ color: var(--text2);
1011
1011
  line-height: 1.5;
1012
1012
  margin-bottom: 20px;
1013
1013
  }
@@ -1020,14 +1020,14 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1020
1020
  padding: 8px 16px;
1021
1021
  font-size: 13px;
1022
1022
  font-weight: 500;
1023
- border: 1px solid #D1D5DB;
1023
+ border: 1px solid var(--border);
1024
1024
  border-radius: 8px;
1025
- background: #fff;
1026
- color: #374151;
1025
+ background: var(--card);
1026
+ color: var(--text2);
1027
1027
  cursor: pointer;
1028
1028
  transition: background 0.15s;
1029
1029
  }
1030
- .btn-cancel:hover { background: #F9FAFB; }
1030
+ .btn-cancel:hover { background: var(--hover); }
1031
1031
  .btn-confirm-danger {
1032
1032
  display: inline-flex;
1033
1033
  align-items: center;
@@ -1039,11 +1039,11 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1039
1039
  font-weight: 500;
1040
1040
  border: none;
1041
1041
  border-radius: 8px;
1042
- background: #DC2626;
1043
- color: #fff;
1042
+ background: var(--err);
1043
+ color: var(--card);
1044
1044
  cursor: pointer;
1045
1045
  transition: background 0.15s;
1046
1046
  }
1047
- .btn-confirm-danger:hover:not(:disabled) { background: #B91C1C; }
1047
+ .btn-confirm-danger:hover:not(:disabled) { background: var(--err); }
1048
1048
  .btn-confirm-danger:disabled { opacity: 0.7; cursor: not-allowed; }
1049
1049
  </style>
@@ -6,8 +6,8 @@
6
6
  v-if="loading"
7
7
  />
8
8
  <v-row no-gutters v-if="!loading">
9
- <v-col cols="12" elevation="3" class="border">
10
- <v-tabs v-model="activeTab" color="primary" class="px-2">
9
+ <v-col cols="12" elevation="3" class="screen-card">
10
+ <v-tabs v-model="activeTab" color="primary" class="px-2 screen-tabs">
11
11
  <v-tab value="general">
12
12
  <v-icon start>mdi-cog-outline</v-icon>
13
13
  General
@@ -20,10 +20,8 @@
20
20
  <v-row no-gutters align="center" class="w-100">
21
21
  <v-col cols="auto" v-if="canCreateEquipmentItem">
22
22
  <v-btn
23
- class="text-none"
24
- rounded="pill"
25
- variant="tonal"
26
- size="large"
23
+ class="text-none screen-btn-primary"
24
+ variant="flat"
27
25
  @click="openEquipmentItemDialog()"
28
26
  >
29
27
  Checkout Item
@@ -32,7 +30,7 @@
32
30
 
33
31
  <v-spacer />
34
32
 
35
- <v-col cols="auto">
33
+ <v-col cols="auto" class="filter-field">
36
34
  <v-text-field
37
35
  v-model="searchInput"
38
36
  density="compact"
@@ -20,10 +20,8 @@
20
20
  <v-row no-gutters align="center" class="w-100">
21
21
  <v-col cols="auto" v-if="canAddEquipment">
22
22
  <v-btn
23
- class="text-none"
24
- rounded="pill"
25
- variant="tonal"
26
- size="large"
23
+ class="text-none screen-btn-primary"
24
+ variant="flat"
27
25
  @click="onCreateUnit()"
28
26
  >
29
27
  Add Equipment
@@ -32,7 +30,7 @@
32
30
 
33
31
  <v-spacer />
34
32
 
35
- <v-col cols="auto">
33
+ <v-col cols="auto" class="filter-field">
36
34
  <v-text-field
37
35
  v-model="searchInput"
38
36
  density="compact"
@@ -60,7 +58,11 @@
60
58
  </template>
61
59
 
62
60
  <template #item.status="{ value }">
63
- <v-chip class="text-capitalize">{{ value || "N/A" }}</v-chip>
61
+ <StatusChip
62
+ class="text-capitalize"
63
+ :status="value"
64
+ :label="value || 'N/A'"
65
+ />
64
66
  </template>
65
67
 
66
68
  <template #item.block="{ value }">
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
3
  <v-col cols="12" class="mb-2">
4
- <v-row no-gutters align="center">
4
+ <v-row no-gutters align="center" class="filter-bar">
5
5
  <v-text-field
6
6
  v-model="searchText"
7
7
  placeholder="Search feedback..."
@@ -53,24 +53,20 @@
53
53
  <v-btn
54
54
  v-if="canCreateFeedback"
55
55
  text="create feedback"
56
- class="text-none text-capitalize ml-2"
57
- rounded="pill"
58
- variant="tonal"
59
- size="large"
56
+ class="text-none text-capitalize ml-2 screen-btn-primary filter-bar__fit"
57
+ variant="flat"
60
58
  @click="showCreateDialog = true"
61
59
  />
62
60
  </v-row>
63
61
  </v-col>
64
62
 
65
63
  <v-col cols="12">
66
- <v-card
67
- width="100%"
68
- variant="outlined"
69
- border="thin"
70
- rounded="lg"
71
- :loading="loading"
72
- >
73
- <v-toolbar density="compact" color="grey-lighten-4">
64
+ <v-card width="100%" variant="flat" class="table-card" :loading="loading">
65
+ <v-toolbar
66
+ density="compact"
67
+ color="transparent"
68
+ class="table-card__toolbar"
69
+ >
74
70
  <template #prepend>
75
71
  <v-btn
76
72
  fab
@@ -84,7 +80,7 @@
84
80
 
85
81
  <template #append>
86
82
  <v-row no-gutters justify="end" align="center">
87
- <span class="mr-2 text-caption text-fontgray">
83
+ <span class="mr-2 table-card__range">
88
84
  {{ pageRange }}
89
85
  </span>
90
86
  <local-pagination
@@ -139,13 +135,7 @@
139
135
  </template>
140
136
  <template #item.status="{ value }">
141
137
  <span class="d-inline-block text-truncate">
142
- <v-chip
143
- :color="getStatusColor(value ?? '')"
144
- class="pa-5 text-capitalize text-center whitespace-nowrap text-body-1"
145
- variant="flat"
146
- >
147
- {{ value }}
148
- </v-chip>
138
+ <StatusChip class="text-capitalize" :status="value" />
149
139
  </span>
150
140
  </template>
151
141
  <template #item.assigneeInfo="{ item, index }">
@@ -660,7 +650,6 @@ const _feedback = ref({
660
650
  });
661
651
 
662
652
  const {
663
- getStatusColor,
664
653
  debounce,
665
654
  standardFormatDateTime,
666
655
  standardFormatDate,
@@ -10,10 +10,10 @@
10
10
  </v-col>
11
11
  <v-spacer />
12
12
  <v-col v-if="isScheduleClosed" cols="auto" class="d-flex align-center">
13
- <v-chip color="error" variant="tonal" class="text-capitalize">
14
- <v-icon start>mdi-lock</v-icon>
13
+ <StatusChip status="Closed" class="text-capitalize">
14
+ <v-icon size="14">mdi-lock</v-icon>
15
15
  Closed – View Only
16
- </v-chip>
16
+ </StatusChip>
17
17
  </v-col>
18
18
  </v-row>
19
19
  <TableHygiene
@@ -85,7 +85,7 @@
85
85
  <v-sheet
86
86
  border
87
87
  rounded="lg"
88
- class="d-inline-flex flex-column pa-3 bg-grey-lighten-5"
88
+ class="d-inline-flex flex-column pa-3"
89
89
  style="max-width: 420px"
90
90
  >
91
91
  <div class="d-flex align-center ga-2 mb-2">
@@ -93,9 +93,7 @@
93
93
  <span class="text-caption font-weight-bold">
94
94
  Rejection details
95
95
  </span>
96
- <v-chip size="x-small" color="error" variant="tonal">
97
- Rejected
98
- </v-chip>
96
+ <StatusChip status="Rejected" :dot="false" />
99
97
  </div>
100
98
  <div
101
99
  v-if="item.remarks"
@@ -173,22 +171,24 @@
173
171
  <template #group-header-append="{ group }">
174
172
  <v-row no-gutters align="center" class="ga-2">
175
173
  <v-col v-if="isGroupAnyApproved(group)" cols="auto">
176
- <v-chip
177
- size="x-small"
178
- :color="isGroupComplete(group) ? 'success' : 'warning'"
179
- variant="tonal"
180
- :prepend-icon="
181
- isGroupComplete(group)
182
- ? 'mdi-check-circle-outline'
183
- : 'mdi-progress-clock'
184
- "
174
+ <StatusChip
175
+ :status="isGroupComplete(group) ? 'Completed' : 'Ongoing'"
176
+ :tone="isGroupComplete(group) ? 'ok' : 'warn'"
177
+ :dot="false"
185
178
  class="text-none"
186
179
  >
180
+ <v-icon size="12">
181
+ {{
182
+ isGroupComplete(group)
183
+ ? "mdi-check-circle-outline"
184
+ : "mdi-progress-clock"
185
+ }}
186
+ </v-icon>
187
187
  {{ isGroupComplete(group) ? "Completed" : "Ongoing" }}
188
188
  <template v-if="getGroupCompletedByName(group)">
189
189
  · {{ getGroupCompletedByName(group) }}
190
190
  </template>
191
- </v-chip>
191
+ </StatusChip>
192
192
  </v-col>
193
193
  <v-col
194
194
  v-if="group.attachments && group.attachments.length > 0"
@@ -21,7 +21,7 @@
21
21
  <template #extension>
22
22
  <v-row no-gutters class="w-100 d-flex flex-column">
23
23
  <v-card
24
- class="w-100 px-3 d-flex align-center ga-5 py-2"
24
+ class="w-100 filter-bar d-flex align-center ga-5"
25
25
  flat
26
26
  :height="60"
27
27
  >
@@ -68,20 +68,18 @@
68
68
  <v-spacer />
69
69
 
70
70
  <v-col cols="auto">
71
- <v-chip
71
+ <StatusChip
72
72
  v-if="isScheduleClosed"
73
- color="error"
74
- variant="tonal"
73
+ status="Closed"
75
74
  class="text-capitalize mr-2"
76
75
  >
77
- <v-icon start>mdi-lock</v-icon>
76
+ <v-icon size="14">mdi-lock</v-icon>
78
77
  Closed – View Only
79
- </v-chip>
78
+ </StatusChip>
80
79
  <v-btn
81
80
  v-if="canViewHistory"
82
- class="text-none mr-2"
83
- size="large"
84
- color="primary"
81
+ class="text-none mr-2 screen-btn-primary"
82
+ variant="flat"
85
83
  aria-label="History"
86
84
  @click="openHistory"
87
85
  >
@@ -89,9 +87,8 @@
89
87
  </v-btn>
90
88
  <v-btn
91
89
  v-if="canGenerateChecklist"
92
- class="text-none"
93
- size="large"
94
- color="primary"
90
+ class="text-none screen-btn-primary"
91
+ variant="flat"
95
92
  aria-label="Generate"
96
93
  @click="_generateChecklist"
97
94
  :loading="submitting"
@@ -114,20 +111,13 @@
114
111
  </span>
115
112
  </div>
116
113
  <div v-else-if="isScheduleClosed">
117
- <v-chip
118
- size="small"
119
- color="error"
120
- variant="tonal"
121
- class="text-capitalize"
122
- >Closed</v-chip
123
- >
114
+ <StatusChip status="Closed" class="text-capitalize" />
124
115
  </div>
125
116
  <div v-else>
126
117
  <v-btn
127
118
  v-if="canManageScheduleTasks"
128
119
  variant="outlined"
129
- size="medium"
130
- class="text-capitalize px-4 py-2"
120
+ class="text-capitalize screen-btn-ghost"
131
121
  @click.stop="() => _acceptAreaChecklist(item._id)"
132
122
  >
133
123
  Accept
@@ -146,14 +136,11 @@
146
136
  </template>
147
137
 
148
138
  <template #item.status="{ value }">
149
- <v-chip
139
+ <StatusChip
150
140
  class="text-capitalize"
151
- :color="getStatusColor(value)"
152
- variant="flat"
153
- pill
154
- >
155
- {{ value || "No Status" }}
156
- </v-chip>
141
+ :status="value"
142
+ :label="value || 'No Status'"
143
+ />
157
144
  </template>
158
145
  </TableMain></v-col
159
146
  >
@@ -262,27 +249,6 @@ watchEffect(() => {
262
249
  }
263
250
  });
264
251
 
265
- const getStatusColor = (status: unknown): string => {
266
- if (!status) return "grey";
267
-
268
- const normalized = String(status).toLowerCase();
269
-
270
- switch (normalized) {
271
- case "open":
272
- return "grey";
273
- case "ongoing":
274
- return "primary";
275
- case "completed":
276
- case "accepted":
277
- return "success";
278
- case "closed":
279
- case "rejected":
280
- return "error";
281
- default:
282
- return "secondary";
283
- }
284
- };
285
-
286
252
  function showMessage(msg: string, color: string = "error") {
287
253
  message.value = msg;
288
254
  messageColor.value = color;
@@ -47,13 +47,7 @@
47
47
  </template>
48
48
 
49
49
  <template #item.status="{ value }">
50
- <v-chip
51
- :color="getStatusColor(value)"
52
- class="font-weight-bold"
53
- style="background: #ffe6c2; color: #ff9800"
54
- >
55
- {{ value || "To-Do" }}
56
- </v-chip>
50
+ <StatusChip :status="value || 'To-Do'" :label="value || 'To-Do'" />
57
51
  </template>
58
52
  <!-- Completion Date/Time -->
59
53
  <template #item.completionDate="{ value }">
@@ -61,7 +55,11 @@
61
55
  </template>
62
56
  <!-- Action (Accept button) -->
63
57
  <template #item.action="{ item }">
64
- <v-btn outlined class="accept-btn" @click.stop="acceptTask(item)">
58
+ <v-btn
59
+ variant="outlined"
60
+ class="text-none screen-btn-ghost"
61
+ @click.stop="acceptTask(item)"
62
+ >
65
63
  Accept
66
64
  </v-btn>
67
65
  </template>
@@ -146,11 +144,6 @@ function getAvatarColor(name: string) {
146
144
  if (name === "Hygiene SP") return "blue";
147
145
  return "grey";
148
146
  }
149
- function getStatusColor(status: string) {
150
- if (status === "To-Do") return "orange";
151
- if (status === "Completed") return "green";
152
- return "grey";
153
- }
154
147
  function acceptTask(item: any) {
155
148
  selectedTask.value = item;
156
149
  showAcceptDialog.value = true;
@@ -170,13 +163,3 @@ function onRowClick(data: any) {
170
163
  }
171
164
  }
172
165
  </script>
173
-
174
- <style scoped>
175
- .accept-btn {
176
- border: 1px solid #333;
177
- background: #fff;
178
- border-radius: 4px;
179
- cursor: pointer;
180
- min-width: 80px;
181
- }
182
- </style>
@@ -1,8 +1,13 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
- <v-expansion-panels multiple v-model="openPanels">
3
+ <!--
4
+ The design draws settings as a stack of bordered sections with one open
5
+ at a time. `multiple` is BEHAVIOUR - which sections a user may have open
6
+ together - so it is left exactly as it was and only the drawing changes.
7
+ -->
8
+ <v-expansion-panels multiple v-model="openPanels" class="screen-accordion">
4
9
  <!-- SITE SETTINGS -->
5
- <v-expansion-panel v-if="canManageSiteInformation" color="primary">
10
+ <v-expansion-panel v-if="canManageSiteInformation">
6
11
  <v-expansion-panel-title>
7
12
  <v-icon class="mr-2">mdi-cog</v-icon>
8
13
  Site Information
@@ -22,7 +27,7 @@
22
27
  <v-img v-if="coverPhotoUrl" :src="coverPhotoUrl" aspect-ratio="16/9" cover rounded="lg"
23
28
  class="w-100 border" />
24
29
  <div v-else
25
- class="w-100 d-flex align-center justify-center rounded-lg bg-grey-lighten-4 border border-dashed"
30
+ class="w-100 d-flex align-center justify-center rounded-lg border border-dashed site-settings__placeholder"
26
31
  style="aspect-ratio: 16/9">
27
32
  <span class="text-caption text-medium-emphasis">No cover photo uploaded</span>
28
33
  </div>
@@ -76,7 +81,7 @@
76
81
  </v-expansion-panel>
77
82
 
78
83
  <!-- ANPR CAMERA -->
79
- <v-expansion-panel v-if="showAnprCamera && canManageANPRCamera" color="primary">
84
+ <v-expansion-panel v-if="showAnprCamera && canManageANPRCamera">
80
85
  <v-expansion-panel-title>
81
86
  <v-icon class="mr-2">mdi-camera</v-icon>
82
87
  ANPR Camera
@@ -118,7 +123,7 @@
118
123
  </v-expansion-panel>
119
124
 
120
125
  <!-- CCTV CAMERA -->
121
- <v-expansion-panel v-if="showCctvCamera && canManageCCTVCamera" color="primary">
126
+ <v-expansion-panel v-if="showCctvCamera && canManageCCTVCamera">
122
127
  <v-expansion-panel-title>
123
128
  <v-icon class="mr-2">mdi-cctv</v-icon>
124
129
  CCTV Camera
@@ -129,7 +134,7 @@
129
134
  </v-expansion-panel-text>
130
135
  </v-expansion-panel>
131
136
 
132
- <v-expansion-panel v-if="showDeliveryCompanies && canManageDeliveryCompanies" color="primary">
137
+ <v-expansion-panel v-if="showDeliveryCompanies && canManageDeliveryCompanies">
133
138
  <v-expansion-panel-title>
134
139
  <v-icon class="mr-2">mdi-truck</v-icon>
135
140
  Delivery Companies
@@ -140,7 +145,7 @@
140
145
  </v-expansion-panel-text>
141
146
  </v-expansion-panel>
142
147
 
143
- <v-expansion-panel v-if="showResidentVisitors && canManageResidentVisitors" color="primary">
148
+ <v-expansion-panel v-if="showResidentVisitors && canManageResidentVisitors">
144
149
  <v-expansion-panel-title>
145
150
  <v-icon class="mr-2">mdi-car</v-icon>
146
151
  Resident Visitors
@@ -150,7 +155,7 @@
150
155
  </v-expansion-panel-text>
151
156
  </v-expansion-panel>
152
157
 
153
- <v-expansion-panel color="primary">
158
+ <v-expansion-panel>
154
159
  <v-expansion-panel-title>
155
160
  <v-icon class="mr-2">mdi-face-recognition</v-icon>
156
161
  HID Face Reader
@@ -421,3 +426,11 @@ const saveANPRSettings = async () => {
421
426
  }
422
427
  };
423
428
  </script>
429
+
430
+ <style scoped>
431
+ /* Was `bg-grey-lighten-4`: a literal light grey, so the empty cover-photo tile
432
+ stayed a white slab on the dark page. */
433
+ .site-settings__placeholder {
434
+ background: var(--thead);
435
+ }
436
+ </style>
@@ -5,10 +5,8 @@
5
5
  <slot name="actions">
6
6
  <v-btn
7
7
  v-if="canCreate"
8
- class="text-none"
9
- rounded="pill"
10
- variant="tonal"
11
- size="large"
8
+ class="text-none screen-btn-primary"
9
+ variant="flat"
12
10
  @click="emits('create')"
13
11
  >
14
12
  {{ createLabel }}
@@ -18,16 +16,11 @@
18
16
  </v-col>
19
17
 
20
18
  <v-col cols="12">
21
- <v-card
22
- width="100%"
23
- variant="outlined"
24
- border="thin"
25
- rounded="lg"
26
- :loading="loading"
27
- >
19
+ <v-card width="100%" variant="flat" class="table-card" :loading="loading">
28
20
  <v-toolbar
29
21
  density="compact"
30
- color="grey-lighten-4"
22
+ color="transparent"
23
+ class="table-card__toolbar"
31
24
  :extension-height="extensionHeight"
32
25
  >
33
26
  <template #prepend>
@@ -46,7 +39,7 @@
46
39
 
47
40
  <template #append>
48
41
  <v-row no-gutters justify="end" align="center">
49
- <span class="mr-2 text-caption text-fontgray">
42
+ <span class="mr-2 table-card__range">
50
43
  {{ pageRange }}
51
44
  </span>
52
45
  <local-pagination
@@ -68,25 +61,16 @@
68
61
  :max-height="`calc(100vh - (${offset}px))`"
69
62
  class="overflow-y-auto"
70
63
  >
71
- <v-row
72
- v-if="groupedItems.length === 0"
73
- no-gutters
74
- justify="center"
75
- class="py-10"
76
- >
77
- <v-col
78
- cols="auto"
79
- class="text-center text-medium-emphasis text-body-2"
80
- >
81
- {{ noDataText }}
82
- </v-col>
83
- </v-row>
64
+ <div v-if="groupedItems.length === 0" class="table-card__empty">
65
+ <v-icon icon="mdi-magnify-close" size="32" />
66
+ <span>{{ noDataText }}</span>
67
+ </div>
84
68
 
85
69
  <template
86
70
  v-for="(group, groupIndex) in groupedItems"
87
71
  :key="`group-${groupIndex}`"
88
72
  >
89
- <v-sheet color="grey-lighten-4" border="b t">
73
+ <v-sheet color="transparent" class="table-card__group" border="b t">
90
74
  <v-row no-gutters align="center" class="px-4 py-2">
91
75
  <v-col cols="auto" class="d-flex align-center ga-2">
92
76
  <span
@@ -94,39 +78,37 @@
94
78
  >
95
79
  Set {{ group.set }}
96
80
  </span>
97
- <v-chip
81
+ <StatusChip
98
82
  v-if="group.isScheduleTask"
99
- size="x-small"
100
- color="info"
101
- variant="tonal"
102
- prepend-icon="mdi-calendar-clock"
83
+ tone="info"
84
+ :dot="false"
103
85
  class="text-none"
104
86
  >
87
+ <v-icon size="12">mdi-calendar-clock</v-icon>
105
88
  Schedule Task
106
- </v-chip>
89
+ </StatusChip>
107
90
  <slot name="group-header-chips" :group="group">
108
- <v-chip
91
+ <StatusChip
109
92
  v-if="group.completedByName && isGroupComplete(group)"
110
- size="x-small"
111
- color="success"
112
- variant="tonal"
113
- prepend-icon="mdi-check-circle-outline"
93
+ status="Completed"
94
+ :dot="false"
114
95
  class="text-none"
115
96
  >
97
+ <v-icon size="12">mdi-check-circle-outline</v-icon>
116
98
  Completed · {{ group.completedByName }}
117
- </v-chip>
118
- <v-chip
99
+ </StatusChip>
100
+ <StatusChip
119
101
  v-else-if="
120
102
  group.completedByName && isGroupInProgress(group)
121
103
  "
122
- size="x-small"
123
- color="warning"
124
- variant="tonal"
125
- prepend-icon="mdi-progress-clock"
104
+ status="Ongoing"
105
+ tone="warn"
106
+ :dot="false"
126
107
  class="text-none"
127
108
  >
109
+ <v-icon size="12">mdi-progress-clock</v-icon>
128
110
  Ongoing · {{ group.completedByName }}
129
- </v-chip>
111
+ </StatusChip>
130
112
  </slot>
131
113
  </v-col>
132
114
  <v-spacer />
@@ -139,7 +121,8 @@
139
121
  <v-sheet
140
122
  v-for="item in group.items"
141
123
  :key="item[itemValue]"
142
- color="white"
124
+ color="transparent"
125
+ class="table-card__row"
143
126
  border="b"
144
127
  >
145
128
  <v-row no-gutters align="center" class="px-4 py-2">
@@ -24,10 +24,8 @@
24
24
  <!-- Primary action -->
25
25
  <v-btn
26
26
  v-if="canCreateUnit"
27
- class="text-none mr-3"
28
- rounded="pill"
29
- variant="tonal"
30
- size="large"
27
+ class="text-none mr-3 screen-btn-primary"
28
+ variant="flat"
31
29
  @click="onCreateUnit()"
32
30
  >
33
31
  Add Unit
@@ -37,10 +35,8 @@
37
35
  <template #activator="{ props: t }">
38
36
  <v-btn
39
37
  v-bind="t"
40
- class="ma-1"
41
- variant="tonal"
42
- size="large"
43
- rounded="pill"
38
+ class="ma-1 screen-icon-btn"
39
+ variant="flat"
44
40
  href="/files/unit-sample-data.xlsx"
45
41
  target="_blank"
46
42
  download
@@ -55,10 +51,8 @@
55
51
  <template #activator="{ props: t }">
56
52
  <v-btn
57
53
  v-bind="t"
58
- class="ma-1"
59
- variant="tonal"
60
- size="large"
61
- rounded="pill"
54
+ class="ma-1 screen-icon-btn"
55
+ variant="flat"
62
56
  @click="onImportData"
63
57
  >
64
58
  <v-icon>mdi-upload</v-icon>
@@ -71,10 +65,8 @@
71
65
  <template #activator="{ props: t }">
72
66
  <v-btn
73
67
  v-bind="t"
74
- class="ma-1"
75
- variant="tonal"
76
- size="large"
77
- rounded="pill"
68
+ class="ma-1 screen-icon-btn"
69
+ variant="flat"
78
70
  @click="handleDownloadExcel"
79
71
  :loading="isDownloading"
80
72
  >
@@ -88,7 +80,7 @@
88
80
 
89
81
  <v-spacer />
90
82
 
91
- <v-col cols="auto">
83
+ <v-col cols="auto" class="filter-field">
92
84
  <v-text-field
93
85
  v-model="searchInput"
94
86
  density="compact"
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.2.2-staging.86",
5
+ "version": "3.2.2-staging.88",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {