big refactor
This commit is contained in:
118
app/components/back-office/NestedJsonViewer.vue
Normal file
118
app/components/back-office/NestedJsonViewer.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'NestedJsonViewer' })
|
||||
|
||||
interface Props {
|
||||
data: any
|
||||
depth?: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const depth = computed(() => props.depth || 0)
|
||||
|
||||
// Font size decreases with depth: 12px base, -1px per level
|
||||
const fontSize = computed(() => Math.max(10, 12 - depth.value * 1))
|
||||
|
||||
// Padding decreases with depth
|
||||
const padding = computed(() => Math.max(1, 4 - depth.value))
|
||||
|
||||
function isObject(value: any): boolean {
|
||||
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
|
||||
function isArray(value: any): boolean {
|
||||
return Array.isArray(value)
|
||||
}
|
||||
|
||||
function isDateString(value: string): boolean {
|
||||
if (typeof value !== 'string') return false
|
||||
return /^\d{4}-\d{2}-\d{2}/.test(value) && !isNaN(Date.parse(value))
|
||||
}
|
||||
|
||||
function formatValue(value: any): string {
|
||||
if (value === null || value === undefined) return '—'
|
||||
if (typeof value === 'boolean') return value ? 'Yes' : 'No'
|
||||
if (typeof value === 'number') return value.toLocaleString()
|
||||
if (isDateString(value)) {
|
||||
try {
|
||||
return new Date(value).toLocaleDateString('es-PA', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return String(value)
|
||||
}
|
||||
|
||||
function formatKey(key: string): string {
|
||||
return key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="nested-json-viewer" :style="{ fontSize: fontSize + 'px' }">
|
||||
<!-- Object: render as table -->
|
||||
<table v-if="isObject(data) && Object.keys(data).length > 0" class="json-table border rounded overflow-hidden mb-2">
|
||||
<tbody>
|
||||
<tr v-for="(value, key) in data" :key="key" class="border-t border-gray-200 hover:bg-gray-50">
|
||||
<td class="field-name px-3 py-2 font-medium text-gray-600 align-top whitespace-nowrap" :style="{ padding: padding + 'px', fontSize: (fontSize - 1) + 'px' }">
|
||||
{{ formatKey(key) }}
|
||||
</td>
|
||||
<td class="field-value px-3 py-2 text-gray-900 align-top" :style="{ padding: padding + 'px' }">
|
||||
<NestedJsonViewer :data="value" :depth="depth + 1" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-else-if="isObject(data) && Object.keys(data).length === 0" class="text-gray-400 italic" :style="{ fontSize: fontSize + 'px' }">
|
||||
Empty object
|
||||
</div>
|
||||
|
||||
<!-- Array -->
|
||||
<div v-else-if="isArray(data)" class="array-container">
|
||||
<div v-for="(item, index) in data" :key="index" class="array-item mb-2 border rounded p-2">
|
||||
<div class="text-xs font-semibold text-gray-500 mb-1">[{{ index }}]</div>
|
||||
<NestedJsonViewer :data="item" :depth="depth + 1" />
|
||||
</div>
|
||||
<div v-if="data.length === 0" class="text-gray-400 italic" :style="{ fontSize: fontSize + 'px' }">
|
||||
Empty array
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Primitive -->
|
||||
<span v-else class="primitive-value" :class="{ 'text-gray-400': data === '—' }">
|
||||
{{ formatValue(data) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.nested-json-viewer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.json-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.field-name {
|
||||
min-width: 120px;
|
||||
background: #f9fafb;
|
||||
}
|
||||
|
||||
.field-value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.array-item {
|
||||
background: white;
|
||||
border-color: var(--card-border, #e5e7eb);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user