upend/webui/src/components/display/UpLink.svelte

89 lines
2.2 KiB
Svelte

<script lang="ts">
import { getContext } from "svelte";
import { useNavigate, useLocation } from "svelte-navigator";
import { readable } from "svelte/store";
import type { Address, VALUE_TYPE } from "@upnd/upend/types";
import type { BrowseContext } from "../../util/browse";
import api from "../../lib/api";
const location = useLocation();
const navigate = useNavigate();
export let passthrough = false;
export let title: string | undefined = undefined;
export let text = false;
export let to: {
entity?: Address;
attribute?: string;
surfaceAttribute?: string;
value?: { t: VALUE_TYPE; c: string };
};
const NOOP = "#";
let targetHref = NOOP;
$: {
if (to.entity) {
targetHref = to.entity;
} else if (to.attribute) {
api
.componentsToAddress({ t: "Attribute", c: to.attribute })
.then((address) => {
targetHref = address;
});
} else if (to.surfaceAttribute) {
targetHref = `surface:${to.surfaceAttribute}`;
}
}
const context = getContext("browse") as BrowseContext | undefined;
const index = context ? context.index : readable(0);
const addresses = context ? context.addresses : readable([]);
function onClick(ev: MouseEvent) {
if ($location.pathname.startsWith("/browse")) {
let newAddresses = $addresses.concat();
// Shift to append to the end instead of replacing
if (ev.shiftKey) {
newAddresses = newAddresses.concat([targetHref]);
} else {
if ($addresses[$index] !== targetHref) {
newAddresses = newAddresses.slice(0, $index + 1).concat([targetHref]);
}
}
navigate("/browse/" + newAddresses.join(","));
return true;
} else {
navigate(`/browse/${targetHref}`);
}
}
</script>
<a
class="uplink"
class:text
class:passthrough
class:unresolved={targetHref === NOOP}
href="/#/browse/{targetHref}"
on:click|preventDefault={onClick}
{title}
>
<slot />
</a>
<style lang="scss">
:global(.uplink) {
text-decoration: none;
max-width: 100%;
}
:global(.uplink.text) {
text-decoration: underline;
}
:global(.uplink.passthrough) {
display: contents;
}
:global(.uplink.unresolved) {
pointer-events: none;
}
</style>