@jx3box/jx3box-ui 2.0.5 → 2.0.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.
Files changed (241) hide show
  1. package/.storybook/preview.js +22 -13
  2. package/.storybook/storybookMocks.js +214 -0
  3. package/README.md +39 -43
  4. package/assets/css/bread/admin.less +20 -2
  5. package/assets/css/bread/breadcrumb.less +5 -2
  6. package/assets/css/comment/quick-reply.less +1 -1
  7. package/assets/css/common/left-sidebar.less +1 -1
  8. package/assets/css/interact/like2.less +5 -2
  9. package/assets/css/interact/qrcode.less +69 -0
  10. package/assets/css/single/author.less +15 -10
  11. package/assets/css/single/cms-single.less +1 -0
  12. package/assets/css/single/thx.less +34 -11
  13. package/assets/css/wiki/wiki-comments.less +176 -0
  14. package/assets/css/wiki/wiki-panel.less +177 -0
  15. package/assets/css/wiki/wiki-revisions.less +62 -0
  16. package/assets/data/nav.json +344 -10
  17. package/assets/img/comment/comment.svg +1 -1
  18. package/assets/img/comment/heart_1.svg +1 -1
  19. package/assets/img/comment/hide.svg +1 -1
  20. package/assets/img/leftsidebar/medal.svg +1 -1
  21. package/assets/img/leftsidebar/post.svg +27 -46
  22. package/i18n/messages/en-US.js +357 -22
  23. package/i18n/messages/vi.js +350 -22
  24. package/i18n/messages/zh-CN.js +469 -20
  25. package/i18n/messages/zh-TW.js +350 -22
  26. package/index.js +19 -7
  27. package/package.json +8 -5
  28. package/service/cms.js +22 -0
  29. package/service/commit-history.js +18 -0
  30. package/service/community.js +60 -0
  31. package/service/fav.js +5 -6
  32. package/src/App.vue +210 -80
  33. package/src/Breadcrumb.vue +24 -11
  34. package/src/CommonFooter.vue +2 -2
  35. package/src/Footer.vue +13 -5
  36. package/src/LeftSideToggle.vue +10 -3
  37. package/src/LeftSidebar.vue +19 -5
  38. package/src/Main.vue +9 -2
  39. package/src/RightSidebar.vue +12 -3
  40. package/src/SuspendCommon.vue +52 -38
  41. package/src/author/AuthorFans.vue +7 -5
  42. package/src/author/AuthorFollow.vue +14 -7
  43. package/src/author/AuthorGift.vue +25 -17
  44. package/src/author/AuthorInfo.vue +46 -19
  45. package/src/author/AuthorLink.vue +3 -1
  46. package/src/author/AuthorMedals.vue +5 -2
  47. package/src/author/AuthorPosts.vue +31 -13
  48. package/src/author/AuthorRss.vue +7 -3
  49. package/src/author/AuthorTeams.vue +3 -1
  50. package/src/author/UserPop.vue +29 -17
  51. package/src/bread/Admin.vue +55 -32
  52. package/src/bread/AdminDirectMessage.vue +15 -8
  53. package/src/bread/AdminDrop.vue +124 -45
  54. package/src/bread/CommunityAdmin.vue +527 -0
  55. package/src/bread/DesignTask.vue +30 -26
  56. package/src/bread/ListAdmin.vue +199 -0
  57. package/src/bread/MigrateCommunity.vue +192 -0
  58. package/src/bread/MoveToCommunityDialog.vue +234 -0
  59. package/src/comment/Avatar.vue +18 -24
  60. package/src/comment/CommentContent.vue +57 -37
  61. package/src/comment/CommentContentSimple.vue +61 -63
  62. package/src/comment/CommentInputForm.vue +45 -34
  63. package/src/comment/CommentWithReply.vue +9 -6
  64. package/src/comment/QuickReply.vue +5 -1
  65. package/src/comment/ReplyForReply.vue +6 -4
  66. package/src/comment/ReplyList.vue +28 -18
  67. package/src/comment/Upload.vue +24 -6
  68. package/src/filters/clientBy.vue +10 -8
  69. package/src/filters/markBy.vue +35 -31
  70. package/src/filters/menuBy.vue +20 -22
  71. package/src/filters/orderBy.vue +17 -11
  72. package/src/filters/tagBy.vue +4 -2
  73. package/src/filters/topicBy.vue +12 -10
  74. package/src/filters/versionBy.vue +5 -3
  75. package/src/filters/zlpBy.vue +29 -25
  76. package/src/footer/copyright.vue +5 -5
  77. package/src/footer/links.vue +2 -2
  78. package/src/footer/official.vue +1 -1
  79. package/src/footer/resource.vue +6 -6
  80. package/src/header/alternate.vue +35 -18
  81. package/src/header/asset.vue +9 -19
  82. package/src/header/box.vue +20 -8
  83. package/src/header/box2.vue +16 -9
  84. package/src/header/client.vue +7 -7
  85. package/src/header/lang.vue +41 -6
  86. package/src/header/logo.vue +2 -3
  87. package/src/header/manage.vue +2 -2
  88. package/src/header/message.vue +3 -3
  89. package/src/header/nav.vue +26 -23
  90. package/src/header/publish.vue +2 -2
  91. package/src/header/search.vue +2 -2
  92. package/src/header/shop.vue +2 -2
  93. package/src/header/user.vue +4 -4
  94. package/src/header/userInfo.vue +22 -24
  95. package/src/header/vip.vue +2 -2
  96. package/src/interact/BoxcoinAdmin.vue +30 -16
  97. package/src/interact/BoxcoinRecords.vue +28 -11
  98. package/src/interact/BoxcoinUser.vue +33 -17
  99. package/src/interact/Fav.vue +5 -1
  100. package/src/interact/Homework.vue +317 -0
  101. package/src/interact/Like.vue +4 -2
  102. package/src/interact/QRcode.vue +104 -0
  103. package/src/interact/Rss.vue +10 -4
  104. package/src/interact/Share.vue +18 -19
  105. package/src/interact/WatchLater.vue +5 -1
  106. package/src/main.js +1 -0
  107. package/src/single/Author.vue +5 -1
  108. package/src/single/CmsSingle.vue +29 -15
  109. package/src/single/Collection.vue +36 -26
  110. package/src/single/Comment.vue +19 -13
  111. package/src/single/Creators.vue +5 -3
  112. package/src/single/PostCollection.vue +158 -0
  113. package/src/single/PostDirectory.vue +0 -126
  114. package/src/single/PostGuide.vue +93 -0
  115. package/src/single/PostHeader.vue +39 -17
  116. package/src/single/PostTopic.vue +3 -3
  117. package/src/single/PostVersion.vue +219 -0
  118. package/src/single/RightAffix.vue +160 -0
  119. package/src/single/SimpleThx.vue +4 -2
  120. package/src/single/Thx.vue +14 -2
  121. package/src/single/VersionDialog.vue +238 -0
  122. package/src/stories/components/StoryPropsTable.vue +137 -0
  123. package/src/stories/filters/FilterGallery.stories.js +110 -0
  124. package/src/stories/filters/clientBy.stories.js +24 -0
  125. package/src/stories/filters/markBy.stories.js +6 -0
  126. package/src/stories/filters/menuBy.stories.js +6 -0
  127. package/src/stories/filters/orderBy.stories.js +6 -0
  128. package/src/stories/filters/tagBy.stories.js +6 -0
  129. package/src/stories/filters/topicBy.stories.js +6 -0
  130. package/src/stories/filters/versionBy.stories.js +6 -0
  131. package/src/stories/filters/zlpBy.stories.js +6 -0
  132. package/src/stories/interact/QRcode.stories.js +59 -0
  133. package/src/stories/layout/BaseShell.stories.js +38 -0
  134. package/src/stories/layout/Breadcrumb.stories.js +40 -0
  135. package/src/stories/layout/CommonFooter.stories.js +1 -1
  136. package/src/stories/layout/CommonHeader.stories.js +1 -1
  137. package/src/stories/layout/LeftSideToggle.stories.js +78 -0
  138. package/src/stories/layout/LeftSidebar.stories.js +40 -0
  139. package/src/stories/layout/Main.stories.js +41 -0
  140. package/src/stories/layout/RightSidebar.stories.js +36 -0
  141. package/src/stories/layout/StorybookShell.vue +271 -0
  142. package/src/stories/layout/SuspendCommon.stories.js +67 -0
  143. package/src/stories/layout/SuspendCommonStage.vue +143 -0
  144. package/src/stories/mockData.js +369 -0
  145. package/src/stories/other/UserPop.stories.js +51 -0
  146. package/src/stories/single/Author.stories.js +19 -0
  147. package/src/stories/single/AuthorStoryStage.vue +103 -0
  148. package/src/stories/single/CmsSingle.stories.js +19 -0
  149. package/src/stories/single/CmsSingleStoryStage.vue +118 -0
  150. package/src/stories/single/Collection.stories.js +34 -0
  151. package/src/stories/single/Comment.stories.js +36 -0
  152. package/src/stories/single/Creators.stories.js +34 -0
  153. package/src/stories/single/PostCollection.stories.js +34 -0
  154. package/src/stories/single/PostDirectory.stories.js +31 -0
  155. package/src/stories/single/PostGuide.stories.js +47 -0
  156. package/src/stories/single/PostHeader.stories.js +39 -0
  157. package/src/stories/single/PostVersion.stories.js +41 -0
  158. package/src/stories/single/RightAffix.stories.js +84 -0
  159. package/src/stories/single/SimpleThx.stories.js +39 -0
  160. package/src/stories/single/SingleGallery.stories.js +207 -0
  161. package/src/stories/single/Thx.stories.js +38 -0
  162. package/src/stories/wiki/GamePrice.stories.js +64 -0
  163. package/src/stories/wiki/WikiComments.stories.js +58 -0
  164. package/src/stories/wiki/WikiPanel.stories.js +69 -0
  165. package/src/stories/wiki/WikiRevisions.stories.js +47 -0
  166. package/src/wiki/GamePrice.vue +107 -0
  167. package/src/wiki/WikiComment.vue +153 -0
  168. package/src/wiki/WikiComments.vue +206 -0
  169. package/src/wiki/WikiPanel.vue +121 -0
  170. package/src/wiki/WikiRevisions.vue +125 -0
  171. package/vue.config.js +2 -12
  172. package/assets/css/common/bottom.less +0 -25
  173. package/assets/css/editor/article.less +0 -36
  174. package/assets/css/editor/combo.less +0 -362
  175. package/assets/css/editor/resource.less +0 -399
  176. package/assets/css/editor/tinymce.less +0 -100
  177. package/assets/css/editor/upload.less +0 -136
  178. package/assets/css/module/author.less +0 -231
  179. package/assets/css/module/buff.less +0 -88
  180. package/assets/css/module/directory.less +0 -165
  181. package/assets/css/module/icon.less +0 -25
  182. package/assets/css/module/item.less +0 -279
  183. package/assets/css/module/item_simple.less +0 -58
  184. package/assets/css/module/jx3_element.less +0 -5
  185. package/assets/css/module/macro.less +0 -89
  186. package/assets/css/module/npc.less +0 -265
  187. package/assets/css/module/resource.less +0 -93
  188. package/assets/css/module/skill.less +0 -74
  189. package/assets/css/module/talent.less +0 -495
  190. package/assets/js/a.js +0 -46
  191. package/assets/js/code.js +0 -13
  192. package/assets/js/combo.js +0 -40
  193. package/assets/js/directory.js +0 -114
  194. package/assets/js/filter2.js +0 -186
  195. package/assets/js/fold.js +0 -11
  196. package/assets/js/gallery.js +0 -14
  197. package/assets/js/hljs_languages.js +0 -177
  198. package/assets/js/iframe.js +0 -38
  199. package/assets/js/img.js +0 -23
  200. package/assets/js/item/attribute_percent.js +0 -88
  201. package/assets/js/item/bind.js +0 -18
  202. package/assets/js/item/border.js +0 -19
  203. package/assets/js/item/border_quest.js +0 -12
  204. package/assets/js/item/color.js +0 -25
  205. package/assets/js/item/hljs_languages.js +0 -177
  206. package/assets/js/item/icon_url.js +0 -15
  207. package/assets/js/item/second_format.js +0 -19
  208. package/assets/js/jx3_element.js +0 -73
  209. package/assets/js/katex.js +0 -181
  210. package/assets/js/macro.js +0 -16
  211. package/assets/js/nextpage.js +0 -4
  212. package/assets/js/pswp.js +0 -67
  213. package/assets/js/pswp_template.js +0 -66
  214. package/assets/js/pz_iframe.js +0 -30
  215. package/assets/js/qixue.js +0 -28
  216. package/assets/js/renderImgPreview.js +0 -18
  217. package/assets/js/script.js +0 -6
  218. package/assets/js/stat.js +0 -107
  219. package/assets/js/talent2.js +0 -21
  220. package/assets/js/tex-mml-chtml.js +0 -36310
  221. package/assets/js/voice.js +0 -238
  222. package/assets/js/xss.js +0 -130
  223. package/src/editor/Article.vue +0 -230
  224. package/src/editor/BoxResource.vue +0 -441
  225. package/src/editor/Resource.vue +0 -623
  226. package/src/editor/Tinymce.vue +0 -204
  227. package/src/editor/Upload.vue +0 -277
  228. package/src/editor/UploadAlum.vue +0 -176
  229. package/src/editor/UploadBanner.vue +0 -156
  230. package/src/editor/components/Author.vue +0 -322
  231. package/src/editor/components/Avatar.vue +0 -95
  232. package/src/editor/components/Buff.vue +0 -80
  233. package/src/editor/components/Combo.vue +0 -259
  234. package/src/editor/components/Equip.vue +0 -299
  235. package/src/editor/components/GameText.vue +0 -242
  236. package/src/editor/components/Item.vue +0 -325
  237. package/src/editor/components/ItemSimple.vue +0 -134
  238. package/src/editor/components/Medal.vue +0 -43
  239. package/src/editor/components/Npc.vue +0 -215
  240. package/src/editor/components/PostAuthor.vue +0 -102
  241. package/src/editor/components/Skill.vue +0 -71
@@ -0,0 +1,137 @@
1
+ <template>
2
+ <section class="story-props-table">
3
+ <div class="story-props-table__header">
4
+ <div>
5
+ <div class="story-props-table__eyebrow">Props</div>
6
+ <h3 class="story-props-table__title">{{ title }}</h3>
7
+ </div>
8
+ <p v-if="description" class="story-props-table__desc">{{ description }}</p>
9
+ </div>
10
+
11
+ <div class="story-props-table__body">
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Prop</th>
16
+ <th>类型</th>
17
+ <th>默认值</th>
18
+ <th>说明</th>
19
+ </tr>
20
+ </thead>
21
+ <tbody>
22
+ <tr v-for="item in items" :key="item.name">
23
+ <td>
24
+ <code>{{ item.name }}</code>
25
+ <span v-if="item.required" class="story-props-table__required">必填</span>
26
+ </td>
27
+ <td>{{ item.type || '-' }}</td>
28
+ <td><code>{{ item.default ?? '-' }}</code></td>
29
+ <td>{{ item.description || '-' }}</td>
30
+ </tr>
31
+ </tbody>
32
+ </table>
33
+ </div>
34
+ </section>
35
+ </template>
36
+
37
+ <script>
38
+ export default {
39
+ name: "StoryPropsTable",
40
+ props: {
41
+ title: {
42
+ type: String,
43
+ default: "组件 Props",
44
+ },
45
+ description: {
46
+ type: String,
47
+ default: "",
48
+ },
49
+ items: {
50
+ type: Array,
51
+ default: function () {
52
+ return [];
53
+ },
54
+ },
55
+ },
56
+ };
57
+ </script>
58
+
59
+ <style lang="less">
60
+ .story-props-table {
61
+ border-radius: 20px;
62
+ background: rgba(255, 255, 255, 0.92);
63
+ box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
64
+ overflow: hidden;
65
+ }
66
+
67
+ .story-props-table__header {
68
+ display: flex;
69
+ justify-content: space-between;
70
+ gap: 20px;
71
+ padding: 24px 24px 18px;
72
+ border-bottom: 1px solid rgba(15, 23, 42, 0.08);
73
+ }
74
+
75
+ .story-props-table__eyebrow {
76
+ font-size: 12px;
77
+ font-weight: 700;
78
+ letter-spacing: 0.08em;
79
+ text-transform: uppercase;
80
+ color: #0ea5e9;
81
+ }
82
+
83
+ .story-props-table__title {
84
+ margin: 8px 0 0;
85
+ font-size: 22px;
86
+ color: #0f172a;
87
+ }
88
+
89
+ .story-props-table__desc {
90
+ max-width: 28rem;
91
+ margin: 0;
92
+ font-size: 14px;
93
+ line-height: 1.8;
94
+ color: #64748b;
95
+ }
96
+
97
+ .story-props-table__body {
98
+ overflow-x: auto;
99
+ }
100
+
101
+ .story-props-table table {
102
+ width: 100%;
103
+ border-collapse: collapse;
104
+ }
105
+
106
+ .story-props-table th,
107
+ .story-props-table td {
108
+ padding: 14px 16px;
109
+ border-bottom: 1px solid rgba(15, 23, 42, 0.06);
110
+ text-align: left;
111
+ font-size: 13px;
112
+ line-height: 1.7;
113
+ color: #334155;
114
+ vertical-align: top;
115
+ }
116
+
117
+ .story-props-table th {
118
+ font-weight: 700;
119
+ color: #0f172a;
120
+ background: rgba(248, 250, 252, 0.9);
121
+ }
122
+
123
+ .story-props-table code {
124
+ padding: 2px 6px;
125
+ border-radius: 999px;
126
+ background: rgba(15, 23, 42, 0.06);
127
+ color: #0f172a;
128
+ }
129
+
130
+ .story-props-table__required {
131
+ display: inline-block;
132
+ margin-left: 8px;
133
+ font-size: 11px;
134
+ color: #b91c1c;
135
+ font-weight: 700;
136
+ }
137
+ </style>
@@ -0,0 +1,110 @@
1
+ import clientBy from '../../filters/clientBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+ import markBy from '../../filters/markBy.vue';
4
+ import menuBy from '../../filters/menuBy.vue';
5
+ import orderBy from '../../filters/orderBy.vue';
6
+ import tagBy from '../../filters/tagBy.vue';
7
+ import topicBy from '../../filters/topicBy.vue';
8
+ import versionBy from '../../filters/versionBy.vue';
9
+ import zlpBy from '../../filters/zlpBy.vue';
10
+
11
+ const meta = {
12
+ title: 'Filters/Index',
13
+ parameters: {
14
+ layout: 'fullscreen',
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ export const Default = {
21
+ render: () => ({
22
+ components: {
23
+ clientBy,
24
+ StoryPropsTable,
25
+ markBy,
26
+ menuBy,
27
+ orderBy,
28
+ tagBy,
29
+ topicBy,
30
+ versionBy,
31
+ zlpBy,
32
+ },
33
+ data() {
34
+ return {
35
+ selectedTopic: '',
36
+ menuOptions: {
37
+ pve: '副本',
38
+ pvp: '竞技',
39
+ tool: '工具',
40
+ },
41
+ tagOptions: {
42
+ beginner: '入门',
43
+ build: '配装',
44
+ macro: '宏循环',
45
+ },
46
+ topics: ['版本速报', '配装思路', '副本机制'],
47
+ filterProps: [
48
+ {
49
+ title: 'clientBy / versionBy',
50
+ description: '客户端与版本筛选类组件。',
51
+ items: [
52
+ { name: 'type / value', type: 'String', default: '""', description: '当前激活项。' },
53
+ { name: 'clients', type: 'Object', default: 'null', description: 'clientBy 自定义客户端列表。' },
54
+ { name: 'showWujie', type: 'Boolean', default: 'false', description: 'clientBy 是否展示无界。' },
55
+ ],
56
+ },
57
+ {
58
+ title: 'markBy / menuBy / orderBy / tagBy / zlpBy',
59
+ description: '下拉或条件筛选组件。',
60
+ items: [
61
+ { name: 'data / marks', type: 'Object', default: '{}', description: '候选项映射。' },
62
+ { name: 'placeholder', type: 'String', default: '""', description: '未选中时展示文案。' },
63
+ { name: 'type', type: 'String', default: '组件内默认值', description: 'emit 时返回的筛选键。' },
64
+ { name: 'client', type: 'String', default: '""', description: 'zlpBy 根据客户端决定资料片列表。' },
65
+ ],
66
+ },
67
+ {
68
+ title: 'topicBy',
69
+ description: '主题选择组件,推荐配合 v-model 使用。',
70
+ items: [
71
+ { name: 'topics', type: 'Array', default: '[]', required: true, description: '主题列表。' },
72
+ { name: 'modelValue', type: 'String', default: '""', description: '当前选中主题。' },
73
+ { name: 'label', type: 'String', default: '"主题"', description: '未选中时显示文案。' },
74
+ ],
75
+ },
76
+ ],
77
+ };
78
+ },
79
+ template: `
80
+ <div style="display: grid; gap: 24px;">
81
+ <section style="border-radius: 20px; background: rgba(255,255,255,0.92); padding: 24px; box-shadow: 0 24px 60px rgba(15,23,42,0.08);">
82
+ <div style="font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #0ea5e9;">list</div>
83
+ <h2 style="margin: 10px 0 0; font-size: 28px; color: #0f172a;">筛选模块总览</h2>
84
+ <p style="margin-top: 12px; color: #475569; line-height: 1.8;">README 中的筛选模块在这里统一展示,方便查看组件外观和交互手感。</p>
85
+ </section>
86
+
87
+ <section style="border-radius: 20px; background: rgba(255,255,255,0.92); padding: 24px; box-shadow: 0 24px 60px rgba(15,23,42,0.08);">
88
+ <div style="display: flex; flex-wrap: wrap; gap: 16px; align-items: center;">
89
+ <markBy />
90
+ <menuBy :data="menuOptions" placeholder="栏目" />
91
+ <orderBy />
92
+ <tagBy :data="tagOptions" />
93
+ <topicBy v-model="selectedTopic" :topics="topics" />
94
+ <zlpBy client="std" />
95
+ <versionBy />
96
+ <clientBy :show-wujie="true" />
97
+ </div>
98
+ </section>
99
+
100
+ <StoryPropsTable
101
+ v-for="item in filterProps"
102
+ :key="item.title"
103
+ :title="item.title"
104
+ :description="item.description"
105
+ :items="item.items"
106
+ />
107
+ </div>
108
+ `,
109
+ }),
110
+ };
@@ -0,0 +1,24 @@
1
+ import clientBy from '../../filters/clientBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = {
5
+ title: 'Filters/clientBy',
6
+ component: clientBy,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ };
11
+ export default meta;
12
+ export const Default = {
13
+ render: () => ({
14
+ components: { clientBy, StoryPropsTable },
15
+ setup() {
16
+ return { propsInfo: [
17
+ { name: 'type', type: 'String', default: '""', description: '当前选中的客户端值。' },
18
+ { name: 'clients', type: 'Object', default: 'null', description: '自定义客户端映射。' },
19
+ { name: 'showWujie', type: 'Boolean', default: 'false', description: '是否显示无界。' },
20
+ ] };
21
+ },
22
+ template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><clientBy :show-wujie="true" /></section><StoryPropsTable title="clientBy" description="客户端筛选组件。" :items="propsInfo" /></div>`,
23
+ }),
24
+ };
@@ -0,0 +1,6 @@
1
+ import markBy from '../../filters/markBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/markBy', component: markBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { markBy, StoryPropsTable }, setup() { return { propsInfo: [ { name: 'placeholder', type: 'String', default: '""', description: '默认展示文案。' }, { name: 'type', type: 'String', default: '"mark"', description: 'emit 时返回的筛选键。' }, { name: 'marks', type: 'Object', default: 'default_marks', description: '精选项映射。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><markBy /></section><StoryPropsTable title="markBy" description="精选标记筛选组件。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import menuBy from '../../filters/menuBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/menuBy', component: menuBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { menuBy, StoryPropsTable }, data() { return { dataMap: { pve: '副本', pvp: '竞技', tool: '工具' }, propsInfo: [ { name: 'data', type: 'Object', default: '{}', required: true, description: '候选项映射。' }, { name: 'type', type: 'String', default: '"menu"', description: 'emit 类型。' }, { name: 'placeholder', type: 'String', default: '""', description: '默认文案。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><menuBy :data="dataMap" placeholder="栏目" /></section><StoryPropsTable title="menuBy" description="通用下拉筛选组件。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import orderBy from '../../filters/orderBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/orderBy', component: orderBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { orderBy, StoryPropsTable }, setup() { return { propsInfo: [] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><orderBy /></section><StoryPropsTable title="orderBy" description="当前组件无 props,通过内部状态管理排序选项。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import tagBy from '../../filters/tagBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/tagBy', component: tagBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { tagBy, StoryPropsTable }, data() { return { dataMap: { beginner: '入门', build: '配装', macro: '宏循环' }, propsInfo: [ { name: 'data', type: 'Object', default: '{}', required: true, description: '标签映射。' }, { name: 'type', type: 'String', default: '"tag"', description: 'emit 类型。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><tagBy :data="dataMap" /></section><StoryPropsTable title="tagBy" description="标签筛选组件。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import TopicBy from '../../filters/topicBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/topicBy', component: TopicBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { TopicBy, StoryPropsTable }, data() { return { selected: '', propsInfo: [ { name: 'topics', type: 'Array', default: '[]', required: true, description: '主题列表。' }, { name: 'modelValue', type: 'String', default: '""', description: '当前选中值。' }, { name: 'label', type: 'String', default: '"主题"', description: '默认文案。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><TopicBy v-model="selected" :topics="['版本速报','配装思路','副本机制']" /></section><StoryPropsTable title="topicBy" description="主题筛选组件,推荐用 v-model。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import versionBy from '../../filters/versionBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/versionBy', component: versionBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { versionBy, StoryPropsTable }, setup() { return { propsInfo: [ { name: 'value', type: 'String | Number', default: '""', description: '默认版本值。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><versionBy /></section><StoryPropsTable title="versionBy" description="双端/旗舰/无界筛选。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,6 @@
1
+ import zlpBy from '../../filters/zlpBy.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = { title: 'Filters/zlpBy', component: zlpBy, parameters: { layout: 'fullscreen' } };
5
+ export default meta;
6
+ export const Default = { render: () => ({ components: { zlpBy, StoryPropsTable }, setup() { return { propsInfo: [ { name: 'client', type: 'String', default: '""', description: '按客户端切换资料片列表。' } ] }; }, template: `<div style="display:grid;gap:24px;"><section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);"><zlpBy client="std" /></section><StoryPropsTable title="zlpBy" description="资料片筛选组件。" :items="propsInfo" /></div>` }) };
@@ -0,0 +1,59 @@
1
+ import QRcode from '../../interact/QRcode.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+
4
+ const meta = {
5
+ title: 'Interact/QRcode',
6
+ component: QRcode,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ argTypes: {
11
+ href: { control: 'text' },
12
+ v: { control: 'radio', options: ['cms', 'static'] },
13
+ s: { control: { type: 'number', min: 80, max: 240, step: 10 } },
14
+ },
15
+ };
16
+
17
+ export default meta;
18
+
19
+ export const Default = {
20
+ args: {
21
+ href: 'https://www.jx3box.com',
22
+ v: 'cms',
23
+ s: 120,
24
+ },
25
+ render: (args) => ({
26
+ components: { QRcode, StoryPropsTable },
27
+ setup() {
28
+ return {
29
+ args,
30
+ propsInfo: [
31
+ { name: 'href', type: 'String', default: 'location.href', description: '二维码指向地址。' },
32
+ { name: 'v', type: 'String', default: '"cms"', description: '展示模式,支持弹出态和静态态。' },
33
+ { name: 's', type: 'Number', default: '100', description: '二维码尺寸。' },
34
+ ],
35
+ };
36
+ },
37
+ template: `
38
+ <div style="display:grid;gap:24px;padding:32px;background:linear-gradient(180deg,#f8fafc 0%,#eef2f7 100%);min-height:100vh;">
39
+ <section style="display:flex;align-items:center;justify-content:space-between;gap:24px;padding:24px;border-radius:20px;background:rgba(255,255,255,0.92);box-shadow:0 24px 60px rgba(15,23,42,0.08);">
40
+ <div>
41
+ <h2 style="margin:0;font-size:28px;color:#0f172a;">QRcode</h2>
42
+ <p style="margin:12px 0 0;color:#475569;line-height:1.8;">用于文章和百科详情页中的扫码访问入口。</p>
43
+ </div>
44
+ <QRcode v-bind="args" />
45
+ </section>
46
+ <StoryPropsTable title="QRcode" description="二维码组件参数说明。" :items="propsInfo" />
47
+ </div>
48
+ `,
49
+ }),
50
+ };
51
+
52
+ export const StaticCard = {
53
+ args: {
54
+ href: 'https://www.jx3box.com/wiki/achievement/1001',
55
+ v: 'static',
56
+ s: 140,
57
+ },
58
+ render: Default.render,
59
+ };
@@ -0,0 +1,38 @@
1
+ const meta = {
2
+ title: 'Layout/BaseShell',
3
+ parameters: {
4
+ layout: 'fullscreen',
5
+ },
6
+ };
7
+
8
+ export default meta;
9
+
10
+ export const Default = {
11
+ render: () => ({
12
+ template: `
13
+ <section style="display: grid; gap: 20px;">
14
+ <div style="border-radius: 18px; background: rgba(255,255,255,0.92); box-shadow: 0 24px 60px rgba(15,23,42,0.08); padding: 32px; min-height: 300px;">
15
+ <div style="font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #0ea5e9;">README / 全局模块</div>
16
+ <h1 style="margin: 12px 0 0; font-size: 36px; line-height: 1.15; font-weight: 700; color: #0f172a;">Storybook 基座</h1>
17
+ <p style="margin-top: 16px; max-width: 44rem; color: #334155; line-height: 1.9;">
18
+ 这个 story 复刻了 src/App.vue 的基础结构,包含公共头、面包屑、主内容区、左右侧栏和公共底。后续全局模块或内容组件都可以直接通过 parameters.shell 挂到对应区域里预览。
19
+ </p>
20
+ </div>
21
+ <div style="display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));">
22
+ <div style="border-radius: 16px; background: rgba(255,255,255,0.88); padding: 20px;">
23
+ <div style="font-weight: 700; color: #0f172a;">Header + Breadcrumb</div>
24
+ <p style="margin-top: 8px; color: #475569; line-height: 1.7;">模拟全局导航和频道入口。</p>
25
+ </div>
26
+ <div style="border-radius: 16px; background: rgba(255,255,255,0.88); padding: 20px;">
27
+ <div style="font-weight: 700; color: #0f172a;">Main + Sidebars</div>
28
+ <p style="margin-top: 8px; color: #475569; line-height: 1.7;">模拟详情页和筛选页的主要布局骨架。</p>
29
+ </div>
30
+ <div style="border-radius: 16px; background: rgba(255,255,255,0.88); padding: 20px;">
31
+ <div style="font-weight: 700; color: #0f172a;">Footer</div>
32
+ <p style="margin-top: 8px; color: #475569; line-height: 1.7;">保留全局落点,方便观察页面收尾效果。</p>
33
+ </div>
34
+ </div>
35
+ </section>
36
+ `,
37
+ }),
38
+ };
@@ -0,0 +1,40 @@
1
+ import Breadcrumb from '../../Breadcrumb.vue';
2
+
3
+ const meta = {
4
+ title: 'Layout/Breadcrumb',
5
+ component: Breadcrumb,
6
+ parameters: {
7
+ layout: 'fullscreen',
8
+ },
9
+ argTypes: {
10
+ publishEnable: { control: 'boolean' },
11
+ feedbackEnable: { control: 'boolean' },
12
+ adminEnable: { control: 'boolean' },
13
+ crumbEnable: { control: 'boolean' },
14
+ withoutLeft: { control: 'boolean' },
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ export const Default = {
21
+ args: {
22
+ name: '频道名称',
23
+ slug: 'story',
24
+ root: '/story',
25
+ publishEnable: true,
26
+ feedbackEnable: true,
27
+ adminEnable: false,
28
+ crumbEnable: false,
29
+ withoutLeft: false,
30
+ },
31
+ render: (args) => ({
32
+ components: { Breadcrumb },
33
+ setup() {
34
+ return { args };
35
+ },
36
+ template: `
37
+ <Breadcrumb v-bind="args" />
38
+ `,
39
+ }),
40
+ };
@@ -14,7 +14,7 @@ export const Default = {
14
14
  render: () => ({
15
15
  components: { CommonFooter },
16
16
  template: `
17
- <div style="min-height: 100vh; display: flex; align-items: flex-end; background: #111827;">
17
+ <div style="min-height: 100vh; display: flex; align-items: flex-end;">
18
18
  <CommonFooter style="width: 100%;" />
19
19
  </div>
20
20
  `,
@@ -23,7 +23,7 @@ export const Default = {
23
23
  return { args };
24
24
  },
25
25
  template: `
26
- <div style="min-height: 200vh; background: linear-gradient(180deg, #0b1220 0%, #1f2937 100%);">
26
+ <div style="min-height: 100vh;">
27
27
  <CommonHeader v-bind="args" />
28
28
  <div style="height: 1600px;"></div>
29
29
  </div>
@@ -0,0 +1,78 @@
1
+ import LeftSideToggle from '../../LeftSideToggle.vue';
2
+ import StoryPropsTable from '../components/StoryPropsTable.vue';
3
+ import Bus from '../../../utils/bus';
4
+
5
+ const meta = {
6
+ title: 'Layout/LeftSideToggle',
7
+ component: LeftSideToggle,
8
+ parameters: {
9
+ layout: 'fullscreen',
10
+ },
11
+ argTypes: {
12
+ mobileOnly: { control: 'boolean' },
13
+ },
14
+ };
15
+
16
+ export default meta;
17
+
18
+ export const Default = {
19
+ args: {
20
+ mobileOnly: false,
21
+ },
22
+ render: (args) => ({
23
+ components: { LeftSideToggle, StoryPropsTable },
24
+ setup() {
25
+ return { args };
26
+ },
27
+ data() {
28
+ return {
29
+ leftOpen: true,
30
+ propsInfo: [
31
+ { name: 'mobileOnly', type: 'Boolean', default: 'false', description: '是否只在移动端显示折叠按钮。' },
32
+ ],
33
+ };
34
+ },
35
+ mounted() {
36
+ this.__storyToggleHandler = (status) => {
37
+ this.leftOpen = status;
38
+ };
39
+ Bus.on('toggleLeftSide', this.__storyToggleHandler);
40
+ Bus.emit('toggleLeftSide', true);
41
+ },
42
+ beforeUnmount() {
43
+ if (this.__storyToggleHandler) {
44
+ Bus.off('toggleLeftSide', this.__storyToggleHandler);
45
+ this.__storyToggleHandler = null;
46
+ }
47
+ },
48
+ methods: {
49
+ reopen() {
50
+ Bus.emit('toggleLeftSide', true);
51
+ },
52
+ },
53
+ template: `
54
+ <div style="display:grid;gap:24px;">
55
+ <section style="border-radius:20px;background:rgba(255,255,255,0.92);padding:24px;box-shadow:0 24px 60px rgba(15,23,42,0.08);">
56
+ <div style="display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;">
57
+ <div>
58
+ <div style="font-size:12px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#0ea5e9;">layout</div>
59
+ <h2 style="margin:10px 0 0;font-size:28px;color:#0f172a;">LeftSideToggle</h2>
60
+ <p style="margin-top:12px;color:#475569;line-height:1.8;">点击图标会通过事件总线切换左栏开关,适合与 LeftSidebar、Main 配合使用。</p>
61
+ </div>
62
+ <div style="display:flex;align-items:center;gap:16px;">
63
+ <div style="padding:8px 14px;border-radius:999px;background:#e2e8f0;color:#0f172a;font-weight:700;">
64
+ 当前状态:{{ leftOpen ? '展开' : '收起' }}
65
+ </div>
66
+ <button type="button" class="el-button el-button--primary is-plain" @click="reopen">重置为展开</button>
67
+ </div>
68
+ </div>
69
+ <div style="margin-top:24px;display:flex;align-items:center;gap:16px;padding:20px;border-radius:16px;background:linear-gradient(135deg,#f8fafc 0%,#e0f2fe 100%);">
70
+ <LeftSideToggle v-bind="args" />
71
+ <div style="color:#334155;line-height:1.7;">左栏折叠按钮预览区域</div>
72
+ </div>
73
+ </section>
74
+ <StoryPropsTable title="LeftSideToggle" description="左侧边栏开关按钮,通过事件总线广播状态。" :items="propsInfo" />
75
+ </div>
76
+ `,
77
+ }),
78
+ };
@@ -0,0 +1,40 @@
1
+ import LeftSidebar from '../../LeftSidebar.vue';
2
+
3
+ const meta = {
4
+ title: 'Layout/LeftSidebar',
5
+ component: LeftSidebar,
6
+ parameters: {
7
+ layout: 'fullscreen',
8
+ },
9
+ argTypes: {
10
+ open: { control: 'boolean' },
11
+ withoutBread: { control: 'boolean' },
12
+ uid: { control: 'number' },
13
+ },
14
+ };
15
+
16
+ export default meta;
17
+
18
+ export const Default = {
19
+ args: {
20
+ open: true,
21
+ withoutBread: false,
22
+ uid: null,
23
+ },
24
+ render: (args) => ({
25
+ components: { LeftSidebar },
26
+ setup() {
27
+ return { args };
28
+ },
29
+ template: `
30
+ <LeftSidebar v-bind="args">
31
+ <div style="border-radius: 18px; background: rgba(255,255,255,0.88); padding: 20px; box-shadow: 0 24px 60px rgba(15,23,42,0.08);">
32
+ <div style="font-weight: 700; color: #0f172a;">LeftSidebar</div>
33
+ <p style="margin-top: 8px; color: #475569; line-height: 1.7;">
34
+ 左栏通常用于承载作者、分类导航、作品集或筛选补充信息。
35
+ </p>
36
+ </div>
37
+ </LeftSidebar>
38
+ `,
39
+ }),
40
+ };
@@ -0,0 +1,41 @@
1
+ import Main from '../../Main.vue';
2
+
3
+ const meta = {
4
+ title: 'Layout/Main',
5
+ component: Main,
6
+ parameters: {
7
+ layout: 'fullscreen',
8
+ },
9
+ argTypes: {
10
+ withoutLeft: { control: 'boolean' },
11
+ withoutRight: { control: 'boolean' },
12
+ withoutBread: { control: 'boolean' },
13
+ },
14
+ };
15
+
16
+ export default meta;
17
+
18
+ export const Default = {
19
+ args: {
20
+ withoutLeft: false,
21
+ withoutRight: false,
22
+ withoutBread: false,
23
+ },
24
+ render: (args) => ({
25
+ components: { Main },
26
+ setup() {
27
+ return { args };
28
+ },
29
+ template: `
30
+ <Main v-bind="args">
31
+ <div style="border-radius: 18px; background: rgba(255,255,255,0.92); box-shadow: 0 24px 60px rgba(15,23,42,0.08); padding: 32px; min-height: 360px;">
32
+ <div style="font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: #0ea5e9;">Main</div>
33
+ <h2 style="margin: 12px 0 0; font-size: 32px; line-height: 1.2; font-weight: 700; color: #0f172a;">主内容布局容器</h2>
34
+ <p style="margin-top: 16px; max-width: 42rem; color: #334155; line-height: 1.9;">
35
+ 这里模拟单页正文区域,你可以把详情组件、筛选模块或任何内容组件直接挂进来查看与左右栏组合后的效果。
36
+ </p>
37
+ </div>
38
+ </Main>
39
+ `,
40
+ }),
41
+ };