- 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>
158 lines
3.3 KiB
Svelte
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>
|