@jx3box/jx3box-editor 3.2.5 → 3.2.7
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/.storybook/main.js +70 -0
- package/.storybook/middleware.js +73 -0
- package/.storybook/preview.js +90 -0
- package/package.json +9 -1
- package/src/Article.vue +6 -1
- package/src/ArticleMarkdown.vue +1 -1
- package/src/assets/css/markdown/markdown-article.less +13 -13
- package/src/assets/css/markdown/markdown-editor.less +11 -11
- package/src/components/Author.vue +312 -52
- package/src/components/QRcode.vue +1 -1
- package/src/service/cms.js +13 -1
- package/src/storybook/storybook-vars.less +1 -0
- package/src/storybook/storybook.helpers.js +154 -0
- package/stories/components/Author.stories.js +36 -0
- package/stories/components/Avatar.stories.js +55 -0
- package/stories/components/Combo.stories.js +37 -0
- package/stories/components/Letter.stories.js +30 -0
- package/stories/components/PostAuthor.stories.js +32 -0
- package/stories/components/QRcode.stories.js +37 -0
- package/stories/components/SkillMartial.stories.js +31 -0
- package/stories/exports/Article.stories.js +48 -0
- package/stories/exports/BoxResource.stories.js +31 -0
- package/stories/exports/Buff.stories.js +38 -0
- package/stories/exports/GameText.stories.js +38 -0
- package/stories/exports/Item.stories.js +51 -0
- package/stories/exports/ItemSimple.stories.js +50 -0
- package/stories/exports/Markdown.stories.js +46 -0
- package/stories/exports/Npc.stories.js +35 -0
- package/stories/exports/Resource.stories.js +29 -0
- package/stories/exports/Skill.stories.js +38 -0
- package/stories/exports/Tinymce.stories.js +46 -0
- package/stories/exports/Upload.stories.js +41 -0
- package/stories/exports/UploadAlbum.stories.js +31 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- @圈人pop:作者卡片 -->
|
|
3
3
|
<div class="w-author" v-loading="loading">
|
|
4
|
-
<div class="w-author-wrapper el-popover" v-if="data" :style="
|
|
4
|
+
<div class="w-author-wrapper el-popover" :class="{ 'is-no-atcard': !bg }" v-if="data" :style="authorCardStyle">
|
|
5
5
|
<div class="u-author">
|
|
6
6
|
<Avatar
|
|
7
7
|
class="u-avatar"
|
|
8
8
|
:uid="uid"
|
|
9
9
|
:url="data.user_avatar"
|
|
10
|
-
:size="
|
|
10
|
+
:size="60"
|
|
11
11
|
:frame="data.user_avatar_frame"
|
|
12
12
|
/>
|
|
13
13
|
<div class="u-info">
|
|
@@ -58,29 +58,61 @@
|
|
|
58
58
|
</div>
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
61
|
-
<div class="u-
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
61
|
+
<div class="u-author-role" v-if="authorRoles.length">
|
|
62
|
+
<div class="u-author-role-label"></div>
|
|
63
|
+
<div class="u-author-roles">
|
|
64
|
+
<component
|
|
65
|
+
:is="item.url ? 'a' : 'span'"
|
|
66
|
+
class="u-author-role-item"
|
|
67
|
+
:href="item.url"
|
|
68
|
+
:target="item.url ? '_blank' : null"
|
|
69
|
+
:style="roleStyle(item)"
|
|
70
|
+
v-for="item in authorRoles"
|
|
71
|
+
:key="item.key"
|
|
72
|
+
>
|
|
73
|
+
<img class="u-author-role-icon" v-if="item.icon" :src="item.icon" />
|
|
74
|
+
<span class="u-author-role-content">
|
|
75
|
+
<span class="u-author-role-name">{{ item.name }}</span>
|
|
76
|
+
<span class="u-author-role-server" v-if="item.server">@{{ item.server }}</span>
|
|
77
|
+
</span>
|
|
78
|
+
</component>
|
|
79
|
+
</div>
|
|
66
80
|
</div>
|
|
67
81
|
</div>
|
|
68
82
|
</div>
|
|
69
83
|
</template>
|
|
70
84
|
|
|
71
85
|
<script>
|
|
72
|
-
import { authorLink,
|
|
73
|
-
import { getUserInfo, getUserMedals
|
|
74
|
-
import { getDecoration, getDecorationJson } from "../service/cms.js";
|
|
86
|
+
import { authorLink, getMedalLink, showSchoolIcon } from "@jx3box/jx3box-common/js/utils";
|
|
87
|
+
import { getUserInfo, getUserMedals } from "../service/author.js";
|
|
88
|
+
import { getDecoration, getDecorationJson, getUserSkin } from "../service/cms.js";
|
|
75
89
|
import User from "@jx3box/jx3box-common/js/user";
|
|
76
90
|
import JX3BOX from "@jx3box/jx3box-common/data/jx3box.json";
|
|
77
91
|
import Avatar from "./Avatar.vue";
|
|
78
|
-
const
|
|
92
|
+
const ATCARD_CACHE_KEY = "skin_atcard_pc_authorcard_v2_";
|
|
93
|
+
const ATCARD_SUBTYPE = "pc_authorcard";
|
|
79
94
|
const DECORATION_JSON = "decoration_json";
|
|
80
95
|
const DECORATION_KEY = "decoration_me";
|
|
81
96
|
const HONOR_KEY = "honor_me";
|
|
97
|
+
const POSITION_MAP = {
|
|
98
|
+
lt: "left top",
|
|
99
|
+
mt: "center top",
|
|
100
|
+
ct: "center top",
|
|
101
|
+
rt: "right top",
|
|
102
|
+
lm: "left center",
|
|
103
|
+
ml: "left center",
|
|
104
|
+
mm: "center center",
|
|
105
|
+
cm: "center center",
|
|
106
|
+
o: "center center",
|
|
107
|
+
rm: "right center",
|
|
108
|
+
mr: "right center",
|
|
109
|
+
lb: "left bottom",
|
|
110
|
+
mb: "center bottom",
|
|
111
|
+
cb: "center bottom",
|
|
112
|
+
rb: "right bottom",
|
|
113
|
+
};
|
|
82
114
|
|
|
83
|
-
const { __server, __imgPath, __userLevelColor, __cdn, __userLevel } = JX3BOX;
|
|
115
|
+
const { __server, __imgPath, __userLevelColor, __cdn, __Root, __userLevel } = JX3BOX;
|
|
84
116
|
export default {
|
|
85
117
|
name: "Author",
|
|
86
118
|
components: {
|
|
@@ -91,13 +123,17 @@ export default {
|
|
|
91
123
|
type: [String, Number],
|
|
92
124
|
required: true,
|
|
93
125
|
},
|
|
126
|
+
visible: {
|
|
127
|
+
type: Boolean,
|
|
128
|
+
default: true,
|
|
129
|
+
},
|
|
94
130
|
},
|
|
95
131
|
data: () => ({
|
|
96
132
|
data: null,
|
|
97
133
|
medals: [],
|
|
98
|
-
teams: [],
|
|
99
134
|
loading: false,
|
|
100
135
|
bg: "",
|
|
136
|
+
bgPosition: "right top",
|
|
101
137
|
honor: "",
|
|
102
138
|
honorStyle: {},
|
|
103
139
|
}),
|
|
@@ -123,6 +159,18 @@ export default {
|
|
|
123
159
|
isSuperAuthor: function () {
|
|
124
160
|
return !!this.data?.sign;
|
|
125
161
|
},
|
|
162
|
+
authorRoles: function () {
|
|
163
|
+
const roles = this.normalizeRoles(this.data?.public_roles);
|
|
164
|
+
return roles.map(this.normalizeRole).filter((item) => item.name);
|
|
165
|
+
},
|
|
166
|
+
authorCardStyle: function () {
|
|
167
|
+
return this.bg
|
|
168
|
+
? {
|
|
169
|
+
backgroundImage: `url(${this.bg})`,
|
|
170
|
+
backgroundPosition: this.bgPosition,
|
|
171
|
+
}
|
|
172
|
+
: {};
|
|
173
|
+
},
|
|
126
174
|
},
|
|
127
175
|
watch: {
|
|
128
176
|
uid: {
|
|
@@ -130,20 +178,28 @@ export default {
|
|
|
130
178
|
handler(val) {
|
|
131
179
|
if (val) {
|
|
132
180
|
this.loadData();
|
|
133
|
-
this.
|
|
181
|
+
if (this.visible) {
|
|
182
|
+
this.getAtcard();
|
|
183
|
+
}
|
|
134
184
|
// this.getHonor();
|
|
135
185
|
}
|
|
136
186
|
},
|
|
137
187
|
},
|
|
188
|
+
visible: {
|
|
189
|
+
handler(val) {
|
|
190
|
+
if (val && this.uid) {
|
|
191
|
+
this.getAtcard();
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
},
|
|
138
195
|
},
|
|
139
196
|
methods: {
|
|
140
197
|
loadData: function () {
|
|
141
|
-
const promises = [getUserInfo(this.uid), getUserMedals(this.uid)
|
|
198
|
+
const promises = [getUserInfo(this.uid), getUserMedals(this.uid)];
|
|
142
199
|
this.loading = true;
|
|
143
200
|
Promise.all(promises).then((res) => {
|
|
144
201
|
this.data = res[0];
|
|
145
202
|
this.medals = res[1];
|
|
146
|
-
this.teams = res[2];
|
|
147
203
|
this.loading = false;
|
|
148
204
|
});
|
|
149
205
|
},
|
|
@@ -157,36 +213,98 @@ export default {
|
|
|
157
213
|
this.medals = data;
|
|
158
214
|
});
|
|
159
215
|
},
|
|
160
|
-
loadTeams: function () {
|
|
161
|
-
return getUserPublicTeams(this.uid).then((data) => {
|
|
162
|
-
this.teams = data && data.slice(0, 5);
|
|
163
|
-
});
|
|
164
|
-
},
|
|
165
216
|
getAtcard() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
217
|
+
const uid = this.uid;
|
|
218
|
+
this.bg = "";
|
|
219
|
+
this.bgPosition = "right top";
|
|
220
|
+
|
|
221
|
+
const cached = this.getAtcardCache(uid);
|
|
222
|
+
if (cached) {
|
|
223
|
+
this.setAtcardBackground(cached === "no" ? null : cached);
|
|
169
224
|
return;
|
|
170
225
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
226
|
+
|
|
227
|
+
getUserSkin({
|
|
228
|
+
user_id: uid,
|
|
229
|
+
type: "atcard",
|
|
230
|
+
})
|
|
231
|
+
.then((data) => {
|
|
232
|
+
if (this.uid !== uid) return;
|
|
233
|
+
|
|
234
|
+
let rows = data?.data?.data || [];
|
|
235
|
+
let skin = this.selectAtcardSkin(this.flattenUserSkins(rows));
|
|
236
|
+
let image = this.showDecorationImage(skin?.image);
|
|
237
|
+
if (!image) {
|
|
238
|
+
this.setAtcardCache(uid, "no");
|
|
239
|
+
this.bg = "";
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
let payload = {
|
|
243
|
+
image,
|
|
244
|
+
position: this.resolveAtcardPosition(skin?.position),
|
|
245
|
+
};
|
|
246
|
+
this.setAtcardCache(uid, payload);
|
|
247
|
+
this.setAtcardBackground(payload);
|
|
248
|
+
})
|
|
249
|
+
.catch(() => {
|
|
250
|
+
if (this.uid === uid) {
|
|
251
|
+
this.bg = "";
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
setAtcardBackground(val) {
|
|
256
|
+
if (typeof val === "string") {
|
|
257
|
+
this.bg = val || "";
|
|
258
|
+
this.bgPosition = "right top";
|
|
174
259
|
return;
|
|
175
260
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
261
|
+
this.bg = val?.image || "";
|
|
262
|
+
this.bgPosition = val?.position || "right top";
|
|
263
|
+
},
|
|
264
|
+
getAtcardCache(uid) {
|
|
265
|
+
let cached = sessionStorage.getItem(ATCARD_CACHE_KEY + uid);
|
|
266
|
+
if (!cached) return null;
|
|
267
|
+
if (cached === "no") return cached;
|
|
268
|
+
try {
|
|
269
|
+
return JSON.parse(cached);
|
|
270
|
+
} catch (e) {
|
|
271
|
+
sessionStorage.removeItem(ATCARD_CACHE_KEY + uid);
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
setAtcardCache(uid, val) {
|
|
276
|
+
if (!uid) return;
|
|
277
|
+
sessionStorage.setItem(ATCARD_CACHE_KEY + uid, val === "no" ? "no" : JSON.stringify(val));
|
|
278
|
+
},
|
|
279
|
+
flattenUserSkins(rows = []) {
|
|
280
|
+
return rows.reduce((list, row) => {
|
|
281
|
+
let skins = Array.isArray(row?.skins) ? row.skins : [];
|
|
282
|
+
return list.concat(skins);
|
|
283
|
+
}, []);
|
|
284
|
+
},
|
|
285
|
+
selectAtcardSkin(list = []) {
|
|
286
|
+
let skins = list.filter((item) => item?.subtype === ATCARD_SUBTYPE && item?.image);
|
|
287
|
+
let theme = this.getCurrentTheme();
|
|
288
|
+
return (
|
|
289
|
+
skins.find((item) => item?.theme === "all") ||
|
|
290
|
+
skins.find((item) => item?.theme === theme) ||
|
|
291
|
+
skins.find((item) => !item?.theme) ||
|
|
292
|
+
null
|
|
293
|
+
);
|
|
294
|
+
},
|
|
295
|
+
getCurrentTheme() {
|
|
296
|
+
let theme =
|
|
297
|
+
document.documentElement.getAttribute("data-theme") ||
|
|
298
|
+
document.body?.getAttribute("data-theme") ||
|
|
299
|
+
localStorage.getItem("__theme") ||
|
|
300
|
+
"light";
|
|
301
|
+
return String(theme || "light").toLowerCase() === "dark" ? "dark" : "light";
|
|
187
302
|
},
|
|
188
|
-
|
|
189
|
-
|
|
303
|
+
resolveAtcardPosition(position) {
|
|
304
|
+
let key = String(position || "rt")
|
|
305
|
+
.trim()
|
|
306
|
+
.toLowerCase();
|
|
307
|
+
return POSITION_MAP[key] || POSITION_MAP.rt;
|
|
190
308
|
},
|
|
191
309
|
getHonor() {
|
|
192
310
|
this.honor = "";
|
|
@@ -265,7 +383,7 @@ export default {
|
|
|
265
383
|
},
|
|
266
384
|
|
|
267
385
|
showMedalIcon: function (val) {
|
|
268
|
-
return __cdn + "/design/medals/user/" + val + ".
|
|
386
|
+
return __cdn + "/design/medals/user/" + val + ".webp";
|
|
269
387
|
},
|
|
270
388
|
medalLink: function ({ rank_id, medal_type = "rank" }) {
|
|
271
389
|
return getMedalLink(rank_id, medal_type);
|
|
@@ -273,17 +391,87 @@ export default {
|
|
|
273
391
|
showMedalDesc: function (item) {
|
|
274
392
|
return item.medal_desc || medal_map[item.medal];
|
|
275
393
|
},
|
|
276
|
-
teamLink: function (team_id) {
|
|
277
|
-
return getLink("org", team_id);
|
|
278
|
-
},
|
|
279
|
-
showTeamLogo: function (val) {
|
|
280
|
-
return getThumbnail(val, 96);
|
|
281
|
-
},
|
|
282
394
|
showLevelColor: function (level) {
|
|
283
395
|
return __userLevelColor[level];
|
|
284
396
|
},
|
|
285
|
-
|
|
286
|
-
|
|
397
|
+
showDecorationImage: function (val) {
|
|
398
|
+
if (!val) return "";
|
|
399
|
+
if (/^(https?:)?\/\//.test(val) || /^(data|blob):/.test(val)) return val;
|
|
400
|
+
return __cdn.replace(/\/$/, "") + "/" + val.replace(/^\//, "");
|
|
401
|
+
},
|
|
402
|
+
normalizeRoles: function (roles) {
|
|
403
|
+
if (!roles) return [];
|
|
404
|
+
if (Array.isArray(roles)) return roles;
|
|
405
|
+
if (typeof roles === "string") {
|
|
406
|
+
try {
|
|
407
|
+
const parsed = JSON.parse(roles);
|
|
408
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
409
|
+
} catch (e) {
|
|
410
|
+
return roles
|
|
411
|
+
.split(/[,,]/)
|
|
412
|
+
.map((item) => item.trim())
|
|
413
|
+
.filter(Boolean);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return [roles];
|
|
417
|
+
},
|
|
418
|
+
normalizeRole: function (role, index) {
|
|
419
|
+
if (typeof role === "string") {
|
|
420
|
+
return {
|
|
421
|
+
key: role + index,
|
|
422
|
+
name: role,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const info = role?.role_info || role?.info || {};
|
|
427
|
+
const name =
|
|
428
|
+
role?.name ||
|
|
429
|
+
role?.title ||
|
|
430
|
+
role?.label ||
|
|
431
|
+
role?.role_name ||
|
|
432
|
+
role?.display_name ||
|
|
433
|
+
role?.remark ||
|
|
434
|
+
info?.name ||
|
|
435
|
+
info?.title ||
|
|
436
|
+
info?.label ||
|
|
437
|
+
info?.role_name ||
|
|
438
|
+
"";
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
key: role?.id || role?.key || role?.val || name + index,
|
|
442
|
+
name,
|
|
443
|
+
server: role?.server || role?.role_server || role?.jx3_server || info?.server || info?.role_server || "",
|
|
444
|
+
url: this.normalizeLink(role?.url || role?.link || role?.href || info?.url || info?.link || ""),
|
|
445
|
+
icon: this.normalizeRoleIcon(role, info),
|
|
446
|
+
color: role?.color || info?.color || "",
|
|
447
|
+
backgroundColor: role?.background_color || role?.bg_color || info?.background_color || info?.bg_color || "",
|
|
448
|
+
borderColor: role?.border_color || info?.border_color || "",
|
|
449
|
+
};
|
|
450
|
+
},
|
|
451
|
+
normalizeRoleAsset: function (url) {
|
|
452
|
+
if (!url) return "";
|
|
453
|
+
url = String(url).trim();
|
|
454
|
+
if (/^(https?:)?\/\//.test(url)) return url;
|
|
455
|
+
return __cdn + url.replace(/^\/+/, "");
|
|
456
|
+
},
|
|
457
|
+
normalizeRoleIcon: function (role, info) {
|
|
458
|
+
const mount = role?.mount || role?.school || role?.school_id || info?.mount || info?.school || info?.school_id || "";
|
|
459
|
+
if (mount) return showSchoolIcon(mount);
|
|
460
|
+
|
|
461
|
+
return this.normalizeRoleAsset(role?.icon || role?.logo || role?.image || info?.icon || info?.logo || "");
|
|
462
|
+
},
|
|
463
|
+
normalizeLink: function (url) {
|
|
464
|
+
if (!url) return "";
|
|
465
|
+
url = String(url).trim();
|
|
466
|
+
if (/^(https?:)?\/\//.test(url)) return url;
|
|
467
|
+
return __Root + url.replace(/^\/+/, "");
|
|
468
|
+
},
|
|
469
|
+
roleStyle: function (role) {
|
|
470
|
+
return {
|
|
471
|
+
color: role.color || null,
|
|
472
|
+
backgroundColor: role.backgroundColor || null,
|
|
473
|
+
borderColor: role.borderColor || null,
|
|
474
|
+
};
|
|
287
475
|
},
|
|
288
476
|
authorLink,
|
|
289
477
|
},
|
|
@@ -294,15 +482,31 @@ export default {
|
|
|
294
482
|
@import "../assets/css/module/author.less";
|
|
295
483
|
.w-author {
|
|
296
484
|
.w-author-wrapper {
|
|
485
|
+
width: 300px;
|
|
486
|
+
min-width: 300px;
|
|
487
|
+
max-width: 300px;
|
|
488
|
+
padding: 12px;
|
|
489
|
+
border: 1px solid rgba(132, 146, 166, 0.28);
|
|
490
|
+
border-radius: 8px;
|
|
491
|
+
background-color: #fff;
|
|
297
492
|
background-repeat: no-repeat;
|
|
298
493
|
background-position: top right;
|
|
299
494
|
background-size: 100% auto;
|
|
495
|
+
box-shadow: 0 14px 34px rgba(31, 41, 55, 0.16), 0 2px 8px rgba(31, 41, 55, 0.08);
|
|
496
|
+
&.is-no-atcard {
|
|
497
|
+
border-color: rgba(124, 134, 156, 0.34);
|
|
498
|
+
background: linear-gradient(180deg, #ffffff 0%, #f3f6fb 100%);
|
|
499
|
+
}
|
|
300
500
|
.u-author {
|
|
301
|
-
padding:
|
|
501
|
+
padding: 4px 10px 12px 5px;
|
|
302
502
|
}
|
|
303
503
|
.u-avatar {
|
|
304
504
|
.fl;
|
|
305
|
-
.mr(
|
|
505
|
+
.mr(12px);
|
|
506
|
+
.size(60px);
|
|
507
|
+
}
|
|
508
|
+
.u-info {
|
|
509
|
+
height: 60px;
|
|
306
510
|
}
|
|
307
511
|
img {
|
|
308
512
|
border: none;
|
|
@@ -320,7 +524,7 @@ export default {
|
|
|
320
524
|
.u-displayname {
|
|
321
525
|
.fz(15px);
|
|
322
526
|
.nobreak;
|
|
323
|
-
max-width:
|
|
527
|
+
max-width: 190px;
|
|
324
528
|
color: @color;
|
|
325
529
|
.bold;
|
|
326
530
|
}
|
|
@@ -336,5 +540,61 @@ export default {
|
|
|
336
540
|
.mb(15px);
|
|
337
541
|
.r(2px);
|
|
338
542
|
}
|
|
543
|
+
.u-author-role {
|
|
544
|
+
.mt(8px);
|
|
545
|
+
}
|
|
546
|
+
.u-author-role-label {
|
|
547
|
+
margin: 0 0 8px 0;
|
|
548
|
+
height: 1px;
|
|
549
|
+
background-color: rgba(154, 167, 181, 0.28);
|
|
550
|
+
}
|
|
551
|
+
.u-author-roles {
|
|
552
|
+
display: flex;
|
|
553
|
+
flex-direction: column;
|
|
554
|
+
gap: 4px;
|
|
555
|
+
}
|
|
556
|
+
.u-author-role-item {
|
|
557
|
+
.flex(y);
|
|
558
|
+
gap: 7px;
|
|
559
|
+
max-width: 100%;
|
|
560
|
+
min-height: 21px;
|
|
561
|
+
color: #56677a;
|
|
562
|
+
font-size: 12px;
|
|
563
|
+
line-height: 21px;
|
|
564
|
+
box-sizing: border-box;
|
|
565
|
+
text-decoration: none;
|
|
566
|
+
|
|
567
|
+
&:hover {
|
|
568
|
+
.u-author-role-server {
|
|
569
|
+
color: #fba524;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
.u-author-role-icon {
|
|
574
|
+
.size(20px);
|
|
575
|
+
flex-shrink: 0;
|
|
576
|
+
object-fit: contain;
|
|
577
|
+
}
|
|
578
|
+
.u-author-role-content {
|
|
579
|
+
min-width: 0;
|
|
580
|
+
display: flex;
|
|
581
|
+
align-items: baseline;
|
|
582
|
+
}
|
|
583
|
+
.u-author-role-name {
|
|
584
|
+
min-width: 0;
|
|
585
|
+
margin-right: 2px;
|
|
586
|
+
overflow: hidden;
|
|
587
|
+
text-overflow: ellipsis;
|
|
588
|
+
white-space: nowrap;
|
|
589
|
+
color: #42566d;
|
|
590
|
+
font-size: 12px;
|
|
591
|
+
font-weight: 400;
|
|
592
|
+
}
|
|
593
|
+
.u-author-role-server {
|
|
594
|
+
flex-shrink: 0;
|
|
595
|
+
color: #fba524;
|
|
596
|
+
font-size: 12px;
|
|
597
|
+
font-weight: 400;
|
|
598
|
+
}
|
|
339
599
|
}
|
|
340
600
|
</style>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<div class="u-qrcode">
|
|
12
12
|
<qrcode-vue class="u-pic" :value="value" :size="size" level="H"></qrcode-vue>
|
|
13
13
|
<span class="u-txt"
|
|
14
|
-
><img class="u-icon" svg-inline src="
|
|
14
|
+
><img class="u-icon" svg-inline src="../assets/img/other/qr-code.svg" />扫一扫手机访问</span
|
|
15
15
|
>
|
|
16
16
|
</div>
|
|
17
17
|
</div>
|
package/src/service/cms.js
CHANGED
|
@@ -28,6 +28,18 @@ function getDecoration(params) {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function getDecorationV2(params) {
|
|
32
|
+
return $cms().get(`/api/cms/user/decoration/v2`, {
|
|
33
|
+
params,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getUserSkin(params) {
|
|
38
|
+
return $cms().get(`/api/cms/user/skin`, {
|
|
39
|
+
params,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
function getDecorationJson() {
|
|
32
44
|
let url = __cdn + "design/decoration/index.json";
|
|
33
45
|
return axios.get(url);
|
|
@@ -39,4 +51,4 @@ function getLetterPaper(params) {
|
|
|
39
51
|
params,
|
|
40
52
|
});
|
|
41
53
|
}
|
|
42
|
-
export { uploadFile, loadAuthors, loadEmotions, getDecoration, getDecorationJson, getLetterPaper };
|
|
54
|
+
export { uploadFile, loadAuthors, loadEmotions, getDecoration, getDecorationV2, getUserSkin, getDecorationJson, getLetterPaper };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@bg-black: #111827;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { onMounted, ref } from "vue";
|
|
2
|
+
|
|
3
|
+
export function createMeta({ title, component, args = {}, argTypes = {}, docs = "", parameters = {} }) {
|
|
4
|
+
return {
|
|
5
|
+
title,
|
|
6
|
+
component,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
args,
|
|
9
|
+
argTypes: buildArgTypes(argTypes),
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "padded",
|
|
12
|
+
docs: {
|
|
13
|
+
description: {
|
|
14
|
+
component: docs,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
...parameters,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function componentStory(component, options = {}) {
|
|
23
|
+
const { template, style = "", components = {}, setup } = options;
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
render: (args) => ({
|
|
27
|
+
components: {
|
|
28
|
+
StoryComponent: component,
|
|
29
|
+
...components,
|
|
30
|
+
},
|
|
31
|
+
setup() {
|
|
32
|
+
return {
|
|
33
|
+
args,
|
|
34
|
+
...(typeof setup === "function" ? setup(args) : {}),
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
template:
|
|
38
|
+
template ||
|
|
39
|
+
`<div style="${style}"><StoryComponent v-bind="args" /></div>`,
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function previewStory(component, options = {}) {
|
|
45
|
+
const { title = "效果预览", description = "", code = "", style = "", template, components = {}, setup } = options;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
render: (args) => ({
|
|
49
|
+
components: {
|
|
50
|
+
StoryComponent: component,
|
|
51
|
+
...components,
|
|
52
|
+
},
|
|
53
|
+
setup() {
|
|
54
|
+
return {
|
|
55
|
+
args,
|
|
56
|
+
previewTitle: title,
|
|
57
|
+
previewDescription: description,
|
|
58
|
+
previewCode: code,
|
|
59
|
+
...(typeof setup === "function" ? setup(args) : {}),
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
template: `
|
|
63
|
+
<div style="display:grid;gap:16px;min-width:320px;">
|
|
64
|
+
<div style="padding:16px 18px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;">
|
|
65
|
+
<div style="font-size:16px;font-weight:600;color:#111827;">{{ previewTitle }}</div>
|
|
66
|
+
<div v-if="previewDescription" style="margin-top:8px;color:#4b5563;line-height:1.7;white-space:pre-line;">{{ previewDescription }}</div>
|
|
67
|
+
<pre v-if="previewCode" style="margin:12px 0 0;padding:12px;border-radius:10px;background:#0f172a;color:#e2e8f0;font-size:12px;line-height:1.6;overflow:auto;white-space:pre-wrap;word-break:break-word;">{{ previewCode }}</pre>
|
|
68
|
+
</div>
|
|
69
|
+
<div style="padding:20px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;${style}">
|
|
70
|
+
${template || `<StoryComponent v-bind="args" />`}
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
`,
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function docsOnlyStory(message) {
|
|
79
|
+
return {
|
|
80
|
+
render: () => ({
|
|
81
|
+
template: `<div style="max-width:720px;padding:16px 18px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;color:#374151;line-height:1.7;">${escapeHtml(
|
|
82
|
+
message
|
|
83
|
+
)}</div>`,
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function useDemoText(url, fallback = "") {
|
|
89
|
+
const content = ref(fallback);
|
|
90
|
+
const loaded = ref(false);
|
|
91
|
+
|
|
92
|
+
onMounted(async () => {
|
|
93
|
+
try {
|
|
94
|
+
const response = await fetch(url);
|
|
95
|
+
if (response.ok) {
|
|
96
|
+
content.value = await response.text();
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.warn(`[storybook] failed to load demo content: ${url}`, error);
|
|
100
|
+
} finally {
|
|
101
|
+
loaded.value = true;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
content,
|
|
107
|
+
loaded,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildArgTypes(argTypes) {
|
|
112
|
+
return Object.fromEntries(
|
|
113
|
+
Object.entries(argTypes).map(([name, config]) => {
|
|
114
|
+
const table = {};
|
|
115
|
+
|
|
116
|
+
if (config.type) {
|
|
117
|
+
table.type = { summary: config.type };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (config.defaultValue !== undefined) {
|
|
121
|
+
table.defaultValue = { summary: config.defaultValue };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (config.required) {
|
|
125
|
+
table.category = "required";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return [
|
|
129
|
+
name,
|
|
130
|
+
{
|
|
131
|
+
description: config.description,
|
|
132
|
+
control: config.control === false ? false : config.control || inferControl(config.type),
|
|
133
|
+
options: config.options,
|
|
134
|
+
table,
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function inferControl(type = "") {
|
|
142
|
+
if (type.includes("Boolean")) return "boolean";
|
|
143
|
+
if (type.includes("Number")) return "number";
|
|
144
|
+
if (type.includes("Array") || type.includes("Object")) return "object";
|
|
145
|
+
return "text";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function escapeHtml(value) {
|
|
149
|
+
return String(value)
|
|
150
|
+
.replace(/&/g, "&")
|
|
151
|
+
.replace(/</g, "<")
|
|
152
|
+
.replace(/>/g, ">")
|
|
153
|
+
.replace(/\n/g, "<br />");
|
|
154
|
+
}
|