@jx3box/jx3box-ui 2.2.3 → 2.2.5

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": "@jx3box/jx3box-ui",
3
- "version": "2.2.3",
3
+ "version": "2.2.5",
4
4
  "description": "JX3BOX Vue3 UI",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,9 +1,6 @@
1
1
  <template>
2
- <div
3
- class="flex flex-col items-center justify-between pt-8 text-gray-500 md:flex-row"
4
- style="border-top: 1px solid rgba(55, 65, 81, 1); font-size: 11px"
5
- >
6
- <div class="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 md:justify-start">
2
+ <div class="c-footer-copyright">
3
+ <div class="c-footer-copyright__main">
7
4
  <span>{{
8
5
  $jx3boxT("jx3boxUi.commonFooter.copyright", "© 2019-{year} JX3BOX {poweredBy}", {
9
6
  year: new Date().getFullYear(),
@@ -11,7 +8,7 @@
11
8
  })
12
9
  }}</span>
13
10
  <a
14
- class="text-gray-500 hover:underline"
11
+ class="c-footer-copyright__link c-footer-copyright__link--underline"
15
12
  href="https://beian.miit.gov.cn/"
16
13
  target="_blank"
17
14
  rel="noopener noreferrer"
@@ -19,9 +16,9 @@
19
16
  {{ $jx3boxT("jx3boxUi.commonFooter.icp", "湘ICP备2021002288号") }}
20
17
  </a>
21
18
  </div>
22
- <div class="mt-4 flex items-center space-x-6 md:mt-0">
19
+ <div class="c-footer-copyright__extra">
23
20
  <a
24
- class="text-gray-500 transition-colors hover:text-white"
21
+ class="c-footer-copyright__link"
25
22
  href="https://rx-planet.com/contact"
26
23
  target="_blank"
27
24
  rel="noopener noreferrer"
@@ -29,8 +26,8 @@
29
26
  {{ $jx3boxT("jx3boxUi.commonFooter.contactUs", "联系我们") }}
30
27
  </a>
31
28
  <a
32
- class="text-gray-500 transition-colors hover:text-white"
33
- href="https://www.jx3box.com/dashboard/feedback"
29
+ class="c-footer-copyright__link"
30
+ href="/dashboard/feedback"
34
31
  target="_blank"
35
32
  rel="noopener noreferrer"
36
33
  >
@@ -57,3 +54,65 @@ export default {
57
54
  mounted: function () {},
58
55
  };
59
56
  </script>
57
+
58
+ <style lang="less">
59
+ /* src/footer/copyright.vue */
60
+ .c-footer-copyright {
61
+ display: flex;
62
+ flex-direction: column;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ padding-top: 32px;
66
+ border-top: 1px solid #374151;
67
+ color: #6b7280;
68
+ font-size: 11px;
69
+ line-height: 16px;
70
+
71
+ @media (min-width: 768px) {
72
+ flex-direction: row;
73
+ }
74
+
75
+ &__main,
76
+ &__extra {
77
+ display: flex;
78
+ align-items: center;
79
+ }
80
+
81
+ &__main {
82
+ flex-wrap: wrap;
83
+ justify-content: center;
84
+ gap: 8px 24px;
85
+
86
+ @media (min-width: 768px) {
87
+ justify-content: flex-start;
88
+ }
89
+ }
90
+
91
+ &__extra {
92
+ margin-top: 16px;
93
+
94
+ > * + * {
95
+ margin-left: 24px;
96
+ }
97
+
98
+ @media (min-width: 768px) {
99
+ margin-top: 0;
100
+ }
101
+ }
102
+
103
+ &__link {
104
+ color: #6b7280;
105
+ text-decoration: none;
106
+ transition: color 0.2s ease;
107
+
108
+ &:hover {
109
+ color: #fff;
110
+ }
111
+
112
+ &--underline:hover {
113
+ color: #6b7280;
114
+ text-decoration: underline;
115
+ }
116
+ }
117
+ }
118
+ </style>
@@ -1,15 +1,15 @@
1
1
  <template>
2
- <section class="lg:col-span-4">
3
- <div class="grid grid-cols-1 gap-8 sm:grid-cols-3">
2
+ <section class="c-footer-links">
3
+ <div class="c-footer-links__grid">
4
4
  <div v-for="group in footerGroups" :key="group.title">
5
- <h3 class="text-sm font-semibold tracking-wide text-white">
5
+ <h3 class="c-footer-links__title">
6
6
  {{ $jx3boxT(`jx3boxUi.commonFooter.${group.key}`, group.title) }}
7
7
  </h3>
8
- <div class="mt-4 space-y-3">
8
+ <div class="c-footer-links__list">
9
9
  <a
10
10
  v-for="item in group.links"
11
11
  :key="item.name"
12
- class="block text-xs text-gray-400 transition hover:text-indigo-400"
12
+ class="c-footer-links__link"
13
13
  :href="item.href"
14
14
  target="_blank"
15
15
  rel="noopener noreferrer"
@@ -32,21 +32,21 @@ export default {
32
32
  data: function () {
33
33
  return {
34
34
  aboutLinks: [
35
- { key: "teamMembers", name: "团队成员", href: "https://www.jx3box.com/about/" },
36
- { key: "joinUs", name: "加入我们", href: "https://www.jx3box.com/notice/21899" },
37
- { key: "devDocs", name: "开发文档", href: "https://www.jx3box.com/tool?subtype=4" },
35
+ { key: "teamMembers", name: "团队成员", href: "/about/" },
36
+ { key: "joinUs", name: "加入我们", href: "/notice/21899" },
37
+ { key: "devDocs", name: "开发文档", href: "/tool?subtype=4" },
38
38
  { key: "codeRepo", name: "代码仓库", href: "https://github.com/JX3BOX" },
39
39
  ],
40
40
  legalLinks: [
41
- { key: "userAgreement", name: "用户协议", href: "https://www.jx3box.com/about/license" },
42
- { key: "creatorTreaty", name: "创作公约", href: "https://www.jx3box.com/about/treaty" },
43
- { key: "privacyPolicy", name: "隐私政策", href: "https://www.jx3box.com/about/privacy" },
44
- { key: "creatorIncentives", name: "创作激励", href: "https://www.jx3box.com/about/incentives" },
41
+ { key: "userAgreement", name: "用户协议", href: "/about/license" },
42
+ { key: "creatorTreaty", name: "创作公约", href: "/about/treaty" },
43
+ { key: "privacyPolicy", name: "隐私政策", href: "/about/privacy" },
44
+ { key: "creatorIncentives", name: "创作激励", href: "/about/incentives" },
45
45
  ],
46
46
  extraLinks: [
47
- { key: "gameVersion", name: "游戏版本", href: "https://www.jx3box.com/topic" },
48
- { key: "eventCenter", name: "活动中心", href: "https://www.jx3box.com/event" },
49
- { key: "siteMap", name: "全站地图", href: "https://www.jx3box.com/app/" },
47
+ { key: "gameVersion", name: "游戏版本", href: "/topic" },
48
+ { key: "eventCenter", name: "活动中心", href: "/event" },
49
+ { key: "siteMap", name: "全站地图", href: "/app/" },
50
50
  ],
51
51
  };
52
52
  },
@@ -77,3 +77,52 @@ export default {
77
77
  mounted: function () {},
78
78
  };
79
79
  </script>
80
+
81
+ <style lang="less">
82
+ /* src/footer/links.vue */
83
+ .c-footer-links {
84
+ @media (min-width: 1024px) {
85
+ grid-column: span 4 / span 4;
86
+ }
87
+
88
+ &__grid {
89
+ display: grid;
90
+ grid-template-columns: minmax(0, 1fr);
91
+ gap: 32px;
92
+
93
+ @media (min-width: 640px) {
94
+ grid-template-columns: repeat(3, minmax(0, 1fr));
95
+ }
96
+ }
97
+
98
+ &__title {
99
+ margin: 0;
100
+ color: #fff;
101
+ font-size: 14px;
102
+ font-weight: 600;
103
+ line-height: 20px;
104
+ letter-spacing: 0.025em;
105
+ }
106
+
107
+ &__list {
108
+ margin-top: 16px;
109
+
110
+ > * + * {
111
+ margin-top: 12px;
112
+ }
113
+ }
114
+
115
+ &__link {
116
+ display: block;
117
+ color: #9ca3af;
118
+ font-size: 12px;
119
+ line-height: 16px;
120
+ text-decoration: none;
121
+ transition: color 0.2s ease;
122
+
123
+ &:hover {
124
+ color: #818cf8;
125
+ }
126
+ }
127
+ }
128
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="c-footer-official mt-6 flex flex-wrap gap-3">
2
+ <div class="c-footer-official">
3
3
  <div v-for="item in socials" :key="item.name">
4
4
  <el-popover
5
5
  v-if="item.qrcode"
@@ -9,34 +9,34 @@
9
9
  popper-class="c-footer--v4__popover"
10
10
  @show="handlePopoverShow"
11
11
  >
12
- <div class="flex w-36 flex-col items-center p-3">
12
+ <div class="c-footer-official__qrcode">
13
13
  <img
14
- class="h-32 w-32 rounded-md object-cover"
14
+ class="c-footer-official__qrcode-img"
15
15
  :src="item.qrcode"
16
16
  :alt="getSocialName(item)"
17
17
  @load="handleQrcodeLoad"
18
18
  />
19
- <span class="mt-2 text-xs font-black">{{ item.label || getSocialName(item) }}</span>
19
+ <span class="c-footer-official__qrcode-label">{{ item.label || getSocialName(item) }}</span>
20
20
  </div>
21
21
  <template #reference>
22
22
  <a
23
- class="u-link flex h-11 w-11 items-center justify-center rounded-full border border-gray-700 bg-gray-800 transition"
23
+ class="u-link"
24
24
  :title="item.label"
25
25
  href="javascript:;"
26
26
  >
27
- <img class="h-5 w-5" :src="item.icon" :alt="getSocialName(item)" />
27
+ <img class="u-link__icon" :src="item.icon" :alt="getSocialName(item)" />
28
28
  </a>
29
29
  </template>
30
30
  </el-popover>
31
31
  <a
32
32
  v-else
33
- class="u-link flex h-11 w-11 items-center justify-center rounded-full border border-gray-700 bg-gray-800 transition"
33
+ class="u-link"
34
34
  :href="item.href"
35
35
  target="_blank"
36
36
  rel="noopener noreferrer"
37
37
  :title="item.label"
38
38
  >
39
- <img class="h-5 w-5" :src="item.icon" :alt="getSocialName(item)" />
39
+ <img class="u-link__icon" :src="item.icon" :alt="getSocialName(item)" />
40
40
  </a>
41
41
  </div>
42
42
  </div>
@@ -134,10 +134,53 @@ export default {
134
134
  <style lang="less">
135
135
  /* src/footer/official.vue */
136
136
  .c-footer-official {
137
+ display: flex;
138
+ flex-wrap: wrap;
139
+ gap: 12px;
140
+ margin-top: 24px;
141
+
137
142
  .u-link {
143
+ display: flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+ width: 44px;
147
+ height: 44px;
148
+ border: 1px solid #374151;
149
+ border-radius: 50%;
150
+ background: #1f2937;
151
+ transition: background-color 0.2s ease, border-color 0.2s ease;
152
+
138
153
  &:hover {
139
154
  background-color: rgba(255, 255, 255, 1);
140
155
  }
141
156
  }
157
+
158
+ .u-link__icon {
159
+ display: block;
160
+ width: 20px;
161
+ height: 20px;
162
+ }
163
+
164
+ &__qrcode {
165
+ display: flex;
166
+ flex-direction: column;
167
+ align-items: center;
168
+ width: 144px;
169
+ padding: 12px;
170
+ }
171
+
172
+ &__qrcode-img {
173
+ width: 128px;
174
+ height: 128px;
175
+ border-radius: 6px;
176
+ object-fit: cover;
177
+ }
178
+
179
+ &__qrcode-label {
180
+ margin-top: 8px;
181
+ font-size: 12px;
182
+ font-weight: 900;
183
+ line-height: 16px;
184
+ }
142
185
  }
143
186
  </style>
@@ -1,29 +1,29 @@
1
1
  <template>
2
- <section class="lg:col-span-4 lg:col-start-9">
3
- <h3 class="text-sm font-semibold tracking-wide text-white">
2
+ <section class="c-footer-resource">
3
+ <h3 class="c-footer-resource__title">
4
4
  {{ $jx3boxT("jx3boxUi.commonFooter.downloadCenter", "下载中心") }}
5
5
  </h3>
6
- <div class="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2">
6
+ <div class="c-footer-resource__grid">
7
7
  <div v-for="item in downloadLinks" :key="item.name">
8
8
  <el-popover v-if="item.qrcode" trigger="hover" placement="top" popper-class="c-footer--v4__popover">
9
- <div class="flex flex-col items-center p-3">
9
+ <div class="c-footer-resource__qrcode">
10
10
  <img
11
- class="h-32 w-32 rounded-md object-cover"
11
+ class="c-footer-resource__qrcode-img"
12
12
  :src="item.qrcode"
13
13
  :alt="getDownloadName(item)"
14
14
  />
15
- <span class="mt-2 text-xs font-black">{{ getDownloadLabel(item) }}</span>
15
+ <span class="c-footer-resource__qrcode-label">{{ getDownloadLabel(item) }}</span>
16
16
  </div>
17
17
  <template #reference>
18
18
  <a
19
- class="flex h-12 items-center rounded-xl border border-gray-700 bg-gray-800 px-4 text-xs text-gray-300 transition hover:border-blue-500 hover:bg-gray-700"
19
+ class="c-footer-resource__download"
20
20
  :href="item.href || '#'"
21
21
  :target="item.href ? '_blank' : null"
22
22
  :rel="item.href ? 'noopener noreferrer' : null"
23
23
  @click="handleLinkClick($event, item)"
24
24
  >
25
- <span class="mr-2.5 flex h-4 w-4 items-center justify-center">
26
- <img class="h-4 w-4" :src="item.icon" :alt="getDownloadName(item)" />
25
+ <span class="c-footer-resource__download-icon">
26
+ <img :src="item.icon" :alt="getDownloadName(item)" />
27
27
  </span>
28
28
  <span>{{ getDownloadName(item) }}</span>
29
29
  </a>
@@ -36,19 +36,19 @@
36
36
  :show-after="150"
37
37
  popper-class="c-footer--v4__popover"
38
38
  >
39
- <div class="p-3 text-center text-xs font-semibold">
39
+ <div class="c-footer-resource__placeholder">
40
40
  {{ item.placeholder }}
41
41
  </div>
42
42
  <template #reference>
43
43
  <a
44
- class="flex h-12 items-center rounded-xl border border-gray-700 bg-gray-800 px-4 text-xs text-gray-300 transition hover:border-blue-500 hover:bg-gray-700"
44
+ class="c-footer-resource__download"
45
45
  :href="item.href || '#'"
46
46
  :target="item.href ? '_blank' : null"
47
47
  :rel="item.href ? 'noopener noreferrer' : null"
48
48
  @click="handleLinkClick($event, item)"
49
49
  >
50
- <span class="mr-2.5 flex h-4 w-4 items-center justify-center">
51
- <img class="h-4 w-4" :src="item.icon" :alt="getDownloadName(item)" />
50
+ <span class="c-footer-resource__download-icon">
51
+ <img :src="item.icon" :alt="getDownloadName(item)" />
52
52
  </span>
53
53
  <span>{{ getDownloadName(item) }}</span>
54
54
  </a>
@@ -56,49 +56,41 @@
56
56
  </el-popover>
57
57
  <a
58
58
  v-else
59
- class="flex h-12 items-center rounded-xl border border-gray-700 bg-gray-800 px-4 text-xs text-gray-300 transition hover:border-blue-500 hover:bg-gray-700"
59
+ class="c-footer-resource__download"
60
60
  :href="item.href || '#'"
61
61
  :target="item.href ? '_blank' : null"
62
62
  :rel="item.href ? 'noopener noreferrer' : null"
63
63
  @click="handleLinkClick($event, item)"
64
64
  >
65
- <span class="mr-2.5 flex h-4 w-4 items-center justify-center">
66
- <img class="h-4 w-4" :src="item.icon" :alt="getDownloadName(item)" />
65
+ <span class="c-footer-resource__download-icon">
66
+ <img :src="item.icon" :alt="getDownloadName(item)" />
67
67
  </span>
68
68
  <span>{{ getDownloadName(item) }}</span>
69
69
  </a>
70
70
  </div>
71
71
  </div>
72
72
 
73
- <div
74
- class="mt-4 flex items-center justify-between rounded-xl border p-4"
75
- style="
76
- border-color: rgba(59, 130, 246, 0.2);
77
- background-image: linear-gradient(90deg, rgba(30, 64, 175, 0.2), rgba(31, 41, 55, 0.4));
78
- "
79
- >
80
- <div class="flex items-center space-x-3">
73
+ <div class="c-footer-resource__qqbot">
74
+ <div class="c-footer-resource__qqbot-main">
81
75
  <div
82
76
  @click="gotoQQbot"
83
- class="flex h-10 w-10 items-center justify-center rounded-lg text-blue-400 cursor-pointer"
84
- style="background-color: rgba(59, 130, 246, 0.2)"
77
+ class="c-footer-resource__qqbot-icon"
85
78
  >
86
79
  <img
87
- class="h-6 w-6"
88
80
  svg-inline
89
81
  src="../../assets/img/common/qqbot.svg"
90
82
  :alt="$jx3boxT('jx3boxUi.commonFooter.qqBot', 'QQ机器人')"
91
83
  />
92
84
  </div>
93
- <div @click="copyText('3889010020')" class="cursor-pointer">
94
- <p class="font-bold uppercase tracking-wider text-gray-500" style="font-size: 10px">
85
+ <div @click="copyText('3889010020')" class="c-footer-resource__qqbot-text">
86
+ <p class="c-footer-resource__qqbot-label">
95
87
  {{ $jx3boxT("jx3boxUi.commonFooter.qqBotService", "QQ 机器人服务") }}
96
88
  </p>
97
- <p class="mt-1 font-mono text-sm font-semibold text-white">3889 010 020</p>
89
+ <p class="c-footer-resource__qqbot-number">3889 010 020</p>
98
90
  </div>
99
91
  </div>
100
92
  <a
101
- class="rounded-md bg-blue-600 px-3 py-1.5 text-xs font-medium text-white transition hover:bg-blue-500"
93
+ class="c-footer-resource__qqbot-button"
102
94
  href="tencent://AddContact/?uin=3889010020&Site=www.jx3box.com&Menu=yes"
103
95
  target="_blank"
104
96
  rel="noopener noreferrer"
@@ -184,3 +176,174 @@ export default {
184
176
  mounted: function () {},
185
177
  };
186
178
  </script>
179
+
180
+ <style lang="less">
181
+ /* src/footer/resource.vue */
182
+ .c-footer-resource {
183
+ @media (min-width: 1024px) {
184
+ grid-column: 9 / span 4;
185
+ }
186
+
187
+ &__title {
188
+ margin: 0;
189
+ color: #fff;
190
+ font-size: 14px;
191
+ font-weight: 600;
192
+ line-height: 20px;
193
+ letter-spacing: 0.025em;
194
+ }
195
+
196
+ &__grid {
197
+ display: grid;
198
+ grid-template-columns: minmax(0, 1fr);
199
+ gap: 12px;
200
+ margin-top: 16px;
201
+
202
+ @media (min-width: 640px) {
203
+ grid-template-columns: repeat(2, minmax(0, 1fr));
204
+ }
205
+ }
206
+
207
+ &__qrcode {
208
+ display: flex;
209
+ flex-direction: column;
210
+ align-items: center;
211
+ padding: 12px;
212
+ }
213
+
214
+ &__qrcode-img {
215
+ width: 128px;
216
+ height: 128px;
217
+ border-radius: 6px;
218
+ object-fit: cover;
219
+ }
220
+
221
+ &__qrcode-label {
222
+ margin-top: 8px;
223
+ font-size: 12px;
224
+ font-weight: 900;
225
+ line-height: 16px;
226
+ }
227
+
228
+ &__placeholder {
229
+ padding: 12px;
230
+ text-align: center;
231
+ font-size: 12px;
232
+ font-weight: 600;
233
+ line-height: 16px;
234
+ }
235
+
236
+ &__download {
237
+ display: flex;
238
+ align-items: center;
239
+ height: 48px;
240
+ padding: 0 16px;
241
+ border: 1px solid #374151;
242
+ border-radius: 12px;
243
+ background: #1f2937;
244
+ color: #d1d5db;
245
+ font-size: 12px;
246
+ line-height: 16px;
247
+ text-decoration: none;
248
+ transition: background-color 0.2s ease, border-color 0.2s ease;
249
+
250
+ &:hover {
251
+ border-color: #3b82f6;
252
+ background: #374151;
253
+ }
254
+ }
255
+
256
+ &__download-icon {
257
+ display: flex;
258
+ align-items: center;
259
+ justify-content: center;
260
+ width: 16px;
261
+ height: 16px;
262
+ margin-right: 10px;
263
+
264
+ img {
265
+ display: block;
266
+ width: 16px;
267
+ height: 16px;
268
+ }
269
+ }
270
+
271
+ &__qqbot {
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: space-between;
275
+ margin-top: 16px;
276
+ padding: 16px;
277
+ border: 1px solid rgba(59, 130, 246, 0.2);
278
+ border-radius: 12px;
279
+ background-image: linear-gradient(90deg, rgba(30, 64, 175, 0.2), rgba(31, 41, 55, 0.4));
280
+ }
281
+
282
+ &__qqbot-main {
283
+ display: flex;
284
+ align-items: center;
285
+
286
+ > * + * {
287
+ margin-left: 12px;
288
+ }
289
+ }
290
+
291
+ &__qqbot-icon {
292
+ display: flex;
293
+ align-items: center;
294
+ justify-content: center;
295
+ width: 40px;
296
+ height: 40px;
297
+ border-radius: 8px;
298
+ background: rgba(59, 130, 246, 0.2);
299
+ color: #60a5fa;
300
+ cursor: pointer;
301
+
302
+ svg,
303
+ img {
304
+ display: block;
305
+ width: 24px;
306
+ height: 24px;
307
+ }
308
+ }
309
+
310
+ &__qqbot-text {
311
+ cursor: pointer;
312
+ }
313
+
314
+ &__qqbot-label {
315
+ margin: 0;
316
+ color: #6b7280;
317
+ font-size: 10px;
318
+ font-weight: 700;
319
+ line-height: 14px;
320
+ letter-spacing: 0.05em;
321
+ text-transform: uppercase;
322
+ }
323
+
324
+ &__qqbot-number {
325
+ margin: 4px 0 0;
326
+ color: #fff;
327
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
328
+ font-size: 14px;
329
+ font-weight: 600;
330
+ line-height: 20px;
331
+ }
332
+
333
+ &__qqbot-button {
334
+ padding: 6px 12px;
335
+ border-radius: 6px;
336
+ background: #2563eb;
337
+ color: #fff;
338
+ font-size: 12px;
339
+ font-weight: 500;
340
+ line-height: 16px;
341
+ text-decoration: none;
342
+ transition: background-color 0.2s ease;
343
+
344
+ &:hover {
345
+ background: #3b82f6;
346
+ }
347
+ }
348
+ }
349
+ </style>
@@ -1,19 +1,19 @@
1
1
  <template>
2
- <div class="relative h-full c-header-client" ref="dropdown">
2
+ <div class="c-header-client" ref="dropdown">
3
3
  <!-- 当前选择展示 (触发器) -->
4
4
  <button
5
5
  type="button"
6
- class="u-trigger h-full px-4 flex items-center gap-2 transition-colors duration-200"
6
+ class="u-trigger"
7
7
  :class="{ 'is-active': isMenuOpen }"
8
8
  @click="toggleMenu"
9
9
  :aria-expanded="isMenuOpen"
10
10
  aria-haspopup="true"
11
11
  >
12
12
  <div class="u-client--current">
13
- <span class="text-sm font-medium text-gray-200">{{ currentGameLabel }}</span>
13
+ <span>{{ currentGameLabel }}</span>
14
14
  <svg
15
- class="w-3 h-3 text-gray-400 transition-transform duration-300"
16
- :class="{ 'rotate-180': isMenuOpen }"
15
+ class="u-arrow"
16
+ :class="{ 'is-open': isMenuOpen }"
17
17
  viewBox="0 0 20 20"
18
18
  fill="currentColor"
19
19
  aria-hidden="true"
@@ -29,67 +29,64 @@
29
29
 
30
30
  <!-- 下拉菜单内容 -->
31
31
  <div
32
- class="absolute top-full left-0 w-56 bg-[#242424] border border-gray-700 rounded-b-lg shadow-2xl py-2 overflow-hidden z-50 transition duration-200 ease-out origin-top"
32
+ class="u-menu"
33
33
  :class="{
34
- 'opacity-100 translate-y-0 visible pointer-events-auto': isMenuOpen,
35
- 'opacity-0 -translate-y-2 invisible pointer-events-none': !isMenuOpen
34
+ 'is-open': isMenuOpen
36
35
  }"
37
36
  role="menu"
38
37
  >
39
- <div class="px-3 py-2 text-[10px] text-gray-500 uppercase tracking-widest border-b border-gray-800 mb-1">
38
+ <div class="u-menu__title">
40
39
  {{ $jx3boxT("jx3boxUi.commonHeader.chooseGameVersion", "选择游戏版本") }}
41
40
  </div>
42
41
 
43
42
  <!-- 剑网3 -->
44
43
  <a
45
44
  href="javascript:void(0)"
46
- class="flex items-center justify-between px-4 py-3 hover:bg-indigo-600 active:bg-indigo-700 transition-colors group/item"
45
+ class="u-menu__item"
47
46
  role="menuitem"
48
47
  @click.prevent="switchGame('std')"
49
48
  >
50
- <div class="flex items-center">
51
- <span class="mr-3 text-indigo-400 group-hover/item:text-white">
49
+ <div class="u-game">
50
+ <span class="u-game__icon u-game__icon--std">
52
51
  <img
53
- class="w-4 h-4"
54
52
  svg-inline
55
53
  src="../../assets/img/common/jx3-www.svg"
56
54
  :alt="$jx3boxT('jx3boxUi.commonHeader.jx3Full', '剑网3 / 无界')"
57
55
  />
58
56
  </span>
59
- <div>
60
- <div class="text-sm font-bold text-gray-200 group-hover/item:text-white">
57
+ <div class="u-game__text">
58
+ <div class="u-game__name">
61
59
  {{ $jx3boxT("jx3boxUi.commonHeader.jx3Full", "剑网3 / 无界") }}
62
60
  </div>
63
- <div class="text-[10px] text-gray-500 group-hover/item:text-indigo-200">www.jx3box.com</div>
61
+ <div class="u-game__host">www.jx3box.com</div>
64
62
  </div>
65
63
  </div>
66
- <span class="h-2 w-2 bg-amber-400 rounded-full" :class="{ hidden: activeKey !== 'std' }"></span>
64
+ <span class="u-dot" :class="{ 'is-hidden': activeKey !== 'std' }"></span>
67
65
  </a>
68
66
 
69
67
  <!-- 缘起 -->
70
68
  <a
71
69
  href="javascript:void(0)"
72
- class="flex items-center justify-between px-4 py-3 hover:bg-indigo-600 active:bg-indigo-700 transition-colors group/item"
70
+ class="u-menu__item"
73
71
  role="menuitem"
74
72
  @click.prevent="switchGame('origin')"
75
73
  >
76
- <div class="flex items-center">
77
- <span class="mr-3 text-amber-400 group-hover/item:text-white">
74
+ <div class="u-game">
75
+ <span class="u-game__icon u-game__icon--origin">
78
76
  <img
79
- class="w-4 h-4"
80
77
  svg-inline
81
78
  src="../../assets/img/common/jx3-origin.svg"
82
79
  :alt="$jx3boxT('jx3boxUi.commonHeader.originFull', '剑网3·缘起')"
83
80
  />
84
81
  </span>
85
- <div>
86
- <div class="text-sm font-bold text-gray-200 group-hover/item:text-white">
82
+ <div class="u-game__text">
83
+ <div class="u-game__name">
87
84
  {{ $jx3boxT("jx3boxUi.commonHeader.originFull", "剑网3·缘起") }}
88
85
  </div>
89
- <div class="text-[10px] text-gray-500 group-hover/item:text-indigo-200">origin.jx3box.com</div>
86
+ <div class="u-game__host">origin.jx3box.com</div>
90
87
  </div>
91
88
  </div>
92
- <span class="h-2 w-2 bg-amber-400 rounded-full" :class="{ hidden: activeKey !== 'origin' }"></span>
89
+ <span class="u-dot" :class="{ 'is-hidden': activeKey !== 'origin' }"></span>
93
90
  </a>
94
91
  </div>
95
92
  </div>
@@ -169,8 +166,22 @@ export default {
169
166
  <style lang="less">
170
167
  /* src/header/client.vue */
171
168
  .c-header-client {
169
+ .pr;
170
+ height: @header-height;
171
+
172
+ * {
173
+ .pointer;
174
+ }
175
+
172
176
  .u-trigger {
173
177
  .pr;
178
+ height: 100%;
179
+ padding: 0 16px;
180
+ .flex(y);
181
+ gap: 8px;
182
+ border: 0;
183
+ background: transparent;
184
+ color: #fff;
174
185
  // 为iOS添加触摸反馈
175
186
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
176
187
 
@@ -192,34 +203,162 @@ export default {
192
203
  }
193
204
  }
194
205
 
195
- // 桌面端保留hover效果
196
- //@media (hover: hover) and (pointer: fine) {
197
- // &:hover .u-trigger::after {
198
- // opacity: 1;
199
- // }
200
- //}
201
- height: @header-height;
202
- * {
203
- .pointer;
204
- }
205
-
206
206
  .u-client--current {
207
207
  background-color: @v4primary500;
208
208
  .r(4px);
209
209
  padding: 2px 5px;
210
210
  .flex(y);
211
+ gap: 4px;
212
+ white-space: nowrap;
211
213
 
212
214
  span {
213
215
  color: #fff !important;
216
+ font-size: 14px;
217
+ font-weight: 500;
218
+ line-height: 20px;
214
219
  }
215
- svg {
220
+ .u-arrow {
221
+ width: 12px;
222
+ height: 12px;
216
223
  fill: #fff !important;
224
+ transition: transform 0.3s ease;
225
+
226
+ &.is-open {
227
+ transform: rotate(180deg);
228
+ }
229
+ }
230
+ }
231
+
232
+ .u-menu {
233
+ .pa;
234
+ top: 100%;
235
+ left: 0;
236
+ z-index: 50;
237
+ width: 224px;
238
+ padding: 8px 0;
239
+ overflow: hidden;
240
+ background: #242424;
241
+ border: 1px solid #374151;
242
+ border-top: 0;
243
+ border-radius: 0 0 8px 8px;
244
+ box-shadow: 0 18px 32px rgba(0, 0, 0, 0.32);
245
+ transform: translateY(-8px);
246
+ transform-origin: top;
247
+ opacity: 0;
248
+ visibility: hidden;
249
+ pointer-events: none;
250
+ transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
251
+
252
+ &.is-open {
253
+ transform: translateY(0);
254
+ opacity: 1;
255
+ visibility: visible;
256
+ pointer-events: auto;
257
+ }
258
+ }
259
+
260
+ .u-menu__title {
261
+ padding: 8px 12px;
262
+ margin-bottom: 4px;
263
+ color: #6b7280;
264
+ border-bottom: 1px solid #1f2937;
265
+ font-size: 10px;
266
+ line-height: 14px;
267
+ letter-spacing: 0.08em;
268
+ text-transform: uppercase;
269
+ }
270
+
271
+ .u-menu__item {
272
+ .flex;
273
+ align-items: center;
274
+ justify-content: space-between;
275
+ gap: 12px;
276
+ padding: 12px 16px;
277
+ color: #e5e7eb;
278
+ text-decoration: none;
279
+ transition: background-color 0.2s ease, color 0.2s ease;
280
+
281
+ &:hover,
282
+ &:active {
283
+ background-color: rgb(79, 70, 229);
284
+ color: #fff;
285
+
286
+ .u-game__name {
287
+ color: #fff;
288
+ }
289
+
290
+ .u-game__host {
291
+ color: #c7d2fe;
292
+ }
293
+
294
+ .u-game__icon {
295
+ color: #fff;
296
+ }
297
+ }
298
+ }
299
+
300
+ .u-game {
301
+ .flex(y);
302
+ min-width: 0;
303
+ }
304
+
305
+ .u-game__icon {
306
+ .flex(x);
307
+ flex: 0 0 auto;
308
+ width: 16px;
309
+ height: 16px;
310
+ margin-right: 12px;
311
+
312
+ &,
313
+ svg,
314
+ img {
315
+ width: 16px !important;
316
+ height: 16px !important;
317
+ }
318
+
319
+ svg,
320
+ img {
321
+ display: block;
322
+ }
323
+
324
+ &--std {
325
+ color: #818cf8;
217
326
  }
327
+
328
+ &--origin {
329
+ color: #fbbf24;
330
+ }
331
+ }
332
+
333
+ .u-game__text {
334
+ min-width: 0;
218
335
  }
219
336
 
220
- // 为iOS添加active状态样式
221
- a[role="menuitem"]:active {
222
- background-color: rgb(79, 70, 229) !important;
337
+ .u-game__name {
338
+ color: #e5e7eb;
339
+ font-size: 14px;
340
+ font-weight: 700;
341
+ line-height: 20px;
342
+ white-space: nowrap;
343
+ }
344
+
345
+ .u-game__host {
346
+ color: #6b7280;
347
+ font-size: 10px;
348
+ line-height: 14px;
349
+ white-space: nowrap;
350
+ }
351
+
352
+ .u-dot {
353
+ flex: 0 0 auto;
354
+ width: 8px;
355
+ height: 8px;
356
+ border-radius: 50%;
357
+ background: #fbbf24;
358
+
359
+ &.is-hidden {
360
+ visibility: hidden;
361
+ }
223
362
  }
224
363
  }
225
364
  </style>