diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f916098..be0708a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -83,8 +83,8 @@ export default function App() { colorBgElevated: theme === 'light' ? '#ffffff' : theme === 'blue' ? '#15273d' : '#24283b', colorBgLayout: theme === 'light' ? '#f1f5f9' : theme === 'blue' ? '#0a1522' : '#16181e', colorTextLightSolid: '#ffffff', - colorBorder: theme === 'light' ? undefined : theme === 'blue' ? 'rgba(143, 187, 224, 0.55)' : 'rgba(192, 202, 245, 0.5)', - colorBorderSecondary: theme === 'light' ? undefined : theme === 'blue' ? 'rgba(143, 187, 224, 0.35)' : 'rgba(192, 202, 245, 0.32)', + colorBorder: theme === 'light' ? '#c9d1d9' : theme === 'blue' ? 'rgba(143, 187, 224, 0.55)' : 'rgba(192, 202, 245, 0.5)', + colorBorderSecondary: theme === 'light' ? '#c9d1d9' : theme === 'blue' ? 'rgba(143, 187, 224, 0.35)' : 'rgba(192, 202, 245, 0.32)', }, components: { Button: { @@ -92,11 +92,16 @@ export default function App() { defaultShadow: 'none', dangerShadow: 'none', }, + Table: { + borderColor: theme === 'light' ? '#c9d1d9' : theme === 'blue' ? 'rgba(143, 187, 224, 0.45)' : 'rgba(192, 202, 245, 0.4)', + headerSplitColor: theme === 'light' ? '#c9d1d9' : theme === 'blue' ? 'rgba(143, 187, 224, 0.45)' : 'rgba(192, 202, 245, 0.4)', + }, Drawer: { colorBgElevated: theme === 'light' ? '#ffffff' : theme === 'blue' ? '#15273d' : '#24283b', }, Checkbox: { - colorBorder: theme === 'light' ? undefined : theme === 'blue' ? 'rgba(143, 187, 224, 0.65)' : 'rgba(192, 202, 245, 0.58)', + colorBorder: theme === 'light' ? '#64748b' : theme === 'blue' ? 'rgba(143, 187, 224, 0.65)' : 'rgba(192, 202, 245, 0.58)', + colorPrimary: THEME_PRIMARY[theme] || '#1677ff', }, Select: { selectorBg: theme === 'light' ? '#ffffff' : theme === 'blue' ? '#15273d' : '#24283b', diff --git a/frontend/src/index.css b/frontend/src/index.css index c7b6ef5..6e30aa3 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -13,7 +13,7 @@ html.theme-light { --text: #0f172a; --muted: #64748b; - --border: #e2e8f0; + --border: #cbd5e1; --danger: #dc2626; --success: #16a34a; diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css index 4dc67bf..6a5094f 100644 --- a/frontend/src/styles/app.css +++ b/frontend/src/styles/app.css @@ -452,7 +452,7 @@ img.bizcare-logo--header { max-width: min(100%, 560px); } .stock-title-actions .sheet-notice { white-space: nowrap; } -.stock-filter-card { margin-bottom: 12px; border-color: #dfe5ec; } +.stock-filter-card { margin-bottom: 12px; border-color: var(--border); } .stock-filter-card .ant-card-body { padding: 12px 14px; } .stock-filter-row { display: flex; align-items: center; gap: 6px; min-height: 39px; flex-wrap: wrap; } .stock-filter-row .ant-form-item { margin: 3px 0; } @@ -494,12 +494,17 @@ img.bizcare-logo--header { display: contents; } .w-100 { width: 100px; }.w-110 { width: 110px; }.w-120 { width: 120px; }.w-130 { width: 130px; }.w-150 { width: 150px; }.w-170 { width: 170px; }.w-230 { width: 230px; } -.stock-table-card { border-color: #dfe5ec; } +.stock-table-card { border-color: var(--border); } .stock-table-card .ant-card-body { padding: 0 12px 12px; } .stock-table-actions { display: flex; justify-content: space-between; align-items: center; } .stock-table-actions .ant-tabs { margin-bottom: 0; } .stock-table-card .ant-table { font-size: 12px; } -.stock-table-card .ant-table-thead > tr > th { white-space: nowrap; color: #536273; background: #f6f8fa; padding: 9px 7px; } +.stock-table-card .ant-table-thead > tr > th { + white-space: nowrap; + color: var(--muted); + background: var(--surface-2); + padding: 9px 7px; +} .stock-table-card .ant-table-tbody > tr > td { padding: 8px 7px; white-space: nowrap; } /* 목록 공통 정렬: 헤더·일반 텍스트 중앙, 숫자/금액 우측 */ @@ -3307,37 +3312,63 @@ html.theme-blue .ant-btn-text { color: var(--text) !important; } -/* 다크/블루: 목록 체크박스 대비 강화 */ -html.theme-dark .ant-checkbox .ant-checkbox-inner, -html.theme-blue .ant-checkbox .ant-checkbox-inner { - background-color: color-mix(in srgb, var(--surface) 70%, #000) !important; - border-color: color-mix(in srgb, var(--text) 55%, transparent) !important; +/* 목록·폼 체크박스 대비 (라이트/다크/블루 공통) */ +.ant-checkbox .ant-checkbox-inner { + background-color: var(--surface) !important; + border-color: color-mix(in srgb, var(--text) 45%, var(--border)) !important; border-width: 1.5px !important; } -html.theme-dark .ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner, -html.theme-blue .ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner, -html.theme-dark .ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover .ant-checkbox-inner, -html.theme-blue .ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover .ant-checkbox-inner { +.ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner, +.ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover .ant-checkbox-inner { border-color: var(--primary) !important; } -html.theme-dark .ant-checkbox-checked .ant-checkbox-inner, -html.theme-blue .ant-checkbox-checked .ant-checkbox-inner, -html.theme-dark .ant-checkbox-indeterminate .ant-checkbox-inner, -html.theme-blue .ant-checkbox-indeterminate .ant-checkbox-inner { +.ant-checkbox-checked .ant-checkbox-inner, +.ant-checkbox-indeterminate .ant-checkbox-inner { background-color: var(--primary) !important; border-color: var(--primary) !important; } -html.theme-dark .ant-checkbox-checked .ant-checkbox-inner::after, -html.theme-blue .ant-checkbox-checked .ant-checkbox-inner::after { - border-color: var(--on-primary) !important; +.ant-checkbox-checked .ant-checkbox-inner::after { + border-color: #fff !important; } -html.theme-dark .ant-checkbox-indeterminate .ant-checkbox-inner::after, -html.theme-blue .ant-checkbox-indeterminate .ant-checkbox-inner::after { - background-color: var(--on-primary) !important; +.ant-checkbox-indeterminate .ant-checkbox-inner::after { + background-color: #fff !important; } -html.theme-dark .ant-table-selection-column .ant-checkbox-inner, -html.theme-blue .ant-table-selection-column .ant-checkbox-inner { - box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 18%, transparent); +.ant-table-selection-column .ant-checkbox-inner, +table.order-list .col-chk .ant-checkbox-inner { + box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 12%, transparent); +} +/* 라이트: 흰 배경에 묻히지 않도록 테두리·그림자 강화 */ +html.theme-light .ant-checkbox .ant-checkbox-inner { + background-color: #fff !important; + border-color: #64748b !important; + border-width: 1.5px !important; +} +html.theme-light .ant-checkbox:not(.ant-checkbox-disabled):hover .ant-checkbox-inner, +html.theme-light .ant-checkbox-wrapper:not(.ant-checkbox-wrapper-disabled):hover .ant-checkbox-inner { + border-color: var(--primary) !important; +} +html.theme-light .ant-checkbox-checked .ant-checkbox-inner, +html.theme-light .ant-checkbox-indeterminate .ant-checkbox-inner { + background-color: var(--primary) !important; + border-color: var(--primary) !important; +} +html.theme-light .ant-table-selection-column .ant-checkbox-inner, +html.theme-light table.order-list .col-chk .ant-checkbox-inner { + box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.18); +} +/* 네이티브 checkbox (멀티셀렉트 등) */ +input[type='checkbox'] { + accent-color: var(--primary); + width: 14px; + height: 14px; + flex-shrink: 0; + cursor: pointer; +} +html.theme-light input[type='checkbox'] { + accent-color: var(--primary); + outline: 1px solid #64748b; + outline-offset: 0; + border-radius: 2px; } /* ===== 공통 드래그 타이틀바 모달 (antd v6: container) ===== */ @@ -4979,23 +5010,90 @@ table.order-list .floating-cell:hover .floating-layer { display: block; } color: #fff !important; } -/* Ant Table bordered — 접수리스트(order-list)와 유사한 행·열 구분선 */ -.ant-table-bordered .ant-table-container, -.ant-table-bordered .ant-table-container table { - border-color: var(--border) !important; +/* 목록 그리드 — 접수리스트(order-list)와 동일하게 행·열 구분선 강제 + * Ant Design 기본 borderColor(rgba 6%)는 라이트에서 거의 안 보임 */ +.ant-table-wrapper .ant-table-container { + border: 1px solid var(--border) !important; + border-radius: 0 !important; } -.ant-table-bordered .ant-table-thead > tr > th, -.ant-table-bordered .ant-table-tbody > tr > td, -.ant-table-bordered .ant-table-summary > tr > th, -.ant-table-bordered .ant-table-summary > tr > td { - border-color: var(--border) !important; +.ant-table-wrapper .ant-table-container table { + border-collapse: collapse !important; } -html.theme-light .ant-table-bordered .ant-table-thead > tr > th, -html.theme-light .ant-table-bordered .ant-table-tbody > tr > td { - border-color: #d9dee5 !important; +.ant-table-wrapper .ant-table-container table > thead > tr > th, +.ant-table-wrapper .ant-table-container table > tbody > tr > th, +.ant-table-wrapper .ant-table-container table > tbody > tr > td, +.ant-table-wrapper .ant-table-container table > tfoot > tr > th, +.ant-table-wrapper .ant-table-container table > tfoot > tr > td { + border: 1px solid var(--border) !important; + border-inline-end: 1px solid var(--border) !important; + border-bottom: 1px solid var(--border) !important; +} +/* 헤더 기본 세로 스플리터(::before)는 셀 border와 중복되므로 숨김 */ +.ant-table-wrapper .ant-table-thead > tr > th::before { + display: none !important; + background: transparent !important; + width: 0 !important; + content: none !important; +} +/* 스크롤 측정용 행은 구분선/높이 제외 */ +.ant-table-wrapper .ant-table-measure-row > th, +.ant-table-wrapper .ant-table-measure-row > td { + border: 0 !important; + padding: 0 !important; + height: 0 !important; +} +html.theme-light .ant-table-wrapper .ant-table-container, +html.theme-light .ant-table-wrapper .ant-table-container table > thead > tr > th, +html.theme-light .ant-table-wrapper .ant-table-container table > tbody > tr > th, +html.theme-light .ant-table-wrapper .ant-table-container table > tbody > tr > td, +html.theme-light .ant-table-wrapper .ant-table-container table > tfoot > tr > th, +html.theme-light .ant-table-wrapper .ant-table-container table > tfoot > tr > td { + border-color: #c9d1d9 !important; +} +html.theme-dark .ant-table-wrapper .ant-table-container, +html.theme-dark .ant-table-wrapper .ant-table-container table > thead > tr > th, +html.theme-dark .ant-table-wrapper .ant-table-container table > tbody > tr > th, +html.theme-dark .ant-table-wrapper .ant-table-container table > tbody > tr > td, +html.theme-blue .ant-table-wrapper .ant-table-container, +html.theme-blue .ant-table-wrapper .ant-table-container table > thead > tr > th, +html.theme-blue .ant-table-wrapper .ant-table-container table > tbody > tr > th, +html.theme-blue .ant-table-wrapper .ant-table-container table > tbody > tr > td { + border-color: color-mix(in srgb, var(--text) 28%, transparent) !important; } -/* 라이트 모드: 액션 버튼 = 파란 배경 + 흰 텍스트로 통일 (primary와 동일) */ +/* 라이트: Input/Select/Picker 테두리도 테마에 맞게 선명하게 */ +html.theme-light .ant-input, +html.theme-light .ant-input-affix-wrapper, +html.theme-light .ant-input-number, +html.theme-light .ant-picker, +html.theme-light .ant-select:not(.ant-select-customize-input) .ant-select-selector { + border-color: #cbd5e1 !important; +} +html.theme-light .ant-input:hover, +html.theme-light .ant-input-affix-wrapper:hover, +html.theme-light .ant-picker:hover, +html.theme-light .ant-select:not(.ant-select-disabled):hover .ant-select-selector { + border-color: var(--primary) !important; +} +html.theme-light .ant-input:focus, +html.theme-light .ant-input-affix-wrapper-focused, +html.theme-light .ant-picker-focused, +html.theme-light .ant-select-focused:not(.ant-select-disabled):not(.ant-select-customize-input) .ant-select-selector { + border-color: var(--primary) !important; + box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 22%, transparent) !important; +} +html.theme-light .ant-radio-wrapper .ant-radio-inner { + border-color: #64748b !important; + border-width: 1.5px !important; + background: #fff !important; +} +html.theme-light .ant-radio-wrapper .ant-radio-checked .ant-radio-inner { + border-color: var(--primary) !important; + background: #fff !important; +} +html.theme-light .ant-radio-wrapper .ant-radio-checked .ant-radio-inner::after { + background-color: var(--primary) !important; +} html.theme-light .ant-btn.ant-btn-default:not(.ant-btn-dangerous):not(.ant-btn-disabled):not(:disabled), html.theme-light .ant-btn.ant-btn-dashed:not(.ant-btn-dangerous):not(.ant-btn-disabled):not(:disabled) { background: var(--primary) !important;