chore: Delete various UI components, form elements, and associated example/showcase pages from the UI package and web app.
This commit is contained in:
@@ -1,9 +1,3 @@
|
||||
import Showcase from './showcase/showcase';
|
||||
|
||||
export default function ExamplePage() {
|
||||
return (
|
||||
<div>
|
||||
<Showcase />
|
||||
</div>
|
||||
);
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
import { Checkbox, InputStatusType } from '@repo/ui';
|
||||
|
||||
interface CheckboxShowcaseProps {
|
||||
status?: InputStatusType;
|
||||
}
|
||||
|
||||
export default function CheckboxShowcase({ status: overrideStatus }: CheckboxShowcaseProps) {
|
||||
/**
|
||||
* Helper untuk menentukan status.
|
||||
* Jika overrideStatus diberikan (dari props pemanggil), maka gunakan itu.
|
||||
* Jika tidak, gunakan status lokal yang didefinisikan di matrix.
|
||||
*/
|
||||
const resolveStatus = (localStatus: InputStatusType): InputStatusType => {
|
||||
return overrideStatus && overrideStatus !== 'default' ? overrideStatus : localStatus;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-12">
|
||||
{/* 1. VARIANT COMPARISON */}
|
||||
<section>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-bold text-gray-800">Checkbox Variants</h2>
|
||||
<p className="text-sm text-gray-500">Dua tipe visual utama: Outlined (default) dan Filled.</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="p-4 border border-gray-100 rounded-xl bg-gray-50/50">
|
||||
<span className="block mb-3 text-xs font-bold text-gray-400 uppercase">Outlined (Default)</span>
|
||||
<div className="flex gap-4">
|
||||
<Checkbox status={overrideStatus} label="Standard" defaultChecked />
|
||||
<Checkbox status={overrideStatus} label="Unchecked" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 border border-gray-100 rounded-xl bg-gray-50/50">
|
||||
<span className="block mb-3 text-xs font-bold text-gray-400 uppercase">Filled</span>
|
||||
<div className="flex gap-4">
|
||||
<Checkbox status={overrideStatus} label="Standard" defaultChecked />
|
||||
<Checkbox status={overrideStatus} label="Unchecked" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 2. STATUS MATRIX (OVERRIDABLE) */}
|
||||
<section>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-bold text-gray-800">Status Matrix</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Warna akan berubah otomatis berdasarkan status (Error, Warning, Success, Info).
|
||||
{overrideStatus && (
|
||||
<span className="text-brand-600 font-medium"> [Overridden by Prop: {overrideStatus}]</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
{/* Outlined Status */}
|
||||
<div className="flex flex-wrap gap-6 p-6 border border-gray-200 rounded-xl">
|
||||
<Checkbox status={resolveStatus('default')} label={resolveStatus('default')} defaultChecked />
|
||||
<Checkbox status={resolveStatus('error')} label={resolveStatus('error')} defaultChecked />
|
||||
<Checkbox status={resolveStatus('warning')} label={resolveStatus('warning')} defaultChecked />
|
||||
<Checkbox status={resolveStatus('success')} label={resolveStatus('success')} defaultChecked />
|
||||
<Checkbox status={resolveStatus('info')} label={resolveStatus('info')} defaultChecked />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 3. CONTENT & LAYOUT FEATURES */}
|
||||
<section>
|
||||
<div className="mb-4">
|
||||
<h2 className="text-lg font-bold text-gray-800">Rich Content & States</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Mendukung konten kompleks di dalam label dan berbagai state interaksi.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{/* Column A: Complex Labels */}
|
||||
<div className="space-y-4">
|
||||
<span className="text-xs font-bold text-gray-400 uppercase">Label Variations</span>
|
||||
<Checkbox status={overrideStatus}>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium text-gray-900 leading-tight">Terms of Service</span>
|
||||
<span className="text-xs text-gray-500 mt-1">I have read and agree to the privacy policy.</span>
|
||||
</div>
|
||||
</Checkbox>
|
||||
<Checkbox status={overrideStatus} label={<strong>Bold Label Text</strong>} />
|
||||
</div>
|
||||
|
||||
{/* Column B: Interactive States */}
|
||||
<div className="space-y-4">
|
||||
<span className="text-xs font-bold text-gray-400 uppercase">Disabled States</span>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Checkbox disabled label="Disabled Unchecked" />
|
||||
<Checkbox disabled defaultChecked label="Disabled Checked" />
|
||||
<Checkbox disabled label="Disabled Filled" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Column C: Edge Cases */}
|
||||
<div className="space-y-4">
|
||||
<span className="text-xs font-bold text-gray-400 uppercase">Layout Config</span>
|
||||
<div className="flex items-center gap-6">
|
||||
<Checkbox status={overrideStatus} />
|
||||
<span className="text-xs text-gray-400 italic font-mono bg-gray-100 px-2 py-1 rounded">
|
||||
No Label Prop
|
||||
</span>
|
||||
</div>
|
||||
<Checkbox status={overrideStatus}>
|
||||
<span className="flex items-center gap-2 text-brand-600 font-semibold">
|
||||
<span className="w-2 h-2 rounded-full bg-brand-500 animate-pulse" />
|
||||
Live Children Label
|
||||
</span>
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
import React from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
TimePicker,
|
||||
DatePicker,
|
||||
WeekPicker,
|
||||
MonthPicker,
|
||||
QuarterPicker,
|
||||
YearPicker,
|
||||
TimeRangePicker,
|
||||
DateRangePicker,
|
||||
WeekRangePicker,
|
||||
MonthRangePicker,
|
||||
QuarterRangePicker,
|
||||
YearRangePicker,
|
||||
InputStatusType,
|
||||
Calendar,
|
||||
} from '@repo/ui'; // Sesuaikan path
|
||||
import { DateUtils } from '@repo/utils';
|
||||
|
||||
// --- UI Helper Components ---
|
||||
const Section = ({
|
||||
title,
|
||||
description,
|
||||
children,
|
||||
}: {
|
||||
title: string;
|
||||
description?: string;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<section className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden mb-8">
|
||||
<div className="bg-gray-50 px-6 py-4 border-b border-gray-200">
|
||||
<h2 className="text-lg font-bold text-gray-800">{title}</h2>
|
||||
{description && <p className="text-sm text-gray-500 mt-1">{description}</p>}
|
||||
</div>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">{children}</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
const Card = ({ label, code, children }: { label: string; code?: string; children: React.ReactNode }) => (
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex justify-between items-baseline">
|
||||
<label className="text-sm font-semibold text-gray-700">{label}</label>
|
||||
{code && <span className="text-xs font-mono text-gray-400 bg-gray-100 px-1.5 py-0.5 rounded">{code}</span>}
|
||||
</div>
|
||||
<div className="w-full">{children}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default function PickerShowcase({ status }: { status: InputStatusType }) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-10 px-4 sm:px-6 lg:px-8 font-sans">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="mb-10 text-center">
|
||||
<h1 className="text-3xl font-extrabold text-gray-900 tracking-tight">Component Picker Showcase</h1>
|
||||
<p className="mt-2 text-lg text-gray-600">
|
||||
Fully typed, Tailwind-styled, and robust date manipulation components.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 1. Single Pickers */}
|
||||
<Section title="Single Pickers" description="Komponen untuk memilih satu nilai waktu spesifik.">
|
||||
<Card label="Time Picker" code="<TimePicker />">
|
||||
<TimePicker placeholder="Select time..." className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Date Picker" code="<DatePicker />">
|
||||
<DatePicker placeholder="Select date..." className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Week Picker" code="<WeekPicker />">
|
||||
<WeekPicker placeholder="Select week..." className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Month Picker" code="<MonthPicker />">
|
||||
<MonthPicker placeholder="Select month..." className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Quarter Picker" code="<QuarterPicker />">
|
||||
<QuarterPicker placeholder="Select quarter..." className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Year Picker" code="<YearPicker />">
|
||||
<YearPicker placeholder="Select year..." className="w-full" />
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
{/* 2. Range Pickers */}
|
||||
<Section title="Range Pickers" description="Komponen untuk memilih rentang waktu (Start - End).">
|
||||
<Card label="Time Range" code="<TimeRangePicker />">
|
||||
<TimeRangePicker className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Date Range" code="<DateRangePicker />">
|
||||
<DateRangePicker className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Week Range" code="<WeekRangePicker />">
|
||||
<WeekRangePicker className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Month Range" code="<MonthRangePicker />">
|
||||
<MonthRangePicker className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Quarter Range" code="<QuarterRangePicker />">
|
||||
<QuarterRangePicker className="w-full" />
|
||||
</Card>
|
||||
|
||||
<Card label="Year Range" code="<YearRangePicker />">
|
||||
<YearRangePicker className="w-full" />
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
{/* 3. Validation States */}
|
||||
<Section title="Validation & States" description="Visualisasi state error, warning, dan disabled.">
|
||||
<Card label="Error State" code={`status="${status}"`}>
|
||||
<DatePicker status={status} placeholder="Field is required" />
|
||||
<span className="text-xs text-red-500 mt-1 block">This field is required.</span>
|
||||
</Card>
|
||||
|
||||
<Card label="Warning State" code={`status="${status}"`}>
|
||||
<DatePicker status={status} placeholder="Check compatibility" defaultValue={dayjs()} />
|
||||
<span className="text-xs text-yellow-600 mt-1 block">Warning: Date is in the past.</span>
|
||||
</Card>
|
||||
|
||||
<Card label="Success State" code={`status="${status}"`}>
|
||||
<DatePicker status={status} defaultValue={dayjs()} />
|
||||
</Card>
|
||||
|
||||
<Card label="Disabled State" code="disabled">
|
||||
<div className="space-y-3">
|
||||
<DatePicker disabled placeholder="Cannot select" />
|
||||
<DateRangePicker disabled />
|
||||
</div>
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
{/* 4. Advanced & Customization */}
|
||||
<Section title="Advanced Features" description="Fitur lanjutan seperti format, waktu, dan presets.">
|
||||
<Card label="Date & Time" code="showTime">
|
||||
<DatePicker showTime format="YYYY-MM-DD HH:mm" placeholder="Select date & time" />
|
||||
</Card>
|
||||
|
||||
<Card label="Custom Format" code='format="DD/MM/YYYY"'>
|
||||
<DatePicker format="DD/MM/YYYY" placeholder="31/12/2025" />
|
||||
</Card>
|
||||
|
||||
<Card label="Range with Presets" code="presets={[...]}">
|
||||
<DateRangePicker
|
||||
presets={[
|
||||
{ label: 'Today', value: [dayjs(), dayjs()] },
|
||||
{ label: 'Next 7 Days', value: [dayjs(), dayjs().add(7, 'd')] },
|
||||
{ label: 'This Month', value: [dayjs().startOf('month'), dayjs().endOf('month')] },
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Card label="Read Only Input" code="inputReadOnly">
|
||||
<DatePicker inputReadOnly placeholder="Click to open (No typing)" />
|
||||
</Card>
|
||||
</Section>
|
||||
|
||||
{/* 5. STATIC CALENDAR (Picker Panel) */}
|
||||
<Section
|
||||
title="Static Calendar (Embedded)"
|
||||
description="Kalender statis yang langsung ditampilkan di halaman (bukan popup)."
|
||||
>
|
||||
{/* Basic Calendar */}
|
||||
<div className="col-span-1 md:col-span-1">
|
||||
<Card label="Standard Calendar" code="<Calendar />">
|
||||
<div className="border border-gray-200 rounded-lg shadow-sm bg-white inline-block overflow-hidden">
|
||||
<Calendar />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Calendar with State & Time */}
|
||||
<div className="col-span-1 md:col-span-2">
|
||||
<Card label="Calendar with Date & Time" code="<Calendar showTime />">
|
||||
<div className="flex flex-col sm:flex-row gap-6 items-start">
|
||||
{/* Visual Calendar */}
|
||||
<div className="border border-gray-200 rounded-lg shadow-sm bg-white inline-block overflow-hidden">
|
||||
<Calendar
|
||||
showTime
|
||||
onChange={(date) => {
|
||||
console.log('Selected:', new DateUtils(date as any).format('YYYY-MM-DD HH:mm:ss'));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Info Text */}
|
||||
<div className="p-4 bg-blue-50 text-blue-800 rounded-lg text-sm max-w-xs">
|
||||
<p className="font-semibold mb-2">Info:</p>
|
||||
<p>
|
||||
Komponen <code>Calendar</code> ini adalah <i>Panel</i> dasar. Sangat berguna untuk sidebar,
|
||||
dashboard widget, atau form yang membutuhkan pemilihan tanggal yang selalu terlihat.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</Section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import { Form, Input, InputPassword } from '@repo/ui';
|
||||
// --- 2. Main Showcase Component ---
|
||||
export default function FormShowcase() {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values: any) => {
|
||||
console.log('Success - Form Values:', values);
|
||||
alert(JSON.stringify(values, null, 2));
|
||||
};
|
||||
|
||||
const handleFinishFailed = (errorInfo: any) => {
|
||||
console.log('Failed:', errorInfo);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto mt-10 p-6 bg-white rounded-lg shadow-md border border-gray-200">
|
||||
<h2 className="text-xl font-bold mb-6 text-gray-800">Test Migrasi @rc-component/form</h2>
|
||||
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
onFinishFailed={handleFinishFailed}
|
||||
initialValues={{ role: 'user', agree: false }}
|
||||
>
|
||||
{/* Case 1: Text Input Biasa + Validasi Required */}
|
||||
<Form.Item name="username" label="Username" rules={[{ required: true, message: 'Username wajib diisi!' }]}>
|
||||
<Input placeholder="Masukkan username" />
|
||||
</Form.Item>
|
||||
|
||||
{/* Case 2: Email + Validasi Format */}
|
||||
<Form.Item
|
||||
name="email"
|
||||
label="Email"
|
||||
rules={[
|
||||
{ required: true, message: 'Email wajib diisi!' },
|
||||
{ type: 'email', message: 'Format email tidak valid!' },
|
||||
]}
|
||||
>
|
||||
<Input type="email" placeholder="contoh@email.com" />
|
||||
</Form.Item>
|
||||
|
||||
{/* Case 3: Password + Validasi Panjang */}
|
||||
<Form.Item
|
||||
name="password"
|
||||
label="Password"
|
||||
rules={[
|
||||
{ required: true, message: 'Password wajib diisi!' },
|
||||
{ min: 6, message: 'Password minimal 6 karakter!' },
|
||||
]}
|
||||
>
|
||||
<InputPassword placeholder="Masukkan password" />
|
||||
</Form.Item>
|
||||
|
||||
{/* Tombol Aksi */}
|
||||
<div className="flex gap-3 mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 font-medium transition"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => form.resetFields()}
|
||||
className="px-4 py-2 bg-gray-100 text-gray-700 rounded hover:bg-gray-200 font-medium transition"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
import { Input, InputPassword, InputNumber, InputCurrency, InputStatusType, TextArea } from '@repo/ui';
|
||||
|
||||
// Helper untuk label kolom
|
||||
const Label = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="text-xs font-bold text-gray-400 uppercase mb-3 tracking-wider">{children}</div>
|
||||
);
|
||||
|
||||
// Helper untuk prefix/suffix visual
|
||||
const Fix = ({ children }: { children: React.ReactNode }) => <span className="text-gray-400 text-sm">{children}</span>;
|
||||
|
||||
export default function InputShowCase({ status }: { status?: InputStatusType }) {
|
||||
return (
|
||||
<div className="p-8 rounded-2xl">
|
||||
{/* --- SECTION 1: OUTLINED VARIANT (DEFAULT) --- */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-lg font-bold text-gray-800 border-b pb-2">Outlined Variant (Standard)</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="space-y-3">
|
||||
<Label>Basic</Label>
|
||||
<Input status={status} placeholder="Input text..." />
|
||||
<InputPassword status={status} placeholder="Password..." />
|
||||
<InputNumber status={status} className="w-full" placeholder="Number..." />
|
||||
<InputCurrency status={status} className="w-full" placeholder="Currency..." />
|
||||
<TextArea status={status} placeholder="TextArea..." rows={2} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>With Prefix</Label>
|
||||
<Input status={status} prefix={<Fix>@</Fix>} placeholder="username" />
|
||||
<InputPassword status={status} prefix={<Fix>🔒</Fix>} placeholder="password" />
|
||||
<InputNumber status={status} prefix={<Fix>#</Fix>} className="w-full" placeholder="id" />
|
||||
<InputCurrency status={status} prefix="Rp " className="w-full" placeholder="price" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>With Suffix</Label>
|
||||
<Input status={status} suffix={<Fix>.com</Fix>} placeholder="website" />
|
||||
<InputPassword status={status} suffix={<Fix>Required</Fix>} placeholder="password" />
|
||||
<InputNumber status={status} suffix={<Fix>kg</Fix>} className="w-full" placeholder="weight" />
|
||||
<InputCurrency status={status} suffix={<Fix>nett</Fix>} className="w-full" placeholder="total" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<Label>Both & Special</Label>
|
||||
<Input status={status} prefix={<Fix>https://</Fix>} suffix={<Fix>.io</Fix>} placeholder="domain" />
|
||||
{/* Password Tanpa Toggle */}
|
||||
<InputPassword
|
||||
status={status}
|
||||
visibilityToggle={false}
|
||||
prefix={<Fix>🔑</Fix>}
|
||||
suffix={<Fix>?</Fix>}
|
||||
placeholder="Hidden Password"
|
||||
/>
|
||||
<InputNumber
|
||||
status={status}
|
||||
prefix={<Fix>+</Fix>}
|
||||
suffix={<Fix>%</Fix>}
|
||||
className="w-full"
|
||||
placeholder="tax"
|
||||
/>
|
||||
<InputCurrency
|
||||
status={status}
|
||||
prefix="USD "
|
||||
suffix={<Fix>cents</Fix>}
|
||||
className="w-full"
|
||||
placeholder="amount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* --- SECTION 2: Component States & Validation --- */}
|
||||
|
||||
<section className="space-y-6 mt-6">
|
||||
<h2 className="text-lg font-bold text-gray-800 border-b pb-2">Component States & Validation</h2>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{/* COLUMN 1: DISABLED (Semua Component) */}
|
||||
<div className="space-y-3">
|
||||
<Label>Disabled State</Label>
|
||||
<div className="p-4 bg-gray-50 rounded-lg space-y-3 border border-dashed border-gray-200">
|
||||
<Input disabled placeholder="Disabled Input" prefix={<Fix>🚫</Fix>} />
|
||||
<InputPassword disabled placeholder="Disabled Password" />
|
||||
<InputNumber disabled className="w-full" placeholder="0" />
|
||||
<InputCurrency disabled className="w-full" placeholder="Rp 0" />
|
||||
<TextArea disabled placeholder="Disabled TextArea" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* COLUMN 2: READ ONLY (Semua Component) */}
|
||||
<div className="space-y-3">
|
||||
<Label>Read Only State</Label>
|
||||
<div className="p-4 bg-gray-50 rounded-lg space-y-3 border border-dashed border-gray-200">
|
||||
<Input readOnly value="Read only text" prefix={<Fix>📖</Fix>} />
|
||||
<InputPassword readOnly value="secretpassword" />
|
||||
<InputNumber readOnly className="w-full" value={12345} />
|
||||
<InputCurrency readOnly className="w-full" value={50000} />
|
||||
<TextArea readOnly value="This content is read only and cannot be edited." rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* COLUMN 3: ERROR OUTLINED */}
|
||||
<div className="space-y-3">
|
||||
<Label>Error (Outlined)</Label>
|
||||
<div className="space-y-3">
|
||||
<Input status="error" placeholder="Invalid input" />
|
||||
<InputPassword status="error" placeholder="Wrong password" />
|
||||
<InputNumber status="error" className="w-full" placeholder="Out of range" />
|
||||
<InputCurrency status="error" className="w-full" placeholder="Invalid amount" />
|
||||
<TextArea status="error" placeholder="Error in message" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* COLUMN 4: ERROR FILLED */}
|
||||
<div className="space-y-3">
|
||||
<Label>Error (Filled)</Label>
|
||||
<div className="space-y-3">
|
||||
<Input status="error" placeholder="Invalid input" />
|
||||
<InputPassword status="error" placeholder="Wrong password" />
|
||||
<InputNumber status="error" className="w-full" placeholder="Out of range" />
|
||||
<InputCurrency status="error" className="w-full" placeholder="Invalid amount" />
|
||||
<TextArea status="error" placeholder="Error in message" rows={2} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Switch } from '@repo/ui';
|
||||
|
||||
export const SwitchShowcase = () => {
|
||||
// State untuk Controlled Switch Demo
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 p-8 font-sans text-gray-800">
|
||||
<div className="max-w-4xl mx-auto space-y-10">
|
||||
{/* Header */}
|
||||
<div className="border-b border-gray-200 pb-5">
|
||||
<h1 className="text-3xl font-bold text-gray-900">Switch Component</h1>
|
||||
<p className="mt-2 text-gray-600">Showcase fitur, variant, status, dan state interaksi.</p>
|
||||
</div>
|
||||
|
||||
{/* 1. VARIANTS */}
|
||||
<section>
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">1. Variants</h2>
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
{/* Variant: Outlined (Default) */}
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium text-gray-500 uppercase tracking-wider">Outlined (Default)</h3>
|
||||
<p className="text-xs text-gray-400 mb-2">Background transparan saat off.</p>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Switch label="Outlined Off" />
|
||||
<Switch defaultChecked label="Outlined On" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Variant: Filled */}
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-medium text-gray-500 uppercase tracking-wider">Filled</h3>
|
||||
<p className="text-xs text-gray-400 mb-2">Background abu-abu solid saat off.</p>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Switch label="Filled Off" />
|
||||
<Switch defaultChecked label="Filled On" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 2. STATUS COLORS */}
|
||||
<section>
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">2. Status Colors</h2>
|
||||
<p className="text-sm text-gray-500 mb-4">
|
||||
Warna diterapkan pada state <strong>Checked</strong> dan <strong>Focus Ring</strong>.
|
||||
</p>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="default" defaultChecked />
|
||||
<span className="text-xs font-medium text-gray-500">Default (Brand)</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="success" defaultChecked />
|
||||
<span className="text-xs font-medium text-green-600">Success</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="warning" defaultChecked />
|
||||
<span className="text-xs font-medium text-amber-600">Warning</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="error" defaultChecked />
|
||||
<span className="text-xs font-medium text-red-600">Error</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="info" defaultChecked />
|
||||
<span className="text-xs font-medium text-sky-600">Info</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-6">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="default" defaultChecked />
|
||||
<span className="text-xs font-medium text-gray-500">Default (Brand)</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="success" defaultChecked />
|
||||
<span className="text-xs font-medium text-green-600">Success</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="warning" defaultChecked />
|
||||
<span className="text-xs font-medium text-amber-600">Warning</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="error" defaultChecked />
|
||||
<span className="text-xs font-medium text-red-600">Error</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch status="info" defaultChecked />
|
||||
<span className="text-xs font-medium text-sky-600">Info</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 3. STATES (Loading & Disabled) */}
|
||||
<section>
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">3. States</h2>
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 space-y-8">
|
||||
{/* Disabled State */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500 mb-3">Disabled</h3>
|
||||
<div className="flex gap-6 items-center">
|
||||
<Switch disabled label="Disabled Off" />
|
||||
<Switch disabled defaultChecked label="Disabled On" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="border-gray-100" />
|
||||
|
||||
{/* Loading State */}
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500 mb-3">Loading</h3>
|
||||
<div className="flex gap-6 items-center flex-wrap">
|
||||
<Switch loading label="Loading Off" />
|
||||
<Switch loading defaultChecked label="Loading On" />
|
||||
{/* Loading with Status Color */}
|
||||
<Switch loading status="error" defaultChecked label="Loading Error" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 4. CUSTOM SIZES */}
|
||||
<section>
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">4. Custom Sizes</h2>
|
||||
<p className="text-sm text-gray-500 mb-4">Menggunakan CSS Variables inline untuk override ukuran default.</p>
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 flex items-end gap-8">
|
||||
{/* Small Override */}
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch
|
||||
defaultChecked
|
||||
style={
|
||||
{
|
||||
'--switch-width': '32px',
|
||||
'--switch-height': '16px',
|
||||
'--switch-handle-size': '12px',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
<span className="text-xs text-gray-400">Tiny</span>
|
||||
</div>
|
||||
|
||||
{/* Normal */}
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch defaultChecked />
|
||||
<span className="text-xs text-gray-400">Default</span>
|
||||
</div>
|
||||
|
||||
{/* Large Override */}
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<Switch
|
||||
defaultChecked
|
||||
style={
|
||||
{
|
||||
'--switch-width': '60px',
|
||||
'--switch-height': '30px',
|
||||
'--switch-handle-size': '26px',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
<span className="text-xs text-gray-400">Large</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 5. INTERACTIVE PLAYGROUND */}
|
||||
<section>
|
||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">5. Interactive Playground</h2>
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<div className="flex items-center justify-between mb-6 bg-gray-50 p-4 rounded-md">
|
||||
<div className="text-sm">
|
||||
<p>
|
||||
<strong>Value:</strong> {checked ? 'true' : 'false'}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Loading:</strong> {loading ? 'true' : 'false'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => setLoading(!loading)}
|
||||
className="px-3 py-1 text-xs bg-white border border-gray-300 rounded shadow-sm hover:bg-gray-50"
|
||||
>
|
||||
Toggle Loading
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-8 justify-center p-8 border-2 border-dashed border-gray-100 rounded-lg">
|
||||
<Switch
|
||||
checked={checked}
|
||||
onChange={(v) => setChecked(v)}
|
||||
loading={loading}
|
||||
label="Control Me"
|
||||
status="success"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,80 +0,0 @@
|
||||
import { useState } from 'react';
|
||||
import { InputStatusType } from '@repo/ui';
|
||||
import CheckboxShowcase from './components/checkbox.showcase';
|
||||
import InputShowCase from './components/input.showcase';
|
||||
import { SwitchShowcase } from './components/switch.showcase';
|
||||
import PickerShowcase from './components/date-picker.showcase';
|
||||
|
||||
export default function Showcase() {
|
||||
// State untuk menyimpan status yang dipilih
|
||||
const [selectedStatus, setSelectedStatus] = useState<InputStatusType>('default');
|
||||
|
||||
const statuses: { label: string; value: InputStatusType; color: string }[] = [
|
||||
{ label: 'Default', value: 'default', color: 'bg-gray-500' },
|
||||
{ label: 'Error', value: 'error', color: 'bg-red-500' },
|
||||
{ label: 'Warning', value: 'warning', color: 'bg-amber-500' },
|
||||
{ label: 'Success', value: 'success', color: 'bg-emerald-500' },
|
||||
{ label: 'Info', value: 'info', color: 'bg-blue-500' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50/50">
|
||||
<main className="mx-auto p-8 space-y-8">
|
||||
{/* HEADER & SELECTOR */}
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-white p-6 rounded-2xl border border-gray-200 shadow-sm">
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="text-xl font-bold text-gray-800">Input Components</h2>
|
||||
<span className="px-2 py-0.5 text-[10px] bg-blue-100 text-blue-600 rounded-full uppercase tracking-wider font-bold">
|
||||
Interactive Lab
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
Pilih status untuk melihat perubahan validasi pada semua tipe input.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* TAB SELECTOR */}
|
||||
<div className="flex bg-gray-100 p-1 rounded-xl w-fit border border-gray-200">
|
||||
{statuses.map((item) => (
|
||||
<button
|
||||
key={item.value}
|
||||
onClick={() => setSelectedStatus(item.value)}
|
||||
className={`
|
||||
px-4 py-2 text-sm font-medium rounded-lg transition-all duration-200
|
||||
${
|
||||
selectedStatus === item.value
|
||||
? 'bg-white text-gray-900 shadow-sm'
|
||||
: 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={`w-2 h-2 rounded-full ${item.color}`} />
|
||||
{item.label}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* RENDER COMPONENT */}
|
||||
<section className="animate-in fade-in slide-in-from-bottom-2 duration-500">
|
||||
<div className="relative">
|
||||
{/* Label Indikator Status Aktif */}
|
||||
<div className="absolute -top-3 left-8 px-3 py-1 rounded-full text-[10px] font-bold uppercase tracking-widest bg-white border border-gray-200 shadow-sm z-10">
|
||||
Active Status: <span className="text-blue-600">{selectedStatus}</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-12 p-8 ">
|
||||
{/* <SwitchShowcase /> */}
|
||||
{/* <CheckboxShowcase status={selectedStatus} /> */}
|
||||
{/* <InputShowCase status={selectedStatus} /> */}
|
||||
<PickerShowcase status={selectedStatus} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DateServiceExample, StyleGuideOne, StyleGuideTree, StyleGuideTwo } from '@repo/ui';
|
||||
import { lazy } from 'react';
|
||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||
|
||||
@@ -7,10 +6,6 @@ const ExamplePage = lazy(() => import('./example/example.page'));
|
||||
export default function AppModule() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/example/*" element={<DateServiceExample />} />
|
||||
<Route path="/guide-1/*" element={<StyleGuideOne />} />
|
||||
<Route path="/guide-2/*" element={<StyleGuideTwo />} />
|
||||
<Route path="/guide-3/*" element={<StyleGuideTree />} />
|
||||
<Route path="/" element={<ExamplePage />} />
|
||||
<Route path="*" element={<Navigate to={'/404'} replace={true} />} />
|
||||
</Routes>
|
||||
|
||||
Reference in New Issue
Block a user