fix(화면): 패널 높이·접힘이 탭을 새로 열 때마다 초기화되던 것
화면 취향까지 sessionStorage 에 있어 **탭을 새로 열거나 브라우저를 껐다 켜면** 패널 높이· 접힘·유토곡선 열림이 매번 초기화됐음. 계획서에는 「PC 를 바꾸면」으로 적혀 있었으나 실제 불편은 훨씬 잦았음(사용자 승인 뒤 조사에서 드러남). - 저장소를 통(bucket)으로 가름 — **`pref` 만 localStorage**, 초안·결과는 세션 그대로. 설계 데이터가 아니므로 CLAUDE.md 5장 「캐시=세션」에 걸리지 않음. - 키만 들고 저장소를 직접 만지던 화면 공용 부품 셋(`ui_template_resizer`·`_overlay`· `_overlay_drag`)이 같은 판단(`storageOf`)을 쓰게 함 — 안 그러면 높이 값만 세션에 남아 절반만 옮겨졌음(실측: 접힘 4개는 옮겨지고 높이 3개는 안 옮겨짐). - 첫 로드 때 세션에 남은 옛 취향을 한 번 쓸어 옮김 — 이 변경으로 쓰던 크기가 초기화되지 않게. 실측(공용 브라우저) — 옮긴 뒤 취향 8개 전부 localStorage, 세션 0개, 높이 보존 (종단 438px · 표 204px). **새 탭에서도 8개 그대로**(같은 값). 검증 탭은 닫음. 시험 `tmp/tests/test_prefs_persist_across_tabs.py` 4건 — 취향만 갈리는지 · 초안·결과는 세션인지 · 공용 부품이 같은 판단을 쓰는지 · 옛 값을 한 번 옮기는지. 이 조각은 DB 없이 되는 몫임. 계정 저장(`018_user_ui_prefs`)은 다음 단계. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -202,10 +202,55 @@ export function stateKey(
|
||||
return `${head}:${projectId}:${routeId}`;
|
||||
}
|
||||
|
||||
/** 세션 접근은 저장소가 막힌 브라우저(사생활 보호)에서 던진다 — 전부 조용히 넘긴다. */
|
||||
/**
|
||||
* 어느 저장소에 둘지 — **화면 취향(`pref`)만 `localStorage`**, 나머지는 세션이다.
|
||||
*
|
||||
* 2026-09-07 확인 — 취향까지 세션에 있어 **탭을 새로 열거나 브라우저를 껐다 켤 때마다**
|
||||
* 패널 높이·접힘이 초기화됐다(계획서에는 「PC 를 바꾸면」으로 적혀 있었으나 실제 불편은
|
||||
* 훨씬 잦았다). 취향은 설계 데이터가 아니므로 5장 「캐시=세션」 규칙에 걸리지 않는다 —
|
||||
* **설계값·초안·계산 결과는 세션 그대로** 둔다(그 경계를 흐리지 말 것).
|
||||
*/
|
||||
function storageFor(key: string): Storage {
|
||||
return key.startsWith("aislo:pref:") ? window.localStorage : window.sessionStorage;
|
||||
}
|
||||
|
||||
/** 위와 같은 판단을 **키만 들고 저장소를 직접 만지는 화면 공용 부품**에 내준다
|
||||
* (`ui_template_resizer`·`ui_template_overlay`·`ui_template_overlay_drag`).
|
||||
* 그 부품들은 등록표에서 받은 키로 높이·열림·자리를 저장하는데, 여기를 안 거치면
|
||||
* 취향만 세션에 남아 탭을 새로 열 때마다 초기화된다. */
|
||||
export function storageOf(key: string): Storage {
|
||||
return storageFor(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션에 남아 있던 옛 취향을 **한 번에 브라우저 저장소로 옮긴다**(2026-09-07).
|
||||
*
|
||||
* 취향을 쓰는 화면 부품(높이 조절자·접이식 패널)은 키만 들고 저장소를 직접 만지므로
|
||||
* 읽는 자리마다 건져 올리는 방식으로는 **높이 값이 안 옮겨졌다**(실측: 접힘 4개는 옮겨지고
|
||||
* 높이 3개는 세션에 남음). 그래서 첫 로드 때 한 번 쓸어 옮긴다 — 쓰던 패널 크기가
|
||||
* 이 변경 때문에 초기화되지 않게 한다. 여러 번 불려도 안전하다.
|
||||
*/
|
||||
function liftPrefsToLocalStorage(): void {
|
||||
try {
|
||||
const stale = Object.keys(window.sessionStorage).filter((key) => key.startsWith("aislo:pref:"));
|
||||
for (const key of stale) {
|
||||
const value = window.sessionStorage.getItem(key);
|
||||
if (value !== null && window.localStorage.getItem(key) === null) {
|
||||
window.localStorage.setItem(key, value);
|
||||
}
|
||||
window.sessionStorage.removeItem(key);
|
||||
}
|
||||
} catch {
|
||||
/* 저장소가 막힌 브라우저 — 취향은 이번 세션 동안 화면 메모리로만 산다. */
|
||||
}
|
||||
}
|
||||
|
||||
liftPrefsToLocalStorage();
|
||||
|
||||
/** 저장소 접근은 막힌 브라우저(사생활 보호)에서 던진다 — 전부 조용히 넘긴다. */
|
||||
function readRaw(key: string): string | null {
|
||||
try {
|
||||
return window.sessionStorage.getItem(key);
|
||||
return storageFor(key).getItem(key);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -213,8 +258,9 @@ function readRaw(key: string): string | null {
|
||||
|
||||
function writeRaw(key: string, value: string | null): void {
|
||||
try {
|
||||
if (value === null) window.sessionStorage.removeItem(key);
|
||||
else window.sessionStorage.setItem(key, value);
|
||||
const store = storageFor(key);
|
||||
if (value === null) store.removeItem(key);
|
||||
else store.setItem(key, value);
|
||||
} catch {
|
||||
/* 무시 — 값은 화면 메모리에 남는다. */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user