vue3-router-tab 1.1.9 → 1.2.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/README.md +1 -1
- package/lib/core/createRouterTabs.ts +2 -1
- package/lib/persistence.ts +9 -1
- package/lib/scss/index.scss +125 -227
- package/lib/scss/variables.scss +1 -1
- package/lib/theme.ts +85 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ The composable also exposes `serialize` / `deserialize` options so you can encry
|
|
|
115
115
|
The plugin initialises a lightweight theme layer on install:
|
|
116
116
|
|
|
117
117
|
- Reads `tab-theme-style` (`'light'`, `'dark'`, or `'system'`; defaults to `'system'`).
|
|
118
|
-
- Reads `tab-theme-primary-color` (defaults to `#
|
|
118
|
+
- Reads `tab-theme-primary-color` (defaults to `#0f172a`).
|
|
119
119
|
- Applies the choice via `data-theme` and `--theme-primary` CSS variables, keeping “system” in sync with OS changes.
|
|
120
120
|
|
|
121
121
|
Override the theme at runtime:
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
CloseTabOptions,
|
|
4
4
|
RouteMatchResult,
|
|
5
5
|
RouterTabsContext,
|
|
6
|
+
RouterTabsMenuPreset,
|
|
6
7
|
RouterTabsOptions,
|
|
7
8
|
RouterTabsSnapshot,
|
|
8
9
|
RouterTabsSnapshotTab,
|
|
@@ -215,7 +216,7 @@ export function createRouterTabs(
|
|
|
215
216
|
return options.defaultRoute
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
async function closeTab(id: string |
|
|
219
|
+
async function closeTab(id: string | null = activeId.value, closeOptions: CloseTabOptions = {}) {
|
|
219
220
|
if (!id) return
|
|
220
221
|
if (!closeOptions.force && options.keepLastTab && tabs.length === 1) {
|
|
221
222
|
throw new Error('[RouterTabs] Unable to close the final tab when keepLastTab is true.')
|
package/lib/persistence.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { onMounted, ref, watch } from 'vue'
|
|
1
|
+
import { nextTick, onMounted, ref, watch } from 'vue'
|
|
2
2
|
import type { RouteLocationRaw } from 'vue-router'
|
|
3
3
|
import { useRouterTabs } from './useRouterTabs'
|
|
4
4
|
import type { RouterTabsSnapshot } from './core/types'
|
|
@@ -108,6 +108,14 @@ export function useRouterTabsPersistence(options: RouterTabsPersistenceOptions =
|
|
|
108
108
|
try {
|
|
109
109
|
hydrating.value = true
|
|
110
110
|
await ctrl.hydrate(initialSnapshot)
|
|
111
|
+
if (initialSnapshot.active) {
|
|
112
|
+
await nextTick()
|
|
113
|
+
const activeTab = ctrl.tabs.find(t => t.to === initialSnapshot.active)
|
|
114
|
+
if (activeTab) {
|
|
115
|
+
ctrl.activeId.value = activeTab.id
|
|
116
|
+
ctrl.current.value = activeTab
|
|
117
|
+
}
|
|
118
|
+
}
|
|
111
119
|
} finally {
|
|
112
120
|
hydrating.value = false
|
|
113
121
|
}
|
package/lib/scss/index.scss
CHANGED
|
@@ -2,64 +2,46 @@
|
|
|
2
2
|
@use "sass:color";
|
|
3
3
|
@use "variables" as *;
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
:
|
|
15
|
-
color-scheme: dark;
|
|
16
|
-
--router-tab-active-border: #ffff;
|
|
17
|
-
--router-tab-background: #{$router-tab-bg-dark};
|
|
18
|
-
--router-tab-foreground: #{$router-tab-text-dark};
|
|
19
|
-
--router-tab-border: #{$router-tab-border-dark};
|
|
20
|
-
--router-tab-header-bg: #{$router-tab-bg-dark};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@media (prefers-color-scheme: dark) {
|
|
24
|
-
:root:not([data-theme]) {
|
|
25
|
-
color-scheme: dark;
|
|
26
|
-
--router-tab-background: #{$router-tab-bg-dark};
|
|
27
|
-
--router-tab-foreground: #{$router-tab-text-dark};
|
|
28
|
-
--router-tab-border: #{$router-tab-border-dark};
|
|
29
|
-
--router-tab-header-bg: #{$router-tab-bg-dark};
|
|
30
|
-
}
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// CSS Custom Properties & Theme System
|
|
7
|
+
// =============================================================================
|
|
8
|
+
|
|
9
|
+
:root {
|
|
10
|
+
|
|
11
|
+
// Layout variables
|
|
12
|
+
--router-tab-header-height: #{$router-tab-header-height};
|
|
13
|
+
--router-tab-padding: #{$router-tab-padding};
|
|
14
|
+
--router-tab-font-size: #{$router-tab-font-size};
|
|
31
15
|
}
|
|
32
16
|
|
|
17
|
+
// =============================================================================
|
|
33
18
|
// Main Component Styles
|
|
19
|
+
// =============================================================================
|
|
20
|
+
|
|
34
21
|
.router-tab {
|
|
35
22
|
display: flex;
|
|
36
23
|
flex-direction: column;
|
|
37
24
|
min-height: 300px;
|
|
38
25
|
background-color: var(--router-tab-background);
|
|
39
|
-
color: var(--router-tab-
|
|
26
|
+
color: var(--router-tab-text);
|
|
40
27
|
|
|
41
28
|
&__header {
|
|
42
29
|
position: relative;
|
|
43
|
-
z-index:
|
|
30
|
+
z-index: 10;
|
|
44
31
|
display: flex;
|
|
45
32
|
flex: none;
|
|
33
|
+
align-items: center;
|
|
46
34
|
box-sizing: border-box;
|
|
47
|
-
height: var(--router-tab-header-height
|
|
35
|
+
height: var(--router-tab-header-height);
|
|
48
36
|
background-color: var(--router-tab-header-bg);
|
|
49
|
-
transition: $router-tab-transition-fast;
|
|
50
37
|
border-bottom: 1px solid var(--router-tab-border);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
&__slot-start,
|
|
54
|
-
&__slot-end {
|
|
55
|
-
display: flex;
|
|
56
|
-
align-items: center;
|
|
38
|
+
transition: $router-tab-transition-fast;
|
|
57
39
|
}
|
|
58
40
|
|
|
59
41
|
&__scroll {
|
|
60
42
|
position: relative;
|
|
61
43
|
flex: 1 1 0px;
|
|
62
|
-
height:
|
|
44
|
+
height: 100%;
|
|
63
45
|
overflow: hidden;
|
|
64
46
|
|
|
65
47
|
&-container {
|
|
@@ -70,40 +52,12 @@
|
|
|
70
52
|
&.is-mobile {
|
|
71
53
|
overflow-x: auto;
|
|
72
54
|
overflow-y: hidden;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
&__scrollbar {
|
|
78
|
-
$h: 3px;
|
|
79
|
-
|
|
80
|
-
position: absolute;
|
|
81
|
-
right: 0;
|
|
82
|
-
bottom: 0;
|
|
83
|
-
left: 0;
|
|
84
|
-
height: $h;
|
|
85
|
-
background-color: rgba(0, 0, 0, 0.1);
|
|
86
|
-
border-radius: $h;
|
|
87
|
-
opacity: 0;
|
|
88
|
-
transition: opacity 0.3s ease-in-out;
|
|
55
|
+
scrollbar-width: none;
|
|
56
|
+
-ms-overflow-style: none;
|
|
89
57
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
&-thumb {
|
|
96
|
-
position: absolute;
|
|
97
|
-
top: 0;
|
|
98
|
-
left: 0;
|
|
99
|
-
height: 100%;
|
|
100
|
-
background-color: rgba(0, 0, 0, 0.1);
|
|
101
|
-
border-radius: $h;
|
|
102
|
-
transition: background-color 0.3s ease-in-out;
|
|
103
|
-
|
|
104
|
-
&:hover,
|
|
105
|
-
.router-tab__scrollbar.is-dragging & {
|
|
106
|
-
background-color: rgba(0, 0, 0, 0.2);
|
|
58
|
+
&::-webkit-scrollbar {
|
|
59
|
+
display: none;
|
|
60
|
+
}
|
|
107
61
|
}
|
|
108
62
|
}
|
|
109
63
|
}
|
|
@@ -123,47 +77,59 @@
|
|
|
123
77
|
display: flex;
|
|
124
78
|
flex: none;
|
|
125
79
|
align-items: center;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
cursor: pointer;
|
|
131
|
-
transition: var(--router-tab-transition, $router-tab-transition);
|
|
132
|
-
user-select: none;
|
|
80
|
+
gap: 0.5rem;
|
|
81
|
+
padding: 0 var(--router-tab-padding);
|
|
82
|
+
color: var(--router-tab-text);
|
|
83
|
+
font-size: var(--router-tab-font-size);
|
|
133
84
|
background-color: transparent;
|
|
85
|
+
border: none;
|
|
134
86
|
border-right: 1px solid var(--router-tab-border);
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
user-select: none;
|
|
89
|
+
transition: var(--router-tab-transition);
|
|
135
90
|
|
|
136
91
|
&:first-child {
|
|
137
92
|
border-left: 1px solid var(--router-tab-border);
|
|
138
93
|
}
|
|
139
94
|
|
|
140
|
-
|
|
95
|
+
&:hover {
|
|
96
|
+
background-color: color-mix(in srgb, var(--router-tab-primary) 4%, transparent);
|
|
141
97
|
color: var(--router-tab-primary);
|
|
142
98
|
}
|
|
143
99
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
&.is-drag-over {
|
|
151
|
-
background: $router-tab-drag-over-bg;
|
|
152
|
-
transition: background 0.15s ease;
|
|
100
|
+
&.is-active {
|
|
101
|
+
background-color: var(--router-tab-active-background);
|
|
102
|
+
color: var(--router-tab-active-text);
|
|
103
|
+
font-weight: 510;
|
|
153
104
|
|
|
154
|
-
&::
|
|
105
|
+
&::after {
|
|
155
106
|
content: "";
|
|
156
107
|
position: absolute;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
background: var(--router-tab-
|
|
108
|
+
bottom: -1px;
|
|
109
|
+
left: 0;
|
|
110
|
+
right: 0;
|
|
111
|
+
height: 2px;
|
|
112
|
+
background-color: var(--router-tab-active-border);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
& + .router-tab__item {
|
|
116
|
+
border-left-color: transparent;
|
|
162
117
|
}
|
|
163
118
|
}
|
|
164
119
|
|
|
165
|
-
|
|
166
|
-
|
|
120
|
+
// Icon styling using the dedicated color
|
|
121
|
+
&-icon {
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
font-size: $router-tab-icon-size;
|
|
124
|
+
color: var(--router-tab-icon-color);
|
|
125
|
+
|
|
126
|
+
.router-tab__item.is-active & {
|
|
127
|
+
color: var(--router-tab-active-text);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.router-tab__item:hover & {
|
|
131
|
+
color: currentColor;
|
|
132
|
+
}
|
|
167
133
|
}
|
|
168
134
|
|
|
169
135
|
&-title {
|
|
@@ -174,125 +140,57 @@
|
|
|
174
140
|
text-overflow: ellipsis;
|
|
175
141
|
}
|
|
176
142
|
|
|
177
|
-
|
|
178
|
-
margin-right: $router-tab-icon-margin;
|
|
179
|
-
font-size: $router-tab-icon-size;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
&:hover,
|
|
183
|
-
&.is-active {
|
|
184
|
-
color: var(--router-tab-active-border);
|
|
185
|
-
|
|
186
|
-
&.is-closable {
|
|
187
|
-
padding: 0
|
|
188
|
-
calc(
|
|
189
|
-
var(--router-tab-padding, #{$router-tab-padding}) -
|
|
190
|
-
(#{$router-tab-close-icon-size} + #{$router-tab-close-icon-margin}) / 2
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.router-tab__item-close {
|
|
195
|
-
width: $router-tab-close-icon-size;
|
|
196
|
-
margin-left: $router-tab-close-icon-margin;
|
|
197
|
-
|
|
198
|
-
&::before,
|
|
199
|
-
&::after {
|
|
200
|
-
background-color: currentColor;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
&.is-active {
|
|
206
|
-
background-color: var(--router-tab-background);
|
|
207
|
-
color: var(--router-tab-active-border);
|
|
208
|
-
border-bottom: 2px solid var(--router-tab-active-border);
|
|
209
|
-
font-weight: 510;
|
|
210
|
-
}
|
|
211
|
-
|
|
143
|
+
// Close button using button colors
|
|
212
144
|
&-close {
|
|
213
|
-
$
|
|
214
|
-
|
|
145
|
+
$close-size: $router-tab-close-icon-size;
|
|
146
|
+
$inner-line: 8px;
|
|
147
|
+
|
|
215
148
|
position: relative;
|
|
216
149
|
display: block;
|
|
217
150
|
width: 0;
|
|
218
|
-
height: $
|
|
219
|
-
|
|
151
|
+
height: $close-size;
|
|
152
|
+
flex-shrink: 0;
|
|
220
153
|
overflow: hidden;
|
|
154
|
+
border: none;
|
|
221
155
|
border-radius: 50%;
|
|
156
|
+
background: var(--router-tab-button-bg);
|
|
157
|
+
color: var(--router-tab-button-color);
|
|
222
158
|
cursor: pointer;
|
|
223
|
-
transition: var(--router-tab-transition
|
|
224
|
-
background: transparent;
|
|
225
|
-
border: none;
|
|
159
|
+
transition: var(--router-tab-transition);
|
|
226
160
|
|
|
227
161
|
&::before,
|
|
228
162
|
&::after {
|
|
229
163
|
position: absolute;
|
|
230
|
-
top:
|
|
164
|
+
top: 50%;
|
|
231
165
|
left: 50%;
|
|
232
166
|
display: block;
|
|
233
|
-
width: $inner;
|
|
167
|
+
width: $inner-line;
|
|
234
168
|
height: 1px;
|
|
235
|
-
margin-left: math.div(-$inner, 2);
|
|
169
|
+
margin-left: math.div(-$inner-line, 2);
|
|
236
170
|
background-color: currentColor;
|
|
237
171
|
transition: background-color 0.2s ease-in-out;
|
|
238
172
|
content: "";
|
|
239
173
|
}
|
|
240
174
|
|
|
241
|
-
&::before {
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
&::after {
|
|
246
|
-
transform: rotate(45deg);
|
|
247
|
-
}
|
|
175
|
+
&::before { transform: translateY(-50%) rotate(-45deg); }
|
|
176
|
+
&::after { transform: translateY(-50%) rotate(45deg); }
|
|
248
177
|
|
|
249
178
|
&:hover {
|
|
250
|
-
background
|
|
251
|
-
|
|
252
|
-
&::before,
|
|
253
|
-
&::after {
|
|
254
|
-
background-color: #fff;
|
|
255
|
-
}
|
|
179
|
+
background: var(--router-tab-active-button-bg);
|
|
180
|
+
color: var(--router-tab-active-button-color);
|
|
256
181
|
}
|
|
257
182
|
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
&__contextmenu {
|
|
261
|
-
position: fixed;
|
|
262
|
-
z-index: 1000;
|
|
263
|
-
min-width: $router-tab-contextmenu-min-width;
|
|
264
|
-
padding: $router-tab-contextmenu-padding;
|
|
265
|
-
font-size: var(--router-tab-font-size, $router-tab-font-size);
|
|
266
|
-
background: var(--router-tab-background);
|
|
267
|
-
border: 1px solid var(--router-tab-border);
|
|
268
|
-
box-shadow: $router-tab-contextmenu-shadow;
|
|
269
|
-
border-radius: $router-tab-contextmenu-border-radius;
|
|
270
|
-
|
|
271
|
-
&-item {
|
|
272
|
-
display: block;
|
|
273
|
-
width: 100%;
|
|
274
|
-
padding: $router-tab-contextmenu-item-padding;
|
|
275
|
-
line-height: $router-tab-contextmenu-item-height;
|
|
276
|
-
text-align: left;
|
|
277
|
-
text-decoration: none;
|
|
278
|
-
background: transparent;
|
|
279
|
-
border: none;
|
|
280
|
-
color: inherit;
|
|
281
|
-
cursor: pointer;
|
|
282
|
-
font: inherit;
|
|
283
|
-
transition: background-color 0.2s ease-in-out;
|
|
284
|
-
border-radius: calc(#{$router-tab-contextmenu-border-radius} - 4px);
|
|
285
183
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
184
|
+
// Show close button on hover/active
|
|
185
|
+
&:hover,
|
|
186
|
+
&.is-active {
|
|
187
|
+
&.is-closable {
|
|
188
|
+
padding-right: calc(var(--router-tab-padding) - #{($router-tab-close-icon-size + $router-tab-close-icon-margin) * 0.5});
|
|
290
189
|
}
|
|
291
190
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
color: var(--router-tab-primary);
|
|
191
|
+
.router-tab__item-close {
|
|
192
|
+
width: $router-tab-close-icon-size;
|
|
193
|
+
margin-left: $router-tab-close-icon-margin;
|
|
296
194
|
}
|
|
297
195
|
}
|
|
298
196
|
}
|
|
@@ -304,44 +202,44 @@
|
|
|
304
202
|
overflow: hidden;
|
|
305
203
|
}
|
|
306
204
|
}
|
|
307
|
-
.router-tab__item.is-active:after {
|
|
308
|
-
display: none !important;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
.router-tab__item.is-active + .router-tab__item {
|
|
312
|
-
border-left-color: transparent;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Transition animations
|
|
316
|
-
.router-tab-zoom-enter-active,
|
|
317
|
-
.router-tab-zoom-leave-active {
|
|
318
|
-
transition: all 0.3s ease;
|
|
319
|
-
}
|
|
320
205
|
|
|
321
|
-
|
|
322
|
-
.router-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
206
|
+
// Context Menu using button colors
|
|
207
|
+
.router-tab__contextmenu {
|
|
208
|
+
position: fixed;
|
|
209
|
+
z-index: 1000;
|
|
210
|
+
min-width: $router-tab-contextmenu-min-width;
|
|
211
|
+
padding: $router-tab-contextmenu-padding;
|
|
212
|
+
font-size: var(--router-tab-font-size);
|
|
213
|
+
background: var(--router-tab-background);
|
|
214
|
+
border: 1px solid var(--router-tab-border);
|
|
215
|
+
border-radius: $router-tab-contextmenu-border-radius;
|
|
216
|
+
box-shadow: $router-tab-contextmenu-shadow;
|
|
217
|
+
|
|
218
|
+
&-item {
|
|
219
|
+
display: block;
|
|
220
|
+
width: 100%;
|
|
221
|
+
padding: $router-tab-contextmenu-item-padding;
|
|
222
|
+
line-height: $router-tab-contextmenu-item-height;
|
|
223
|
+
text-align: left;
|
|
224
|
+
text-decoration: none;
|
|
225
|
+
background: var(--router-tab-button-bg);
|
|
226
|
+
border: none;
|
|
227
|
+
color: var(--router-tab-button-color);
|
|
228
|
+
cursor: pointer;
|
|
229
|
+
font: inherit;
|
|
230
|
+
border-radius: calc(#{$router-tab-contextmenu-border-radius} - 4px);
|
|
231
|
+
transition: all 0.2s ease-in-out;
|
|
232
|
+
|
|
233
|
+
&[aria-disabled="true"] {
|
|
234
|
+
color: color-mix(in srgb, var(--router-tab-text) 40%);
|
|
235
|
+
pointer-events: none;
|
|
236
|
+
cursor: not-allowed;
|
|
237
|
+
}
|
|
343
238
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
239
|
+
&:hover:not([aria-disabled="true"]),
|
|
240
|
+
&:focus-visible {
|
|
241
|
+
background: var(--router-tab-active-button-bg);
|
|
242
|
+
color: var(--router-tab-active-button-color);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
package/lib/scss/variables.scss
CHANGED
|
@@ -26,7 +26,7 @@ $router-tab-icon-size: 14px !default;
|
|
|
26
26
|
$router-tab-icon-margin: 6px !default;
|
|
27
27
|
|
|
28
28
|
// Close icon
|
|
29
|
-
$router-tab-close-icon-size:
|
|
29
|
+
$router-tab-close-icon-size: 12px !default;
|
|
30
30
|
$router-tab-close-icon-margin: 4px !default;
|
|
31
31
|
|
|
32
32
|
// Context menu
|
package/lib/theme.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const STYLE_KEY = 'tab-theme-style'
|
|
2
2
|
const PRIMARY_KEY = 'tab-theme-primary-color'
|
|
3
3
|
const DEFAULT_STYLE: 'light' | 'dark' | 'system' = 'system'
|
|
4
|
-
const DEFAULT_PRIMARY = '#635bff'
|
|
5
4
|
const MEDIA_QUERY = '(prefers-color-scheme: dark)'
|
|
6
5
|
|
|
7
6
|
let mediaListener: ((event: MediaQueryListEvent) => void) | null = null
|
|
@@ -12,11 +11,86 @@ export interface RouterTabsThemeOptions {
|
|
|
12
11
|
defaultStyle?: 'light' | 'dark' | 'system'
|
|
13
12
|
defaultPrimary?: string
|
|
14
13
|
}
|
|
14
|
+
export interface ColorStyle {
|
|
15
|
+
// Core colors
|
|
16
|
+
primary: string;
|
|
17
|
+
background: string;
|
|
18
|
+
text: string;
|
|
19
|
+
border: string;
|
|
20
|
+
|
|
21
|
+
// Interactive states
|
|
22
|
+
activeBackground: string;
|
|
23
|
+
activeText: string;
|
|
24
|
+
activeBorder: string;
|
|
25
|
+
|
|
26
|
+
// Header specific
|
|
27
|
+
headerBackground: string;
|
|
28
|
+
|
|
29
|
+
// Button specific
|
|
30
|
+
buttonBackground: string;
|
|
31
|
+
buttonColor: string;
|
|
32
|
+
activeButtonBackground: string;
|
|
33
|
+
activeButtonColor: string;
|
|
34
|
+
|
|
35
|
+
// Icon specific
|
|
36
|
+
iconColor: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const defaultColors: ColorStyle = {
|
|
40
|
+
primary: "#034960",
|
|
41
|
+
background: "#ffffff",
|
|
42
|
+
text: "#1e293b",
|
|
43
|
+
border: "#e2e8f0",
|
|
44
|
+
|
|
45
|
+
activeBackground: "#034960",
|
|
46
|
+
activeText: "#ffffff",
|
|
47
|
+
activeBorder: "#034960",
|
|
48
|
+
|
|
49
|
+
headerBackground: "#ffff",
|
|
50
|
+
|
|
51
|
+
buttonBackground: "#f8fafc",
|
|
52
|
+
buttonColor: "#034960",
|
|
53
|
+
activeButtonBackground: "#034960",
|
|
54
|
+
activeButtonColor: "#ffffff",
|
|
55
|
+
|
|
56
|
+
iconColor: "#475569",
|
|
57
|
+
}
|
|
15
58
|
|
|
16
|
-
|
|
59
|
+
const defaultDarkColor: ColorStyle = {
|
|
60
|
+
primary: "#38bdf8",
|
|
61
|
+
background: "#0f172a",
|
|
62
|
+
text: "#f1f5f9",
|
|
63
|
+
border: "#334155",
|
|
64
|
+
|
|
65
|
+
activeBackground: "#1e293b",
|
|
66
|
+
activeText: "#38bdf8",
|
|
67
|
+
activeBorder: "#38bdf8",
|
|
68
|
+
|
|
69
|
+
headerBackground: "#0c4a6e", // Darker shade of primary
|
|
70
|
+
|
|
71
|
+
buttonBackground: "#1e293b",
|
|
72
|
+
buttonColor: "#f1f5f9",
|
|
73
|
+
activeButtonBackground: "#38bdf8",
|
|
74
|
+
activeButtonColor: "#0f172a",
|
|
75
|
+
|
|
76
|
+
iconColor: "#cbd5e1",
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function applyPrimary(color: ColorStyle) {
|
|
17
80
|
if (typeof document === 'undefined') return
|
|
18
|
-
|
|
19
|
-
document.documentElement.style.setProperty('--router-tab-primary', color)
|
|
81
|
+
console.log('applyPrimary', color)
|
|
82
|
+
document.documentElement.style.setProperty('--router-tab-primary', color.primary ?? defaultColors.primary)
|
|
83
|
+
document.documentElement.style.setProperty('--router-tab-header-bg', color.headerBackground ?? defaultColors.headerBackground)
|
|
84
|
+
document.documentElement.style.setProperty('--router-tab-background', color.background ?? defaultColors.background)
|
|
85
|
+
document.documentElement.style.setProperty('--router-tab-active-background', color.activeBackground ?? defaultColors.activeBackground)
|
|
86
|
+
document.documentElement.style.setProperty('--router-tab-text', color.text ?? defaultColors.text)
|
|
87
|
+
document.documentElement.style.setProperty('--router-tab-active-text', color.activeText ?? defaultColors.activeText)
|
|
88
|
+
document.documentElement.style.setProperty('--router-tab-border', color.border ?? defaultColors.border)
|
|
89
|
+
document.documentElement.style.setProperty('--router-tab-active-border', color.activeBorder ?? defaultColors.activeBorder)
|
|
90
|
+
document.documentElement.style.setProperty('--router-tab-button-color', color.buttonColor ?? defaultColors.buttonColor)
|
|
91
|
+
document.documentElement.style.setProperty('--router-tab-active-button-color', color.activeButtonColor ?? defaultColors.activeButtonColor)
|
|
92
|
+
document.documentElement.style.setProperty('--router-tab-button-background', color.buttonBackground ?? defaultColors.buttonBackground)
|
|
93
|
+
document.documentElement.style.setProperty('--router-tab-active-button-background', color.activeButtonBackground ?? defaultColors.activeButtonBackground)
|
|
20
94
|
}
|
|
21
95
|
|
|
22
96
|
function applyStyle(style: 'light' | 'dark' | 'system') {
|
|
@@ -48,16 +122,17 @@ export function initRouterTabsTheme(options: RouterTabsThemeOptions = {}) {
|
|
|
48
122
|
|
|
49
123
|
const {
|
|
50
124
|
styleKey = STYLE_KEY,
|
|
51
|
-
primaryKey = PRIMARY_KEY,
|
|
52
125
|
defaultStyle = DEFAULT_STYLE,
|
|
53
|
-
defaultPrimary = DEFAULT_PRIMARY
|
|
54
126
|
} = options
|
|
55
127
|
|
|
56
128
|
const storedStyle = (window.localStorage.getItem(styleKey) as 'light' | 'dark' | 'system' | null) ?? defaultStyle
|
|
57
|
-
const storedPrimary = window.localStorage.getItem(primaryKey) ?? defaultPrimary
|
|
58
129
|
|
|
59
130
|
applyStyle(storedStyle)
|
|
60
|
-
|
|
131
|
+
if (storedStyle === 'dark') {
|
|
132
|
+
applyPrimary(defaultDarkColor)
|
|
133
|
+
} else {
|
|
134
|
+
applyPrimary(defaultColors)
|
|
135
|
+
}
|
|
61
136
|
}
|
|
62
137
|
|
|
63
138
|
export function setRouterTabsTheme(style: 'light' | 'dark' | 'system', options?: RouterTabsThemeOptions) {
|
|
@@ -67,9 +142,9 @@ export function setRouterTabsTheme(style: 'light' | 'dark' | 'system', options?:
|
|
|
67
142
|
applyStyle(style)
|
|
68
143
|
}
|
|
69
144
|
|
|
70
|
-
export function setRouterTabsPrimary(color:
|
|
145
|
+
export function setRouterTabsPrimary(color: ColorStyle, options?: RouterTabsThemeOptions) {
|
|
71
146
|
if (typeof window === 'undefined') return
|
|
72
147
|
const key = options?.primaryKey ?? PRIMARY_KEY
|
|
73
|
-
window.localStorage.setItem(key, color)
|
|
148
|
+
window.localStorage.setItem(key, JSON.stringify(color))
|
|
74
149
|
applyPrimary(color)
|
|
75
150
|
}
|