@jx3box/jx3box-ui 2.3.21 → 2.3.23
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/assets/css/wiki/wiki-comments.less +239 -0
- package/assets/css/wiki/wiki-panel.less +291 -0
- package/assets/css/wiki/wiki-revisions.less +78 -0
- package/assets/img/common/jx3-origin_bak.svg +15 -0
- package/assets/img/common/jx3-www_bak.svg +9 -0
- package/i18n/messages/en-US.js +5 -1
- package/i18n/messages/vi.js +10 -1
- package/i18n/messages/zh-CN.js +5 -1
- package/i18n/messages/zh-TW.js +5 -1
- package/package.json +2 -1
- package/service/admin.js +9 -1
- package/src/App.vue +53 -10
- package/src/bread/Admin.vue +25 -7
- package/src/comment/CommentContent.vue +9 -0
- package/src/interact/QRcode.vue +21 -3
- package/src/single/Creators.vue +2 -4
- package/src/wiki/GamePrice.vue +68 -11
- package/src/wiki/WikiComment.vue +46 -15
- package/src/wiki/WikiComments.vue +19 -4
- package/src/wiki/WikiPanel.vue +22 -4
- package/src/wiki/WikiRevisions.vue +6 -1
- package/tests/wiki-i18n-contract.test.js +113 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<WikiPanel class="c-wiki-comments" scene="detail">
|
|
2
|
+
<WikiPanel class="c-wiki-comments" scene="detail" :variant="variant">
|
|
3
3
|
<template #head-title>
|
|
4
4
|
<i class="u-icon el-icon-chat-line-round"></i>
|
|
5
5
|
<span class="u-txt">{{ $jx3boxT('jx3boxUi.wikiComments.title', '百科评论') }}</span>
|
|
@@ -29,10 +29,18 @@
|
|
|
29
29
|
<i class="el-icon-chat-dot-round"></i>
|
|
30
30
|
<span>{{ $jx3boxT('jx3boxUi.wiki.reply', '回复') }}</span>
|
|
31
31
|
</h4>
|
|
32
|
-
<textarea
|
|
32
|
+
<textarea
|
|
33
|
+
class="u-reply-content"
|
|
34
|
+
v-model="reply_form.content"
|
|
35
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.reply', '回复')"
|
|
36
|
+
></textarea>
|
|
33
37
|
<div class="u-author">
|
|
34
38
|
<span>{{ $jx3boxT('jx3boxUi.wiki.nickname', '昵称:') }}</span>
|
|
35
|
-
<input
|
|
39
|
+
<input
|
|
40
|
+
v-model="reply_form.user_nickname"
|
|
41
|
+
type="text"
|
|
42
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.nickname', '昵称:')"
|
|
43
|
+
/>
|
|
36
44
|
</div>
|
|
37
45
|
<el-button type="primary" class="u-submit" @click="create_comment(reply_form)">
|
|
38
46
|
<i class="el-icon-check"></i>
|
|
@@ -61,6 +69,11 @@ export default {
|
|
|
61
69
|
type: [Number, String],
|
|
62
70
|
default: 0,
|
|
63
71
|
},
|
|
72
|
+
variant: {
|
|
73
|
+
type: String,
|
|
74
|
+
default: "default",
|
|
75
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
76
|
+
},
|
|
64
77
|
},
|
|
65
78
|
data() {
|
|
66
79
|
return {
|
|
@@ -163,7 +176,9 @@ export default {
|
|
|
163
176
|
});
|
|
164
177
|
},
|
|
165
178
|
getDefaultNickname() {
|
|
166
|
-
return User.isLogin()
|
|
179
|
+
return User.isLogin()
|
|
180
|
+
? User.getInfo().name
|
|
181
|
+
: this.$jx3boxT("jx3boxUi.wiki.mysterious", "神秘侠士");
|
|
167
182
|
},
|
|
168
183
|
handleCurrentChange(page) {
|
|
169
184
|
this.page = page;
|
package/src/wiki/WikiPanel.vue
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
class="c-wiki-panel"
|
|
4
|
-
:class="
|
|
5
|
-
border: border,
|
|
6
|
-
}"
|
|
4
|
+
:class="rootClasses"
|
|
7
5
|
>
|
|
8
6
|
<div class="m-panel-head">
|
|
9
7
|
<slot name="head-before"></slot>
|
|
@@ -11,7 +9,13 @@
|
|
|
11
9
|
<slot name="head-title"></slot>
|
|
12
10
|
</div>
|
|
13
11
|
<div class="m-panel-actions">
|
|
14
|
-
<QRcode
|
|
12
|
+
<QRcode
|
|
13
|
+
v-if="wikiPost && showQR"
|
|
14
|
+
class="u-qr"
|
|
15
|
+
:trigger-text="$jx3boxT('jx3boxUi.wikiPanel.qrTrigger', '二维码')"
|
|
16
|
+
:popup-text="$jx3boxT('jx3boxUi.wikiPanel.qrScanToVisit', '扫一扫即可访问')"
|
|
17
|
+
popup-class="u-wiki-panel-qrcode-popup"
|
|
18
|
+
/>
|
|
15
19
|
<slot name="head-actions"></slot>
|
|
16
20
|
</div>
|
|
17
21
|
<slot name="head-after"></slot>
|
|
@@ -72,6 +76,11 @@ export default {
|
|
|
72
76
|
type: String,
|
|
73
77
|
default: "default",
|
|
74
78
|
},
|
|
79
|
+
variant: {
|
|
80
|
+
type: String,
|
|
81
|
+
default: "default",
|
|
82
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
83
|
+
},
|
|
75
84
|
border: {
|
|
76
85
|
type: Boolean,
|
|
77
86
|
default: true,
|
|
@@ -86,6 +95,15 @@ export default {
|
|
|
86
95
|
stat: null,
|
|
87
96
|
};
|
|
88
97
|
},
|
|
98
|
+
computed: {
|
|
99
|
+
rootClasses() {
|
|
100
|
+
return {
|
|
101
|
+
border: this.border,
|
|
102
|
+
[`is-${this.variant}`]: true,
|
|
103
|
+
[`is-scene-${this.scene}`]: true,
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
},
|
|
89
107
|
watch: {
|
|
90
108
|
wikiPost: {
|
|
91
109
|
immediate: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<WikiPanel class="c-wiki-revisions" scene="detail">
|
|
2
|
+
<WikiPanel class="c-wiki-revisions" scene="detail" :variant="variant">
|
|
3
3
|
<template #head-title>
|
|
4
4
|
<i class="u-icon el-icon-time"></i>
|
|
5
5
|
<span class="u-txt">{{ $jx3boxT('jx3boxUi.wikiRevisions.title', '历史版本') }}</span>
|
|
@@ -62,6 +62,11 @@ export default {
|
|
|
62
62
|
type: [Boolean, Number],
|
|
63
63
|
default: false,
|
|
64
64
|
},
|
|
65
|
+
variant: {
|
|
66
|
+
type: String,
|
|
67
|
+
default: "default",
|
|
68
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
69
|
+
},
|
|
65
70
|
},
|
|
66
71
|
data: function () {
|
|
67
72
|
return {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const assert = require("node:assert/strict");
|
|
2
|
+
const test = require("node:test");
|
|
3
|
+
|
|
4
|
+
require("@babel/register")({
|
|
5
|
+
babelrc: false,
|
|
6
|
+
configFile: false,
|
|
7
|
+
extensions: [".js"],
|
|
8
|
+
ignore: [/node_modules/],
|
|
9
|
+
plugins: ["@babel/plugin-transform-modules-commonjs"],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
createJx3boxUiI18n,
|
|
14
|
+
getJx3boxUiMessages,
|
|
15
|
+
mergeJx3boxUiMessages,
|
|
16
|
+
setJx3boxUiI18n,
|
|
17
|
+
} = require("../i18n");
|
|
18
|
+
const i18nMixin = require("../i18n/mixin").default;
|
|
19
|
+
const { createI18n } = require("vue-i18n");
|
|
20
|
+
|
|
21
|
+
const TARGET_PREFIXES = [
|
|
22
|
+
"wiki.",
|
|
23
|
+
"wikiPanel.",
|
|
24
|
+
"wikiComments.",
|
|
25
|
+
"wikiComment.",
|
|
26
|
+
"wikiRevisions.",
|
|
27
|
+
"gamePrice.",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function flattenMessages(value, prefix = "", output = {}) {
|
|
31
|
+
Object.entries(value || {}).forEach(([key, child]) => {
|
|
32
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
33
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
34
|
+
flattenMessages(child, path, output);
|
|
35
|
+
} else {
|
|
36
|
+
output[path] = child;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return output;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function placeholders(value) {
|
|
43
|
+
return [...String(value ?? "").matchAll(/\{(\w+)\}/g)].map((match) => match[1]).sort();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
test("loads the target component messages for each supported locale", () => {
|
|
47
|
+
const messages = getJx3boxUiMessages();
|
|
48
|
+
Object.entries(messages).forEach(([locale, message]) => {
|
|
49
|
+
const flattened = flattenMessages(message);
|
|
50
|
+
TARGET_PREFIXES.forEach((prefix) => {
|
|
51
|
+
assert.ok(
|
|
52
|
+
Object.keys(flattened).some((key) => key.startsWith(prefix)),
|
|
53
|
+
`${locale} is missing ${prefix}`
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const i18n = createJx3boxUiI18n({ locale: "en-US" });
|
|
59
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiComment.setTop"), "Pin");
|
|
60
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiPanel.qrTrigger"), "QR code");
|
|
61
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiPanel.qrScanToVisit"), "Scan to open this page");
|
|
62
|
+
assert.equal(i18n.global.t("jx3boxUi.gamePrice.jin"), "gold");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("merges target messages into a host i18n instance", () => {
|
|
66
|
+
const hostI18n = createI18n({
|
|
67
|
+
legacy: false,
|
|
68
|
+
locale: "en-US",
|
|
69
|
+
fallbackLocale: "zh-CN",
|
|
70
|
+
messages: {
|
|
71
|
+
"en-US": {
|
|
72
|
+
host: {
|
|
73
|
+
title: "Host",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
mergeJx3boxUiMessages(hostI18n);
|
|
80
|
+
setJx3boxUiI18n(hostI18n);
|
|
81
|
+
|
|
82
|
+
assert.equal(hostI18n.global.t("host.title"), "Host");
|
|
83
|
+
assert.equal(hostI18n.global.t("jx3boxUi.wikiComments.title"), "Wiki Comments");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("component mixin keeps the explicit fallback when the host misses a key", () => {
|
|
87
|
+
setJx3boxUiI18n(null);
|
|
88
|
+
const context = {
|
|
89
|
+
$t(key) {
|
|
90
|
+
return key;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
assert.equal(
|
|
95
|
+
i18nMixin.methods.$jx3boxT.call(context, "jx3boxUi.missing.example", "欢迎 {name}", { name: "侠士" }),
|
|
96
|
+
"欢迎 侠士"
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("keeps four locale message keys and placeholders aligned", () => {
|
|
101
|
+
const messages = getJx3boxUiMessages();
|
|
102
|
+
const locales = Object.keys(messages);
|
|
103
|
+
const baseline = flattenMessages(messages["zh-CN"]);
|
|
104
|
+
const baselineKeys = Object.keys(baseline).sort();
|
|
105
|
+
|
|
106
|
+
locales.forEach((locale) => {
|
|
107
|
+
const current = flattenMessages(messages[locale]);
|
|
108
|
+
assert.deepEqual(Object.keys(current).sort(), baselineKeys, `${locale} message keys differ from zh-CN`);
|
|
109
|
+
baselineKeys.forEach((key) => {
|
|
110
|
+
assert.deepEqual(placeholders(current[key]), placeholders(baseline[key]), `${locale}:${key} placeholders differ`);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|