mirror of
https://github.com/speatzle/nfsense.git
synced 2025-09-13 15:19:08 +00:00
add initial test client
This commit is contained in:
parent
0a51ba0beb
commit
fbc899fbe0
28 changed files with 4829 additions and 0 deletions
55
client/src/components/NiceTable.vue
Normal file
55
client/src/components/NiceTable.vue
Normal file
|
@ -0,0 +1,55 @@
|
|||
<script setup lang="ts">
|
||||
const props = defineModel<{
|
||||
columns?: Record<string, string>,
|
||||
data?: Record<string, any>[],
|
||||
sortSelf?: boolean,
|
||||
sortBy?: string,
|
||||
sortDesc?: boolean,
|
||||
}>();
|
||||
let { columns, data, sortSelf, sortBy, sortDesc } = $(props);
|
||||
|
||||
const displayData = $computed(() => (sortSelf && sortBy !== '')
|
||||
? data?.sort((a, b) => {
|
||||
let result;
|
||||
if (a[sortBy ?? ''] > b[sortBy ?? '']) result = 1;
|
||||
else if (a[sortBy ?? ''] === b[sortBy ?? '']) result = 0;
|
||||
else result = -1;
|
||||
|
||||
if (sortDesc) return -result;
|
||||
return result;
|
||||
})
|
||||
: data);
|
||||
|
||||
function toggleSorting(columnName: string) {
|
||||
if (columnName === sortBy) sortDesc = !sortDesc;
|
||||
else {
|
||||
sortDesc = false;
|
||||
sortBy = columnName;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="[name, heading] in Object.entries(columns ?? {})" :key="name" @click="toggleSorting(name)">
|
||||
<div class="flex-row">
|
||||
{{ heading }}
|
||||
<i-mdi-arrow-down v-if="name === sortBy && sortDesc"/>
|
||||
<i-mdi-arrow-up v-else-if="name === sortBy"/>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- eslint-disable-next-line vue/require-v-for-key -->
|
||||
<tr v-for="row of displayData">
|
||||
<td v-for="cell in row" :key="cell" v-text="cell"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
16
client/src/components/meta/PageHeader.vue
Normal file
16
client/src/components/meta/PageHeader.vue
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
const { title, noSpacer } = $(withDefaults(defineProps<{
|
||||
title?: string,
|
||||
noSpacer?: boolean,
|
||||
}>(), {
|
||||
title: "",
|
||||
noSpacer: false,
|
||||
}));
|
||||
watchEffect(() => useTitle(`${title} - nfSense`));
|
||||
</script>
|
||||
<template>
|
||||
<Portal to="page-header">
|
||||
<h1 v-if="title !== ''" v-text="title" :class="{'flex-grow': !noSpacer}"/>
|
||||
<slot/>
|
||||
</Portal>
|
||||
</template>
|
25
client/src/components/meta/Portal.vue
Normal file
25
client/src/components/meta/Portal.vue
Normal file
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
let activeTargets = $ref<string[]>([]);
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = $defineProps<{
|
||||
from?: string,
|
||||
to?: string,
|
||||
}>();
|
||||
const { from, to } = $(props);
|
||||
|
||||
if (from) {
|
||||
onMounted(() => activeTargets.push(from));
|
||||
onBeforeUnmount(() => activeTargets.splice(activeTargets.indexOf(from), 1));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="from" :id="'portal-' + from">
|
||||
<slot/>
|
||||
</div>
|
||||
<Teleport v-else-if="to && activeTargets.includes(to)" :to="'#portal-' + to">
|
||||
<slot/>
|
||||
</Teleport>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue