Agent skill

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.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/sikhaid-components

SKILL.md

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

svelte
<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

svelte
// 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

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

Importing Types

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

Importing Data

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

Importing Icons

svelte
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}
svelte
<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
svelte
<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
svelte
<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}
svelte
<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

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

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

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

Reactive Declarations

svelte
<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

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

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

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

Event Handling Patterns

Standard Events

svelte
<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
svelte
<form on:submit|preventDefault={handleSubmit}>
<div on:click|self={handleBackdrop}>

Custom Events (Component Communication)

svelte
<!-- 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)

svelte
<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

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

Component-Scoped Styles (When Needed)

svelte
<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)

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

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

Child → Parent (Events)

svelte
<!-- 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)

svelte
<!-- 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

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

ARIA Labels

svelte
<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

svelte
<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

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results