feat(share): symbol page share button + distinguish note delete vs failure

- New ShareButton in the page header tries navigator.share() first
  (native sheet on mobile), then falls back to navigator.clipboard, then
  to a hidden textarea + execCommand("copy") for non-secure-context LAN.
  Shows a brief "링크 복사됨" / "복사 안됨" toast; native share success
  shows none (the OS sheet is the feedback).
- Mounted between ⇄ 비교 and the Star button.

Fixes reviewer concern on 442cc38: writeNote() used to return null for
both "user emptied the textarea (intentional delete)" and "localStorage
quota failure," so clearing a note showed "저장 안됨." It now returns a
discriminated { status: "saved" | "deleted" | "failed" } and the panel
shows "저장됨" / "삭제됨" / "저장 안됨" accordingly. Failure keeps the
user's text so they can retry or shorten it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-owner
2026-05-29 00:08:37 +09:00
parent 442cc38c32
commit f18493fad4
4 changed files with 129 additions and 10 deletions

View File

@@ -24,20 +24,25 @@ export function readNote(code: string): Note | null {
}
}
export function writeNote(code: string, text: string): Note | null {
if (typeof window === "undefined") return null;
export type WriteResult =
| { status: "saved"; note: Note }
| { status: "deleted" }
| { status: "failed" };
export function writeNote(code: string, text: string): WriteResult {
if (typeof window === "undefined") return { status: "failed" };
const trimmed = text.slice(0, MAX_LEN);
// 공백만이면 키 자체 제거 → 빈 잔여물 방지.
// 공백만이면 키 자체 제거 → 빈 잔여물 방지. 의도된 삭제이므로 failed 와 구분.
if (!trimmed.trim()) {
clearNote(code);
return null;
return { status: "deleted" };
}
const next: Note = { text: trimmed, updatedAt: new Date().toISOString() };
try {
window.localStorage.setItem(`${PREFIX}${code}`, JSON.stringify(next));
return next;
return { status: "saved", note: next };
} catch {
return null; // quota 등 — UI 가 저장 실패 처리
return { status: "failed" }; // quota 등 — UI 가 저장 실패 처리
}
}