chatmu 전시장

컴포넌트를 격리해서 여러 상태로 늘어놓는 자리다. 여기 있는 것은 실제 소스이고 데이터만 fixture 다 — 베낀 화면이 아니라서 원본이 바뀌면 여기도 함께 바뀐다.

묶음 — 첫 줄과 이어 말한 줄

같은 Actor 가 같은 분에 이어 말하면 아바타·이름·시각이 첫 줄에만 선다. 이어 말한 줄에서 그 셋은 사라지는 것이 아니라 접힌다 — 아바타 자리는 빈 칸이 지키고, 이름과 시각은 `.srOnly` 로 남아 읽는 기계에는 그대로 들린다.

김
김소리04:12

묶음의 첫 줄이다 — 아바타·이름·시각이 함께 선다.

김소리04:12

이어 말한 줄. 본문의 왼쪽 시작점이 위와 똑같은 것이 요점이다.

김소리04:12

세 번째 줄도 마찬가지다. 묶음은 여섯 줄까지 이어진다.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

남이 쓴 줄 · 봇이 쓴 줄

「고치기·지우기」는 내 줄에만 선다 — 남의 것은 서버가 어차피 거절하지만, 누를 수 없는 버튼을 보여줄 이유가 없다. 사람 아닌 화자는 `bot` 배지를 달고, 아바타도 그 배지와 같은 색이다(표식이 하나로 읽혀야 한다).

AK
Alex Kim04:12

남이 쓴 줄이다. 위에 마우스를 얹어도 버튼이 안 뜬다.

D
deploybotbot04:12

배포가 끝났습니다. chatmu-local → 초록.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

(수정됨) — 고친 적이 있는 줄

`(수정됨)` 은 되풀이되지 않는 사실이라 묶음의 몇 번째 줄이든 가려지지 않는다. 마지막 블록이 문단이면 글자 끝에 붙고, 고친 적이 없으면 이 상자를 아예 안 그린다.

김
김소리04:12

이 줄은 한 번 고쳐졌다.

(수정됨)
김소리04:12

이 줄은 안 고쳤다 — 그래서 표식 상자가 아예 없다.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

자국 — 보고 있던 줄이 지워졌다

내가 그리고 있던 줄이 지워지면 본문 자리에 낱말 하나가 남는다. 이름·아바타·시각은 평소대로다 — 자국도 그 사람이 그때 말한 자리라, 묶음의 첫 줄이면 이름과 시각이 거기 선다. 버튼도 `(수정됨)` 도 안 뜬다(이미 거둔 것이고, 지우기는 수정이 아니다). ⚠️ 본 적 없는 줄이 지워진 채로 오면 이 칸의 모양조차 안 나온다 — 목록에 아예 안 들어오고, 그 갈림은 화면이 아니라 `lib/roomTimeline.ts` 가 한다.

김
김소리04:12

[메시지 삭제됨]

김소리04:12

자국 뒤에 이어 말한 줄. 자국이 줄 하나를 차지하므로 묶음이 안 끊긴다.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

아직 안 간 줄 — 보내는 중 · 발신 실패

확정된 것과 같은 모양으로 그린다 — 서버가 id 를 주는 순간 서식이 튀면 안 된다. 다른 것은 셋뿐이다: 시각이 없고(서버가 아직 안 줬다), 버튼이 없고, 실패하면 다시 보낼 길이 선다. 실패를 삼키면 사용자는 안 간 Message 를 갔다고 믿는다.

김
김소리

지금 보내는 중이다.

보내는 중…
김소리

이건 못 갔다.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

긴 본문

본문 칸은 오른쪽에 버튼 자리 88px 을 늘 비워 둔다 — 겹쳐 뜬 버튼이 글자를 가리지 않는 것을 겹침 판정이 아니라 자리를 아예 안 주는 것으로 보장한다.

김
김소리04:12

긴 본문은 묶음 판정에도 걸린다 — 다섯 줄을 넘으면 그 줄은 덩어리로 쳐서 뒤를 새 묶음으로 끊는다(isBlockBody). 여기서 보는 것은 그 판정이 아니라 한 줄이 길어졌을 때의 모양이다: 본문 칸이 오른쪽 버튼 자리(88px)를 넘지 않는지, 줄 간격이 목록의 밀도와 맞는지.

문단이 갈리면 빈 줄이 하나 들어간다. 그리고 마지막 문단이 문단인 한, (수정됨) 과 보내는 중… 은 그 문단의 마지막 줄에 붙는다 — 상자가 아니라 흐름이 그 자리를 정한다.

세 번째 문단이다. 여기까지 와도 왼쪽 시작점은 흔들리지 않는다 — 아바타 칸이 늘 같은 폭을 지키기 때문이다.

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

코드블록 — 마지막 블록이 문단이 아닐 때

고정폭 자리는 Cascadia Mono 다(우리 오리진에서 온다). 마지막 블록이 문단이 아니면 `(수정됨)` 이 붙을 줄이 없어 아래로 떨어진다 — 이 줄은 그 아래에 문단이 하나 더 있다.

김
김소리04:12

배포가 이렇게 끝났다:

export function messageRowKey(row: GroupedItem): string {
  return row.kind === 'sent' ? `sent-${row.id}` : `pending-${row.clientMessageId}`;
}

⚠️ 마지막 블록이 문단이 아니면 (수정됨) 이 아래로 떨어진다 — 붙일 줄이 없어서다.

(수정됨)

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

표

본문 안의 상자는 남이 보낸 마크다운이 그린 것이다 — 우리는 흐름만 정한다.

김
김소리04:12
무엇열둘지금
넘기는 것128
그중 state·ref40

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

mermaid

` ```mermaid ` 블록만 다른 곳으로 넘어간다(`lib/mermaidBlock.ts`). 화면에 들어올 때 비로소 내려받고, 결과는 우리가 만든 `sandbox=""` iframe 에 얹힌다 — 알아보지 못하면 코드블록으로 남는다.

김
김소리04:12
graph LR
  P["방 화면"] -->|"row · 신호 다섯"| R["MessageRow"]
  R --> B["messageBody"]
  R --> A["actorAvatar"]

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

아래 네 칸은 손으로 적은 목록이 아니다. 하나는 왕복이 맞는 경우이고, 나머지 셋은 lib/editSurface.ts 의 EditFallbackReason 을 순회한 것이다 — 폴백 사유가 늘면 칸이 저절로 하나 더 서고, 없어지면 컴파일이 막는다. 제목 옆의 표식은 fixture 가 주장하는 것이 아니라 editSurfaceFor 가 그 본문에 실제로 대답한 값이다.

고치기 — 쓸 때와 같은 편집기

editor

왕복이 확인된 본문만 여기로 온다. 보이는 그대로이고 화면에 별표가 없다. 툴바는 없다 — Message 줄마다 툴바가 들어차면 목록이 안 읽힌다. 폼 안의 버튼은 저장·취소 둘뿐이다.

김
김소리04:12

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

고치기 — 폴백 (unknownFormat)

fallback · unknownFormat

형식이 `markdown` 이 아니다 — 모르는 형식은 추측해서 읽지 않는다 (ADR 0010). 폴백은 지금의 textarea 이고, 왜 화면이 다른지를 위의 한 줄이 말한다 — 모르면 고장으로 읽힌다.

김
김소리04:12

text/plain 형식은 편집기가 다루지 못해 원문 그대로 엽니다 — 고치지 않은 곳은 그대로 저장됩니다

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

고치기 — 폴백 (unsupportedNode)

fallback · unsupportedNode

`markdownToPlateNodes` 가 던진다. 안 잡으면 「고치기」를 누르는 순간 화면이 터진다. 폴백은 지금의 textarea 이고, 왜 화면이 다른지를 위의 한 줄이 말한다 — 모르면 고장으로 읽힌다.

김
김소리04:12

편집기가 이 글의 서식을 온전히 다루지 못해 원문 그대로 엽니다 — 고치지 않은 곳은 그대로 저장됩니다

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

고치기 — 폴백 (roundTripChanged)

fallback · roundTripChanged

던지지는 않는데 왕복 결과가 정규형과 다르다. 아무도 안 알려 주므로 셋 중 가장 위험하다. 폴백은 지금의 textarea 이고, 왜 화면이 다른지를 위의 한 줄이 말한다 — 모르면 고장으로 읽힌다.

김
김소리04:12

편집기가 이 글의 서식을 온전히 다루지 못해 원문 그대로 엽니다 — 고치지 않은 곳은 그대로 저장됩니다

마지막 신호

아직 없다 — 줄 위에 마우스를 얹으면 「고치기·지우기」가 나타난다

「지우기」를 눌러도 아무것도 안 지워진다. 전시장에는 지울 곳이 없어서다 — 대신 그 신호가 칸 아래에 찍힌다. 줄이 바깥으로 내는 것은 신호 다섯 (onStartEdit · onSaveEdit · onCancelEdit · onDelete · onRetry)뿐이고, 정말로 고치고 지우고 다시 보내는 일은 방 화면의 것이다.

이 화면을 열면 마지막 고치기 칸으로 훌쩍 내려간다 — 고장이 아니다. 폴백 textarea 에 autoFocus 가 걸려 있어서다. 방에서는 한 번에 하나만 열리므로 그것이 옳지만(키보드로 「고치기」를 누른 사람이 초점을 잃지 않는다), 넷이 한꺼번에 뜨는 이 화면에서는 마지막 것이 이긴다. 전시장이 처음으로 만든 자리다 — 폼이 컴포넌트가 되면서 둘이 동시에 뜰 수 있게 됐고, 안내 문구를 잇는 aria-describedby 가 여기서도 안 엉키는 것은 MessageEditSession 이 고정 id 대신 useId 를 쓰기 때문이다.

「표」 칸에서 「고치기」를 눌러 보면 폴백으로 열린다. 표는 마크다운 층이 읽고 쓸 줄 알지만 구분선의 모양이 왕복에서 달라진다 — 던지지 않고 조용히 달라지는 쪽이라roundTripChanged 로 걸린다. 이것은 전시장이 만든 것이 아니라 앱의 지금 동작이고, fixture 목록의 정본은 app/gallery/messageFixtures.ts 다.