"Popup 은 tooltip. Side panel 은 dock. Track 4 는 ClipDeck 을 user 가 page 읽으면서 열어 둘 수 있는 surface 로 졸업시키기 — 책상 위 sticky note 와 notebook 의 차이."
Surface, 솔직하게
Side panel 은 Chrome 이 user tab 의 오른쪽 docked 영역에 렌더하는 extension-owned HTML document. 시각적으론 bookmark bar 와 toolbar 오른쪽 가장자리 사이. 기능적으론 popup 과 같은 extension page — 같은 chrome.* API access, 같은 isolated context, 같은 DevTools-inspectable.
핵심 차이는 lifetime: popup 은 user 가 다른 곳 click 하는 즉시 죽음; side panel 은 user 가 toolbar toggle 통해 명시적으로 닫을 때까지 열려 있음. ClipDeck 엔, user 가 article 읽으면서 clip list visible 하게 유지하고 저장 사이 아무것도 다시 열지 안 하고 새 clip 연달아 추가 가능.
History
chrome.sidePanel 이 stable Chrome 114, 2023 중반쯤 도착. 그 전엔 docked sidebar 흉내 유일한 방법은 content script 통해 iframe inject — strict CSP 가진 site 에서 fragile, cross-origin embed 에서 broken, view-source page 에서 doomed. Stable API 가 page DOM 과 전혀 충돌 안 하는 Chrome-owned 영역 줘.
오늘 만드는 거면 minimum 으로 Chrome 114 가정. Firefox 는 다른 shape 의 자체 sidebar API; 이 lesson 은 Chrome-specific. Track 8 의 packaging note 가 끝에서 cross-browser 전략 살짝 다룸.
세 가지 user-facing behavior
Toolbar-icon click 으로 열림 (chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }) 로 구성). 발견 가장 쉬움.
API 호출로 열림 — user-gesture handler 에서: context-menu entry, keyboard command, 또는 chrome.sidePanel.open() trigger 하는 popup 의 버튼. Custom shortcut bind 가능.
Tab switch 너머로 열려 있음 default 로. 표시된 panel content 는 tab 별로 바뀔 수 있지만 (다음 lesson 이 per-tab vs global 다룸), Chrome 이 user tab 전환 시 dock 자동 닫지 안 함.
안에 뭐가 살아
Side panel 은 그냥 panel.html 과 그 script / style. 원하는 거 뭐든 렌더 — vanilla DOM, React/Svelte/Solid app, self-hosted URL 가리키는 iframe. HTML 이 extension content security policy 아래 load 돼서, external script 와 inline event handler 는 CSP 넓히지 안 하면 차단 (Lesson 5 가 다룸).
Storage access 는 어디서나 같은 방식: mount 시 chrome.storage.local, live update 위해 chrome.storage.onChanged. SW 로 message passing 은 써 오던 같은 chrome.runtime.sendMessage.
왜 ClipDeck 이 panel 필요
Popup 이 첫 두 track 잘 봉사 — 작고, 빠르고, obvious. Clip 10 개 넘어가면 popup 답답. 50 개 넘어가면 unusable. Side panel 은 scale: timestamp / source URL / search / (Track 7) inline edit/delete affordance 가진 full-height list. Popup 은 quick-status surface ("오늘 clip 몇 개?") 와 "Open side panel" 버튼 hosting 자리로 계속 존재.
Popup = tooltip (transient, 작음, click 시 열림). Side panel = dock (persistent, full-height, dismiss 까지 유지). 다른 UX 니즈 cover; ClipDeck 은 둘 다 ship.
Chrome side panel vs Firefox sidebar. Chrome 의 chrome.sidePanel 과 Firefox 의 browser.sidebarAction 이 비슷해 보이지만 다른 lifecycle 모델과 살짝 다른 API. Cross-browser extension 은 보통 feature-detect 하고 두 구현 ship. 이 quest 는 Chrome 에 머묾; ClipDeck v2 가 Firefox parity 추가할 수도, 별개 관심사.
Code
manifest.json — version 0.6.0, side_panel.default_path 선언·json
첫 번째 code block 의 manifest 변경 적용 (version 0.6.0, side_panel.default_path: "panel.html", permission 에 "sidePanel"). clipdeck/panel.html 과 clipdeck/panel.js 를 두 번째 / 세 번째 code block 으로 생성. Extension reload. ClipDeck toolbar icon click — popup 여전히 나타나야 함, panel 은 아직 아님 (openPanelOnActionClick 아직 활성화 안 함). 이제 Chrome toolbar 의 side-panel toggle (Chrome 버전에 따라 puzzle-piece menu 나 dedicated side panel icon) click 하고 ClipDeck 선택. Panel 열림. Track 3 exercise 에서 저장한 clip 있으면 보임; 없으면 Ctrl+Shift+K 로 몇 개 저장하고 panel 이 수동 refresh 없이 update 되는지 확인.
Hint
Side-panel toggle 에 ClipDeck 안 보이면 "sidePanel" 이 permissions 에 있고 side_panel.default_path 가 설정됐는지 확인, 다음 extension 완전 reload (chrome://extensions → ClipDeck → reload). Panel 열리는데 빈 page 보이면 panel DevTools (panel 안 어디든 우클릭 → Inspect) 열고 JS error 찾기 — 가장 흔한 게 <script src="panel.js"> 경로 typo. Panel 은 일반 extension page; popup 에 쓰는 같은 DevTools workflow 사용 가능.
Progress
Progress is local-only — sign in to sync across devices.