jedmund-svelte/SVG_ANALYSIS_REPORT.md
Justin Edmund 1c38dc87e3 fix: drag handle actions now affect the correct block
- Added menuNode state to capture the node position when menu opens
- Updated all action functions to use menuNode instead of currentNode
- This ensures drag handle actions (Turn into, Delete, etc.) always affect the block where the handle was clicked, not where the mouse currently hovers
- Also formatted code with prettier

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-26 10:33:27 -04:00

5.4 KiB

SVG Usage Analysis Report

Summary

This analysis examines SVG usage patterns in the Svelte 5 codebase to identify optimization opportunities, inconsistencies, and unused assets.

Key Findings

1. Inline SVGs vs. Imported SVGs

Inline SVGs Found:

  • Close/X buttons: Found in 7+ components with identical SVG code

    • admin/Modal.svelte
    • admin/UnifiedMediaModal.svelte
    • admin/MediaInput.svelte
    • admin/AlbumSelectorModal.svelte
    • admin/GalleryManager.svelte
    • admin/MediaDetailsModal.svelte
    • Lightbox.svelte
  • Loading spinners: Found in 2+ components

    • admin/Button.svelte
    • admin/ImageUploader.svelte
    • admin/GalleryUploader.svelte
  • Navigation arrows: Found in PhotoLightbox.svelte

  • Lock icon: Found in LabCard.svelte

  • External link icon: Found in LabCard.svelte

2. SVG Import Patterns

Consistent patterns using aliases:

// Good - using $icons alias import ArrowLeft from '$icons/arrow-left.svg' import ChevronDownIcon
from '$icons/chevron-down.svg' // Component imports with ?component import PhotosIcon from
'$icons/photos.svg?component' import ViewSingleIcon from '$icons/view-single.svg?component' // Raw
imports import ChevronDownIcon from '$icons/chevron-down.svg?raw'

3. Unused SVG Files

Unused icons in /src/assets/icons/:

  • dashboard.svg
  • metadata.svg

Unused illustrations in /src/assets/illos/:

  • jedmund-blink.svg
  • jedmund-headphones.svg
  • jedmund-listening-downbeat.svg
  • jedmund-listening.svg
  • jedmund-open.svg
  • jedmund-signing-downbeat.svg
  • jedmund-singing.svg
  • logo-figma.svg
  • logo-maitsu.svg
  • logo-pinterest.svg
  • logo-slack.svg

4. Duplicate SVG Definitions

Close/X Button SVG (appears 7+ times):

<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>

Loading Spinner SVG (appears 3+ times):

<svg class="spinner" width="24" height="24" viewBox="0 0 24 24">
  <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" stroke-dasharray="25" stroke-dashoffset="25" stroke-linecap="round">
    <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>
  </circle>
</svg>

5. SVGs That Could Be Componentized

  1. Close Button: Used across multiple modals and components
  2. Loading Spinner: Used in buttons and upload components
  3. Navigation Arrows: Used in lightbox and potentially other navigation
  4. Status Icons: Lock, external link, eye icons in LabCard

Recommendations

1. Create Reusable Icon Components

Option A: Create individual icon components

<!-- $lib/components/icons/CloseIcon.svelte -->
<script>
	let { size = 24, class: className = '' } = $props()
</script>

<svg width={size} height={size} viewBox="0 0 24 24" fill="none" class={className}>
	<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>

Option B: Create an Icon component with name prop

<!-- $lib/components/Icon.svelte -->
<script>
	import CloseIcon from '$icons/close.svg'
	import LoadingIcon from '$icons/loading.svg'
	// ... other imports

	let { name, size = 24, class: className = '' } = $props()

	const icons = {
		close: CloseIcon,
		loading: LoadingIcon
		// ... other icons
	}

	const IconComponent = $derived(icons[name])
</script>

{#if IconComponent}
	<IconComponent {size} class={className} />
{/if}

2. Extract Inline SVGs to Files

Create new SVG files for commonly used inline SVGs:

  • /src/assets/icons/close.svg
  • /src/assets/icons/loading.svg
  • /src/assets/icons/external-link.svg
  • /src/assets/icons/lock.svg
  • /src/assets/icons/eye-off.svg

3. Clean Up Unused Assets

Remove the following unused files to reduce bundle size:

  • All unused illustration files (11 files)
  • Unused icon files (2 files)

4. Standardize Import Methods

Establish a consistent pattern:

  • Use ?component for SVGs used as Svelte components
  • Use direct imports for SVGs used as images
  • Avoid ?raw imports unless necessary

5. Create a Loading Component

<!-- $lib/components/LoadingSpinner.svelte -->
<script>
	let { size = 24, class: className = '' } = $props()
</script>

<svg class="loading-spinner {className}" width={size} height={size} viewBox="0 0 24 24">
	<circle
		cx="12"
		cy="12"
		r="10"
		stroke="currentColor"
		stroke-width="2"
		fill="none"
		stroke-dasharray="25"
		stroke-dashoffset="25"
		stroke-linecap="round"
	>
		<animateTransform
			attributeName="transform"
			type="rotate"
			from="0 12 12"
			to="360 12 12"
			dur="1s"
			repeatCount="indefinite"
		/>
	</circle>
</svg>

<style>
	.loading-spinner {
		color: currentColor;
	}
</style>

Benefits of These Changes

  1. Reduced code duplication: Eliminate 20+ duplicate SVG definitions
  2. Smaller bundle size: Remove 13 unused SVG files
  3. Better maintainability: Centralized icon management
  4. Consistent styling: Easier to apply consistent styles to all icons
  5. Type safety: With proper component props
  6. Performance: Less inline SVG parsing, better caching

Implementation Priority

  1. High Priority: Extract and componentize duplicate inline SVGs (close button, loading spinner)
  2. Medium Priority: Remove unused SVG files
  3. Low Priority: Standardize all import patterns and create comprehensive icon system