feat: add basic group section to home
parent
f548a32b22
commit
42d5e085a2
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue