Friday, 31 July 2026
File tree UX improvements, page editor toolbar, EditorConsole message system, console-panel tab.
Before this fix, calling refresh() on file-tree-panel
collapsed all open directories. The fix records which ftp-dir elements
carry the open class (via data-path on their
ftp-dir-label) before rebuilding the HTML, then re-adds
open to the matching labels after the new tree renders.
The double-click listener on ftp-dir-label was removed.
"As Root Directory" is now a context menu entry that appears when right-clicking
a directory, inside the existing showItemMenu() method.
isDir detection uses targetPath.endsWith('/').
When right-clicking a file that has a known editor, the context menu shows an
Open > submenu listing the default editor plus all registered
alternatives. Selecting an entry calls _openFileIn(path, editorTag),
which focuses an existing tab of that type or creates a new one.
Two static maps drive this:
_panelTypeMap (editorTag → panelType + label) and
_editorAlternatives (defaultEditorTag → alternativeEditorTags[]).
_openFileDefault (single click) focuses the file in any open editor
regardless of type; _openFileIn (context menu) focuses only in the
specified editor type.
The context menu title now shows only the filename (not the full path), truncated
to a configurable menuLabelMaxChars (20). Names longer than the limit
are shown as ...last-20-chars.
The left sidebar (.pep-sidebar) and its wrapper (.pep-main)
were removed. The Blocks (⊞) and Areas (T) mode buttons were moved directly into
.pep-toolbar, separated from the left-side toolbar items by a
.pep-toolbar-sep spacer (flex: 1) that pushes them to
the right. page-editor-panel now uses flex-direction: column
with three direct children: toolbar, mode panel, iframe.
New singleton EditorConsole (source/editor/EditorConsole.ts)
holds a capped ring of 500 ConsoleMessage objects
(text, type: 'info'|'error'|'hint',
timestamp) and dispatches them via onMessage: EventSlot.
showHover / hideHover dispatch a secondary
onHover: EventSlot<string | null> for future tooltip use.
editor-shell subscribes to onMessage and shows incoming
messages in a new .es-info element in the header — fades in for 5 s
then fades out. Portrait mode hides the inline element and would show a fixed bottom
bar instead. Editor.get().onFileTypeUnknown is now handled here,
logging to EditorConsole rather than as an inline error in
file-tree-panel.
console-panel is a new tab that renders all messages from
EditorConsole. Custom elements: conp-header,
conp-title, conp-list, conp-entry,
conp-time, conp-text. On connect it pre-populates
from EditorConsole.get().messages, then appends new entries as they
arrive. Time format: HH:MM:SS. Entry classes (conp-entry-error,
conp-entry-hint) colour conp-text accordingly.
Implements EditorPanelDefinition.type via __interfaces__.
openDocumentIn ignored the target panel type
Editor.openDocumentIn(filePath, panelElement) was re-resolving
editorTag from the FileEditorRegistry, which always
returned the default editor for the file type (e.g. page-editor-panel
for .page files). The code-panel listener checked
if ('code-panel' !== e.editorTag) return and bailed, so the file
appeared to open but showed no content.
Fix: derive editorTag from panelElement.tagName.toLowerCase()
directly, removing the registry lookup entirely from openDocumentIn.
The caller already decided which panel to target; the dispatch should respect that
decision.
EditorConsole as a standalone singleton, not part of
Editor.
Keeping it separate means any component (including future non-editor panels) can
import just EditorConsole without pulling in the full editor state.
Editor.onFileTypeUnknown is bridged to it in editor-shell,
the single component that knows about both.
Two open-file methods instead of one.
_openFileDefault (single click) focuses the file in any editor;
_openFileIn (context menu "Open >") focuses only in the specified
editor type and forces that type when creating a new tab. This makes the intent
explicit without adding a flag parameter.