diff --git a/src/lib/components/ui/menu/ContextMenuWrapper.svelte b/src/lib/components/ui/menu/ContextMenuWrapper.svelte new file mode 100644 index 00000000..a79fe762 --- /dev/null +++ b/src/lib/components/ui/menu/ContextMenuWrapper.svelte @@ -0,0 +1,36 @@ + + + + + {#snippet child({ props })} +
+ {@render trigger()} +
+ {/snippet} +
+ + + + {@render menu()} + + +
+ + diff --git a/src/lib/components/ui/menu/GearMenuButton.svelte b/src/lib/components/ui/menu/GearMenuButton.svelte new file mode 100644 index 00000000..29afa99d --- /dev/null +++ b/src/lib/components/ui/menu/GearMenuButton.svelte @@ -0,0 +1,123 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + + + {@render menu()} + + + + + diff --git a/src/lib/components/ui/menu/MenuItems.svelte b/src/lib/components/ui/menu/MenuItems.svelte new file mode 100644 index 00000000..b287dfa7 --- /dev/null +++ b/src/lib/components/ui/menu/MenuItems.svelte @@ -0,0 +1,52 @@ + + +{#if onViewDetails} + + {viewDetailsLabel} + +{/if} + +{#if canEdit} + {#if onReplace} + + {replaceLabel} + + {/if} + + {#if onRemove} + + + {removeLabel} + + {/if} +{/if} diff --git a/src/lib/components/ui/menu/UnitMenuContainer.svelte b/src/lib/components/ui/menu/UnitMenuContainer.svelte new file mode 100644 index 00000000..1536269e --- /dev/null +++ b/src/lib/components/ui/menu/UnitMenuContainer.svelte @@ -0,0 +1,55 @@ + + +
+ + + {#if showGearButton} + + {/if} +
+ + diff --git a/src/lib/components/ui/menu/menu-styles.scss b/src/lib/components/ui/menu/menu-styles.scss new file mode 100644 index 00000000..3e1465df --- /dev/null +++ b/src/lib/components/ui/menu/menu-styles.scss @@ -0,0 +1,102 @@ +@use '$src/themes/spacing' as *; +@use '$src/themes/layout' as *; +@use '$src/themes/typography' as *; +@use '$src/themes/effects' as *; + +// Shared menu container styles +@mixin menu-container { + background: var(--menu-bg); + border: 1px solid var(--border-subtle); + border-radius: $card-corner; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + padding: $unit-half; + min-width: calc($unit * 22.5); + z-index: 200; + animation: slideIn $duration-quick ease-out; +} + +// Shared menu item styles +@mixin menu-item { + padding: $unit $unit-2x; + border-radius: $item-corner-small; + cursor: pointer; + font-size: $font-regular; + color: var(--menu-text); + display: flex; + align-items: center; + gap: $unit; + @include smooth-transition($duration-standard, background); + + &:hover { + background: var(--menu-bg-item-hover); + } + + &:first-child { + border-top-left-radius: $item-corner; + border-top-right-radius: $item-corner; + } + + &:last-child { + border-bottom-left-radius: $item-corner; + border-bottom-right-radius: $item-corner; + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + &.danger { + color: var(--danger); + + &:hover { + background: var(--danger-bg); + } + } +} + +// Shared menu separator styles +@mixin menu-separator { + border-radius: $full-corner; + height: 2px; + background: var(--menu-separator); + margin: $unit-half ($unit * 0.75); +} + +// Slide in animation +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-$unit-fourth); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +// Global styles for context menu +:global(.context-menu) { + @include menu-container; +} + +:global(.context-menu-item) { + @include menu-item; +} + +:global(.context-menu-separator) { + @include menu-separator; +} + +// Global styles for dropdown menu +:global(.dropdown-menu) { + @include menu-container; +} + +:global(.dropdown-menu-item) { + @include menu-item; +} + +:global(.dropdown-menu-separator) { + @include menu-separator; +}