handoff-app 1.0.3 → 1.0.4
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/Changelog.md +10 -5
- package/dist/cli.js +0 -0
- package/dist/index.js +4 -1
- package/dist/transformers/plugins/ssr-render.js +4 -3
- package/dist/transformers/preview/component/api.js +3 -2
- package/dist/transformers/preview/component/builder.js +2 -1
- package/dist/transformers/utils/handlebars.js +3 -2
- package/package.json +1 -1
- package/src/app/components/Component/Preview.tsx +121 -121
- package/src/app/components/ComponentSearch.tsx +1 -1
- package/src/app/components/util/index.ts +17 -9
- package/src/app/pages/system/component/[component]/index.tsx +1 -1
- package/src/app/pages/system/index.tsx +2 -2
- package/src/app/pages/system/tokens/index.tsx +10 -10
- package/src/index.ts +3 -0
- package/src/transformers/plugins/ssr-render.ts +3 -3
- package/src/transformers/preview/component/api.ts +1 -1
- package/src/transformers/preview/component/builder.ts +1 -1
- package/src/transformers/utils/handlebars.ts +2 -2
- package/dist/commands/platform/init.d.ts +0 -6
- package/dist/commands/platform/init.js +0 -231
- package/dist/commands/platform/login.d.ts +0 -6
- package/dist/commands/platform/login.js +0 -108
- package/dist/commands/platform/logout.d.ts +0 -6
- package/dist/commands/platform/logout.js +0 -88
- package/dist/commands/platform/pull.d.ts +0 -8
- package/dist/commands/platform/pull.js +0 -112
- package/dist/commands/platform/push.d.ts +0 -8
- package/dist/commands/platform/push.js +0 -428
- package/dist/platform/client.d.ts +0 -122
- package/dist/platform/client.js +0 -228
- package/dist/platform/credentials.d.ts +0 -40
- package/dist/platform/credentials.js +0 -91
- package/dist/platform/sync.d.ts +0 -68
- package/dist/platform/sync.js +0 -349
package/Changelog.md
CHANGED
|
@@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
|
6
6
|
and this project adheres to
|
|
7
7
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
8
8
|
|
|
9
|
-
## \[1.0.
|
|
9
|
+
## \[1.0.4] - 2026-02-19
|
|
10
10
|
|
|
11
11
|
Bugfixes, UX improvements to the component page, improvements to react docgen,
|
|
12
12
|
a new quickstart command, and security fixes.
|
|
@@ -31,6 +31,11 @@ a new quickstart command, and security fixes.
|
|
|
31
31
|
* The API preview would through a 500 error under some conditions
|
|
32
32
|
* Using TSX components would cause an error in the code preview if the tsx component
|
|
33
33
|
used some kinds of valid react formatting.
|
|
34
|
+
* If you create pages without a declared weight, handoff would throw an error
|
|
35
|
+
* There was an old structure in the way we used handlebars that surfaces a warning
|
|
36
|
+
on build. We've updated that method.
|
|
37
|
+
* We removed an old page template that was no longer needed.
|
|
38
|
+
* The API calls to the component url were not working well in subpaths.
|
|
34
39
|
|
|
35
40
|
## Type Gen
|
|
36
41
|
|
|
@@ -57,6 +62,10 @@ a new quickstart command, and security fixes.
|
|
|
57
62
|
* Fixes a bug in webpack that made the include path lookups fail. @handoff and @/util now
|
|
58
63
|
works properly.
|
|
59
64
|
|
|
65
|
+
## \[1.0.3]
|
|
66
|
+
|
|
67
|
+
This this version was skipped.
|
|
68
|
+
|
|
60
69
|
## \[1.0.2] - 2026-01-12
|
|
61
70
|
|
|
62
71
|
Bugfixes focused on developer quality of life.
|
|
@@ -67,10 +76,6 @@ Bugfixes focused on developer quality of life.
|
|
|
67
76
|
resulting in a 404 error. This patch resolves a race condition in the HMR, by
|
|
68
77
|
preventing double write of the next config.
|
|
69
78
|
* Patch an issue where the example component doesn't load in a clean project
|
|
70
|
-
* If you create pages without a declared weight, handoff would throw an error
|
|
71
|
-
* There was an old structure in the way we used handlebars that surfaces a warning
|
|
72
|
-
on build. We've updated that method.
|
|
73
|
-
* We removed an old page template that was no longer needed.
|
|
74
79
|
|
|
75
80
|
## \[1.0.1] - 2025-12-28
|
|
76
81
|
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
@@ -71,12 +71,15 @@ class Handoff {
|
|
|
71
71
|
global.handoff = this;
|
|
72
72
|
}
|
|
73
73
|
init(configOverride) {
|
|
74
|
-
var _a, _b;
|
|
74
|
+
var _a, _b, _c;
|
|
75
75
|
const config = initConfig(configOverride !== null && configOverride !== void 0 ? configOverride : {});
|
|
76
76
|
this.config = config;
|
|
77
77
|
this.exportsDirectory = (_a = config.exportsOutputDirectory) !== null && _a !== void 0 ? _a : this.exportsDirectory;
|
|
78
78
|
this.sitesDirectory = (_b = config.sitesOutputDirectory) !== null && _b !== void 0 ? _b : this.exportsDirectory;
|
|
79
79
|
[this.runtimeConfig, this._configFilePaths] = (0, exports.initRuntimeConfig)(this);
|
|
80
|
+
if (this.config.app.base_path && !process.env.HANDOFF_APP_BASE_PATH) {
|
|
81
|
+
process.env.HANDOFF_APP_BASE_PATH = (_c = this.config.app.base_path) !== null && _c !== void 0 ? _c : '';
|
|
82
|
+
}
|
|
80
83
|
return this;
|
|
81
84
|
}
|
|
82
85
|
reload() {
|
|
@@ -111,13 +111,14 @@ function generateClientHydrationSource(componentPath) {
|
|
|
111
111
|
* @returns Complete HTML document
|
|
112
112
|
*/
|
|
113
113
|
function generateHtmlDocument(componentId, previewTitle, renderedHtml, clientJs, props) {
|
|
114
|
+
var _a, _b, _c;
|
|
114
115
|
return `<!DOCTYPE html>
|
|
115
116
|
<html lang="en">
|
|
116
117
|
<head>
|
|
117
118
|
<meta charset="UTF-8" />
|
|
118
|
-
<link rel="stylesheet" href="/api/component/main.css" />
|
|
119
|
-
<link rel="stylesheet" href="/api/component/${componentId}.css" />
|
|
120
|
-
<link rel="stylesheet" href="/assets/css/preview.css" />
|
|
119
|
+
<link rel="stylesheet" href="${(_a = process.env.HANDOFF_APP_BASE_PATH) !== null && _a !== void 0 ? _a : ''}/api/component/main.css" />
|
|
120
|
+
<link rel="stylesheet" href="${(_b = process.env.HANDOFF_APP_BASE_PATH) !== null && _b !== void 0 ? _b : ''}/api/component/${componentId}.css" />
|
|
121
|
+
<link rel="stylesheet" href="${(_c = process.env.HANDOFF_APP_BASE_PATH) !== null && _c !== void 0 ? _c : ''}/assets/css/preview.css" />
|
|
121
122
|
<script id="${PLUGIN_CONSTANTS.PROPS_SCRIPT_ID}" type="application/json">${JSON.stringify(props)}</script>
|
|
122
123
|
<script type="module">
|
|
123
124
|
${clientJs}
|
|
@@ -95,20 +95,21 @@ exports.writeComponentApi = writeComponentApi;
|
|
|
95
95
|
* @param componentData
|
|
96
96
|
*/
|
|
97
97
|
const updateComponentSummaryApi = (handoff_1, componentData_1, ...args_1) => __awaiter(void 0, [handoff_1, componentData_1, ...args_1], void 0, function* (handoff, componentData, isFullRebuild = false) {
|
|
98
|
+
var _a;
|
|
98
99
|
if (isFullRebuild) {
|
|
99
100
|
// Full rebuild: replace the entire file
|
|
100
101
|
yield writeComponentSummaryAPI(handoff, componentData);
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
103
104
|
// Partial update: merge with existing data
|
|
104
|
-
const apiPath = path_1.default.resolve(handoff.workingPath, '
|
|
105
|
+
const apiPath = path_1.default.resolve(handoff.workingPath, `${(_a = process.env.HANDOFF_APP_BASE_PATH) !== null && _a !== void 0 ? _a : ''}/api/components.json`);
|
|
105
106
|
let existingData = [];
|
|
106
107
|
if (fs_extra_1.default.existsSync(apiPath)) {
|
|
107
108
|
try {
|
|
108
109
|
const existing = yield fs_extra_1.default.readFile(apiPath, 'utf8');
|
|
109
110
|
existingData = JSON.parse(existing);
|
|
110
111
|
}
|
|
111
|
-
catch (
|
|
112
|
+
catch (_b) {
|
|
112
113
|
// Corrupt or missing JSON — treat as empty
|
|
113
114
|
existingData = [];
|
|
114
115
|
}
|
|
@@ -313,6 +313,7 @@ function processComponents(handoff, id, segmentToProcess, options) {
|
|
|
313
313
|
* @returns
|
|
314
314
|
*/
|
|
315
315
|
const buildComponentSummary = (id, data) => {
|
|
316
|
+
var _a;
|
|
316
317
|
return {
|
|
317
318
|
id,
|
|
318
319
|
title: data.title,
|
|
@@ -325,7 +326,7 @@ const buildComponentSummary = (id, data) => {
|
|
|
325
326
|
tags: data.tags ? data.tags : [],
|
|
326
327
|
properties: data.properties,
|
|
327
328
|
previews: data.previews,
|
|
328
|
-
path:
|
|
329
|
+
path: `${(_a = process.env.HANDOFF_APP_BASE_PATH) !== null && _a !== void 0 ? _a : ''}/api/component/${id}.json`,
|
|
329
330
|
};
|
|
330
331
|
};
|
|
331
332
|
exports.default = processComponents;
|
|
@@ -52,9 +52,10 @@ exports.registerHandlebarsHelpers = registerHandlebarsHelpers;
|
|
|
52
52
|
* @returns Handlebars context object
|
|
53
53
|
*/
|
|
54
54
|
const createHandlebarsContext = (data, previewData) => {
|
|
55
|
+
var _a, _b, _c, _d, _e;
|
|
55
56
|
return {
|
|
56
|
-
style: `<link rel="stylesheet" href="/api/component/shared.css"><link rel="stylesheet" href="/api/component/${data.id}.css">\n<link rel="stylesheet" href="/assets/css/preview.css">`,
|
|
57
|
-
script: `<script src="/api/component/${data.id}.js"></script>\n<script src="/assets/js/preview.js"></script><script>var fields = ${JSON.stringify(data.properties)};</script>`,
|
|
57
|
+
style: `<link rel="stylesheet" href="${(_a = process.env.HANDOFF_APP_BASE_PATH) !== null && _a !== void 0 ? _a : ''}/api/component/shared.css"><link rel="stylesheet" href="${(_b = process.env.HANDOFF_APP_BASE_PATH) !== null && _b !== void 0 ? _b : ''}/api/component/${data.id}.css">\n<link rel="stylesheet" href="${(_c = process.env.HANDOFF_APP_BASE_PATH) !== null && _c !== void 0 ? _c : ''}/assets/css/preview.css">`,
|
|
58
|
+
script: `<script src="${(_d = process.env.HANDOFF_APP_BASE_PATH) !== null && _d !== void 0 ? _d : ''}/api/component/${data.id}.js"></script>\n<script src="${(_e = process.env.HANDOFF_APP_BASE_PATH) !== null && _e !== void 0 ? _e : ''}/assets/js/preview.js"></script><script>var fields = ${JSON.stringify(data.properties)};</script>`,
|
|
58
59
|
properties: previewData.values || {},
|
|
59
60
|
fields: data.properties,
|
|
60
61
|
title: data.title,
|
package/package.json
CHANGED
|
@@ -303,7 +303,7 @@ export const ComponentDisplay: React.FC<{
|
|
|
303
303
|
className="h-7 px-3 hover:bg-gray-300 [&_svg]:size-3"
|
|
304
304
|
onClick={() => {
|
|
305
305
|
// open in new tab
|
|
306
|
-
window.open('/api/component
|
|
306
|
+
window.open(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/component/${previewUrl}`, '_blank');
|
|
307
307
|
}}
|
|
308
308
|
variant="ghost"
|
|
309
309
|
>
|
|
@@ -333,7 +333,7 @@ export const ComponentDisplay: React.FC<{
|
|
|
333
333
|
display: 'block',
|
|
334
334
|
margin: '0 auto',
|
|
335
335
|
}}
|
|
336
|
-
src={
|
|
336
|
+
src={`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/component/${previewUrl}`}
|
|
337
337
|
/>
|
|
338
338
|
</div>
|
|
339
339
|
) : (
|
|
@@ -539,9 +539,9 @@ const hasNestedProperties = (row: SlotMetadata): boolean => {
|
|
|
539
539
|
);
|
|
540
540
|
};
|
|
541
541
|
|
|
542
|
-
const TableRows: React.FC<{
|
|
543
|
-
rows: SlotMetadata[];
|
|
544
|
-
openSheet: (field: SlotMetadata) => void;
|
|
542
|
+
const TableRows: React.FC<{
|
|
543
|
+
rows: SlotMetadata[];
|
|
544
|
+
openSheet: (field: SlotMetadata) => void;
|
|
545
545
|
depth?: number;
|
|
546
546
|
parentPath?: string;
|
|
547
547
|
}> = ({
|
|
@@ -550,24 +550,24 @@ const TableRows: React.FC<{
|
|
|
550
550
|
depth = 0,
|
|
551
551
|
parentPath = '',
|
|
552
552
|
}) => {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
};
|
|
553
|
+
return (
|
|
554
|
+
<>
|
|
555
|
+
{rows.map((row, i) => {
|
|
556
|
+
if (!row) return null;
|
|
557
|
+
const currentPath = parentPath ? `${parentPath}.${row.key || row.name}` : (row.key || row.name);
|
|
558
|
+
return (
|
|
559
|
+
<ExpandableTableRow
|
|
560
|
+
key={`row-${currentPath}-${i}`}
|
|
561
|
+
row={row}
|
|
562
|
+
openSheet={openSheet}
|
|
563
|
+
depth={depth}
|
|
564
|
+
path={currentPath}
|
|
565
|
+
/>
|
|
566
|
+
);
|
|
567
|
+
})}
|
|
568
|
+
</>
|
|
569
|
+
);
|
|
570
|
+
};
|
|
571
571
|
|
|
572
572
|
const humanReadableSizeRule = (rule: string, value: any) => {
|
|
573
573
|
switch (rule) {
|
|
@@ -597,9 +597,9 @@ const humanReadableSizeRule = (rule: string, value: any) => {
|
|
|
597
597
|
* An expandable table row that can show nested properties
|
|
598
598
|
* Supports deep nesting with visual indentation and expand/collapse
|
|
599
599
|
*/
|
|
600
|
-
const ExpandableTableRow: React.FC<{
|
|
601
|
-
row: SlotMetadata;
|
|
602
|
-
openSheet: (field: SlotMetadata) => void;
|
|
600
|
+
const ExpandableTableRow: React.FC<{
|
|
601
|
+
row: SlotMetadata;
|
|
602
|
+
openSheet: (field: SlotMetadata) => void;
|
|
603
603
|
depth: number;
|
|
604
604
|
path: string;
|
|
605
605
|
}> = ({
|
|
@@ -608,104 +608,104 @@ const ExpandableTableRow: React.FC<{
|
|
|
608
608
|
depth,
|
|
609
609
|
path,
|
|
610
610
|
}) => {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
const getSizeDisplay = (row: SlotMetadata) => {
|
|
616
|
-
if (!row.rules) return '-';
|
|
617
|
-
|
|
618
|
-
// Find the first applicable size rule
|
|
619
|
-
const sizeRules = ['dimensions', 'content', 'maxSize'];
|
|
620
|
-
const rule = Object.keys(row.rules).find((r) => sizeRules.includes(r));
|
|
621
|
-
|
|
622
|
-
return rule ? humanReadableSizeRule(rule, row.rules[rule]) : '-';
|
|
623
|
-
};
|
|
611
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
612
|
+
const nested = getNestedProperties(row);
|
|
613
|
+
const canExpand = hasNestedProperties(row);
|
|
624
614
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
// Get background color based on depth for visual hierarchy
|
|
629
|
-
const getDepthBgClass = (depth: number) => {
|
|
630
|
-
if (depth === 0) return '';
|
|
631
|
-
if (depth === 1) return 'bg-gray-50/50 dark:bg-gray-800/30';
|
|
632
|
-
if (depth === 2) return 'bg-gray-100/50 dark:bg-gray-800/50';
|
|
633
|
-
return 'bg-gray-100/70 dark:bg-gray-800/70';
|
|
634
|
-
};
|
|
615
|
+
const getSizeDisplay = (row: SlotMetadata) => {
|
|
616
|
+
if (!row.rules) return '-';
|
|
635
617
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
openSheet(row);
|
|
642
|
-
};
|
|
618
|
+
// Find the first applicable size rule
|
|
619
|
+
const sizeRules = ['dimensions', 'content', 'maxSize'];
|
|
620
|
+
const rule = Object.keys(row.rules).find((r) => sizeRules.includes(r));
|
|
643
621
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
setIsExpanded(!isExpanded);
|
|
647
|
-
};
|
|
622
|
+
return rule ? humanReadableSizeRule(rule, row.rules[rule]) : '-';
|
|
623
|
+
};
|
|
648
624
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
625
|
+
// Calculate indent based on depth (each level adds 20px)
|
|
626
|
+
const indentPx = depth * 20;
|
|
627
|
+
|
|
628
|
+
// Get background color based on depth for visual hierarchy
|
|
629
|
+
const getDepthBgClass = (depth: number) => {
|
|
630
|
+
if (depth === 0) return '';
|
|
631
|
+
if (depth === 1) return 'bg-gray-50/50 dark:bg-gray-800/30';
|
|
632
|
+
if (depth === 2) return 'bg-gray-100/50 dark:bg-gray-800/50';
|
|
633
|
+
return 'bg-gray-100/70 dark:bg-gray-800/70';
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
const handleRowClick = (e: React.MouseEvent) => {
|
|
637
|
+
// If clicking on the expand button area, don't open the sheet
|
|
638
|
+
if ((e.target as HTMLElement).closest('.expand-toggle')) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
openSheet(row);
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
const handleExpandToggle = (e: React.MouseEvent) => {
|
|
645
|
+
e.stopPropagation();
|
|
646
|
+
setIsExpanded(!isExpanded);
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
return (
|
|
650
|
+
<>
|
|
651
|
+
<TableRow
|
|
652
|
+
className={`h-10 cursor-pointer border-b-[0.5px] ${getDepthBgClass(depth)}`}
|
|
653
|
+
onClick={handleRowClick}
|
|
654
|
+
>
|
|
655
|
+
<TableCell className="whitespace-nowrap border-l-[0.5px] border-r-[0.5px] px-4 py-1">
|
|
656
|
+
<div className="flex items-center" style={{ paddingLeft: `${indentPx}px` }}>
|
|
657
|
+
{canExpand ? (
|
|
658
|
+
<button
|
|
659
|
+
className="expand-toggle mr-2 flex h-5 w-5 items-center justify-center rounded hover:bg-gray-200 dark:hover:bg-gray-700"
|
|
660
|
+
onClick={handleExpandToggle}
|
|
661
|
+
aria-label={isExpanded ? 'Collapse' : 'Expand'}
|
|
662
|
+
>
|
|
663
|
+
{isExpanded ? (
|
|
664
|
+
<ChevronDown className="h-4 w-4 text-gray-500" />
|
|
665
|
+
) : (
|
|
666
|
+
<ChevronRight className="h-4 w-4 text-gray-500" />
|
|
667
|
+
)}
|
|
668
|
+
</button>
|
|
669
|
+
) : (
|
|
670
|
+
<span className="mr-2 w-5" />
|
|
671
|
+
)}
|
|
672
|
+
<span className={depth > 0 ? 'text-gray-700 dark:text-gray-300' : ''}>
|
|
673
|
+
{startCase(row.name)}
|
|
678
674
|
</span>
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
</
|
|
686
|
-
|
|
687
|
-
<Badge variant=
|
|
688
|
-
{row.
|
|
675
|
+
{canExpand && (
|
|
676
|
+
<span className="ml-2 text-xs text-gray-400">
|
|
677
|
+
({Object.keys(nested || {}).length} {row.type === 'array' ? 'item fields' : 'fields'})
|
|
678
|
+
</span>
|
|
679
|
+
)}
|
|
680
|
+
</div>
|
|
681
|
+
</TableCell>
|
|
682
|
+
<TableCell className="border-r-[0.5px] px-3.5 py-1">
|
|
683
|
+
<Badge variant={getVariantForType(row.type)} className="rounded-xl px-2.5">
|
|
684
|
+
{row.type}
|
|
689
685
|
</Badge>
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
<
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
686
|
+
{row.type === 'array' && row.items?.type && (
|
|
687
|
+
<Badge variant="outline" className="ml-1 rounded-xl px-2 text-[10px]">
|
|
688
|
+
{row.items.type}[]
|
|
689
|
+
</Badge>
|
|
690
|
+
)}
|
|
691
|
+
</TableCell>
|
|
692
|
+
<TableCell className="whitespace-nowrap border-l-[0.5px] border-r-[0.5px] px-4 py-1 text-gray-600 dark:text-gray-300">
|
|
693
|
+
{getSizeDisplay(row)}
|
|
694
|
+
</TableCell>
|
|
695
|
+
<TableCell className="border-r-[0.5px] px-4 py-1 text-gray-600 dark:text-gray-300">
|
|
696
|
+
<span className="slot-description line-clamp-1">{row.description || row.generic || '-'}</span>
|
|
697
|
+
</TableCell>
|
|
698
|
+
</TableRow>
|
|
699
|
+
|
|
700
|
+
{/* Render nested properties when expanded */}
|
|
701
|
+
{isExpanded && nested && nested.length > 0 && (
|
|
702
|
+
<TableRows
|
|
703
|
+
rows={nested}
|
|
704
|
+
openSheet={openSheet}
|
|
705
|
+
depth={depth + 1}
|
|
706
|
+
parentPath={path}
|
|
707
|
+
/>
|
|
708
|
+
)}
|
|
709
|
+
</>
|
|
710
|
+
);
|
|
711
|
+
};
|
|
@@ -9,7 +9,7 @@ import React from 'react';
|
|
|
9
9
|
*/
|
|
10
10
|
export const getComponentList = async (): Promise<ComponentListObject[]> => {
|
|
11
11
|
// Try to load the component from the public json
|
|
12
|
-
let data = await fetch(
|
|
12
|
+
let data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`).then((res) => res.json());
|
|
13
13
|
return data as ComponentListObject[];
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -206,6 +206,9 @@ export const staticBuildMenu = () => {
|
|
|
206
206
|
// // Contents of docs
|
|
207
207
|
const docRoot = path.join(process.env.HANDOFF_MODULE_PATH ?? '', 'config/docs');
|
|
208
208
|
// Get the file list
|
|
209
|
+
if(!fs.existsSync(docRoot)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
209
212
|
const files = fs.readdirSync(docRoot);
|
|
210
213
|
let list = files;
|
|
211
214
|
const workingPages = path.resolve(process.env.HANDOFF_WORKING_PATH ?? '', 'pages');
|
|
@@ -277,7 +280,7 @@ export const staticBuildMenu = () => {
|
|
|
277
280
|
title: metadata.menuTitle ?? metadata.title,
|
|
278
281
|
external,
|
|
279
282
|
weight: metadata.weight ?? 0,
|
|
280
|
-
path: filepath
|
|
283
|
+
path: `${filepath}`,
|
|
281
284
|
subSections,
|
|
282
285
|
};
|
|
283
286
|
}
|
|
@@ -287,6 +290,7 @@ export const staticBuildMenu = () => {
|
|
|
287
290
|
};
|
|
288
291
|
|
|
289
292
|
const staticBuildComponentMenu = (type?: boolean | string) => {
|
|
293
|
+
const basePath = (process.env.HANDOFF_APP_BASE_PATH ?? '').replace(/^\//, '');
|
|
290
294
|
let menu = [];
|
|
291
295
|
let components = fetchComponents({ includeTokens: false });
|
|
292
296
|
if (typeof type === 'string' && type !== '') {
|
|
@@ -305,7 +309,7 @@ const staticBuildComponentMenu = (type?: boolean | string) => {
|
|
|
305
309
|
if (component.name) {
|
|
306
310
|
title = component.name;
|
|
307
311
|
}
|
|
308
|
-
menuGroup.menu.push({ path:
|
|
312
|
+
menuGroup.menu.push({ path: `${basePath}/system/component/${component.id}`, title });
|
|
309
313
|
});
|
|
310
314
|
// sort the menu group by name alphabetical
|
|
311
315
|
menuGroup.menu = menuGroup.menu.sort((a, b) => a.title.localeCompare(b.title));
|
|
@@ -317,22 +321,24 @@ const staticBuildComponentMenu = (type?: boolean | string) => {
|
|
|
317
321
|
};
|
|
318
322
|
|
|
319
323
|
const staticBuildTokensMenu = () => {
|
|
324
|
+
const basePath = (process.env.HANDOFF_APP_BASE_PATH ?? '').replace(/^\//, '');
|
|
325
|
+
|
|
320
326
|
const menu = [
|
|
321
327
|
{
|
|
322
328
|
title: `Foundations`,
|
|
323
|
-
path:
|
|
329
|
+
path: `${basePath}/system/tokens/foundations`,
|
|
324
330
|
menu: [
|
|
325
331
|
{
|
|
326
332
|
title: `Colors`,
|
|
327
|
-
path:
|
|
333
|
+
path: `${basePath}/system/tokens/foundations/colors`,
|
|
328
334
|
},
|
|
329
335
|
{
|
|
330
336
|
title: `Effects`,
|
|
331
|
-
path:
|
|
337
|
+
path: `${basePath}/system/tokens/foundations/effects`,
|
|
332
338
|
},
|
|
333
339
|
{
|
|
334
340
|
title: `Typography`,
|
|
335
|
-
path:
|
|
341
|
+
path: `${basePath}/system/tokens/foundations/typography`,
|
|
336
342
|
},
|
|
337
343
|
],
|
|
338
344
|
},
|
|
@@ -352,14 +358,14 @@ const staticBuildTokensMenu = () => {
|
|
|
352
358
|
if (component.name) {
|
|
353
359
|
title = component.name;
|
|
354
360
|
}
|
|
355
|
-
componentMenuItems.push({ path:
|
|
361
|
+
componentMenuItems.push({ path: `${basePath}/system/tokens/components/${component.id}`, title });
|
|
356
362
|
});
|
|
357
363
|
});
|
|
358
364
|
|
|
359
365
|
if (componentMenuItems.length > 0) {
|
|
360
366
|
menu.push({
|
|
361
367
|
title: `Components`,
|
|
362
|
-
path:
|
|
368
|
+
path: `${basePath}/system/tokens/components`,
|
|
363
369
|
menu: componentMenuItems,
|
|
364
370
|
});
|
|
365
371
|
}
|
|
@@ -368,9 +374,11 @@ const staticBuildTokensMenu = () => {
|
|
|
368
374
|
};
|
|
369
375
|
|
|
370
376
|
const staticBuildTokenMenu = () => {
|
|
377
|
+
const basePath = (process.env.HANDOFF_APP_BASE_PATH ?? '').replace(/^\//, '');
|
|
378
|
+
|
|
371
379
|
let subSections = {
|
|
372
380
|
title: 'Tokens',
|
|
373
|
-
path:
|
|
381
|
+
path: `${basePath}/system/tokens`,
|
|
374
382
|
menu: [],
|
|
375
383
|
};
|
|
376
384
|
const tokens = getTokens();
|
|
@@ -110,7 +110,7 @@ const GenericComponentPage = ({ menu, metadata, current, id, config, componentHo
|
|
|
110
110
|
const [componentPreviews, setComponentPreviews] = useState<PreviewObject | [string, PreviewObject][]>();
|
|
111
111
|
|
|
112
112
|
const fetchComponents = async () => {
|
|
113
|
-
let data = await fetch(
|
|
113
|
+
let data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/component/${id}.json`).then((res) => res.json());
|
|
114
114
|
setComponent(data as PreviewObject);
|
|
115
115
|
};
|
|
116
116
|
|
|
@@ -67,7 +67,7 @@ const ComponentsPage = ({ content, menu, metadata, current, config }: ComponentP
|
|
|
67
67
|
// Fetch components from api
|
|
68
68
|
const [components, setComponents] = useState<PreviewObject[]>(undefined);
|
|
69
69
|
const fetchComponents = async () => {
|
|
70
|
-
let data = await fetch(
|
|
70
|
+
let data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`).then((res) => res.json());
|
|
71
71
|
setComponents(data as PreviewObject[]);
|
|
72
72
|
};
|
|
73
73
|
useEffect(() => {
|
|
@@ -108,7 +108,7 @@ const ComponentsPage = ({ content, menu, metadata, current, config }: ComponentP
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const apiUrl = (window.location.origin && window.location.origin) +
|
|
111
|
+
const apiUrl = (window.location.origin && window.location.origin) + `${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`;
|
|
112
112
|
return (
|
|
113
113
|
<Layout config={config} menu={menu} current={current} metadata={metadata}>
|
|
114
114
|
<div className="flex flex-col gap-2 pb-7">
|
|
@@ -39,14 +39,14 @@ export const getStaticProps: GetStaticProps = async (context) => {
|
|
|
39
39
|
...fetchDocPageMarkdown('docs/', 'system', `/system`).props,
|
|
40
40
|
components: components
|
|
41
41
|
? components.reduce(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
(acc, component) => ({
|
|
43
|
+
...acc,
|
|
44
|
+
...{
|
|
45
|
+
[component]: fetchDocPageMetadataAndContent('docs/components/', component).metadata,
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
{}
|
|
49
|
+
)
|
|
50
50
|
: null,
|
|
51
51
|
} as ComponentPageDocumentationProps,
|
|
52
52
|
},
|
|
@@ -61,14 +61,14 @@ const ComponentsPage = ({ content, menu, metadata, current, config }: ComponentP
|
|
|
61
61
|
// Fetch components from api
|
|
62
62
|
const [components, setComponents] = useState<PreviewObject[]>(undefined);
|
|
63
63
|
const fetchComponents = async () => {
|
|
64
|
-
let data = await fetch(
|
|
64
|
+
let data = await fetch(`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`).then((res) => res.json());
|
|
65
65
|
setComponents(data as PreviewObject[]);
|
|
66
66
|
};
|
|
67
67
|
useEffect(() => {
|
|
68
68
|
fetchComponents();
|
|
69
69
|
}, []);
|
|
70
70
|
if (!components) return <p>Loading...</p>;
|
|
71
|
-
const apiUrl = (window.location.origin && window.location.origin) +
|
|
71
|
+
const apiUrl = (window.location.origin && window.location.origin) + `${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`;
|
|
72
72
|
return (
|
|
73
73
|
<Layout config={config} menu={menu} current={current} metadata={metadata}>
|
|
74
74
|
<div className="flex flex-col gap-2 pb-7">
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,9 @@ class Handoff {
|
|
|
55
55
|
this.exportsDirectory = config.exportsOutputDirectory ?? this.exportsDirectory;
|
|
56
56
|
this.sitesDirectory = config.sitesOutputDirectory ?? this.exportsDirectory;
|
|
57
57
|
[this.runtimeConfig, this._configFilePaths] = initRuntimeConfig(this);
|
|
58
|
+
if(this.config.app.base_path && !process.env.HANDOFF_APP_BASE_PATH) {
|
|
59
|
+
process.env.HANDOFF_APP_BASE_PATH = this.config.app.base_path ?? '';
|
|
60
|
+
}
|
|
58
61
|
return this;
|
|
59
62
|
}
|
|
60
63
|
|
|
@@ -118,9 +118,9 @@ function generateHtmlDocument(componentId: string, previewTitle: string, rendere
|
|
|
118
118
|
<html lang="en">
|
|
119
119
|
<head>
|
|
120
120
|
<meta charset="UTF-8" />
|
|
121
|
-
<link rel="stylesheet" href="/api/component/main.css" />
|
|
122
|
-
<link rel="stylesheet" href="/api/component/${componentId}.css" />
|
|
123
|
-
<link rel="stylesheet" href="/assets/css/preview.css" />
|
|
121
|
+
<link rel="stylesheet" href="${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/component/main.css" />
|
|
122
|
+
<link rel="stylesheet" href="${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/component/${componentId}.css" />
|
|
123
|
+
<link rel="stylesheet" href="${process.env.HANDOFF_APP_BASE_PATH ?? ''}/assets/css/preview.css" />
|
|
124
124
|
<script id="${PLUGIN_CONSTANTS.PROPS_SCRIPT_ID}" type="application/json">${JSON.stringify(props)}</script>
|
|
125
125
|
<script type="module">
|
|
126
126
|
${clientJs}
|
|
@@ -107,7 +107,7 @@ export const updateComponentSummaryApi = async (handoff: Handoff, componentData:
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
// Partial update: merge with existing data
|
|
110
|
-
const apiPath = path.resolve(handoff.workingPath, '
|
|
110
|
+
const apiPath = path.resolve(handoff.workingPath, `${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/components.json`);
|
|
111
111
|
let existingData: ComponentListObject[] = [];
|
|
112
112
|
|
|
113
113
|
if (fs.existsSync(apiPath)) {
|