Repository navigation
feat(fragments): move a section, page or component between sites with its styles - #640
Draft
DavidBabinec wants to merge 13 commits into
Draft
DavidBabinec wants to merge 13 commits into
DavidBabinec wants to merge 13 commits into
Conversation
A fragment is one versioned file that carries a section, a page or a Visual Component with everything it needs to render in another site: classes and the ambient rules built on them, conditions, the component closure, the tokens its styles read, the tables its loops and forms use, its media and its page links. extractFragment builds one from a live site or a site-transfer bundle, and the barrel stays headless so build scripts can import it under Bun.
planFragmentInsert decides everything an insert adds without touching the site: fresh node ids, classes and components reused by name, ambient rules and conditions only when missing, colours added with their full definitions, scale steps slotted into the site's own groups without moving the base, tables matched by slug, links remapped by slug or turned into "#", and the same outlet and component cycle guards saved layouts use. The report lists every addition so nothing changes silently.
commitFragmentPlan runs the server work first (media reused by name and size or uploaded, fonts installed or registered, tables and rows created, missing fields appended), resolves the plan against the ids that produced, then hands it to the editor's new fragments slice, which applies it in one store transaction and regenerates framework utilities when the insert added a colour or a scale step. A failed upload or table write stops before the document is touched.
"Insert fragment from file..." opens a dialog that reads a fragment package, plans the insert against the open document, and shows what it will add and what it keeps from the site before anything changes. Insert runs the commit and the dialog then lists what was added, including links that became "#", rules the fragment depended on through its old parents, and other notes.
Creating a data table is a sensitive action, so the first real insert of a fragment with a loop or a form failed with step_up_required. Every server write of the insert now goes through runStepUp, which asks for the password and retries, and closing that prompt reads as a cancelled insert. The report also stops listing an empty media row.
New sites now start with font-heading, font-body and font-mono, so a fragment's token of the same name is kept and the family the fragment bound to it is no longer needed. The planner now installs a family only when an added token binds to it or a carried rule names it, so inserting into a new site never downloads a font or uploads a font file for a token the site keeps.
Adds the feature doc (format, closure, merge rules, commit, script usage) and links it from the docs that describe paste, saved layouts, Spotlight, HTML import, site import and site transfer. Also records the new headless gate, the shared style rule registry helpers, the fragments store slice, and refreshes the gate counts.
After an insert the new section stays selected, and the paste rule put the next fragment inside that container, so two sections inserted in a row ended up nested. Fragments now land as the next sibling of the selection, or at the end of the document.
The fragment engine carried its own copies of helpers Instatic already has: the root-scope selector test from the site importer, the repeater-aware media id walk from the data.rows loop source, the framework class id prefix, the condition registration the paste and site import paths both inline, the page ref builder, the subtree id map and the error message helper. Each copy was a second place to keep in step. The shared ones now live in core (isRootScopeSelector in page-tree, collectCellMediaIds in data/cells, addMissingConditions in page-tree, FRAMEWORK_ID_PREFIX exported from the framework) and every caller, old and new, goes through them. It also drops what nothing used: the extractor's mediaSrc option (no caller passes it), the plan's create flag on custom properties (apply looks the rule up itself), a second copy of the font-family scan, and the move of indexStyleRulesByName into core, which only the editor store needs.
…bilities for fragments The insert fragment slice compared documents with its own copy of isSameActiveDocument, and the Spotlight command restated the site-write capability list editor.ts already defines. Both now import the existing ones. The dialog prints the fragment kind directly instead of mapping each kind to itself, the command's keywords drop "library", which suggested a feature that does not exist, and the headless gate no longer describes who runs the build scripts.
Five test files each rebuilt the same source, extracted the same hero section, and the plan and commit tests restated the same plan and adapter setup in every case. A fixture helper extracts once per file and the plan and commit tests build their target through one function. Planning and extraction are pure, so sharing the result changes no assertion: the same 60 tests run the same 253 expectations.
…importer The reference listed indexStyleRulesByName as shared page-tree API, but it stays with the editor store's import linking; the helpers fragments really share with site import and HTML paste are the order allocator, the root-scope selector test and condition registration.
Unresolved links are reported in report.links.unresolved, never as a link-unresolved warning, so the code only widened the union UI code has to handle. The token planner also stops returning its family reuse map, which only it reads.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A site fragment is a portable piece of a site: a section, a page or a component, with everything it needs to render the same elsewhere (classes and selectors, conditions, components, tokens, scale steps, tables, media).
src/core/fragmentsextracts one from a live site or a transfer archive and plans its insert into another site, and Spotlight Insert fragment from file… shows that plan, inserts it as one undo step, and reports what was added or kept. Helpers shared with site import and paste live once in core.Why
Copy and paste and saved layouts only work inside one site: they match classes by id and drop the selectors, conditions, tokens and media a section depends on. Moving a section between sites meant rebuilding its styles by hand. The insert never overwrites anything the site already has, and only fetches the media the plan adds.
Verification
Unit tests use synthetic sites. In a browser, two sections from two other sites went into a third: styles, images and a looped table survived, both landed as siblings, and the published page matched the editor.