사이드바 패널
context.ui.setPanel (sidebar 필요, sandboxed)
섹션 제목: “context.ui.setPanel (sidebar 필요, sandboxed)”sandboxed 플러그인은 사이드바에 자기 패널을 세 개까지 둘 수 있습니다. 패널마다 활동 표시줄에 버튼이 하나 생기고, 패널은
Baram이 그리는 머리 — 패널 제목과 플러그인 · 뒤의 플러그인 이름 — 아래에서 사이드바를 채웁니다. 패널의 내용은
문자열로 보냅니다. 코드 블록 렌더러가 돌려주는 것과 같은 HTML과 CSS이고, Baram이
그것을 걸러 패널만의 shadow root에 그립니다.
trusted 플러그인은 대신 ctx.ui.addSidebarPanel로 패널에 자기 DOM을 붙입니다 —
컨텍스트: UI 와 Shadow DOM 격리를 보십시오.
setPanel(id: string, content: RenderedContent): void;onPanelAction(id: string, handler: (action: string) => Promise<void> | void): Disposable;
// RenderedContent = { html: string; css?: string }패널 선언
섹션 제목: “패널 선언”모든 패널을 매니페스트에 sidebar 권한과 함께 선언합니다.
{ "trust": "sandboxed", "capabilities": ["sidebar", "files:readonly"], "contributions": { "panels": [{ "id": "recent", "title": "Recent notes", "icon": "🕘" }] }}- 패널은 최대 3개입니다.
id는 영문자, 숫자,_,-로 64자까지이고 한 번씩만 씁니다.title은 비어 있지 않은 글이며, Baram이 그것을 걸러 64자로 줄이고 남는 것이 없으면 패널의id를 보입니다.icon을 주면 한 글자 — 이모지나 문자 하나 — 이고 UTF-16으로 16 단위까지입니다. 아이콘이 없거나, 아무것도 그리지 않는 것(예: 공백, 줄바꿈, 폭 없는 결합자, 변이 선택자 하나, 한글 채움 문자)이면 버튼에 일반 플러그인 아이콘이 나옵니다. sidebar권한이 없는panels는 매니페스트 오류이고, trusted 매니페스트의panels도 오류입니다.- 버튼은 플러그인 코드가 돌기 전에 나오므로 플러그인이 시작하는 동안에도 보입니다. 버튼의 이름은 패널 제목 뒤에
플러그인 ·과 플러그인 이름을 붙인 것이라, 패널이 Baram의 패널인 척할 수 없습니다. - 사용자는 매니페스트가 적은 권한 전부를 한 번의 답으로 승인합니다 — 플러그인을 설치할 때, 그리고 업데이트가 권한을
더할 때 다시. 그래서
sidebar없이 설치하는 길은 없습니다. Baram이sidebar를 주지 않는 것은 플러그인에 기록된 승인이 그것을 담지 않을 때뿐입니다. 그때는 패널 버튼이 나오지 않고 Baram이setPanel을 하나하나 거부합니다 — throw하지 않으므로 플러그인은 오류를 받지 않습니다.
내용 보내기
섹션 제목: “내용 보내기”const escape = (text: string) => text.replace(/[&<>"]/g, (c) => `&#${c.charCodeAt(0)};`);
export function activate(ctx: SandboxContext) { const draw = async () => { const names = (await ctx.files.listDir("")).filter((n) => n.endsWith(".md")); ctx.ui.setPanel("recent", { html: `<ul>${names .map((n) => `<li><a data-note="${escape(n)}">${escape(n)}</a></li>`) .join("")}</ul>`, css: "ul { margin: 0; padding: 0 12px; }", }); }; void draw(); ctx.events.on("vault:changed", () => void draw());}setPanel은 선언하지 않은 id와 상한을 넘는 내용 — UTF-8로 HTML 1 MiB나 CSS 64 KiB를 넘거나, 고립 서로게이트(이모지의 반쪽)가 든 것 — 에 곧바로 throw합니다. 문구는 렌더러의 결과가 받는 것과 같습니다.- Baram은 패널마다 마지막 내용을 기억합니다. 화면에 없는 패널은 그리지 않고, 사용자가 패널을 열면 마지막으로 받은 내용을 그립니다.
setPanel은 얼마든지 자주 불러도 됩니다. 가장 최근 내용이 이기고, Baram은 화면에 있는 패널을 250밀리초에 한 번까지 그립니다. 앞 호출이 아직 가는 동안 한 호출은 보낼 차례를 기다리는 내용을 바꾸므로, 마지막 내용은 늘 도착합니다.- 첫
setPanel전에는 패널에 아직 보일 것이 없다고 나옵니다.
돌려줄 수 있는 것
섹션 제목: “돌려줄 수 있는 것”Baram은 패널의 내용을 코드 블록 렌더러의 결과처럼 거릅니다 — 무엇이 지워지거나 거부되는지와 상한은 돌려줄 수 있는 것을 보십시오. 다른 점은 둘입니다.
- 패널은 사이드바 안에서 세로로 스크롤되고 자기 높이 상한이 없습니다. 옆으로는 스크롤되지 않습니다 — 사이드바보다
넓은 부분은 잘리므로, 넓은 내용은
overflow-x: auto를 준 자기 요소에 담으십시오. - 거부된 CSS나 노드 상한을 넘은 내용은 패널 머리 아래에
그리지 못했습니다 —와 이유를 한 줄로 보이고, 마지막 그림은 흐리게 남습니다.
클릭은 코드 블록에서처럼 판정됩니다 — 클릭을 보십시오. 다른 점은 이렇습니다.
data-note="notes/a.md"는 사용자가 누를 때 활성인 볼트나 폴더의 루트 기준입니다 — 패널은 어느 노트에도 속하지 않습니다. 활성인 볼트나 폴더가 없거나 그 경로가 거기 있는 노트가 아니면 아무것도 열지 않고 Baram이 그렇게 알립니다.data-note와context없는listDir("")가 늘 같은 볼트를 읽는 것은 아닙니다. 클릭은 앱이 활성으로 보이는 볼트나 폴더를 쓰고,listDir는 Baram의 백엔드가 활성으로 쥔 것을 씁니다. 둘은 다를 수 있습니다 — 예를 들어 단일 파일로 연 노트가 활성인 동안(클릭은 아무것도 열지 않지만listDir("")는 그 전에 활성이던 볼트나 폴더를 여전히 나열할 수 있습니다)과 볼트를 바꾸는 잠깐 동안입니다. 볼트를 직접 고르려면listDir("", { context })에context를 넘기십시오.vault:changed(files나files:readonly가 필요합니다)나file:open(events가 필요합니다)에서 다시 그리면 되고, 둘 다 자기가 가리키는context를 싣습니다.data-action="name"은onPanelAction(id, handler)로 그 패널에 등록한 핸들러를 부르고, 핸들러마다 그 이름을 받습니다. 모든 핸들러가 끝날 때까지ctx.prompts를 열 수 있습니다 — 명령이 도는 30초와 같고, 클릭부터, 그리고 선택창이나 입력창이 닫힐 때마다 다시 흐릅니다.onPanelAction은 선언하지 않은 id에 throw합니다.- 오른쪽 클릭은 이 가운데 아무것도 하지 않습니다.
패널을 보이거나 그리는 것만으로는 아무 권리도 생기지 않습니다. 플러그인이 선택창을 열 수 있는 것은 data-action 요소를
누를 때뿐입니다.
Baram 저장소에는 패널을 쓰는 예제 플러그인이 없습니다. examples/plugins/backlinks-block이 같은 종류의 내용을 코드
블록에 그립니다.
버전 하한
섹션 제목: “버전 하한”ctx.ui.setPanel, ctx.ui.onPanelAction, contributions.panels는 새 API입니다. engines.baram을 릴리스 노트에 이것이
처음 실린 버전으로 적으십시오 — 버전 하한을 보십시오.

