[ui] add thumbnail HIER view

feat/vaults
Tomáš Mládek 2022-02-02 19:17:30 +01:00
parent ede5ea5555
commit 639e6d5c1c
No known key found for this signature in database
GPG Key ID: ED21612889E75EC5
4 changed files with 244 additions and 43 deletions

View File

@ -29,8 +29,8 @@
},
];
if (type?.widgetInfo) {
availableWidgets = [type.widgetInfo, ...availableWidgets];
if (type?.widgetInfo.length > 0) {
availableWidgets = [...type.widgetInfo, ...availableWidgets];
}
currentWidget = availableWidgets[0].name;
}

View File

@ -0,0 +1,126 @@
<script lang="ts">
import type { UpEntry } from "upend";
import Thumbnail from "./gallery/Thumbnail.svelte";
export let entries: UpEntry[];
export let editable = false;
// Sorting
let sortedAttributes = entries;
let sortKeys: { [key: string]: string[] } = {};
function addSortKeys(key: string, vals: string[], resort = true) {
if (!sortKeys[key]) {
sortKeys[key] = [];
}
let changed = false;
vals.forEach((val) => {
if (!sortKeys[key].includes(val)) {
changed = true;
sortKeys[key].push(val);
}
});
if (resort && changed) sortAttributes();
}
function sortAttributes() {
sortedAttributes = entries
.concat()
.sort((aEntry, bEntry) => {
if (
!sortKeys[aEntry.value.c]?.length ||
!sortKeys[bEntry.value.c]?.length
) {
if (
Boolean(sortKeys[aEntry.value.c]?.length) &&
!sortKeys[bEntry.value.c]?.length
) {
return -1;
} else if (
!sortKeys[aEntry.value.c]?.length &&
Boolean(sortKeys[bEntry.value.c]?.length)
) {
return 1;
} else {
return String(aEntry.value.c).localeCompare(String(bEntry.value.c));
}
} else {
return sortKeys[aEntry.value.c][0].localeCompare(
sortKeys[bEntry.value.c][0],
undefined,
{ numeric: true, sensitivity: "base" }
);
}
})
.sort((aEntry, bEntry) => {
return String(aEntry.value.c).length - String(bEntry.value.c).length;
})
.sort((aEntry, bEntry) => {
return aEntry.attribute.localeCompare(bEntry.attribute);
})
.sort((aEntry, bEntry) => {
if (
!sortKeys[aEntry.entity]?.length ||
!sortKeys[bEntry.entity]?.length
) {
if (
Boolean(sortKeys[aEntry.entity]?.length) &&
!sortKeys[bEntry.entity]?.length
) {
return -1;
} else if (
!sortKeys[aEntry.entity]?.length &&
Boolean(sortKeys[bEntry.entity]?.length)
) {
return 1;
} else {
return aEntry.entity.localeCompare(bEntry.entity);
}
} else {
return sortKeys[aEntry.entity][0].localeCompare(
sortKeys[bEntry.entity][0]
);
}
});
}
entries.forEach((entry) => {
addSortKeys(entry.entity, entry.listing.getObject(entry.entity).identify());
if (entry.value.t === "Address") {
addSortKeys(
entry.value.c,
entry.listing.getObject(String(entry.value.c)).identify(),
false
);
}
});
sortAttributes();
</script>
<div class="gallery">
{#each sortedAttributes as entry (entry.address)}
<div class="thumbnail">
<Thumbnail
address={String(entry.value.c)}
on:resolved={(event) => {
addSortKeys(String(entry.value.c), event.detail);
}}
/>
</div>
{/each}
</div>
<style lang="scss">
.gallery {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.thumbnail {
flex-grow: 1;
min-width: 0;
}
</style>

View File

@ -0,0 +1,61 @@
<script lang="ts">
import UpObject from "../../display/UpObject.svelte";
import HashBadge from "../../display/HashBadge.svelte";
import Spinner from "../../utils/Spinner.svelte";
import UpLink from "../../display/UpLink.svelte";
import { createEventDispatcher } from "svelte";
export let address: string;
let loaded = "";
let handled = true;
let identity = address;
</script>
<UpLink to={{ entity: address }}>
<div class="thumbnail">
<div class="image" class:loaded={loaded == address || !handled}>
{#if handled && loaded != address}
<div class="spinner">
<Spinner />
</div>
{/if}
{#if handled}
<img
src="/api/thumb/{address}"
alt="Thumbnail for {identity}..."
on:load={() => (loaded = address)}
on:error={() => (handled = false)}
/>
{:else}
<div class="hashbadge">
<HashBadge {address} />
</div>
{/if}
</div>
<div class="label">
<UpObject {address} on:resolved />
</div>
</div>
</UpLink>
<style lang="scss">
.thumbnail {
border: 1px solid var(--foreground);
border-radius: 4px;
padding: 0.5em;
}
.image.loaded {
text-align: center;
}
img {
max-width: 100%;
}
.hashbadge {
font-size: 64px;
opacity: 0.25;
}
</style>

View File

@ -1,4 +1,5 @@
import Table from "../components/widgets/Table.svelte";
import Gallery from "../components/widgets/Gallery.svelte";
export class UpType {
address: string;
@ -14,8 +15,8 @@ export class UpType {
return this.name ? TYPE_ICONS[this.name] : undefined;
}
public get widgetInfo(): Widget | undefined {
return this.name ? TYPE_WIDGETS[this.name] : undefined;
public get widgetInfo(): Widget[] {
return TYPE_WIDGETS[this.name] || [];
}
}
@ -37,44 +38,57 @@ const TYPE_ICONS: { [key: string]: string } = {
HIER: "folder",
};
const TYPE_WIDGETS: { [key: string]: Widget } = {
HIER: {
name: "hierarchical-listing",
icon: "folder",
components: [
{
component: Table,
props: {
columns: "value",
header: false,
const TYPE_WIDGETS: { [key: string]: Widget[] } = {
HIER: [
{
name: "hierarchical-listing",
icon: "folder",
components: [
{
component: Table,
props: {
columns: "value",
header: false,
},
},
},
],
},
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",
// },
// },
],
},
],
},
{
name: "gallery-view",
icon: "image",
components: [
{
component: Gallery,
},
],
},
],
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",
// },
// },
],
},
],
};