Skip to content

Commit

Permalink
Canvas: Inline add components (#6529)
Browse files Browse the repository at this point in the history
* selected component index null directly

* inline add component

* fix spacing

* granular events handling for triggering contextmenu

* shared menu items

* remove dup contextmenu in blank canvas

* remove add component menu

* lint

* remove unused

* re-add ml-2 to canvas filters

* Revert "remove add component menu"

This reverts commit d7a1765.

* add component
  • Loading branch information
lovincyrus authored Feb 3, 2025
1 parent ad5843f commit 56cd169
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 105 deletions.
64 changes: 8 additions & 56 deletions web-common/src/features/canvas/BlankCanvas.svelte
Original file line number Diff line number Diff line change
@@ -1,36 +1,5 @@
<script lang="ts">
import { PlusCircleIcon } from "lucide-svelte";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@rilldata/web-common/components/context-menu";
import type { CanvasComponentType } from "./components/types";
import type { ComponentType, SvelteComponent } from "svelte";
import ChartIcon from "./icons/ChartIcon.svelte";
import TableIcon from "./icons/TableIcon.svelte";
import TextIcon from "./icons/TextIcon.svelte";
import BigNumberIcon from "./icons/BigNumberIcon.svelte";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();
const menuItems: {
id: CanvasComponentType;
label: string;
icon: ComponentType<SvelteComponent>;
}[] = [
{ id: "bar_chart", label: "Chart", icon: ChartIcon },
{ id: "table", label: "Table", icon: TableIcon },
{ id: "markdown", label: "Text", icon: TextIcon },
{ id: "kpi", label: "KPI", icon: BigNumberIcon },
{ id: "image", label: "Image", icon: ChartIcon },
];
function handleAddComponent(componentType: CanvasComponentType) {
dispatch("add", { type: componentType });
}
function handleButtonClick(event: MouseEvent) {
const contextMenuEvent = new MouseEvent("contextmenu", {
Expand All @@ -43,31 +12,14 @@
</script>

<div class="size-full p-4 bg-white">
<ContextMenu>
<ContextMenuTrigger>
<button
type="button"
class="blank-canvas-button flex flex-col items-center gap-2 p-8 rounded-[6px] border border-slate-200 w-full"
on:click={handleButtonClick}
>
<PlusCircleIcon class="w-6 h-6 text-slate-500" />
<span class="text-sm font-medium text-slate-500">Add a component</span>
</button>
</ContextMenuTrigger>
<ContextMenuContent>
{#each menuItems as item}
<ContextMenuItem
on:click={() => handleAddComponent(item.id)}
class="text-gray-700 text-xs"
>
<div class="flex flex-row gap-x-2">
<svelte:component this={item.icon} />
<span class="text-gray-700 text-xs font-normal">{item.label}</span>
</div>
</ContextMenuItem>
{/each}
</ContextMenuContent>
</ContextMenu>
<button
type="button"
class="blank-canvas-button flex flex-col items-center gap-2 p-8 rounded-[6px] border border-slate-200 w-full"
on:click={handleButtonClick}
>
<PlusCircleIcon class="w-6 h-6 text-slate-500" />
<span class="text-sm font-medium text-slate-500">Add a component</span>
</button>
</div>

<style lang="postcss">
Expand Down
66 changes: 55 additions & 11 deletions web-common/src/features/canvas/Canvas.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@
import type { CanvasComponentType } from "./components/types";
import BlankCanvas from "./BlankCanvas.svelte";
import CanvasFilters from "@rilldata/web-common/features/canvas/filters/CanvasFilters.svelte";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@rilldata/web-common/components/context-menu";
import { menuItems } from "./components/menu-items.svelte";
export let fileArtifact: FileArtifact;
Expand Down Expand Up @@ -177,6 +184,22 @@
async function handleAdd(e: CustomEvent<{ type: CanvasComponentType }>) {
await addComponent(e.detail.type);
}
function handleContextMenu(
event: CustomEvent<{ originalEvent: MouseEvent }>,
) {
const target = event.detail.originalEvent.target as HTMLElement;
const gridStackEl = target.closest(".grid-stack-item");
// Prevent context menu if clicking on a grid item
if (gridStackEl) {
event.detail.originalEvent.preventDefault();
event.detail.originalEvent.stopPropagation();
event.preventDefault();
event.stopPropagation();
return false;
}
}
</script>

{#if filtersEnabled}
Expand All @@ -188,17 +211,38 @@
</div>
{/if}

{#if items.length === 0}
<BlankCanvas on:add={handleAdd} />
{:else}
<CanvasDashboardPreview
{items}
{spec}
activeIndex={$selectedIndex}
on:update={handleUpdate}
on:delete={handleDelete}
/>
{/if}
<ContextMenu>
<ContextMenuTrigger
class="h-full w-full block"
on:contextmenu={handleContextMenu}
>
{#if items.length === 0}
<BlankCanvas />
{:else}
<CanvasDashboardPreview
{items}
{spec}
activeIndex={$selectedIndex}
on:update={handleUpdate}
on:delete={handleDelete}
/>
{/if}
</ContextMenuTrigger>
<ContextMenuContent>
{#each menuItems as item}
<ContextMenuItem
on:click={() =>
handleAdd(new CustomEvent("add", { detail: { type: item.id } }))}
class="text-gray-700 text-xs"
>
<div class="flex flex-row gap-x-2">
<svelte:component this={item.icon} />
<span class="text-gray-700 text-xs font-normal">{item.label}</span>
</div>
</ContextMenuItem>
{/each}
</ContextMenuContent>
</ContextMenu>

<svelte:window
on:keydown={async (e) => {
Expand Down
15 changes: 2 additions & 13 deletions web-common/src/features/canvas/CanvasDashboardPreview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@
}
function handleDeselect() {
activeIndex = null;
canvasEntity.setSelectedComponentIndex(activeIndex);
canvasEntity.setSelectedComponentIndex(null);
}
function handleClickOutside(event: Event) {
Expand All @@ -121,21 +120,11 @@
// Only deselect if click is inside canvas or dashboard-theme-boundary but outside grid-stack
if ((canvasEl || dashboardThemeBoundaryEl) && !gridStackEl) {
activeIndex = null;
canvasEntity.setSelectedComponentIndex(activeIndex);
canvasEntity.setSelectedComponentIndex(null);
}
}
</script>

<!-- {#if showFilterBar}
<div
id="header"
class="border-b w-fit min-w-full flex flex-col bg-slate-50 slide"
>
<CanvasFilters />
</div>
{/if} -->

<CanvasDashboardWrapper bind:contentRect height={maxBottom}>
<div bind:this={gridContainer} use:clickOutside={[null, handleClickOutside]}>
<SvelteGridStack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,11 @@
import * as DropdownMenu from "@rilldata/web-common/components/dropdown-menu";
import type { CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types";
import { ChevronDown, Plus } from "lucide-svelte";
import type { ComponentType, SvelteComponent } from "svelte";
import ChartIcon from "../icons/ChartIcon.svelte";
import TableIcon from "../icons/TableIcon.svelte";
import TextIcon from "../icons/TextIcon.svelte";
import BigNumberIcon from "../icons/BigNumberIcon.svelte";
import { menuItems } from "./menu-items.svelte";
export let addComponent: (componentType: CanvasComponentType) => void;
let open = false;
const menuItems: {
id: CanvasComponentType;
label: string;
icon: ComponentType<SvelteComponent>;
}[] = [
{ id: "bar_chart", label: "Chart", icon: ChartIcon },
{ id: "table", label: "Table", icon: TableIcon },
{ id: "markdown", label: "Text", icon: TextIcon },
{ id: "kpi", label: "KPI", icon: BigNumberIcon },
{ id: "image", label: "Image", icon: ChartIcon },
];
</script>

<DropdownMenu.Root bind:open typeahead={false}>
Expand Down
22 changes: 22 additions & 0 deletions web-common/src/features/canvas/components/menu-items.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts" context="module">
import type { CanvasComponentType } from "./types";
import ChartIcon from "../icons/ChartIcon.svelte";
import TableIcon from "../icons/TableIcon.svelte";
import TextIcon from "../icons/TextIcon.svelte";
import BigNumberIcon from "../icons/BigNumberIcon.svelte";
import type { ComponentType, SvelteComponent } from "svelte";
export type MenuItem = {
id: CanvasComponentType;
label: string;
icon: ComponentType<SvelteComponent>;
};
export const menuItems: MenuItem[] = [
{ id: "bar_chart", label: "Chart", icon: ChartIcon },
{ id: "table", label: "Table", icon: TableIcon },
{ id: "markdown", label: "Text", icon: TextIcon },
{ id: "kpi", label: "KPI", icon: BigNumberIcon },
{ id: "image", label: "Image", icon: ChartIcon },
];
</script>
7 changes: 3 additions & 4 deletions web-common/src/features/canvas/filters/CanvasFilters.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@
}
</script>

<div class="flex flex-col gap-y-2 w-full h-20 justify-center ml-2">
<div class="flex flex-row flex-wrap gap-x-2 gap-y-1.5 items-center">
<div class="flex flex-col gap-y-2 w-full h-20 justify-center">
<div class="flex flex-row flex-wrap gap-x-2 gap-y-1.5 items-center ml-2">
<Calendar size="16px" />
<CanvasSuperPill
allTimeRange={$allTimeRange}
Expand All @@ -108,8 +108,7 @@
selectedComparisonTimeRange={$selectedComparisonTimeRange}
/>
</div>

<div class="relative flex flex-row gap-x-2 gap-y-2 items-start">
<div class="relative flex flex-row gap-x-2 gap-y-2 items-start ml-2">
{#if !readOnly}
<Filter size="16px" className="ui-copy-icon flex-none mt-[5px]" />
{/if}
Expand Down
8 changes: 4 additions & 4 deletions web-common/src/features/workspaces/CanvasWorkspace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import Canvas from "@rilldata/web-common/features/canvas/Canvas.svelte";
import CanvasEditor from "@rilldata/web-common/features/canvas/CanvasEditor.svelte";
import CanvasThemeProvider from "@rilldata/web-common/features/canvas/CanvasThemeProvider.svelte";
import AddComponentMenu from "@rilldata/web-common/features/canvas/components/AddComponentMenu.svelte";
import type { CanvasComponentType } from "@rilldata/web-common/features/canvas/components/types";
import { getComponentRegistry } from "@rilldata/web-common/features/canvas/components/util";
import VisualCanvasEditing from "@rilldata/web-common/features/canvas/inspector/VisualCanvasEditing.svelte";
import { useDefaultMetrics } from "@rilldata/web-common/features/canvas/selector";
Expand All @@ -27,9 +25,11 @@
import WorkspaceEditorContainer from "@rilldata/web-common/layout/workspace/WorkspaceEditorContainer.svelte";
import { queryClient } from "@rilldata/web-common/lib/svelte-query/globalQueryClient";
import { runtime } from "@rilldata/web-common/runtime-client/runtime-store";
import { parseDocument } from "yaml";
import PreviewButton from "../explores/PreviewButton.svelte";
import { findNextAvailablePosition } from "@rilldata/web-common/features/canvas/util";
import type { CanvasComponentType } from "../canvas/components/types";
import { parseDocument } from "yaml";
import { findNextAvailablePosition } from "../canvas/util";
import AddComponentMenu from "../canvas/components/AddComponentMenu.svelte";
export let fileArtifact: FileArtifact;
Expand Down

1 comment on commit 56cd169

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.