175 lines
4.4 KiB
Svelte
175 lines
4.4 KiB
Svelte
<script lang="ts">
|
|
import { createEventDispatcher, getContext } from "svelte";
|
|
import { BLOB_TYPE_ADDR } from "upend/constants";
|
|
import HashBadge from "./HashBadge.svelte";
|
|
import Ellipsis from "../utils/Ellipsis.svelte";
|
|
import UpLink from "./UpLink.svelte";
|
|
import { useEntity } from "../../lib/entity";
|
|
import { nativeOpen as nativeOpenApi } from "../../lib/api";
|
|
import { readable } from "svelte/store";
|
|
import { notify, UpNotification } from "../../notifications";
|
|
import IconButton from "../utils/IconButton.svelte";
|
|
import { vaultInfo } from "../../util/info";
|
|
import type { BrowseContext } from "../../util/browse";
|
|
const dispatch = createEventDispatcher();
|
|
|
|
export let address: string;
|
|
export let labels: string[] | undefined = undefined;
|
|
export let link = false;
|
|
export let banner = false;
|
|
|
|
let entity = readable(undefined);
|
|
$: if (labels === undefined) ({ entity } = useEntity(address));
|
|
|
|
// isFile
|
|
$: isFile = $entity?.get("IS") === BLOB_TYPE_ADDR;
|
|
|
|
// Identification
|
|
let inferredIds: string[] = [];
|
|
$: inferredIds = $entity?.identify() || [];
|
|
$: resolving = inferredIds.concat(labels || []).length == 0 && !$entity;
|
|
|
|
$: displayLabel =
|
|
Array.from(new Set(inferredIds.concat(labels || []))).join(" | ") ||
|
|
address;
|
|
|
|
$: dispatch("resolved", inferredIds);
|
|
|
|
// Navigation highlights
|
|
const context = getContext("browse") as BrowseContext | undefined;
|
|
const index = context?.index || undefined;
|
|
const addresses = context?.addresses || readable([]);
|
|
|
|
// Native open
|
|
function nativeOpen() {
|
|
notify.emit(
|
|
"notification",
|
|
new UpNotification(
|
|
`Opening ${
|
|
inferredIds[0] || address
|
|
} in a default native application...`
|
|
)
|
|
);
|
|
nativeOpenApi(address)
|
|
.then(async (response) => {
|
|
if (!response.ok) {
|
|
throw new Error(`${response.statusText} - ${await response.text()}`);
|
|
}
|
|
if (response.headers.has("warning")) {
|
|
const warningText = response.headers
|
|
.get("warning")
|
|
.split(" ")
|
|
.slice(2)
|
|
.join(" ");
|
|
notify.emit(
|
|
"notification",
|
|
new UpNotification(warningText, "warning")
|
|
);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
notify.emit(
|
|
"notification",
|
|
new UpNotification(
|
|
`Failed to open in native application! (${err})`,
|
|
"error"
|
|
)
|
|
);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
class="upobject"
|
|
class:left-active={address == $addresses[$index - 1]}
|
|
class:right-active={address == $addresses[$index + 1]}
|
|
>
|
|
<div class="address" class:identified={Boolean(inferredIds)} class:banner>
|
|
<HashBadge {address} />
|
|
<div class="separator" />
|
|
<div class="label" class:resolving title={displayLabel}>
|
|
{#if banner && isFile}
|
|
<a href="api/raw/{address}">
|
|
<Ellipsis value={displayLabel} />
|
|
</a>
|
|
{:else if link}
|
|
<UpLink to={{ entity: address }}>
|
|
<Ellipsis value={displayLabel} />
|
|
</UpLink>
|
|
{:else}
|
|
<Ellipsis value={displayLabel} />
|
|
{/if}
|
|
</div>
|
|
{#if $vaultInfo?.desktop}
|
|
{#if banner && isFile}
|
|
<div class="icon">
|
|
<IconButton
|
|
name="window-open"
|
|
on:click={nativeOpen}
|
|
title="Open in default application..."
|
|
/>
|
|
</div>
|
|
{/if}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style scoped lang="scss">
|
|
@use "../../styles/colors";
|
|
|
|
.upobject {
|
|
border-radius: 4px;
|
|
|
|
&.left-active {
|
|
background: linear-gradient(90deg, colors.$orange 0%, transparent 100%);
|
|
padding: 2px 0 2px 2px;
|
|
}
|
|
|
|
&.right-active {
|
|
background: linear-gradient(90deg, transparent 0%, colors.$orange 100%);
|
|
padding: 2px 2px 2px 0;
|
|
}
|
|
}
|
|
|
|
.address {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
padding: 0.1em 0.25em;
|
|
|
|
font-family: var(--monospace-font);
|
|
line-break: anywhere;
|
|
|
|
background: var(--background-lighter);
|
|
border: 0.1em solid var(--foreground-lighter);
|
|
border-radius: 0.2em;
|
|
|
|
&.banner {
|
|
border: 0.12em solid var(--foreground);
|
|
padding: 0.5em 0.25em;
|
|
}
|
|
|
|
&.identified {
|
|
font-family: var(--default-font);
|
|
font-size: 0.95em;
|
|
line-break: auto;
|
|
}
|
|
}
|
|
|
|
.label {
|
|
flex-grow: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.separator {
|
|
width: 0.5em;
|
|
}
|
|
|
|
.icon {
|
|
margin: 0 0.25em;
|
|
}
|
|
|
|
.resolving {
|
|
opacity: 0.7;
|
|
}
|
|
</style>
|