2023-06-16 16:30:17 +02:00
|
|
|
<script lang="ts" context="module">
|
|
|
|
export interface WidgetComponent {
|
|
|
|
component: ComponentType;
|
|
|
|
props: { [key: string]: unknown };
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface Widget {
|
|
|
|
name: string;
|
|
|
|
icon?: string;
|
2023-08-28 18:14:06 +02:00
|
|
|
components: (input: {
|
|
|
|
entries: UpEntry[];
|
2023-10-22 13:38:52 +02:00
|
|
|
entities: string[];
|
2023-08-28 18:14:06 +02:00
|
|
|
group?: string;
|
2023-09-07 18:57:45 +02:00
|
|
|
address?: string;
|
2023-08-28 18:14:06 +02:00
|
|
|
}) => Array<WidgetComponent>;
|
2023-06-16 16:30:17 +02:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
2021-11-11 23:37:42 +01:00
|
|
|
<script lang="ts">
|
2022-09-04 23:29:41 +02:00
|
|
|
import EntryList from "./widgets/EntryList.svelte";
|
2023-10-07 11:06:45 +02:00
|
|
|
import type { UpEntry } from "@upnd/upend";
|
2021-12-30 19:28:43 +01:00
|
|
|
import Icon from "./utils/Icon.svelte";
|
|
|
|
import IconButton from "./utils/IconButton.svelte";
|
2023-06-16 16:30:17 +02:00
|
|
|
import { createEventDispatcher, type ComponentType } from "svelte";
|
2023-07-30 17:02:52 +02:00
|
|
|
import UpObject from "./display/UpObject.svelte";
|
2023-09-05 20:57:01 +02:00
|
|
|
import LabelBorder from "./utils/LabelBorder.svelte";
|
2022-03-22 20:35:01 +01:00
|
|
|
const dispatch = createEventDispatcher();
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2023-10-22 13:38:52 +02:00
|
|
|
export let entries: UpEntry[] = [];
|
|
|
|
export let entities: string[] = [];
|
2022-09-06 00:10:24 +02:00
|
|
|
export let widgets: Widget[] | undefined = undefined;
|
2022-03-22 20:35:01 +01:00
|
|
|
export let initialWidget: string | undefined = undefined;
|
2023-06-16 16:30:17 +02:00
|
|
|
export let title: string | undefined = undefined;
|
2023-07-30 17:02:52 +02:00
|
|
|
export let group: string | undefined = undefined;
|
2023-09-07 18:57:45 +02:00
|
|
|
export let address: string | undefined = undefined;
|
2023-06-16 16:30:17 +02:00
|
|
|
export let icon: string | undefined = undefined;
|
2023-05-03 16:21:03 +02:00
|
|
|
export let highlighted = false;
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2021-12-01 15:56:12 +01:00
|
|
|
let currentWidget: string | undefined;
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2022-03-22 20:35:01 +01:00
|
|
|
function switchWidget(widget: string) {
|
|
|
|
currentWidget = widget;
|
|
|
|
dispatch("widgetSwitched", currentWidget);
|
|
|
|
}
|
|
|
|
|
2021-11-11 23:37:42 +01:00
|
|
|
let availableWidgets: Widget[] = [];
|
|
|
|
$: {
|
2023-10-22 13:38:52 +02:00
|
|
|
availableWidgets = [];
|
|
|
|
|
|
|
|
if (entries.length) {
|
|
|
|
availableWidgets = [
|
|
|
|
...availableWidgets,
|
|
|
|
{
|
|
|
|
name: "Entry List",
|
|
|
|
icon: "table",
|
|
|
|
components: ({ entries }) => [
|
|
|
|
{
|
|
|
|
component: EntryList,
|
|
|
|
props: { entries, columns: "entity, attribute, value" },
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2022-09-04 23:29:41 +02:00
|
|
|
if (widgets?.length) {
|
|
|
|
availableWidgets = [...widgets, ...availableWidgets];
|
|
|
|
}
|
|
|
|
|
2022-03-22 20:35:01 +01:00
|
|
|
if (availableWidgets.map((w) => w.name).includes(initialWidget)) {
|
|
|
|
currentWidget = initialWidget;
|
|
|
|
} else {
|
|
|
|
currentWidget = availableWidgets[0].name;
|
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
|
2023-06-16 16:30:17 +02:00
|
|
|
let components: WidgetComponent[] = [];
|
2021-11-11 23:37:42 +01:00
|
|
|
$: {
|
2023-06-16 16:30:17 +02:00
|
|
|
components = availableWidgets
|
|
|
|
.find((w) => w.name === currentWidget)
|
2023-10-22 13:38:52 +02:00
|
|
|
.components({ entries, entities, group, address });
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
2023-10-22 13:38:52 +02:00
|
|
|
<LabelBorder hide={entries.length === 0 && entities.length === 0}>
|
2023-09-05 20:57:01 +02:00
|
|
|
<svelte:fragment slot="header-full">
|
|
|
|
<h3 class:highlighted>
|
2023-07-30 17:02:52 +02:00
|
|
|
{#if group}
|
|
|
|
{#if icon}
|
|
|
|
<div class="icon">
|
|
|
|
<Icon name={icon} />
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
<UpObject link address={group} labels={title ? [title] : undefined} />
|
2023-07-09 19:28:15 +02:00
|
|
|
{:else}
|
|
|
|
{#if icon}
|
|
|
|
<div class="icon">
|
|
|
|
<Icon name={icon} />
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
{title || ""}
|
2021-11-11 23:37:42 +01:00
|
|
|
{/if}
|
|
|
|
</h3>
|
|
|
|
|
2023-09-01 19:52:49 +02:00
|
|
|
{#if currentWidget && availableWidgets.length > 1}
|
2021-11-11 23:37:42 +01:00
|
|
|
<div class="views">
|
|
|
|
{#each availableWidgets as widget (widget.name)}
|
2021-12-30 19:28:43 +01:00
|
|
|
<IconButton
|
2023-06-16 16:30:17 +02:00
|
|
|
name={widget.icon || "cube"}
|
|
|
|
title={widget.name}
|
2021-12-30 19:28:43 +01:00
|
|
|
active={widget.name === currentWidget}
|
|
|
|
--active-color="var(--foreground)"
|
2023-07-29 16:45:35 +02:00
|
|
|
on:click={() => switchWidget(widget.name)}
|
2023-06-16 16:30:17 +02:00
|
|
|
>
|
2023-07-29 16:45:35 +02:00
|
|
|
{widget.name}
|
|
|
|
</IconButton>
|
2021-11-11 23:37:42 +01:00
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/if}
|
2023-09-05 20:57:01 +02:00
|
|
|
</svelte:fragment>
|
|
|
|
{#each components as component}
|
|
|
|
<svelte:component
|
|
|
|
this={component.component}
|
|
|
|
{...component.props || {}}
|
|
|
|
on:change
|
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
</LabelBorder>
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2023-09-05 20:57:01 +02:00
|
|
|
.icon {
|
|
|
|
display: inline-block;
|
|
|
|
font-size: 1.25em;
|
|
|
|
margin-top: -0.3em;
|
|
|
|
position: relative;
|
|
|
|
bottom: -2px;
|
|
|
|
}
|
2023-06-16 16:30:17 +02:00
|
|
|
|
2023-09-05 20:57:01 +02:00
|
|
|
h3 {
|
|
|
|
margin: 0;
|
|
|
|
transition: text-shadow 0.2s;
|
2023-05-03 16:21:03 +02:00
|
|
|
|
2023-09-05 20:57:01 +02:00
|
|
|
&.highlighted {
|
2023-06-16 16:30:17 +02:00
|
|
|
text-shadow: #cb4b16 0 0 0.5em;
|
|
|
|
}
|
2022-01-22 20:19:26 +01:00
|
|
|
}
|
2021-11-11 23:37:42 +01:00
|
|
|
|
2022-01-22 20:19:26 +01:00
|
|
|
.views {
|
|
|
|
display: flex;
|
2023-07-29 12:29:53 +02:00
|
|
|
font-size: 16px;
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
</style>
|