upend/webui/src/lib/components/EntryView.svelte

151 lines
3.5 KiB
Svelte

<script lang="ts" context="module">
import type { ComponentType } from 'svelte';
export interface WidgetComponent {
component: ComponentType;
props: { [key: string]: unknown };
}
export interface Widget {
name: string;
icon?: string;
components: (input: {
entries: UpEntry[];
entities: string[];
group?: string;
address?: string;
}) => Array<WidgetComponent>;
}
</script>
<script lang="ts">
import EntryList from './widgets/EntryList.svelte';
import type { UpEntry } from '@upnd/upend';
import Icon from './utils/Icon.svelte';
import IconButton from './utils/IconButton.svelte';
import { createEventDispatcher } from 'svelte';
import UpObject from './display/UpObject.svelte';
import LabelBorder from './utils/LabelBorder.svelte';
const dispatch = createEventDispatcher();
export let entries: UpEntry[] = [];
export let entities: string[] = [];
export let widgets: Widget[] | undefined = undefined;
export let initialWidget: string | undefined = undefined;
export let title: string | undefined = undefined;
export let group: string | undefined = undefined;
export let address: string | undefined = undefined;
export let icon: string | undefined = undefined;
export let highlighted = false;
let currentWidget: string | undefined;
function switchWidget(widget: string) {
currentWidget = widget;
dispatch('widgetSwitched', currentWidget);
}
let availableWidgets: Widget[] = [];
$: {
availableWidgets = [];
if (entries.length) {
availableWidgets = [
...availableWidgets,
{
name: 'Entry List',
icon: 'table',
components: ({ entries }) => [
{
component: EntryList,
props: { entries, columns: 'entity, attribute, value' }
}
]
}
];
}
if (widgets?.length) {
availableWidgets = [...widgets, ...availableWidgets];
}
if (initialWidget && availableWidgets.map((w) => w.name).includes(initialWidget)) {
currentWidget = initialWidget;
} else {
currentWidget = availableWidgets[0].name;
}
}
let components: WidgetComponent[] = [];
$: {
components =
availableWidgets
.find((w) => w.name === currentWidget)
?.components({ entries, entities, group, address }) || [];
}
</script>
<LabelBorder hide={entries.length === 0 && entities.length === 0}>
<svelte:fragment slot="header-full">
<h3 class:highlighted>
{#if group}
{#if icon}
<div class="icon">
<Icon plain name={icon} />
</div>
{/if}
<UpObject link address={group} labels={title ? [title] : undefined} />
{:else}
{#if icon}
<div class="icon">
<Icon plain name={icon} />
</div>
{/if}
{title || ''}
{/if}
</h3>
{#if currentWidget && availableWidgets.length > 1}
<div class="views">
{#each availableWidgets as widget (widget.name)}
<IconButton
name={widget.icon || 'cube'}
title={widget.name}
active={widget.name === currentWidget}
--active-color="var(--foreground)"
on:click={() => switchWidget(widget.name)}
>
{widget.name}
</IconButton>
{/each}
</div>
{/if}
</svelte:fragment>
{#each components as component}
<svelte:component this={component.component} {...component.props || {}} on:change />
{/each}
</LabelBorder>
<style lang="scss">
.icon {
display: inline-block;
font-size: 1.25em;
margin-top: -0.3em;
position: relative;
bottom: -2px;
}
h3 {
margin: 0;
transition: text-shadow 0.2s;
&.highlighted {
text-shadow: #cb4b16 0 0 0.5em;
}
}
.views {
display: flex;
font-size: 16px;
}
</style>