diff --git a/frontend-modern/src/components/Dashboard/GuestRow.tsx b/frontend-modern/src/components/Dashboard/GuestRow.tsx index e8ce814..af500a9 100644 --- a/frontend-modern/src/components/Dashboard/GuestRow.tsx +++ b/frontend-modern/src/components/Dashboard/GuestRow.tsx @@ -61,6 +61,7 @@ export function GuestRow(props: GuestRowProps) { const isEditingUrl = createMemo(() => currentlyEditingGuestId() === guestId()); const [customUrl, setCustomUrl] = createSignal(props.customUrl); + const [shouldAnimateIcon, setShouldAnimateIcon] = createSignal(false); const [drawerOpen, setDrawerOpen] = createSignal(drawerState.get(initialGuestId) ?? false); const editingUrlValue = createMemo(() => { editingValuesVersion(); // Subscribe to changes @@ -82,7 +83,17 @@ export function GuestRow(props: GuestRowProps) { createEffect(() => { // Don't update customUrl from props if this guest is currently being edited if (currentlyEditingGuestId() !== guestId()) { - setCustomUrl(props.customUrl); + const prevUrl = customUrl(); + const newUrl = props.customUrl; + + // Only animate when URL transitions from empty to having a value + if (!prevUrl && newUrl) { + setShouldAnimateIcon(true); + // Remove animation class after it completes + setTimeout(() => setShouldAnimateIcon(false), 200); + } + + setCustomUrl(newUrl); } }); @@ -250,6 +261,14 @@ export function GuestRow(props: GuestRowProps) { try { await GuestMetadataAPI.updateMetadata(guestId(), { customUrl: newUrl }); + + // Animate if transitioning from no URL to having a URL + const hadUrl = !!customUrl(); + if (!hadUrl && newUrl) { + setShouldAnimateIcon(true); + setTimeout(() => setShouldAnimateIcon(false), 200); + } + setCustomUrl(newUrl || undefined); // Notify parent to update metadata @@ -430,7 +449,7 @@ export function GuestRow(props: GuestRowProps) { href={customUrl()} target="_blank" rel="noopener noreferrer" - class="flex-shrink-0 text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors" + class={`flex-shrink-0 text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 transition-colors ${shouldAnimateIcon() ? 'animate-fadeIn' : ''}`} title="Open in new tab" onClick={(event) => event.stopPropagation()} > diff --git a/frontend-modern/tailwind.config.js b/frontend-modern/tailwind.config.js index 2e56f29..891b93e 100644 --- a/frontend-modern/tailwind.config.js +++ b/frontend-modern/tailwind.config.js @@ -13,6 +13,13 @@ export default { }, animation: { 'spin-slow': 'spin 2s linear infinite', + 'fadeIn': 'fadeIn 0.2s ease-in', + }, + keyframes: { + fadeIn: { + '0%': { opacity: '0' }, + '100%': { opacity: '1' }, + } } }, },