| <script lang="ts"> | |
| import { onMount } from "svelte"; | |
| import Arrow from "./Arrow.svelte"; | |
| import type { I18nFormatter } from "js/utils/src"; | |
| export let x: number; | |
| export let y: number; | |
| export let on_add_row_above: () => void; | |
| export let on_add_row_below: () => void; | |
| export let on_add_column_left: () => void; | |
| export let on_add_column_right: () => void; | |
| export let row: number; | |
| export let i18n: I18nFormatter; | |
| let menu_element: HTMLDivElement; | |
| $: is_header = row === -1; | |
| onMount(() => { | |
| position_menu(); | |
| }); | |
| function position_menu(): void { | |
| if (!menu_element) return; | |
| const viewport_width = window.innerWidth; | |
| const viewport_height = window.innerHeight; | |
| const menu_rect = menu_element.getBoundingClientRect(); | |
| let new_x = x - 30; | |
| let new_y = y - 20; | |
| if (new_x + menu_rect.width > viewport_width) { | |
| new_x = x - menu_rect.width + 10; | |
| } | |
| if (new_y + menu_rect.height > viewport_height) { | |
| new_y = y - menu_rect.height + 10; | |
| } | |
| menu_element.style.left = `${new_x}px`; | |
| menu_element.style.top = `${new_y}px`; | |
| } | |
| </script> | |
| <div bind:this={menu_element} class="cell-menu"> | |
| {#if !is_header} | |
| <button on:click={() => on_add_row_above()}> | |
| <Arrow transform="rotate(-90 12 12)" /> | |
| {i18n("dataframe.add_row_above")} | |
| </button> | |
| <button on:click={() => on_add_row_below()}> | |
| <Arrow transform="rotate(90 12 12)" /> | |
| {i18n("dataframe.add_row_below")} | |
| </button> | |
| {/if} | |
| <button on:click={() => on_add_column_left()}> | |
| <Arrow transform="rotate(180 12 12)" /> | |
| {i18n("dataframe.add_column_left")} | |
| </button> | |
| <button on:click={() => on_add_column_right()}> | |
| <Arrow transform="rotate(0 12 12)" /> | |
| {i18n("dataframe.add_column_right")} | |
| </button> | |
| </div> | |
| <style> | |
| .cell-menu { | |
| position: fixed; | |
| z-index: var(--layer-2); | |
| background: var(--background-fill-primary); | |
| border: 1px solid var(--border-color-primary); | |
| border-radius: var(--radius-sm); | |
| padding: var(--size-1); | |
| display: flex; | |
| flex-direction: column; | |
| gap: var(--size-1); | |
| box-shadow: var(--shadow-drop-lg); | |
| min-width: 150px; | |
| } | |
| .cell-menu button { | |
| background: none; | |
| border: none; | |
| cursor: pointer; | |
| text-align: left; | |
| padding: var(--size-1) var(--size-2); | |
| border-radius: var(--radius-sm); | |
| color: var(--body-text-color); | |
| font-size: var(--text-sm); | |
| transition: | |
| background-color 0.2s, | |
| color 0.2s; | |
| display: flex; | |
| align-items: center; | |
| gap: var(--size-2); | |
| } | |
| .cell-menu button:hover { | |
| background-color: var(--background-fill-secondary); | |
| } | |
| .cell-menu button :global(svg) { | |
| fill: currentColor; | |
| transition: fill 0.2s; | |
| } | |
| .cell-menu button:hover :global(svg) { | |
| fill: var(--color-accent); | |
| } | |
| </style> | |