initial
This commit is contained in:
parent
aa7c30950c
commit
72716e1c28
41 changed files with 15461 additions and 0 deletions
48
frontend/app/components/ConfirmationModal.vue
Normal file
48
frontend/app/components/ConfirmationModal.vue
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<u-modal
|
||||
title="Confirmation"
|
||||
description="Confirmation required for the selected action"
|
||||
:dismissible="false"
|
||||
>
|
||||
<template #body>
|
||||
<p class="my-3">
|
||||
Type <strong>{{ message }}</strong> to confirm.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<u-field-group class="w-full">
|
||||
<u-input
|
||||
v-model="inputMessage"
|
||||
name="user-input"
|
||||
autocomplete="false"
|
||||
type="text"
|
||||
class="w-full"
|
||||
/>
|
||||
<u-button color="error" :disabled="!matched" @click="onSubmit">
|
||||
Submit
|
||||
</u-button>
|
||||
</u-field-group>
|
||||
</div>
|
||||
</template>
|
||||
</u-modal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { UModal, UInput, UButton } from "#components";
|
||||
|
||||
interface Props {
|
||||
message: string;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{ close: [boolean] }>();
|
||||
|
||||
const inputMessage = ref("");
|
||||
|
||||
const matched = computed(() => {
|
||||
return inputMessage.value === props.message;
|
||||
});
|
||||
|
||||
function onSubmit() {
|
||||
emit("close", true);
|
||||
}
|
||||
</script>
|
||||
96
frontend/app/components/DataTypeEditor.vue
Normal file
96
frontend/app/components/DataTypeEditor.vue
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
<template>
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<u-card variant="soft">
|
||||
<u-form-field label="Type Name">
|
||||
<u-input v-model="type.name" class="w-full" />
|
||||
</u-form-field>
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-0">#</th>
|
||||
<th>Property Name</th>
|
||||
<th>Property Type</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(property, idx) in type.properties" :key="idx">
|
||||
<th class="align-top w-0 pt-4">{{ idx + 1 }}</th>
|
||||
<td>
|
||||
<u-input v-model="property.name" class="w-full" />
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<u-radio-group
|
||||
v-model="property.type"
|
||||
:items="typeItems"
|
||||
orientation="vertical"
|
||||
/>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<u-button
|
||||
icon="i-bi-trash"
|
||||
size="xs"
|
||||
color="error"
|
||||
@click="deleteProperty(idx)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<u-button
|
||||
icon="i-bi-plus"
|
||||
size="sm"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
@click="addProperty"
|
||||
>
|
||||
New Property
|
||||
</u-button>
|
||||
|
||||
<template #footer>
|
||||
<p class="text-xs muted">
|
||||
Add and delete type parameters, change their types, the dynamic form
|
||||
on the right will be automatically updated.
|
||||
</p>
|
||||
</template>
|
||||
</u-card>
|
||||
<div v-if="allParametersAreValid">
|
||||
<h4 style="margin-top: 0">Sample Form</h4>
|
||||
<simple-form :type="type" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DataType, UiPropertyType } from "~/types";
|
||||
|
||||
// Here we define our type as a model, meaning that any changes to this object will be published back to the parent view
|
||||
const type = defineModel<DataType>({ required: true });
|
||||
|
||||
const typeItems = ref<UiPropertyType[]>(["number", "string", "text"]);
|
||||
|
||||
// Form won't be shown if there are empty parameters
|
||||
const allParametersAreValid = computed(() => {
|
||||
const typeProps = type.value.properties;
|
||||
if (typeProps.length == 0) {
|
||||
return false; // No properties at all
|
||||
}
|
||||
|
||||
for (const p of typeProps) {
|
||||
if (p.name.length === 0) {
|
||||
return false; // Missing a name
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
function deleteProperty(index: number) {
|
||||
const copy = type.value.properties;
|
||||
copy.splice(index, 1);
|
||||
type.value.properties = copy;
|
||||
}
|
||||
|
||||
function addProperty() {
|
||||
type.value.properties.push({ name: "", type: "string" });
|
||||
}
|
||||
</script>
|
||||
42
frontend/app/components/NavBar.vue
Normal file
42
frontend/app/components/NavBar.vue
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<UNavigationMenu :items="items" class="w-full justify-start bg-neutral-50">
|
||||
<template #list-trailing>
|
||||
<div class="flex flex-1 justify-end mx-2">
|
||||
<UBadge
|
||||
icon="i-mdi-clock-outline"
|
||||
size="md"
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
class="font-mono"
|
||||
>
|
||||
{{ currentTime }}
|
||||
</UBadge>
|
||||
</div>
|
||||
</template>
|
||||
</UNavigationMenu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavigationMenuItem } from "@nuxt/ui";
|
||||
import { appState } from "#imports";
|
||||
|
||||
const state = appState();
|
||||
|
||||
const currentTime = computed(() => {
|
||||
return state.value.time.toLocaleTimeString();
|
||||
});
|
||||
|
||||
const items = ref<NavigationMenuItem[]>([
|
||||
{
|
||||
icon: "i-mdi-home",
|
||||
to: "/",
|
||||
active: false,
|
||||
},
|
||||
{
|
||||
label: "Data Structures",
|
||||
icon: "i-material-symbols-account-tree-outline-rounded",
|
||||
to: "/data",
|
||||
active: false,
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
41
frontend/app/components/SimpleBreadcrumb.vue
Normal file
41
frontend/app/components/SimpleBreadcrumb.vue
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<u-breadcrumb :items="items" class="my-nav mb-3" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { BreadcrumbItem } from "@nuxt/ui";
|
||||
import { UBreadcrumb } from "#components";
|
||||
import type { NavRoute } from "~/ui";
|
||||
|
||||
interface Props {
|
||||
previous: NavRoute[];
|
||||
last: string;
|
||||
}
|
||||
|
||||
const items = computed(() => {
|
||||
const arr: BreadcrumbItem[] = [];
|
||||
for (const h of props.previous) {
|
||||
arr.push({
|
||||
label: h.title,
|
||||
to: h.path,
|
||||
});
|
||||
}
|
||||
arr.push({
|
||||
label: props.last,
|
||||
disabled: true,
|
||||
class: "text-muted",
|
||||
});
|
||||
return arr;
|
||||
});
|
||||
|
||||
const props = defineProps<Props>();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Override default high margins for <ol> lists */
|
||||
.my-nav ol {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
</style>
|
||||
66
frontend/app/components/SimpleForm.vue
Normal file
66
frontend/app/components/SimpleForm.vue
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="p-2 bg-neutral-50 rounded-lg shadow-neutral-300 shadow-sm">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr v-for="(prop, idx) in type.properties" :key="idx">
|
||||
<td class="font-semibold w-0 text-nowrap px-2">
|
||||
{{ prop.name }}
|
||||
</td>
|
||||
<td>
|
||||
<u-input
|
||||
v-if="prop.type === 'string'"
|
||||
v-model="formData[prop.name]"
|
||||
type="text"
|
||||
class="w-full"
|
||||
/>
|
||||
<u-textarea
|
||||
v-if="prop.type === 'text'"
|
||||
v-model="formData[prop.name]"
|
||||
class="w-full"
|
||||
/>
|
||||
<u-input
|
||||
v-if="prop.type === 'number'"
|
||||
v-model="formData[prop.name]"
|
||||
type="number"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="mx-0">Form Data</h4>
|
||||
<pre class="mx-0 my-0">{{ formData }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { DataType } from "~/types";
|
||||
|
||||
interface Props {
|
||||
type: DataType;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const formData = ref<Record<string, string>>({});
|
||||
|
||||
watch(
|
||||
props,
|
||||
() => {
|
||||
// Property value changed, resetting the form data
|
||||
formData.value = {};
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Override default high margins for <ol> lists */
|
||||
.table {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue