@keyflow2/keyflow-kit-store 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/icons/icon-128.png +0 -0
- package/icons/icon-256.png +0 -0
- package/icons/icon-48.png +0 -0
- package/icons/icon-64.png +0 -0
- package/icons/icon-96.png +0 -0
- package/manifest.json +106 -0
- package/package.json +25 -0
- package/ui/app/index.html +423 -0
- package/ui/app/main.js +968 -0
- package/ui/app/styles.css +969 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>下载中心</title>
|
|
7
|
+
<link rel="stylesheet" href="../../../shared/ui/ime-panel.css" />
|
|
8
|
+
<link rel="stylesheet" href="../../../shared/ui/kit-shadcn.css" />
|
|
9
|
+
<link rel="stylesheet" href="./styles.css" />
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div class="store-shell" id="app" v-cloak :data-route="route" :data-tab="tab" :data-detail-tab="detailTab">
|
|
13
|
+
<header class="store-topbar" :hidden="route !== 'home' || searchOpen">
|
|
14
|
+
<div class="store-tabs" role="tablist" aria-label="store tabs">
|
|
15
|
+
<button class="store-tab" type="button" :aria-selected="tab === 'discover' ? 'true' : 'false'" @click="setTab('discover')">
|
|
16
|
+
发现
|
|
17
|
+
</button>
|
|
18
|
+
<button class="store-tab" type="button" :aria-selected="tab === 'manage' ? 'true' : 'false'" @click="setTab('manage')">
|
|
19
|
+
管理
|
|
20
|
+
<span class="tab-badge" v-if="updateCount > 0">{{ updateCount > 99 ? '99+' : updateCount }}</span>
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="store-actions" aria-label="actions">
|
|
24
|
+
<button class="icon-button" type="button" aria-label="search" @click="openSearch">
|
|
25
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
26
|
+
<path
|
|
27
|
+
d="M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Zm6.7 1.4-4.1-4.1"
|
|
28
|
+
fill="none"
|
|
29
|
+
stroke="currentColor"
|
|
30
|
+
stroke-width="2"
|
|
31
|
+
stroke-linecap="round"
|
|
32
|
+
/>
|
|
33
|
+
</svg>
|
|
34
|
+
</button>
|
|
35
|
+
<button class="icon-button" type="button" aria-label="settings" @click="openSettings">
|
|
36
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
37
|
+
<path
|
|
38
|
+
d="M12 15.2a3.2 3.2 0 1 0 0-6.4 3.2 3.2 0 0 0 0 6.4Z"
|
|
39
|
+
fill="none"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
stroke-width="2"
|
|
42
|
+
/>
|
|
43
|
+
<path
|
|
44
|
+
d="M19.4 12a7.6 7.6 0 0 0-.1-1.3l2-1.6-2-3.4-2.5 1a7.8 7.8 0 0 0-2.2-1.3l-.4-2.7H10l-.4 2.7a7.8 7.8 0 0 0-2.2 1.3l-2.5-1-2 3.4 2 1.6a7.6 7.6 0 0 0-.1 1.3c0 .4 0 .9.1 1.3l-2 1.6 2 3.4 2.5-1a7.8 7.8 0 0 0 2.2 1.3l.4 2.7h4.2l.4-2.7a7.8 7.8 0 0 0 2.2-1.3l2.5 1 2-3.4-2-1.6c.1-.4.1-.9.1-1.3Z"
|
|
45
|
+
fill="none"
|
|
46
|
+
stroke="currentColor"
|
|
47
|
+
stroke-width="1.6"
|
|
48
|
+
stroke-linejoin="round"
|
|
49
|
+
/>
|
|
50
|
+
</svg>
|
|
51
|
+
</button>
|
|
52
|
+
<button class="icon-button" type="button" aria-label="import" @click="openImport">
|
|
53
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
54
|
+
<path
|
|
55
|
+
d="M12 5v14M5 12h14"
|
|
56
|
+
fill="none"
|
|
57
|
+
stroke="currentColor"
|
|
58
|
+
stroke-width="2"
|
|
59
|
+
stroke-linecap="round"
|
|
60
|
+
/>
|
|
61
|
+
</svg>
|
|
62
|
+
</button>
|
|
63
|
+
<button class="icon-button" type="button" aria-label="collapse" @click="collapsePanel">
|
|
64
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
65
|
+
<path
|
|
66
|
+
d="m6 14 6-6 6 6"
|
|
67
|
+
fill="none"
|
|
68
|
+
stroke="currentColor"
|
|
69
|
+
stroke-width="2"
|
|
70
|
+
stroke-linecap="round"
|
|
71
|
+
stroke-linejoin="round"
|
|
72
|
+
/>
|
|
73
|
+
</svg>
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
</header>
|
|
77
|
+
|
|
78
|
+
<header class="search-topbar" :hidden="route !== 'home' || !searchOpen">
|
|
79
|
+
<label class="search-field">
|
|
80
|
+
<span class="search-icon" aria-hidden="true">
|
|
81
|
+
<svg viewBox="0 0 24 24">
|
|
82
|
+
<path
|
|
83
|
+
d="M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Zm6.7 1.4-4.1-4.1"
|
|
84
|
+
fill="none"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
stroke-width="2"
|
|
87
|
+
stroke-linecap="round"
|
|
88
|
+
/>
|
|
89
|
+
</svg>
|
|
90
|
+
</span>
|
|
91
|
+
<input id="searchInput" type="search" placeholder="搜索名称或标签..." autocomplete="off" v-model="searchQuery" />
|
|
92
|
+
</label>
|
|
93
|
+
<button class="text-button" type="button" @click="closeSearch">取消</button>
|
|
94
|
+
</header>
|
|
95
|
+
|
|
96
|
+
<main class="store-main" id="homeView" :hidden="route !== 'home'">
|
|
97
|
+
<section class="store-list" aria-label="discover list" :hidden="tab !== 'discover' || searchOpen">
|
|
98
|
+
<div class="empty" v-if="discoverItems.length === 0">暂无可用目录,请先在设置里添加 Catalog 源</div>
|
|
99
|
+
<article class="kit-card" v-for="item in discoverItems" :key="item.kitId" :data-kit-id="item.kitId" @click="openDetail(item)">
|
|
100
|
+
<div class="ribbon" v-if="item.updateAvailable || item.featured" :class="item.updateAvailable ? 'ribbon--update' : ''">
|
|
101
|
+
{{ item.updateAvailable ? '更新' : '精选' }}
|
|
102
|
+
</div>
|
|
103
|
+
<div class="kit-icon" :class="item.iconClass">
|
|
104
|
+
<img v-if="item.iconUrl" :src="item.iconUrl" alt="" decoding="async" loading="lazy" />
|
|
105
|
+
<span v-else>{{ emojiFor(item.kitId) }}</span>
|
|
106
|
+
</div>
|
|
107
|
+
<div class="kit-info">
|
|
108
|
+
<h3 class="kit-title">{{ item.title }}</h3>
|
|
109
|
+
<div class="kit-subline">
|
|
110
|
+
<span class="tag-row" v-if="item.sub && item.sub.tags && item.sub.tags.length">
|
|
111
|
+
<span class="tag" v-for="tagText in item.sub.tags.slice(0, 2)" :key="tagText">{{ tagText }}</span>
|
|
112
|
+
</span>
|
|
113
|
+
<span class="tag-row" v-else-if="item.sub && item.sub.tag">
|
|
114
|
+
<span class="tag">{{ item.sub.tag }}</span>
|
|
115
|
+
</span>
|
|
116
|
+
<span class="subtext">{{ (item.sub && item.sub.desc) || '' }}</span>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
<button
|
|
120
|
+
class="kit-action"
|
|
121
|
+
type="button"
|
|
122
|
+
:class="item.action && (item.action.kind === 'install' || item.action.kind === 'update') ? 'kit-action--get' : 'kit-action--open'"
|
|
123
|
+
@click.stop="handleCardAction(item)"
|
|
124
|
+
>
|
|
125
|
+
{{ (item.action && item.action.label) || '打开' }}
|
|
126
|
+
</button>
|
|
127
|
+
</article>
|
|
128
|
+
</section>
|
|
129
|
+
|
|
130
|
+
<section class="store-list" aria-label="manage list" :hidden="tab !== 'manage' || searchOpen">
|
|
131
|
+
<div class="empty" v-if="manageItems.length === 0">暂无已安装功能件</div>
|
|
132
|
+
<article class="kit-card" v-for="item in manageItems" :key="item.kitId" :data-kit-id="item.kitId" @click="openDetail(item)">
|
|
133
|
+
<div class="ribbon" v-if="item.updateAvailable || item.featured" :class="item.updateAvailable ? 'ribbon--update' : ''">
|
|
134
|
+
{{ item.updateAvailable ? '更新' : '精选' }}
|
|
135
|
+
</div>
|
|
136
|
+
<div class="kit-icon" :class="item.iconClass">
|
|
137
|
+
<img v-if="item.iconUrl" :src="item.iconUrl" alt="" decoding="async" loading="lazy" />
|
|
138
|
+
<span v-else>{{ emojiFor(item.kitId) }}</span>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="kit-info">
|
|
141
|
+
<h3 class="kit-title">{{ item.title }}</h3>
|
|
142
|
+
<div class="kit-subline">
|
|
143
|
+
<span class="tag-row" v-if="item.sub && item.sub.tags && item.sub.tags.length">
|
|
144
|
+
<span class="tag" v-for="tagText in item.sub.tags.slice(0, 2)" :key="tagText">{{ tagText }}</span>
|
|
145
|
+
</span>
|
|
146
|
+
<span class="tag-row" v-else-if="item.sub && item.sub.tag">
|
|
147
|
+
<span class="tag">{{ item.sub.tag }}</span>
|
|
148
|
+
</span>
|
|
149
|
+
<span class="subtext">{{ (item.sub && item.sub.desc) || '' }}</span>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<button
|
|
153
|
+
class="kit-action"
|
|
154
|
+
type="button"
|
|
155
|
+
:class="item.action && (item.action.kind === 'install' || item.action.kind === 'update') ? 'kit-action--get' : 'kit-action--open'"
|
|
156
|
+
@click.stop="handleCardAction(item)"
|
|
157
|
+
>
|
|
158
|
+
{{ (item.action && item.action.label) || '打开' }}
|
|
159
|
+
</button>
|
|
160
|
+
</article>
|
|
161
|
+
</section>
|
|
162
|
+
|
|
163
|
+
<section class="store-list" aria-label="search list" :hidden="!searchOpen">
|
|
164
|
+
<div class="empty" v-if="searchItems.length === 0">{{ searchQuery.trim() ? '没有找到匹配结果' : '暂无内容' }}</div>
|
|
165
|
+
<article
|
|
166
|
+
class="kit-card"
|
|
167
|
+
v-for="item in searchItems"
|
|
168
|
+
:key="item.kind + ':' + item.kitId"
|
|
169
|
+
:data-kit-id="item.kitId"
|
|
170
|
+
@click="openDetail(item)"
|
|
171
|
+
>
|
|
172
|
+
<div class="ribbon" v-if="item.updateAvailable || item.featured" :class="item.updateAvailable ? 'ribbon--update' : ''">
|
|
173
|
+
{{ item.updateAvailable ? '更新' : '精选' }}
|
|
174
|
+
</div>
|
|
175
|
+
<div class="kit-icon" :class="item.iconClass">
|
|
176
|
+
<img v-if="item.iconUrl" :src="item.iconUrl" alt="" decoding="async" loading="lazy" />
|
|
177
|
+
<span v-else>{{ emojiFor(item.kitId) }}</span>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="kit-info">
|
|
180
|
+
<h3 class="kit-title">{{ item.title }}</h3>
|
|
181
|
+
<div class="kit-subline">
|
|
182
|
+
<span class="tag-row" v-if="item.sub && item.sub.tags && item.sub.tags.length">
|
|
183
|
+
<span class="tag" v-for="tagText in item.sub.tags.slice(0, 2)" :key="tagText">{{ tagText }}</span>
|
|
184
|
+
</span>
|
|
185
|
+
<span class="tag-row" v-else-if="item.sub && item.sub.tag">
|
|
186
|
+
<span class="tag">{{ item.sub.tag }}</span>
|
|
187
|
+
</span>
|
|
188
|
+
<span class="subtext">{{ (item.sub && item.sub.desc) || '' }}</span>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
<button
|
|
192
|
+
class="kit-action"
|
|
193
|
+
type="button"
|
|
194
|
+
:class="item.action && (item.action.kind === 'install' || item.action.kind === 'update') ? 'kit-action--get' : 'kit-action--open'"
|
|
195
|
+
@click.stop="handleCardAction(item)"
|
|
196
|
+
>
|
|
197
|
+
{{ (item.action && item.action.label) || '打开' }}
|
|
198
|
+
</button>
|
|
199
|
+
</article>
|
|
200
|
+
</section>
|
|
201
|
+
</main>
|
|
202
|
+
|
|
203
|
+
<footer class="store-pager" aria-label="pages" :hidden="route !== 'home'">
|
|
204
|
+
<button class="pager-dot" type="button" aria-label="发现" :aria-selected="tab === 'discover' ? 'true' : 'false'" @click="setTab('discover')"></button>
|
|
205
|
+
<button class="pager-dot" type="button" aria-label="管理" :aria-selected="tab === 'manage' ? 'true' : 'false'" @click="setTab('manage')"></button>
|
|
206
|
+
</footer>
|
|
207
|
+
|
|
208
|
+
<main class="store-main" :hidden="route !== 'settings'">
|
|
209
|
+
<header class="sub-topbar">
|
|
210
|
+
<button class="back-button" type="button" aria-label="back" @click="backFromSubView">
|
|
211
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
212
|
+
<path
|
|
213
|
+
d="m14 6-6 6 6 6"
|
|
214
|
+
fill="none"
|
|
215
|
+
stroke="currentColor"
|
|
216
|
+
stroke-width="2.2"
|
|
217
|
+
stroke-linecap="round"
|
|
218
|
+
stroke-linejoin="round"
|
|
219
|
+
/>
|
|
220
|
+
</svg>
|
|
221
|
+
</button>
|
|
222
|
+
<div class="sub-title">设置中心</div>
|
|
223
|
+
<div class="sub-spacer"></div>
|
|
224
|
+
</header>
|
|
225
|
+
|
|
226
|
+
<section class="settings-section">
|
|
227
|
+
<div class="settings-label">Catalog 源管理</div>
|
|
228
|
+
<div class="settings-list">
|
|
229
|
+
<div class="settings-item" v-for="source in catalogSources" :key="source.url">
|
|
230
|
+
<div class="settings-url">{{ source.url }}</div>
|
|
231
|
+
<button class="settings-remove" type="button" @click="removeCatalogSource(source.url)">移除</button>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div class="settings-row settings-row--add">
|
|
236
|
+
<input class="settings-input" placeholder="新 JSON 源" v-model="catalogAddUrl" />
|
|
237
|
+
<button class="pill pill--primary" type="button" @click="addCatalogSource">添加</button>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<button class="danger-link" type="button" @click="resetCatalogSources">恢复兜底默认设置</button>
|
|
241
|
+
</section>
|
|
242
|
+
</main>
|
|
243
|
+
|
|
244
|
+
<main class="store-main" :hidden="route !== 'import'">
|
|
245
|
+
<header class="sub-topbar sub-topbar--import">
|
|
246
|
+
<button class="text-button" type="button" @click="backFromSubView">取消</button>
|
|
247
|
+
<div class="sub-title">导入外部功能</div>
|
|
248
|
+
<button class="text-button text-button--disabled" type="button" disabled>完成</button>
|
|
249
|
+
</header>
|
|
250
|
+
|
|
251
|
+
<section class="import-section">
|
|
252
|
+
<input class="import-input" placeholder="npm:@keyflow2/keyflow-kit-wx-reply@0.2.10 或 https://...(.tgz/.zip)" v-model="importUrl" />
|
|
253
|
+
<button class="primary-wide" type="button" @click="installImportUrl">验证并安装</button>
|
|
254
|
+
<div class="or-divider">
|
|
255
|
+
<span>OR</span>
|
|
256
|
+
</div>
|
|
257
|
+
<button class="secondary-wide" type="button" @click="installFromZip">
|
|
258
|
+
<span class="plus" aria-hidden="true">+</span>
|
|
259
|
+
从本地选择 ZIP
|
|
260
|
+
</button>
|
|
261
|
+
</section>
|
|
262
|
+
</main>
|
|
263
|
+
|
|
264
|
+
<main class="store-main" :hidden="route !== 'detail'">
|
|
265
|
+
<header class="detail-topbar">
|
|
266
|
+
<button class="detail-back" type="button" @click="backFromDetail">
|
|
267
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
268
|
+
<path
|
|
269
|
+
d="m14 6-6 6 6 6"
|
|
270
|
+
fill="none"
|
|
271
|
+
stroke="currentColor"
|
|
272
|
+
stroke-width="2.2"
|
|
273
|
+
stroke-linecap="round"
|
|
274
|
+
stroke-linejoin="round"
|
|
275
|
+
/>
|
|
276
|
+
</svg>
|
|
277
|
+
返回
|
|
278
|
+
</button>
|
|
279
|
+
<div class="detail-more" aria-hidden="true"></div>
|
|
280
|
+
</header>
|
|
281
|
+
|
|
282
|
+
<div class="detail-scroll">
|
|
283
|
+
<section class="detail-header" v-if="selectedItem">
|
|
284
|
+
<div class="detail-icon">
|
|
285
|
+
<img v-if="selectedItem.iconUrl" :src="selectedItem.iconUrl" alt="" decoding="async" loading="lazy" />
|
|
286
|
+
<span v-else>{{ emojiFor(selectedItem.kitId) }}</span>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div class="detail-headline">
|
|
290
|
+
<div class="detail-title-row">
|
|
291
|
+
<h2 class="detail-title">{{ selectedItem.title }}</h2>
|
|
292
|
+
<span class="detail-badge" :style="{ visibility: selectedItem.featured ? 'visible' : 'hidden' }">精选</span>
|
|
293
|
+
</div>
|
|
294
|
+
<div class="detail-meta">{{ detailMeta }}</div>
|
|
295
|
+
</div>
|
|
296
|
+
<button
|
|
297
|
+
v-if="selectedItem.kind === 'package'"
|
|
298
|
+
class="kit-action kit-action--get"
|
|
299
|
+
type="button"
|
|
300
|
+
@click="installPackage(selectedItem.pkg)"
|
|
301
|
+
>
|
|
302
|
+
{{ selectedItem.action && selectedItem.action.kind === 'install' ? '获取' : selectedItem.action && selectedItem.action.kind === 'update' ? '更新' : '重新安装' }}
|
|
303
|
+
</button>
|
|
304
|
+
</section>
|
|
305
|
+
|
|
306
|
+
<nav class="segmented" aria-label="detail tabs">
|
|
307
|
+
<button class="segment" type="button" :aria-selected="detailTab === 'overview' ? 'true' : 'false'" @click="setDetailTab('overview')">
|
|
308
|
+
概览
|
|
309
|
+
</button>
|
|
310
|
+
<button class="segment" type="button" :aria-selected="detailTab === 'permissions' ? 'true' : 'false'" @click="setDetailTab('permissions')">
|
|
311
|
+
权限
|
|
312
|
+
</button>
|
|
313
|
+
<button class="segment" type="button" :aria-selected="detailTab === 'reviews' ? 'true' : 'false'" @click="setDetailTab('reviews')">
|
|
314
|
+
评价
|
|
315
|
+
</button>
|
|
316
|
+
<button class="segment" type="button" :aria-selected="detailTab === 'security' ? 'true' : 'false'" @click="setDetailTab('security')">
|
|
317
|
+
安全
|
|
318
|
+
</button>
|
|
319
|
+
</nav>
|
|
320
|
+
|
|
321
|
+
<section class="detail-body" v-if="selectedItem">
|
|
322
|
+
<section class="detail-card overview-card" v-if="detailTab === 'overview'">
|
|
323
|
+
<div class="overview-text">{{ overviewText }}</div>
|
|
324
|
+
<div>
|
|
325
|
+
<div class="version-row">
|
|
326
|
+
<div class="version-title">{{ versionTitle }}</div>
|
|
327
|
+
<div class="version-size">{{ versionSize }}</div>
|
|
328
|
+
</div>
|
|
329
|
+
<div class="version-note">{{ selectedItem.kitId }}</div>
|
|
330
|
+
</div>
|
|
331
|
+
</section>
|
|
332
|
+
|
|
333
|
+
<section class="detail-card" v-if="detailTab === 'permissions'">
|
|
334
|
+
<div class="list-header">
|
|
335
|
+
<span>声明权限</span>
|
|
336
|
+
<span class="risk" v-if="permissionRisky">
|
|
337
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
338
|
+
<path
|
|
339
|
+
d="M12 3 1.8 20.2c-.5.9.1 1.8 1.2 1.8h18c1.1 0 1.7-.9 1.2-1.8L12 3Z"
|
|
340
|
+
fill="none"
|
|
341
|
+
stroke="#FF3B30"
|
|
342
|
+
stroke-width="2"
|
|
343
|
+
/>
|
|
344
|
+
<path d="M12 9v5" stroke="#FF3B30" stroke-width="2" stroke-linecap="round" />
|
|
345
|
+
<path d="M12 17.2h.01" stroke="#FF3B30" stroke-width="3" stroke-linecap="round" />
|
|
346
|
+
</svg>
|
|
347
|
+
高风险
|
|
348
|
+
</span>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<div class="list-row" v-for="perm in detailPermissions" :key="perm">
|
|
352
|
+
<div>{{ permissionLabel(perm) }}</div>
|
|
353
|
+
<div class="row-dot"></div>
|
|
354
|
+
</div>
|
|
355
|
+
</section>
|
|
356
|
+
|
|
357
|
+
<section class="detail-card" v-if="detailTab === 'reviews'">
|
|
358
|
+
<div class="rating-head">
|
|
359
|
+
<div class="rating-left">
|
|
360
|
+
<div class="rating-score">4.8</div>
|
|
361
|
+
<div class="rating-meta">满分 5.0 (1250人)</div>
|
|
362
|
+
</div>
|
|
363
|
+
<button class="rating-action" type="button" @click="showToast('写评价')">写评价</button>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<div class="review-item" v-for="review in reviews" :key="review.name">
|
|
367
|
+
<div>
|
|
368
|
+
<div class="review-name">{{ review.name }}</div>
|
|
369
|
+
<div class="review-text">{{ review.text }}</div>
|
|
370
|
+
</div>
|
|
371
|
+
<div class="stars">{{ stars(review.stars) }}</div>
|
|
372
|
+
</div>
|
|
373
|
+
</section>
|
|
374
|
+
|
|
375
|
+
<section class="detail-card" v-if="detailTab === 'security'">
|
|
376
|
+
<div
|
|
377
|
+
class="link-row"
|
|
378
|
+
v-for="link in securityLinks"
|
|
379
|
+
:key="link.label"
|
|
380
|
+
:class="{ 'link-row--danger': link.kind === 'danger' }"
|
|
381
|
+
@click="showToast(link.label)"
|
|
382
|
+
>
|
|
383
|
+
<div>{{ link.label }}</div>
|
|
384
|
+
<span class="link-arrow" aria-hidden="true">
|
|
385
|
+
<svg v-if="link.icon === 'upright'" viewBox="0 0 24 24">
|
|
386
|
+
<path d="M7 17 17 7" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
|
|
387
|
+
<path
|
|
388
|
+
d="M10 7h7v7"
|
|
389
|
+
fill="none"
|
|
390
|
+
stroke="currentColor"
|
|
391
|
+
stroke-width="2.4"
|
|
392
|
+
stroke-linecap="round"
|
|
393
|
+
stroke-linejoin="round"
|
|
394
|
+
/>
|
|
395
|
+
</svg>
|
|
396
|
+
<svg v-else viewBox="0 0 24 24">
|
|
397
|
+
<path d="M6 12h12" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
|
|
398
|
+
<path
|
|
399
|
+
d="m14 7 5 5-5 5"
|
|
400
|
+
fill="none"
|
|
401
|
+
stroke="currentColor"
|
|
402
|
+
stroke-width="2.4"
|
|
403
|
+
stroke-linecap="round"
|
|
404
|
+
stroke-linejoin="round"
|
|
405
|
+
/>
|
|
406
|
+
</svg>
|
|
407
|
+
</span>
|
|
408
|
+
</div>
|
|
409
|
+
|
|
410
|
+
<button class="uninstall" type="button" @click="uninstallSelected">卸载组件</button>
|
|
411
|
+
</section>
|
|
412
|
+
</section>
|
|
413
|
+
</div>
|
|
414
|
+
</main>
|
|
415
|
+
|
|
416
|
+
<div class="toast" id="toast" :hidden="!toast.open">{{ toast.text }}</div>
|
|
417
|
+
</div>
|
|
418
|
+
|
|
419
|
+
<script src="../../../../function-kit-runtime-sdk/dist/function-kit-runtime.js"></script>
|
|
420
|
+
<script src="../../../shared/vendor/petite-vue/petite-vue.iife.js"></script>
|
|
421
|
+
<script src="./main.js"></script>
|
|
422
|
+
</body>
|
|
423
|
+
</html>
|