adds initial user defined panels

This commit is contained in:
2025-12-23 16:41:21 -05:00
parent a110aa6376
commit ebbf864af9
33 changed files with 2188 additions and 370 deletions

View File

@@ -79,7 +79,12 @@ onUnmounted(() => {
<template>
<span class="test monospace" :data-after-content="value">
<span ref="data-span" class="transparent" :copy-value="value">
<span
ref="data-span"
class="transparent"
:copy-value="value"
v-bind="$attrs"
>
{{ overlay }}
</span>
</span>

View File

@@ -0,0 +1,218 @@
<script setup lang="ts">
import type { OptionalDynamicComponentData } from '@/composables/dynamic.ts';
import { computed, defineAsyncComponent } from 'vue';
const TelemetryValue = defineAsyncComponent(
() => import('@/components/TelemetryValue.vue'),
);
const GridLayout = defineAsyncComponent(
() => import('@/components/layout/GridLayout.vue'),
);
const model = defineModel<OptionalDynamicComponentData>('data', {
required: true,
});
const selection = defineModel<symbol>('selection');
const props = defineProps<{
editable: boolean;
}>();
const thisSymbol = Symbol();
const isSelected = computed(() => {
return selection.value == thisSymbol && props.editable;
});
function selectThis() {
selection.value = thisSymbol;
}
function deleteThis() {
model.value = {
type: 'none',
};
}
function makeText() {
model.value = {
type: 'text',
text: '',
justify_right: false,
};
}
function makeTelemetry() {
model.value = {
type: 'telemetry',
data: '',
};
}
function makeGrid() {
model.value = {
type: 'grid',
columns: 1,
equal_width: false,
cells: [],
};
}
function addRow() {
const grid = model.value;
if (grid.type == 'grid') {
const row: OptionalDynamicComponentData[] = [];
for (let i = 0; i < grid.columns; i++) {
row.push({ type: 'none' });
}
grid.cells.push(row);
model.value = grid;
}
}
function deleteRow() {
const grid = model.value;
if (grid.type == 'grid') {
grid.cells.pop();
model.value = grid;
}
}
function addColumn() {
const grid = model.value;
if (grid.type == 'grid') {
for (let i = 0; i < grid.cells.length; i++) {
grid.cells[i].push({ type: 'none' });
}
grid.columns += 1;
model.value = grid;
}
}
function deleteColumn() {
const grid = model.value;
if (grid.type == 'grid') {
for (let i = 0; i < grid.cells.length; i++) {
grid.cells[i].pop();
}
grid.columns -= 1;
model.value = grid;
}
}
</script>
<template>
<Teleport v-if="isSelected" to="#inspector">
<div class="row">
<button
v-if="model.type != 'none'"
@click.stop.prevent="deleteThis"
>
Delete
</button>
<button v-if="model.type != 'text'" @click.stop.prevent="makeText">
Make Text
</button>
<button
v-if="model.type != 'telemetry'"
@click.stop.prevent="makeTelemetry"
>
Make Telemetry
</button>
<button v-if="model.type != 'grid'" @click.stop.prevent="makeGrid">
Make Grid
</button>
</div>
</Teleport>
<template v-if="model.type == 'none'">
<!-- Intentionally Left Empty -->
<span
v-if="editable"
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
@click.stop.prevent="selectThis"
></span>
</template>
<template v-else-if="model.type == 'text'">
<span
:class="`${model.justify_right ? 'justify-right' : ''} ${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
@click.stop.prevent="selectThis"
>
{{ model.text }}
</span>
<Teleport v-if="isSelected" to="#inspector">
<div class="row">
<label>Text: </label>
<input v-model="model.text" />
</div>
<div class="row">
<label>Justify Right: </label>
<input type="checkbox" v-model="model.justify_right" />
</div>
</Teleport>
</template>
<template v-else-if="model.type == 'telemetry'">
<span
v-if="editable"
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
@click.stop.prevent="selectThis"
>
{{ '{' }} {{ model.data }} {{ '}' }}
</span>
<TelemetryValue
v-else
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
:data="model.data"
@click.stop.prevent="selectThis"
></TelemetryValue>
<Teleport v-if="isSelected" to="#inspector">
<label>Telemetry Item: </label>
<input v-model="model.data" />
</Teleport>
</template>
<template v-else-if="model.type == 'grid'">
<GridLayout
:class="`${editable ? 'editable' : ''} ${isSelected ? 'selected' : ''}`"
:cols="model.columns"
:equal_col_width="model.equal_width"
@click.stop.prevent="selectThis"
>
<template v-for="x in model.cells.length" :key="x">
<template v-for="y in model.columns" :key="y">
<DynamicComponent
v-model:data="model.cells[x - 1][y - 1]"
:editable="editable"
v-model:selection="selection"
></DynamicComponent>
</template>
</template>
</GridLayout>
<Teleport v-if="isSelected" to="#inspector">
<div class="row">
<label>Equal Width: </label>
<input type="checkbox" v-model="model.equal_width" />
</div>
<div class="row">
<button @click.stop.prevent="addRow">Add Row</button>
<button
:disabled="model.cells.length <= 0"
@click.stop.prevent="deleteRow"
>
Delete Row
</button>
<button @click.stop.prevent="addColumn">Add Column</button>
<button
:disabled="model.columns <= 0"
@click.stop.prevent="deleteColumn"
>
Delete Column
</button>
</div>
</Teleport>
</template>
<template v-else> ERROR: Unknown data: {{ model }} </template>
</template>
<style scoped lang="scss">
@use '@/assets/variables';
</style>

View File

@@ -68,10 +68,15 @@ watch([display_value], ([display_str]) => {
<template>
<template v-if="copyable">
<CopyableDynamicSpan :value="display_value"></CopyableDynamicSpan>
<CopyableDynamicSpan
:value="display_value"
v-bind="$attrs"
></CopyableDynamicSpan>
</template>
<template v-else>
{{ display_value }}
<span v-bind="$attrs">
{{ display_value }}
</span>
</template>
</template>

View File

@@ -48,14 +48,15 @@ const numeric_data = computed(() => {
</script>
<template>
<span v-if="!is_data_present"> No Data </span>
<span v-if="!is_data_present" v-bind="$attrs"> No Data </span>
<template v-else>
<NumericText
v-if="numeric_data"
v-bind="$attrs"
:value="numeric_data"
:max_width="10"
></NumericText>
<span v-else>
<span v-else v-bind="$attrs">
Cannot Display Data of Type {{ telemetry_data!.data_type }}
</span>
</template>