/** * SatelliteRequest.tsx 디자인 시스템 적용 스크립트 * 실행: node scripts/fix-satellite-request.mjs */ import { readFileSync, writeFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, resolve } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const filePath = resolve(__dirname, '../frontend/src/tabs/aerial/components/SatelliteRequest.tsx'); let src = readFileSync(filePath, 'utf-8'); // ──────────────────────────────────────────────────── // 작업 1: UI 개선 // ──────────────────────────────────────────────────── // 1-1. stats 배열 color 필드 제거 src = src.replace( `const stats = [ { value: '3', label: '요청 대기', color: 'var(--color-info)' }, { value: '1', label: '촬영 진행 중', color: 'var(--color-caution)' }, { value: '7', label: '수신 완료', color: 'var(--color-success)' }, { value: '0.5m', label: '최고 해상도', color: 'var(--color-accent)' }, ];`, `const stats = [ { value: '3', label: '요청 대기' }, { value: '1', label: '촬영 진행 중' }, { value: '7', label: '수신 완료' }, { value: '0.5m', label: '최고 해상도' }, ];` ); // 1-1. stats 값 div: style color 제거, text-fg 추가 src = src.replace( `
`, `
` ); // 1-2. 예상수신 컬럼 style 제거 src = src.replace( `
{r.expectedReceive}
`, `
{r.expectedReceive}
` ); // 1-2. 해상도 컬럼 style 제거 src = src.replace( `
{r.resolution}
`, `
{r.resolution}
` ); // 1-3. statusBadge 아이콘 제거 src = src.replace(` ⏳ 대기`, ` 대기`); src = src.replace(` ✕ 취소`, ` 취소`); src = src.replace(` ✅ 완료`, ` 완료`); // 1-4. 촬영 가능 시간 스타일 변경 src = src.replace( `
{passSchedules.map((ps, i) => (
{ps.time} {ps.desc}
))}`, `
{passSchedules.map((ps, i) => (
{ps.time} {ps.desc}
))}` ); // ──────────────────────────────────────────────────── // 작업 2: rgba 비-accent → color-mix 전환 // ──────────────────────────────────────────────────── // 제외 구간 마킹: up42Satellites 배열 (L181-310 범위)은 보호 // 전략: 배열 부분을 임시 플레이스홀더로 치환 → bulk 작업 → 복원 const UP42_PLACEHOLDER = '___UP42_SATELLITES_PLACEHOLDER___'; const up42StartMarker = '// UP42 위성 카탈로그 데이터\nconst up42Satellites = ['; const up42EndMarker = '];\n\n// up42Passes'; const up42Start = src.indexOf(up42StartMarker); const up42End = src.indexOf(up42EndMarker) + up42EndMarker.length; if (up42Start === -1 || up42End === -1) { console.error('up42Satellites 배열을 찾지 못했습니다. 스크립트를 중단합니다.'); process.exit(1); } const up42Block = src.slice(up42Start, up42End); src = src.slice(0, up42Start) + UP42_PLACEHOLDER + src.slice(up42End); // --- rgba → color-mix 전환 --- // 매핑 함수 function pct(alpha) { // alpha: 문자열 (예: ".15", "0.15", ".5", "0.5") const n = parseFloat(alpha); return Math.round(n * 100) + '%'; } // 정규식 패턴: rgba(R,G,B,A) 형태를 매칭 (공백 허용) // 각 색상별로 처리 // rgba(59,130,246,N) → info src = src.replace(/rgba\(59,\s*130,\s*246,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--color-info) ${pct(alpha)}, transparent)`; }); // rgba(99,102,241,N) → info (보라 계열도 info로) src = src.replace(/rgba\(99,\s*102,\s*241,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--color-info) ${pct(alpha)}, transparent)`; }); // rgba(34,197,94,N) → success src = src.replace(/rgba\(34,\s*197,\s*94,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--color-success) ${pct(alpha)}, transparent)`; }); // rgba(239,68,68,N) → danger src = src.replace(/rgba\(239,\s*68,\s*68,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--color-danger) ${pct(alpha)}, transparent)`; }); // rgba(234,179,8,N) → caution src = src.replace(/rgba\(234,\s*179,\s*8,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--color-caution) ${pct(alpha)}, transparent)`; }); // rgba(100,116,139,N) → fg-disabled src = src.replace(/rgba\(100,\s*116,\s*139,\s*([\d.]+)\)/g, (match, alpha) => { return `color-mix(in srgb, var(--fg-disabled) ${pct(alpha)}, transparent)`; }); // Tailwind className 내 변환 // border-[rgba(59,130,246,.3)] → border-[rgba(6,182,212,0.3)] src = src.replace(/border-\[rgba\(59,130,246,\.3\)\]/g, 'border-[rgba(6,182,212,0.3)]'); src = src.replace(/hover:border-\[rgba\(59,130,246,\.5\)\]/g, 'hover:border-[rgba(6,182,212,0.4)]'); src = src.replace(/hover:bg-\[rgba\(59,130,246,\.04\)\]/g, 'hover:bg-[rgba(6,182,212,0.04)]'); // className 내 border-[rgba(99,102,241,...)] 는 그대로 유지 (위성 식별용이 아닌 UI 요소) // → 이미 위 정규식으로 style 속성 내는 변환됨. className 내의 것은 별도 처리 src = src.replace(/border-\[rgba\(99,102,241,\.3\)\]/g, 'border-[rgba(6,182,212,0.3)]'); src = src.replace(/hover:border-\[rgba\(99,102,241,\.5\)\]/g, 'hover:border-[rgba(6,182,212,0.4)]'); src = src.replace(/hover:bg-\[rgba\(99,102,241,\.04\)\]/g, 'hover:bg-[rgba(6,182,212,0.04)]'); // up42 블록 복원 src = src.replace(UP42_PLACEHOLDER, up42Block); // ──────────────────────────────────────────────────── // 작업 3: 나머지 하드코딩 색상 // ──────────────────────────────────────────────────── // urgency '예정' color: '#06b6d4' → 'var(--color-accent)' // L2122 근처: urgency === '예정' ? '#06b6d4' 패턴 src = src.replace( ` ? '#06b6d4'`, ` ? 'var(--color-accent)'` ); // UP42 제출 버튼 전체 변경 (color '#fff' → 'var(--color-accent)', boxShadow 제거) src = src.replace( `