mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-23 17:26:43 +02:00
feat: add layout components to shared-ui (Tier 6)
Button enhancements: - Add 'outline' and 'success' variants - Add 'xl' size option New skeleton/loading components: - SkeletonBox: Base skeleton with shimmer animation (theme-aware) - SkeletonText: Multi-line text skeleton New feedback components: - EmptyState: Standardized empty state display with icon, title, message, and optional action buttons New confirmation components: - ConfirmationModal: Pre-styled confirmation dialog for delete/warning actions with 'danger', 'warning', and 'info' variants These components reduce duplication across apps and provide consistent UX patterns. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c87641f91b
commit
3c457f9c18
10 changed files with 413 additions and 7 deletions
126
packages/shared-ui/src/organisms/ConfirmationModal.svelte
Normal file
126
packages/shared-ui/src/organisms/ConfirmationModal.svelte
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* ConfirmationModal - Pre-styled confirmation dialog
|
||||
*
|
||||
* Used for delete confirmations, destructive actions, or any action
|
||||
* that requires user confirmation before proceeding.
|
||||
*
|
||||
* @example Delete confirmation
|
||||
* ```svelte
|
||||
* <ConfirmationModal
|
||||
* visible={showDeleteModal}
|
||||
* onClose={() => showDeleteModal = false}
|
||||
* onConfirm={handleDelete}
|
||||
* variant="danger"
|
||||
* title="Delete memo?"
|
||||
* message="This action cannot be undone."
|
||||
* confirmLabel="Delete"
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @example Warning confirmation
|
||||
* ```svelte
|
||||
* <ConfirmationModal
|
||||
* visible={showWarningModal}
|
||||
* onClose={() => showWarningModal = false}
|
||||
* onConfirm={handleProceed}
|
||||
* variant="warning"
|
||||
* title="Are you sure?"
|
||||
* message="You have unsaved changes that will be lost."
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { Icon } from '@manacore/shared-icons';
|
||||
import Modal from './Modal.svelte';
|
||||
import { Text, Button } from '../atoms';
|
||||
|
||||
type ConfirmationVariant = 'danger' | 'warning' | 'info';
|
||||
|
||||
interface Props {
|
||||
/** Whether the modal is visible */
|
||||
visible: boolean;
|
||||
/** Called when modal is closed (cancel or backdrop click) */
|
||||
onClose: () => void;
|
||||
/** Called when user confirms the action */
|
||||
onConfirm: () => void | Promise<void>;
|
||||
/** Visual variant */
|
||||
variant?: ConfirmationVariant;
|
||||
/** Modal title */
|
||||
title: string;
|
||||
/** Confirmation message */
|
||||
message?: string;
|
||||
/** Confirm button label */
|
||||
confirmLabel?: string;
|
||||
/** Cancel button label */
|
||||
cancelLabel?: string;
|
||||
/** Whether confirm action is in progress */
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
visible,
|
||||
onClose,
|
||||
onConfirm,
|
||||
variant = 'danger',
|
||||
title,
|
||||
message,
|
||||
confirmLabel = 'Confirm',
|
||||
cancelLabel = 'Cancel',
|
||||
loading = false
|
||||
}: Props = $props();
|
||||
|
||||
const variantConfig: Record<
|
||||
ConfirmationVariant,
|
||||
{ iconName: string; iconColor: string; buttonVariant: 'danger' | 'primary' }
|
||||
> = {
|
||||
danger: {
|
||||
iconName: 'alert-triangle',
|
||||
iconColor: 'text-red-500',
|
||||
buttonVariant: 'danger'
|
||||
},
|
||||
warning: {
|
||||
iconName: 'alert-circle',
|
||||
iconColor: 'text-yellow-500',
|
||||
buttonVariant: 'primary'
|
||||
},
|
||||
info: {
|
||||
iconName: 'info',
|
||||
iconColor: 'text-blue-500',
|
||||
buttonVariant: 'primary'
|
||||
}
|
||||
};
|
||||
|
||||
const config = $derived(variantConfig[variant]);
|
||||
|
||||
async function handleConfirm() {
|
||||
await onConfirm();
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal {visible} {onClose} {title} maxWidth="sm">
|
||||
{#snippet icon()}
|
||||
<div class="p-2 rounded-full bg-menu-hover">
|
||||
<Icon name={config.iconName} size={20} class={config.iconColor} />
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<div class="text-center py-2">
|
||||
{#if message}
|
||||
<Text variant="muted" class="leading-relaxed">
|
||||
{message}
|
||||
</Text>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#snippet footer()}
|
||||
<div class="flex gap-3 justify-end">
|
||||
<Button variant="ghost" onclick={onClose} disabled={loading}>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
<Button variant={config.buttonVariant} onclick={handleConfirm} {loading}>
|
||||
{confirmLabel}
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { default as Modal } from './Modal.svelte';
|
||||
export { default as ConfirmationModal } from './ConfirmationModal.svelte';
|
||||
export { default as AppSlider } from './AppSlider.svelte';
|
||||
export type { AppItem } from './AppSlider.svelte';
|
||||
export type { AppItem } from './AppSlider.types';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue