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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user