Slate is a local-first Markdown viewer plugin for Workshop. It turns explicitly configured local Markdown files into clean reference views without copying their content to a server, repository, or cloud service.
Slate is the tool's source-of-truth repository. Workshop is the desktop host:
it provides the desktop frame, promotion state, and constrained local-source
capabilities. Slate exports workshopPluginDeclaration and
WorkshopToolView; it reads only declared sources through the generic host
capabilities read_configured_markdown_sources,
read_configured_markdown_source, start_configured_markdown_watch, and the
optional, narrow configuration-management pair
read_configured_markdown_config / write_configured_markdown_config.
It has peer dependencies on React and @tauri-apps/api.
Slate's neutral view props also support an optional browseWorkspaceRoot()
callback. A desktop host can use it to open its own native folder chooser and
return { ok: true, root }; Slate then places that absolute path in the setup
field for review before the user connects it. Cancellation returns undefined
or { ok: false, canceled: true } and changes nothing. Slate does not import a
dialog plugin or gain filesystem discovery through this callback.
The optional browseMarkdownFile(currentPath?) callback provides the same
host-owned boundary for a single Markdown file. It returns { ok: true, path }
after a user chooses an existing absolute .md or .markdown file. Extensions
are matched case-insensitively. Slate places that path in
the unsaved document draft; it does not persist anything until Save
documents is chosen. Cancellation preserves the draft, and hosts may return a
specific error for Slate to show. Slate does not import a native dialog package,
enumerate a directory, copy the file, or edit its contents.
When Slate is embedded in Workshop, it inherits Workshop's active semantic CSS
custom properties for canvas and surfaces, borders, text, accents, focus, status
colors, and gradients. A palette change therefore reaches Slate through the CSS
cascade immediately; it does not require a Slate rebuild, a source refresh, or
a change to slate.config.json.
The integration is progressive. Every host value is consumed with a Slate-owned
fallback, for example var(--workshop-canvas, #070708). When all host tokens are
absent—as they are in the local browser preview—those standalone fallbacks
preserve Slate's existing dark pink-and-yellow treatment. Slate does not import
Workshop source, depend on a Workshop palette id, or require a theme capability
to load.
Slate scopes its aliases and component rules beneath .slate-plugin, so it does
not restyle Workshop chrome or sibling plugins. Host applications may provide
any or all of these semantic variables:
--workshop-canvas
--workshop-surface
--workshop-surface-raised
--workshop-border
--workshop-text
--workshop-text-muted
--workshop-accent
--workshop-accent-strong
--workshop-accent-warm
--workshop-focus-ring
--workshop-success
--workshop-warning
--workshop-danger
--workshop-gradient-start
--workshop-gradient-middle
--workshop-gradient-end
Slate accepts safe http, https, and mailto links in configured Markdown.
In a browser preview, those links behave as ordinary browser links. In Workshop,
Slate uses the optional generic open_external_url host capability to hand the
link to the operating system's default handler. Slate does not bundle a Tauri
opener plugin. If an older Workshop install does not provide that capability,
Slate shows an update message instead of opening a dead webview tab.
Each person keeps their filled-in configuration outside this repository and outside Workshop's public repository. The configuration can list any number of unique local Markdown files.
In Slate, select Connect a Slate folder, then enter the absolute path to an
existing private folder containing slate.config.json. When the host provides
its folder-picker callback, Browse… opens the host's folder chooser and
places the selection in the same field; review it, then choose Connect
folder or press Enter. Canceling the chooser preserves the current field and
connection. Once connected, use Change Slate folder from the source chooser
to replace it. Workshop keeps
the selected folder path as local UI state, so reopening the app or renewing
OS folder access does not require re-entering it. Use Disconnect to forget
that local selection; the folder, configuration, Markdown files, and source
data remain untouched. Slate never scans the folder or creates configuration
for you: it reads only the Markdown files explicitly declared in that
configuration.
Slate reads the sources array in your private slate.config.json. Use
Manage documents in Slate to add, edit, remove, and validate that
list without editing JSON. Save validates every id, label, view, duplicate
path, and absolute Markdown path; Workshop then writes only the existing
slate.config.json in the selected private folder. It will not create a
configuration file, discover documents, or edit any Markdown file. A failed
save leaves the draft visible with an error so it can be corrected or canceled.
The manager permits an empty document list. That leaves Slate connected and
shows its "No documents configured" state until a source is added again.
Slate preserves the existing configuration order internally, but does not expose
ordering controls because the visible home shelves are always alphabetized by
label. New documents are appended to the private configuration.
Each source needs a unique lowercase, hyphenated id, a human-readable
label, an absolute Markdown path, and a supported view.
{
"version": 1,
"sources": [
{
"id": "tasks",
"label": "Tasks",
"path": "/absolute/path/to/tasks.md",
"view": "markdown-tabs"
},
{
"id": "notes",
"label": "Notes",
"path": "/absolute/path/to/notes.md",
"view": "markdown"
},
{
"id": "inventory",
"label": "Inventory",
"path": "/absolute/path/to/inventory.md",
"view": "table"
},
{
"id": "archive",
"label": "Archive",
"path": "/absolute/path/to/archive.md",
"view": "table-tabs"
}
]
}Supported views:
markdown-tabsgroups top-level Markdown headings into tabs. Valid Markdown tables render in place inside their owning tab and retain Slate's sortable column controls; a table is never borrowed from another tab. Content before the first heading stays above the tabs.markdownpreserves a single, scrollable Markdown view. Valid Markdown tables render in place among the surrounding headings, prose, and lists and retain Slate's sortable column controls. A heading is optional.tablerenders the largest valid Markdown table in the file, keeping its source columns and row order. This lets a file include a small legend or key before its primary data table. “Largest” means the most body rows; if tables tie, Slate uses the first one. A valid table needs a header row and Markdown separator row.table-tabskeeps a divider-delimited document title and intro above a row of tabs, then renders the largest valid Markdown table inside the selected top-level-heading tab. Tables are never selected from another tab. A tab with no valid table shows an in-place message instead of failing the document.
All four views use the same table tokenizer, including support for escaped
literal pipes (\|) inside cells, optional leading and trailing table pipes,
left/center/right separator alignment, and safe inline links. Sorting is
UI-only: it never changes the Markdown file or writes a reordered copy.
Malformed table syntax remains visible as text in markdown and
markdown-tabs rather than silently disappearing. Table examples inside
backtick or tilde code fences remain ordinary text rather than sortable tables
and are not selected by table views.
Slate alphabetizes source cards by their visible labels. The manager’s order is
preserved in the private configuration for intentional source ordering, while
the picker continues to alphabetize the visible cards. A user can toggle the
star in the upper-right corner of any source card to place it in a Favorites
section above the remaining documents; both sections remain alphabetized.
When no source is starred, Slate shows only the normal source grid—there is no
empty Favorites section. Favorites are a Slate-local preference scoped to the
selected private workspace. They do not modify slate.config.json, Markdown
files, or Workshop, and they do not sync across computers.
Filled favorite stars deliberately remain yellow across host themes so the
learned favorite signal does not change when the surrounding palette does.
Slate stores no source content. The host may read only the absolute paths that the user placed in their private configuration; it must not search directories, discover fallback files, upload content, or persist a second copy. Do not commit filled-in configuration files, real source files, screenshots, local paths, or personal data.
npm install
npm test
npm run test:coverage
npm run typecheck
npm run build
npm run public:check
npm run package:checkThe coverage gate requires at least 89% statement coverage, 95% line coverage, and 85% branch and function coverage across Slate's production TypeScript.
Run npm run preview:local for Slate's standalone fallbacks. Add
?host-theme=preview to that local URL to exercise the generic inherited-token
path with a representative non-Workshop test palette.