Temuulen Ankhbayar d7efede122
Some checks failed
Pull Request Checks / Code Quality & Security (push) Has been cancelled
Security Audit / Security Vulnerability Audit (push) Has been cancelled
Security Audit / Dependency Review (push) Has been cancelled
Security Audit / CodeQL Security Analysis (push) Has been cancelled
Security Audit / Check Outdated Dependencies (push) Has been cancelled
refactor: complete shadcn/ui migration and unify raw HTML with component library
- Migrate all molecule components (DataTable, PaginationBar, FilterDropdown,
  AlertBanner, FormField, SectionCard, SubCard, MetricCard, AnimatedCard,
  OtpInput) to shadcn/ui primitives with legacy backups and comparison stories
- Install 24 shadcn/ui primitives (accordion, alert, badge, button, card,
  checkbox, collapsible, dialog, dropdown-menu, input-otp, input, label,
  pagination, popover, radio-group, select, separator, sheet, skeleton,
  table, tabs, toggle-group, toggle, tooltip) with barrel exports
- Replace 69 raw HTML elements across all features with shadcn components:
  35+ <button> → Button, 5 <select> → Select, 15+ <label> → Label,
  6 <input type=checkbox> → Checkbox, 7 <input type=radio> → RadioGroup
- Add TextRotate animation component and integrate into hero section
  with rotating service names (Internet, Phone Plans, VPN, IT Support, Business)
- Add destructive color token aliases for error state consistency
- Add CLAUDE.md rules for shadcn migration process

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:21:36 +09:00

109 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React from "react";
import {
CheckCircleIcon,
InformationCircleIcon,
ExclamationTriangleIcon,
XCircleIcon,
} from "@heroicons/react/24/outline";
type Variant = "success" | "info" | "warning" | "error";
type IconType = React.ComponentType<React.SVGProps<SVGSVGElement>>;
const variantClasses: Record<
Variant,
{ bg: string; border: string; text: string; icon: string; Icon: IconType }
> = {
success: {
bg: "bg-success-soft",
border: "border-success/30",
text: "text-success",
icon: "text-success",
Icon: CheckCircleIcon,
},
info: {
bg: "bg-info-soft",
border: "border-info/30",
text: "text-info",
icon: "text-info",
Icon: InformationCircleIcon,
},
warning: {
bg: "bg-warning-soft",
border: "border-warning/35",
text: "text-foreground",
icon: "text-warning",
Icon: ExclamationTriangleIcon,
},
error: {
bg: "bg-danger-soft",
border: "border-danger/30",
text: "text-danger",
icon: "text-danger",
Icon: XCircleIcon,
},
};
interface AlertBannerProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: Variant;
title?: string;
children?: React.ReactNode;
icon?: React.ReactNode;
size?: "sm" | "md";
elevated?: boolean;
onClose?: () => void;
}
export function AlertBanner({
variant = "info",
title,
children,
icon,
size = "md",
elevated = false,
onClose,
className,
...rest
}: AlertBannerProps) {
const styles = variantClasses[variant];
const Icon = styles.Icon;
const padding = size === "sm" ? "p-3" : "p-4";
const radius = "rounded-xl";
const shadow = elevated ? "shadow-sm" : "";
const role = variant === "error" || variant === "warning" ? "alert" : "status";
return (
<div
className={[radius, padding, "border", shadow, styles.bg, styles.border, className]
.filter(Boolean)
.join(" ")}
role={role}
{...rest}
>
<div className="flex items-start gap-3">
<div className="mt-0.5 flex-shrink-0">
{icon ? icon : <Icon className={["h-5 w-5", styles.icon].join(" ")} />}
</div>
<div className="flex-1">
{title && <p className={["font-medium", styles.text].join(" ")}>{title}</p>}
{children && (
<div className={["text-sm mt-1 text-foreground/80"].join(" ")}>{children}</div>
)}
</div>
{onClose && (
<button
onClick={onClose}
aria-label="Close alert"
className="text-muted-foreground hover:text-foreground transition-colors"
>
×
</button>
)}
</div>
</div>
);
}
export type { AlertBannerProps };