Friday, 25 July 2026
Page editor panel: structured .page format, block registry, rich-text toolbar, default theme.
html-editor-panel → page-editor-panel
The old HTML editor panel is replaced by page-editor-panel
(PageEditorPanel), handling .page files instead of
.html/.htm. All references updated across:
FileEditorRegistry.ts, editor.html,
editor-shell.ts, tab-container.ts,
file-tree-panel.ts. The old folder was deleted.
editor-shell no longer auto-opens index.html on startup
— the panel shows an empty state until the user opens a .page file
from the file tree.
.page format
A .page file is a full HTML document whose <body>
must contain exactly one <page-header>, one
<page-root>, and one <page-footer> as direct
children, in that order.
<page-root> holds any number of <page-block>
elements; each block contains one or more <page-area> elements
for rich-text content.
Format validation is a placeholder function (validatePageFormat) that
always returns true, documented for future implementation. When real
validation is added, invalid files fall back to code-panel.
Auto-template for empty files: when a .page file is
opened with empty content, validation is bypassed and the standard template
(full-width block, default theme) is injected automatically. The document is marked
dirty — the user must save to persist the structure.
Available block templates are defined in a static table
(PAGE_BLOCK_REGISTRY) in page-editor-panel.ts. Each
entry has a name, optional CSS-sketch preview markup
(using .pbp-* helper classes), and an html snippet
appended to <page-root> when selected. Two standard blocks ship:
<page-area> spanning the
full container width (pep-block-full).<page-area> elements
side by side on landscape; stacked top-to-bottom on portrait via a CSS media
query (pep-block-two-col).
Block items without a preview entry show their name as a text label
inside the preview box.
Two icon buttons on the left edge of the panel switch between editing modes:
<page-root> in the iframe and makes
its new <page-area> elements contenteditable immediately,
without a full re-render.B (bold), I (italic), U
(underline), then a separator, then H1, H2,
H3.wrapSelection
Formatting is applied via wrapSelection(doc, range, tagName, attributes?)
— no execCommand. The helper uses Range.extractContents()
to pull the selected fragment out of the DOM, wraps it in the target element
(created in the iframe document), and re-inserts via Range.insertNode().
The Range API automatically splits text nodes and element boundaries, so both
fully-contained nodes and boundary intersections are handled correctly.
Semantic tags are preferred: <b>, <i>,
<u>, <h1>–<h3>.
Adjacent identical elements are not merged after wrapping (future work, documented).
The editor iframe carries sandbox="allow-same-origin", blocking script
execution for user-authored <script> tags. The sandbox attribute
is documented as the single point to change if sandboxing needs adjustment.
Editor-side layout styles (PEP_EDITOR_STYLES) are injected into the
live iframe <head> post-load as
<style id="pep-editor-injected">. Before saving, the element is
temporarily removed, outerHTML is captured, then the element is
re-appended — so the injected styles never reach disk. The MutationObserver watches
only <page-root>, so head mutations do not trigger change events.
default-roject
All theme CSS rules are scoped to [data-theme="default-roject"].
The <body> and <page-root> in the standard
template both carry this attribute so the theme applies to the full document and
to all content inside blocks.
The theme CSS (DEFAULT_THEME_CSS) is embedded as a
<style> block in the page <head> for new
files. Future plan: replace with a <link> to
styles.rokojori.com when themes are hosted there.
Styles defined:
#0f1117), whitish copy (#c8cce0),
Barlow font via @import from styles.rokojori.com,
1rem / 1.7 line-height.h1: blue (#7c8cff), 2.5rem, 900 italic, uppercase.h2: blue (#7c8cff), 1.6rem, 700.h3: muted blue (#9ba4c7), 1.2rem, 700.b / strong: bright white (#e2e4ed).
Placeholder validation instead of gating immediately.
The real format check (exactly one page-header / page-root / page-footer in body,
no other elements) is documented but not enforced yet — validatePageFormat
always returns true. This keeps the editor usable while the format
stabilises, without hiding the validation contract.
wrapSelection for headings, not block-level replacement.
H1/H2/H3 buttons wrap the selection the same way as B/I/U rather than replacing
the parent block element. This is consistent with the existing system and avoids
the complexity of block-level conversion for now. The limitation is documented.
Theme attribute on both <body> and
<page-root>.
Putting data-theme on <body> lets the base styles
(background, font, colour) apply to the full document without a separate unscoped
body { } rule. <page-root> keeps its own attribute
for future per-block theme overrides.