refactor: toggles CSS를 Tailwind + @wing/ui로 전환

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
htlee 2026-02-17 06:18:57 +09:00
부모 e9a41c6663
커밋 2adcbc9a93
7개의 변경된 파일41개의 추가작업 그리고 108개의 파일을 삭제

파일 보기

@ -6,9 +6,8 @@
@import "./styles/base.css";
/* Components (layout.css, topbar.css → inline Tailwind) */
/* Components (layout/topbar/toggles → inline Tailwind + @wing/ui) */
@import "./styles/components/panels.css";
@import "./styles/components/toggles.css";
@import "./styles/components/speed.css";
@import "./styles/components/vessel-list.css";
@import "./styles/components/ais-list.css";

파일 보기

@ -1,75 +0,0 @@
/* Type grid */
.tg {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3px;
}
.tb {
background: var(--card);
border: 1px solid transparent;
border-radius: 5px;
padding: 4px;
cursor: pointer;
text-align: center;
transition: all 0.15s;
user-select: none;
}
.tb:hover {
border-color: var(--border);
}
.tb.on {
border-color: var(--accent);
background: rgba(59, 130, 246, 0.1);
}
.tb .c {
font-size: 11px;
font-weight: 800;
}
.tb .n {
font-size: 8px;
color: var(--muted);
}
/* Toggles */
.tog {
display: flex;
gap: 3px;
flex-wrap: wrap;
margin-bottom: 6px;
}
.tog.tog-map {
/* Keep "지도 표시 설정" buttons in a predictable 2-row layout (4 columns). */
gap: 4px;
}
.tog.tog-map .tog-btn {
flex: 1 1 calc(25% - 4px);
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tog-btn {
font-size: 8px;
padding: 2px 6px;
border-radius: 3px;
border: 1px solid var(--border);
background: var(--card);
color: var(--muted);
cursor: pointer;
transition: all 0.15s;
user-select: none;
}
.tog-btn.on {
background: var(--accent);
color: #fff;
border-color: var(--accent);
}

파일 보기

@ -1,3 +1,4 @@
import { ToggleButton } from '@wing/ui';
import type { Map3DSettings } from "../../widgets/map3d/Map3D";
type Props = {
@ -13,11 +14,11 @@ export function Map3DSettingsToggles({ value, onToggle }: Props) {
];
return (
<div className="tog">
<div className="flex flex-wrap gap-0.75 mb-1.5">
{items.map((t) => (
<div key={t.id} className={`tog-btn ${value[t.id] ? "on" : ""}`} onClick={() => onToggle(t.id)}>
<ToggleButton key={t.id} on={value[t.id]} onClick={() => onToggle(t.id)}>
{t.label}
</div>
</ToggleButton>
))}
</div>
);

파일 보기

@ -146,8 +146,7 @@ export function MapSettingsPanel({ value, onChange }: MapSettingsPanelProps) {
<div className="ms-label" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<span
className={`tog-btn${autoGradient ? ' on' : ''}`}
style={{ fontSize: 8, padding: '1px 5px', marginLeft: 8 }}
className={`ml-2 cursor-pointer rounded border px-1.5 py-px text-[8px] transition-all duration-150 select-none ${autoGradient ? 'border-wing-accent bg-wing-accent text-white' : 'border-wing-border bg-wing-card text-wing-muted'}`}
onClick={toggleAutoGradient}
title="최소/최대 색상 기준으로 중간 구간을 자동 보간합니다"
>
@ -176,11 +175,11 @@ export function MapSettingsPanel({ value, onChange }: MapSettingsPanelProps) {
{/* ── Depth font size ───────────────────────────── */}
<div className="ms-section">
<div className="ms-label"> </div>
<div className="tog" style={{ gap: 3 }}>
<div className="flex flex-wrap gap-0.75">
{FONT_SIZES.map((fs) => (
<div
key={fs.value}
className={`tog-btn${value.depthFontSize === fs.value ? ' on' : ''}`}
className={`cursor-pointer rounded border px-1.5 py-0.5 text-[8px] transition-all duration-150 select-none ${value.depthFontSize === fs.value ? 'border-wing-accent bg-wing-accent text-white' : 'border-wing-border bg-wing-card text-wing-muted'}`}
onClick={() => update('depthFontSize', fs.value)}
>
{fs.label}

파일 보기

@ -1,3 +1,5 @@
import { ToggleButton } from '@wing/ui';
export type MapToggleState = {
pairLines: boolean;
pairRange: boolean;
@ -27,11 +29,16 @@ export function MapToggles({ value, onToggle }: Props) {
];
return (
<div className="tog tog-map">
<div className="flex flex-wrap gap-1">
{items.map((t) => (
<div key={t.id} className={`tog-btn ${value[t.id] ? "on" : ""}`} onClick={() => onToggle(t.id)}>
<ToggleButton
key={t.id}
on={value[t.id]}
onClick={() => onToggle(t.id)}
className="flex-[1_1_calc(25%-4px)] overflow-hidden text-center text-ellipsis whitespace-nowrap"
>
{t.label}
</div>
</ToggleButton>
))}
</div>
);

파일 보기

@ -9,26 +9,26 @@ type Props = {
onToggleAll: () => void;
};
const TB = "cursor-pointer rounded-[5px] border p-1 text-center transition-all duration-150 select-none";
const TB_ON = "border-wing-accent bg-wing-accent/10";
const TB_OFF = "border-transparent bg-wing-card hover:border-wing-border";
export function TypeFilterGrid({ enabled, totalCount, countsByType, onToggle, onToggleAll }: Props) {
const allOn = VESSEL_TYPE_ORDER.every((c) => enabled[c]);
return (
<div className="tg">
<div className={`tb ${allOn ? "on" : ""}`} onClick={onToggleAll} style={{ gridColumn: "1/-1" }}>
<div className="c" style={{ color: "var(--accent)" }}>
</div>
<div className="n">{totalCount}</div>
<div className="grid grid-cols-3 gap-0.75">
<div className={`col-span-full ${TB} ${allOn ? TB_ON : TB_OFF}`} onClick={onToggleAll}>
<div className="text-[11px] font-extrabold text-wing-accent"></div>
<div className="text-[8px] text-wing-muted">{totalCount}</div>
</div>
{VESSEL_TYPE_ORDER.map((code) => {
const t = VESSEL_TYPES[code];
const cnt = countsByType[code] ?? 0;
return (
<div key={code} className={`tb ${enabled[code] ? "on" : ""}`} onClick={() => onToggle(code)}>
<div className="c" style={{ color: t.color }}>
{code}
</div>
<div className="n">{cnt}</div>
<div key={code} className={`${TB} ${enabled[code] ? TB_ON : TB_OFF}`} onClick={() => onToggle(code)}>
<div className="text-[11px] font-extrabold" style={{ color: t.color }}>{code}</div>
<div className="text-[8px] text-wing-muted">{cnt}</div>
</div>
);
})}

파일 보기

@ -1,3 +1,4 @@
import { ToggleButton } from '@wing/ui';
import type { AisTarget } from '../../entities/aisTarget/model/types';
import type { LegacyVesselIndex } from '../../entities/legacyVessel/lib';
import type { LegacyVesselDataset, LegacyVesselInfo } from '../../entities/legacyVessel/model/types';
@ -97,9 +98,9 @@ export function DashboardSidebar({
<div className="flex flex-col overflow-y-auto border-r border-wing-border bg-wing-surface max-md:hidden">
<div className="sb">
<div className="sb-t"> </div>
<div className="tog">
<div
className={`tog-btn ${showTargets ? 'on' : ''}`}
<div className="flex flex-wrap gap-0.75 mb-1.5">
<ToggleButton
on={showTargets}
onClick={() => {
setShowTargets((v) => {
const next = !v;
@ -110,10 +111,10 @@ export function DashboardSidebar({
title="레거시(CN permit) 대상 선박 표시"
>
</div>
<div className={`tog-btn ${showOthers ? 'on' : ''}`} onClick={() => setShowOthers((v) => !v)} title="대상 외 AIS 선박 표시">
</ToggleButton>
<ToggleButton on={showOthers} onClick={() => setShowOthers((v) => !v)} title="대상 외 AIS 선박 표시">
AIS
</div>
</ToggleButton>
</div>
<TypeFilterGrid
enabled={typeEnabled}
@ -138,14 +139,15 @@ export function DashboardSidebar({
<div className="sb-t" style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ flex: 1 }} />
<div
className={`tog-btn ${projection === 'globe' ? 'on' : ''}${isProjectionToggleDisabled ? ' disabled' : ''}`}
<ToggleButton
on={projection === 'globe'}
onClick={isProjectionToggleDisabled ? undefined : () => setProjection((p) => (p === 'globe' ? 'mercator' : 'globe'))}
title={isProjectionToggleDisabled ? '3D 모드 준비 중...' : '3D 지구본 투영: 드래그로 회전, 휠로 확대/축소'}
style={{ fontSize: 9, padding: '2px 8px', opacity: isProjectionToggleDisabled ? 0.4 : 1, cursor: isProjectionToggleDisabled ? 'not-allowed' : 'pointer' }}
className="px-2 py-0.5 text-[9px]"
style={{ opacity: isProjectionToggleDisabled ? 0.4 : 1, cursor: isProjectionToggleDisabled ? 'not-allowed' : 'pointer' }}
>
3D
</div>
</ToggleButton>
</div>
<MapToggles value={overlays} onToggle={(k) => setOverlays((prev) => ({ ...prev, [k]: !prev[k] }))} />
</div>