sikhaid-components

Use when creating, modifying, or understanding Svelte components in SikhAid project. Covers component naming conventions, file organization, component hierarchy, import patterns, and reusable UI patterns.

allowed_tools: Read, Edit, Write, Glob

$ 설치

git clone https://github.com/majiayu000/claude-skill-registry /tmp/claude-skill-registry && cp -r /tmp/claude-skill-registry/skills/data/sikhaid-components ~/.claude/skills/claude-skill-registry

// tip: Run this command in your terminal to install the skill


name: sikhaid-components description: Use when creating, modifying, or understanding Svelte components in SikhAid project. Covers component naming conventions, file organization, component hierarchy, import patterns, and reusable UI patterns. allowed-tools: Read, Edit, Write, Glob

SikhAid Component Patterns

Component Hierarchy

1. Layout Components

Purpose: Wrapper components that provide consistent structure across pages

  • src/routes/+layout.svelte - Root layout

    • Wraps all pages with Header and Footer
    • Conditionally hides Header/Footer on admin routes
    • Loads Razorpay script
    • Includes global styles
  • src/routes/admin/+layout.svelte - Admin nested layout

    • Adds admin-specific styling and structure
    • Inherits from root layout

2. Page Components

Purpose: Route-specific entry points

  • Located in src/routes/
  • Named +page.svelte
  • Compose feature and UI components
  • Example: src/routes/+page.svelte (home page)

3. Feature Components

Purpose: Reusable sections that combine multiple UI elements

Location: src/lib/components/

Examples:

  • Header.svelte - Navigation with dropdown menu, responsive mobile menu
  • Footer.svelte - Footer with quick links, admin login modal
  • Hero.svelte - Hero section with background image and CTA
  • CampaignCarousel.svelte - Featured campaigns with Swiper/carousel
  • PaymentForm.svelte - Complete donation form with Razorpay integration

Home-specific features:

  • Location: src/lib/components/home/
  • Examples: ImpactCounterSection.svelte, MissionSection.svelte

Admin-specific features:

  • Location: src/lib/components/admin/
  • Examples: SubmissionModal.svelte

4. UI Components

Purpose: Small, highly reusable elements

  • Buttons, inputs, cards, modals
  • Often accept props for customization
  • Example: Modal components, form inputs with validation

Naming Conventions

Component Files

  • Format: PascalCase
  • Pattern: [Descriptor][Type].svelte
  • Examples:
    • PaymentForm.svelte - Form for payments
    • CampaignCarousel.svelte - Carousel for campaigns
    • ImpactCounterSection.svelte - Section with impact counters
    • SubmissionModal.svelte - Modal for form submissions

Component Organization

src/lib/components/
├── Header.svelte           # Global components at root
├── Footer.svelte
├── PaymentForm.svelte
├── Hero.svelte
├── CampaignCarousel.svelte
├── home/                   # Home page specific
│   ├── ImpactCounterSection.svelte
│   ├── MissionSection.svelte
│   └── ...
└── admin/                  # Admin specific
    ├── SubmissionModal.svelte
    └── ...

Component Structure Pattern

Standard Component Template

<script lang="ts">
  // 1. Imports
  import { Icon } from '@iconify/svelte';
  import { storeName } from '$lib/stores/storeName';

  // 2. Props (if any)
  export let propName: string;
  export let optionalProp: number = 0;

  // 3. Local state
  let localVariable = '';
  let isLoading = false;

  // 4. Reactive declarations
  $: computedValue = propName.toUpperCase();

  // 5. Functions
  async function handleSubmit() {
    // Event handler logic
  }
</script>

<!-- 6. Markup -->
<div class="container">
  <!-- Component content -->
</div>

<!-- 7. Component-specific styles (if needed) -->
<style>
  .custom-class {
    /* Scoped styles */
  }
</style>

Import Patterns

Importing Components

// From lib/components
import Header from '$lib/components/Header.svelte';
import PaymentForm from '$lib/components/PaymentForm.svelte';

// From subdirectories
import ImpactCounter from '$lib/components/home/ImpactCounterSection.svelte';
import SubmissionModal from '$lib/components/admin/SubmissionModal.svelte';

Importing Stores

import { selectedAmount, setDonationAmount } from '$lib/stores/donation';
import { contactSubmissions } from '$lib/stores/contact';

Importing Types

import type { Campaign } from '$lib/types/campaign';
import type { ContactSubmission } from '$lib/stores/contact';

Importing Data

import { campaigns } from '$lib/data/campaigns';

Importing Icons

import { Icon } from '@iconify/svelte';

// Usage:
<Icon icon="mdi:heart" />
<Icon icon="mdi:email" />

Common Component Patterns

1. Form Component Pattern

Example: PaymentForm.svelte

Key Features:

  • Two-way binding: bind:value={formData.field}
  • Validation on submit
  • Loading states: isSubmitting
  • Success/error messages
  • Prevent default: on:submit|preventDefault={handleSubmit}
<script lang="ts">
  let formData = { name: '', email: '', phone: '' };
  let isSubmitting = false;
  let errorMessage = '';

  async function handleSubmit() {
    if (!validateForm()) return;

    isSubmitting = true;
    try {
      // Submit logic
      await addToFirestore(formData);
    } catch (error) {
      errorMessage = 'Submission failed';
    } finally {
      isSubmitting = false;
    }
  }
</script>

<form on:submit|preventDefault={handleSubmit}>
  <input type="text" bind:value={formData.name} required />
  <button type="submit" disabled={isSubmitting}>
    {isSubmitting ? 'Submitting...' : 'Submit'}
  </button>
</form>

2. Navigation Component Pattern

Example: Header.svelte

Key Features:

  • Dropdown menus with state
  • Mobile responsive menu toggle
  • Active route highlighting with $page.url.pathname
  • Conditional rendering
<script lang="ts">
  import { page } from '$app/stores';

  let isMenuOpen = false;
  let isDropdownOpen = false;

  $: currentPath = $page.url.pathname;
  $: isActive = (path: string) => currentPath === path;
</script>

<nav>
  <a href="/about" class:active={isActive('/about')}>About</a>

  <button on:click={() => isMenuOpen = !isMenuOpen}>
    Menu
  </button>
</nav>

3. Modal Component Pattern

Example: SubmissionModal.svelte in admin

Key Features:

  • Show/hide state
  • Backdrop click to close
  • Slot for content
  • Escape key handling
<script lang="ts">
  export let isOpen = false;
  export let onClose: () => void;

  function handleBackdropClick(event: MouseEvent) {
    if (event.target === event.currentTarget) {
      onClose();
    }
  }
</script>

{#if isOpen}
  <div class="modal-backdrop" on:click={handleBackdropClick}>
    <div class="modal-content">
      <slot />
      <button on:click={onClose}>Close</button>
    </div>
  </div>
{/if}

4. Data Display Component Pattern

Example: Campaign cards, blog cards

Key Features:

  • Props for data
  • Click handlers
  • Conditional rendering with {#if}
  • Iteration with {#each}
<script lang="ts">
  import type { Campaign } from '$lib/types/campaign';
  import { campaigns } from '$lib/data/campaigns';

  function handleCampaignClick(slug: string) {
    goto(`/campaigns/${slug}`);
  }
</script>

<div class="grid">
  {#each campaigns as campaign}
    <div class="card" on:click={() => handleCampaignClick(campaign.slug)}>
      <h3>{campaign.title}</h3>
      <p>{campaign.shortDescription}</p>
      {#if campaign.status === 'ongoing'}
        <span class="badge">Active</span>
      {/if}
    </div>
  {/each}
</div>

Reactivity Patterns

Store Subscriptions

<script lang="ts">
  import { selectedAmount } from '$lib/stores/donation';

  // Auto-subscribes with $ prefix
  $: amount = $selectedAmount;
</script>

<div>Selected: ₹{$selectedAmount}</div>

Reactive Declarations

<script lang="ts">
  let count = 0;

  // Recomputes when count changes
  $: doubled = count * 2;

  // Reactive statement
  $: if (count > 10) {
    console.log('Count exceeded 10!');
  }
</script>

Reactive Bindings

<script lang="ts">
  let value = '';

  $: valueLength = value.length;
</script>

<input bind:value />
<p>Length: {valueLength}</p>

Event Handling Patterns

Standard Events

<button on:click={handleClick}>Click</button>
<form on:submit|preventDefault={handleSubmit}>...</form>
<input on:input={handleInput} on:blur={handleBlur} />

Event Modifiers

  • preventDefault - Prevent default behavior
  • stopPropagation - Stop event bubbling
  • once - Fire handler only once
  • self - Only fire if event.target is the element itself
<form on:submit|preventDefault={handleSubmit}>
<div on:click|self={handleBackdrop}>

Custom Events (Component Communication)

<!-- Child component -->
<script lang="ts">
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();

  function emitEvent() {
    dispatch('custom-event', { data: 'value' });
  }
</script>

<!-- Parent component -->
<ChildComponent on:custom-event={handleCustomEvent} />

Styling Patterns

Tailwind Classes (Primary Method)

<div class="container mx-auto px-4 py-8">
  <h1 class="text-3xl md:text-5xl font-bold text-navy-custom">
    Title
  </h1>
</div>

Conditional Classes

<div class="btn" class:active={isActive} class:disabled={isDisabled}>
  Button
</div>

Component-Scoped Styles (When Needed)

<style>
  .custom-animation {
    animation: fade-in 0.6s ease-out;
  }

  /* Scoped to this component only */
  h1 {
    color: var(--navy);
  }
</style>

Component Communication

Parent → Child (Props)

<!-- Parent -->
<ChildComponent title="Hello" count={5} />

<!-- Child -->
<script lang="ts">
  export let title: string;
  export let count: number;
</script>

Child → Parent (Events)

<!-- Child -->
<script lang="ts">
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();
</script>
<button on:click={() => dispatch('clicked', { data })}>Click</button>

<!-- Parent -->
<Child on:clicked={handleClick} />

Sibling Components (Stores)

<!-- Component A -->
<script lang="ts">
  import { selectedAmount } from '$lib/stores/donation';
  $selectedAmount = 1000;
</script>

<!-- Component B -->
<script lang="ts">
  import { selectedAmount } from '$lib/stores/donation';
</script>
<div>Amount: {$selectedAmount}</div>

Accessibility Patterns

Semantic HTML

<nav>...</nav>
<main>...</main>
<section>...</section>
<form>...</form>

ARIA Labels

<button aria-label="Close menu" on:click={closeMenu}>
  <Icon icon="mdi:close" />
</button>

<input
  type="email"
  aria-label="Email address"
  aria-required="true"
/>

Form Labels

<label for="name">Full Name *</label>
<input id="name" name="name" type="text" required />

When to Use This Skill

  • Creating new Svelte components
  • Refactoring existing components
  • Understanding component structure
  • Implementing forms, navigation, or modals
  • Setting up component communication
  • Adding interactivity or reactivity

Related Skills

  • sikhaid-styling - Tailwind patterns and design system
  • sikhaid-forms - Form-specific patterns and validation
  • sikhaid-data - Store usage and data fetching