feat: web UI chat render, panels, presence + analytics
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<script lang="ts">
|
||||
import type { InlineButton } from "$lib/api/types";
|
||||
|
||||
interface Props {
|
||||
rows: InlineButton[][];
|
||||
}
|
||||
|
||||
let { rows }: Props = $props();
|
||||
|
||||
let copied = $state<string | null>(null);
|
||||
let resetTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
async function copy(key: string, data: string): Promise<void> {
|
||||
await navigator.clipboard.writeText(data);
|
||||
copied = key;
|
||||
clearTimeout(resetTimer);
|
||||
resetTimer = setTimeout(() => {
|
||||
copied = null;
|
||||
}, 1500);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="InlineButtons">
|
||||
{#each rows as row, rowIndex (rowIndex)}
|
||||
<div class="row">
|
||||
{#each row as button, colIndex (colIndex)}
|
||||
{@const key = `${rowIndex}:${colIndex}`}
|
||||
{#if button.kind === "url" && button.url}
|
||||
<a class="button" href={button.url} target="_blank" rel="noopener">
|
||||
<span class="label">{button.text}</span>
|
||||
<span class="corner">↗</span>
|
||||
</a>
|
||||
{:else if button.kind === "callback" && button.data}
|
||||
<button
|
||||
class="button"
|
||||
type="button"
|
||||
onclick={() => copy(key, button.data ?? "")}
|
||||
>
|
||||
<span class="label"
|
||||
>{copied === key ? "Скопировано" : button.text}</span
|
||||
>
|
||||
</button>
|
||||
{:else}
|
||||
<span class="button static">
|
||||
<span class="label">{button.text}</span>
|
||||
</span>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.InlineButtons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1875rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: minmax(0, 1fr);
|
||||
gap: 0.1875rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
min-height: 2rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border: none;
|
||||
border-radius: var(--border-radius-messages-small);
|
||||
|
||||
font-family: inherit;
|
||||
font-size: 0.875rem;
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--color-text);
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
|
||||
background-color: var(--color-message-reaction);
|
||||
cursor: pointer;
|
||||
|
||||
transition: background-color 150ms;
|
||||
|
||||
&:hover:not(.static) {
|
||||
background-color: var(--color-message-reaction-hover);
|
||||
}
|
||||
|
||||
&.static {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.corner {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user