Skip to content

Commit 1aa9d6e

Browse files
committed
refactor(cli,src): migrate CLI to layered TS bridge and harden FSD boundaries
1 parent ed328ff commit 1aa9d6e

100 files changed

Lines changed: 3343 additions & 4324 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,6 @@ gitpagedocs/
195195
1.1.1/...
196196
```
197197

198-
### Source code viewer (`source-viewer`)
199-
200-
Each version includes a self-contained **Source code** HTML page per language (`en`, `pt`, `es`). The viewer:
201-
202-
- **Scans** `src/`, `cli/`, and root files (README.md, package.json, next.config.ts, tsconfig.json, etc.)
203-
- **Displays** a GitHub-style dark interface with file tree, search, syntax highlighting, line numbers, copy button
204-
- **Special handling** for README.md: toggle between rendered Markdown preview and raw code
205-
- **Uses** highlight.js and marked from CDN; single HTML file, no build step
206-
207198
Local layout mode adds:
208199

209200
```text
@@ -213,24 +204,6 @@ gitpagedocs/layouts/
213204
templates/*.json
214205
```
215206

216-
### Documentation structure
217-
218-
| Page | Description |
219-
|------|-------------|
220-
| Getting Started | Setup from zero, prerequisites, install, generate, local run, troubleshooting |
221-
| Project overview | Stack, goals, folder structure, architecture summary, data flow |
222-
| Functionalities | CLI commands and options, config, deployment, architecture, themes, FAQ, source viewer |
223-
| GitHub issues and projects | Issues (bugs, features), Projects (Kanban, tables), workflows |
224-
| Introduction to Git | Basic Git concepts for beginners |
225-
| Source code | GitHub-style file tree viewer with syntax highlighting and Markdown preview |
226-
| Configuration | Site, layout, VersionControl sections; content types; env vars |
227-
| Deployment | Official site, self-hosted GitHub Pages, npm publish |
228-
| Architecture | Route parser, load-docs, docs-shell; data flow; reliability |
229-
| Themes | Layout strategies, template model, runtime behavior |
230-
| FAQ | Remote repos, version path, theme selection, GitHub Pages behavior |
231-
232-
Docs are versioned (`1.0.0`, `1.1.0`, `1.1.1`) and localized (`en`, `pt`, `es`).
233-
234207
## Configuration Keys (Layout Source)
235208

236209
Main layout source keys in `gitpagedocs/config.json` (or `config.js` / `config.ts`):
@@ -327,7 +300,7 @@ All routes for accessing documentation files on the official site or self-hosted
327300

328301
**HTML pages** (by slug)
329302

330-
- Source code viewer (GitHub-style file tree, syntax highlighting, README preview):
303+
- Source code viewer:
331304
https://vidigal-code.github.io/git-page-docs/Vidigal-code/git-page-docs/v/1.0.0/?lang=en&menu=en&name=source-viewer
332305

333306
**Video pages** (route id 1–4; pages combine MD + HTML + Video by id)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { CliOptions } from "../../domain/models/cli-options";
2+
3+
export interface CliRuntimeParams {
4+
root: string;
5+
pkgRoot: string;
6+
prebuiltDir: string;
7+
buildConfigArtifacts: (...args: unknown[]) => unknown;
8+
createThemeTemplate: (...args: unknown[]) => unknown;
9+
layouts: unknown[];
10+
}
11+
12+
export interface CliCommandContext extends CliRuntimeParams {
13+
options: CliOptions;
14+
}
15+
16+
export interface CliCommandRunner {
17+
runConfigOnly: (params: CliCommandContext) => Promise<void>;
18+
runHome: (params: CliCommandContext) => Promise<void>;
19+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { CliOptions } from "../../domain/models/cli-options";
2+
import type { CliCommandRunner, CliRuntimeParams } from "../ports/cli-runtime-ports";
3+
4+
export async function dispatchMode(
5+
options: CliOptions,
6+
params: CliRuntimeParams,
7+
runner: CliCommandRunner,
8+
): Promise<void> {
9+
if (options.mode === "home") {
10+
await runner.runHome({ ...params, options });
11+
return;
12+
}
13+
await runner.runConfigOnly({ ...params, options });
14+
}

cli/builders/source-viewer.mjs

Lines changed: 48 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ function collectSourceFiles(projectRoot) {
2525
const files = {};
2626
function scan(dir, prefix = "") {
2727
if (!existsSync(dir)) return;
28-
const entries = readdirSync(dir, { withFileTypes: true });
28+
const entries = readdirSync(dir, { withFileTypes: true })
29+
.sort((a, b) => a.name.localeCompare(b.name));
2930
for (const e of entries) {
3031
const name = e.name;
3132
if (name === "node_modules" || name.startsWith(".")) continue;
@@ -81,81 +82,78 @@ export function generateSourceViewerHtml(root) {
8182
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/markdown.min.js"></script>
8283
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
8384
<style>
84-
/* GitHub Dark 100% - exact colors from github.com */
85+
/* GitHub dark theme - variables */
8586
:root{
86-
--color-canvas-default:#0d1117;
87-
--color-canvas-subtle:#161b22;
88-
--color-canvas-inset:#010409;
89-
--color-border-default:#30363d;
90-
--color-border-muted:#21262d;
91-
--color-fg-default:#e6edf3;
92-
--color-fg-muted:#8b949e;
93-
--color-fg-subtle:#6e7681;
94-
--color-accent-fg:#58a6ff;
95-
--color-accent-subtle:rgba(56,139,253,0.15);
96-
--font-sans:-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif;
97-
--font-mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
87+
--github-bg: #0d1117;
88+
--github-bg-secondary: #161b22;
89+
--github-bg-tertiary: #21262d;
90+
--github-border: #30363d;
91+
--github-border-muted: #21262d;
92+
--github-fg: #e6edf3;
93+
--github-fg-muted: #8b949e;
94+
--github-accent: #58a6ff;
95+
--github-accent-soft: #79c0ff;
9896
}
9997
*{box-sizing:border-box;margin:0;padding:0}
100-
body{font-family:var(--font-sans);background:var(--color-canvas-default);color:var(--color-fg-default);min-height:100vh;font-size:14px;line-height:1.5}
98+
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;background:var(--github-bg);color:var(--github-fg);min-height:100vh;font-size:14px;line-height:1.5}
10199
102-
/* Top bar - GitHub blob header */
103-
.top-bar{background:var(--color-canvas-subtle);border-bottom:1px solid var(--color-border-muted);padding:12px 16px;min-height:52px;display:flex;align-items:center;gap:4px;flex-wrap:wrap}
104-
.top-bar .crumb{color:var(--color-fg-muted);text-decoration:none}
105-
.top-bar .crumb:hover{color:var(--color-accent-fg)}
106-
.top-bar .crumb-sep{color:var(--color-fg-muted);user-select:none}
107-
.top-bar .file-name{color:var(--color-fg-default);font-weight:600;font-family:var(--font-mono)}
100+
/* Top bar - GitHub style */
101+
.top-bar{background:var(--github-bg-secondary);border-bottom:1px solid var(--github-border-muted);padding:8px 16px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
102+
.top-bar .crumb{color:var(--github-fg-muted);text-decoration:none}
103+
.top-bar .crumb:hover{color:var(--github-accent)}
104+
.top-bar .crumb-sep{color:var(--github-fg-muted);user-select:none}
105+
.top-bar .file-name{color:var(--github-fg);font-weight:600}
108106
109107
/* Layout */
110-
.layout{display:flex;height:calc(100vh - 52px)}
108+
.layout{display:flex;height:calc(100vh - 45px)}
111109
112110
/* Sidebar - GitHub file tree */
113-
.sidebar{width:260px;min-width:200px;background:var(--color-canvas-subtle);border-right:1px solid var(--color-border-muted);overflow-y:auto;padding:8px 0;flex-shrink:0}
111+
.sidebar{width:260px;min-width:200px;background:var(--github-bg-secondary);border-right:1px solid var(--github-border-muted);overflow-y:auto;padding:8px 0;flex-shrink:0}
114112
.sidebar .folder,.sidebar .file{padding:4px 12px 4px 8px;font-size:13px;cursor:pointer;display:flex;align-items:center;gap:6px;border-radius:6px;margin:0 8px}
115-
.sidebar .folder:hover,.sidebar .file:hover{background:var(--color-border-muted)}
116-
.sidebar .file{color:var(--color-fg-muted)}
117-
.sidebar .file.active{color:var(--color-accent-fg);background:var(--color-accent-subtle)}
113+
.sidebar .folder:hover,.sidebar .file:hover{background:var(--github-bg-tertiary)}
114+
.sidebar .file{color:var(--github-fg-muted)}
115+
.sidebar .file.active{color:var(--github-accent);background:var(--github-bg-tertiary)}
118116
.sidebar .icon{width:16px;text-align:center;flex-shrink:0}
119117
.sidebar .icon svg{vertical-align:middle}
120-
.sidebar .folder .icon{color:var(--color-accent-fg)}
118+
.sidebar .folder .icon{color:var(--github-accent-soft)}
121119
.sidebar .chevron{width:16px;transition:transform .15s;flex-shrink:0}
122120
.sidebar .folder.collapsed .chevron{transform:rotate(-90deg)}
123121
.sidebar .children{margin-left:4px}
124122
.sidebar .children.hidden{display:none}
125-
.sidebar .search-wrap{padding:8px;border-bottom:1px solid var(--color-border-muted)}
126-
.sidebar .search-input{width:100%;padding:6px 10px;font-size:12px;border:1px solid var(--color-border-default);border-radius:6px;background:var(--color-canvas-default);color:var(--color-fg-default);outline:none}
127-
.sidebar .search-input:focus{border-color:var(--color-accent-fg)}
128-
.sidebar .search-input::placeholder{color:var(--color-fg-muted)}
129-
.sidebar .tree-actions{display:flex;gap:4px;padding:4px 8px;border-bottom:1px solid var(--color-border-muted)}
130-
.sidebar .tree-btn{padding:4px 8px;font-size:11px;border:1px solid var(--color-border-default);border-radius:4px;background:var(--color-border-muted);color:var(--color-fg-muted);cursor:pointer}
131-
.sidebar .tree-btn:hover{color:var(--color-fg-default);background:var(--color-border-default)}
123+
.sidebar .search-wrap{padding:8px;border-bottom:1px solid var(--github-border-muted)}
124+
.sidebar .search-input{width:100%;padding:6px 10px;font-size:12px;border:1px solid var(--github-border);border-radius:6px;background:var(--github-bg);color:var(--github-fg);outline:none}
125+
.sidebar .search-input:focus{border-color:var(--github-accent)}
126+
.sidebar .search-input::placeholder{color:var(--github-fg-muted)}
127+
.sidebar .tree-actions{display:flex;gap:4px;padding:4px 8px;border-bottom:1px solid var(--github-border-muted)}
128+
.sidebar .tree-btn{padding:4px 8px;font-size:11px;border:1px solid var(--github-border);border-radius:4px;background:var(--github-bg-tertiary);color:var(--github-fg-muted);cursor:pointer}
129+
.sidebar .tree-btn:hover{color:var(--github-fg);background:var(--github-border)}
132130
133131
/* Content - GitHub file view */
134-
.content{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--color-canvas-default)}
135-
.content .file-header{background:var(--color-canvas-subtle);border-bottom:1px solid var(--color-border-muted);padding:8px 16px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0}
136-
.content .file-header .file-path{font-weight:600;color:var(--color-fg-default)}
137-
.content .file-header .copy-btn{padding:4px 12px;font-size:12px;border:1px solid var(--color-border-default);border-radius:6px;background:var(--color-border-muted);color:var(--color-fg-default);cursor:pointer}
138-
.content .file-header .copy-btn:hover{background:var(--color-border-default);border-color:var(--color-fg-muted)}
132+
.content{flex:1;display:flex;flex-direction:column;overflow:hidden;background:var(--github-bg)}
133+
.content .file-header{background:var(--github-bg-secondary);border-bottom:1px solid var(--github-border-muted);padding:8px 16px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0}
134+
.content .file-header .file-path{font-weight:600;color:var(--github-fg)}
135+
.content .file-header .copy-btn{padding:4px 12px;font-size:12px;border:1px solid var(--github-border);border-radius:6px;background:var(--github-bg-tertiary);color:var(--github-fg);cursor:pointer}
136+
.content .file-header .copy-btn:hover{background:var(--github-border);border-color:var(--github-fg-muted)}
139137
.content .code-wrap{flex:1;overflow:auto}
140138
.content .code-table{width:100%;border-collapse:collapse;font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;font-size:12px;line-height:1.45}
141139
.content .code-table td{vertical-align:top;padding:0}
142-
.content .line-nums{padding:16px 0;text-align:right;user-select:none;color:var(--color-fg-muted);background:var(--color-canvas-subtle);border-right:1px solid var(--color-border-muted);width:1%;min-width:50px}
140+
.content .line-nums{padding:16px 0;text-align:right;user-select:none;color:var(--github-fg-muted);background:var(--github-bg-secondary);border-right:1px solid var(--github-border-muted);width:1%;min-width:50px}
143141
.content .line-nums span{display:block;padding:0 16px}
144142
.content .line-code{padding:16px 0;padding-left:16px}
145143
.content .line-code .line{display:block;min-height:1.45em;white-space:pre}
146-
.content .empty{color:var(--color-fg-muted);padding:24px;font-style:italic}
144+
.content .empty{color:var(--github-fg-muted);padding:24px;font-style:italic}
147145
.content .md-preview{padding:24px;line-height:1.6}
148146
.content .md-preview h1,.content .md-preview h2,.content .md-preview h3{margin-top:1em;margin-bottom:0.5em;font-weight:600}
149-
.content .md-preview code{background:var(--color-border-muted);padding:2px 6px;border-radius:4px;font-size:0.9em}
150-
.content .md-preview pre{background:var(--color-border-muted);padding:16px;overflow-x:auto;border-radius:6px;font-size:13px}
147+
.content .md-preview code{background:var(--github-bg-tertiary);padding:2px 6px;border-radius:4px;font-size:0.9em}
148+
.content .md-preview pre{background:var(--github-bg-tertiary);padding:16px;overflow-x:auto;border-radius:6px;font-size:13px}
151149
.content .btn-group{display:flex;gap:8px;margin-bottom:16px}
152-
.content .btn{padding:6px 12px;border:1px solid var(--color-border-default);border-radius:6px;background:var(--color-border-muted);color:var(--color-fg-default);cursor:pointer;font-size:12px}
153-
.content .btn.active{background:var(--color-accent-fg);border-color:var(--color-accent-fg);color:#fff}
154-
.content .btn:hover{background:var(--color-border-default)}
150+
.content .btn{padding:6px 12px;border:1px solid var(--github-border);border-radius:6px;background:var(--github-bg-tertiary);color:var(--github-fg);cursor:pointer;font-size:12px}
151+
.content .btn.active{background:var(--github-accent);border-color:var(--github-accent);color:#fff}
152+
.content .btn:hover{background:var(--github-border)}
155153
156154
@media(max-width:767px){
157155
.layout{flex-direction:column;height:auto;min-height:100vh}
158-
.sidebar{width:100%;max-height:200px;border-right:none;border-bottom:1px solid var(--color-border-muted)}
156+
.sidebar{width:100%;max-height:200px;border-right:none;border-bottom:1px solid var(--github-border-muted)}
159157
.content .code-wrap{min-height:400px}
160158
}
161159
</style>
@@ -204,26 +202,14 @@ function selectFile(path){
204202
document.querySelectorAll(".sidebar .file.active").forEach(function(n){n.classList.remove("active")});
205203
document.querySelectorAll(".sidebar .folder.active").forEach(function(n){n.classList.remove("active")});
206204
var node=document.querySelector('.sidebar .file[data-path="'+path.replace(/"/g,'\\"')+'"]');
207-
if(node){
208-
node.classList.add("active");
209-
var parent=node.parentElement;
210-
while(parent&&parent.id!=="tree"){
211-
var folder=parent.previousElementSibling;
212-
if(folder&&folder.classList.contains("folder")){
213-
folder.classList.remove("collapsed");
214-
parent.classList.remove("hidden");
215-
}
216-
parent=parent.parentElement;
217-
}
218-
node.scrollIntoView({block:"nearest"});
219-
}
205+
if(node){node.classList.add("active");node.scrollIntoView({block:"nearest"})}
220206
document.getElementById("breadcrumbFile").textContent=path;
221207
document.getElementById("fileHeader").style.display="block";
222208
document.getElementById("headerPath").textContent=path;
223209
var content=files[path]||"";
224-
var isMd=path.toLowerCase().endsWith(".md");
210+
var isReadme=path.toLowerCase()==="readme.md";
225211
var viewer=document.getElementById("viewer");
226-
if(isMd){
212+
if(isReadme){
227213
var btnHtml='<div class="btn-group"><button class="btn'+(viewMode==='preview'?' active':'')+'" data-mode="preview">Preview</button><button class="btn'+(viewMode==='code'?' active':'')+'" data-mode="code">Code</button></div>';
228214
if(viewMode==="preview"&&typeof marked!=="undefined"){
229215
viewer.innerHTML=btnHtml+'<div class="md-preview">'+marked.parse(content||"")+'</div>';

cli/builders/version-config-builder.mjs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import {
1212
ROUTE_META_ID3,
1313
ROUTE_META_ID4,
1414
ROUTE_META_ID5,
15-
ROUTE_META_ID6,
16-
ROUTE_META_ID7,
17-
ROUTE_META_ID8,
18-
ROUTE_META_ID9,
19-
ROUTE_META_ID10,
2015
VIDEO_META_ID1,
2116
VIDEO_META_ID2,
2217
VIDEO_META_ID3,
@@ -25,15 +20,12 @@ import {
2520
} from "../data/route-metas.mjs";
2621
import { buildMdRoute, buildHtmlRoute, buildVideoRoute } from "./route-builders.mjs";
2722

28-
const ROUTE_METAS = {
29-
1: ROUTE_META_ID1, 2: ROUTE_META_ID2, 3: ROUTE_META_ID3, 4: ROUTE_META_ID4, 5: ROUTE_META_ID5,
30-
6: ROUTE_META_ID6, 7: ROUTE_META_ID7, 8: ROUTE_META_ID8, 9: ROUTE_META_ID9, 10: ROUTE_META_ID10,
31-
};
23+
const ROUTE_METAS = { 1: ROUTE_META_ID1, 2: ROUTE_META_ID2, 3: ROUTE_META_ID3, 4: ROUTE_META_ID4, 5: ROUTE_META_ID5 };
3224
const VIDEO_METAS = { 1: VIDEO_META_ID1, 2: VIDEO_META_ID2, 3: VIDEO_META_ID3, 4: VIDEO_META_ID4 };
3325

3426
function buildVersionMdRoutes(versionId) {
3527
const base = `gitpagedocs/docs/versions/${versionId}`;
36-
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((id) => {
28+
return [1, 2, 3, 4, 5].map((id) => {
3729
const paths = ROUTE_PATHS[id];
3830
const meta = ROUTE_METAS[id];
3931
const pathByLang = {
@@ -76,7 +68,7 @@ function buildVersionVideoRoutes(versionId) {
7668

7769
function buildVersionMenus(versionId) {
7870
const base = `gitpagedocs/docs/versions/${versionId}`;
79-
const menuMd = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((id) => ({
71+
const menuMd = [1, 2, 3, 4, 5].map((id) => ({
8072
id: id,
8173
pt: { title: ROUTE_METAS[id].titles.pt, "path-click": `${base}/pt/${ROUTE_PATHS[id].pt}` },
8274
en: { title: ROUTE_METAS[id].titles.en, "path-click": `${base}/en/${ROUTE_PATHS[id].en}` },

0 commit comments

Comments
 (0)