@litodocs/cli 1.1.0 → 1.2.0
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/package.json +1 -1
- package/src/core/landing-sync.js +140 -15
- package/src/core/sync.js +1 -1
package/package.json
CHANGED
package/src/core/landing-sync.js
CHANGED
|
@@ -98,11 +98,17 @@ export async function syncCustomLanding(sourcePath, projectDir, frameworkConfig,
|
|
|
98
98
|
// Read all files from _landing/
|
|
99
99
|
const files = await readdir(landingSource, { withFileTypes: true });
|
|
100
100
|
|
|
101
|
+
// Check if navbar/footer are explicitly hidden
|
|
102
|
+
const navbarHidden = landingConfig.navbar === false;
|
|
103
|
+
const footerHidden = landingConfig.footer === false;
|
|
104
|
+
|
|
101
105
|
// Separate files by type
|
|
102
106
|
const htmlFiles = [];
|
|
103
107
|
const cssFiles = [];
|
|
104
108
|
const jsFiles = [];
|
|
105
109
|
const assetFiles = [];
|
|
110
|
+
let navbarHtml = null;
|
|
111
|
+
let footerHtml = null;
|
|
106
112
|
|
|
107
113
|
for (const file of files) {
|
|
108
114
|
if (file.isDirectory()) {
|
|
@@ -114,8 +120,17 @@ export async function syncCustomLanding(sourcePath, projectDir, frameworkConfig,
|
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
const ext = extname(file.name).toLowerCase();
|
|
123
|
+
const name = basename(file.name, ext).toLowerCase();
|
|
124
|
+
|
|
117
125
|
if (ext === '.html' || ext === '.htm') {
|
|
118
|
-
|
|
126
|
+
// Detect custom navbar/footer HTML files (skip if hidden)
|
|
127
|
+
if (!navbarHidden && (name === 'navbar' || name === 'nav' || name === 'header')) {
|
|
128
|
+
navbarHtml = file.name;
|
|
129
|
+
} else if (!footerHidden && name === 'footer') {
|
|
130
|
+
footerHtml = file.name;
|
|
131
|
+
} else if (!((name === 'navbar' || name === 'nav' || name === 'header') || name === 'footer')) {
|
|
132
|
+
htmlFiles.push(file.name);
|
|
133
|
+
}
|
|
119
134
|
} else if (ext === '.css') {
|
|
120
135
|
cssFiles.push(file.name);
|
|
121
136
|
} else if (ext === '.js' || ext === '.mjs') {
|
|
@@ -123,6 +138,31 @@ export async function syncCustomLanding(sourcePath, projectDir, frameworkConfig,
|
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
|
|
141
|
+
// Read custom navbar/footer content if present
|
|
142
|
+
let navbarContent = navbarHidden ? '__hidden__' : null;
|
|
143
|
+
let footerContent = footerHidden ? '__hidden__' : null;
|
|
144
|
+
|
|
145
|
+
if (!navbarHidden && navbarHtml) {
|
|
146
|
+
navbarContent = await readFile(join(landingSource, navbarHtml), 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
if (!footerHidden && footerHtml) {
|
|
149
|
+
footerContent = await readFile(join(landingSource, footerHtml), 'utf-8');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Also check config for custom navbar/footer (skip if hidden)
|
|
153
|
+
if (!navbarHidden && !navbarContent && landingConfig.navbar?.html) {
|
|
154
|
+
const navPath = join(landingSource, '..', landingConfig.navbar.html);
|
|
155
|
+
if (await pathExists(navPath)) {
|
|
156
|
+
navbarContent = await readFile(navPath, 'utf-8');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!footerHidden && !footerContent && landingConfig.footer?.html) {
|
|
160
|
+
const footerPath = join(landingSource, '..', landingConfig.footer.html);
|
|
161
|
+
if (await pathExists(footerPath)) {
|
|
162
|
+
footerContent = await readFile(footerPath, 'utf-8');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
126
166
|
// Generate landing page based on framework
|
|
127
167
|
await generateLandingForFramework(
|
|
128
168
|
projectDir,
|
|
@@ -133,6 +173,8 @@ export async function syncCustomLanding(sourcePath, projectDir, frameworkConfig,
|
|
|
133
173
|
cssFiles,
|
|
134
174
|
jsFiles,
|
|
135
175
|
assetFiles,
|
|
176
|
+
navbarContent,
|
|
177
|
+
footerContent,
|
|
136
178
|
config: landingConfig,
|
|
137
179
|
}
|
|
138
180
|
);
|
|
@@ -170,12 +212,55 @@ export async function syncSectionsLanding(sourcePath, projectDir, frameworkConfi
|
|
|
170
212
|
}
|
|
171
213
|
}
|
|
172
214
|
|
|
215
|
+
// Check if navbar/footer are explicitly hidden
|
|
216
|
+
const navbarHidden = landingConfig.navbar === false;
|
|
217
|
+
const footerHidden = landingConfig.footer === false;
|
|
218
|
+
|
|
219
|
+
// Check for custom navbar/footer in _landing/ folder
|
|
220
|
+
const landingSource = join(sourcePath, landingConfig.source || '_landing');
|
|
221
|
+
let navbarContent = navbarHidden ? '__hidden__' : null;
|
|
222
|
+
let footerContent = footerHidden ? '__hidden__' : null;
|
|
223
|
+
|
|
224
|
+
if (!navbarHidden) {
|
|
225
|
+
const navbarNames = ['navbar.html', 'nav.html', 'header.html'];
|
|
226
|
+
for (const name of navbarNames) {
|
|
227
|
+
const navPath = join(landingSource, name);
|
|
228
|
+
if (await pathExists(navPath)) {
|
|
229
|
+
navbarContent = await readFile(navPath, 'utf-8');
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!footerHidden) {
|
|
236
|
+
const footerPath = join(landingSource, 'footer.html');
|
|
237
|
+
if (await pathExists(footerPath)) {
|
|
238
|
+
footerContent = await readFile(footerPath, 'utf-8');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Also check config for custom navbar/footer (skip if hidden)
|
|
243
|
+
if (!navbarHidden && !navbarContent && landingConfig.navbar?.html) {
|
|
244
|
+
const navPath = join(sourcePath, landingConfig.navbar.html);
|
|
245
|
+
if (await pathExists(navPath)) {
|
|
246
|
+
navbarContent = await readFile(navPath, 'utf-8');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (!footerHidden && !footerContent && landingConfig.footer?.html) {
|
|
250
|
+
const fPath = join(sourcePath, landingConfig.footer.html);
|
|
251
|
+
if (await pathExists(fPath)) {
|
|
252
|
+
footerContent = await readFile(fPath, 'utf-8');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
173
256
|
// Generate sections landing for framework
|
|
174
257
|
await generateSectionsLandingForFramework(
|
|
175
258
|
projectDir,
|
|
176
259
|
frameworkConfig,
|
|
177
260
|
{
|
|
178
261
|
sections: processedSections,
|
|
262
|
+
navbarContent,
|
|
263
|
+
footerContent,
|
|
179
264
|
config: landingConfig,
|
|
180
265
|
}
|
|
181
266
|
);
|
|
@@ -213,7 +298,7 @@ async function generateLandingForFramework(projectDir, frameworkConfig, landingD
|
|
|
213
298
|
* Generate Astro landing page (standalone, no template imports)
|
|
214
299
|
*/
|
|
215
300
|
async function generateAstroLanding(projectDir, landingData) {
|
|
216
|
-
const { sourcePath, htmlFiles, cssFiles, jsFiles, config } = landingData;
|
|
301
|
+
const { sourcePath, htmlFiles, cssFiles, jsFiles, navbarContent, footerContent, config } = landingData;
|
|
217
302
|
|
|
218
303
|
// Read main HTML file
|
|
219
304
|
const mainHtml = htmlFiles.includes('index.html') ? 'index.html' : htmlFiles[0];
|
|
@@ -224,13 +309,17 @@ async function generateAstroLanding(projectDir, landingData) {
|
|
|
224
309
|
|
|
225
310
|
let htmlContent = await readFile(join(sourcePath, mainHtml), 'utf-8');
|
|
226
311
|
|
|
227
|
-
// Read CSS files
|
|
312
|
+
// Read CSS files and write to a separate file
|
|
228
313
|
let cssContent = '';
|
|
229
314
|
for (const cssFile of cssFiles) {
|
|
230
315
|
const css = await readFile(join(sourcePath, cssFile), 'utf-8');
|
|
231
316
|
cssContent += `/* ${cssFile} */\n${css}\n\n`;
|
|
232
317
|
}
|
|
233
318
|
|
|
319
|
+
// Write landing CSS to a separate file so Vite processes it through the full pipeline
|
|
320
|
+
const landingCssPath = join(projectDir, 'src', 'styles', 'landing.css');
|
|
321
|
+
await writeFile(landingCssPath, cssContent, 'utf-8');
|
|
322
|
+
|
|
234
323
|
// Read JS files
|
|
235
324
|
let jsContent = '';
|
|
236
325
|
for (const jsFile of jsFiles) {
|
|
@@ -238,13 +327,33 @@ async function generateAstroLanding(projectDir, landingData) {
|
|
|
238
327
|
jsContent += `// ${jsFile}\n${js}\n\n`;
|
|
239
328
|
}
|
|
240
329
|
|
|
330
|
+
// Determine header/footer: hidden ('__hidden__'), custom (string HTML), or default (null)
|
|
331
|
+
const navbarIsHidden = navbarContent === '__hidden__';
|
|
332
|
+
const footerIsHidden = footerContent === '__hidden__';
|
|
333
|
+
const hasCustomNavbar = !navbarIsHidden && !!navbarContent;
|
|
334
|
+
const hasCustomFooter = !footerIsHidden && !!footerContent;
|
|
335
|
+
|
|
336
|
+
const headerImport = navbarIsHidden || hasCustomNavbar ? '' : "import Header from '../components/Header.astro';";
|
|
337
|
+
const footerImport = footerIsHidden || hasCustomFooter ? '' : "import Footer from '../components/Footer.astro';";
|
|
338
|
+
const headerRender = navbarIsHidden
|
|
339
|
+
? ''
|
|
340
|
+
: hasCustomNavbar
|
|
341
|
+
? `<header class="landing-custom-navbar">\n ${navbarContent}\n </header>`
|
|
342
|
+
: '<Header />';
|
|
343
|
+
const footerRender = footerIsHidden
|
|
344
|
+
? ''
|
|
345
|
+
: hasCustomFooter
|
|
346
|
+
? `<footer class="landing-custom-footer">\n ${footerContent}\n </footer>`
|
|
347
|
+
: '<Footer />';
|
|
348
|
+
|
|
241
349
|
// Generate standalone Astro component
|
|
242
350
|
const astroContent = `---
|
|
243
351
|
// Custom landing page - auto-generated by Lito CLI
|
|
244
352
|
// Source: _landing/ folder
|
|
245
353
|
import '../styles/global.css';
|
|
246
|
-
import
|
|
247
|
-
|
|
354
|
+
import '../styles/landing.css';
|
|
355
|
+
${headerImport}
|
|
356
|
+
${footerImport}
|
|
248
357
|
import { getConfigFile } from '../utils/config';
|
|
249
358
|
|
|
250
359
|
const config = await getConfigFile();
|
|
@@ -269,18 +378,15 @@ const config = await getConfigFile();
|
|
|
269
378
|
document.documentElement.classList.add('light');
|
|
270
379
|
}
|
|
271
380
|
</script>
|
|
272
|
-
<style>
|
|
273
|
-
${cssContent}
|
|
274
|
-
</style>
|
|
275
381
|
</head>
|
|
276
382
|
<body class="bg-background text-foreground font-sans antialiased">
|
|
277
|
-
|
|
383
|
+
${headerRender}
|
|
278
384
|
|
|
279
385
|
<main class="landing-custom">
|
|
280
386
|
${htmlContent}
|
|
281
387
|
</main>
|
|
282
388
|
|
|
283
|
-
|
|
389
|
+
${footerRender}
|
|
284
390
|
|
|
285
391
|
${jsContent ? `<script>\n${jsContent}\n</script>` : ''}
|
|
286
392
|
</body>
|
|
@@ -571,7 +677,7 @@ async function generateSectionsLandingForFramework(projectDir, frameworkConfig,
|
|
|
571
677
|
* Generate Astro sections landing page
|
|
572
678
|
*/
|
|
573
679
|
async function generateAstroSectionsLanding(projectDir, landingData) {
|
|
574
|
-
const { sections, config } = landingData;
|
|
680
|
+
const { sections, navbarContent, footerContent, config } = landingData;
|
|
575
681
|
|
|
576
682
|
// Generate section renders
|
|
577
683
|
const sectionRenders = sections.map((section, index) => {
|
|
@@ -591,11 +697,30 @@ async function generateAstroSectionsLanding(projectDir, landingData) {
|
|
|
591
697
|
}
|
|
592
698
|
}).join('\n');
|
|
593
699
|
|
|
700
|
+
// Determine header/footer: hidden ('__hidden__'), custom (string HTML), or default (null)
|
|
701
|
+
const navbarIsHidden = navbarContent === '__hidden__';
|
|
702
|
+
const footerIsHidden = footerContent === '__hidden__';
|
|
703
|
+
const hasCustomNavbar = !navbarIsHidden && !!navbarContent;
|
|
704
|
+
const hasCustomFooter = !footerIsHidden && !!footerContent;
|
|
705
|
+
|
|
706
|
+
const headerImport = navbarIsHidden || hasCustomNavbar ? '' : "import Header from '../components/Header.astro';";
|
|
707
|
+
const footerImport = footerIsHidden || hasCustomFooter ? '' : "import Footer from '../components/Footer.astro';";
|
|
708
|
+
const headerRender = navbarIsHidden
|
|
709
|
+
? ''
|
|
710
|
+
: hasCustomNavbar
|
|
711
|
+
? `<header class="landing-custom-navbar">\n ${navbarContent}\n </header>`
|
|
712
|
+
: '<Header />';
|
|
713
|
+
const footerRender = footerIsHidden
|
|
714
|
+
? ''
|
|
715
|
+
: hasCustomFooter
|
|
716
|
+
? `<footer class="landing-custom-footer">\n ${footerContent}\n </footer>`
|
|
717
|
+
: '<Footer />';
|
|
718
|
+
|
|
594
719
|
const astroContent = `---
|
|
595
720
|
// Sections-based landing page - auto-generated by Lito CLI
|
|
596
721
|
import '../styles/global.css';
|
|
597
|
-
|
|
598
|
-
|
|
722
|
+
${headerImport}
|
|
723
|
+
${footerImport}
|
|
599
724
|
import { getConfigFile } from '../utils/config';
|
|
600
725
|
|
|
601
726
|
const config = await getConfigFile();
|
|
@@ -621,13 +746,13 @@ const config = await getConfigFile();
|
|
|
621
746
|
</script>
|
|
622
747
|
</head>
|
|
623
748
|
<body class="bg-background text-foreground font-sans antialiased">
|
|
624
|
-
|
|
749
|
+
${headerRender}
|
|
625
750
|
|
|
626
751
|
<main class="landing-sections">
|
|
627
752
|
${sectionRenders}
|
|
628
753
|
</main>
|
|
629
754
|
|
|
630
|
-
|
|
755
|
+
${footerRender}
|
|
631
756
|
</body>
|
|
632
757
|
</html>
|
|
633
758
|
`;
|
package/src/core/sync.js
CHANGED
|
@@ -13,7 +13,7 @@ const KNOWN_LOCALES = [
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
// Special folders that are not content
|
|
16
|
-
const SPECIAL_FOLDERS = ['_assets', '_css', '_images', '_static', '_landing', 'public'];
|
|
16
|
+
const SPECIAL_FOLDERS = ['_assets', '_css', '_images', '_static', '_landing', '_navbar', '_footer', 'public'];
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Get i18n configuration from docs-config.json
|