Compare commits

...
3 Commits
Author SHA1 Message Date
jcchoi c2396f093b 필수입력 안내 메세지
Deploy Frontend / deploy (push) Successful in 8m31s
2026-10-07 19:43:06 +09:00
jcchoi bdf65dcfd1 설치인가 사업구분 팝업 사이즈 조정 2026-10-07 19:42:42 +09:00
jcchoi 2aefbe17ee 웹접근성 2차 수정 2026-10-07 19:42:20 +09:00
23 changed files with 89 additions and 71 deletions
@@ -155,7 +155,7 @@
}
.basinLabel.active {
background: #006bf8;
background: #0056b3;
color: #fff;
border-color: #96c3ff;
box-shadow: 0 4px 12px rgba(0, 107, 248, 0.3);
@@ -40,18 +40,18 @@ export function DashboardNotiList({
);
return (
<section className="card card-border m-0 bg-background">
<section className="card card-border m-0 bg-[#FAFBFC]">
<div className="card-header flex items-center justify-between gap-4">
<h3 className="text-2xl font-semibold">
알림이력
{dataUpdatedAt > 0 ? (
<span className="pl-2 text-lg font-medium text-muted-foreground">
<span className="pl-2 text-lg font-medium text-[#4A4A4A]">
(업데이트 일시: {dayjs(dataUpdatedAt).format("YYYY-MM-DD HH:mm")})
</span>
) : null}
</h3>
<div className="flex items-center gap-4">
<Button type="button" size="sm" color="white" onClick={() => router.push("/nti-hstry")}>
<Button type="button" size="sm" color="white" className="!text-[#0056B3]" onClick={() => router.push("/nti-hstry")}>
전체보기
</Button>
</div>
@@ -60,7 +60,7 @@ export function DashboardNotiList({
<div className="flex flex-col gap-4 p-2">
<div className="flex flex-wrap gap-2 pt-2">
{NOTI_STAT_CHIPS.map((chip) => (
<Badge key={chip.field} color={chip.color}>
<Badge key={chip.field} color={chip.color} className={chip.className}>
{chip.label} {isPending ? "-" : (notiStats?.[chip.field] ?? 0)}건
</Badge>
))}
@@ -75,7 +75,7 @@ export function DashboardNotiList({
) : null}
{isError ? (
<p className="flex min-h-[12rem] items-center justify-center text-muted-foreground">
<p className="flex min-h-[12rem] items-center justify-center text-[#4A4A4A]">
알림이력을 불러오지 못했습니다.
</p>
) : null}
@@ -110,11 +110,11 @@ interface DashboardNotiRowProps {
function DashboardNotiRow({ row, isActionPending, onAction }: DashboardNotiRowProps) {
return (
<div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-4 border-b px-2 py-4 last:border-b-0">
<span className="text-lg text-muted-foreground">
<span className="text-lg text-[#4A4A4A]">
{row.regDt ? dayjs(row.regDt).format("YYYY-MM-DD") : "-"}
</span>
<p className="min-w-0 line-clamp-2 text-xl sm:line-clamp-1">{row.notiTtl}</p>
<Button type="button" size="sm" color="white" disabled={isActionPending} onClick={onAction}>
<Button type="button" size="sm" color="white" className="!text-[#0056B3]" disabled={isActionPending} onClick={onAction}>
처리하기
</Button>
</div>
@@ -137,7 +137,7 @@ function resolveNotiUrl(row: NotiAsUserResponseDto) {
}
const NOTI_STAT_CHIPS = [
{ field: "todayCount", label: "오늘", color: "green" },
{ field: "delayCount", label: "지연", color: "orange" },
{ field: "pendingCount", label: "완료대기", color: "gray" },
{ field: "todayCount", label: "오늘", color: "green", className: "!bg-[#188038]" },
{ field: "delayCount", label: "지연", color: "orange", className: "!bg-[#C5221F]" },
{ field: "pendingCount", label: "완료대기", color: "gray", className: "!bg-[#5F6368]" },
] as const;
@@ -46,10 +46,10 @@ export function DashboardNoticeTable() {
});
return (
<section className="card card-border m-0 bg-background">
<section className="card card-border m-0 bg-[#FAFBFC]">
<div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-semibold">공지사항</h3>
<Button type="button" size="sm" color="white" onClick={handleMoreClick}>
<Button type="button" size="sm" color="white" className="!text-[#0056B3]" onClick={handleMoreClick}>
더보기
</Button>
</div>
@@ -11,7 +11,7 @@ export function DashboardPage() {
const { data, isPending, isError, dataUpdatedAt } = useGetMainDashboard();
return (
<div className="mt-4 flex gap-4 px-[1.8rem] pb-6">
<div className="flex min-h-full gap-4 bg-[#E9EDF2] px-[1.8rem] pb-6 pt-4 text-[#1E1E1E]">
<div className="hidden flex-[0.5] sm:block">
<NationalAsMap basinDocPrgrsList={data?.basinDocPrgrsList} />
</div>
@@ -24,7 +24,7 @@ export function DocPrgrsSttsCards({ items, isPending, isError }: DocPrgrsSttsCar
if (isError) {
return (
<div className="card card-border m-0 flex min-h-[14rem] items-center justify-center bg-background text-muted-foreground">
<div className="card card-border m-0 flex min-h-[14rem] items-center justify-center bg-[#FAFBFC] text-[#4A4A4A]">
진행상황을 불러오지 못했습니다.
</div>
);
@@ -39,7 +39,7 @@ export function DocPrgrsSttsCards({ items, isPending, isError }: DocPrgrsSttsCar
return (
<div
key={slot.docSeComCd}
className="card card-border hover:bg-muted/40 m-0 block bg-background transition-colors"
className="card card-border hover:bg-muted/40 m-0 block bg-[#FAFBFC] transition-colors"
>
<div className="card-header">
<h3 className="text-2xl font-semibold">{slot.title}</h3>
@@ -90,7 +90,7 @@ function DocPrgrsSttsMetric({
>
<Icon className="size-6" />
</span>
<span className="text-xl text-muted-foreground">{label}</span>
<span className="text-xl text-[#4A4A4A]">{label}</span>
<span className="text-3xl font-semibold tabular-nums">{count}</span>
</div>
);
@@ -107,21 +107,21 @@ const STAT_METRICS = [
{
field: "reqCnt",
label: "신청",
iconClassName: "bg-blue-500",
iconClassName: "bg-[#4285F4]",
bgColor: "bg-blue-100",
Icon: FilePlus,
},
{
field: "prgrsCnt",
label: "진행",
iconClassName: "bg-emerald-500",
iconClassName: "bg-[#34A853]",
bgColor: "bg-emerald-100",
Icon: RefreshCw,
},
{
field: "cmptnCnt",
label: "완료",
iconClassName: "bg-orange-500",
iconClassName: "bg-[#EA4335]",
bgColor: "bg-orange-100",
Icon: CircleCheck,
},
@@ -18,7 +18,7 @@ export function NationalAsMap({ basinDocPrgrsList }: NationalAsMapProps) {
const popupColumnSpan = Math.max(1, popupContent.items.length);
return (
<section className="card card-border m-0 flex h-full min-h-[40rem] flex-col bg-background">
<section className="card card-border m-0 flex h-full min-h-[40rem] flex-col bg-[#FAFBFC]">
<div className="card-header">
<h3 className="text-2xl font-semibold">전국 행정지원 지도</h3>
</div>
@@ -165,8 +165,11 @@ function DesignFormPage({ mode, initialData, createDefaults }: DesignFormPagePro
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-6 space-y-4">
<SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2">
<div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div>
<div className="space-y-4">
{initialData?.detDto?.designCnstnDocNo && (
@@ -248,8 +248,11 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps)
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2">
<div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div>
<div className="space-y-4">
{initialData?.detDto?.fnrsCnsltnDocNo && (
@@ -209,8 +209,11 @@ function InstlFormPage({ mode, initialData, createDefaults }: InstlFormPageProps
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2">
<div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div>
<div className="space-y-4">
{initialData?.detDto.instlSncnDocNo && (
@@ -246,8 +246,11 @@ function SewerBscPlanFormPage({
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2">
<div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div>
<div className="space-y-4">
{initialData?.detDto?.sewerBscPlanDocNo && (
@@ -97,7 +97,7 @@ function PbadmsTaskApplyDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
<DialogContent className="max-w-[66rem]" aria-describedby={undefined}>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
@@ -107,10 +107,10 @@ function PbadmsTaskApplyDialog({
) : (
<Table caption="행정지원 신청 정보 입력" variant="secondary">
<colgroup>
<col width="15%" />
<col width="35%" />
<col width="15%" />
<col width="35%" />
<col width="20%" />
<col width="30%" />
<col width="20%" />
<col width="30%" />
</colgroup>
<TableHeader>
{canSidoGugunSelectable && (
+2 -2
View File
@@ -74,8 +74,8 @@
}
nav[aria-label="pagination"] li a[aria-current="page"] {
border-color: #2094fa !important;
background-color: #2094fa !important;
border-color: #0a84f0 !important;
background-color: #0a84f0 !important;
color: #fafafa !important;
}
@@ -10,8 +10,8 @@
width: 0.55rem;
height: 0.55rem;
border-radius: 9999px;
background: #ff6c64;
box-shadow: 0 0 0 0 rgba(255, 108, 100, 0.75);
background: #e53e35;
box-shadow: 0 0 0 0 rgba(229, 62, 53, 0.75);
animation: verification-result-btn-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
pointer-events: none;
}
+3 -3
View File
@@ -132,7 +132,7 @@
@apply !font-semibold;
}
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected {
@apply !font-semibold !text-[#ff6c64];
@apply !font-semibold !text-[#e53e35];
white-space: nowrap !important;
}
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected > * {
@@ -150,8 +150,8 @@
width: 0.6125rem;
height: 0.6125rem;
border-radius: 9999px;
background: #ff6c64;
box-shadow: 0 0 0 0 rgba(255, 108, 100, 0.75);
background: #e53e35;
box-shadow: 0 0 0 0 rgba(229, 62, 53, 0.75);
animation: rg-cell-stats-status-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-total {
+4 -4
View File
@@ -2411,13 +2411,13 @@ useEffect(() => {
) : statusInfo.laeSbmsnSttsCd === "2" ? (
<span className="!text-[#2094fa]">제출</span>
) : statusInfo.laeSbmsnSttsCd === "3" ? (
<span className="!text-[#1fd078]">승인</span>
<span className="!text-[#179d5b]">승인</span>
) : statusInfo.laeSbmsnSttsCd === "4" ? (
<span className="relative inline-flex pr-3 !text-[#ff6c64]">
<span className="relative inline-flex pr-3 !text-[#e53e35]">
반려
<span className="absolute -right-0.5 -top-0.5 inline-flex size-[0.6125rem]">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#ff6c64] opacity-75" />
<span className="relative inline-flex size-[0.6125rem] rounded-full bg-[#ff6c64]" />
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#e53e35] opacity-75" />
<span className="relative inline-flex size-[0.6125rem] rounded-full bg-[#e53e35]" />
</span>
</span>
) : (
+8 -8
View File
@@ -10,21 +10,21 @@
--card-foreground: #0a0a0a;
--popover: #ffffff;
--popover-foreground: #0a0a0a;
--primary: #2094fa;
--primary: #0a84f0;
--primary-foreground: #fafafa;
--primary-transparent: rgba(32, 148, 250, 0.1);
--primary-transparent: rgba(10, 132, 240, 0.1);
--secondary: #f5f5f5;
--secondary-foreground: #0f1e33;
--muted: #f5f5f5;
--muted-foreground: #737373;
--accent: #f5f5f5;
--accent-foreground: #0f1e33;
--destructive: #ff6c64;
--destructive: #e53e35;
--destructive-foreground: #fafafa;
--border: #e5e5e5;
--input: #e5e5e5;
--label: #666666;
--placeholder: #a2a2a2;
--placeholder: #8a8a8a;
--ring: #0a0a0a;
--chart-1: #2094fa;
--chart-2: #00dfe5;
@@ -62,12 +62,12 @@
--muted-foreground: #a2a2a2;
--accent: #262626;
--accent-foreground: #fafafa;
--destructive: #b22222;
--destructive: #d23c3c;
--destructive-foreground: #fafafa;
--border: #262626;
--input: #262626;
--label: #f1f1f1;
--placeholder: #737373;
--placeholder: #c4c4c4;
--ring: #d4d4d4;
--chart-1: #66b3ff;
--chart-2: #66f0f2;
@@ -90,12 +90,12 @@
--title: #fff;
}
[data-theme="red"] {
--primary: #ff6464;
--primary: #ff4040;
--destructive: #7388ec;
--container: #f6f6f9;
}
[data-theme="green"] {
--primary: #00b9b8;
--primary: #009a9a;
--container: #f2f2f3;
}
}
@@ -16,31 +16,31 @@
.badge.outline {
}
.badge.red {
@apply bg-[#ff6354];
@apply bg-[#e53e35];
}
.badge.blue {
@apply bg-[#1ba9ff];
@apply bg-[#008ee4];
}
.badge.yellow {
@apply bg-[#fbc700];
@apply bg-[#fbc700] text-[#1e1e1e];
}
.badge.orange {
@apply bg-[#ff8a22];
@apply bg-[#dc6800];
}
.badge.smokyBlue {
@apply bg-[#5b85ff];
}
.badge.purple {
@apply bg-[#d85bff];
@apply bg-[#d344ff];
}
.badge.green {
@apply bg-[#07bd9d];
@apply bg-[#069b80];
}
.badge.gray {
@apply bg-[#838383];
}
.badge.lightGray {
@apply bg-[#b9b9b9];
@apply bg-[#8a8a8a];
}
.badge.base {
@apply px-2.5 py-0.5 text-[1.1rem];
@@ -8,19 +8,19 @@
@apply bg-primary;
}
button[role="button"].green {
@apply bg-[rgba(31,208,120,1)];
@apply bg-[#179d5b];
}
button[role="button"].sky {
@apply bg-[rgba(50,154,203,1)];
}
button[role="button"].yellow {
@apply bg-[rgba(243,201,0,1)];
@apply bg-[rgba(243,201,0,1)] text-[#1e1e1e];
}
button[role="button"].orange {
@apply bg-[rgba(255,149,0,1)];
@apply bg-[#c97600];
}
button[role="button"].emerald {
@apply bg-[rgba(90,200,250,1)];
@apply bg-[#0691d1];
}
button[role="button"].white {
@apply border border-border bg-[rgba(255,255,255,1)] text-[#666];
@@ -29,9 +29,9 @@
@apply bg-destructive;
}
button[role="button"].gray {
@apply bg-[rgba(153,153,153,1)];
@apply bg-[#8a8a8a];
}
button[role="button"].lightGray {
@apply bg-[rgba(235,235,235,1)] text-[#929292];
@apply bg-[rgba(235,235,235,1)] text-[#707070];
}
}
@@ -39,7 +39,7 @@
[data-theme="blue"] {
header {
background: #00afe5;
background: #0094c1;
border: none;
}
header h1 span {
@@ -103,7 +103,7 @@
}
#lnb > ul > li.on.noDepth a {
color: #ffffff;
background: #40a5ff;
background: #0589ff;
border-radius: 5px;
}
#lnb > ul > li.on > a {
@@ -204,12 +204,12 @@
}
#lnb > ul > li > ul > li.on a:hover {
color: #ffffff;
background: #40a5ff;
background: #0589ff;
}
[data-theme="blue"] {
footer {
background: #6ec05d;
background: #4c9a3c;
}
footer p {
color: #fff;
@@ -218,7 +218,7 @@
[data-theme="green"] {
footer {
background: #24ec7d;
background: #0e9f4e;
}
footer p {
color: #fff;
@@ -316,6 +316,7 @@ export function LNB({
!isSidebarOpen && "justify-center",
)}
tooltip={item.menuKornNm}
aria-expanded={isOpen}
>
<div className="flex items-center gap-2">
<i
@@ -333,6 +334,9 @@ export function LNB({
>
{item.menuKornNm}
</span>
<span className="sr-only">
{isOpen ? "하위 메뉴 펼쳐짐" : "하위 메뉴 접힘"}
</span>
</div>
<ChevronRight
className={cn(
@@ -104,20 +104,22 @@ type TableHeadProps = React.ThHTMLAttributes<HTMLTableCellElement> & {
};
const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
({ children, className, scope = "col", ...props }, ref) => {
const isRequired = props["data-required"] !== undefined;
({ children, className, scope = "col", "data-required": dataRequired, ...props }, ref) => {
const isRequired =
dataRequired !== undefined && dataRequired !== false && dataRequired !== "false";
return (
<th
ref={ref}
scope={scope}
className={cn("align-middle", className)}
data-required={isRequired ? "" : undefined}
{...props}
>
{children}
{isRequired && (
<span className="table-required-marker" title="필수 항목">
(*)
{" "}(*)
</span>
)}
</th>
@@ -8,7 +8,7 @@
@apply px-4 py-[1.2rem] text-[1.3rem] font-medium leading-[1.2];
}
.table-ui th[data-required] .table-required-marker {
@apply ml-1 text-red-600;
@apply whitespace-nowrap text-red-600;
}
.table-ui td {
@apply px-2 py-[1.2rem] text-[1.3rem] font-normal leading-[1.2];