Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import TooltipDescription from "@rilldata/web-common/components/tooltip/TooltipDescription.svelte";
import TooltipTitle from "@rilldata/web-common/components/tooltip/TooltipTitle.svelte";
import type { MetricsViewSpecMeasure } from "@rilldata/web-common/runtime-client";
import TooltipShortcutContainer from "@rilldata/web-common/components/tooltip/TooltipShortcutContainer.svelte";
import StackingWord from "@rilldata/web-common/components/tooltip/StackingWord.svelte";
import Shortcut from "@rilldata/web-common/components/tooltip/Shortcut.svelte";

export let measure: MetricsViewSpecMeasure;
export let value = "";
Expand All @@ -25,4 +28,13 @@
<TooltipDescription>
{description}
</TooltipDescription>

<TooltipShortcutContainer>
<div>
<StackingWord key="shift">Copy</StackingWord> to clipboard
</div>
<Shortcut>
<span style="font-family: var(--system);">⇧</span> + Click
</Shortcut>
</TooltipShortcutContainer>
</TooltipContent>
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@
{filterExcludeMode}
{atLeastOneActive}
{dimensionName}
dataType={dimension.dataType?.code ?? ""}
{itemData}
{isValidPercentOfTotal}
{leaderboardShowContextForAllMeasures}
Expand All @@ -396,6 +397,7 @@
<LeaderboardRow
{itemData}
{dimensionName}
dataType={dimension.dataType?.code ?? ""}
{isBeingCompared}
{filterExcludeMode}
{atLeastOneActive}
Expand Down
144 changes: 144 additions & 0 deletions web-common/src/features/dashboards/leaderboard/LeaderboardCell.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<script lang="ts">
import { onDestroy } from "svelte";
import * as Tooltip from "@rilldata/web-common/components/tooltip-v2";
import Shortcut from "@rilldata/web-common/components/tooltip/Shortcut.svelte";
import StackingWord from "@rilldata/web-common/components/tooltip/StackingWord.svelte";
import {
copyToClipboard,
isClipboardApiSupported,
} from "@rilldata/web-common/lib/actions/copy-to-clipboard.ts";
import { builderActions, getAttrs } from "bits-ui";
import { TOOLTIP_STRING_LIMIT } from "@rilldata/web-common/layout/config.ts";
import { modified } from "@rilldata/web-common/lib/actions/modified-click.ts";
import { cellInspectorStore } from "@rilldata/web-common/features/dashboards/stores/cell-inspector-store.ts";
import { FormattedDataType } from "@rilldata/web-common/components/data-types";

export let value: string;
export let dataType: string;
export let cellType: "dimension" | "measure" | "comparison";
export let className: string = "";
export let background: string = "";

const HideLeaderboardTooltipAfter = 3000;

const clipboardSupported =
typeof navigator !== "undefined" ? isClipboardApiSupported() : false;
const disabled = !clipboardSupported;

let tooltipActive = false;
$: if (tooltipActive) {
showTemporarily();
} else {
clearHideTimer();
}

let hideTimer: ReturnType<typeof setTimeout> | undefined;

function clearHideTimer() {
if (hideTimer) {
clearTimeout(hideTimer);
hideTimer = undefined;
}
}

function showTemporarily() {
if (disabled) return;
clearHideTimer();
hideTimer = setTimeout(() => {
tooltipActive = false;
}, HideLeaderboardTooltipAfter);
}

function shiftClickHandler(label: string) {
let truncatedLabel = label?.toString();
if (truncatedLabel?.length > TOOLTIP_STRING_LIMIT) {
truncatedLabel = `${truncatedLabel.slice(0, TOOLTIP_STRING_LIMIT)}...`;
}
copyToClipboard(
label,
`copied dimension value "${truncatedLabel}" to clipboard`,
);
}

onDestroy(clearHideTimer);
</script>

<Tooltip.Root
bind:open={tooltipActive}
openDelay={1000}
closeOnPointerDown={false}
>
<Tooltip.Trigger asChild let:builder {disabled}>
<td
role="button"
tabindex="0"
{...getAttrs([builder])}
use:builderActions={{ builders: [builder] }}
on:click={modified({
shift: () => shiftClickHandler(value),
})}
on:pointerover={() => {
if (value?.toString) {
// Always update the value in the store, but don't change visibility
cellInspectorStore.updateValue(value.toString());
}
}}
on:focus={() => {
if (value?.toString) {
// Always update the value in the store, but don't change visibility
cellInspectorStore.updateValue(value.toString());
}
}}
on:mouseleave={() => (tooltipActive = false)}
style:background
class="{cellType}-cell {className}"
>
<slot />
</td>
</Tooltip.Trigger>

{#if clipboardSupported && !disabled}
<Tooltip.Content
class="flex flex-col max-w-[280px] gap-y-2 p-2 shadow-md bg-gray-700 dark:bg-gray-900 text-surface"
sideOffset={16}
>
<FormattedDataType
customStyle="font-semibold"
isNull={value === null || value === undefined}
type={dataType}
{value}
/>
<div class="flex flex-row gap-x-6 items-baseline text-gray-100">
<div>
<StackingWord key="shift">Copy</StackingWord>
this value to clipboard
</div>
<Shortcut>
<span style="font-family: var(--system);">⇧</span> + Click
</Shortcut>
</div>
</Tooltip.Content>
{/if}
</Tooltip.Root>

<style lang="postcss">
td {
@apply text-right p-0;
@apply px-2 relative;
height: 22px;
}

td.comparison-cell {
@apply bg-surface px-1 truncate;
}

td.dimension-cell {
@apply sticky left-0 z-30 bg-surface;
}

:global(tr:hover td.dimension-cell),
:global(tr:hover td.measure-cell),
:global(tr:hover td.comparison-cell) {
@apply bg-gray-100;
}
</style>
Loading
Loading