@mixd-id/web-scaffold 0.1.230406124 → 0.1.230406126
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/package.json +1 -1
- package/src/components/ListView.vue +267 -174
- package/src/components/Tabs.vue +2 -2
- package/src/components/VirtualGrid.vue +269 -0
- package/src/components/VirtualScroll.vue +19 -8
- package/src/components/VirtualTable.vue +5 -3
- package/src/index.js +40 -0
- package/src/themes/default/index.js +17 -2
- package/src/utils/listview.js +0 -4
- package/src/widgets/BoxSetting.vue +3 -1
- package/src/widgets/FeatureList.vue +12 -14
- package/src/widgets/FeatureListSetting.vue +34 -1
- package/src/widgets/WebPageBuilder.vue +32 -2
package/package.json
CHANGED
|
@@ -1,167 +1,209 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<div class="
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<div class="flex-1 flex flex-col gap-4 md:w-[270px] cursor-pointer p-6">
|
|
16
|
-
<div class="pb-0 flex flex-row gap-4">
|
|
17
|
-
<h4 class="flex-1">Select Preset</h4>
|
|
18
|
-
<button type="button" class="text-primary" @click="openPreset">Settings</button>
|
|
2
|
+
<Suspense>
|
|
3
|
+
<div :class="$style.comp" v-if="configLoaded">
|
|
4
|
+
|
|
5
|
+
<slot v-if="$slots.head" name="head"></slot>
|
|
6
|
+
<div v-else :class="$style.toolbar">
|
|
7
|
+
<div class="flex-1 flex flex-row gap-6">
|
|
8
|
+
<button type="button" ref="presetSelectorBtn"
|
|
9
|
+
class="flex-1 md:flex-none flex flex-col text-left md:ml-2 leading-tight"
|
|
10
|
+
@click="$refs.presetSelector.toggle($refs.presetSelectorBtn)">
|
|
11
|
+
<small v-if="title" class="text-text-400 text-xs">{{ title }}</small>
|
|
12
|
+
<div class="flex flex-row items-center">
|
|
13
|
+
<h3 class="overflow-hidden whitespace-nowrap text-ellipsis">{{ preset.name }}</h3>
|
|
14
|
+
<svg width="13" height="13" class="ml-1 relative top-[2px] fill-text hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"/></svg>
|
|
19
15
|
</div>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</div>
|
|
28
|
-
</ContextMenu>
|
|
29
|
-
|
|
30
|
-
<div class="absolute">
|
|
31
|
-
<Modal ref="setting" width="680" height="560" position="bottom">
|
|
32
|
-
<template #head>
|
|
33
|
-
<div class="relative">
|
|
34
|
-
<div class="absolute top-0 right-0 p-2 py-3">
|
|
35
|
-
<button type="button" class="p-2" @click="$refs.setting.close()">
|
|
36
|
-
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
37
|
-
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
38
|
-
</svg>
|
|
39
|
-
</button>
|
|
40
|
-
</div>
|
|
16
|
+
</button>
|
|
17
|
+
|
|
18
|
+
<ContextMenu ref="presetSelector">
|
|
19
|
+
<div class="flex-1 flex flex-col gap-4 md:w-[270px] cursor-pointer p-6">
|
|
20
|
+
<div class="pb-0 flex flex-row gap-4">
|
|
21
|
+
<h4 class="flex-1">Select Preset</h4>
|
|
22
|
+
<button type="button" class="text-primary" @click="openPreset">Settings</button>
|
|
41
23
|
</div>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
24
|
+
<div class="border-text-50 border-[1px] divide-y divide-text-50 bg-base-400 rounded-lg overflow-hidden">
|
|
25
|
+
<button type="button" v-for="(preset, idx) in config.presets"
|
|
26
|
+
class="p-3 text-left hover:bg-primary hover:text-white block w-full"
|
|
27
|
+
@click="selectPreset(idx)">
|
|
28
|
+
{{ preset.name }}
|
|
29
|
+
</button>
|
|
46
30
|
</div>
|
|
47
|
-
</
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
</div>
|
|
32
|
+
</ContextMenu>
|
|
33
|
+
|
|
34
|
+
<div class="absolute">
|
|
35
|
+
<Modal ref="setting" width="680" height="560" position="bottom">
|
|
36
|
+
<template #head>
|
|
37
|
+
<div class="relative">
|
|
38
|
+
<div class="absolute top-0 right-0 p-2 py-3">
|
|
39
|
+
<button type="button" class="p-2" @click="$refs.setting.close()">
|
|
40
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
41
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
47
|
+
<template #foot>
|
|
48
|
+
<div class="p-6 py-4 border-t-[1px] border-text-50">
|
|
49
|
+
<Button class="w-full md:w-[90px]" @click="applyPreset">Apply</Button>
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|
|
52
|
+
<ListViewSettings ref="listviewSettings" class="flex-1"
|
|
53
|
+
:config="copiedConfig" />
|
|
54
|
+
</Modal>
|
|
55
|
+
</div>
|
|
51
56
|
</div>
|
|
52
|
-
</div>
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
<slot name="headerOpt"></slot>
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
<Textbox v-if="$screenPrefix.value !== ''" :placeholder="$t('Search...')" :clearable="true"
|
|
61
|
+
@clear="clearSearch" v-model="preset.search"
|
|
62
|
+
@keyup.enter="load" :class="$style.searchBox">
|
|
63
|
+
<template #start>
|
|
64
|
+
<div class="pl-2">
|
|
65
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 481.6l-129-129c-2.3-2.3-5.3-3.5-8.5-3.5h-10.3C395 312 416 262.5 416 208 416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c54.5 0 104-21 141.1-55.2V371c0 3.2 1.3 6.2 3.5 8.5l129 129c4.7 4.7 12.3 4.7 17 0l9.9-9.9c4.7-4.7 4.7-12.3 0-17zM208 384c-97.3 0-176-78.7-176-176S110.7 32 208 32s176 78.7 176 176-78.7 176-176 176z"/></svg>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
</Textbox>
|
|
69
|
+
|
|
70
|
+
<div v-if="$screenPrefix.value !== ''">
|
|
71
|
+
<button type="button" class="p-2" @click="changeViewType('grid')" v-tooltip="'Grid'">
|
|
72
|
+
<svg width="16" height="16" :class="computedViewType === 'grid' ? 'fill-primary' : 'fill-text-300 hover:fill-primary'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 424H304a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0-128H304a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0-128H304a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0-128H304a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16zM208 296H16a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0 128H16a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm0-384H16A16 16 0 0 0 0 56v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16zm0 128H16a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16z"/></svg>
|
|
73
|
+
</button>
|
|
74
|
+
<button type="button" class="p-2" @click="changeViewType('table')" v-tooltip="'Table'">
|
|
75
|
+
<svg width="16" height="16" :class="computedViewType === 'table' ? 'fill-primary' : 'fill-text-300 hover:fill-primary'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM232 432H54a6 6 0 0 1-6-6V296h184v136zm0-184H48V112h184v136zm226 184H280V296h184v130a6 6 0 0 1-6 6zm6-184H280V112h184v136z"/></svg>
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
<div v-if="$screenPrefix.value === ''" class="px-6 pb-4 border-b-[1px] border-text-50 bg-base-400 dark:bg-base-300">
|
|
81
|
+
<Textbox :placeholder="$t('Search...')" :clearable="true" @clear="clearSearch" v-model="preset.search"
|
|
82
|
+
@keyup.enter="load" :class="$style.searchBox2">
|
|
83
|
+
<template #start>
|
|
84
|
+
<div class="pl-2">
|
|
85
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 481.6l-129-129c-2.3-2.3-5.3-3.5-8.5-3.5h-10.3C395 312 416 262.5 416 208 416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c54.5 0 104-21 141.1-55.2V371c0 3.2 1.3 6.2 3.5 8.5l129 129c4.7 4.7 12.3 4.7 17 0l9.9-9.9c4.7-4.7 4.7-12.3 0-17zM208 384c-97.3 0-176-78.7-176-176S110.7 32 208 32s176 78.7 176 176-78.7 176-176 176z"/></svg>
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
88
|
+
</Textbox>
|
|
89
|
+
</div>
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
<div v-if="presetSummary && summary" class="h-[300px] max-h-[30vh] flex">
|
|
92
|
+
<Bar v-if="presetSummary.mode === 'bar'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
|
|
93
|
+
<Line v-else-if="presetSummary.mode === 'line'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
|
|
94
|
+
<VirtualTable v-else-if="presetSummary.mode === 'table'" :items="summaryItems" :columns="summaryColumns" class="flex-1"></VirtualTable>
|
|
95
|
+
<Gmaps v-else-if="presetSummary.mode === 'map'" :data="summary.items" :config="presetSummary.map"
|
|
96
|
+
class="flex-1 w-full p-2" :apiKey="mapApiKey" />
|
|
97
|
+
</div>
|
|
85
98
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
<div class="flex-1 flex">
|
|
100
|
+
<VirtualScroll v-if="computedViewType === 'feed'"
|
|
101
|
+
:items="items"
|
|
102
|
+
ref="table1"
|
|
103
|
+
class="flex-1"
|
|
104
|
+
@scroll-end="loadNext">
|
|
105
|
+
<template #item="{ item }">
|
|
106
|
+
<slot name="mobileItem" :item="item">
|
|
107
|
+
<div :class="$style.mobileItem">
|
|
108
|
+
<strong>{{ item.name }}</strong>
|
|
109
|
+
</div>
|
|
110
|
+
</slot>
|
|
111
|
+
</template>
|
|
112
|
+
</VirtualScroll>
|
|
113
|
+
|
|
114
|
+
<VirtualGrid v-else-if="computedViewType === 'grid'"
|
|
115
|
+
:items="items"
|
|
116
|
+
:column="gridColumn"
|
|
117
|
+
:gap="gridGap"
|
|
118
|
+
class="flex-1"
|
|
119
|
+
ref="table1"
|
|
120
|
+
:opt-bar="optBar"
|
|
121
|
+
@scroll-end="loadNext"
|
|
122
|
+
:config="config">
|
|
123
|
+
<template #item="{ item }">
|
|
124
|
+
<slot name="gridItem" :item="item">
|
|
125
|
+
<div :class="$style.mobileItem">
|
|
126
|
+
<strong>{{ item.name }}</strong>
|
|
127
|
+
</div>
|
|
128
|
+
</slot>
|
|
129
|
+
</template>
|
|
130
|
+
</VirtualGrid>
|
|
131
|
+
|
|
132
|
+
<VirtualTable v-else-if="computedViewType === 'table'"
|
|
133
|
+
ref="table1"
|
|
134
|
+
:columns="presetColumns"
|
|
135
|
+
:items="items"
|
|
136
|
+
class="flex-1 bg-base-400"
|
|
137
|
+
@scroll-end="loadNext">
|
|
138
|
+
<template v-for="column in presetColumns" #[colOf(column.key)]="{}">
|
|
139
|
+
<div :class="getHeader(column)" @click="openColumnOptions(column.key, $event.target.closest('.' + $style.header))">
|
|
140
|
+
<div>
|
|
141
|
+
{{ column.label ?? column.key }}
|
|
142
|
+
</div>
|
|
143
|
+
<div class="absolute top-0 right-0 p-2 bg-base-500" v-if="presetSortedColumns[column.key] === 'asc'">
|
|
144
|
+
<svg width="19" height="19" viewBox="0 0 24 24" class="fill-text-400" xmlns="http://www.w3.org/2000/svg">
|
|
145
|
+
<path d="M6.75 5C6.75 4.58579 6.41421 4.25 6 4.25C5.58579 4.25 5.25 4.58579 5.25 5V17.6893L3.53033 15.9697C3.23744 15.6768 2.76256 15.6768 2.46967 15.9697C2.17678 16.2626 2.17678 16.7374 2.46967 17.0303L4.76256 19.3232C5.44598 20.0066 6.55402 20.0066 7.23744 19.3232L9.53033 17.0303C9.82322 16.7374 9.82322 16.2626 9.53033 15.9697C9.23744 15.6768 8.76256 15.6768 8.46967 15.9697L6.75 17.6893V5Z"/>
|
|
146
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 17C12.25 17.4142 12.5858 17.75 13 17.75H21C21.4142 17.75 21.75 17.4142 21.75 17C21.75 16.5858 21.4142 16.25 21 16.25H13C12.5858 16.25 12.25 16.5858 12.25 17Z"/>
|
|
147
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 12C12.25 11.5858 12.5858 11.25 13 11.25H18C18.4142 11.25 18.75 11.5858 18.75 12C18.75 12.4142 18.4142 12.75 18 12.75H13C12.5858 12.75 12.25 12.4142 12.25 12Z"/>
|
|
148
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 7C12.25 6.58579 12.5858 6.25 13 6.25H15C15.4142 6.25 15.75 6.58579 15.75 7C15.75 7.41421 15.4142 7.75 15 7.75H13C12.5858 7.75 12.25 7.41421 12.25 7Z"/>
|
|
149
|
+
</svg>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="absolute top-0 right-0 p-2 bg-base-500" v-else-if="presetSortedColumns[column.key] === 'desc'">
|
|
152
|
+
<svg width="19" height="19" viewBox="0 0 24 24" class="fill-text-400" xmlns="http://www.w3.org/2000/svg">
|
|
153
|
+
<path d="M6.75 5C6.75 4.58579 6.41421 4.25 6 4.25C5.58579 4.25 5.25 4.58579 5.25 5V17.6893L3.53033 15.9697C3.23744 15.6768 2.76256 15.6768 2.46967 15.9697C2.17678 16.2626 2.17678 16.7374 2.46967 17.0303L4.76256 19.3232C5.44598 20.0066 6.55402 20.0066 7.23744 19.3232L9.53033 17.0303C9.82322 16.7374 9.82322 16.2626 9.53033 15.9697C9.23744 15.6768 8.76256 15.6768 8.46967 15.9697L6.75 17.6893V5Z"/>
|
|
154
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 7C12.25 6.58579 12.5858 6.25 13 6.25H21C21.4142 6.25 21.75 6.58579 21.75 7C21.75 7.41421 21.4142 7.75 21 7.75H13C12.5858 7.75 12.25 7.41421 12.25 7Z"/>
|
|
155
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 12C12.25 12.4142 12.5858 12.75 13 12.75H18C18.4142 12.75 18.75 12.4142 18.75 12C18.75 11.5858 18.4142 11.25 18 11.25H13C12.5858 11.25 12.25 11.5858 12.25 12Z"/>
|
|
156
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 17C12.25 17.4142 12.5858 17.75 13 17.75H15C15.4142 17.75 15.75 17.4142 15.75 17C15.75 16.5858 15.4142 16.25 15 16.25H13C12.5858 16.25 12.25 16.5858 12.25 17Z"/>
|
|
157
|
+
</svg>
|
|
158
|
+
</div>
|
|
109
159
|
</div>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 12C12.25 12.4142 12.5858 12.75 13 12.75H18C18.4142 12.75 18.75 12.4142 18.75 12C18.75 11.5858 18.4142 11.25 18 11.25H13C12.5858 11.25 12.25 11.5858 12.25 12Z"/>
|
|
115
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.25 17C12.25 17.4142 12.5858 17.75 13 17.75H15C15.4142 17.75 15.75 17.4142 15.75 17C15.75 16.5858 15.4142 16.25 15 16.25H13C12.5858 16.25 12.25 16.5858 12.25 17Z"/>
|
|
116
|
-
</svg>
|
|
160
|
+
</template>
|
|
161
|
+
<template v-for="(_, slot) in headerSlots" #[slot]="{ item, index }">
|
|
162
|
+
<div :class="getHeader(slot.replace('col-', ''))">
|
|
163
|
+
<slot :name="slot" :item="item" :index="index"></slot>
|
|
117
164
|
</div>
|
|
118
|
-
</
|
|
119
|
-
|
|
120
|
-
<template v-for="(_, slot) in headerSlots" #[slot]="{ item, index }">
|
|
121
|
-
<div :class="getHeader(slot.replace('col-', ''))">
|
|
165
|
+
</template>
|
|
166
|
+
<template v-for="(_, slot) in contentSlots" #[slot]="{ item, index }">
|
|
122
167
|
<slot :name="slot" :item="item" :index="index"></slot>
|
|
123
|
-
</
|
|
124
|
-
</
|
|
125
|
-
|
|
126
|
-
<slot :name="slot" :item="item" :index="index"></slot>
|
|
127
|
-
</template>
|
|
128
|
-
</VirtualTable>
|
|
129
|
-
</div>
|
|
168
|
+
</template>
|
|
169
|
+
</VirtualTable>
|
|
170
|
+
</div>
|
|
130
171
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
</div>
|
|
141
|
-
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
142
|
-
<div class="flex flex-col">
|
|
143
|
-
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="hide">Hide</div>
|
|
144
|
-
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="openPreset();$refs.columnMenu.close()">Column Options</div>
|
|
145
|
-
</div>
|
|
146
|
-
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
147
|
-
<div class="flex flex-col">
|
|
148
|
-
<div class="flex flex-row gap-2 items-center">
|
|
149
|
-
<div class="p-2 text-text-300 flex-1">Filters</div>
|
|
150
|
-
<div class="text-primary cursor-pointer text-sm" @click="openPreset('filter');$refs.columnMenu.close()">Filter Options</div>
|
|
172
|
+
<ContextMenu ref="columnMenu" :dismiss="false">
|
|
173
|
+
<div class="flex-1 flex flex-col w-[270px] p-3">
|
|
174
|
+
<div class="flex flex-col">
|
|
175
|
+
<div class="flex flex-row gap-2 items-center">
|
|
176
|
+
<div class="p-2 text-text-300 flex-1">Sort By</div>
|
|
177
|
+
<div class="text-primary cursor-pointer text-sm" @click="openPreset('sort');$refs.columnMenu.close()">Sort Options</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="setSortCurrent(1)">Sort Ascending</div>
|
|
180
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="setSortCurrent(2)">Sort Descending</div>
|
|
151
181
|
</div>
|
|
152
|
-
<div
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
183
|
+
<div class="flex flex-col">
|
|
184
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="hide">Hide</div>
|
|
185
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click="openPreset();$refs.columnMenu.close()">Column Options</div>
|
|
156
186
|
</div>
|
|
157
|
-
<div
|
|
158
|
-
|
|
187
|
+
<div class="h-[1px] bg-text-50 my-2"></div>
|
|
188
|
+
<div class="flex flex-col">
|
|
189
|
+
<div class="flex flex-row gap-2 items-center">
|
|
190
|
+
<div class="p-2 text-text-300 flex-1">Filters</div>
|
|
191
|
+
<div class="text-primary cursor-pointer text-sm" @click="openPreset('filter');$refs.columnMenu.close()">Filter Options</div>
|
|
192
|
+
</div>
|
|
193
|
+
<div v-if="presetCurrentFilters.length > 0">
|
|
194
|
+
<ListPage1Filter v-if="preset.filters" v-for="filter in presetCurrentFilters"
|
|
195
|
+
:filter="filter" :column="config.columns[config.columns.findIndex((_) => _.key === filter.key)]"
|
|
196
|
+
@remove="removeFilter(filter)" @change="load" />
|
|
197
|
+
</div>
|
|
198
|
+
<div v-else>
|
|
199
|
+
<div class="p-2 cursor-pointer" :class="$style.hoverable" @click.stop="addCurrentFilter">Add Filter</div>
|
|
200
|
+
</div>
|
|
159
201
|
</div>
|
|
160
202
|
</div>
|
|
161
|
-
</
|
|
162
|
-
</ContextMenu>
|
|
203
|
+
</ContextMenu>
|
|
163
204
|
|
|
164
|
-
|
|
205
|
+
</div>
|
|
206
|
+
</Suspense>
|
|
165
207
|
</template>
|
|
166
208
|
|
|
167
209
|
<script>
|
|
@@ -170,10 +212,9 @@ import throttle from "lodash/throttle";
|
|
|
170
212
|
import { Bar, Line } from 'vue-chartjs'
|
|
171
213
|
import Chart from 'chart.js/auto'
|
|
172
214
|
import dayjs from "dayjs";
|
|
173
|
-
import VirtualTable from "./VirtualTable.vue"
|
|
174
215
|
|
|
175
216
|
export default{
|
|
176
|
-
components: {Line, Bar
|
|
217
|
+
components: {Line, Bar},
|
|
177
218
|
|
|
178
219
|
emits: [ ],
|
|
179
220
|
|
|
@@ -192,7 +233,11 @@ export default{
|
|
|
192
233
|
configStore: String,
|
|
193
234
|
subscription: String,
|
|
194
235
|
|
|
195
|
-
title: String
|
|
236
|
+
title: String,
|
|
237
|
+
|
|
238
|
+
optBar: String,
|
|
239
|
+
|
|
240
|
+
containerClass: String
|
|
196
241
|
|
|
197
242
|
},
|
|
198
243
|
|
|
@@ -256,6 +301,10 @@ export default{
|
|
|
256
301
|
this.mediaPrefix = prefix
|
|
257
302
|
},
|
|
258
303
|
|
|
304
|
+
changeViewType(type){
|
|
305
|
+
this.config.viewType = type
|
|
306
|
+
},
|
|
307
|
+
|
|
259
308
|
clearSearch(){
|
|
260
309
|
this.preset.search = ''
|
|
261
310
|
this.load()
|
|
@@ -284,20 +333,27 @@ export default{
|
|
|
284
333
|
async load(){
|
|
285
334
|
if(!this.src) return
|
|
286
335
|
|
|
287
|
-
this.$refs.table1 ? this.$refs.table1.setState(3) :
|
|
288
|
-
|
|
289
|
-
|
|
336
|
+
this.$refs.table1 ? this.$refs.table1.setState(3) : null
|
|
337
|
+
|
|
338
|
+
let itemsPerPage = 16
|
|
339
|
+
switch(this.computedViewType){
|
|
340
|
+
case 'grid':
|
|
341
|
+
itemsPerPage *= this.gridColumn
|
|
342
|
+
break
|
|
343
|
+
case 'table':
|
|
344
|
+
itemsPerPage = 24
|
|
345
|
+
break
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.socketEmit2(this.src, { columns:this.config.columns, preset:this.preset, itemsPerPage })
|
|
290
349
|
.then((res) => {
|
|
291
350
|
Object.assign(this.$data, res)
|
|
292
351
|
})
|
|
293
|
-
.finally(() =>
|
|
294
|
-
this.$refs.table1 ? this.$refs.table1.setState(1) :
|
|
295
|
-
(this.$refs.table2 ? this.$refs.table2.setState(1) : null)
|
|
296
|
-
})
|
|
352
|
+
.finally(() => this.$refs.table1 ? this.$refs.table1.resetState() : null)
|
|
297
353
|
},
|
|
298
354
|
|
|
299
355
|
loadNext(){
|
|
300
|
-
this.$refs.table1 ? this.$refs.table1.setState(2) :
|
|
356
|
+
this.$refs.table1 ? this.$refs.table1.setState(2) : null
|
|
301
357
|
this.socketEmit2(this.src, {
|
|
302
358
|
preset: this.preset,
|
|
303
359
|
afterItem: this.items[this.items.length - 1]
|
|
@@ -309,33 +365,27 @@ export default{
|
|
|
309
365
|
.catch((err) => {
|
|
310
366
|
this.toast(err)
|
|
311
367
|
})
|
|
312
|
-
.finally(() =>
|
|
313
|
-
this.$refs.table1 ? this.$refs.table1.setState(1) : this.$refs.table2.setState(1)
|
|
314
|
-
})
|
|
368
|
+
.finally(() => this.$refs.table1 ? this.$refs.table1.resetState() : null)
|
|
315
369
|
},
|
|
316
370
|
|
|
317
371
|
async loadConfig(){
|
|
318
|
-
|
|
319
372
|
if(!this.configStoreObj || 'reset' in ((this.$route ?? {}).query ?? {})){
|
|
320
373
|
this.configLoaded = true
|
|
321
|
-
|
|
322
374
|
if('reset' in ((this.$route ?? {}).query ?? {}))
|
|
323
375
|
await this.saveConfig()
|
|
324
|
-
|
|
325
|
-
return
|
|
326
376
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
377
|
+
else{
|
|
378
|
+
switch(this.configStoreObj.type){
|
|
379
|
+
case 'socket':
|
|
380
|
+
return this.socketEmit2(this.configStoreObj.src,
|
|
331
381
|
{ key:this.configStoreObj.name ?? 'ListView' })
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
382
|
+
.then((config) => {
|
|
383
|
+
if(config && Array.isArray(config.columns)){
|
|
384
|
+
Object.assign(this.config, config ?? {})
|
|
385
|
+
}
|
|
386
|
+
this.configLoaded = true
|
|
387
|
+
})
|
|
388
|
+
}
|
|
339
389
|
}
|
|
340
390
|
},
|
|
341
391
|
|
|
@@ -533,6 +583,17 @@ export default{
|
|
|
533
583
|
|
|
534
584
|
computed: {
|
|
535
585
|
|
|
586
|
+
computedViewType(){
|
|
587
|
+
if(!this.config.viewType){
|
|
588
|
+
this.config.viewType = 'table'
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if(this.$screenPrefix.value === ''){
|
|
592
|
+
return 'grid'
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return this.config.viewType
|
|
596
|
+
},
|
|
536
597
|
|
|
537
598
|
chartOptions(){
|
|
538
599
|
|
|
@@ -655,6 +716,30 @@ export default{
|
|
|
655
716
|
}*/
|
|
656
717
|
},
|
|
657
718
|
|
|
719
|
+
gridColumn(){
|
|
720
|
+
if(!this.config.gridColumn){
|
|
721
|
+
this.config.gridColumn = 3
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if(this.$screenPrefix.value === ''){
|
|
725
|
+
return 1
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return this.config.gridColumn
|
|
729
|
+
},
|
|
730
|
+
|
|
731
|
+
gridGap(){
|
|
732
|
+
if(!this.config.gridGap){
|
|
733
|
+
this.config.gridGap = 'gap-3'
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if(this.$screenPrefix.value === ''){
|
|
737
|
+
return 'gap-1'
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return this.config.gridGap
|
|
741
|
+
},
|
|
742
|
+
|
|
658
743
|
subscriptionObj(){
|
|
659
744
|
const splitted = ((this.subscription ?? '').toString()).split(':')
|
|
660
745
|
const splitted2 = (splitted[1] ?? '').split(',')
|
|
@@ -835,6 +920,10 @@ export default{
|
|
|
835
920
|
@apply flex-1 flex flex-col md:gap-4;
|
|
836
921
|
}
|
|
837
922
|
|
|
923
|
+
.toolbar{
|
|
924
|
+
@apply flex flex-row items-center gap-4 px-6 md:px-0 py-4 md:py-0 bg-base-400 dark:bg-base-300 md:bg-transparent;
|
|
925
|
+
}
|
|
926
|
+
|
|
838
927
|
.searchBox{
|
|
839
928
|
@apply !bg-base-400 md:w-[300px];
|
|
840
929
|
}
|
|
@@ -858,4 +947,8 @@ export default{
|
|
|
858
947
|
@apply hover:bg-primary hover:text-white;
|
|
859
948
|
}
|
|
860
949
|
|
|
950
|
+
.mobileItem{
|
|
951
|
+
@apply p-3 border-[1px] border-text-100 bg-base-300 rounded-lg;
|
|
952
|
+
}
|
|
953
|
+
|
|
861
954
|
</style>
|
package/src/components/Tabs.vue
CHANGED
|
@@ -89,7 +89,7 @@ export default{
|
|
|
89
89
|
@apply border-[1px] border-primary rounded-xl;
|
|
90
90
|
}
|
|
91
91
|
.button>*{
|
|
92
|
-
@apply p-[1px] px-2
|
|
92
|
+
@apply p-[1px] px-2;
|
|
93
93
|
}
|
|
94
94
|
.button>*:first-child{
|
|
95
95
|
@apply rounded-l-lg;
|
|
@@ -101,7 +101,7 @@ export default{
|
|
|
101
101
|
@apply bg-primary text-text-500;
|
|
102
102
|
}
|
|
103
103
|
.button>*[class*="active"] *{
|
|
104
|
-
@apply text-white;
|
|
104
|
+
@apply text-white fill-white;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
</style>
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.virtualGrid" @click="resize">
|
|
3
|
+
|
|
4
|
+
<div ref="scroller" :class="$style.scroller" :style="scrollerStyle">
|
|
5
|
+
<div :class="spacerClass" ref="spacer" :style="spacerStyle">
|
|
6
|
+
<div v-for="(item, index) in visibleItems" :key="item" :data-id="item.id"
|
|
7
|
+
@click="">
|
|
8
|
+
<slot name="item" :item="item" :index="index"></slot>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div :class="$style.calc" v-if="items && items.length > 0" ref="calc">
|
|
14
|
+
<slot name="item" :item="items[0]" :index="0"></slot>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<Teleport v-if="optBar" :to="optBar">
|
|
18
|
+
<div class="flex flex-row gap-2 items-center">
|
|
19
|
+
<small class="text-text-400">Column</small>
|
|
20
|
+
<select v-model="config.gridColumn"
|
|
21
|
+
class="appearance-none outline-none text-text-400 w-[20px] bg-transparent border-[1px] border-text-100 text-center">
|
|
22
|
+
<option v-for="i in 8" :value="i">{{ i }}</option>
|
|
23
|
+
</select>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="flex flex-row gap-2 items-center">
|
|
26
|
+
<small class="text-text-400">Gap</small>
|
|
27
|
+
<select v-model="config.gridGap"
|
|
28
|
+
class="appearance-none outline-none text-text-400 w-[20px] bg-transparent border-[1px] border-text-100 text-center">
|
|
29
|
+
<option v-for="i in 8" :value="`gap-${i}`">{{ i }}</option>
|
|
30
|
+
</select>
|
|
31
|
+
</div>
|
|
32
|
+
</Teleport>
|
|
33
|
+
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
|
|
39
|
+
import throttle from "lodash/throttle";
|
|
40
|
+
|
|
41
|
+
export default{
|
|
42
|
+
|
|
43
|
+
emits: [ 'scroll-end' ],
|
|
44
|
+
|
|
45
|
+
props: {
|
|
46
|
+
|
|
47
|
+
column: {
|
|
48
|
+
type: [ Number, String ],
|
|
49
|
+
default: 1
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
gap: {
|
|
53
|
+
type: [ String ],
|
|
54
|
+
default: 'gap-6'
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
items: Array,
|
|
58
|
+
|
|
59
|
+
pinned: Function,
|
|
60
|
+
|
|
61
|
+
optBar: String,
|
|
62
|
+
|
|
63
|
+
config: Object
|
|
64
|
+
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
methods: {
|
|
68
|
+
|
|
69
|
+
handleScroll: throttle(function(){
|
|
70
|
+
this.scrollTop = this.$el.scrollTop
|
|
71
|
+
|
|
72
|
+
if(this.scrollTop > this.$refs.scroller.offsetHeight - this.$el.clientHeight - this.itemHeight){
|
|
73
|
+
if(!this.isOnEndScroll){
|
|
74
|
+
this.$emit('scroll-end')
|
|
75
|
+
this.isOnEndScroll = true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else{
|
|
79
|
+
if(this.isOnEndScroll){
|
|
80
|
+
this.isOnEndScroll = false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}, 16),
|
|
84
|
+
|
|
85
|
+
init(){
|
|
86
|
+
this.$el.addEventListener(
|
|
87
|
+
"scroll",
|
|
88
|
+
this.handleScroll,
|
|
89
|
+
this.passiveScrollSupported() ? { passive: true } : false
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
this.resize()
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
passiveScrollSupported() {
|
|
96
|
+
let passiveSupported = false;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const options = {
|
|
100
|
+
get passive() {
|
|
101
|
+
passiveSupported = true;
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
window.addEventListener("test", null, options);
|
|
106
|
+
window.removeEventListener("test", null, options);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
passiveSupported = false;
|
|
109
|
+
}
|
|
110
|
+
return passiveSupported;
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
resetState(){
|
|
114
|
+
this.state = 1
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
async resize(){
|
|
118
|
+
|
|
119
|
+
this.$nextTick(() => {
|
|
120
|
+
if(this.$refs.calc){
|
|
121
|
+
const elHeight = parseInt(window.getComputedStyle(this.$el).height !== '0px' ?
|
|
122
|
+
window.getComputedStyle(this.$el).height :
|
|
123
|
+
window.getComputedStyle(this.$el).maxHeight)
|
|
124
|
+
|
|
125
|
+
if(isNaN(elHeight)) return
|
|
126
|
+
|
|
127
|
+
this.itemHeight = parseFloat(window.getComputedStyle(this.$refs.calc).height.replace('px', ''))
|
|
128
|
+
|
|
129
|
+
this.itemGap = parseFloat(window.getComputedStyle(this.$refs.spacer)['row-gap'].replace('px', ''));
|
|
130
|
+
|
|
131
|
+
this.maxVisibleItems = elHeight > 0 ? (Math.ceil(elHeight / this.itemHeight) * this.column) : this.items.length
|
|
132
|
+
|
|
133
|
+
if(this.itemHeight <= 0){
|
|
134
|
+
console.error('Unable to calculate virtual grid item height, async component not supported.')
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
setState(state){
|
|
142
|
+
this.state = state
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
computed: {
|
|
148
|
+
|
|
149
|
+
scrollerStyle(){
|
|
150
|
+
if(!this.items || this.items.length < 1)
|
|
151
|
+
return {}
|
|
152
|
+
|
|
153
|
+
const rowCount = Math.ceil((this.items.length / this.column))
|
|
154
|
+
const height = (rowCount * this.itemHeight) + (this.itemGap * (rowCount - 1))
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
height: height + 'px'
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
sortedItems(){
|
|
162
|
+
if(!Array.isArray(this.items)) return []
|
|
163
|
+
|
|
164
|
+
if(typeof this.pinned === 'function'){
|
|
165
|
+
const pinnedItems = []
|
|
166
|
+
const unpinnedItems = []
|
|
167
|
+
this.items.forEach((item) => {
|
|
168
|
+
if(this.pinned(item))
|
|
169
|
+
pinnedItems.push(item)
|
|
170
|
+
else
|
|
171
|
+
unpinnedItems.push(item)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
return [
|
|
175
|
+
...pinnedItems,
|
|
176
|
+
...unpinnedItems
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
return this.items
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
spacerClass(){
|
|
183
|
+
return [
|
|
184
|
+
this.$style.spacer,
|
|
185
|
+
this.gap
|
|
186
|
+
]
|
|
187
|
+
.join(' ')
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
spacerStyle(){
|
|
191
|
+
return {
|
|
192
|
+
transform: "translateY(" + (this.visibleStartIndex * (this.itemHeight + this.itemGap)) + "px)",
|
|
193
|
+
'grid-template-columns': `repeat(${this.column}, minmax(0, 1fr))`,
|
|
194
|
+
gap: this.gap
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
visibleItems(){
|
|
199
|
+
if(this.itemHeight <= 0) return []
|
|
200
|
+
return this.sortedItems.slice(this.visibleStartIndex * this.column, (this.visibleStartIndex * this.column) + this.maxVisibleItems)
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
visibleStartIndex(){
|
|
204
|
+
return Math.floor((this.scrollTop < 0 ? 0 : this.scrollTop) / (this.itemHeight + this.itemGap))
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
data(){
|
|
210
|
+
return {
|
|
211
|
+
scrollTop: 0,
|
|
212
|
+
itemHeight: 0,
|
|
213
|
+
itemGap: 0,
|
|
214
|
+
maxVisibleItems: 0,
|
|
215
|
+
isOnEndScroll: false,
|
|
216
|
+
selectedIndex: -1,
|
|
217
|
+
state: 1,
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
mounted() {
|
|
222
|
+
this.init()
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
watch: {
|
|
226
|
+
|
|
227
|
+
column(to){
|
|
228
|
+
this.resize()
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
gap(to){
|
|
232
|
+
this.resize()
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
items(to){
|
|
236
|
+
this.resize()
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
</script>
|
|
244
|
+
|
|
245
|
+
<style module>
|
|
246
|
+
|
|
247
|
+
.virtualGrid{
|
|
248
|
+
@apply flex-1 overflow-y-auto;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.scroller{
|
|
252
|
+
position: relative;
|
|
253
|
+
overflow: hidden;
|
|
254
|
+
will-change: auto;
|
|
255
|
+
@apply min-w-full;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.spacer{
|
|
259
|
+
will-change: auto;
|
|
260
|
+
position: relative;
|
|
261
|
+
@apply grid;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.calc{
|
|
265
|
+
@apply absolute invisible;
|
|
266
|
+
top: -10000px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
</style>
|
|
@@ -43,6 +43,11 @@ export default{
|
|
|
43
43
|
|
|
44
44
|
pinned: Function,
|
|
45
45
|
|
|
46
|
+
gap: {
|
|
47
|
+
type: [ String ],
|
|
48
|
+
default: '0'
|
|
49
|
+
},
|
|
50
|
+
|
|
46
51
|
},
|
|
47
52
|
|
|
48
53
|
computed:{
|
|
@@ -79,7 +84,8 @@ export default{
|
|
|
79
84
|
|
|
80
85
|
spacerStyle(){
|
|
81
86
|
return {
|
|
82
|
-
transform: "translateY(" + (this.visibleStartIndex * this.itemHeight) + "px)"
|
|
87
|
+
transform: "translateY(" + (this.visibleStartIndex * this.itemHeight) + "px)",
|
|
88
|
+
gap: this.gap
|
|
83
89
|
}
|
|
84
90
|
},
|
|
85
91
|
|
|
@@ -87,8 +93,10 @@ export default{
|
|
|
87
93
|
if(!this.items || this.items.length < 1)
|
|
88
94
|
return {}
|
|
89
95
|
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
let gapPx = parseInt(this.gap)
|
|
97
|
+
if(isNaN(gapPx)) gapPx = 0
|
|
98
|
+
|
|
99
|
+
const height = (this.items.length * this.itemHeight) + (gapPx * (this.items.length - 1))
|
|
92
100
|
|
|
93
101
|
return {
|
|
94
102
|
height: height + 'px'
|
|
@@ -124,6 +132,10 @@ export default{
|
|
|
124
132
|
this.resize()
|
|
125
133
|
},
|
|
126
134
|
|
|
135
|
+
resetState(){
|
|
136
|
+
this.state = 1
|
|
137
|
+
},
|
|
138
|
+
|
|
127
139
|
select(item, index){
|
|
128
140
|
this.selectedIndex = (item && item.id) ? item.id : this.visibleStartIndex + index
|
|
129
141
|
if(item._highlight){
|
|
@@ -145,7 +157,7 @@ export default{
|
|
|
145
157
|
this.isOnEndScroll = false
|
|
146
158
|
}
|
|
147
159
|
}
|
|
148
|
-
},
|
|
160
|
+
}, 16),
|
|
149
161
|
|
|
150
162
|
passiveScrollSupported() {
|
|
151
163
|
let passiveSupported = false;
|
|
@@ -175,11 +187,9 @@ export default{
|
|
|
175
187
|
|
|
176
188
|
if(isNaN(elHeight)) return
|
|
177
189
|
|
|
178
|
-
this.itemHeight =
|
|
190
|
+
this.itemHeight = parseFloat(window.getComputedStyle(this.$refs.calc).height)
|
|
179
191
|
this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
|
|
180
192
|
|
|
181
|
-
//console.log('Virtual scroll resize', { elHeight, itemHeight:this.itemHeight, maxVisibleItems:this.maxVisibleItems })
|
|
182
|
-
|
|
183
193
|
if(this.itemHeight <= 0){
|
|
184
194
|
console.error('[VirtualScroll] Unable to calculate item height, make sure not async component.')
|
|
185
195
|
}
|
|
@@ -219,12 +229,13 @@ export default{
|
|
|
219
229
|
position: relative;
|
|
220
230
|
overflow: hidden;
|
|
221
231
|
will-change: auto;
|
|
222
|
-
@apply min-w-full
|
|
232
|
+
@apply min-w-full;
|
|
223
233
|
}
|
|
224
234
|
|
|
225
235
|
.spacer{
|
|
226
236
|
will-change: auto;
|
|
227
237
|
position: relative;
|
|
238
|
+
@apply flex flex-col;
|
|
228
239
|
}
|
|
229
240
|
|
|
230
241
|
.item:hover{
|
|
@@ -197,6 +197,10 @@ export default{
|
|
|
197
197
|
|
|
198
198
|
methods: {
|
|
199
199
|
|
|
200
|
+
resetState(){
|
|
201
|
+
this.state = 1
|
|
202
|
+
},
|
|
203
|
+
|
|
200
204
|
trClass(item, index){
|
|
201
205
|
const highlight = !!item._highlight && (!Array.isArray(item._highlight) ||
|
|
202
206
|
this.visibleColumns.filter((_) => item._highlight.includes(_.key)).length <= 0)
|
|
@@ -237,8 +241,6 @@ export default{
|
|
|
237
241
|
this.itemHeight = parseInt(window.getComputedStyle(this.$refs.calc).height)
|
|
238
242
|
this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
|
|
239
243
|
|
|
240
|
-
//console.log('Virtual table scroll resize', { elHeight, itemHeight:this.itemHeight, maxVisibleItems:this.maxVisibleItems })
|
|
241
|
-
|
|
242
244
|
if(this.itemHeight <= 0){
|
|
243
245
|
console.error('[VirtualTable] Unable to calculate item height, make sure not async component.')
|
|
244
246
|
}
|
|
@@ -262,7 +264,7 @@ export default{
|
|
|
262
264
|
this.isOnEndScroll = false
|
|
263
265
|
}
|
|
264
266
|
}
|
|
265
|
-
},
|
|
267
|
+
}, 16),
|
|
266
268
|
|
|
267
269
|
passiveScrollSupported() {
|
|
268
270
|
let passiveSupported = false;
|
package/src/index.js
CHANGED
|
@@ -282,6 +282,45 @@ export default{
|
|
|
282
282
|
window.addEventListener('resize', onWindowResize)
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
const tooltips = {}
|
|
286
|
+
|
|
287
|
+
app.directive('tooltip', (el, binding) => {
|
|
288
|
+
el.addEventListener('mouseover', () => {
|
|
289
|
+
|
|
290
|
+
if(!el.getAttribute('data-tooltip')){
|
|
291
|
+
const tooltip = document.createElement('div')
|
|
292
|
+
tooltip.classList.add('tooltip')
|
|
293
|
+
tooltip.innerHTML = binding.value
|
|
294
|
+
document.body.appendChild(tooltip)
|
|
295
|
+
|
|
296
|
+
const uid = uniqid()
|
|
297
|
+
el.setAttribute('data-tooltip', uid)
|
|
298
|
+
tooltips[uid] = tooltip
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
window.setTimeout(() => {
|
|
302
|
+
if(el.getAttribute('data-tooltip-open')){
|
|
303
|
+
const uid = el.getAttribute('data-tooltip')
|
|
304
|
+
const tooltip = tooltips[uid]
|
|
305
|
+
const rect = el.getBoundingClientRect()
|
|
306
|
+
tooltip.style.top = (rect.y + rect.height + 10) + 'px'
|
|
307
|
+
tooltip.style.left = rect.x - (Math.round((tooltip.clientWidth - rect.width) / 2)) + 'px'
|
|
308
|
+
tooltip.classList.add('active')
|
|
309
|
+
}
|
|
310
|
+
}, 1300)
|
|
311
|
+
el.setAttribute('data-tooltip-open', true)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
el.addEventListener('mouseout', () => {
|
|
315
|
+
el.removeAttribute('data-tooltip-open')
|
|
316
|
+
const uid = el.getAttribute('data-tooltip')
|
|
317
|
+
const tooltip = tooltips[uid]
|
|
318
|
+
if(tooltip){
|
|
319
|
+
tooltip.classList.remove('active')
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
285
324
|
app.config.globalProperties.uniqid = uniqid
|
|
286
325
|
app.config.globalProperties.$download = download
|
|
287
326
|
app.config.globalProperties.$preload = preload
|
|
@@ -350,6 +389,7 @@ export default{
|
|
|
350
389
|
app.component('Toast', defineAsyncComponent(() => import("./components/Toast.vue")))
|
|
351
390
|
app.component('TreeView', defineAsyncComponent(() => import("./components/TreeView.vue")))
|
|
352
391
|
app.component('TreeViewItem', defineAsyncComponent(() => import("./components/TreeViewItem.vue")))
|
|
392
|
+
app.component('VirtualGrid', defineAsyncComponent(() => import("./components/VirtualGrid.vue")))
|
|
353
393
|
app.component('VirtualScroll', defineAsyncComponent(() => import("./components/VirtualScroll.vue")))
|
|
354
394
|
app.component('VirtualTable', defineAsyncComponent(() => import("./components/VirtualTable.vue")))
|
|
355
395
|
app.component('Slider', defineAsyncComponent(() => import("./components/Slider.vue")))
|
|
@@ -100,7 +100,7 @@ const plugin = Plugin(function({ addBase, config, theme }) {
|
|
|
100
100
|
'fontSize': '14px',
|
|
101
101
|
},
|
|
102
102
|
|
|
103
|
-
"input, input[type='text'], input[type='number'], textarea, select, option": { fontSize:"16px" }
|
|
103
|
+
"input, input[type='text'], input[type='number'], textarea, select, option": { fontSize:"16px !important" }
|
|
104
104
|
},
|
|
105
105
|
|
|
106
106
|
'::-webkit-scrollbar': {
|
|
@@ -143,7 +143,22 @@ const plugin = Plugin(function({ addBase, config, theme }) {
|
|
|
143
143
|
fontWeight: theme('fontWeight.bold'),
|
|
144
144
|
},
|
|
145
145
|
|
|
146
|
-
'.flex-1': { minHeight: "0px", minWidth: "0px" }
|
|
146
|
+
'.flex-1': { minHeight: "0px", minWidth: "0px" },
|
|
147
|
+
|
|
148
|
+
'.tooltip': {
|
|
149
|
+
position: "fixed",
|
|
150
|
+
'z-index': 1000,
|
|
151
|
+
transform: 'scale(0)',
|
|
152
|
+
padding: '.3rem .6rem',
|
|
153
|
+
background: 'rgb(var(--text-50))',
|
|
154
|
+
'border-radius': '5px',
|
|
155
|
+
transition: 'transform .2s ease-in-out',
|
|
156
|
+
'transform-origin': 'top',
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
'.tooltip.active': {
|
|
160
|
+
transform: 'scale(1)',
|
|
161
|
+
}
|
|
147
162
|
|
|
148
163
|
})
|
|
149
164
|
|
package/src/utils/listview.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<p v-if="description" class="mt-2 text-lg">{{ description }}</p>
|
|
7
7
|
<div :class="computedContainerClass">
|
|
8
8
|
<div v-for="item in items" class="flex gap-4" :class="computedItemClass">
|
|
9
|
-
<div
|
|
9
|
+
<div>
|
|
10
10
|
<Image :src="imageUrl(item.imageUrl)" class="bg-gray-200 rounded-xl w-full aspect-square object-contain" />
|
|
11
11
|
</div>
|
|
12
12
|
<div class="flex-1 flex flex-col gap-1">
|
|
@@ -68,16 +68,6 @@ export default{
|
|
|
68
68
|
.join(' ')
|
|
69
69
|
},
|
|
70
70
|
|
|
71
|
-
imageClass(){
|
|
72
|
-
|
|
73
|
-
return [
|
|
74
|
-
this.variant && this.variant[0] === 'variant2' ? 'w-[72px]' : 'w-[72px]',
|
|
75
|
-
this.variant && this.variant[0] === 'variant2' ? 'md:w-[100px]' : 'md:w-[100px]'
|
|
76
|
-
]
|
|
77
|
-
.filter(_ => _)
|
|
78
|
-
.join(' ')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
71
|
}
|
|
82
72
|
|
|
83
73
|
}
|
|
@@ -115,15 +105,23 @@ export default{
|
|
|
115
105
|
|
|
116
106
|
.fl-uO88{
|
|
117
107
|
}
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
.fl-uO88 img{
|
|
109
|
+
@apply w-[80px];
|
|
110
|
+
}
|
|
111
|
+
.fl-uO89 img{
|
|
112
|
+
@apply w-[160px];
|
|
120
113
|
}
|
|
121
114
|
|
|
122
115
|
@media screen(md){
|
|
123
|
-
.md\:fl-uO88{
|
|
116
|
+
.md\:fl-uO88 img{
|
|
117
|
+
@apply w-[120px];
|
|
124
118
|
}
|
|
125
119
|
|
|
126
120
|
.md\:fl-uO89{
|
|
121
|
+
@apply text-center;
|
|
122
|
+
}
|
|
123
|
+
.md\:fl-uO89 img{
|
|
124
|
+
@apply w-[160px];
|
|
127
125
|
}
|
|
128
126
|
}
|
|
129
127
|
|
|
@@ -7,7 +7,19 @@
|
|
|
7
7
|
<Textarea v-model="item.props.description" rows="3" @blur="$emit('change')" placeholder="Description" />
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
<div>
|
|
10
|
+
<div class="flex flex-col gap-1">
|
|
11
|
+
<label class="text-text-400">Mode</label>
|
|
12
|
+
<Dropdown v-model="item.props.mode" @change="item.props.items = []">
|
|
13
|
+
<option value="">Static</option>
|
|
14
|
+
<option value="dynamic">Dynamic</option>
|
|
15
|
+
</Dropdown>
|
|
16
|
+
<Textbox v-if="item.props.mode === 'dynamic'"
|
|
17
|
+
placeholder="Var" v-model="item.props.src"
|
|
18
|
+
@blur="$emit('change')"
|
|
19
|
+
@keyup.enter="$emit('change')" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div v-if="item.props.mode !== 'dynamic'">
|
|
11
23
|
<div class="flex flex-row gap-4">
|
|
12
24
|
<label class="flex-1 text-text-400">Items</label>
|
|
13
25
|
<button type="button" class="text-primary"
|
|
@@ -37,6 +49,21 @@
|
|
|
37
49
|
</ListItem>
|
|
38
50
|
</div>
|
|
39
51
|
|
|
52
|
+
<div v-else>
|
|
53
|
+
<label class="flex-1 text-text-400">Item</label>
|
|
54
|
+
<div class="mt-1 flex flex-col gap-1">
|
|
55
|
+
<Textbox v-model="itemPropsItem.title" placeholder="Title var"
|
|
56
|
+
@blur="$emit('change')"
|
|
57
|
+
@keyup.enter="$emit('change')"/>
|
|
58
|
+
<Textbox v-model="itemPropsItem.description" placeholder="Description var"
|
|
59
|
+
@blur="$emit('change')"
|
|
60
|
+
@keyup.enter="$emit('change')"/>
|
|
61
|
+
<Textbox v-model="itemPropsItem.imageUrl" placeholder="Image var"
|
|
62
|
+
@blur="$emit('change')"
|
|
63
|
+
@keyup.enter="$emit('change')"/>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
40
67
|
<div class="flex flex-row items-center gap-4">
|
|
41
68
|
<label class="flex-1 text-text-400">Columns</label>
|
|
42
69
|
<Dropdown v-for="(_viewType, idx) in viewTypes" class="w-[60px]"
|
|
@@ -154,6 +181,12 @@ export default{
|
|
|
154
181
|
return this.item.props.itemVariant
|
|
155
182
|
},
|
|
156
183
|
|
|
184
|
+
itemPropsItem(){
|
|
185
|
+
if(!this.item.props.item)
|
|
186
|
+
this.item.props.item = {}
|
|
187
|
+
return this.item.props.item
|
|
188
|
+
}
|
|
189
|
+
|
|
157
190
|
}
|
|
158
191
|
|
|
159
192
|
}
|
|
@@ -14,7 +14,19 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<div class="flex flex-col items-center pb-6">
|
|
17
|
-
<Tabs variant="button" :items="tabItems" v-model="store.tabIndex"
|
|
17
|
+
<Tabs variant="button" :items="tabItems" v-model="store.tabIndex">
|
|
18
|
+
<template #tab="{ item }">
|
|
19
|
+
<div v-if="item.value === 1" v-tooltip="'Page Info'" class="p-1 px-2">
|
|
20
|
+
<svg width="14" height="14" class="fill-text pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 40c118.621 0 216 96.075 216 216 0 119.291-96.61 216-216 216-119.244 0-216-96.562-216-216 0-119.203 96.602-216 216-216m0-32C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm-36 344h12V232h-12c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h48c6.627 0 12 5.373 12 12v140h12c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12h-72c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12zm36-240c-17.673 0-32 14.327-32 32s14.327 32 32 32 32-14.327 32-32-14.327-32-32-32z"/></svg>
|
|
21
|
+
</div>
|
|
22
|
+
<div v-else-if="item.value === 2" v-tooltip="'Components'" class="p-1 px-2">
|
|
23
|
+
<svg width="14" height="14" class="fill-text pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M512 256.01c0-9.98-5.81-18.94-14.77-22.81l-99.74-43.27 99.7-43.26c9-3.89 14.81-12.84 14.81-22.81s-5.81-18.92-14.77-22.79L271.94 3.33c-10.1-4.44-21.71-4.45-31.87-.02L14.81 101.06C5.81 104.95 0 113.9 0 123.87s5.81 18.92 14.77 22.79l99.73 43.28-99.7 43.26C5.81 237.08 0 246.03 0 256.01c0 9.97 5.81 18.92 14.77 22.79l99.72 43.26-99.69 43.25C5.81 369.21 0 378.16 0 388.14c0 9.97 5.81 18.92 14.77 22.79l225.32 97.76a40.066 40.066 0 0 0 15.9 3.31c5.42 0 10.84-1.1 15.9-3.31l225.29-97.74c9-3.89 14.81-12.84 14.81-22.81 0-9.98-5.81-18.94-14.77-22.81l-99.72-43.26 99.69-43.25c9-3.89 14.81-12.84 14.81-22.81zM45.23 123.87l208.03-90.26.03-.02c1.74-.71 3.65-.76 5.45.02l208.03 90.26-208.03 90.27c-1.81.77-3.74.77-5.48 0L45.23 123.87zm421.54 264.27L258.74 478.4c-1.81.77-3.74.77-5.48 0L45.23 388.13l110.76-48.06 84.11 36.49a40.066 40.066 0 0 0 15.9 3.31c5.42 0 10.84-1.1 15.9-3.31l84.11-36.49 110.76 48.07zm-208.03-41.87c-1.81.77-3.74.77-5.48 0L45.23 256 156 207.94l84.1 36.5a40.066 40.066 0 0 0 15.9 3.31c5.42 0 10.84-1.1 15.9-3.31l84.1-36.49 110.77 48.07-208.03 90.25z"/></svg>
|
|
24
|
+
</div>
|
|
25
|
+
<div v-else-if="item.value === 3" v-tooltip="'Datasource'" class="p-1 px-2">
|
|
26
|
+
<svg width="14" height="14" class="fill-text pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M224 32c106 0 192 28.75 192 64v32c0 35.25-86 64-192 64S32 163.25 32 128V96c0-35.25 86-64 192-64m192 149.5V224c0 35.25-86 64-192 64S32 259.25 32 224v-42.5c41.25 29 116.75 42.5 192 42.5s150.749-13.5 192-42.5m0 96V320c0 35.25-86 64-192 64S32 355.25 32 320v-42.5c41.25 29 116.75 42.5 192 42.5s150.749-13.5 192-42.5m0 96V416c0 35.25-86 64-192 64S32 451.25 32 416v-42.5c41.25 29 116.75 42.5 192 42.5s150.749-13.5 192-42.5M224 0C145.858 0 0 18.801 0 96v320c0 77.338 146.096 96 224 96 78.142 0 224-18.801 224-96V96c0-77.338-146.096-96-224-96z"/></svg>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
</Tabs>
|
|
18
30
|
</div>
|
|
19
31
|
|
|
20
32
|
<div v-if="store.tabIndex === 1" class="flex flex-col gap-4 p-6">
|
|
@@ -227,6 +239,14 @@
|
|
|
227
239
|
|
|
228
240
|
</div>
|
|
229
241
|
|
|
242
|
+
<div v-else-if="store.tabIndex === 3" class="flex-1">
|
|
243
|
+
|
|
244
|
+
<div class="p-6 text-center">
|
|
245
|
+
<button type="button" class="text-primary">Add Datasource</button>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
</div>
|
|
249
|
+
|
|
230
250
|
</div>
|
|
231
251
|
|
|
232
252
|
<div :class="$style.resize1"
|
|
@@ -266,7 +286,16 @@
|
|
|
266
286
|
</template>
|
|
267
287
|
</Textbox>
|
|
268
288
|
<div class="px-6">
|
|
269
|
-
<Tabs v-model="store.viewType" variant="button" @change="resize" :items="viewTypes"
|
|
289
|
+
<Tabs v-model="store.viewType" variant="button" @change="resize" :items="viewTypes">
|
|
290
|
+
<template #tab="{ item }">
|
|
291
|
+
<div class="p-1 px-2" v-if="item.value === ''" v-tooltip="'Mobile'">
|
|
292
|
+
<svg width="14" height="14" class="fill-text pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M192 416c0 17.7-14.3 32-32 32s-32-14.3-32-32 14.3-32 32-32 32 14.3 32 32zM320 48v416c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V48C0 21.5 21.5 0 48 0h224c26.5 0 48 21.5 48 48zm-32 0c0-8.8-7.2-16-16-16H48c-8.8 0-16 7.2-16 16v416c0 8.8 7.2 16 16 16h224c8.8 0 16-7.2 16-16V48z"/></svg>
|
|
293
|
+
</div>
|
|
294
|
+
<div v-else-if="item.value === 'md:'" v-tooltip="'Tablet'" class="p-1 px-2">
|
|
295
|
+
<svg width="14" height="14" class="fill-text pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M400 0H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm16 464c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V48c0-8.8 7.2-16 16-16h352c8.8 0 16 7.2 16 16v416zm-140-16H172c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h104c6.6 0 12 5.4 12 12v8c0 6.6-5.4 12-12 12z"/></svg>
|
|
296
|
+
</div>
|
|
297
|
+
</template>
|
|
298
|
+
</Tabs>
|
|
270
299
|
</div>
|
|
271
300
|
</div>
|
|
272
301
|
</div>
|
|
@@ -1002,6 +1031,7 @@ export default{
|
|
|
1002
1031
|
tabItems: [
|
|
1003
1032
|
{ text:"Page Info", value:1 },
|
|
1004
1033
|
{ text:"Components", value:2 },
|
|
1034
|
+
{ text:"Datasource", value:3 },
|
|
1005
1035
|
],
|
|
1006
1036
|
viewTypes: [
|
|
1007
1037
|
{ text:'Mobile', value:'' },
|