/* Main — 방사형 허브 + 배치 변형 */ /* ---- 업무영역 카드 내용 편집 저장소 (세이프스쿨 전용) ---------------- 기본값은 SS_DATA.AREAS, 편집분만 localStorage에 덮어쓰기로 보관 */ const SS_AREAS_KEY = "ss-areas-override-v1"; function loadAreaOverrides() { try { return JSON.parse(localStorage.getItem(SS_AREAS_KEY)) || {}; } catch (e) { return {}; } } function saveAreaOverrides(ov) { try { localStorage.setItem(SS_AREAS_KEY, JSON.stringify(ov)); } catch (e) {} } function mergeAreas(overrides) { return window.SS_DATA.AREAS.map((a) => { const o = overrides[a.id]; return o ? { ...a, ...o } : a; }); } /* ---- 카드별 보조 박스 (세이프스쿨이 사진/안내 입력 → 학교가 열람) ---- 내용이 비면 학교·미리보기에서는 아예 보이지 않음 */ const SS_EXTRA_KEY = "ss-area-extra-v1"; function loadAreaExtras() { try { return JSON.parse(localStorage.getItem(SS_EXTRA_KEY)) || {}; } catch (e) { return {}; } } function saveAreaExtras(ex) { try { localStorage.setItem(SS_EXTRA_KEY, JSON.stringify(ex)); } catch (e) {} } // 업로드 사진을 캔버스로 축소해 dataURL로 (localStorage 용량 보호) function fileToScaledDataURL(file, maxW, cb) { const reader = new FileReader(); reader.onload = () => { const img = new Image(); img.onload = () => { const scale = Math.min(1, maxW / img.width); const w = Math.round(img.width * scale), h = Math.round(img.height * scale); const cv = document.createElement("canvas"); cv.width = w; cv.height = h; cv.getContext("2d").drawImage(img, 0, 0, w, h); cb(cv.toDataURL("image/jpeg", 0.82)); }; img.src = reader.result; }; reader.readAsDataURL(file); } function AreaExtra({ extra, editing, onText, onPhoto, onClearPhoto }) { const fileRef = useRef(null); const ex = extra || {}; const hasContent = !!(ex.text || ex.img); const handleFile = (e) => { const f = e.target.files && e.target.files[0]; if (!f) return; fileToScaledDataURL(f, 720, (dataURL) => onPhoto(dataURL)); e.target.value = ""; }; // 편집 모드가 아니면 — 내용이 있을 때만 노출 (학교 담당자 / 세이프스쿨 미리보기) if (!editing) { if (!hasContent) return null; return (
{ex.img && } {ex.text &&

{ex.text}

}
); } // 편집 모드 (세이프스쿨 전용) — 항상 입력 affordance 표시 return (
e.stopPropagation()}>
학교 안내 (선택)
{ex.img && (
)}