Skip to content
cccskills
FreePublished on GitHub

component-api-scaffolding

Create new React components, API routes, SWR hooks, and context providers following repo patterns.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md7.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Component & API Scaffolding

When to use this skill

  • Creating a new UI component
  • Adding a new API route
  • Creating a custom SWR hook
  • Adding a new context provider
  • Creating a new page or section
  • Adding a new modal

Patterns to follow

1. UI component template

Location: src/components/ui/

'use client';

import { useState } from 'react';

interface MyComponentProps {
  title: string;
  onAction: () => void;
}

export function MyComponent({ title, onAction }: Readonly<MyComponentProps>) {
  const [state, setState] = useState('');

  return (
    <div className="rounded-xl border border-border-light dark:border-border-dark bg-white dark:bg-card-bg-dark p-5">
      <h3 className="text-sm font-semibold text-text-primary-light dark:text-text-primary-dark">
        {title}
      </h3>
      <button
        type="button"
        onClick={onAction}
        className="mt-3 inline-flex items-center gap-2 rounded-lg bg-accent-pink px-4 py-2 text-sm font-medium text-white hover:bg-accent-pink-hover dark:hover:bg-accent-pink-hover-dark transition-colors"
      >
        Action
      </button>
    </div>
  );
}

Component conventions:

  • File name: PascalCase.tsx (e.g., MyComponent.tsx)
  • Export: Named export (export function MyComponent)
  • Props: interface with Readonly<> wrapper
  • Styling: Tailwind utility classes with theme tokens
  • Dark mode: Always include -light / -dark suffix pairs
  • Accessibility: aria-label, role, semantic HTML
  • Client components: Add 'use client' at top

2. Section component template

Location: src/components/sections/

'use client';

import { useCmsContent } from '@/hooks/useCmsContent';

export function MySection() {
  const { profile } = useCmsContent();

  return (
    <section className="py-16 sm:py-20" id="my-section">
      <div className="mx-auto max-w-6xl px-4 sm:px-6">
        <h2 className="text-2xl font-bold text-text-primary-light dark:text-text-primary-dark">
          Section Title
        </h2>
        {/* Content */}
      </div>
    </section>
  );
}

Section conventions:

  • Location: src/components/sections/
  • Always has id for navigation
  • Uses max-w-6xl mx-auto px-4 sm:px-6 container
  • Vertical padding: py-16 sm:py-20
  • Data from useCmsContent() hook

3. API route template

Location: src/app/api/<route>/route.ts

import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  try {
    // Logic here
    return NextResponse.json({ data: result });
  } catch (error) {
    console.error('[API Error]', error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    // Validate body
    // Process
    return NextResponse.json({ success: true }, { status: 201 });
  } catch (error) {
    console.error('[API Error]', error);
    return NextResponse.json(
      { error: 'Internal server error' },
      { status: 500 }
    );
  }
}

API route conventions:

  • File: route.ts (not page.ts)
  • Methods: Named exports (GET, POST, PUT, DELETE)
  • Error handling: try/catch with console.error
  • Logging prefix: [API Name] for easy filtering
  • Response: Always NextResponse.json()
  • Validation: Validate before processing

4. SWR hook template

Location: src/hooks/

import useSWR from 'swr';

const fetcher = (url: string) => fetch(url).then((res) => res.json());

export function useMyData() {
  const { data, error, isLoading } = useSWR('/api/my-data', fetcher, {
    revalidateOnFocus: true,
    revalidateOnReconnect: true,
    dedupingInterval: 60000,
  });

  return {
    data: data ?? null,
    error: error ?? null,
    isLoading,
  };
}

SWR conventions:

  • File: use<Name>.ts (e.g., useProjects.ts)
  • Always provide default values (?? null)
  • Set dedupingInterval to prevent excessive requests
  • Use with SWRConfig in tests for isolation

5. Context provider template

Location: src/hooks/ (for small state) or src/contexts/ (for complex state)

'use client';

import { createContext, useCallback, useContext, useMemo, useState } from 'react';

type MyContextValue = {
  value: string;
  setValue: (v: string) => void;
};

const MyContext = createContext<MyContextValue | null>(null);

export function MyProvider({ children }: { children: React.ReactNode }) {
  const [value, setValue] = useState('');

  const contextValue = useMemo(() => ({ value, setValue }), [value]);

  return (
    <MyContext.Provider value={contextValue}>
      {children}
    </MyContext.Provider>
  );
}

export function useMyContext() {
  const context = useContext(MyContext);
  if (!context) throw new Error('useMyContext must be used within MyProvider');
  return context;
}

6. Modal template

Location: src/components/ui/

Modals use the base <Modal> component:

'use client';

import { Modal } from './Modal';

interface MyModalProps {
  open: boolean;
  onClose: () => void;
}

export function MyModal({ open, onClose }: Readonly<MyModalProps>) {
  return (
    <Modal open={open} onClose={onClose} title="My Modal">
      <div className="px-5 py-6">
        {/* Modal content */}
      </div>
    </Modal>
  );
}

Modal conventions:

  • Register in src/hooks/useModal.tsx (add to ModalName type)
  • Add to ModalProvider component
  • Use fullScreen prop for content-heavy modals
  • Always include title for accessibility

7. Page template

Location: src/app/<route>/page.tsx

import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Page Title | PP Namias',
  description: 'Page description',
};

export default function MyPage() {
  return (
    <main>
      {/* Page content */}
    </main>
  );
}

Page conventions:

  • Export metadata for SEO
  • Use <main> as root element
  • Pages are server components by default
  • Client components: wrap with 'use client' or use dynamic import

File organization

src/
  components/
    ui/           # Reusable UI components (Button, Modal, Card)
    sections/     # Page sections (Hero, Projects, Contact)
    layout/       # Layout components (Header, Footer, Navigation)
  hooks/          # Custom React hooks
  contexts/       # React context providers
  lib/            # Utilities, constants, helpers
  app/            # Next.js App Router pages and API routes
  __tests__/      # Test files (mirrors src/ structure)

Naming conventions

TypeConventionExample
Component filePascalCaseContactModal.tsx
Hook filecamelCase, use prefixuseCmsContent.ts
Utility filecamelCasebuildEmailLinks.ts
Constant filecamelCaseconstants.ts
Type filecamelCasetypes.ts
Test file*.test.tsxContactModal.test.tsx
API routeroute.tssrc/app/api/chat/route.ts

Common mistakes

  • Creating a component without TypeScript types
  • Forgetting 'use client' on components that use hooks
  • Not including dark mode variants in Tailwind classes
  • Using <div onClick> instead of <button onClick> (accessibility)
  • Not wrapping props in Readonly<>
  • Forgetting to register new modals in useModal.tsx

Delivery checks

  • Component has TypeScript types
  • Component works in both light and dark mode
  • Component is keyboard navigable
  • Component has proper ARIA attributes
  • Component follows existing naming conventions
  • No new warnings in console
  • TypeScript passes (npx tsc --noEmit)
  • Lint passes (npm run lint)

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Audit and fix accessibility issues across the portfolio to ensure WCAG 2.1 AA compliance.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

Creates a new blog post document in the Sanity studio. Use when the user wants to write a blog post, publish an article, or schedule a future post.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

Creates a new certification document in the Sanity studio. Use when the user wants to add a credential, certificate, or professional accreditation to the Certifications collection.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

Adds a new skill MD file to the studio's skills collection. Use when the user wants to author a new step-by-step recipe for the studio's in-app Skills tool or the .agents mirror.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

Creates a new project document in the Sanity studio. Use when the user wants to add a new portfolio project, a case study, or a work sample to the Projects collection.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

Creates a new experience document in the Sanity studio. Use when the user wants to add a job, role, internship, or work history entry to the Experience collection.

The English summary is being prepared. Showing the original description.

PP-Namias/Portfolio2Updated Oct 16, 2026

See all skills by PP-Namias

Report a problem with this skill