2021-11-11 23:37:42 +01:00
|
|
|
<script lang="ts">
|
2021-11-30 22:59:34 +01:00
|
|
|
import { createEventDispatcher } from "svelte";
|
2021-11-11 23:37:42 +01:00
|
|
|
import type { IEntry } from "upend/types";
|
|
|
|
import UpLink from "./UpLink.svelte";
|
|
|
|
import type { Component, UpType, Widget } from "../lib/types";
|
|
|
|
import Table from "./widgets/Table.svelte";
|
2021-11-30 22:59:34 +01:00
|
|
|
import TableComponent from "./widgets/Table.svelte"; // silence false svelte(reactive-component) warnings
|
2021-12-02 18:45:29 +01:00
|
|
|
import type { AttributeChange } from "../types/base";
|
|
|
|
const dispatch = createEventDispatcher();
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
export let attributes: [string, IEntry][];
|
|
|
|
export let type: UpType | undefined = undefined;
|
|
|
|
export let address: String;
|
|
|
|
export let title: String | undefined = undefined;
|
|
|
|
export let editable = false;
|
|
|
|
export let reverse = false;
|
|
|
|
|
2021-12-01 15:56:12 +01:00
|
|
|
let currentWidget: string | undefined;
|
2021-11-11 23:37:42 +01:00
|
|
|
|
|
|
|
let availableWidgets: Widget[] = [];
|
|
|
|
$: {
|
|
|
|
availableWidgets = [
|
|
|
|
{
|
|
|
|
name: "table",
|
|
|
|
icon: "table",
|
|
|
|
components: [
|
|
|
|
{
|
2021-11-30 22:59:34 +01:00
|
|
|
component: TableComponent,
|
2021-11-11 23:37:42 +01:00
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
if (type?.widgetInfo) {
|
|
|
|
availableWidgets = [type.widgetInfo, ...availableWidgets];
|
|
|
|
}
|
2021-12-01 15:56:12 +01:00
|
|
|
currentWidget = availableWidgets[0].name;
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let components: Component[] = [];
|
|
|
|
$: {
|
|
|
|
components = availableWidgets.find(
|
|
|
|
(w) => w.name === currentWidget
|
|
|
|
)!.components;
|
|
|
|
}
|
|
|
|
|
2021-12-02 18:45:29 +01:00
|
|
|
async function onChange(change: AttributeChange) {
|
|
|
|
switch (change.type) {
|
|
|
|
case "create":
|
|
|
|
await fetch(`/api/obj`, {
|
|
|
|
method: "PUT",
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
body: JSON.stringify({
|
|
|
|
entity: address,
|
|
|
|
attribute: change.attribute,
|
|
|
|
value: {
|
|
|
|
t: "Value",
|
|
|
|
c: change.value,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
case "delete":
|
|
|
|
await fetch(`/api/obj/${change.addr}`, { method: "DELETE" });
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.error("Unimplemented AttributeChange", change);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dispatch("changed");
|
2021-11-11 23:37:42 +01:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<section class="attribute-view">
|
|
|
|
<header>
|
|
|
|
<h3>
|
|
|
|
{#if type}
|
|
|
|
<UpLink to={{ entity: type.address }}>
|
|
|
|
{#if type.icon}
|
|
|
|
<sl-icon name={type.icon} />
|
|
|
|
{/if}
|
|
|
|
{type.name || "???"}
|
|
|
|
</UpLink>
|
|
|
|
{:else}
|
|
|
|
{title || "???"}
|
|
|
|
{/if}
|
|
|
|
</h3>
|
|
|
|
|
2021-12-01 15:56:12 +01:00
|
|
|
{#if currentWidget && (availableWidgets.length > 1 || editable)}
|
2021-11-11 23:37:42 +01:00
|
|
|
<div class="views">
|
|
|
|
{#each availableWidgets as widget (widget.name)}
|
|
|
|
<sl-icon-button
|
|
|
|
name={widget.icon || "question-diamond"}
|
|
|
|
class:active={widget.name === currentWidget}
|
|
|
|
on:click={() => (currentWidget = widget.name)}
|
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
</div>
|
|
|
|
{/if}
|
|
|
|
</header>
|
2021-11-30 22:59:34 +01:00
|
|
|
{#if !reverse}
|
|
|
|
{#each components as component}
|
|
|
|
<svelte:component
|
|
|
|
this={component.component}
|
|
|
|
{...component.props || {}}
|
|
|
|
{attributes}
|
|
|
|
{editable}
|
2021-12-02 18:45:29 +01:00
|
|
|
on:change={(ev) => onChange(ev.detail)}
|
2021-11-30 22:59:34 +01:00
|
|
|
/>
|
|
|
|
{/each}
|
|
|
|
{:else}
|
2021-12-01 15:39:26 +01:00
|
|
|
<Table columns="entity, attribute" {attributes} />
|
2021-11-30 22:59:34 +01:00
|
|
|
{/if}
|
2021-11-11 23:37:42 +01:00
|
|
|
</section>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
section {
|
|
|
|
position: relative;
|
|
|
|
overflow: visible;
|
|
|
|
|
|
|
|
margin-top: 1.66em;
|
|
|
|
padding: 1ex 1em;
|
|
|
|
|
2021-11-30 20:59:53 +01:00
|
|
|
border: 0.1em solid var(--foreground);
|
2021-11-11 23:37:42 +01:00
|
|
|
border-radius: 4px;
|
|
|
|
|
|
|
|
header {
|
|
|
|
margin-bottom: 0.2em;
|
|
|
|
|
|
|
|
& > * {
|
|
|
|
position: absolute;
|
|
|
|
top: -0.66em;
|
|
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
|
|
background: var(--background);
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
|
|
line-height: 1;
|
|
|
|
padding: 0 0.75ex;
|
|
|
|
|
|
|
|
sl-icon {
|
|
|
|
margin-bottom: -2px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h3 {
|
|
|
|
left: 1ex;
|
|
|
|
}
|
|
|
|
|
|
|
|
.views {
|
|
|
|
right: 1ex;
|
|
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
|
|
sl-icon-button {
|
|
|
|
&::part(base) {
|
|
|
|
padding: 0 calc(0.75ex / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
&::part(base) {
|
|
|
|
color: var(--foreground);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|