astro-tractstack 2.0.18 → 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -32
- package/package.json +1 -1
- package/templates/src/components/codehooks/BunnyVideoSetup.tsx +1 -4
- package/templates/src/components/codehooks/FeaturedArticleSetup.tsx +0 -4
- package/templates/src/components/codehooks/ListContentSetup.tsx +1 -8
- package/templates/src/components/codehooks/ProductCardSetup.tsx +0 -2
- package/templates/src/components/codehooks/ProductGridSetup.tsx +0 -2
- package/templates/src/components/compositor/Compositor.tsx +3 -6
- package/templates/src/components/compositor/Node.tsx +13 -32
- package/templates/src/components/compositor/NodeWithGuid.tsx +49 -5
- package/templates/src/components/compositor/nodes/Pane.tsx +4 -21
- package/templates/src/components/compositor/nodes/Pane_DesignLibrary.tsx +27 -7
- package/templates/src/components/compositor/nodes/tagElements/NodeBasicTag.tsx +3 -1
- package/templates/src/components/compositor/preview/OgImagePreview.tsx +0 -5
- package/templates/src/components/compositor/preview/PaneSnapshotGenerator.tsx +5 -6
- package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +1 -0
- package/templates/src/components/edit/PanelSwitch.tsx +3 -24
- package/templates/src/components/edit/SettingsPanel.tsx +0 -1
- package/templates/src/components/edit/ToolMode.tsx +6 -14
- package/templates/src/components/edit/pane/AddPanePanel.tsx +45 -25
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +277 -70
- package/templates/src/components/edit/pane/AddPanePanel_paste.tsx +111 -0
- package/templates/src/components/edit/pane/RestylePaneModal.tsx +7 -14
- package/templates/src/components/edit/pane/steps/AiDesignStep.tsx +0 -5
- package/templates/src/components/edit/pane/steps/DesignLibraryStep.tsx +4 -11
- package/templates/src/components/edit/panels/StyleBreakPanel.tsx +1 -3
- package/templates/src/components/edit/panels/StyleElementPanel_update.tsx +0 -6
- package/templates/src/components/edit/panels/StyleImagePanel.tsx +0 -1
- package/templates/src/components/edit/panels/StyleImagePanel_update.tsx +0 -3
- package/templates/src/components/edit/panels/StyleLiElementPanel_update.tsx +0 -4
- package/templates/src/components/edit/panels/StyleLinkPanel_config.tsx +8 -5
- package/templates/src/components/edit/panels/StyleLinkPanel_update.tsx +1 -2
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +1 -3
- package/templates/src/components/edit/panels/StyleParentPanel_update.tsx +2 -5
- package/templates/src/components/edit/panels/StyleWidgetPanel_config.tsx +2 -8
- package/templates/src/components/edit/panels/StyleWidgetPanel_update.tsx +0 -4
- package/templates/src/components/edit/state/SaveToLibraryModal.tsx +27 -16
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +9 -26
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_og.tsx +7 -16
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_slug.tsx +5 -6
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +0 -5
- package/templates/src/components/fields/BackgroundImageWrapper.tsx +1 -7
- package/templates/src/components/fields/ColorPickerCombo.tsx +8 -12
- package/templates/src/components/fields/ViewportComboBox.tsx +4 -6
- package/templates/src/constants/prompts.json +22 -1
- package/templates/src/stores/nodes.ts +297 -222
- package/templates/src/stores/storykeep.ts +3 -3
- package/templates/src/types/compositorTypes.ts +21 -1
- package/templates/src/types/tractstack.ts +1 -0
- package/templates/src/utils/compositor/TemplatePanes.ts +0 -76
- package/templates/src/utils/compositor/aiPaneParser.ts +265 -83
- package/templates/src/utils/compositor/designLibraryHelper.ts +252 -26
- package/templates/src/utils/helpers.ts +5 -4
- package/utils/inject-files.ts +6 -32
- package/templates/src/components/compositor/preview/VisualBreakPreview.tsx +0 -154
- package/templates/src/components/edit/pane/PageGen_preview.tsx +0 -511
- package/templates/src/utils/compositor/processMarkdown.ts +0 -445
- package/templates/src/utils/compositor/templateMarkdownStyles.ts +0 -1273
|
@@ -38,6 +38,7 @@ import type {
|
|
|
38
38
|
PaneNode,
|
|
39
39
|
StoryFragmentNode,
|
|
40
40
|
Tag,
|
|
41
|
+
TemplateGridLayout,
|
|
41
42
|
TemplateMarkdown,
|
|
42
43
|
TemplateNode,
|
|
43
44
|
TemplatePane,
|
|
@@ -102,7 +103,6 @@ export class NodesContext {
|
|
|
102
103
|
toolAddModeStore = map<{ value: ToolAddMode }>({
|
|
103
104
|
value: 'p',
|
|
104
105
|
});
|
|
105
|
-
showGuids = atom<boolean>(false);
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* Sets an edit lock on a specific node to prevent re-renders during editing
|
|
@@ -1445,124 +1445,126 @@ export class NodesContext {
|
|
|
1445
1445
|
}
|
|
1446
1446
|
break;
|
|
1447
1447
|
|
|
1448
|
-
case 'TagElement':
|
|
1449
|
-
{
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
desktop: {},
|
|
1455
|
-
};
|
|
1448
|
+
case 'TagElement': {
|
|
1449
|
+
const getButtonClasses = (node: FlatNode) => {
|
|
1450
|
+
return {
|
|
1451
|
+
mobile: strippedStyles(node.buttonPayload?.buttonClasses || {}),
|
|
1452
|
+
tablet: {},
|
|
1453
|
+
desktop: {},
|
|
1456
1454
|
};
|
|
1455
|
+
};
|
|
1457
1456
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
};
|
|
1457
|
+
const getHoverClasses = (node: FlatNode) => {
|
|
1458
|
+
return {
|
|
1459
|
+
mobile: strippedStyles(
|
|
1460
|
+
node.buttonPayload?.buttonHoverClasses || {}
|
|
1461
|
+
),
|
|
1462
|
+
tablet: {},
|
|
1463
|
+
desktop: {},
|
|
1466
1464
|
};
|
|
1465
|
+
};
|
|
1467
1466
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1467
|
+
if (hasButtonPayload(node)) {
|
|
1468
|
+
const [classesPayload] = processClassesForViewports(
|
|
1469
|
+
getButtonClasses(node),
|
|
1470
|
+
{},
|
|
1471
|
+
1
|
|
1472
|
+
);
|
|
1473
|
+
const [classesHoverPayload] = processClassesForViewports(
|
|
1474
|
+
getHoverClasses(node),
|
|
1475
|
+
{},
|
|
1476
|
+
1
|
|
1477
|
+
);
|
|
1478
|
+
return `${classesPayload?.length ? classesPayload[0] : ``} ${
|
|
1479
|
+
classesHoverPayload?.length
|
|
1480
|
+
? addHoverPrefix(classesHoverPayload[0])
|
|
1481
|
+
: ``
|
|
1482
|
+
}`;
|
|
1483
|
+
}
|
|
1485
1484
|
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1485
|
+
if ('tagName' in node && node.tagName === 'span') {
|
|
1486
|
+
const spanNode = node as FlatNode;
|
|
1487
|
+
const [all, mobile, tablet, desktop] = processClassesForViewports(
|
|
1488
|
+
{ mobile: {}, tablet: {}, desktop: {} },
|
|
1489
|
+
spanNode.overrideClasses || {},
|
|
1490
|
+
1
|
|
1491
|
+
);
|
|
1492
|
+
const outlineClass =
|
|
1493
|
+
this.toolModeValStore.get().value === 'styles'
|
|
1494
|
+
? ' outline outline-1 outline-dotted outline-gray-400/60'
|
|
1495
|
+
: '';
|
|
1497
1496
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1497
|
+
const getClassString = (classes: string[]): string =>
|
|
1498
|
+
classes && classes.length > 0 ? classes[0] : '';
|
|
1500
1499
|
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
}
|
|
1500
|
+
if (isPreview) return getClassString(desktop) + outlineClass;
|
|
1501
|
+
switch (viewport) {
|
|
1502
|
+
case 'desktop':
|
|
1503
|
+
return getClassString(desktop) + outlineClass;
|
|
1504
|
+
case 'tablet':
|
|
1505
|
+
return getClassString(tablet) + outlineClass;
|
|
1506
|
+
case 'mobile':
|
|
1507
|
+
return getClassString(mobile) + outlineClass;
|
|
1508
|
+
default:
|
|
1509
|
+
return getClassString(all) + outlineClass;
|
|
1512
1510
|
}
|
|
1511
|
+
}
|
|
1513
1512
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1513
|
+
// Begin Default Class Lookup Logic
|
|
1514
|
+
const markdownParentId = this.getClosestNodeTypeFromId(
|
|
1515
|
+
nodeId,
|
|
1516
|
+
'Markdown'
|
|
1517
|
+
);
|
|
1518
|
+
if (!markdownParentId) break;
|
|
1520
1519
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
}
|
|
1520
|
+
const markdownParentNode = this.allNodes
|
|
1521
|
+
.get()
|
|
1522
|
+
.get(markdownParentId) as MarkdownPaneFragmentNode;
|
|
1523
|
+
if (!markdownParentNode) break;
|
|
1524
|
+
|
|
1525
|
+
const tagNameStr = (node as FlatNode).tagName as string;
|
|
1526
|
+
|
|
1527
|
+
// By default, assume the markdown node is the source of styles.
|
|
1528
|
+
let styleSourceNode: MarkdownPaneFragmentNode | GridLayoutNode =
|
|
1529
|
+
markdownParentNode;
|
|
1530
|
+
let styles = styleSourceNode.defaultClasses?.[tagNameStr];
|
|
1531
|
+
|
|
1532
|
+
// If the markdown node has no styles for this tag, check for a GridLayout grandparent.
|
|
1533
|
+
// This handles the case where the MarkdownNode is a column.
|
|
1534
|
+
if (!styles || Object.keys(styles.mobile).length === 0) {
|
|
1535
|
+
const grandparent = markdownParentNode.parentId
|
|
1536
|
+
? this.allNodes.get().get(markdownParentNode.parentId)
|
|
1537
|
+
: null;
|
|
1538
|
+
|
|
1539
|
+
if (grandparent && isGridLayoutNode(grandparent)) {
|
|
1540
|
+
styleSourceNode = grandparent;
|
|
1541
|
+
styles = styleSourceNode.defaultClasses?.[tagNameStr];
|
|
1544
1542
|
}
|
|
1543
|
+
}
|
|
1545
1544
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1545
|
+
const baseStyles =
|
|
1546
|
+
styles && styles.mobile
|
|
1547
|
+
? styles
|
|
1548
|
+
: { mobile: {}, tablet: {}, desktop: {} };
|
|
1549
|
+
|
|
1550
|
+
const [all, mobile, tablet, desktop] = processClassesForViewports(
|
|
1551
|
+
baseStyles,
|
|
1552
|
+
(node as FlatNode)?.overrideClasses || {},
|
|
1553
|
+
1
|
|
1554
|
+
);
|
|
1555
|
+
|
|
1556
|
+
if (isPreview) return desktop[0];
|
|
1557
|
+
switch (viewport) {
|
|
1558
|
+
case 'desktop':
|
|
1559
|
+
return desktop[0];
|
|
1560
|
+
case 'tablet':
|
|
1561
|
+
return tablet[0];
|
|
1562
|
+
case 'mobile':
|
|
1563
|
+
return mobile[0];
|
|
1564
|
+
default:
|
|
1565
|
+
return all[0];
|
|
1564
1566
|
}
|
|
1565
|
-
|
|
1567
|
+
}
|
|
1566
1568
|
|
|
1567
1569
|
case 'StoryFragment': {
|
|
1568
1570
|
const storyFragment = node as StoryFragmentNode;
|
|
@@ -1775,39 +1777,20 @@ export class NodesContext {
|
|
|
1775
1777
|
duplicatedPane.isChanged = true;
|
|
1776
1778
|
|
|
1777
1779
|
// Track all nodes that need to be added
|
|
1778
|
-
|
|
1780
|
+
// Call the new helper to process markdown, gridLayout, and bgPane
|
|
1781
|
+
const allNodes: BaseNode[] = this._processPaneTemplate(
|
|
1782
|
+
duplicatedPane,
|
|
1783
|
+
ownerId
|
|
1784
|
+
);
|
|
1779
1785
|
|
|
1780
|
-
|
|
1786
|
+
if (duplicatedPane.bgPane) {
|
|
1787
|
+
delete duplicatedPane.bgPane;
|
|
1788
|
+
}
|
|
1781
1789
|
if (duplicatedPane.markdown) {
|
|
1782
|
-
duplicatedPane.markdown
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
duplicatedPane.
|
|
1786
|
-
|
|
1787
|
-
let markdownNodes: TemplateNode[] = [];
|
|
1788
|
-
if (duplicatedPane.markdown.markdownBody) {
|
|
1789
|
-
const markdownGen = new MarkdownGenerator(this);
|
|
1790
|
-
markdownNodes = markdownGen.markdownToFlatNodes(
|
|
1791
|
-
duplicatedPane.markdown.markdownBody,
|
|
1792
|
-
duplicatedPane.markdown.id
|
|
1793
|
-
) as TemplateNode[];
|
|
1794
|
-
allNodes = [...allNodes, duplicatedPane.markdown, ...markdownNodes];
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
// Markdown already as nodes
|
|
1798
|
-
else if (
|
|
1799
|
-
typeof duplicatedPane.markdown !== `undefined` &&
|
|
1800
|
-
typeof duplicatedPane.markdown.id === `string`
|
|
1801
|
-
) {
|
|
1802
|
-
duplicatedPane?.markdown.nodes?.forEach((node) => {
|
|
1803
|
-
const childrenNodes = this.setupTemplateNodeRecursively(
|
|
1804
|
-
node,
|
|
1805
|
-
duplicatedPane?.markdown?.id || ''
|
|
1806
|
-
);
|
|
1807
|
-
markdownNodes.push(...childrenNodes);
|
|
1808
|
-
});
|
|
1809
|
-
allNodes = [...allNodes, duplicatedPane.markdown, ...markdownNodes];
|
|
1810
|
-
}
|
|
1790
|
+
delete duplicatedPane.markdown;
|
|
1791
|
+
}
|
|
1792
|
+
if (duplicatedPane.gridLayout) {
|
|
1793
|
+
delete duplicatedPane.gridLayout;
|
|
1811
1794
|
}
|
|
1812
1795
|
|
|
1813
1796
|
this.addNode(duplicatedPane as PaneNode);
|
|
@@ -1852,87 +1835,21 @@ export class NodesContext {
|
|
|
1852
1835
|
}
|
|
1853
1836
|
}
|
|
1854
1837
|
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
duplicatedPane.markdown.markdownId = pane?.markdown?.markdownId || ulid();
|
|
1861
|
-
duplicatedPane.markdown.parentId = duplicatedPaneId;
|
|
1862
|
-
|
|
1863
|
-
let markdownNodes: TemplateNode[] = [];
|
|
1864
|
-
if (duplicatedPane.markdown.markdownBody) {
|
|
1865
|
-
const markdownGen = new MarkdownGenerator(this);
|
|
1866
|
-
markdownNodes = markdownGen.markdownToFlatNodes(
|
|
1867
|
-
duplicatedPane.markdown.markdownBody,
|
|
1868
|
-
duplicatedPane.markdown.id
|
|
1869
|
-
) as TemplateNode[];
|
|
1870
|
-
allNodes = [...allNodes, duplicatedPane.markdown, ...markdownNodes];
|
|
1871
|
-
} else if (
|
|
1872
|
-
typeof duplicatedPane.markdown !== `undefined` &&
|
|
1873
|
-
typeof duplicatedPane.markdown.id === `string`
|
|
1874
|
-
) {
|
|
1875
|
-
// Create a map to track the original node ID to its duplicated node ID
|
|
1876
|
-
const oldToNewIdMap = new Map<string, string>();
|
|
1877
|
-
// First pass: Clone nodes and generate new IDs
|
|
1878
|
-
const nodesClone =
|
|
1879
|
-
duplicatedPane?.markdown?.nodes?.map((originalNode) => {
|
|
1880
|
-
const newNode = cloneDeep(originalNode);
|
|
1881
|
-
newNode.id = ulid();
|
|
1882
|
-
oldToNewIdMap.set(originalNode.id, newNode.id);
|
|
1883
|
-
return newNode;
|
|
1884
|
-
}) || [];
|
|
1885
|
-
// Second pass: Update parent IDs using the mapping
|
|
1886
|
-
nodesClone.forEach((node) => {
|
|
1887
|
-
// Special case for direct children of markdown
|
|
1888
|
-
if (node.parentId === pane?.markdown?.id) {
|
|
1889
|
-
node.parentId = duplicatedPane?.markdown?.id || '';
|
|
1890
|
-
} else {
|
|
1891
|
-
// For all other nodes, use the mapping to find the new parent ID
|
|
1892
|
-
const newParentId = oldToNewIdMap.get(node.parentId || '');
|
|
1893
|
-
if (newParentId) {
|
|
1894
|
-
node.parentId = newParentId;
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
markdownNodes.push(node);
|
|
1898
|
-
});
|
|
1899
|
-
allNodes = [...allNodes, duplicatedPane.markdown, ...markdownNodes];
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1838
|
+
// Call the new helper to process markdown, gridLayout, and bgPane
|
|
1839
|
+
const allNodes: BaseNode[] = this._processPaneTemplate(
|
|
1840
|
+
duplicatedPane,
|
|
1841
|
+
duplicatedPaneId
|
|
1842
|
+
);
|
|
1902
1843
|
|
|
1903
1844
|
if (duplicatedPane.bgPane) {
|
|
1904
|
-
const bgPaneId = ulid();
|
|
1905
|
-
|
|
1906
|
-
if (duplicatedPane.bgPane.type === 'visual-break') {
|
|
1907
|
-
const visualBreakPane = duplicatedPane.bgPane as VisualBreakNode;
|
|
1908
|
-
const bgPaneNode: VisualBreakNode = {
|
|
1909
|
-
id: bgPaneId,
|
|
1910
|
-
nodeType: 'BgPane',
|
|
1911
|
-
parentId: duplicatedPaneId,
|
|
1912
|
-
type: 'visual-break',
|
|
1913
|
-
breakDesktop: visualBreakPane.breakDesktop,
|
|
1914
|
-
breakTablet: visualBreakPane.breakTablet,
|
|
1915
|
-
breakMobile: visualBreakPane.breakMobile,
|
|
1916
|
-
};
|
|
1917
|
-
allNodes.push(bgPaneNode);
|
|
1918
|
-
} else if (duplicatedPane.bgPane.type === 'artpack-image') {
|
|
1919
|
-
const artpackBgPane = duplicatedPane.bgPane as ArtpackImageNode;
|
|
1920
|
-
const bgPaneNode: ArtpackImageNode = {
|
|
1921
|
-
id: bgPaneId,
|
|
1922
|
-
nodeType: 'BgPane',
|
|
1923
|
-
parentId: duplicatedPaneId,
|
|
1924
|
-
type: 'artpack-image',
|
|
1925
|
-
collection: artpackBgPane.collection,
|
|
1926
|
-
image: artpackBgPane.image,
|
|
1927
|
-
src: artpackBgPane.src,
|
|
1928
|
-
srcSet: artpackBgPane.srcSet,
|
|
1929
|
-
alt: artpackBgPane.alt || `Artpack image`,
|
|
1930
|
-
objectFit: artpackBgPane.objectFit || 'cover',
|
|
1931
|
-
};
|
|
1932
|
-
allNodes.push(bgPaneNode);
|
|
1933
|
-
}
|
|
1934
1845
|
delete duplicatedPane.bgPane;
|
|
1935
1846
|
}
|
|
1847
|
+
if (duplicatedPane.markdown) {
|
|
1848
|
+
delete duplicatedPane.markdown;
|
|
1849
|
+
}
|
|
1850
|
+
if (duplicatedPane.gridLayout) {
|
|
1851
|
+
delete duplicatedPane.gridLayout;
|
|
1852
|
+
}
|
|
1936
1853
|
|
|
1937
1854
|
const storyFragmentNode = ownerNode as StoryFragmentNode;
|
|
1938
1855
|
let specificIdx = -1;
|
|
@@ -1973,10 +1890,14 @@ export class NodesContext {
|
|
|
1973
1890
|
this.addNodes(allNodes);
|
|
1974
1891
|
this.notifyNode(ownerId);
|
|
1975
1892
|
|
|
1893
|
+
// Combine the pane and all its child nodes for the history patch
|
|
1894
|
+
const nodesToHistory = [duplicatedPane as BaseNode, ...allNodes];
|
|
1895
|
+
|
|
1976
1896
|
this.history.addPatch({
|
|
1977
1897
|
op: PatchOp.ADD,
|
|
1978
1898
|
undo: (ctx) => {
|
|
1979
|
-
|
|
1899
|
+
// Delete all nodes created (pane + children)
|
|
1900
|
+
ctx.deleteNodes(nodesToHistory);
|
|
1980
1901
|
|
|
1981
1902
|
if (
|
|
1982
1903
|
storyFragmentNode &&
|
|
@@ -1988,8 +1909,6 @@ export class NodesContext {
|
|
|
1988
1909
|
);
|
|
1989
1910
|
storyFragmentNode.isChanged = storyFragmentWasChanged;
|
|
1990
1911
|
}
|
|
1991
|
-
|
|
1992
|
-
ctx.deleteNodes([duplicatedPane]);
|
|
1993
1912
|
},
|
|
1994
1913
|
redo: (ctx) => {
|
|
1995
1914
|
if (storyFragmentNode?.nodeType === 'StoryFragment') {
|
|
@@ -2005,13 +1924,13 @@ export class NodesContext {
|
|
|
2005
1924
|
storyFragmentNode.isChanged = true;
|
|
2006
1925
|
}
|
|
2007
1926
|
|
|
2008
|
-
|
|
1927
|
+
// Add all nodes back (pane + children)
|
|
1928
|
+
ctx.addNodes(nodesToHistory);
|
|
2009
1929
|
ctx.linkChildToParent(
|
|
2010
1930
|
duplicatedPane.id,
|
|
2011
1931
|
duplicatedPane.parentId,
|
|
2012
1932
|
specificIdx
|
|
2013
1933
|
);
|
|
2014
|
-
ctx.addNodes(allNodes);
|
|
2015
1934
|
},
|
|
2016
1935
|
});
|
|
2017
1936
|
|
|
@@ -2098,7 +2017,7 @@ export class NodesContext {
|
|
|
2098
2017
|
|
|
2099
2018
|
let autoCreatedMarkdownNode: MarkdownPaneFragmentNode | null = null;
|
|
2100
2019
|
|
|
2101
|
-
console.log(`--- [TRAP - TEMPLATE BEFORE] ---`, cloneDeep(node));
|
|
2020
|
+
//console.log(`--- [TRAP - TEMPLATE BEFORE] ---`, cloneDeep(node));
|
|
2102
2021
|
// 3. HANDLE EMPTY PANE BY AUTO-CREATING A MARKDOWN NODE
|
|
2103
2022
|
if (targetNode.nodeType === 'Pane') {
|
|
2104
2023
|
// Create a minimal markdown node to act as the container
|
|
@@ -2176,7 +2095,7 @@ export class NodesContext {
|
|
|
2176
2095
|
);
|
|
2177
2096
|
}
|
|
2178
2097
|
|
|
2179
|
-
console.log(`--- [TRAP - FLATTENED AFTER] ---`, cloneDeep(flattenedNodes));
|
|
2098
|
+
//console.log(`--- [TRAP - FLATTENED AFTER] ---`, cloneDeep(flattenedNodes));
|
|
2180
2099
|
|
|
2181
2100
|
// 5. PERFORM REMAINING STATE MUTATIONS
|
|
2182
2101
|
if (originalPaneNode) {
|
|
@@ -2275,7 +2194,9 @@ export class NodesContext {
|
|
|
2275
2194
|
|
|
2276
2195
|
node.id = ulid();
|
|
2277
2196
|
node.parentId = parentId;
|
|
2278
|
-
|
|
2197
|
+
const thisNode = cloneDeep(node);
|
|
2198
|
+
delete thisNode.nodes;
|
|
2199
|
+
result.push(thisNode);
|
|
2279
2200
|
if ('nodes' in node && node.nodes) {
|
|
2280
2201
|
for (let i = 0; i < node.nodes.length; ++i) {
|
|
2281
2202
|
result = result.concat(
|
|
@@ -3224,6 +3145,160 @@ export class NodesContext {
|
|
|
3224
3145
|
|
|
3225
3146
|
return deletedNodes;
|
|
3226
3147
|
}
|
|
3148
|
+
|
|
3149
|
+
/**
|
|
3150
|
+
* Processes a TemplatePane's content (markdown, grid, or bgPane) and
|
|
3151
|
+
* returns a flat list of all nodes to be added to the store.
|
|
3152
|
+
* This is a de-duplicated helper used by addTemplatePane and addContextTemplatePane.
|
|
3153
|
+
* @param paneTemplate - The TemplatePane object to process.
|
|
3154
|
+
* @param newPaneId - The ID of the parent Pane node.
|
|
3155
|
+
* @returns An array of BaseNode objects to be added to allNodes.
|
|
3156
|
+
*/
|
|
3157
|
+
private _processPaneTemplate(
|
|
3158
|
+
paneTemplate: TemplatePane,
|
|
3159
|
+
newPaneId: string
|
|
3160
|
+
): BaseNode[] {
|
|
3161
|
+
let allNodes: BaseNode[] = [];
|
|
3162
|
+
|
|
3163
|
+
// 1. Process Markdown Content
|
|
3164
|
+
if (paneTemplate.markdown) {
|
|
3165
|
+
const duplicatedMarkdown = cloneDeep(
|
|
3166
|
+
paneTemplate.markdown
|
|
3167
|
+
) as TemplateMarkdown;
|
|
3168
|
+
duplicatedMarkdown.id = paneTemplate.markdown.id || ulid();
|
|
3169
|
+
duplicatedMarkdown.markdownId =
|
|
3170
|
+
paneTemplate.markdown.markdownId || ulid();
|
|
3171
|
+
duplicatedMarkdown.parentId = newPaneId;
|
|
3172
|
+
|
|
3173
|
+
let markdownNodes: TemplateNode[] = [];
|
|
3174
|
+
if (duplicatedMarkdown.markdownBody) {
|
|
3175
|
+
const markdownGen = new MarkdownGenerator(this);
|
|
3176
|
+
markdownNodes = markdownGen.markdownToFlatNodes(
|
|
3177
|
+
duplicatedMarkdown.markdownBody,
|
|
3178
|
+
duplicatedMarkdown.id
|
|
3179
|
+
) as TemplateNode[];
|
|
3180
|
+
allNodes = [...allNodes, duplicatedMarkdown, ...markdownNodes];
|
|
3181
|
+
} else if (
|
|
3182
|
+
typeof duplicatedMarkdown !== `undefined` &&
|
|
3183
|
+
typeof duplicatedMarkdown.id === `string`
|
|
3184
|
+
) {
|
|
3185
|
+
// Create a map to track the original node ID to its duplicated node ID
|
|
3186
|
+
const oldToNewIdMap = new Map<string, string>();
|
|
3187
|
+
// First pass: Clone nodes and generate new IDs
|
|
3188
|
+
const nodesClone =
|
|
3189
|
+
duplicatedMarkdown.nodes?.map((originalNode) => {
|
|
3190
|
+
const newNode = cloneDeep(originalNode);
|
|
3191
|
+
newNode.id = ulid();
|
|
3192
|
+
oldToNewIdMap.set(originalNode.id, newNode.id);
|
|
3193
|
+
return newNode;
|
|
3194
|
+
}) || [];
|
|
3195
|
+
// Second pass: Update parent IDs using the mapping
|
|
3196
|
+
nodesClone.forEach((node) => {
|
|
3197
|
+
// Special case for direct children of markdown
|
|
3198
|
+
if (node.parentId === paneTemplate.markdown?.id) {
|
|
3199
|
+
node.parentId = duplicatedMarkdown.id;
|
|
3200
|
+
} else {
|
|
3201
|
+
// For all other nodes, use the mapping to find the new parent ID
|
|
3202
|
+
const newParentId = oldToNewIdMap.get(node.parentId || '');
|
|
3203
|
+
if (newParentId) {
|
|
3204
|
+
node.parentId = newParentId;
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
markdownNodes.push(node);
|
|
3208
|
+
});
|
|
3209
|
+
allNodes = [...allNodes, duplicatedMarkdown, ...markdownNodes];
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
// 2. Process GridLayout Content
|
|
3213
|
+
} else if (paneTemplate.gridLayout) {
|
|
3214
|
+
const duplicatedGrid = cloneDeep(
|
|
3215
|
+
paneTemplate.gridLayout
|
|
3216
|
+
) as TemplateGridLayout;
|
|
3217
|
+
duplicatedGrid.id = paneTemplate.gridLayout.id || ulid();
|
|
3218
|
+
duplicatedGrid.parentId = newPaneId;
|
|
3219
|
+
allNodes.push(duplicatedGrid as GridLayoutNode);
|
|
3220
|
+
|
|
3221
|
+
// Map for all nodes within the grid
|
|
3222
|
+
const oldToNewIdMap = new Map<string, string>();
|
|
3223
|
+
|
|
3224
|
+
// First pass: Collect all column nodes and their descendant nodes
|
|
3225
|
+
const allOriginalNodes: TemplateNode[] = [];
|
|
3226
|
+
const columnNodes: TemplateMarkdown[] = [];
|
|
3227
|
+
|
|
3228
|
+
duplicatedGrid.nodes?.forEach((originalColumn) => {
|
|
3229
|
+
const newColumn = cloneDeep(originalColumn);
|
|
3230
|
+
newColumn.id = ulid();
|
|
3231
|
+
newColumn.markdownId = ulid();
|
|
3232
|
+
oldToNewIdMap.set(originalColumn.id, newColumn.id);
|
|
3233
|
+
columnNodes.push(newColumn);
|
|
3234
|
+
|
|
3235
|
+
originalColumn.nodes?.forEach((colNode) => {
|
|
3236
|
+
allOriginalNodes.push(colNode);
|
|
3237
|
+
});
|
|
3238
|
+
});
|
|
3239
|
+
|
|
3240
|
+
// Second pass: Clone all descendant nodes
|
|
3241
|
+
const allClonedDescendants = allOriginalNodes.map((originalNode) => {
|
|
3242
|
+
const newNode = cloneDeep(originalNode);
|
|
3243
|
+
newNode.id = ulid();
|
|
3244
|
+
oldToNewIdMap.set(originalNode.id, newNode.id);
|
|
3245
|
+
return newNode;
|
|
3246
|
+
});
|
|
3247
|
+
|
|
3248
|
+
// Third pass: Re-map parent IDs for columns
|
|
3249
|
+
columnNodes.forEach((col) => {
|
|
3250
|
+
col.parentId = duplicatedGrid.id;
|
|
3251
|
+
allNodes.push(col as MarkdownPaneFragmentNode);
|
|
3252
|
+
});
|
|
3253
|
+
|
|
3254
|
+
// Fourth pass: Re-map parent IDs for all descendants
|
|
3255
|
+
allClonedDescendants.forEach((node) => {
|
|
3256
|
+
const newParentId = oldToNewIdMap.get(node.parentId || '');
|
|
3257
|
+
if (newParentId) {
|
|
3258
|
+
node.parentId = newParentId;
|
|
3259
|
+
}
|
|
3260
|
+
allNodes.push(node);
|
|
3261
|
+
});
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
// 3. Process Background Pane
|
|
3265
|
+
if (paneTemplate.bgPane) {
|
|
3266
|
+
const bgPaneId = ulid();
|
|
3267
|
+
|
|
3268
|
+
if (paneTemplate.bgPane.type === 'visual-break') {
|
|
3269
|
+
const visualBreakPane = paneTemplate.bgPane as VisualBreakNode;
|
|
3270
|
+
const bgPaneNode: VisualBreakNode = {
|
|
3271
|
+
id: bgPaneId,
|
|
3272
|
+
nodeType: 'BgPane',
|
|
3273
|
+
parentId: newPaneId,
|
|
3274
|
+
type: 'visual-break',
|
|
3275
|
+
breakDesktop: visualBreakPane.breakDesktop,
|
|
3276
|
+
breakTablet: visualBreakPane.breakTablet,
|
|
3277
|
+
breakMobile: visualBreakPane.breakMobile,
|
|
3278
|
+
};
|
|
3279
|
+
allNodes.push(bgPaneNode);
|
|
3280
|
+
} else if (paneTemplate.bgPane.type === 'artpack-image') {
|
|
3281
|
+
const artpackBgPane = paneTemplate.bgPane as ArtpackImageNode;
|
|
3282
|
+
const bgPaneNode: ArtpackImageNode = {
|
|
3283
|
+
id: bgPaneId,
|
|
3284
|
+
nodeType: 'BgPane',
|
|
3285
|
+
parentId: newPaneId,
|
|
3286
|
+
type: 'artpack-image',
|
|
3287
|
+
collection: artpackBgPane.collection,
|
|
3288
|
+
image: artpackBgPane.image,
|
|
3289
|
+
src: artpackBgPane.src,
|
|
3290
|
+
srcSet: artpackBgPane.srcSet,
|
|
3291
|
+
alt: artpackBgPane.alt || `Artpack image`,
|
|
3292
|
+
objectFit: artpackBgPane.objectFit || 'cover',
|
|
3293
|
+
};
|
|
3294
|
+
allNodes.push(bgPaneNode);
|
|
3295
|
+
}
|
|
3296
|
+
// This helper only processes nodes, it doesn't modify the paneTemplate.
|
|
3297
|
+
// The deletion of `duplicatedPane.bgPane` will remain in `addTemplatePane`.
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
return allNodes;
|
|
3301
|
+
}
|
|
3227
3302
|
}
|
|
3228
3303
|
|
|
3229
3304
|
export const globalCtx: NodesContext = new NodesContext();
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
FullContentMapItem,
|
|
7
7
|
Theme,
|
|
8
8
|
ArtpacksStore,
|
|
9
|
+
BrandConfig,
|
|
9
10
|
} from '@/types/tractstack';
|
|
10
11
|
import type { SettingsPanelSignal, ViewportKey } from '@/types/compositorTypes';
|
|
11
12
|
import type {
|
|
@@ -21,9 +22,6 @@ export const fullContentMapStore = atom<FullContentMapItem[]>([]);
|
|
|
21
22
|
export const hasArtpacksStore = map<ArtpacksStore>({});
|
|
22
23
|
export const urlParamsStore = atom<Record<string, string | boolean>>({});
|
|
23
24
|
export const canonicalURLStore = atom<string>('');
|
|
24
|
-
export const brandColourStore = atom<string>(
|
|
25
|
-
'10120d,fcfcfc,f58333,c8df8c,293f58,a7b1b7,393d34,e3e3e3'
|
|
26
|
-
);
|
|
27
25
|
export const preferredThemeStore = atom<Theme>('light');
|
|
28
26
|
|
|
29
27
|
export const hasAssemblyAIStore = atom<boolean>(false);
|
|
@@ -156,6 +154,8 @@ export const resetStoryKeepState = () => {
|
|
|
156
154
|
canRedoStore.set(false);
|
|
157
155
|
};
|
|
158
156
|
|
|
157
|
+
export const brandConfigStore = atom<BrandConfig | null>(null);
|
|
158
|
+
|
|
159
159
|
export const settingsPanelStore = atom<SettingsPanelSignal | null>(null);
|
|
160
160
|
export const stylePanelTargetMemoryStore = atom<Map<string, number>>(
|
|
161
161
|
new Map<string, number>()
|