fix: admin bookings light theme — readable names, badges, and actions
- Name text: text-white → text-neutral-900 dark:text-white - Status badges: -400 colors → -600 for light, dark: keeps -400 - Contact links: same -600/-400 split - BookingCard borders/bg: stronger opacity for light mode - Action buttons: dark:text for light contrast - Group counters: amber-700/blue-600/emerald-600 for light
This commit is contained in:
@@ -47,17 +47,17 @@ export function DeleteBtn({ onClick, name }: { onClick: () => void; name?: strin
|
||||
{confirming && createPortal(
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4" onClick={() => setConfirming(false)}>
|
||||
<div className="absolute inset-0 bg-black/70 backdrop-blur-sm" />
|
||||
<div className="relative w-full max-w-xs rounded-2xl border border-white/[0.08] bg-[#0a0a0a] p-5 shadow-2xl" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={() => setConfirming(false)} className="absolute right-3 top-3 flex h-7 w-7 items-center justify-center rounded-full text-neutral-500 hover:bg-white/[0.06] hover:text-white">
|
||||
<div className="relative w-full max-w-xs rounded-2xl border border-neutral-200 bg-white p-5 shadow-2xl dark:border-white/[0.08] dark:bg-[#0a0a0a]" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={() => setConfirming(false)} className="absolute right-3 top-3 flex h-7 w-7 items-center justify-center rounded-full text-neutral-500 hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-white/[0.06] dark:hover:text-white">
|
||||
<X size={16} />
|
||||
</button>
|
||||
<h3 className="text-sm font-bold text-white">Удалить запись?</h3>
|
||||
{name && <p className="mt-1 text-xs text-neutral-400">{name}</p>}
|
||||
<p className="mt-2 text-xs text-neutral-500">Это действие нельзя отменить.</p>
|
||||
<h3 className="text-sm font-bold text-neutral-900 dark:text-white">Удалить запись?</h3>
|
||||
{name && <p className="mt-1 text-xs text-neutral-500 dark:text-neutral-400">{name}</p>}
|
||||
<p className="mt-2 text-xs text-neutral-400 dark:text-neutral-500">Это действие нельзя отменить.</p>
|
||||
<div className="mt-4 flex gap-2">
|
||||
<button
|
||||
onClick={() => setConfirming(false)}
|
||||
className="flex-1 rounded-lg border border-white/10 bg-neutral-800 py-2 text-xs font-medium text-neutral-300 hover:bg-neutral-700 transition-colors"
|
||||
className="flex-1 rounded-lg border border-neutral-200 bg-neutral-100 py-2 text-xs font-medium text-neutral-700 hover:bg-neutral-200 transition-colors dark:border-white/10 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700"
|
||||
>
|
||||
Отмена
|
||||
</button>
|
||||
@@ -80,17 +80,17 @@ export function ContactLinks({ phone, instagram, telegram }: { phone?: string; i
|
||||
return (
|
||||
<>
|
||||
{phone && (
|
||||
<a href={`tel:${phone.replace(/\D/g, "")}`} className="inline-flex items-center gap-1 text-emerald-400 hover:text-emerald-300 text-xs">
|
||||
<a href={`tel:${phone.replace(/\D/g, "")}`} className="inline-flex items-center gap-1 text-emerald-600 hover:text-emerald-500 dark:text-emerald-400 dark:hover:text-emerald-300 text-xs">
|
||||
<Phone size={10} />{phone}
|
||||
</a>
|
||||
)}
|
||||
{instagram && (
|
||||
<a href={`https://ig.me/m/${instagram.replace(/^@/, "")}`} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-pink-400 hover:text-pink-300 text-xs">
|
||||
<a href={`https://ig.me/m/${instagram.replace(/^@/, "")}`} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-pink-600 hover:text-pink-500 dark:text-pink-400 dark:hover:text-pink-300 text-xs">
|
||||
<Instagram size={10} />{instagram}
|
||||
</a>
|
||||
)}
|
||||
{telegram && (
|
||||
<a href={`https://t.me/${telegram.replace(/^@/, "")}`} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-blue-400 hover:text-blue-300 text-xs">
|
||||
<a href={`https://t.me/${telegram.replace(/^@/, "")}`} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-blue-600 hover:text-blue-500 dark:text-blue-400 dark:hover:text-blue-300 text-xs">
|
||||
<Send size={10} />{telegram}
|
||||
</a>
|
||||
)}
|
||||
@@ -109,7 +109,7 @@ export function FilterTabs({ filter, counts, total, onFilter }: {
|
||||
<button
|
||||
onClick={() => onFilter("all")}
|
||||
className={`rounded-full px-3 py-1.5 text-xs font-medium transition-all ${
|
||||
filter === "all" ? "bg-gold/20 text-gold border border-gold/40" : "bg-neutral-800 text-neutral-400 border border-white/10 hover:text-white"
|
||||
filter === "all" ? "bg-gold/20 text-gold border border-gold/40" : "bg-neutral-100 text-neutral-500 border border-neutral-300 hover:text-neutral-900 dark:bg-neutral-800 dark:text-neutral-400 dark:border-white/10 dark:hover:text-white"
|
||||
}`}
|
||||
>
|
||||
Все <span className="text-neutral-500 ml-1">{total}</span>
|
||||
@@ -119,7 +119,7 @@ export function FilterTabs({ filter, counts, total, onFilter }: {
|
||||
key={s.key}
|
||||
onClick={() => onFilter(s.key)}
|
||||
className={`rounded-full px-3 py-1.5 text-xs font-medium transition-all ${
|
||||
filter === s.key ? `${s.bg} ${s.color} border ${s.border}` : "bg-neutral-800 text-neutral-400 border border-white/10 hover:text-white"
|
||||
filter === s.key ? `${s.bg} ${s.color} border ${s.border}` : "bg-neutral-100 text-neutral-500 border border-neutral-300 hover:text-neutral-900 dark:bg-neutral-800 dark:text-neutral-400 dark:border-white/10 dark:hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{s.label}
|
||||
@@ -147,14 +147,14 @@ export function StatusActions({ status, onStatus }: { status: BookingStatus; onS
|
||||
);
|
||||
return (
|
||||
<div className="flex gap-1 ml-auto">
|
||||
{status === "new" && actionBtn("Связались →", () => onStatus("contacted"), "bg-blue-500/10 text-blue-400 border border-blue-500/30 hover:bg-blue-500/20")}
|
||||
{status === "new" && actionBtn("Связались →", () => onStatus("contacted"), "bg-blue-500/10 text-blue-600 dark:text-blue-400 border border-blue-500/30 hover:bg-blue-500/20")}
|
||||
{status === "contacted" && (
|
||||
<>
|
||||
{actionBtn("Подтвердить", () => onStatus("confirmed"), "bg-emerald-500/10 text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/20")}
|
||||
{actionBtn("Отказ", () => onStatus("declined"), "bg-red-500/10 text-red-400 border border-red-500/30 hover:bg-red-500/20")}
|
||||
{actionBtn("Подтвердить", () => onStatus("confirmed"), "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/20")}
|
||||
{actionBtn("Отказ", () => onStatus("declined"), "bg-red-500/10 text-red-600 dark:text-red-400 border border-red-500/30 hover:bg-red-500/20")}
|
||||
</>
|
||||
)}
|
||||
{(status === "confirmed" || status === "declined") && actionBtn("Вернуть", () => onStatus("contacted"), "bg-neutral-800/50 text-neutral-500 border border-transparent hover:border-white/10 hover:text-neutral-300")}
|
||||
{(status === "confirmed" || status === "declined") && actionBtn("Вернуть", () => onStatus("contacted"), "bg-neutral-100 text-neutral-600 border border-neutral-300 hover:border-neutral-400 hover:text-neutral-800 dark:bg-neutral-800/50 dark:text-neutral-500 dark:border-transparent dark:hover:border-white/10 dark:hover:text-neutral-300")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -163,10 +163,10 @@ export function BookingCard({ status, highlight, children }: { status: BookingSt
|
||||
return (
|
||||
<div
|
||||
className={`rounded-lg border p-3 transition-all duration-200 cursor-default ${
|
||||
status === "declined" ? "border-red-500/15 bg-red-500/[0.02] opacity-50 hover:opacity-70 hover:border-red-500/30"
|
||||
: status === "confirmed" ? "border-emerald-500/15 bg-emerald-500/[0.02] hover:border-emerald-500/30 hover:bg-emerald-500/[0.05]"
|
||||
: status === "new" ? "border-gold/20 bg-gold/[0.03] hover:border-gold/40 hover:bg-gold/[0.06]"
|
||||
: "border-white/10 bg-neutral-800/30 hover:border-white/20 hover:bg-neutral-800/50"
|
||||
status === "declined" ? "border-red-500/20 bg-red-500/[0.04] opacity-50 hover:opacity-70 hover:border-red-500/30 dark:border-red-500/15 dark:bg-red-500/[0.02]"
|
||||
: status === "confirmed" ? "border-emerald-500/20 bg-emerald-500/[0.04] hover:border-emerald-500/30 hover:bg-emerald-500/[0.08] dark:border-emerald-500/15 dark:bg-emerald-500/[0.02] dark:hover:bg-emerald-500/[0.05]"
|
||||
: status === "new" ? "border-gold/30 bg-gold/[0.06] hover:border-gold/50 hover:bg-gold/[0.1] dark:border-gold/20 dark:bg-gold/[0.03] dark:hover:border-gold/40 dark:hover:bg-gold/[0.06]"
|
||||
: "border-neutral-200 bg-neutral-50 hover:border-neutral-300 hover:bg-neutral-100 dark:border-white/10 dark:bg-neutral-800/30 dark:hover:border-white/20 dark:hover:bg-neutral-800/50"
|
||||
}${highlight ? " ring-2 ring-gold/40 animate-[pulse_1s_ease-in-out_1]" : ""}`}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -109,7 +109,7 @@ export function GenericBookingsList<T extends BaseBooking>({
|
||||
<BookingCard status={item.status} highlight={isHighlighted}>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex items-center gap-2 flex-wrap text-sm min-w-0">
|
||||
<span className="font-medium text-white truncate max-w-[200px]">{item.name}</span>
|
||||
<span className="font-medium text-neutral-900 dark:text-white truncate max-w-[200px]">{item.name}</span>
|
||||
<ContactLinks phone={item.phone} instagram={item.instagram} telegram={item.telegram} />
|
||||
{renderExtra?.(item)}
|
||||
</div>
|
||||
@@ -167,9 +167,9 @@ export function GenericBookingsList<T extends BaseBooking>({
|
||||
<span className="text-[10px] text-neutral-500 bg-neutral-200 rounded-full px-2 py-0.5 shrink-0 dark:bg-neutral-800">{group.items.length} чел.</span>
|
||||
{!group.isArchived && (
|
||||
<div className="flex gap-2 ml-auto text-[10px]">
|
||||
{groupCounts.new > 0 && <span className="text-gold">{groupCounts.new} новых</span>}
|
||||
{groupCounts.contacted > 0 && <span className="text-blue-400">{groupCounts.contacted} связ.</span>}
|
||||
{groupCounts.confirmed > 0 && <span className="text-emerald-400">{groupCounts.confirmed} подтв.</span>}
|
||||
{groupCounts.new > 0 && <span className="text-amber-700 dark:text-gold">{groupCounts.new} новых</span>}
|
||||
{groupCounts.contacted > 0 && <span className="text-blue-600 dark:text-blue-400">{groupCounts.contacted} связ.</span>}
|
||||
{groupCounts.confirmed > 0 && <span className="text-emerald-600 dark:text-emerald-400">{groupCounts.confirmed} подтв.</span>}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
|
||||
@@ -17,10 +17,10 @@ export interface BaseBooking {
|
||||
export { SHORT_DAYS };
|
||||
|
||||
export const BOOKING_STATUSES: { key: BookingStatus; label: string; color: string; bg: string; border: string }[] = [
|
||||
{ key: "new", label: "Новая", color: "text-gold", bg: "bg-gold/10", border: "border-gold/30" },
|
||||
{ key: "contacted", label: "Связались", color: "text-blue-400", bg: "bg-blue-500/10", border: "border-blue-500/30" },
|
||||
{ key: "confirmed", label: "Подтверждено", color: "text-emerald-400", bg: "bg-emerald-500/10", border: "border-emerald-500/30" },
|
||||
{ key: "declined", label: "Отказ", color: "text-red-400", bg: "bg-red-500/10", border: "border-red-500/30" },
|
||||
{ key: "new", label: "Новая", color: "text-amber-700 dark:text-gold", bg: "bg-gold/10", border: "border-gold/30" },
|
||||
{ key: "contacted", label: "Связались", color: "text-blue-600 dark:text-blue-400", bg: "bg-blue-500/10", border: "border-blue-500/30" },
|
||||
{ key: "confirmed", label: "Подтверждено", color: "text-emerald-600 dark:text-emerald-400", bg: "bg-emerald-500/10", border: "border-emerald-500/30" },
|
||||
{ key: "declined", label: "Отказ", color: "text-red-600 dark:text-red-400", bg: "bg-red-500/10", border: "border-red-500/30" },
|
||||
];
|
||||
|
||||
export function fmtDate(iso: string): string {
|
||||
|
||||
Reference in New Issue
Block a user