Skip to content

Commit 1663a9a

Browse files
committed
feat: refactor ui
1 parent 365629d commit 1663a9a

4 files changed

Lines changed: 97 additions & 85 deletions

File tree

examples/prototype-data-inspector/src/spa/App.vue

Lines changed: 77 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ import ActionDarkToggle from '@antfu/design/components/Action/ActionDarkToggle.v
55
import DisplayBadge from '@antfu/design/components/Display/DisplayBadge.vue'
66
import FormSelect from '@antfu/design/components/Form/FormSelect.vue'
77
import LayoutSplitPane from '@antfu/design/components/Layout/LayoutSplitPane.vue'
8-
import LayoutToolbar from '@antfu/design/components/Layout/LayoutToolbar.vue'
98
import { Pane } from 'splitpanes'
10-
import { computed, onMounted } from 'vue'
11-
import DataSourceInfoPanel from './components/DataSourceInfoPanel.vue'
9+
import { computed, onMounted, ref } from 'vue'
10+
import DataShapePanel from './components/DataShapePanel.vue'
1211
import QueryEditor from './components/QueryEditor.vue'
1312
import QuerySettings from './components/QuerySettings.vue'
1413
import ResultViewer from './components/ResultViewer.vue'
@@ -26,6 +25,8 @@ const sourceOptions = computed(() =>
2625
wb.sources.value.map(s => ({ value: s.id, label: s.title })),
2726
)
2827
28+
const showDataSourceDetails = ref(false)
29+
2930
onMounted(async () => {
3031
await connect()
3132
if (!connection.connected)
@@ -75,45 +76,67 @@ function queryAppend(path: string): void {
7576

7677
<template>
7778
<div class="h-100dvh flex flex-col bg-base color-base font-sans">
78-
<LayoutToolbar :glass="false">
79-
<div class="flex items-center gap-1.5 shrink-0 font-semibold text-sm select-none">
80-
<span class="i-ph:tree-structure-duotone text-base color-active" />
81-
<span>Data Inspector</span>
82-
</div>
83-
84-
<div class="flex items-center gap-2">
85-
<FormSelect v-model="wb.sourceId.value" :options="sourceOptions" placeholder="Data source" />
86-
<DisplayBadge v-if="wb.activeSource.value?.static" text="static" :color="false" />
87-
</div>
88-
89-
<template #end>
90-
<span
91-
class="flex items-center gap-1.5 text-xs color-muted select-none"
92-
:title="connection.error ?? undefined"
93-
>
94-
<span
95-
class="inline-block w-2 h-2 rounded-full"
96-
:class="connection.connected ? 'bg-green-600 dark:bg-green-400' : 'bg-red-600 dark:bg-red-400'"
97-
/>
98-
{{ connection.status }}
99-
</span>
100-
<ActionDarkToggle
101-
:color-scheme="colorScheme"
102-
@update:color-scheme="colorScheme = $event"
103-
/>
104-
</template>
105-
</LayoutToolbar>
106-
10779
<main class="flex-1 min-h-0">
10880
<LayoutSplitPane storage-key="data-inspector-panes" class="h-full">
10981
<Pane :size="38" min-size="24" class="min-w-0">
110-
<!-- The left column's sections resize with the same split-pane setup. -->
111-
<LayoutSplitPane horizontal storage-key="data-inspector-left-panes" class="h-full">
112-
<Pane :size="42" min-size="20" class="flex flex-col gap-2 p-3 pb-1.5 min-h-0">
113-
<div class="flex items-center gap-2 font-semibold text-sm select-none">
114-
<div>Jora Query</div>
82+
<div class="flex flex-col h-full overflow-hidden min-h-0">
83+
<div class="flex items-center gap-1.5 shrink-0 select-none border-b border-base py1 px3">
84+
<span class="i-ph-crosshair-duotone text-base color-primary" />
85+
<span class="color-primary font-semibold">Data Inspector</span>
86+
<span class="op-fade text-sm">Inspect server side data/objects interactively</span>
87+
<DisplayBadge
88+
v-if="connection.status !== 'connected'"
89+
class="flex items-center gap-1.5 py-1 text-xs select-none capitalize"
90+
:title="connection.error ?? undefined"
91+
:text="connection.status"
92+
:color="connection.connected ? 100 : 200"
93+
/>
94+
<div class="flex-auto" />
95+
<ActionDarkToggle
96+
:color-scheme="colorScheme"
97+
@update:color-scheme="colorScheme = $event"
98+
/>
99+
</div>
100+
101+
<div class="px3 py2 border-b border-base flex flex-col gap-2 shrink-0">
102+
<div class="flex items-center gap-2">
103+
<div class="font-semibold text-xs op-fade uppercase tracking-wide select-none">
104+
Data Source
105+
</div>
106+
<FormSelect v-model="wb.sourceId.value" :options="sourceOptions" placeholder="Data source" class="text-sm font-semibold text-primary" />
107+
<DisplayBadge v-if="wb.activeSource.value?.static" text="static" :color="false" />
108+
<div v-if="wb.activeSource.value?.description && !showDataSourceDetails" class="text-xs op-fade ws-nowrap of-hidden shrink" :title="wb.activeSource.value?.description">
109+
{{ wb.activeSource.value?.description }}
110+
</div>
111+
<div class="flex-auto" />
112+
<Button
113+
size="sm"
114+
:icon="showDataSourceDetails ? 'i-ph:eye-slash-duotone' : 'i-ph:eye-duotone'"
115+
@click="showDataSourceDetails = !showDataSourceDetails"
116+
>
117+
<span>{{ showDataSourceDetails ? 'Hide' : 'Show' }} details</span>
118+
</Button>
119+
</div>
120+
121+
<template v-if="showDataSourceDetails">
122+
<DataShapePanel
123+
:source="wb.activeSource.value"
124+
:skeleton="wb.skeleton.value"
125+
:error="wb.skeletonError.value"
126+
:loading="wb.skeletonLoading.value"
127+
@refresh="wb.loadSkeleton()"
128+
@select="queryProp"
129+
/>
130+
</template>
131+
</div>
132+
133+
<div class="border-b border-base flex-auto flex-col flex">
134+
<div class="flex px3 py2 items-center gap-2 select-none ">
135+
<div class="font-semibold text-xs op-fade uppercase tracking-wide select-none">
136+
Jora Query
137+
</div>
115138
<a
116-
href="https://discoveryjs.github.io/jora/"
139+
href="https://discoveryjs.github.io/jora/#article:jora-syntax"
117140
target="_blank"
118141
title="Jora query language reference"
119142
class="flex items-center gap-1 color-muted hover:color-active"
@@ -124,6 +147,7 @@ function queryAppend(path: string): void {
124147
<Button
125148
v-if="wb.query.value"
126149
:disabled="!wb.query.value"
150+
class="text-sm"
127151
title="Clear query"
128152
icon="i-ph:trash-duotone"
129153
@click="wb.query.value = ''"
@@ -133,6 +157,7 @@ function queryAppend(path: string): void {
133157
<Button
134158
:disabled="wb.running.value"
135159
:loading="wb.running.value"
160+
class="text-sm"
136161
title="Run query"
137162
icon="i-ph:play-duotone"
138163
@click="wb.runNow()"
@@ -144,37 +169,25 @@ function queryAppend(path: string): void {
144169
v-model="wb.query.value"
145170
:syntax="wb.syntax.value"
146171
:suggestions="wb.suggestions.value"
147-
class="flex-1 min-h-0"
172+
class="flex-1 min-h-0 mx2"
148173
@run="wb.runNow()"
149174
@suggest="wb.scheduleSuggestions($event)"
150175
@accept="wb.acceptSuggestion($event)"
151176
@dismiss="wb.suggestions.value = []"
152177
/>
153-
<QuerySettings v-model="wb.settings" />
154-
</Pane>
155-
<Pane min-size="12" class="p-3 pt-1.5 min-h-0">
156-
<SavedQueriesPanel
157-
:saved="savedApi.saved.value"
158-
:suggested="wb.activeSource.value?.queries ?? []"
159-
:current-query="wb.query.value"
160-
:current-filters="wb.settings"
161-
class="h-full"
162-
@load="loadRecipe"
163-
@remove="savedApi.remove($event)"
164-
@save="saveCurrent"
165-
/>
166-
</Pane>
167-
<Pane :size="33" min-size="12" class="p-3 py-1.5 min-h-0">
168-
<DataSourceInfoPanel
169-
:source="wb.activeSource.value"
170-
:skeleton="wb.skeleton.value"
171-
:error="wb.skeletonError.value"
172-
:loading="wb.skeletonLoading.value"
173-
@refresh="wb.loadSkeleton()"
174-
@select="queryProp"
175-
/>
176-
</Pane>
177-
</LayoutSplitPane>
178+
<QuerySettings v-model="wb.settings" class="py2 px4" />
179+
</div>
180+
<SavedQueriesPanel
181+
:saved="savedApi.saved.value"
182+
:suggested="wb.activeSource.value?.queries ?? []"
183+
:current-query="wb.query.value"
184+
:current-filters="wb.settings"
185+
class="px3 py2"
186+
@load="loadRecipe"
187+
@remove="savedApi.remove($event)"
188+
@save="saveCurrent"
189+
/>
190+
</div>
178191
</Pane>
179192
<Pane class="min-w-0">
180193
<ResultViewer

examples/prototype-data-inspector/src/spa/components/DataSourceInfoPanel.vue renamed to examples/prototype-data-inspector/src/spa/components/DataShapePanel.vue

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<script setup lang="ts">
22
import type { DataSourceMeta } from '../../rpc-contract'
33
import ActionIconButton from '@antfu/design/components/Action/ActionIconButton.vue'
4-
import DisplayBadge from '@antfu/design/components/Display/DisplayBadge.vue'
54
import { computed } from 'vue'
65
76
const props = defineProps<{
@@ -65,10 +64,11 @@ const rootLabel = computed(() => {
6564

6665
<template>
6766
<div class="flex flex-col h-full min-h-0">
68-
<div class="flex items-center gap-2 px-1 pb-1.5">
69-
<span class="text-sm font-semibold truncate select-none">{{ source?.title ?? 'Data source' }}</span>
70-
<DisplayBadge v-if="source?.static" text="static" :color="false" />
71-
<div class="flex-1" />
67+
<div class="flex gap-2">
68+
<div v-if="source?.description" class="text-sm op-fade">
69+
{{ source.description }}
70+
</div>
71+
<div class="flex-auto" />
7272
<ActionIconButton
7373
size="sm"
7474
:icon="loading ? 'i-ph:arrows-clockwise animate-spin' : 'i-ph:arrows-clockwise'"
@@ -78,9 +78,6 @@ const rootLabel = computed(() => {
7878
@click="emit('refresh')"
7979
/>
8080
</div>
81-
<p v-if="source?.description" class="m-0 px-1 pb-2 text-xs color-muted">
82-
{{ source.description }}
83-
</p>
8481

8582
<div
8683
v-if="error"
@@ -90,7 +87,7 @@ const rootLabel = computed(() => {
9087
</div>
9188

9289
<!-- One-level data shape as a plain code block; click a prop to query it. -->
93-
<div class="flex-1 min-h-0 overflow-auto font-mono text-xs leading-relaxed bg-secondary border border-base rounded-lg px-3 py-2">
90+
<div class="flex-1 min-h-0 overflow-auto font-mono max-h50 overflow-auto text-xs border border-base rounded-lg px-3 py-2">
9491
<template v-if="entries.length">
9592
<div class="op50 select-none">
9693
{

examples/prototype-data-inspector/src/spa/components/QuerySettings.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const settings = defineModel<Required<FilterOptions>>({ required: true })
66
</script>
77

88
<template>
9-
<div class="flex items-center gap-4 flex-wrap px-1 text-sm">
9+
<div class="flex items-center gap-4 flex-wrap text-sm">
1010
<span class="text-xs font-medium color-muted uppercase tracking-wide select-none">Filters</span>
1111
<FormCheckbox v-model="settings.excludeFunctions" label="Exclude functions" />
1212
<FormCheckbox v-model="settings.excludeUnderscoreProps" label="Exclude _ props" />

examples/prototype-data-inspector/src/spa/components/SavedQueriesPanel.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,20 @@ function filterBadges(entry: Query): string[] {
6868
</script>
6969

7070
<template>
71-
<div class="flex flex-col gap-2 min-h-0">
71+
<div class="flex flex-col gap-2">
7272
<div class="flex items-center gap-2">
73-
<span class="text-xs font-medium color-muted uppercase tracking-wide select-none">Queries</span>
74-
<span v-if="saved.length + suggested.length" class="text-xs color-faint font-mono tabular-nums">{{ saved.length + suggested.length }}</span>
73+
<div class="font-semibold text-xs op-fade uppercase tracking-wide select-none">
74+
Saved Queries
75+
</div>
76+
<span v-if="saved.length + suggested.length" class="text-xs op-fade font-mono tabular-nums">({{ saved.length + suggested.length }})</span>
7577
<div class="flex-1" />
76-
<ActionButton size="sm" icon="i-ph:bookmark-simple-duotone" @click="openDialog">
78+
<ActionButton class="text-sm" icon="i-ph:bookmark-simple-duotone" @click="openDialog">
7779
Save query
7880
</ActionButton>
7981
</div>
8082

81-
<div v-if="saved.length || suggested.length" class="flex flex-col gap-1 overflow-auto min-h-0">
83+
<div v-if="saved.length || suggested.length" class="overflow-auto min-h-0 max-h-200 grid grid-cols-[repeat(auto-fit,minmax(20rem,1fr))] gap-2">
84+
<!-- TODO: merge and unify this two sources -->
8285
<div
8386
v-for="entry in suggested"
8487
:key="`suggested:${entry.query}`"
@@ -93,7 +96,6 @@ function filterBadges(entry: Query): string[] {
9396
</div>
9497
<div class="flex-1" />
9598
<span v-for="badge in filterBadges(entry)" :key="badge" class="font-mono text-10px color-faint">{{ badge }}</span>
96-
<DisplayBadge text="suggested" :color="false" class="shrink-0" />
9799
</div>
98100

99101
<div
@@ -110,11 +112,6 @@ function filterBadges(entry: Query): string[] {
110112
</div>
111113
<div class="flex-1" />
112114
<span v-for="badge in filterBadges(entry)" :key="badge" class="font-mono text-10px color-faint">{{ badge }}</span>
113-
<DisplayBadge
114-
:text="entry.scope"
115-
:color="entry.scope === 'project' ? 150 : false"
116-
class="shrink-0"
117-
/>
118115
<ActionIconButton
119116
size="sm"
120117
icon="i-ph:trash-duotone"
@@ -123,6 +120,11 @@ function filterBadges(entry: Query): string[] {
123120
class="op0 group-hover:op100 transition-opacity"
124121
@click.stop="emit('remove', entry)"
125122
/>
123+
<DisplayBadge
124+
:text="entry.scope"
125+
:color="entry.scope === 'project' ? 150 : false"
126+
class="shrink-0"
127+
/>
126128
</div>
127129
</div>
128130
<div v-else class="text-xs color-faint px-1 select-none">

0 commit comments

Comments
 (0)