本文へ移動
cccskills
無料GitHub で公開

component-api-scaffolding

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

インストール方法を見る

含まれるファイル(1)

  • SKILL.md7.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

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)

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

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

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

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.

日本語の概要は準備中です。原文の説明を表示しています。

PP-Namias/Portfolio22026年10月7日 更新

PP-Namias のスキルをすべて見る

このスキルの問題を報告する