diff options
Diffstat (limited to 'packages/frontend/src/components/MkObjectView.value.vue')
| -rw-r--r-- | packages/frontend/src/components/MkObjectView.value.vue | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/packages/frontend/src/components/MkObjectView.value.vue b/packages/frontend/src/components/MkObjectView.value.vue new file mode 100644 index 0000000000..0c7230d783 --- /dev/null +++ b/packages/frontend/src/components/MkObjectView.value.vue @@ -0,0 +1,160 @@ +<template> +<div class="igpposuu _monospace"> + <div v-if="value === null" class="null">null</div> + <div v-else-if="typeof value === 'boolean'" class="boolean" :class="{ true: value, false: !value }">{{ value ? 'true' : 'false' }}</div> + <div v-else-if="typeof value === 'string'" class="string">"{{ value }}"</div> + <div v-else-if="typeof value === 'number'" class="number">{{ number(value) }}</div> + <div v-else-if="isArray(value) && isEmpty(value)" class="array empty">[]</div> + <div v-else-if="isArray(value)" class="array"> + <div v-for="i in value.length" class="element"> + {{ i }}: <XValue :value="value[i - 1]" collapsed/> + </div> + </div> + <div v-else-if="isObject(value) && isEmpty(value)" class="object empty">{}</div> + <div v-else-if="isObject(value)" class="object"> + <div v-for="k in Object.keys(value)" class="kv"> + <button class="toggle _button" :class="{ visible: collapsable(value[k]) }" @click="collapsed[k] = !collapsed[k]">{{ collapsed[k] ? '+' : '-' }}</button> + <div class="k">{{ k }}:</div> + <div v-if="collapsed[k]" class="v"> + <button class="_button" @click="collapsed[k] = !collapsed[k]"> + <template v-if="typeof value[k] === 'string'">"..."</template> + <template v-else-if="isArray(value[k])">[...]</template> + <template v-else-if="isObject(value[k])">{...}</template> + </button> + </div> + <div v-else class="v"><XValue :value="value[k]"/></div> + </div> + </div> +</div> +</template> + +<script lang="ts"> +import { computed, defineComponent, reactive, ref } from 'vue'; +import number from '@/filters/number'; + +export default defineComponent({ + name: 'XValue', + + props: { + value: { + required: true, + }, + }, + + setup(props) { + const collapsed = reactive({}); + + if (isObject(props.value)) { + for (const key in props.value) { + collapsed[key] = collapsable(props.value[key]); + } + } + + function isObject(v): boolean { + return typeof v === 'object' && !Array.isArray(v) && v !== null; + } + + function isArray(v): boolean { + return Array.isArray(v); + } + + function isEmpty(v): boolean { + return (isArray(v) && v.length === 0) || (isObject(v) && Object.keys(v).length === 0); + } + + function collapsable(v): boolean { + return (isObject(v) || isArray(v)) && !isEmpty(v); + } + + return { + number, + collapsed, + isObject, + isArray, + isEmpty, + collapsable, + }; + }, +}); +</script> + +<style lang="scss" scoped> +.igpposuu { + display: inline; + + > .null { + display: inline; + opacity: 0.7; + } + + > .boolean { + display: inline; + color: var(--codeBoolean); + + &.true { + font-weight: bold; + } + + &.false { + opacity: 0.7; + } + } + + > .string { + display: inline; + color: var(--codeString); + } + + > .number { + display: inline; + color: var(--codeNumber); + } + + > .array.empty { + display: inline; + opacity: 0.7; + } + + > .array:not(.empty) { + display: inline; + + > .element { + display: block; + padding-left: 16px; + } + } + + > .object.empty { + display: inline; + opacity: 0.7; + } + + > .object:not(.empty) { + display: inline; + + > .kv { + display: block; + padding-left: 16px; + + > .toggle { + width: 16px; + color: var(--accent); + visibility: hidden; + + &.visible { + visibility: visible; + } + } + + > .k { + display: inline; + margin-right: 8px; + } + + > .v { + display: inline; + } + } + } +} +</style> |