feat(interface-design): add comprehensive interface design skill documentation and references

- Introduced SKILL.md outlining the principles and processes for effective interface design.
- Added critique.md for evaluating design outputs and ensuring craft over correctness.
- Created example.md to illustrate the application of subtle layering principles in design decisions.
- Developed principles.md detailing core craft principles for consistent design quality.
- Implemented validation.md for memory management and pattern reuse in the design system.
- Established system.md for the Playzer design system, defining direction, domain concepts, and design decisions.
- Added StatusBadge component for displaying booking statuses with appropriate styles and labels.
- Updated skills-lock.json to include the new interface-design skill.
This commit is contained in:
Jose Selesan
2026-04-24 11:23:45 -03:00
parent 7bfa3b390e
commit 503c29613b
13 changed files with 1200 additions and 32 deletions

View File

@@ -66,11 +66,25 @@ function extractMessage(error: unknown, fallback: string) {
return fallback;
}
function formatDateLabel(dateIso: string) {
function formatDateLabel(dateIso: string, todayIso: string) {
const [year, month, day] = dateIso.split('-').map(Number);
if (!year || !month || !day) return dateIso;
const [tYear, tMonth, tDay] = todayIso.split('-').map(Number);
const isToday = year === tYear && month === tMonth && day === tDay;
const tmrw = new Date(tYear, tMonth - 1, tDay);
tmrw.setDate(tmrw.getDate() + 1);
const isTomorrow =
year === tmrw.getFullYear() &&
month === tmrw.getMonth() + 1 &&
day === tmrw.getDate();
if (isToday) return 'Hoy';
if (isTomorrow) return 'Mañana';
const date = new Date(year, month - 1, day);
return new Intl.DateTimeFormat('es-AR', {
weekday: 'long',
@@ -104,21 +118,6 @@ function effectiveStatusLabel(status: 'CONFIRMED' | 'CANCELLED' | 'COMPLETED' |
return 'Confirmada';
}
function effectiveStatusClassName(status: 'CONFIRMED' | 'CANCELLED' | 'COMPLETED' | 'NO_SHOW') {
if (status === 'NO_SHOW') {
return 'border-orange-200 bg-orange-50 text-orange-700';
}
if (status === 'COMPLETED') {
return 'border-emerald-200 bg-emerald-50 text-emerald-700';
}
if (status === 'CANCELLED') {
return 'border-rose-200 bg-rose-50 text-rose-700';
}
return 'border-sky-200 bg-sky-50 text-sky-700';
}
export function HomePage() {
const queryClient = useQueryClient();
const navigate = useNavigate();
@@ -704,7 +703,7 @@ export function HomePage() {
<div className="mt-4 space-y-4">
{groupedBookings.map(([date, bookings]) => (
<article key={date} className="rounded-lg border bg-background p-3">
<h2 className="text-sm font-semibold capitalize">{formatDateLabel(date)}</h2>
<h2 className="text-sm font-semibold">{formatDateLabel(date, todayIso)}</h2>
<div className="mt-3 space-y-2">
{bookings.map((booking) => {
const effectiveStatus = getEffectiveStatus(booking);
@@ -712,10 +711,36 @@ export function HomePage() {
booking.status === 'CONFIRMED' && effectiveStatus === 'CONFIRMED';
const isMutating = updateStatusMutation.isPending;
const statusColorMap: Record<string, string> = {
CONFIRMED: 'border-l-sky-500 dark:border-l-sky-400',
COMPLETED: 'border-l-emerald-500 dark:border-l-emerald-400',
CANCELLED: 'border-l-rose-500 dark:border-l-rose-400',
NO_SHOW: 'border-l-orange-500 dark:border-l-orange-400',
};
const statusBgMap: Record<string, string> = {
CONFIRMED: 'bg-sky-50/30 dark:bg-sky-950/20',
COMPLETED: 'bg-emerald-50/30 dark:bg-emerald-950/20',
CANCELLED: 'bg-rose-50/30 dark:bg-rose-950/20',
NO_SHOW: 'bg-orange-50/30 dark:bg-orange-950/20',
};
const colorClass = statusColorMap[effectiveStatus] || '';
const bgClass = statusBgMap[effectiveStatus] || '';
const badgeColorMap: Record<string, string> = {
CONFIRMED: 'border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-800 dark:bg-sky-950 dark:text-sky-300',
COMPLETED: 'border-emerald-200 bg-emerald-50 text-emerald-700 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-300',
CANCELLED: 'border-rose-200 bg-rose-50 text-rose-700 dark:border-rose-800 dark:bg-rose-950 dark:text-rose-300',
NO_SHOW: 'border-orange-200 bg-orange-50 text-orange-700 dark:border-orange-800 dark:bg-orange-950 dark:text-orange-300',
};
const badgeClass = badgeColorMap[effectiveStatus] || '';
return (
<div
key={booking.id}
className="flex flex-col gap-2 rounded-md border p-3 sm:flex-row sm:items-center sm:justify-between"
className={`flex flex-col gap-2 rounded-md border border-l-[3px] p-3 sm:flex-row sm:items-center sm:justify-between ${colorClass} ${bgClass}`}
>
<div>
<p className="text-sm font-medium">
@@ -729,7 +754,7 @@ export function HomePage() {
<div className="flex flex-wrap items-center gap-2">
<span
className={`inline-flex rounded-full border px-2 py-1 text-xs font-medium ${effectiveStatusClassName(effectiveStatus)}`}
className={`hidden sm:inline-flex rounded-full border px-2 py-1 text-xs font-medium ${badgeClass}`}
>
{effectiveStatusLabel(effectiveStatus)}
</span>