xto-fronted 0.7.0 → 0.8.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.
@@ -37,12 +37,11 @@ const layoutOptions: { value: LayoutMode; label: string; icon: string }[] = [
37
37
 
38
38
  // 主题色选项
39
39
  const colorOptions = [
40
- { value: '#12B6AF', label: '品牌蓝' },
41
- { value: '#1890ff', label: '科技蓝' },
42
- { value: '#52c41a', label: '极光绿' },
43
- { value: '#faad14', label: '日落橙' },
44
- { value: '#f5222d', label: '薄暮红' },
45
- { value: '#722ed1', label: '酱紫' }
40
+ { value: '#4F46E5', label: '品牌蓝' },
41
+ { value: '#0F6FDE', label: '企业蓝' },
42
+ { value: '#00A870', label: '翡翠绿' },
43
+ { value: '#D46B08', label: '琥珀橙' },
44
+ { value: '#1F2329', label: '石墨黑' }
46
45
  ]
47
46
 
48
47
  // 面包屑
@@ -352,7 +351,7 @@ onUnmounted(() => {
352
351
  <span>{{ userStore.userName?.charAt(0) || 'U' }}</span>
353
352
  </div>
354
353
  <span class="header__user-name">{{ userStore.userName }}</span>
355
- <span class="header__user-arrow" :class="{ 'is-active': dropdownVisible }">▼</span>
354
+ <span class="header__user-arrow" :class="{ 'is-active': dropdownVisible }"><svg viewBox="0 0 12 12" width="10" height="10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 4.5 6 8l3.5-3.5"/></svg></span>
356
355
  </div>
357
356
 
358
357
  <!-- 下拉菜单 -->
@@ -500,7 +499,7 @@ onUnmounted(() => {
500
499
  transition: color 0.2s;
501
500
 
502
501
  &:hover {
503
- color: var(--xto-color-primary, #12B6AF);
502
+ color: var(--xto-color-primary, #4F46E5);
504
503
  }
505
504
  }
506
505
 
@@ -613,8 +612,8 @@ onUnmounted(() => {
613
612
  height: 16px;
614
613
  font-size: 12px;
615
614
  font-weight: 600;
616
- color: var(--xto-color-primary, #12B6AF);
617
- background-color: var(--xto-color-primary-light-8, #DDF6F4);
615
+ color: var(--xto-color-primary, #4F46E5);
616
+ background-color: var(--xto-color-primary-light-8, #DCDAFC);
618
617
  border-radius: var(--xto-border-radius-small, 4px);
619
618
  }
620
619
 
@@ -639,7 +638,7 @@ onUnmounted(() => {
639
638
 
640
639
  &:hover {
641
640
  background-color: var(--xto-fill-color, #F2F3F5);
642
- color: var(--xto-color-primary, #12B6AF);
641
+ color: var(--xto-color-primary, #4F46E5);
643
642
  }
644
643
  }
645
644
 
@@ -686,7 +685,7 @@ onUnmounted(() => {
686
685
  width: 32px;
687
686
  height: 32px;
688
687
  border-radius: 50%;
689
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #2ED3CB));
688
+ background: var(--xto-color-primary, #4F46E5);
690
689
  display: flex;
691
690
  align-items: center;
692
691
  justify-content: center;
@@ -717,7 +716,7 @@ onUnmounted(() => {
717
716
  width: 40px;
718
717
  height: 40px;
719
718
  border-radius: 50%;
720
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #2ED3CB));
719
+ background: var(--xto-color-primary, #4F46E5);
721
720
  display: flex;
722
721
  align-items: center;
723
722
  justify-content: center;
@@ -809,11 +808,11 @@ onUnmounted(() => {
809
808
  transition: all 0.2s;
810
809
 
811
810
  &:hover {
812
- border-color: var(--xto-color-primary-light-5, #A0E8E4);
811
+ border-color: var(--xto-color-primary-light-5, #A7A2F2);
813
812
  }
814
813
 
815
814
  &.is-active {
816
- border-color: var(--xto-color-primary, #12B6AF);
815
+ border-color: var(--xto-color-primary, #4F46E5);
817
816
  background-color: var(--xto-color-primary-light-9, #EAF9F8);
818
817
  }
819
818
 
@@ -839,7 +838,7 @@ onUnmounted(() => {
839
838
  .preview-aside {
840
839
  width: 25%;
841
840
  height: 100%;
842
- background-color: var(--xto-color-primary-light-7, #CFF3F0);
841
+ background-color: var(--xto-color-primary-light-7, #CAC7F9);
843
842
  }
844
843
 
845
844
  .preview-main {
@@ -866,7 +865,7 @@ onUnmounted(() => {
866
865
 
867
866
  .preview-header-full {
868
867
  height: 25%;
869
- background-color: var(--xto-color-primary-light-7, #CFF3F0);
868
+ background-color: var(--xto-color-primary-light-7, #CAC7F9);
870
869
  }
871
870
 
872
871
  .preview-content-full {
@@ -882,12 +881,12 @@ onUnmounted(() => {
882
881
 
883
882
  .preview-header-mix {
884
883
  height: 25%;
885
- background-color: var(--xto-color-primary-light-7, #CFF3F0);
884
+ background-color: var(--xto-color-primary-light-7, #CAC7F9);
886
885
  display: flex;
887
886
 
888
887
  .preview-mix-left {
889
888
  width: 30%;
890
- background-color: var(--xto-color-primary, #12B6AF);
889
+ background-color: var(--xto-color-primary, #4F46E5);
891
890
  }
892
891
  }
893
892
 
@@ -897,7 +896,7 @@ onUnmounted(() => {
897
896
 
898
897
  .preview-mix-aside {
899
898
  width: 25%;
900
- background-color: var(--xto-color-primary-light-8, #DDF6F4);
899
+ background-color: var(--xto-color-primary-light-8, #DCDAFC);
901
900
  }
902
901
 
903
902
  .preview-mix-content {
@@ -927,7 +926,7 @@ onUnmounted(() => {
927
926
  }
928
927
 
929
928
  &.is-active {
930
- box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #12B6AF);
929
+ box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #4F46E5);
931
930
  }
932
931
  }
933
932
 
@@ -978,7 +977,7 @@ onUnmounted(() => {
978
977
 
979
978
  &.is-checked {
980
979
  .switch-core {
981
- background-color: var(--xto-color-primary, #12B6AF);
980
+ background-color: var(--xto-color-primary, #4F46E5);
982
981
 
983
982
  &::after {
984
983
  left: 24px;
@@ -289,11 +289,10 @@ const handleLayoutChange = (mode: LayoutMode) => {
289
289
  // 主题色选项
290
290
  const colorOptions = [
291
291
  { value: '#409eff', label: '默认蓝' },
292
- { value: '#1890ff', label: '科技蓝' },
293
- { value: '#52c41a', label: '极光绿' },
294
- { value: '#faad14', label: '日落橙' },
295
- { value: '#f5222d', label: '薄暮红' },
296
- { value: '#722ed1', label: '酱紫' }
292
+ { value: '#0F6FDE', label: '企业蓝' },
293
+ { value: '#00A870', label: '翡翠绿' },
294
+ { value: '#D46B08', label: '琥珀橙' },
295
+ { value: '#1F2329', label: '石墨黑' }
297
296
  ]
298
297
 
299
298
  // 设置主题色
@@ -448,7 +447,7 @@ onUnmounted(() => {
448
447
  <span>{{ userStore.userName?.charAt(0) || 'U' }}</span>
449
448
  </div>
450
449
  <span class="mix-top-menu__user-name">{{ userStore.userName }}</span>
451
- <span class="mix-top-menu__user-arrow" :class="{ 'is-active': dropdownVisible }">▼</span>
450
+ <span class="mix-top-menu__user-arrow" :class="{ 'is-active': dropdownVisible }"><svg viewBox="0 0 12 12" width="10" height="10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 4.5 6 8l3.5-3.5"/></svg></span>
452
451
  </div>
453
452
 
454
453
  <!-- 下拉菜单 -->
@@ -592,7 +591,7 @@ onUnmounted(() => {
592
591
  &__logo-text {
593
592
  font-size: 16px;
594
593
  font-weight: 600;
595
- color: var(--xto-color-primary, #12B6AF);
594
+ color: var(--xto-color-primary, #4F46E5);
596
595
  }
597
596
 
598
597
  &__menu {
@@ -684,8 +683,8 @@ onUnmounted(() => {
684
683
  height: 16px;
685
684
  font-size: 12px;
686
685
  font-weight: 600;
687
- color: var(--xto-color-primary, #12B6AF);
688
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
686
+ color: var(--xto-color-primary, #4F46E5);
687
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
689
688
  border-radius: var(--xto-border-radius-small, 4px);
690
689
  }
691
690
 
@@ -784,8 +783,8 @@ onUnmounted(() => {
784
783
  height: 16px;
785
784
  font-size: 12px;
786
785
  font-weight: 600;
787
- color: var(--xto-color-primary, #12B6AF);
788
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
786
+ color: var(--xto-color-primary, #4F46E5);
787
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
789
788
  border-radius: var(--xto-border-radius-small, 4px);
790
789
  }
791
790
 
@@ -810,7 +809,7 @@ onUnmounted(() => {
810
809
 
811
810
  &:hover {
812
811
  background-color: var(--xto-fill-color, #EDEEF1);
813
- color: var(--xto-color-primary, #12B6AF);
812
+ color: var(--xto-color-primary, #4F46E5);
814
813
  }
815
814
  }
816
815
 
@@ -857,7 +856,7 @@ onUnmounted(() => {
857
856
  width: 32px;
858
857
  height: 32px;
859
858
  border-radius: 50%;
860
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
859
+ background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #847DEC));
861
860
  display: flex;
862
861
  align-items: center;
863
862
  justify-content: center;
@@ -889,7 +888,7 @@ onUnmounted(() => {
889
888
  width: 40px;
890
889
  height: 40px;
891
890
  border-radius: 50%;
892
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
891
+ background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #847DEC));
893
892
  display: flex;
894
893
  align-items: center;
895
894
  justify-content: center;
@@ -981,11 +980,11 @@ onUnmounted(() => {
981
980
  transition: all 0.2s;
982
981
 
983
982
  &:hover {
984
- border-color: var(--xto-color-primary-light-5, #A5B4FC);
983
+ border-color: var(--xto-color-primary-light-5, #B9B5F5);
985
984
  }
986
985
 
987
986
  &.is-active {
988
- border-color: var(--xto-color-primary, #12B6AF);
987
+ border-color: var(--xto-color-primary, #4F46E5);
989
988
  background-color: var(--xto-color-primary-light-9, #EEF2FF);
990
989
  }
991
990
 
@@ -1059,7 +1058,7 @@ onUnmounted(() => {
1059
1058
 
1060
1059
  .preview-mix-left {
1061
1060
  width: 30%;
1062
- background-color: var(--xto-color-primary, #12B6AF);
1061
+ background-color: var(--xto-color-primary, #4F46E5);
1063
1062
  }
1064
1063
  }
1065
1064
 
@@ -1069,7 +1068,7 @@ onUnmounted(() => {
1069
1068
 
1070
1069
  .preview-mix-aside {
1071
1070
  width: 25%;
1072
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
1071
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
1073
1072
  }
1074
1073
 
1075
1074
  .preview-mix-content {
@@ -1099,7 +1098,7 @@ onUnmounted(() => {
1099
1098
  }
1100
1099
 
1101
1100
  &.is-active {
1102
- box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #12B6AF);
1101
+ box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #4F46E5);
1103
1102
  }
1104
1103
  }
1105
1104
 
@@ -1150,7 +1149,7 @@ onUnmounted(() => {
1150
1149
 
1151
1150
  &.is-checked {
1152
1151
  .switch-core {
1153
- background-color: var(--xto-color-primary, #12B6AF);
1152
+ background-color: var(--xto-color-primary, #4F46E5);
1154
1153
 
1155
1154
  &::after {
1156
1155
  left: 24px;
@@ -107,7 +107,7 @@ watch(displayMenuList, (newList, oldList) => {
107
107
  // 菜单主题相关(浅色模式走 CSS 变量,深色模式保留深底硬编码以配合暗色覆盖)
108
108
  const menuBgColor = computed(() => appStore.isDark ? '#161B21' : '#fff')
109
109
  const menuTextColor = computed(() => appStore.isDark ? '#D9DCE1' : '#4E5566')
110
- const menuActiveTextColor = computed(() => appStore.isDark ? '#2ED3CB' : '#12B6AF')
110
+ const menuActiveTextColor = computed(() => appStore.isDark ? '#818CF8' : '#4F46E5')
111
111
 
112
112
  // 菜单选择
113
113
  const handleMenuSelect = (index: string) => {
@@ -194,7 +194,7 @@ const handleLogout = () => {
194
194
  &__logo-text {
195
195
  font-size: 16px;
196
196
  font-weight: 600;
197
- color: var(--xto-color-primary, #12B6AF);
197
+ color: var(--xto-color-primary, #4F46E5);
198
198
  }
199
199
 
200
200
  &__menu {
@@ -156,8 +156,8 @@ const hasChildren = computed(() => {
156
156
  height: 16px;
157
157
  font-size: 12px;
158
158
  font-weight: 600;
159
- color: var(--xto-color-primary, #12B6AF);
160
- background-color: var(--xto-color-primary-light-8, #DDF6F4);
159
+ color: var(--xto-color-primary, #4F46E5);
160
+ background-color: var(--xto-color-primary-light-8, #DCDAFC);
161
161
  border-radius: var(--xto-border-radius-small, 4px);
162
162
  }
163
163
  </style>
@@ -111,12 +111,12 @@ const handleClose = (path: string) => {
111
111
  transition: color 0.2s;
112
112
 
113
113
  &:hover {
114
- color: var(--xto-color-primary, #12B6AF);
114
+ color: var(--xto-color-primary, #4F46E5);
115
115
  }
116
116
 
117
117
  &.is-active {
118
118
  background-color: transparent;
119
- color: var(--xto-color-primary, #12B6AF);
119
+ color: var(--xto-color-primary, #4F46E5);
120
120
  font-weight: 600;
121
121
 
122
122
  &::after {
@@ -127,7 +127,7 @@ const handleClose = (path: string) => {
127
127
  right: 12px;
128
128
  height: 2px;
129
129
  border-radius: 2px;
130
- background-color: var(--xto-color-primary, #12B6AF);
130
+ background-color: var(--xto-color-primary, #4F46E5);
131
131
  }
132
132
  }
133
133
  }
@@ -233,11 +233,10 @@ const handleLayoutChange = (mode: LayoutMode) => {
233
233
  // 主题色选项
234
234
  const colorOptions = [
235
235
  { value: '#409eff', label: '默认蓝' },
236
- { value: '#1890ff', label: '科技蓝' },
237
- { value: '#52c41a', label: '极光绿' },
238
- { value: '#faad14', label: '日落橙' },
239
- { value: '#f5222d', label: '薄暮红' },
240
- { value: '#722ed1', label: '酱紫' }
236
+ { value: '#0F6FDE', label: '企业蓝' },
237
+ { value: '#00A870', label: '翡翠绿' },
238
+ { value: '#D46B08', label: '琥珀橙' },
239
+ { value: '#1F2329', label: '石墨黑' }
241
240
  ]
242
241
 
243
242
  // 设置主题色
@@ -440,7 +439,7 @@ onUnmounted(() => {
440
439
  <span>{{ userStore.userName?.charAt(0) || 'U' }}</span>
441
440
  </div>
442
441
  <span class="top-menu__user-name">{{ userStore.userName }}</span>
443
- <span class="top-menu__user-arrow" :class="{ 'is-active': dropdownVisible }">▼</span>
442
+ <span class="top-menu__user-arrow" :class="{ 'is-active': dropdownVisible }"><svg viewBox="0 0 12 12" width="10" height="10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 4.5 6 8l3.5-3.5"/></svg></span>
444
443
  </div>
445
444
 
446
445
  <!-- 下拉菜单 -->
@@ -584,7 +583,7 @@ onUnmounted(() => {
584
583
  &__logo-text {
585
584
  font-size: 16px;
586
585
  font-weight: 600;
587
- color: var(--xto-color-primary, #12B6AF);
586
+ color: var(--xto-color-primary, #4F46E5);
588
587
  }
589
588
 
590
589
  &__menu {
@@ -676,8 +675,8 @@ onUnmounted(() => {
676
675
  height: 16px;
677
676
  font-size: 12px;
678
677
  font-weight: 600;
679
- color: var(--xto-color-primary, #12B6AF);
680
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
678
+ color: var(--xto-color-primary, #4F46E5);
679
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
681
680
  border-radius: var(--xto-border-radius-small, 4px);
682
681
  }
683
682
 
@@ -776,8 +775,8 @@ onUnmounted(() => {
776
775
  height: 16px;
777
776
  font-size: 12px;
778
777
  font-weight: 600;
779
- color: var(--xto-color-primary, #12B6AF);
780
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
778
+ color: var(--xto-color-primary, #4F46E5);
779
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
781
780
  border-radius: var(--xto-border-radius-small, 4px);
782
781
  }
783
782
 
@@ -802,7 +801,7 @@ onUnmounted(() => {
802
801
 
803
802
  &:hover {
804
803
  background-color: var(--xto-fill-color, #EDEEF1);
805
- color: var(--xto-color-primary, #12B6AF);
804
+ color: var(--xto-color-primary, #4F46E5);
806
805
  }
807
806
  }
808
807
 
@@ -849,7 +848,7 @@ onUnmounted(() => {
849
848
  width: 32px;
850
849
  height: 32px;
851
850
  border-radius: 50%;
852
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
851
+ background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #847DEC));
853
852
  display: flex;
854
853
  align-items: center;
855
854
  justify-content: center;
@@ -881,7 +880,7 @@ onUnmounted(() => {
881
880
  width: 40px;
882
881
  height: 40px;
883
882
  border-radius: 50%;
884
- background: linear-gradient(135deg, var(--xto-color-primary, #12B6AF), var(--xto-color-primary-light-3, #51DAD3));
883
+ background: linear-gradient(135deg, var(--xto-color-primary, #4F46E5), var(--xto-color-primary-light-3, #847DEC));
885
884
  display: flex;
886
885
  align-items: center;
887
886
  justify-content: center;
@@ -973,11 +972,11 @@ onUnmounted(() => {
973
972
  transition: all 0.2s;
974
973
 
975
974
  &:hover {
976
- border-color: var(--xto-color-primary-light-5, #A5B4FC);
975
+ border-color: var(--xto-color-primary-light-5, #B9B5F5);
977
976
  }
978
977
 
979
978
  &.is-active {
980
- border-color: var(--xto-color-primary, #12B6AF);
979
+ border-color: var(--xto-color-primary, #4F46E5);
981
980
  background-color: var(--xto-color-primary-light-9, #EEF2FF);
982
981
  }
983
982
 
@@ -1051,7 +1050,7 @@ onUnmounted(() => {
1051
1050
 
1052
1051
  .preview-mix-left {
1053
1052
  width: 30%;
1054
- background-color: var(--xto-color-primary, #12B6AF);
1053
+ background-color: var(--xto-color-primary, #4F46E5);
1055
1054
  }
1056
1055
  }
1057
1056
 
@@ -1061,7 +1060,7 @@ onUnmounted(() => {
1061
1060
 
1062
1061
  .preview-mix-aside {
1063
1062
  width: 25%;
1064
- background-color: var(--xto-color-primary-light-8, #C7D2FE);
1063
+ background-color: var(--xto-color-primary-light-8, #CAC7F9);
1065
1064
  }
1066
1065
 
1067
1066
  .preview-mix-content {
@@ -1091,7 +1090,7 @@ onUnmounted(() => {
1091
1090
  }
1092
1091
 
1093
1092
  &.is-active {
1094
- box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #12B6AF);
1093
+ box-shadow: 0 0 0 2px var(--xto-bg-color, #FFFFFF), 0 0 0 4px var(--xto-color-primary, #4F46E5);
1095
1094
  }
1096
1095
  }
1097
1096
 
@@ -1142,7 +1141,7 @@ onUnmounted(() => {
1142
1141
 
1143
1142
  &.is-checked {
1144
1143
  .switch-core {
1145
- background-color: var(--xto-color-primary, #12B6AF);
1144
+ background-color: var(--xto-color-primary, #4F46E5);
1146
1145
 
1147
1146
  &::after {
1148
1147
  left: 24px;
package/src/stores/app.ts CHANGED
@@ -9,6 +9,14 @@ import { local } from '@/utils/storage'
9
9
  export type ThemeMode = 'light' | 'dark'
10
10
  export type LayoutMode = 'sidebar' | 'top' | 'mix'
11
11
 
12
+ /** hex → rgb 数组,非法输入返回 null */
13
+ function hexToRgb(hex: string): [number, number, number] | null {
14
+ const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim())
15
+ if (!m) return null
16
+ const n = parseInt(m[1], 16)
17
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255]
18
+ }
19
+
12
20
  export const useAppStore = defineStore('app', () => {
13
21
  // 状态
14
22
  const appName = ref<string>(local.get<string>('appName') || 'XTO App')
@@ -21,7 +29,7 @@ export const useAppStore = defineStore('app', () => {
21
29
  const showTabs = ref<boolean>(local.get<boolean>('showTabs') ?? true)
22
30
  const showFooter = ref<boolean>(local.get<boolean>('showFooter') ?? true)
23
31
  const showBreadcrumb = ref<boolean>(local.get<boolean>('showBreadcrumb') ?? true)
24
- const primaryColor = ref<string>(local.get<string>('primaryColor') || '#12B6AF')
32
+ const primaryColor = ref<string>(local.get<string>('primaryColor') || '#4F46E5')
25
33
  const cachedViews = ref<string[]>([])
26
34
  const mixSubMenus = ref<any[]>([])
27
35
 
@@ -102,10 +110,26 @@ export const useAppStore = defineStore('app', () => {
102
110
  local.set('showBreadcrumb', showBreadcrumb.value)
103
111
  }
104
112
 
105
- // 设置主题色
113
+ // 设置主题色(同时生成 light-1..9 / dark-1..3 色阶,保证浅色变体跟随)
106
114
  const setPrimaryColor = (color: string) => {
107
115
  primaryColor.value = color
108
- document.documentElement.style.setProperty('--xto-color-primary', color)
116
+ const root = document.documentElement
117
+ root.style.setProperty('--xto-color-primary', color)
118
+ const rgb = hexToRgb(color)
119
+ if (rgb) {
120
+ const mix = (t: number, toWhite: boolean) => {
121
+ const target = toWhite ? [255, 255, 255] : [0, 0, 0]
122
+ const c = rgb.map((v, i) => Math.round(v + (target[i] - v) * t))
123
+ return `#${c.map((v) => v.toString(16).padStart(2, '0')).join('')}`
124
+ }
125
+ for (let n = 1; n <= 9; n++) {
126
+ root.style.setProperty(`--xto-color-primary-light-${n}`, mix(n * 0.1, true))
127
+ }
128
+ root.style.setProperty('--xto-color-primary-dark-1', mix(0.12, false))
129
+ root.style.setProperty('--xto-color-primary-dark-2', mix(0.28, false))
130
+ root.style.setProperty('--xto-color-primary-dark-3', mix(0.45, false))
131
+ root.style.setProperty('--xto-color-ring', color)
132
+ }
109
133
  local.set('primaryColor', color)
110
134
  }
111
135
 
@@ -137,7 +161,7 @@ export const useAppStore = defineStore('app', () => {
137
161
  // 初始化主题
138
162
  const initTheme = () => {
139
163
  updateTheme()
140
- if (primaryColor.value !== '#12B6AF') {
164
+ if (primaryColor.value !== '#4F46E5') {
141
165
  document.documentElement.style.setProperty('--xto-color-primary', primaryColor.value)
142
166
  }
143
167
  }