jedmund-svelte/src/lib/components/admin/StatusDropdown.svelte
Justin Edmund e305bf15ef refactor: replace button text changes with toast notifications
- Update all admin forms to use toast messages
- Remove temporary "Saving..." button text changes
- Remove inline error/success message displays
- Keep buttons disabled during operations
- Show loading, success, and error toasts appropriately

Updated components:
- AlbumForm: Save operations with descriptive messages
- StatusDropdown: Remove loading text from buttons
- MediaDetailsModal: Save, delete, and copy operations
- ProjectForm: Create and update operations
- EssayForm: Publish and save draft operations
- SimplePostForm: Create and update posts
- PhotoPostForm: Publish photo posts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-24 01:56:26 +01:00

158 lines
3.3 KiB
Svelte

<script lang="ts">
import Button from './Button.svelte'
import DropdownMenuContainer from './DropdownMenuContainer.svelte'
import DropdownItem from './DropdownItem.svelte'
interface Props {
currentStatus: string
onStatusChange: (status: string) => void
disabled?: boolean
isLoading?: boolean
primaryAction: {
label: string
status: string
}
dropdownActions?: Array<{
label: string
status: string
show?: boolean
}>
viewUrl?: string
}
let {
currentStatus,
onStatusChange,
disabled = false,
isLoading = false,
primaryAction,
dropdownActions = [],
viewUrl
}: Props = $props()
let isDropdownOpen = $state(false)
function handlePrimaryAction() {
onStatusChange(primaryAction.status)
isDropdownOpen = false
}
function handleDropdownAction(status: string) {
onStatusChange(status)
isDropdownOpen = false
}
function handleDropdownToggle(e: MouseEvent) {
e.stopPropagation()
isDropdownOpen = !isDropdownOpen
}
function handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement
if (!target.closest('.status-dropdown')) {
isDropdownOpen = false
}
}
$effect(() => {
if (isDropdownOpen) {
document.addEventListener('click', handleClickOutside)
return () => document.removeEventListener('click', handleClickOutside)
}
})
const availableActions = $derived(
dropdownActions.filter((action) => action.show !== false && action.status !== currentStatus)
)
const showViewInDropdown = $derived(viewUrl && currentStatus === 'published')
const hasDropdownContent = $derived(availableActions.length > 0 || showViewInDropdown)
</script>
<div class="status-dropdown">
<Button
variant="primary"
buttonSize="large"
onclick={handlePrimaryAction}
disabled={disabled || isLoading}
>
{primaryAction.label}
</Button>
{#if hasDropdownContent}
<Button
variant="ghost"
iconOnly
buttonSize="large"
onclick={handleDropdownToggle}
disabled={disabled || isLoading}
>
<svg slot="icon" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path
d="M3 4.5L6 7.5L9 4.5"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</Button>
{#if isDropdownOpen}
<DropdownMenuContainer>
{#each availableActions as action}
<DropdownItem onclick={() => handleDropdownAction(action.status)}>
{action.label}
</DropdownItem>
{/each}
{#if showViewInDropdown}
{#if availableActions.length > 0}
<div class="dropdown-divider"></div>
{/if}
<a
href={viewUrl}
target="_blank"
rel="noopener noreferrer"
class="dropdown-item view-link"
>
View on site
</a>
{/if}
</DropdownMenuContainer>
{/if}
{/if}
</div>
<style lang="scss">
@import '$styles/variables.scss';
.status-dropdown {
position: relative;
display: flex;
gap: $unit-half;
}
.dropdown-divider {
height: 1px;
background-color: $grey-80;
margin: $unit-half 0;
}
.dropdown-item.view-link {
display: block;
width: 100%;
padding: $unit-2x $unit-3x;
background: none;
border: none;
text-align: left;
font-size: 0.875rem;
color: $grey-20;
cursor: pointer;
transition: background-color 0.2s ease;
text-decoration: none;
&:hover {
background-color: $grey-95;
}
}
</style>