@lucifer.chao.du/home-schema-components 0.1.0
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/README.md +9 -0
- package/package.json +29 -0
- package/src/schema/index.d.ts +183 -0
- package/src/schema/index.js +413 -0
- package/src/web-preview/ActivitiesPreview.vue +120 -0
- package/src/web-preview/CommunitiesPreview.vue +74 -0
- package/src/web-preview/HomeSchemaPreview.vue +103 -0
- package/src/web-preview/ServicesPreview.vue +74 -0
- package/src/web-preview/TagsPreview.vue +507 -0
- package/src/web-preview/ToolsPreview.vue +49 -0
- package/src/web-preview/index.ts +6 -0
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { TagItem, TagsMode } from '../schema/index.js';
|
|
3
|
+
import type { ComponentPublicInstance } from 'vue';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
computed,
|
|
7
|
+
nextTick,
|
|
8
|
+
onBeforeUnmount,
|
|
9
|
+
onBeforeUpdate,
|
|
10
|
+
onMounted,
|
|
11
|
+
ref,
|
|
12
|
+
watch,
|
|
13
|
+
} from 'vue';
|
|
14
|
+
|
|
15
|
+
import { getTextInitial } from '../schema/index.js';
|
|
16
|
+
|
|
17
|
+
type DisplayLastRowData = {
|
|
18
|
+
displayLastRowItemGap: number;
|
|
19
|
+
placeholderWidth: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type DisplayTagData = {
|
|
23
|
+
displayTagCount: number;
|
|
24
|
+
showPlaceholderTag: boolean;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type TagLayoutSnapshot = {
|
|
28
|
+
placeholderTagWidth: number;
|
|
29
|
+
signature: string;
|
|
30
|
+
tagItemWidthList: number[];
|
|
31
|
+
tagListRow: number[];
|
|
32
|
+
tagListWidth: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const props = withDefaults(
|
|
36
|
+
defineProps<{
|
|
37
|
+
mode?: Partial<TagsMode>;
|
|
38
|
+
options?: TagItem[];
|
|
39
|
+
}>(),
|
|
40
|
+
{
|
|
41
|
+
mode: () => ({
|
|
42
|
+
displayRowCount: 4,
|
|
43
|
+
showIcon: true,
|
|
44
|
+
}),
|
|
45
|
+
options: () => [],
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const TAG_LAYOUT_STABLE_CHECK_LIMIT = 4;
|
|
50
|
+
const TAG_LAYOUT_STABLE_REQUIRED_COUNT = 2;
|
|
51
|
+
|
|
52
|
+
const containerRef = ref<HTMLElement | null>(null);
|
|
53
|
+
const placeholderTagRef = ref<HTMLElement | null>(null);
|
|
54
|
+
const tagItemRefs = ref<HTMLElement[]>([]);
|
|
55
|
+
const tagListExpanded = ref(false);
|
|
56
|
+
const tagListRow = ref<number[]>([]);
|
|
57
|
+
const tagListWidth = ref(0);
|
|
58
|
+
const tagItemWidthList = ref<number[]>([]);
|
|
59
|
+
const showAllTagsForMeasurement = ref(true);
|
|
60
|
+
const isMeasurePending = ref(false);
|
|
61
|
+
const currentMeasureVersion = ref(0);
|
|
62
|
+
const placeholderTagWidth = ref(0);
|
|
63
|
+
|
|
64
|
+
let resizeObserver: null | ResizeObserver = null;
|
|
65
|
+
|
|
66
|
+
const tagList = computed<TagItem[]>(() => {
|
|
67
|
+
if (props.options.length === 0) {
|
|
68
|
+
return Array.from({ length: 12 }, () => ({
|
|
69
|
+
icon: '',
|
|
70
|
+
path: undefined as never,
|
|
71
|
+
title: '',
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
return props.options;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const displayTagData = computed<DisplayTagData>(() => {
|
|
78
|
+
let currentRowTotalCount = 0;
|
|
79
|
+
let totalItems = 0;
|
|
80
|
+
for (const rowCount of tagListRow.value) {
|
|
81
|
+
totalItems += rowCount;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (tagListExpanded.value) {
|
|
85
|
+
return {
|
|
86
|
+
displayTagCount: totalItems,
|
|
87
|
+
showPlaceholderTag: true,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const maxDisplayRowCount = Math.max(props.mode.displayRowCount || 4, 1);
|
|
92
|
+
const maxRowIndex = Math.min(maxDisplayRowCount, tagListRow.value.length);
|
|
93
|
+
for (let index = 0; index < maxRowIndex; index += 1) {
|
|
94
|
+
currentRowTotalCount += tagListRow.value[index] || 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const showPlaceholderTag = currentRowTotalCount < totalItems;
|
|
98
|
+
return {
|
|
99
|
+
displayTagCount: showPlaceholderTag
|
|
100
|
+
? currentRowTotalCount - 1
|
|
101
|
+
: currentRowTotalCount,
|
|
102
|
+
showPlaceholderTag,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const showPlaceholderTag = computed(() => displayTagData.value.showPlaceholderTag);
|
|
107
|
+
const displayTagCount = computed(() => displayTagData.value.displayTagCount);
|
|
108
|
+
|
|
109
|
+
const displayLastRowCount = computed(() => {
|
|
110
|
+
let remainingTagCount = displayTagCount.value;
|
|
111
|
+
for (const rowCount of tagListRow.value) {
|
|
112
|
+
if (remainingTagCount <= 0) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
if (remainingTagCount > rowCount) {
|
|
116
|
+
remainingTagCount -= rowCount;
|
|
117
|
+
} else {
|
|
118
|
+
return remainingTagCount;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return 0;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const displayLastRowStartIndex = computed(() =>
|
|
125
|
+
Math.max(displayTagCount.value - displayLastRowCount.value, 0),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const displayLastRowData = computed<DisplayLastRowData>(() => {
|
|
129
|
+
if (displayLastRowCount.value === 0 || displayLastRowCount.value === 3) {
|
|
130
|
+
return {
|
|
131
|
+
displayLastRowItemGap: 0,
|
|
132
|
+
placeholderWidth: 0,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let displayLastRowWidth = 0;
|
|
137
|
+
for (
|
|
138
|
+
let index = displayLastRowStartIndex.value;
|
|
139
|
+
index < displayTagCount.value;
|
|
140
|
+
index += 1
|
|
141
|
+
) {
|
|
142
|
+
displayLastRowWidth += tagItemWidthList.value[index] || 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const placeholderWidthValue = tagListWidth.value - displayLastRowWidth;
|
|
146
|
+
const displayRemainWidth = Math.max(
|
|
147
|
+
tagListWidth.value - displayLastRowWidth - placeholderTagWidth.value,
|
|
148
|
+
0,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
displayLastRowItemGap: Math.max(displayRemainWidth / 4, 0),
|
|
153
|
+
placeholderWidth: placeholderWidthValue,
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const placeholderWidthValue = computed(
|
|
158
|
+
() => displayLastRowData.value.placeholderWidth,
|
|
159
|
+
);
|
|
160
|
+
const showPlaceholder = computed(() => placeholderWidthValue.value !== 0);
|
|
161
|
+
const displayLastRowItemGap = computed(
|
|
162
|
+
() => displayLastRowData.value.displayLastRowItemGap,
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
function normalizeMeasuredWidth(width: number) {
|
|
166
|
+
return Math.max(Math.round(width * 100), 0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function calculateTagListRow(itemWidthList: number[], containerWidth: number) {
|
|
170
|
+
const rowList: number[] = [];
|
|
171
|
+
let currentRowWidth = 0;
|
|
172
|
+
let currentRowCount = 0;
|
|
173
|
+
|
|
174
|
+
for (const itemWidth of itemWidthList) {
|
|
175
|
+
if (currentRowWidth + itemWidth > containerWidth && currentRowCount > 0) {
|
|
176
|
+
rowList.push(currentRowCount);
|
|
177
|
+
currentRowWidth = 0;
|
|
178
|
+
currentRowCount = 0;
|
|
179
|
+
}
|
|
180
|
+
currentRowWidth += itemWidth;
|
|
181
|
+
currentRowCount += 1;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (currentRowCount > 0) {
|
|
185
|
+
rowList.push(currentRowCount);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return rowList;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function createTagLayoutSnapshot(): null | TagLayoutSnapshot {
|
|
192
|
+
const container = containerRef.value;
|
|
193
|
+
if (!container) {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const tagListWidthValue = container.getBoundingClientRect().width;
|
|
198
|
+
if (tagListWidthValue <= 0) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const itemWidthList: number[] = [];
|
|
203
|
+
const normalizedWidthList: number[] = [];
|
|
204
|
+
for (const element of tagItemRefs.value) {
|
|
205
|
+
const itemWidth = element?.getBoundingClientRect().width || 0;
|
|
206
|
+
if (itemWidth <= 0) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
itemWidthList.push(itemWidth);
|
|
210
|
+
normalizedWidthList.push(normalizeMeasuredWidth(itemWidth));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (itemWidthList.length !== tagList.value.length) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const placeholderWidth =
|
|
218
|
+
props.options.length > 0
|
|
219
|
+
? placeholderTagRef.value?.getBoundingClientRect().width || 0
|
|
220
|
+
: 0;
|
|
221
|
+
if (props.options.length > 0 && placeholderWidth <= 0) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
placeholderTagWidth: placeholderWidth,
|
|
227
|
+
signature: [
|
|
228
|
+
normalizeMeasuredWidth(tagListWidthValue),
|
|
229
|
+
normalizeMeasuredWidth(placeholderWidth),
|
|
230
|
+
normalizedWidthList.join(','),
|
|
231
|
+
].join('|'),
|
|
232
|
+
tagItemWidthList: itemWidthList,
|
|
233
|
+
tagListRow: calculateTagListRow(itemWidthList, tagListWidthValue),
|
|
234
|
+
tagListWidth: tagListWidthValue,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function applyTagLayoutSnapshot(
|
|
239
|
+
measureVersion: number,
|
|
240
|
+
snapshot: TagLayoutSnapshot,
|
|
241
|
+
) {
|
|
242
|
+
if (measureVersion !== currentMeasureVersion.value) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
tagListWidth.value = snapshot.tagListWidth;
|
|
247
|
+
placeholderTagWidth.value = snapshot.placeholderTagWidth;
|
|
248
|
+
tagItemWidthList.value = snapshot.tagItemWidthList;
|
|
249
|
+
tagListRow.value = snapshot.tagListRow;
|
|
250
|
+
isMeasurePending.value = false;
|
|
251
|
+
showAllTagsForMeasurement.value = false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function applyTagLayoutFallback(measureVersion: number) {
|
|
255
|
+
if (measureVersion !== currentMeasureVersion.value) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
tagListWidth.value = 0;
|
|
260
|
+
placeholderTagWidth.value = 0;
|
|
261
|
+
tagItemWidthList.value = [];
|
|
262
|
+
tagListRow.value = [];
|
|
263
|
+
isMeasurePending.value = false;
|
|
264
|
+
showAllTagsForMeasurement.value = true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function runTagLayoutStableCheck(
|
|
268
|
+
measureVersion: number,
|
|
269
|
+
previousSignature = '',
|
|
270
|
+
stableCount = 0,
|
|
271
|
+
attemptCount = 0,
|
|
272
|
+
) {
|
|
273
|
+
if (measureVersion !== currentMeasureVersion.value) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
nextTick(() => {
|
|
278
|
+
window.requestAnimationFrame(() => {
|
|
279
|
+
if (measureVersion !== currentMeasureVersion.value) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const currentAttemptCount = attemptCount + 1;
|
|
284
|
+
const snapshot = createTagLayoutSnapshot();
|
|
285
|
+
if (!snapshot) {
|
|
286
|
+
if (currentAttemptCount >= TAG_LAYOUT_STABLE_CHECK_LIMIT) {
|
|
287
|
+
applyTagLayoutFallback(measureVersion);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
runTagLayoutStableCheck(
|
|
291
|
+
measureVersion,
|
|
292
|
+
previousSignature,
|
|
293
|
+
0,
|
|
294
|
+
currentAttemptCount,
|
|
295
|
+
);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const currentStableCount =
|
|
300
|
+
snapshot.signature === previousSignature ? stableCount + 1 : 1;
|
|
301
|
+
|
|
302
|
+
if (
|
|
303
|
+
currentStableCount >= TAG_LAYOUT_STABLE_REQUIRED_COUNT ||
|
|
304
|
+
currentAttemptCount >= TAG_LAYOUT_STABLE_CHECK_LIMIT
|
|
305
|
+
) {
|
|
306
|
+
applyTagLayoutSnapshot(measureVersion, snapshot);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
runTagLayoutStableCheck(
|
|
311
|
+
measureVersion,
|
|
312
|
+
snapshot.signature,
|
|
313
|
+
currentStableCount,
|
|
314
|
+
currentAttemptCount,
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function scheduleTagMeasure() {
|
|
321
|
+
currentMeasureVersion.value += 1;
|
|
322
|
+
isMeasurePending.value = true;
|
|
323
|
+
showAllTagsForMeasurement.value = true;
|
|
324
|
+
runTagLayoutStableCheck(currentMeasureVersion.value);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function isDisplayLastRowTag(index: number) {
|
|
328
|
+
return (
|
|
329
|
+
displayLastRowCount.value > 0 &&
|
|
330
|
+
index >= displayLastRowStartIndex.value &&
|
|
331
|
+
index < displayTagCount.value
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function setTagItemRef(
|
|
336
|
+
element: ComponentPublicInstance | Element | null,
|
|
337
|
+
index: number,
|
|
338
|
+
) {
|
|
339
|
+
if (element instanceof HTMLElement) {
|
|
340
|
+
tagItemRefs.value[index] = element;
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (element && '$el' in element && element.$el instanceof HTMLElement) {
|
|
345
|
+
tagItemRefs.value[index] = element.$el;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function toggleExpanded() {
|
|
350
|
+
tagListExpanded.value = !tagListExpanded.value;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
watch(
|
|
354
|
+
() => [props.options, props.mode.displayRowCount, props.mode.showIcon],
|
|
355
|
+
() => {
|
|
356
|
+
scheduleTagMeasure();
|
|
357
|
+
},
|
|
358
|
+
{ deep: true, immediate: true },
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
onBeforeUpdate(() => {
|
|
362
|
+
tagItemRefs.value = [];
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
onMounted(() => {
|
|
366
|
+
if (!containerRef.value) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
resizeObserver = new ResizeObserver(() => {
|
|
371
|
+
scheduleTagMeasure();
|
|
372
|
+
});
|
|
373
|
+
resizeObserver.observe(containerRef.value);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
onBeforeUnmount(() => {
|
|
377
|
+
resizeObserver?.disconnect();
|
|
378
|
+
});
|
|
379
|
+
</script>
|
|
380
|
+
|
|
381
|
+
<template>
|
|
382
|
+
<div ref="containerRef" class="home-schema-tags">
|
|
383
|
+
<template v-for="(tag, index) in tagList" :key="`tags-${index}`">
|
|
384
|
+
<button
|
|
385
|
+
v-show="showAllTagsForMeasurement || index < displayTagCount"
|
|
386
|
+
:ref="(element) => setTagItemRef(element, index)"
|
|
387
|
+
type="button"
|
|
388
|
+
class="home-schema-tags__item"
|
|
389
|
+
:class="{
|
|
390
|
+
'home-schema-tags__item--no-margin-bottom':
|
|
391
|
+
!isMeasurePending && isDisplayLastRowTag(index),
|
|
392
|
+
}"
|
|
393
|
+
:style="{
|
|
394
|
+
marginRight:
|
|
395
|
+
isMeasurePending || index < displayLastRowStartIndex
|
|
396
|
+
? '0px'
|
|
397
|
+
: `${displayLastRowItemGap}px`,
|
|
398
|
+
}"
|
|
399
|
+
>
|
|
400
|
+
<span
|
|
401
|
+
v-if="props.mode.showIcon"
|
|
402
|
+
class="home-schema-tags__icon"
|
|
403
|
+
>
|
|
404
|
+
{{ getTextInitial(tag.title) }}
|
|
405
|
+
</span>
|
|
406
|
+
<span class="home-schema-tags__text">
|
|
407
|
+
{{ tag.title || `标签 ${index + 1}` }}
|
|
408
|
+
</span>
|
|
409
|
+
</button>
|
|
410
|
+
</template>
|
|
411
|
+
|
|
412
|
+
<template v-if="props.options.length > 0">
|
|
413
|
+
<span
|
|
414
|
+
v-show="!isMeasurePending && showPlaceholder"
|
|
415
|
+
class="home-schema-tags__placeholder"
|
|
416
|
+
:style="{ flexBasis: `${placeholderWidthValue}px` }"
|
|
417
|
+
></span>
|
|
418
|
+
<button
|
|
419
|
+
v-show="isMeasurePending || showPlaceholderTag"
|
|
420
|
+
ref="placeholderTagRef"
|
|
421
|
+
type="button"
|
|
422
|
+
class="home-schema-tags__placeholder-tag"
|
|
423
|
+
:style="{
|
|
424
|
+
marginTop: displayLastRowCount === 3 ? '12px' : '0px',
|
|
425
|
+
pointerEvents: isMeasurePending ? 'none' : 'auto',
|
|
426
|
+
visibility: isMeasurePending ? 'hidden' : 'visible',
|
|
427
|
+
}"
|
|
428
|
+
@click="toggleExpanded"
|
|
429
|
+
>
|
|
430
|
+
<span>{{ tagListExpanded ? '收起' : '展开' }}</span>
|
|
431
|
+
<span class="home-schema-tags__placeholder-icon">
|
|
432
|
+
{{ tagListExpanded ? '↑' : '↓' }}
|
|
433
|
+
</span>
|
|
434
|
+
</button>
|
|
435
|
+
</template>
|
|
436
|
+
</div>
|
|
437
|
+
</template>
|
|
438
|
+
|
|
439
|
+
<style scoped>
|
|
440
|
+
.home-schema-tags {
|
|
441
|
+
display: flex;
|
|
442
|
+
flex-wrap: wrap;
|
|
443
|
+
justify-content: space-between;
|
|
444
|
+
gap: 0 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.home-schema-tags__item,
|
|
448
|
+
.home-schema-tags__placeholder-tag {
|
|
449
|
+
border: 0;
|
|
450
|
+
cursor: default;
|
|
451
|
+
display: inline-flex;
|
|
452
|
+
align-items: center;
|
|
453
|
+
border-radius: 10px;
|
|
454
|
+
background: rgb(255 255 255 / 85%);
|
|
455
|
+
box-shadow: 0 0 10px rgb(15 23 42 / 10%);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.home-schema-tags__item {
|
|
459
|
+
margin-bottom: 12px;
|
|
460
|
+
padding: 8px 10px;
|
|
461
|
+
background: rgb(248 250 252 / 90%);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.home-schema-tags__item--no-margin-bottom {
|
|
465
|
+
margin-bottom: 0;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.home-schema-tags__icon {
|
|
469
|
+
display: inline-flex;
|
|
470
|
+
align-items: center;
|
|
471
|
+
justify-content: center;
|
|
472
|
+
width: 18px;
|
|
473
|
+
height: 18px;
|
|
474
|
+
margin-right: 8px;
|
|
475
|
+
border-radius: 999px;
|
|
476
|
+
background: hsl(var(--primary) / 12%);
|
|
477
|
+
color: hsl(var(--primary));
|
|
478
|
+
font-size: 10px;
|
|
479
|
+
font-weight: 600;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.home-schema-tags__text {
|
|
483
|
+
min-width: 0;
|
|
484
|
+
color: hsl(var(--foreground));
|
|
485
|
+
font-size: 12px;
|
|
486
|
+
line-height: 1.4;
|
|
487
|
+
white-space: normal;
|
|
488
|
+
word-break: break-all;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.home-schema-tags__placeholder {
|
|
492
|
+
flex: 1 0 auto;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.home-schema-tags__placeholder-tag {
|
|
496
|
+
padding: 8px 10px;
|
|
497
|
+
color: hsl(var(--muted-foreground));
|
|
498
|
+
font-size: 12px;
|
|
499
|
+
line-height: 1.4;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.home-schema-tags__placeholder-icon {
|
|
503
|
+
margin-left: 6px;
|
|
504
|
+
color: hsl(var(--primary));
|
|
505
|
+
font-size: 12px;
|
|
506
|
+
}
|
|
507
|
+
</style>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type { ToolItem, ToolsMode } from '../schema/index.js';
|
|
3
|
+
|
|
4
|
+
import { computed } from 'vue';
|
|
5
|
+
|
|
6
|
+
import { getTextInitial } from '../schema/index.js';
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
mode?: Partial<ToolsMode>;
|
|
11
|
+
options?: ToolItem[];
|
|
12
|
+
}>(),
|
|
13
|
+
{
|
|
14
|
+
mode: () => ({
|
|
15
|
+
displayMultipleItems: 10,
|
|
16
|
+
displayRowCount: 5,
|
|
17
|
+
}),
|
|
18
|
+
options: () => [],
|
|
19
|
+
},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const visibleTools = computed(() =>
|
|
23
|
+
props.options.slice(0, props.mode.displayMultipleItems ?? 10),
|
|
24
|
+
);
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div
|
|
29
|
+
class="grid gap-2"
|
|
30
|
+
:style="{
|
|
31
|
+
gridTemplateColumns: `repeat(${props.mode.displayRowCount || 5}, minmax(0, 1fr))`,
|
|
32
|
+
}"
|
|
33
|
+
>
|
|
34
|
+
<div
|
|
35
|
+
v-for="(item, index) in visibleTools"
|
|
36
|
+
:key="`tools-${index}`"
|
|
37
|
+
class="grid gap-2 rounded-2xl border border-border bg-muted/30 px-2 py-3 text-center"
|
|
38
|
+
>
|
|
39
|
+
<div
|
|
40
|
+
class="mx-auto flex h-9 w-9 items-center justify-center rounded-full bg-primary/15 text-xs font-semibold text-primary"
|
|
41
|
+
>
|
|
42
|
+
{{ getTextInitial(item.title) }}
|
|
43
|
+
</div>
|
|
44
|
+
<div class="text-text-secondary truncate text-[11px] leading-4">
|
|
45
|
+
{{ item.title || `工具 ${index + 1}` }}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { default as ActivitiesPreview } from './ActivitiesPreview.vue';
|
|
2
|
+
export { default as CommunitiesPreview } from './CommunitiesPreview.vue';
|
|
3
|
+
export { default as HomeSchemaPreview } from './HomeSchemaPreview.vue';
|
|
4
|
+
export { default as ServicesPreview } from './ServicesPreview.vue';
|
|
5
|
+
export { default as TagsPreview } from './TagsPreview.vue';
|
|
6
|
+
export { default as ToolsPreview } from './ToolsPreview.vue';
|