feat: add basic group section to home

feat/type-attributes
Tomáš Mládek 2023-08-26 10:39:12 +02:00
parent f548a32b22
commit 42d5e085a2
2 changed files with 98 additions and 12 deletions

View File

@ -29,3 +29,9 @@ export const ATTR_ADDED = "ADDED";
* Attribute for cross-vault unambiguous referencing of non-hashable (e.g. UUID) entities.
*/
export const ATTR_KEY = "KEY";
/**
* Address of the root hierarchical entry.
*/
export const HIER_ROOT_ADDR =
"zb2rhmpmTFPxdhaxTQg5Ug3KHFU8DZNUPh8TaPY2v8UQVJbQk";

View File

@ -5,6 +5,7 @@
import { Link } from "svelte-navigator";
import { UpListing } from "upend";
import EntryView from "../components/EntryView.svelte";
import UpObject from "../components/display/UpObject.svelte";
import UpObjectCard from "../components/display/UpObjectCard.svelte";
import Spinner from "../components/utils/Spinner.svelte";
import api from "../lib/api";
@ -12,7 +13,12 @@
import { vaultInfo } from "../util/info";
import { updateTitle } from "../util/title";
import { i18n } from "../i18n";
import { ATTR_ADDED, ATTR_LABEL } from "upend/constants";
import {
ATTR_ADDED,
ATTR_IN,
ATTR_LABEL,
HIER_ROOT_ADDR,
} from "upend/constants";
const roots = (async () => {
const data = await api.fetchRoots();
@ -23,6 +29,47 @@
.sort(([_, i1], [__, i2]) => i1.localeCompare(i2));
})();
const groups = (async () => {
const data = await api.query(`(matches ? "${ATTR_IN}" ?)`);
const addresses = data.entries
.filter((e) => e.value.t === "Address")
.map((e) => e.value.c) as string[];
const sortedAddresses = [...new Set(addresses)]
.map((address) => ({
address,
count: addresses.filter((a) => a === address).length,
}))
.sort((a, b) => b.count - a.count);
const shortlist = sortedAddresses
.slice(0, 25)
.filter(({ address }) => address !== HIER_ROOT_ADDR);
const addressesString = shortlist
.map(({ address }) => `@${address}`)
.join(" ");
const labels = (
await api.query(`(matches (in ${addressesString}) "${ATTR_LABEL}" ? )`)
).entries.filter((e) => e.value.t === "String");
const display = shortlist.map(({ address, count }) => ({
address,
labels: labels
.filter((e) => e.entity === address)
.map((e) => e.value.c)
.sort() as string[],
count,
}));
display
.sort((a, b) => (a.labels[0] || "").localeCompare(b.labels[0] || ""))
.sort((a, b) => b.count - a.count);
return { groups: display, total: sortedAddresses.length };
})();
const { result: recentQuery } = query(`(matches ? "LAST_VISITED" ?)`);
$: recent = ($recentQuery?.entries || [])
.filter((e) => e.value.t == "Number")
@ -130,6 +177,26 @@
{/await}
</section>
<section class="groups">
<h2>{$i18n.t("Groups")}</h2>
{#await groups}
<Spinner centered />
{:then data}
<ul>
{#each data.groups as group}
<li class="group">
<UpObject link address={group.address} labels={group.labels} />
</li>
{:else}
<li>No groups?</li>
{/each}
{#if data.groups && data.total > data.groups.length}
<li>+ {data.total - data.groups.length}...</li>
{/if}
</ul>
{/await}
</section>
<div class="frecent">
{#if frequent.length || $frequentQuery === undefined}
<section class="frequent">
@ -183,7 +250,7 @@
<footer>
<div>
<strong>UpEnd</strong> - {$i18n.t(
"a database for the complex, the changing, and the indeterminate"
"a database for the complex, the changing, and the indeterminate",
)}
</div>
<div>
@ -201,23 +268,24 @@
flex-direction: column;
}
h1 {
font-size: 32pt;
font-variant: small-caps;
}
h2:first-of-type {
margin-top: 0;
}
h1,
h2 {
text-align: center;
}
h1 {
font-size: 32pt;
font-variant: small-caps;
margin: 2rem 0 0 0;
}
h2 {
margin: 2rem 0;
}
.latest,
.frecent {
margin: 2rem;
margin: 0 2rem;
}
.frecent {
@ -248,6 +316,18 @@
}
}
.groups {
ul {
list-style: none;
padding: 0;
margin: 0 2rem;
display: flex;
flex-wrap: wrap;
gap: 0.5em;
}
}
footer {
border-top: 1px solid var(--foreground);
text-align: center;