Skip to content

Instantly share code, notes, and snippets.

@TomByrne
Last active January 21, 2021 03:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TomByrne/0f73e0b3db853d8ff35c4b325b789272 to your computer and use it in GitHub Desktop.
Save TomByrne/0f73e0b3db853d8ff35c4b325b789272 to your computer and use it in GitHub Desktop.
A JSON Viewer component for Vue 3.x (using Typescript class-style components)
<template>
<div
class="json-viewer"
:class="[
'type-' + type,
reallyOpen ? 'open' : 'closed',
simple ? 'simple' : null
]"
>
<span class="name" v-if="hasName && !isNameIndex">"{{ name }}"</span>
<span class="name" v-if="hasName && isNameIndex">[{{ name }}]</span>
<span class="eq" v-if="hasName">: </span>
<span v-if="type == 'string'" class="value">"{{ value }}"</span>
<span v-else-if="simple" class="value">"{{ value }}"</span>
<span v-else-if="type == 'array'" class="value"
><span class="brackets">[</span
><span
v-if="!simple && hasName && hasChildren"
class="open-close"
@click="toggleOpen"
>
{{ open ? "-" : "+" }}</span
>
<div class="children" v-if="reallyOpen">
<JsonViewer
:name="index"
:value="child"
v-for="(child, index) in value"
:key="index"
/>
</div>
<span class="brackets">]</span></span
>
<span v-else-if="type == 'object'" class="value"
><span class="brackets">{</span
><span
v-if="!simple && hasName && hasChildren"
class="open-close"
@click="toggleOpen"
>
{{ open ? "-" : "+" }}</span
>
<div class="children" v-if="reallyOpen">
<JsonViewer
:name="index"
:value="child"
v-for="(child, index) in value"
:key="index"
/>
</div>
<span class="brackets">}</span></span
>
</div>
</template>
<script lang="ts">
import { Options, Vue } from "vue-class-component";
@Options({
name: "JsonViewer",
props: {
name: null,
value: null
}
})
export default class JsonViewer extends Vue {
name?: string;
value: unknown;
open = false;
get isNameIndex(): boolean {
return typeof this.name == "number";
}
get hasName(): boolean {
return this.name != undefined;
}
get hasChildren(): boolean {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const obj: any = this.value;
for (const i in obj) return true;
return false;
}
get reallyOpen(): boolean {
return this.open || !this.hasName;
}
get type(): string {
const type = typeof this.value;
switch (type) {
case "string":
case "number":
case "boolean":
return type;
case "object":
if (this.value instanceof Array) return "array";
else return "object";
default:
return "unknown";
}
}
get simple(): boolean {
const type = typeof this.value;
switch (type) {
case "string":
case "number":
case "boolean":
return true;
default:
return false;
}
}
toggleOpen() {
this.open = !this.open;
}
}
</script>
<style scoped lang="scss">
.json-viewer {
padding: 2px;
.open-close {
background: white;
padding: 0 3px;
border-radius: 6px;
margin: 3px;
font-size: 0.8em;
font-weight: bold;
}
.name {
font-weight: bold;
color: purple;
}
&.simple > .value {
font-weight: bold;
color: green;
}
&.open > .value {
display: block;
}
.children {
padding-left: 10px;
> .json-viewer {
padding-left: 10px;
}
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment