-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Enhance species configuration UI with advanced editing and acti…
…on management - Refactor species configuration section with improved editing capabilities - Add support for editing species configuration name and threshold - Implement custom action menu with edit, add action, and remove options - Enhance input validation and user experience for species configuration - Update Alpine.js components to support more flexible species management - Improve responsiveness and layout of species configuration inputs
- Loading branch information
Showing
6 changed files
with
508 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,180 @@ | ||
{{define "speciesListActionMenu"}} | ||
{{/* | ||
Action menu component for species list items | ||
- Provides a dropdown menu with edit and delete options | ||
- Dispatches events for parent components to handle: | ||
- edit-species event with the index of the species to edit | ||
- remove-species event with the index of the species to remove | ||
- Provides a dropdown menu with configurable actions | ||
- Dispatches events for parent components to handle | ||
- Supports custom actions through the menuItems parameter | ||
- Default actions are edit and delete if no custom actions provided | ||
- Includes sophisticated dropdown positioning logic from the elements version | ||
- Supports both numeric indices and string-based keys (species names) | ||
*/}} | ||
<div class="relative" x-data="{ open: false }"> | ||
<!-- Menu trigger button with three dots --> | ||
<button type="button" | ||
@click.prevent.stop="open = !open" | ||
class="btn btn-xs btn-ghost btn-circle" | ||
aria-label="Open actions menu"> | ||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | ||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" /> | ||
</svg> | ||
<div class="dropdown" | ||
x-data="{ | ||
open: false, | ||
// Ensure index and editIndex are properly defined with fallbacks | ||
safeIndex: typeof index !== 'undefined' ? index : null, | ||
// Use local context for edit state and check on render | ||
inEditMode() { | ||
return typeof editIndex !== 'undefined' && editIndex === this.safeIndex; | ||
}, | ||
notInEditMode() { | ||
return typeof editIndex === 'undefined' || editIndex !== this.safeIndex; | ||
}, | ||
updatePosition() { | ||
this.$nextTick(() => { | ||
const menu = this.$refs.menu; | ||
const button = this.$refs.button; | ||
if (!menu || !button) return; | ||
const buttonRect = button.getBoundingClientRect(); | ||
const spaceBelow = window.innerHeight - buttonRect.bottom; | ||
const spaceAbove = buttonRect.top; | ||
const menuHeight = menu.offsetHeight; | ||
// Position menu relative to viewport | ||
menu.style.position = 'fixed'; | ||
menu.style.zIndex = '50'; | ||
// Determine vertical position | ||
if (spaceBelow < menuHeight && spaceAbove > spaceBelow) { | ||
menu.style.bottom = (window.innerHeight - buttonRect.top + 8) + 'px'; | ||
menu.style.top = 'auto'; | ||
} else { | ||
menu.style.top = (buttonRect.bottom + 8) + 'px'; | ||
menu.style.bottom = 'auto'; | ||
} | ||
// Always align menu's right edge with button's right edge | ||
menu.style.left = 'auto'; | ||
menu.style.right = (window.innerWidth - buttonRect.right) + 'px'; | ||
}); | ||
} | ||
}" | ||
class="relative"> | ||
|
||
<!-- Action button - visible in normal mode --> | ||
<button x-show="notInEditMode()" | ||
x-ref="button" | ||
@click="open = !open; if (open) updatePosition()" | ||
type="button" | ||
class="btn btn-ghost btn-sm"> | ||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | ||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" /> | ||
</svg> | ||
</button> | ||
|
||
<!-- Edit mode buttons - Save and Cancel --> | ||
<div x-show="inEditMode()" class="flex space-x-2" x-cloak> | ||
<!-- Save button --> | ||
<button @click.prevent.stop="$dispatch('save-edit-species', { index: safeIndex, listType: listType })" | ||
type="button" | ||
class="btn btn-primary btn-sm"> | ||
Save | ||
</button> | ||
|
||
<!-- Dropdown menu --> | ||
<div x-show="open" | ||
@click.away="open = false" | ||
@keydown.escape.window="open = false" | ||
class="absolute right-0 mt-2 z-10 w-40 bg-base-100 shadow-lg rounded-md" | ||
x-cloak> | ||
<div class="py-1 rounded-md"> | ||
<!-- Edit option --> | ||
<!-- Cancel button --> | ||
<button @click.prevent.stop="$dispatch('cancel-edit-species', { index: safeIndex, listType: listType })" | ||
type="button" | ||
class="btn btn-outline btn-warning btn-sm"> | ||
Cancel | ||
</button> | ||
</div> | ||
|
||
<!-- Dropdown menu - only visible in normal mode --> | ||
<div x-show="open && notInEditMode()" | ||
x-ref="menu" | ||
@click.away="open = false" | ||
x-transition:enter="transition ease-out duration-200" | ||
x-transition:enter-start="opacity-0 scale-95" | ||
x-transition:enter-end="opacity-100 scale-100" | ||
x-transition:leave="transition ease-in duration-150" | ||
x-transition:leave-start="opacity-100 scale-100" | ||
x-transition:leave-end="opacity-0 scale-95" | ||
class="fixed menu p-2 shadow-lg bg-base-100 rounded-box w-40 border border-base-300" | ||
x-cloak> | ||
|
||
<!-- Custom menu items if provided --> | ||
<template x-if="typeof customMenuItems !== 'undefined' && customMenuItems"> | ||
<div class="py-1 rounded-md"> | ||
<!-- Edit option for custom species configuration --> | ||
<template x-if="customMenuItems.includes('editConfig')"> | ||
<div> | ||
<button type="button" | ||
@click.prevent.stop="$dispatch('edit-species', { index: index }); open = false" | ||
@click.prevent.stop="$dispatch('edit-species-config', { species: item, index: safeIndex }); open = false" | ||
class="w-full text-left px-4 py-2 text-sm hover:bg-base-200"> | ||
<span class="flex items-center"> | ||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | ||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" /> | ||
</svg> | ||
Edit | ||
</span> | ||
<span class="flex items-center"> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 mr-2"> | ||
<path d="M13.488 2.513a1.75 1.75 0 0 0-2.475 0L6.75 6.774a2.75 2.75 0 0 0-.596.892l-.848 2.047a.75.75 0 0 0 .98.98l2.047-.848a2.75 2.75 0 0 0 .892-.596l4.261-4.262a1.75 1.75 0 0 0 0-2.474Z" /> | ||
<path d="M4.75 3.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h6.5c.69 0 1.25-.56 1.25-1.25V9A.75.75 0 0 1 14 9v2.25A2.75 2.75 0 0 1 11.25 14h-6.5A2.75 2.75 0 0 1 2 11.25v-6.5A2.75 2.75 0 0 1 4.75 2H7a.75.75 0 0 1 0 1.5H4.75Z" /> | ||
</svg> | ||
<span>Edit</span> | ||
</span> | ||
</button> | ||
|
||
<!-- Delete option --> | ||
<button type="button" | ||
@click.prevent.stop="$dispatch('remove-species', { index: index }); open = false" | ||
class="w-full text-left px-4 py-2 text-sm text-error hover:bg-base-200"> | ||
<span class="flex items-center"> | ||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | ||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /> | ||
</svg> | ||
Delete | ||
</span> | ||
</div> | ||
</template> | ||
|
||
<!-- Add Action button (for species config) --> | ||
<template x-if="customMenuItems.includes('addAction')"> | ||
<div> | ||
<button type="button" | ||
@click.prevent.stop="$dispatch('species-add-action', { species: item, index: safeIndex }); open = false" | ||
class="w-full text-left px-4 py-2 text-sm hover:bg-base-200"> | ||
<span class="flex items-center"> | ||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | ||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" /> | ||
</svg> | ||
<span x-text="typeof $root.speciesSettings !== 'undefined' && $root.speciesSettings.Config && $root.speciesSettings.Config[item]?.Actions?.length ? 'Edit Action' : 'Add Action'"></span> | ||
</span> | ||
</button> | ||
</div> | ||
</template> | ||
|
||
<!-- Delete/Remove button for custom actions --> | ||
<div> | ||
<button type="button" | ||
@click.prevent.stop="$dispatch('remove-species', { index: safeIndex, listType: listType, species: item }); open = false" | ||
class="w-full text-left px-4 py-2 text-sm hover:bg-base-200"> | ||
<span class="flex items-center"> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4 mr-2"> | ||
<path fill-rule="evenodd" d="M5 3.25V4H2.75a.75.75 0 0 0 0 1.5h.3l.815 8.15A1.5 1.5 0 0 0 5.357 15h5.285a1.5 1.5 0 0 0 1.493-1.35l.815-8.15h.3a.75.75 0 0 0 0-1.5H11v-.75A2.25 2.25 0 0 0 8.75 1h-1.5A2.25 2.25 0 0 0 5 3.25Zm2.25-.75a.75.75 0 0 0-.75.75V4h3v-.75a.75.75 0 0 0-.75-.75h-1.5ZM6.05 6a.75.75 0 0 1 .787.713l.275 5.5a.75.75 0 0 1-1.498.075l-.275-5.5A.75.75 0 0 1 6.05 6Zm3.9 0a.75.75 0 0 1 .712.787l-.275 5.5a.75.75 0 0 1-1.498-.075l.275-5.5a.75.75 0 0 1 .786-.711Z" clip-rule="evenodd" /> | ||
</svg> | ||
<span>Remove</span> | ||
</span> | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<!-- Default menu items if no custom items provided --> | ||
<template x-if="typeof customMenuItems === 'undefined' || !customMenuItems"> | ||
<div> | ||
<!-- Edit option --> | ||
<a href="#" | ||
class="block px-4 py-2 text-sm hover:bg-base-200" | ||
@click.prevent.stop="open = false; $dispatch('edit-species', { index: safeIndex, listType: listType })"> | ||
<div class="flex items-center gap-2"> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"> | ||
<path d="M13.488 2.513a1.75 1.75 0 0 0-2.475 0L6.75 6.774a2.75 2.75 0 0 0-.596.892l-.848 2.047a.75.75 0 0 0 .98.98l2.047-.848a2.75 2.75 0 0 0 .892-.596l4.261-4.262a1.75 1.75 0 0 0 0-2.474Z" /> | ||
<path d="M4.75 3.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h6.5c.69 0 1.25-.56 1.25-1.25V9A.75.75 0 0 1 14 9v2.25A2.75 2.75 0 0 1 11.25 14h-6.5A2.75 2.75 0 0 1 2 11.25v-6.5A2.75 2.75 0 0 1 4.75 2H7a.75.75 0 0 1 0 1.5H4.75Z" /> | ||
</svg> | ||
<span>Edit</span> | ||
</div> | ||
</a> | ||
|
||
<!-- Remove option --> | ||
<a href="#" | ||
class="block px-4 py-2 text-sm hover:bg-base-200" | ||
@click.prevent.stop="open = false; $dispatch('remove-species', { index: safeIndex, listType: listType })"> | ||
<div class="flex items-center gap-2"> | ||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"> | ||
<path fill-rule="evenodd" d="M5 3.25V4H2.75a.75.75 0 0 0 0 1.5h.3l.815 8.15A1.5 1.5 0 0 0 5.357 15h5.285a1.5 1.5 0 0 0 1.493-1.35l.815-8.15h.3a.75.75 0 0 0 0-1.5H11v-.75A2.25 2.25 0 0 0 8.75 1h-1.5A2.25 2.25 0 0 0 5 3.25Zm2.25-.75a.75.75 0 0 0-.75.75V4h3v-.75a.75.75 0 0 0-.75-.75h-1.5ZM6.05 6a.75.75 0 0 1 .787.713l.275 5.5a.75.75 0 0 1-1.498.075l-.275-5.5A.75.75 0 0 1 6.05 6Zm3.9 0a.75.75 0 0 1 .712.787l-.275 5.5a.75.75 0 0 1-1.498-.075l.275-5.5a.75.75 0 0 1 .786-.711Z" clip-rule="evenodd" /> | ||
</svg> | ||
<span>Remove</span> | ||
</div> | ||
</a> | ||
</div> | ||
</template> | ||
|
||
</div> | ||
</div> | ||
{{end}} |
Oops, something went wrong.