wip: get rid of types, new EntryVIew

feat/type-attributes
Tomáš Mládek 2023-06-16 16:30:17 +02:00
parent e428ef188f
commit e496710e20
6 changed files with 211 additions and 345 deletions

View File

@ -1,22 +1,31 @@
<script lang="ts" context="module">
export interface WidgetComponent {
component: ComponentType;
props: { [key: string]: unknown };
}
export interface Widget {
name: string;
icon?: string;
components: (entries: UpEntry[]) => Array<WidgetComponent>;
}
</script>
<script lang="ts"> <script lang="ts">
import UpLink from "./display/UpLink.svelte";
import type { Component, UpType, Widget } from "../lib/types";
import EntryList from "./widgets/EntryList.svelte"; import EntryList from "./widgets/EntryList.svelte";
import type { UpEntry } from "upend"; import type { UpEntry } from "upend";
import Icon from "./utils/Icon.svelte"; import Icon from "./utils/Icon.svelte";
import IconButton from "./utils/IconButton.svelte"; import IconButton from "./utils/IconButton.svelte";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher, type ComponentType } from "svelte";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
import { i18n } from "../i18n";
export let entries: UpEntry[]; export let entries: UpEntry[];
export let type: UpType | undefined = undefined;
export let widgets: Widget[] | undefined = undefined; export let widgets: Widget[] | undefined = undefined;
export let title: string | undefined = undefined;
export let editable = false;
export let reverse = false;
export let initialWidget: string | undefined = undefined; export let initialWidget: string | undefined = undefined;
export let title: string | undefined = undefined;
export let icon: string | undefined = undefined;
export let highlighted = false; export let highlighted = false;
export let editable = false;
let currentWidget: string | undefined; let currentWidget: string | undefined;
@ -29,20 +38,17 @@
$: { $: {
availableWidgets = [ availableWidgets = [
{ {
name: "entrylist", name: "Entry List",
icon: "table", icon: "table",
components: [ components: (entries) => [
{ {
component: EntryList, component: EntryList,
props: { entries, columns: "entity, attribute, value" },
}, },
], ],
}, },
]; ];
if (type?.widgetInfo.length > 0) {
availableWidgets = [...type.widgetInfo, ...availableWidgets];
}
if (widgets?.length) { if (widgets?.length) {
availableWidgets = [...widgets, ...availableWidgets]; availableWidgets = [...widgets, ...availableWidgets];
} }
@ -54,95 +60,80 @@
} }
} }
let components: Component[] = []; let components: WidgetComponent[] = [];
$: { $: {
components = availableWidgets.find( components = availableWidgets
(w) => w.name === currentWidget .find((w) => w.name === currentWidget)
).components; .components(entries);
} }
</script> </script>
<section class="attribute-view labelborder" class:highlighted> <section class="entry-view labelborder" class:highlighted>
<header> <header>
<h3> <h3>
{#if !title && type?.address} {#if icon}
<UpLink to={{ entity: type.address }}> <div class="icon">
{#if type.icon} <Icon name={icon} />
<div class="icon"> </div>
<Icon name={type.icon} />
</div>
{/if}
{#if type.name != "HIER"}
{type.label || type.name || "???"}
{:else}
{$i18n.t("Members")}
{/if}
</UpLink>
{:else}
{title || ""}
{/if} {/if}
{title || ""}
</h3> </h3>
{#if currentWidget && (availableWidgets.length > 1 || editable)} {#if currentWidget && (availableWidgets.length > 1 || editable)}
<div class="views"> <div class="views">
{#each availableWidgets as widget (widget.name)} {#each availableWidgets as widget (widget.name)}
<IconButton <IconButton
name={widget.icon || "question-diamond"} name={widget.icon || "cube"}
title={widget.name}
active={widget.name === currentWidget} active={widget.name === currentWidget}
--active-color="var(--foreground)" --active-color="var(--foreground)"
on:click={() => switchWidget(widget.name)} on:click={() => switchWidget(widget.name)}>{widget.name}</IconButton
/> >
{/each} {/each}
</div> </div>
{/if} {/if}
</header> </header>
<div class="content"> <div class="content">
{#if !reverse} {#each components as component}
{#each components as component}
<svelte:component
this={component.component}
{...(typeof component.props === "function"
? component.props(entries)
: component.props) || {}}
{entries}
{editable}
{type}
on:change
/>
{/each}
{:else}
<!-- shut up svelte check -->
<svelte:component <svelte:component
this={EntryList} this={component.component}
columns="entity, attribute" {...component.props || {}}
{entries} {editable}
on:change
/> />
{/if} {/each}
</div> </div>
</section> </section>
<style scoped lang="scss"> <style scoped lang="scss">
@use "./util"; @use "./util";
section h3 { section.entry-view {
transition: text-shadow 0.2s; header {
} margin-bottom: 0.5rem;
}
section.highlighted h3 { .icon {
text-shadow: #cb4b16 0 0 0.5em; display: inline-block;
} font-size: 1.25em;
margin-top: -0.3em;
position: relative;
bottom: -2px;
}
.icon { h3 {
display: inline-block; transition: text-shadow 0.2s;
font-size: 1.25em; }
margin-top: -0.3em;
position: relative; &.highlighted h3 {
bottom: -2px; text-shadow: #cb4b16 0 0 0.5em;
}
} }
.views { .views {
display: flex; display: flex;
right: 1ex; right: 1ex;
transform: translateY(-25%);
font-size: 18px; font-size: 18px;
} }
</style> </style>

View File

@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
import AttributeView from "./AttributeView.svelte"; import EntryView from "./EntryView.svelte";
import { query, useEntity } from "../lib/entity"; import { query, useEntity } from "../lib/entity";
import UpObject from "./display/UpObject.svelte"; import UpObject from "./display/UpObject.svelte";
import { UpType } from "../lib/types";
import { createEventDispatcher, setContext } from "svelte"; import { createEventDispatcher, setContext } from "svelte";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import type { UpEntry } from "upend"; import type { UpEntry } from "upend";
@ -19,6 +18,7 @@
import { i18n } from "../i18n"; import { i18n } from "../i18n";
import EntryList from "./widgets/EntryList.svelte"; import EntryList from "./widgets/EntryList.svelte";
import api from "../lib/api"; import api from "../lib/api";
import Gallery from "./widgets/Gallery.svelte";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const params = useParams(); const params = useParams();
@ -44,38 +44,6 @@
$: ({ entity, entityInfo, error, revalidate } = useEntity(address)); $: ({ entity, entityInfo, error, revalidate } = useEntity(address));
$: allTypeAddresses = ($entity?.attr["OF"] || [])
.filter((attr) => attr.value.t == "Address")
.map((attr) => attr.value.c);
$: allTypeEntries = query(
`(matches (in ${allTypeAddresses.map((addr) => `@${addr}`).join(" ")}) ? ?)`
).result;
let allTypes: { [key: string]: UpType } = {};
$: {
allTypes = {};
($allTypeEntries?.entries || []).forEach((entry) => {
if (allTypes[entry.entity] === undefined) {
allTypes[entry.entity] = new UpType(entry.entity);
}
switch (entry.attribute) {
case "TYPE":
allTypes[entry.entity].name = String(entry.value.c);
break;
case "LBL":
allTypes[entry.entity].label = String(entry.value.c);
break;
case "TYPE_HAS":
allTypes[entry.entity].attributes.push(String(entry.value.c));
break;
}
});
allTypes = allTypes;
}
let typedAttributes = {} as { [key: string]: UpEntry[] }; let typedAttributes = {} as { [key: string]: UpEntry[] };
let untypedAttributes = [] as UpEntry[]; let untypedAttributes = [] as UpEntry[];
@ -84,8 +52,10 @@
untypedAttributes = []; untypedAttributes = [];
($entity?.attributes || []).forEach((entry) => { ($entity?.attributes || []).forEach((entry) => {
const entryTypes = Object.entries(allTypes).filter(([_, t]) => const entryTypes = Object.entries(/*allTypes*/ {}).filter(
t.attributes.includes(entry.attribute) ([_, t]) =>
// t.attributes.includes(entry.attribute)
false
); );
if (entryTypes.length > 0) { if (entryTypes.length > 0) {
entryTypes.forEach(([addr, _]) => { entryTypes.forEach(([addr, _]) => {
@ -106,7 +76,6 @@
$: filteredUntypedAttributes = untypedAttributes.filter( $: filteredUntypedAttributes = untypedAttributes.filter(
(entry) => (entry) =>
![ ![
"IS",
"LBL", "LBL",
"OF", "OF",
"NOTE", "NOTE",
@ -120,9 +89,15 @@
? untypedAttributes ? untypedAttributes
: filteredUntypedAttributes; : filteredUntypedAttributes;
$: currentBacklinks = $entity?.backlinks || []; $: currentBacklinks =
(editable
? $entity?.backlinks
: $entity?.backlinks.filter(
(entry) => !["OF"].includes(entry.attribute)
)) || [];
$: groups = []; $: groups = ($entity?.attr["OF"] || []).map((e) => e.value.c as string);
$: tagged = $entity?.attr["~OF"] || [];
let attributesUsed: UpEntry[] = []; let attributesUsed: UpEntry[] = [];
$: { $: {
@ -238,33 +213,22 @@
</div> </div>
<NotesEditor {address} {editable} on:change={onChange} /> <NotesEditor {address} {editable} on:change={onChange} />
{#if !$error} {#if !$error}
{#if Object.keys(allTypes).length || groups.length} {#if groups.length}
<section class="tags labelborder"> <section class="tags labelborder">
<header><h3>{$i18n.t("Tags")}</h3></header> <header><h3>{$i18n.t("Tags")}</h3></header>
<div class="content"> <div class="content">
{#each Object.values(allTypes) as type} {#each groups as group}
<div <div
class="tag type" class="tag"
on:mouseenter={() => (highlightedType = type.address)} on:mouseenter={() => (highlightedType = group)}
on:mouseleave={() => (highlightedType = undefined)} on:mouseleave={() => (highlightedType = undefined)}
> >
<UpObject address={type.address} link /> <UpObject address={group} link />
{#if editable} {#if editable}
<IconButton name="x-circle" /> <IconButton name="x-circle" />
{/if} {/if}
</div> </div>
{/each} {/each}
{#each groups as [entryAddress, address]}
<div class="tag group">
<UpObject {address} link />
{#if editable}
<IconButton
name="x-circle"
on:click={() => removeGroup(entryAddress)}
/>
{/if}
</div>
{/each}
{#if editable} {#if editable}
<div class="selector"> <div class="selector">
<Selector <Selector
@ -279,70 +243,97 @@
</div> </div>
</section> </section>
{/if} {/if}
{#if Boolean($allTypeEntries)} <div class="attributes">
<div class="attributes"> {#each Object.entries(typedAttributes) as [typeAddr, entries] (typeAddr)}
{#each Object.entries(typedAttributes) as [typeAddr, entries] (typeAddr)} <EntryView
<AttributeView {entries}
{entries} {editable}
type={allTypes[typeAddr]} on:change={onChange}
{editable} initialWidget={String($entity.get("LAST_ATTRIBUTE_WIDGET"))}
on:change={onChange} on:widgetSwitched={onAttributeWidgetSwitch}
initialWidget={String($entity.get("LAST_ATTRIBUTE_WIDGET"))} highlighted={highlightedType == typeAddr}
on:widgetSwitched={onAttributeWidgetSwitch} />
highlighted={highlightedType == typeAddr} {/each}
/>
{/each}
{#if currentUntypedAttributes.length > 0 || editable} {#if currentUntypedAttributes.length > 0 || editable}
<AttributeView <EntryView
title={$i18n.t("Attributes")} title={$i18n.t("Attributes")}
{editable} {editable}
entries={currentUntypedAttributes} entries={currentUntypedAttributes}
on:change={onChange} on:change={onChange}
/> />
{/if}
{#if currentBacklinks.length > 0}
<AttributeView
title={`${$i18n.t("Referred to")} (${
$entity.backlinks.length
})`}
entries={currentBacklinks}
reverse
on:change={onChange}
/>
{/if}
{#if $entityInfo?.t === "Attribute"}
<div class="buttons">
<div class="button">
<Link to="/surface?x={$entityInfo.c}">
{$i18n.t("Surface view")}
</Link>
</div>
</div>
<section class="labelborder">
<header>
<h3>{$i18n.t("Used")} ({attributesUsed.length})</h3>
</header>
<EntryList
columns="entity,value"
columnWidths={["auto", "33%"]}
entries={attributesUsed}
orderByValue
/>
</section>
{/if}
</div>
{#if editable}
<div class="button" on:click={deleteObject}>
<Icon name="trash" />
</div>
{/if} {/if}
{:else}
<Spinner centered /> {#if currentBacklinks.length > 0}
<EntryView
title={`${$i18n.t("Referred to")} (${currentBacklinks.length})`}
entries={currentBacklinks}
on:change={onChange}
/>
{/if}
{#if tagged.length > 0}
<EntryView
title={`${$i18n.t("Links")}`}
widgets={[
{
name: "List",
components: (entries) => [
{
component: Gallery,
props: {
entities: entries.map((e) => e.entity),
thumbnails: false,
},
},
],
},
{
name: "Gallery",
components: (entries) => [
{
component: Gallery,
props: {
entities: entries.map((e) => e.entity),
thumbnails: true,
},
},
],
},
]}
entries={tagged}
on:change={onChange}
/>
{/if}
{#if $entityInfo?.t === "Attribute"}
<div class="buttons">
<div class="button">
<Link to="/surface?x={$entityInfo.c}">
{$i18n.t("Surface view")}
</Link>
</div>
</div>
<section class="labelborder">
<header>
<h3>{$i18n.t("Used")} ({attributesUsed.length})</h3>
</header>
<EntryList
columns="entity,value"
columnWidths={["auto", "33%"]}
entries={attributesUsed}
orderByValue
/>
</section>
{/if}
</div>
{#if editable}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="button" on:click={deleteObject}>
<Icon name="trash" />
</div>
{/if} {/if}
{:else} {:else}
<div class="error"> <div class="error">

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import filesize from "filesize"; import filesize from "filesize";
import { format, formatRelative, fromUnixTime, parseISO } from "date-fns"; import { formatRelative, fromUnixTime, parseISO } from "date-fns";
import Ellipsis from "../utils/Ellipsis.svelte"; import Ellipsis from "../utils/Ellipsis.svelte";
import UpObject from "../display/UpObject.svelte"; import UpObject from "../display/UpObject.svelte";
import { createEventDispatcher } from "svelte"; import { createEventDispatcher } from "svelte";
@ -17,18 +17,17 @@
import { formatDuration } from "../../util/fragments/time"; import { formatDuration } from "../../util/fragments/time";
import { i18n } from "../../i18n"; import { i18n } from "../../i18n";
import UpLink from "../display/UpLink.svelte"; import UpLink from "../display/UpLink.svelte";
import type { UpType } from "src/lib/types";
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
export let columns: string | undefined = undefined; export let columns: string | undefined = undefined;
export let header = true; export let header = true;
export let orderByValue = false; export let orderByValue = false;
export let columnWidths: string[] = []; export let columnWidths: string[] | undefined = undefined;
export let entries: UpEntry[]; export let entries: UpEntry[];
export let type: UpType | undefined = undefined;
export let editable = false; export let editable = false;
export let attributeOptions: string[] | undefined = undefined;
// Display // Display
$: displayColumns = (columns || "attribute, value") $: displayColumns = (columns || "attribute, value")
@ -182,7 +181,7 @@
<col class="action-col" /> <col class="action-col" />
{/if} {/if}
{#each displayColumns as column, idx} {#each displayColumns as column, idx}
{#if columnWidths.length} {#if columnWidths?.length}
<col <col
class="{column}-col" class="{column}-col"
style="width: {columnWidths[idx] || 'unset'}" style="width: {columnWidths[idx] || 'unset'}"
@ -300,7 +299,7 @@
<Selector <Selector
type="attribute" type="attribute"
bind:attribute={newEntryAttribute} bind:attribute={newEntryAttribute}
attributeOptions={type?.attributes} attributeOptions={attributeOptions || []}
/> />
</td> </td>
{/if} {/if}

View File

@ -1,108 +0,0 @@
import type { UpEntry } from "upend";
import Gallery from "../components/widgets/Gallery.svelte";
export class UpType {
address: string | undefined;
name: string | null = null;
label: string | null = null;
attributes: string[] = [];
constructor(address?: string) {
this.address = address;
}
public get icon(): string | undefined {
return this.name ? TYPE_ICONS[this.name] : undefined;
}
public get widgetInfo(): Widget[] {
return TYPE_WIDGETS[this.name] || [];
}
}
export const UNTYPED = new UpType();
export interface Component {
component: any; // TODO
props?:
| { [key: string]: unknown }
| ((entries: UpEntry[]) => { [key: string]: unknown });
}
export interface Widget {
name: string;
icon?: string;
components: Array<Component>;
}
const TYPE_ICONS: { [key: string]: string } = {
BLOB: "package",
HIER: "folder",
};
const TYPE_WIDGETS: { [key: string]: Widget[] } = {
HIER: [
{
name: "hierarchical-listing",
icon: "folder",
components: [
{
component: Gallery,
props: (entries) => {
return {
thumbnails: false,
entities: entries
.filter((e) => e.attribute == "HAS")
.map((e) => String(e.value.c)),
};
},
},
],
},
{
name: "hierarchical-listing-gallery",
icon: "image",
components: [
{
component: Gallery,
props: (entries) => {
return {
thumbnails: true,
entities: entries
.filter((e) => e.attribute == "HAS")
.map((e) => String(e.value.c)),
};
},
},
],
},
],
KSX_TRACK_MOODS: [
{
name: "ksx-track-compass",
icon: "plus-square",
components: [
// {
// name: "Compass",
// id: "compass_tint_energy",
// props: {
// xAttrName: "KSX_TINT",
// yAttrName: "KSX_ENERGY",
// xLabel: "Lightsoft // Heavydark",
// yLabel: "Chill // Extreme",
// },
// },
// {
// name: "Compass",
// id: "compass_seriousness_materials",
// props: {
// xAttrName: "KSX_SERIOUSNESS",
// yAttrName: "KSX_MATERIALS",
// xLabel: "Dionysia // Apollonia",
// yLabel: "Natural // Reinforced",
// },
// },
],
},
],
};

View File

@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import EntryList from "../components/widgets/EntryList.svelte"; import EntryList from "../components/widgets/EntryList.svelte";
import Gallery from "../components/widgets/Gallery.svelte"; import Gallery from "../components/widgets/Gallery.svelte";
import type { Widget } from "src/lib/types"; import type { Widget } from "../components/EntryView.svelte";
import { Link } from "svelte-navigator"; import { Link } from "svelte-navigator";
import { UpListing } from "upend"; import { UpListing } from "upend";
import AttributeView from "../components/AttributeView.svelte"; import EntryView from "../components/EntryView.svelte";
import UpObjectCard from "../components/display/UpObjectCard.svelte"; import UpObjectCard from "../components/display/UpObjectCard.svelte";
import Spinner from "../components/utils/Spinner.svelte"; import Spinner from "../components/utils/Spinner.svelte";
import api from "../lib/api"; import api from "../lib/api";
@ -42,9 +42,9 @@
const shortWidgets: Widget[] = [ const shortWidgets: Widget[] = [
{ {
name: "list-table", name: "List",
icon: "list-ul", icon: "list-ul",
components: [ components: (entries) => [
{ {
component: EntryList, component: EntryList,
props: { props: {
@ -52,21 +52,20 @@
columnWidths: ["6em"], columnWidths: ["6em"],
orderByValue: true, orderByValue: true,
header: false, header: false,
entries,
}, },
}, },
], ],
}, },
{ {
name: "gallery-view", name: "Gallery",
icon: "image", icon: "image",
components: [ components: (entries) => [
{ {
component: Gallery, component: Gallery,
props: (entries) => { props: {
return { entities: entries.map((e) => e.entity),
entities: entries.map((e) => e.entity), sort: false,
sort: false,
};
}, },
}, },
], ],
@ -75,9 +74,9 @@
const longWidgets: Widget[] = [ const longWidgets: Widget[] = [
{ {
name: "list-table", name: "List",
icon: "list-ul", icon: "list-ul",
components: [ components: (entries) => [
{ {
component: EntryList, component: EntryList,
props: { props: {
@ -85,21 +84,20 @@
columnWidths: ["13em"], columnWidths: ["13em"],
orderByValue: true, orderByValue: true,
header: false, header: false,
entries,
}, },
}, },
], ],
}, },
{ {
name: "gallery-view", name: "Gallery",
icon: "image", icon: "image",
components: [ components: (entries) => [
{ {
component: Gallery, component: Gallery,
props: (entries) => { props: {
return { entities: entries.map((e) => e.entity),
entities: entries.map((e) => e.entity), sort: false,
sort: false,
};
}, },
}, },
], ],
@ -138,7 +136,7 @@
{#if $frequentQuery == undefined} {#if $frequentQuery == undefined}
<Spinner centered /> <Spinner centered />
{:else} {:else}
<AttributeView <EntryView
--current-background="var(--background)" --current-background="var(--background)"
entries={frequent} entries={frequent}
widgets={shortWidgets} widgets={shortWidgets}
@ -152,7 +150,7 @@
{#if $recentQuery == undefined} {#if $recentQuery == undefined}
<Spinner centered /> <Spinner centered />
{:else} {:else}
<AttributeView <EntryView
--current-background="var(--background)" --current-background="var(--background)"
entries={recent} entries={recent}
widgets={longWidgets} widgets={longWidgets}
@ -168,7 +166,7 @@
{#if $latestQuery == undefined} {#if $latestQuery == undefined}
<Spinner centered /> <Spinner centered />
{:else} {:else}
<AttributeView <EntryView
--current-background="var(--background)" --current-background="var(--background)"
entries={latest} entries={latest}
widgets={longWidgets} widgets={longWidgets}

View File

@ -9,10 +9,9 @@
import { baseSearch, createLabelled } from "../util/search"; import { baseSearch, createLabelled } from "../util/search";
import { updateTitle } from "../util/title"; import { updateTitle } from "../util/title";
import { query as queryFn } from "../lib/entity"; import { query as queryFn } from "../lib/entity";
import AttributeView from "../components/AttributeView.svelte"; import EntryView, { type Widget } from "../components/EntryView.svelte";
import api from "../lib/api"; import api from "../lib/api";
import Gallery from "../components/widgets/Gallery.svelte"; import Gallery from "../components/widgets/Gallery.svelte";
import type { Widget } from "src/lib/types";
import { matchSorter } from "match-sorter"; import { matchSorter } from "match-sorter";
const navigate = useNavigate(); const navigate = useNavigate();
@ -44,15 +43,15 @@
let exactHits: string[] = []; let exactHits: string[] = [];
$: { $: {
const addressesString = objects.map((e) => `@${e.entity}`).join(" "); const addressesString = objects.map((e) => `@${e.entity}`).join(" ");
api.query(`(matches (in ${addressesString}) "LBL" ? )`).then( api
(labelListing) => { .query(`(matches (in ${addressesString}) "LBL" ? )`)
.then((labelListing) => {
exactHits = labelListing.entries exactHits = labelListing.entries
.filter( .filter(
(e) => String(e.value.c).toLowerCase() === query.toLowerCase() (e) => String(e.value.c).toLowerCase() === query.toLowerCase()
) )
.map((e) => e.entity); .map((e) => e.entity);
} });
);
} }
async function create() { async function create() {
@ -64,33 +63,29 @@
const searchWidgets: Widget[] = [ const searchWidgets: Widget[] = [
{ {
name: "list-table", name: "List",
icon: "list-ul", icon: "list-ul",
components: [ components: (entries) => [
{ {
component: Gallery, component: Gallery,
props: (entries) => { props: {
return { entities: entries.map((e) => e.entity),
entities: entries.map((e) => e.entity), sort: false,
sort: false, thumbnails: false,
thumbnails: false,
};
}, },
}, },
], ],
}, },
{ {
name: "gallery-view", name: "Gallery",
icon: "image", icon: "image",
components: [ components: (entries) => [
{ {
component: Gallery, component: Gallery,
props: (entries) => { props: {
return { entities: entries.map((e) => e.entity),
entities: entries.map((e) => e.entity), sort: false,
sort: false, thumbnails: true,
thumbnails: true,
};
}, },
}, },
], ],
@ -123,7 +118,7 @@
<section class="objects"> <section class="objects">
{#if sortedObjects.length} {#if sortedObjects.length}
<h2>Objects</h2> <h2>Objects</h2>
<AttributeView <EntryView
--current-background="var(--background)" --current-background="var(--background)"
entries={sortedObjects} entries={sortedObjects}
widgets={searchWidgets} widgets={searchWidgets}