Files
Ready-to-Planner-Tour/.agents/skills/react-component/SKILL.md
T
2026-08-27 19:45:15 +07:00

3.8 KiB

name, description
name description
react-component Panduan membuat React component untuk Tour Planner App. Gunakan skill ini ketika membuat komponen baru, baik UI umum maupun komponen spesifik fitur (trip, schedule, packing, budget).

Skill: React Component — Tour Planner App

Aturan Dasar

Semua komponen HARUS mengikuti pola berikut:

  • Functional component dengan arrow function
  • Props didestruktur di parameter
  • Menggunakan CSS variables dari design system (lihat src/index.css)
  • Menggunakan Framer Motion untuk animasi
  • Menggunakan Lucide React untuk icon

Template Dasar Komponen

import { motion } from 'framer-motion';
import { IconName } from 'lucide-react';
import styles from './ComponentName.module.css'; // opsional

const ComponentName = ({ prop1, prop2, onAction }) => {
  return (
    <motion.div
      className="component-name"
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.3 }}
    >
      {/* content */}
    </motion.div>
  );
};

export default ComponentName;

Komponen UI yang Tersedia

Button

<Button variant="primary|secondary|ghost|danger" size="sm|md|lg" icon={IconComponent} onClick={fn}>
  Label
</Button>

Card

<Card glassmorphism hoverable>
  {/* content */}
</Card>

Variants: glassmorphism (default), elevated, outlined

Modal

<Modal isOpen={bool} onClose={fn} title="Judul Modal">
  {/* content */}
</Modal>

Badge

<Badge variant="primary|success|warning|danger">{text}</Badge>

ProgressBar

<ProgressBar value={0-100} label="Teks" showPercent />

Animasi Standar

// Fade in dari bawah (card, item list)
const fadeInUp = {
  initial: { opacity: 0, y: 20 },
  animate: { opacity: 1, y: 0 },
  transition: { duration: 0.3 }
};

// Stagger anak-anak (list items)
const containerVariants = {
  animate: { transition: { staggerChildren: 0.08 } }
};

// Scale on hover (interactive card)
const hoverScale = {
  whileHover: { scale: 1.02 },
  whileTap: { scale: 0.98 }
};

CSS Classes Tersedia (dari index.css)

.glass          — glassmorphism card
.glass-dark     — glassmorphism gelap
.btn-primary    — tombol primary
.btn-secondary  — tombol secondary
.btn-ghost      — tombol ghost
.text-gradient  — teks dengan gradient
.badge          — badge dasar
.input-field    — input form
.section-title  — heading section

File Baru Selalu di Folder yang Tepat

Tipe Lokasi
Layout component src/components/layout/
UI generic src/components/ui/
Trip feature src/components/trip/
Schedule feature src/components/schedule/
Packing feature src/components/packing/
Budget feature src/components/budget/
Full page src/pages/

Contoh: Membuat Activity Item

// src/components/schedule/ActivityItem.jsx
import { motion } from 'framer-motion';
import { Clock, MapPin, GripVertical, Trash2 } from 'lucide-react';

const ActivityItem = ({ activity, onDelete, dragHandleProps }) => {
  return (
    <motion.div
      className="activity-item"
      layout
      initial={{ opacity: 0, x: -20 }}
      animate={{ opacity: 1, x: 0 }}
      exit={{ opacity: 0, x: 20 }}
    >
      <div className="activity-drag-handle" {...dragHandleProps}>
        <GripVertical size={16} />
      </div>
      <div className="activity-time">
        <Clock size={14} />
        <span>{activity.time}</span>
      </div>
      <div className="activity-content">
        <h4>{activity.name}</h4>
        <div className="activity-location">
          <MapPin size={12} />
          <span>{activity.location}</span>
        </div>
      </div>
      <button onClick={() => onDelete(activity.id)}>
        <Trash2 size={16} />
      </button>
    </motion.div>
  );
};

export default ActivityItem;