explicode 1.0.0 → 1.0.2
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/README.md +24 -53
- package/ghmd-dark.css +12 -41
- package/ghmd-light.css +15 -13
- package/index.template.html +192 -172
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -2,40 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
> Turn your codebase into documentation.
|
|
4
4
|
|
|
5
|
-
**Explicode** lets you write rich Markdown documentation directly inside your code comments, turning a single source file into both runnable code and beautifully rendered documentation.
|
|
5
|
+
**Explicode** is an open-source project that lets you write rich Markdown documentation directly inside your code comments, turning a single source file into both runnable code and beautifully rendered documentation. The VS Code extension provides live previews of your documentation right inside your IDE. Additionally, the `npm` package can convert supported source files into `.md` Markdown via the terminal or generate a GitHub Pages-ready `docs/` folder.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://marketplace.visualstudio.com/items?itemName=Explicode.explicode)[](https://marketplace.visualstudio.com/items?itemName=Explicode.explicode)
|
|
8
8
|
|
|
9
|
-
[](https://marketplace.visualstudio.com/items?itemName=Explicode.explicode)
|
|
10
|
-
[](https://marketplace.visualstudio.com/items?itemName=Explicode.explicode)
|
|
11
9
|
[](https://github.com/benatfroemming/explicode)
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## How It Works
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Explicode lets you write Markdown directly inside your source code comments. The rules for each language are:
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
- **Python** — Triple-quoted docstrings (`""" ... """` or `''' ... '''`) placed in the normal docstring position are treated as prose. All other code is rendered as code blocks.
|
|
16
|
+
- **C-style languages** — Block comments (`/* ... */`) are treated as prose, while the rest of the code is rendered as code blocks.
|
|
17
|
+
- **Markdown files** — Passed through directly without changes.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
npx explicode build
|
|
21
|
-
npx explicode build --dark
|
|
22
|
-
npx explicode convert <file>
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
---
|
|
19
|
+
**Supported Languages:** Python, JavaScript, TypeScript, JSX, TSX, Java, C, C++, C#, CUDA, Rust, Go, Swift, Kotlin, Scala, Dart, PHP, Objective-C, SQL, Markdown
|
|
26
20
|
|
|
27
21
|
## Commands
|
|
28
22
|
|
|
29
23
|
### `convert`
|
|
30
24
|
|
|
31
|
-
Converts a single file to Markdown
|
|
25
|
+
Converts a single file to Markdown.
|
|
32
26
|
|
|
33
27
|
```bash
|
|
34
|
-
npx explicode convert
|
|
28
|
+
npx explicode convert <file> # usage
|
|
29
|
+
npx explicode convert src/utils.py # example: outputs `src/utils.py.md` alongside the original file
|
|
35
30
|
```
|
|
36
31
|
|
|
37
|
-
Outputs `src/utils.py.md` alongside the original file.
|
|
38
|
-
|
|
39
32
|
### `build`
|
|
40
33
|
|
|
41
34
|
Scans the current directory and generates a `docs/` folder.
|
|
@@ -50,32 +43,14 @@ npx explicode build --dark # dark theme
|
|
|
50
43
|
- Wraps code in syntax-highlighted fenced blocks
|
|
51
44
|
- Copies your `README.md` as the docs home page
|
|
52
45
|
- Generates a `_sidebar.md` with your full file tree
|
|
53
|
-
- Writes an `index.html` ready for Docsify + GitHub Pages
|
|
46
|
+
- Writes an `index.html` ready for [Docsify](https://docsify.js.org/#/) + [GitHub Pages](https://docs.github.com/pages)
|
|
54
47
|
- Adds "View on GitHub" source links if a GitHub remote is detected
|
|
55
48
|
|
|
56
49
|
**Skipped directories:** `node_modules`, `.git`, `dist`, `build`, `out`, `docs`, `.next`, `.nuxt`, `.cache`, `.venv`, `venv`, `__pycache__`
|
|
57
50
|
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Supported Languages
|
|
61
|
-
|
|
62
|
-
Python, JavaScript, TypeScript, JSX, TSX, Java, C, C++, C#, CUDA, Rust, Go, Swift, Kotlin, Scala, Dart, PHP, Objective-C, SQL, Markdown
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## How It Works
|
|
67
|
-
|
|
68
|
-
- **Python** — Triple-quoted docstrings (`"""` / `'''`) in docstring position become prose. Everything else becomes a code block.
|
|
69
|
-
- **C-style languages** — Block comments (`/* ... */`) become prose. Everything else becomes a code block.
|
|
70
|
-
- **Markdown** — Passed through as-is.
|
|
71
|
-
|
|
72
|
-
Consecutive segments of the same type are merged, producing clean alternating prose/code sections rather than fragmented blocks.
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
51
|
## GitHub Pages
|
|
77
52
|
|
|
78
|
-
After running `build`, push the `docs/` folder
|
|
53
|
+
After running `npx explicode build`, push your changes including the generated `docs/` folder to your repository. Then, in your repository settings, enable GitHub Pages using the `docs/` folder as the source. Your site will be live at:
|
|
79
54
|
|
|
80
55
|
```
|
|
81
56
|
https://<user>.github.io/<repo>
|
|
@@ -83,23 +58,23 @@ https://<user>.github.io/<repo>
|
|
|
83
58
|
|
|
84
59
|
### Automatic Deployment with GitHub Actions
|
|
85
60
|
|
|
86
|
-
Add the following file to your repository to automatically build and deploy docs on every push:
|
|
61
|
+
Add the following workflow file to your repository to automatically build and deploy your Explicode docs on every push:
|
|
87
62
|
|
|
88
|
-
`.github/workflows/<
|
|
63
|
+
`.github/workflows/<workflow_name>.yml`
|
|
89
64
|
|
|
90
65
|
```yml
|
|
91
|
-
name: Deploy Docs
|
|
66
|
+
name: Deploy Explicode Docs
|
|
92
67
|
|
|
93
68
|
on:
|
|
94
69
|
push:
|
|
95
|
-
branches: [main]
|
|
96
|
-
workflow_dispatch:
|
|
70
|
+
branches: [main] # replace with your desired branch
|
|
71
|
+
workflow_dispatch: # lets users trigger it manually from GitHub UI
|
|
97
72
|
|
|
98
73
|
jobs:
|
|
99
74
|
deploy:
|
|
100
75
|
runs-on: ubuntu-latest
|
|
101
76
|
permissions:
|
|
102
|
-
contents: write
|
|
77
|
+
contents: write # needed to push to gh-pages branch
|
|
103
78
|
|
|
104
79
|
steps:
|
|
105
80
|
- name: Checkout repo
|
|
@@ -111,7 +86,7 @@ jobs:
|
|
|
111
86
|
node-version: 20
|
|
112
87
|
|
|
113
88
|
- name: Build docs
|
|
114
|
-
run:
|
|
89
|
+
run: npx explicode build
|
|
115
90
|
|
|
116
91
|
- name: Deploy to GitHub Pages
|
|
117
92
|
uses: peaceiris/actions-gh-pages@v4
|
|
@@ -120,20 +95,18 @@ jobs:
|
|
|
120
95
|
publish_dir: ./docs
|
|
121
96
|
```
|
|
122
97
|
|
|
123
|
-
This publishes to a `gh-pages` branch.
|
|
98
|
+
This workflow publishes your docs to a `gh-pages` branch. In your repository settings, enable GitHub Pages and select the root `(/)` of the `gh-pages` branch as the source.
|
|
124
99
|
|
|
125
|
-
---
|
|
126
100
|
|
|
127
101
|
## Themes
|
|
128
102
|
|
|
129
103
|
| Flag | Style |
|
|
130
104
|
|------|-------|
|
|
131
|
-
|
|
|
132
|
-
| `--dark` | GitHub Dark
|
|
105
|
+
| `none` | GitHub Light |
|
|
106
|
+
| `--dark` | GitHub Dark |
|
|
133
107
|
|
|
134
|
-
The theme is baked into `docs/ghmd.css` at build time. Re-run with or without `--dark` to switch. You can further customize `index.html` or `ghmd.css` as needed.
|
|
135
108
|
|
|
136
|
-
|
|
109
|
+
The theme is baked into `docs/ghmd.css` at build time. Re-run with or without `--dark` to switch. You can further customize `index.html` or `ghmd.css` as needed.
|
|
137
110
|
|
|
138
111
|
## Output Structure
|
|
139
112
|
|
|
@@ -149,8 +122,6 @@ docs/
|
|
|
149
122
|
<your files>.md # rendered source files
|
|
150
123
|
```
|
|
151
124
|
|
|
152
|
-
---
|
|
153
|
-
|
|
154
125
|
## License
|
|
155
126
|
|
|
156
127
|
MIT
|
package/ghmd-dark.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Explicode — GitHub Dark theme for Docsify */
|
|
2
2
|
|
|
3
|
-
/*
|
|
3
|
+
/* Reset & base */
|
|
4
4
|
*, *::before, *::after { box-sizing: border-box; }
|
|
5
5
|
* { -webkit-font-smoothing: antialiased; -webkit-overflow-scrolling: touch; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-text-size-adjust: none; }
|
|
6
6
|
html, body { height: 100%; }
|
|
@@ -12,19 +12,20 @@ div#app { font-size: 30px; font-weight: lighter; margin: 40vh auto; text-align:
|
|
|
12
12
|
div#app:empty::before { content: 'Loading...'; }
|
|
13
13
|
.progress { background-color: #58a6ff; height: 2px; left: 0; position: fixed; right: 0; top: 0; transition: width 0.2s, opacity 0.4s; width: 0%; z-index: 999999; }
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
main { display: block; position: relative; width: 100vw; height: 100%; z-index: 0; }
|
|
15
|
+
main { display: block; position: relative; width: 100vw; height: 100%; }
|
|
17
16
|
main.hidden { display: none; }
|
|
18
17
|
body.sticky .sidebar, body.sticky .sidebar-toggle { position: fixed; }
|
|
19
18
|
.content { padding-top: 60px; position: absolute; top: 0; right: 0; bottom: 0; left: 270px; transition: left 280ms cubic-bezier(0.4,0,0.2,1); }
|
|
20
19
|
body.close .content { left: 0; }
|
|
21
20
|
|
|
22
|
-
/* ── Sidebar ── */
|
|
23
21
|
.sidebar { background-color: #161b22; border-right: 1px solid #30363d; color: #e6edf3; display: flex; flex-direction: column; overflow: hidden; position: absolute; top: 0; bottom: 0; left: 0; transition: transform 280ms cubic-bezier(0.4,0,0.2,1); width: 270px; z-index: 20; }
|
|
24
|
-
.sidebar > h1 { margin: 0; font-size: 1.05rem; font-weight: 600; text-align: center; flex-shrink: 0; padding: 14px 16px 13px; border-bottom: 1px solid #30363d; }
|
|
22
|
+
.sidebar > h1 { margin: 0; font-size: 1.05rem; font-weight: 600; text-align: center; flex-shrink: 0; padding: 14px 16px 13px; border-bottom: 1px solid #30363d; position: relative; display: flex; align-items: center; justify-content: center; }
|
|
25
23
|
.sidebar > h1 a { color: #e6edf3; text-decoration: none; display: block; }
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
#xp-sidebar-close { display: none; position: absolute; left: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: #8b949e; font-size: 14px; line-height: 1; padding: 4px 6px; border-radius: 4px; transition: color 0.15s, background 0.15s; }
|
|
26
|
+
#xp-sidebar-close:hover { color: #e6edf3; background: rgba(177,186,196,0.08); }
|
|
27
|
+
@media screen and (max-width: 599px) { #xp-sidebar-close { display: flex; align-items: center; justify-content: center; } }
|
|
28
|
+
|
|
28
29
|
.xp-sidebar-scroll { flex: 1; overflow-y: auto; padding: 24px 0 8px; min-height: 0; }
|
|
29
30
|
.xp-sidebar-scroll .sidebar-nav { margin-left: 8px; padding-bottom: 16px; }
|
|
30
31
|
.xp-sidebar-scroll::-webkit-scrollbar { width: 4px; }
|
|
@@ -39,30 +40,22 @@ body.close .content { left: 0; }
|
|
|
39
40
|
.sidebar li > p { margin-left: 8px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #6e7681; padding: 12px 8px 4px; }
|
|
40
41
|
.sidebar ul li .section-link { font-size: 12px; color: #8b949e; }
|
|
41
42
|
|
|
42
|
-
/* ── Sidebar footer ── */
|
|
43
43
|
.xp-sidebar-footer { flex-shrink: 0; border-top: 1px solid #21262d; padding: 10px 16px; display: flex; align-items: center; justify-content: center; }
|
|
44
44
|
.xp-sidebar-footer span, .xp-sidebar-footer { font-size: 11px; color: #484f58; white-space: nowrap; }
|
|
45
45
|
.xp-sidebar-footer a { color: #6e7681; text-decoration: none; font-size: 11px; }
|
|
46
46
|
.xp-sidebar-footer a:hover { color: #8b949e; text-decoration: underline; }
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
#xp-mobile-btn {
|
|
48
|
+
#xp-mobile-btn { display: none; position: fixed; top: 14px; left: 14px; z-index: 18; width: 36px; height: 36px; background: none; border: none; cursor: pointer; align-items: center; justify-content: center; padding: 0; color: #484f58; transition: color 0.15s; }
|
|
49
|
+
#xp-mobile-btn:hover { color: #8b949e; }
|
|
50
50
|
@media screen and (max-width: 599px) { #xp-mobile-btn { display: flex; } }
|
|
51
51
|
.xp-mb-bars { display: flex; flex-direction: column; gap: 5px; align-items: center; justify-content: center; }
|
|
52
|
-
.xp-mb-bars span { display: block; width: 16px; height: 1.5px; background:
|
|
53
|
-
|
|
54
|
-
#xp-mobile-btn[data-open="false"] .xp-mb-bars { display: flex; }
|
|
55
|
-
#xp-mobile-btn[data-open="false"] .xp-mb-close { display: none; }
|
|
56
|
-
#xp-mobile-btn[data-open="true"] .xp-mb-bars { display: none; }
|
|
57
|
-
#xp-mobile-btn[data-open="true"] .xp-mb-close { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
|
|
58
|
-
|
|
59
|
-
/* ── Folder buttons ── */
|
|
52
|
+
.xp-mb-bars span { display: block; width: 16px; height: 1.5px; background: currentColor; border-radius: 2px; }
|
|
53
|
+
|
|
60
54
|
.xp-folder-btn { display: flex; align-items: center; gap: 6px; width: calc(100% - 16px); margin: 0 8px; background: none; border: none; cursor: pointer; color: #8b949e; font-size: 13px; font-weight: 600; padding: 5px 8px; border-radius: 6px; text-align: left; transition: background 0.1s, color 0.1s; }
|
|
61
55
|
.xp-folder-btn:hover { background: rgba(177,186,196,0.08); color: #c9d1d9; }
|
|
62
56
|
.xp-folder-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
63
57
|
.sidebar ul li ul { border-left: 1px solid #21262d; margin-left: 21px !important; padding-left: 0; }
|
|
64
58
|
|
|
65
|
-
/* ── SVG icons via CSS masks ── */
|
|
66
59
|
.xp-item-icon, .xp-folder-icon { display: inline-flex; flex-shrink: 0; width: 14px; height: 14px; background-color: currentColor; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; }
|
|
67
60
|
.xp-hash-icon { width: 12px; height: 12px; }
|
|
68
61
|
.xp-home-icon { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.906.664a1.749 1.749 0 0 1 2.187 0l5.25 4.2c.415.332.657.835.657 1.367v7.019A1.75 1.75 0 0 1 13.25 15h-3.5a.75.75 0 0 1-.75-.75V9H7v5.25a.75.75 0 0 1-.75.75h-3.5A1.75 1.75 0 0 1 1 13.25V6.23c0-.531.242-1.034.657-1.366l5.25-4.2Zm1.25 1.171a.25.25 0 0 0-.312 0l-5.25 4.2a.25.25 0 0 0-.094.196v7.019c0 .138.112.25.25.25H5.5V8.25a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 .75.75v5.25h2.75a.25.25 0 0 0 .25-.25V6.23a.25.25 0 0 0-.094-.195Z'/%3E%3C/svg%3E"); }
|
|
@@ -71,7 +64,6 @@ body.close .content { left: 0; }
|
|
|
71
64
|
.xp-folder-open { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M.513 1.513A1.75 1.75 0 0 1 1.75 1h3.5c.55 0 1.07.26 1.4.7l.9 1.2a.25.25 0 0 0 .2.1H14.25c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 15H1.75A1.75 1.75 0 0 1 0 13.25V2.75c0-.464.184-.91.513-1.237ZM1.75 2.5a.25.25 0 0 0-.25.25v.5h13V4.75a.25.25 0 0 0-.25-.25H7.75A1.75 1.75 0 0 1 6.35 3.8l-.9-1.2a.25.25 0 0 0-.2-.1H1.75Z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M.513 1.513A1.75 1.75 0 0 1 1.75 1h3.5c.55 0 1.07.26 1.4.7l.9 1.2a.25.25 0 0 0 .2.1H14.25c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 15H1.75A1.75 1.75 0 0 1 0 13.25V2.75c0-.464.184-.91.513-1.237ZM1.75 2.5a.25.25 0 0 0-.25.25v.5h13V4.75a.25.25 0 0 0-.25-.25H7.75A1.75 1.75 0 0 1 6.35 3.8l-.9-1.2a.25.25 0 0 0-.2-.1H1.75Z'/%3E%3C/svg%3E"); }
|
|
72
65
|
.xp-folder-closed { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1Z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1Z'/%3E%3C/svg%3E"); }
|
|
73
66
|
|
|
74
|
-
/* ── Nav link colors (dark) ── */
|
|
75
67
|
.sidebar ul li a { color: #8b949e; font-size: 13px; padding: 5px 8px 5px 16px; margin-right: 8px; border-radius: 6px; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 6px; transition: background 0.1s, color 0.1s; }
|
|
76
68
|
.sidebar ul li a:hover { background: rgba(177,186,196,0.08); color: #e6edf3; }
|
|
77
69
|
.sidebar ul li.active > a { background: rgba(56,139,253,0.1); color: #e6edf3; }
|
|
@@ -81,7 +73,6 @@ body.close .content { left: 0; }
|
|
|
81
73
|
.xp-folder-btn .xp-folder-icon { color: #484f58; }
|
|
82
74
|
.xp-folder-btn:hover .xp-folder-icon { color: #6e7681; }
|
|
83
75
|
|
|
84
|
-
/* ── Sub-sidebar header links (dark) ── */
|
|
85
76
|
.app-sub-sidebar { margin: 1px 0 3px 0 !important; padding-left: 0 !important; border-left: 1px solid #21262d !important; margin-left: 21px !important; }
|
|
86
77
|
.app-sub-sidebar li > a { padding: 4px 8px !important; font-size: 12px !important; color: #6e7681 !important; display: flex !important; align-items: center !important; gap: 5px !important; }
|
|
87
78
|
.app-sub-sidebar li > a:hover { color: #8b949e !important; background: rgba(177,186,196,0.06) !important; }
|
|
@@ -89,23 +80,18 @@ body.close .content { left: 0; }
|
|
|
89
80
|
.app-sub-sidebar .xp-item-icon { color: #484f58; }
|
|
90
81
|
.app-sub-sidebar li.active > a .xp-hash-icon { color: #388bfd; }
|
|
91
82
|
|
|
92
|
-
|
|
93
|
-
.xp-drag { position: fixed; top: 0; left: 270px; width: 6px; height: 100%; cursor: col-resize; z-index: 25; background: rgba(110,118,129,0.2); }
|
|
83
|
+
.xp-drag { position: fixed; top: 0; left: 270px; width: 6px; height: 100%; cursor: col-resize; z-index: 25; background: rgba(110,118,129,0.2); transition: opacity 280ms cubic-bezier(0.4,0,0.2,1); }
|
|
94
84
|
.xp-drag:hover, .xp-drag:active { background: rgba(88,166,255,0.5); }
|
|
95
85
|
|
|
96
|
-
/* ── Desktop toggle pill ── */
|
|
97
86
|
#xp-toggle { position: fixed; top: 50%; left: 269px; transform: translateY(-50%); z-index: 26; width: 16px; height: 48px; background: #21262d; border: 1px solid #30363d; border-left: none; border-radius: 0 6px 6px 0; cursor: pointer; color: #8b949e; font-size: 14px; line-height: 1; display: flex; align-items: center; justify-content: center; padding: 0; transition: background 0.15s, color 0.15s; }
|
|
98
87
|
#xp-toggle:hover { background: #30363d; color: #e6edf3; }
|
|
99
88
|
@media screen and (max-width: 599px) { #xp-toggle { display: none !important; } }
|
|
100
89
|
|
|
101
|
-
/* ── Hide docsify built-in toggle ── */
|
|
102
90
|
.sidebar-toggle { display: none !important; }
|
|
103
91
|
|
|
104
|
-
/* ── Close state ── */
|
|
105
92
|
body.close .sidebar { transform: translateX(-100%); }
|
|
106
93
|
body.close .content { left: 0; }
|
|
107
94
|
|
|
108
|
-
/* ── Markdown content ── */
|
|
109
95
|
.markdown-section { margin: 0 auto; max-width: 860px; padding: 32px 40px 60px; position: relative; }
|
|
110
96
|
.markdown-section > * { box-sizing: border-box; font-size: inherit; }
|
|
111
97
|
.markdown-section > :first-child { margin-top: 0 !important; }
|
|
@@ -144,7 +130,6 @@ body.close .content { left: 0; }
|
|
|
144
130
|
.markdown-section p.warn { color: #e6edf3; border-left: 3px solid #388bfd; padding: 0 1rem; margin: 2em 0; }
|
|
145
131
|
.markdown-section p.warn:before { content: "💡 Tip\A"; color: #388bfd; font-weight: 600; white-space: pre-wrap; line-height: 2.5; }
|
|
146
132
|
|
|
147
|
-
/* ── Prism — One Dark Pro ── */
|
|
148
133
|
.markdown-section pre { background-color: #1e2330 !important; border: 1px solid #2d3248; }
|
|
149
134
|
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: #636d83; font-style: italic; }
|
|
150
135
|
.token.namespace { opacity: 0.8; }
|
|
@@ -170,28 +155,14 @@ body.close .content { left: 0; }
|
|
|
170
155
|
.token.important { color: #e06c75; }
|
|
171
156
|
.token.entity { cursor: help; }
|
|
172
157
|
|
|
173
|
-
/* ── Unrendered (non-clickable) sidebar items ── */
|
|
174
158
|
.xp-unrendered { color: #3d444d; font-size: 13px; padding: 5px 8px 5px 16px; display: flex; align-items: center; gap: 6px; cursor: default; user-select: none; }
|
|
175
159
|
.xp-unrendered::before { content: ''; display: inline-flex; flex-shrink: 0; width: 14px; height: 14px; background-color: #3d444d; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688Z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688Z'/%3E%3C/svg%3E"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; }
|
|
176
|
-
|
|
177
|
-
/* ── GitHub source icon button ── */
|
|
178
160
|
span.xp-unrendered:hover { color: #6e7681; cursor: pointer; }
|
|
179
161
|
|
|
180
|
-
/* ── Title link ── */
|
|
181
|
-
.sidebar > h1 { position: relative; display: flex; align-items: center; justify-content: center; }
|
|
182
|
-
|
|
183
|
-
/* ── GitHub icon — fixed top-right, bare icon, all rendered pages ── */
|
|
184
162
|
#xp-gh-page-btn { position: fixed; top: 14px; right: 16px; z-index: 18; display: flex; align-items: center; justify-content: center; color: #484f58; text-decoration: none !important; transition: color 0.15s, transform 0.15s; }
|
|
185
163
|
#xp-gh-page-btn:hover { color: #8b949e; transform: scale(1.15); }
|
|
186
164
|
#xp-gh-page-btn svg { width: 18px; height: 18px; display: block; }
|
|
187
|
-
@media screen and (max-width: 599px) {
|
|
188
|
-
body:not(.close) #xp-gh-page-btn { display: none; }
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/* ── Drag hidden when sidebar closed ── */
|
|
192
|
-
body.close .xp-drag { opacity: 0 !important; pointer-events: none !important; }
|
|
193
165
|
|
|
194
|
-
/* ── Responsive ── */
|
|
195
166
|
@media screen and (max-width: 1100px) and (min-width: 600px) {
|
|
196
167
|
.sidebar { width: 240px; }
|
|
197
168
|
.content { left: 240px; }
|
package/ghmd-light.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Explicode — GitHub Light theme for Docsify */
|
|
2
2
|
|
|
3
|
-
/*
|
|
3
|
+
/* Reset & base */
|
|
4
4
|
*, *::before, *::after { box-sizing: border-box; }
|
|
5
5
|
* { -webkit-font-smoothing: antialiased; -webkit-overflow-scrolling: touch; -webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-text-size-adjust: none; }
|
|
6
6
|
html, body { height: 100%; }
|
|
@@ -11,14 +11,19 @@ body:not(.ready) [data-cloak], body:not(.ready) .app-nav, body:not(.ready) > nav
|
|
|
11
11
|
div#app { font-size: 30px; font-weight: lighter; margin: 40vh auto; text-align: center; color: #1f2328; }
|
|
12
12
|
div#app:empty::before { content: 'Loading...'; }
|
|
13
13
|
.progress { background-color: #0969da; height: 2px; left: 0; position: fixed; right: 0; top: 0; transition: width 0.2s, opacity 0.4s; width: 0%; z-index: 999999; }
|
|
14
|
-
main { display: block; position: relative; width: 100vw; height: 100%;
|
|
14
|
+
main { display: block; position: relative; width: 100vw; height: 100%; }
|
|
15
15
|
main.hidden { display: none; }
|
|
16
16
|
body.sticky .sidebar, body.sticky .sidebar-toggle { position: fixed; }
|
|
17
17
|
.content { padding-top: 60px; position: absolute; top: 0; right: 0; bottom: 0; left: 270px; transition: left 280ms cubic-bezier(0.4,0,0.2,1); }
|
|
18
18
|
body.close .content { left: 0; }
|
|
19
19
|
.sidebar { background-color: #f6f8fa; border-right: 1px solid #d0d7de; color: #1f2328; display: flex; flex-direction: column; overflow: hidden; position: absolute; top: 0; bottom: 0; left: 0; transition: transform 280ms cubic-bezier(0.4,0,0.2,1); width: 270px; z-index: 20; }
|
|
20
|
-
.sidebar > h1 { margin: 0; font-size: 1.05rem; font-weight: 600; text-align: center; flex-shrink: 0; padding: 14px 16px 13px; border-bottom: 1px solid #d0d7de; }
|
|
20
|
+
.sidebar > h1 { margin: 0; font-size: 1.05rem; font-weight: 600; text-align: center; flex-shrink: 0; padding: 14px 16px 13px; border-bottom: 1px solid #d0d7de; position: relative; display: flex; align-items: center; justify-content: center; }
|
|
21
21
|
.sidebar > h1 a { color: #1f2328; text-decoration: none; display: block; }
|
|
22
|
+
|
|
23
|
+
#xp-sidebar-close { display: none; position: absolute; left: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: #57606a; font-size: 14px; line-height: 1; padding: 4px 6px; border-radius: 4px; transition: color 0.15s, background 0.15s; }
|
|
24
|
+
#xp-sidebar-close:hover { color: #1f2328; background: rgba(208,215,222,0.32); }
|
|
25
|
+
@media screen and (max-width: 599px) { #xp-sidebar-close { display: flex; align-items: center; justify-content: center; } }
|
|
26
|
+
|
|
22
27
|
.xp-sidebar-scroll { flex: 1; overflow-y: auto; padding: 24px 0 8px; min-height: 0; }
|
|
23
28
|
.xp-sidebar-scroll .sidebar-nav { margin-left: 8px; padding-bottom: 16px; }
|
|
24
29
|
.xp-sidebar-scroll::-webkit-scrollbar { width: 4px; }
|
|
@@ -36,15 +41,13 @@ body.close .content { left: 0; }
|
|
|
36
41
|
.xp-sidebar-footer span, .xp-sidebar-footer { font-size: 11px; color: #8c959f; white-space: nowrap; }
|
|
37
42
|
.xp-sidebar-footer a { color: #6e7781; text-decoration: none; font-size: 11px; }
|
|
38
43
|
.xp-sidebar-footer a:hover { color: #57606a; text-decoration: underline; }
|
|
39
|
-
|
|
44
|
+
|
|
45
|
+
#xp-mobile-btn { display: none; position: fixed; top: 14px; left: 14px; z-index: 18; width: 36px; height: 36px; background: none; border: none; cursor: pointer; align-items: center; justify-content: center; padding: 0; color: #8c959f; transition: color 0.15s; }
|
|
46
|
+
#xp-mobile-btn:hover { color: #57606a; }
|
|
40
47
|
@media screen and (max-width: 599px) { #xp-mobile-btn { display: flex; } }
|
|
41
48
|
.xp-mb-bars { display: flex; flex-direction: column; gap: 5px; align-items: center; justify-content: center; }
|
|
42
|
-
.xp-mb-bars span { display: block; width: 16px; height: 1.5px; background:
|
|
43
|
-
|
|
44
|
-
#xp-mobile-btn[data-open="false"] .xp-mb-bars { display: flex; }
|
|
45
|
-
#xp-mobile-btn[data-open="false"] .xp-mb-close { display: none; }
|
|
46
|
-
#xp-mobile-btn[data-open="true"] .xp-mb-bars { display: none; }
|
|
47
|
-
#xp-mobile-btn[data-open="true"] .xp-mb-close { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
|
|
49
|
+
.xp-mb-bars span { display: block; width: 16px; height: 1.5px; background: currentColor; border-radius: 2px; }
|
|
50
|
+
|
|
48
51
|
.xp-folder-btn { display: flex; align-items: center; gap: 6px; width: calc(100% - 16px); margin: 0 8px; background: none; border: none; cursor: pointer; color: #57606a; font-size: 13px; font-weight: 600; padding: 5px 8px; border-radius: 6px; text-align: left; transition: background 0.1s, color 0.1s; }
|
|
49
52
|
.xp-folder-btn:hover { background: rgba(208,215,222,0.32); color: #1f2328; }
|
|
50
53
|
.xp-folder-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -142,12 +145,11 @@ body.close .content { left: 0; }
|
|
|
142
145
|
.xp-unrendered { color: #c8cdd3; font-size: 13px; padding: 5px 8px 5px 16px; display: flex; align-items: center; gap: 6px; cursor: default; user-select: none; }
|
|
143
146
|
.xp-unrendered::before { content: ''; display: inline-flex; flex-shrink: 0; width: 14px; height: 14px; background-color: #c8cdd3; -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688Z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688Z'/%3E%3C/svg%3E"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: contain; mask-size: contain; }
|
|
144
147
|
span.xp-unrendered:hover { color: #8c959f; cursor: pointer; }
|
|
145
|
-
|
|
148
|
+
|
|
146
149
|
#xp-gh-page-btn { position: fixed; top: 14px; right: 16px; z-index: 18; display: flex; align-items: center; justify-content: center; color: #b1bac4; text-decoration: none !important; transition: color 0.15s, transform 0.15s; }
|
|
147
150
|
#xp-gh-page-btn:hover { color: #57606a; transform: scale(1.15); }
|
|
148
151
|
#xp-gh-page-btn svg { width: 18px; height: 18px; display: block; }
|
|
149
|
-
|
|
150
|
-
body.close .xp-drag { opacity: 0 !important; pointer-events: none !important; }
|
|
152
|
+
|
|
151
153
|
@media screen and (max-width: 1100px) and (min-width: 600px) { .sidebar { width: 240px; } .content { left: 240px; } .xp-drag { left: 240px; } #xp-toggle { left: 239px; } }
|
|
152
154
|
@media screen and (max-width: 599px) { .sidebar { position: fixed; width: 100vw !important; z-index: 30; } .content { left: 0 !important; padding-top: 56px; } .xp-drag { display: none !important; } }
|
|
153
155
|
@media print { .sidebar, #xp-toggle, #xp-mobile-btn, .xp-drag, .app-nav, #xp-gh-page-btn { display: none !important; } .content { left: 0 !important; } }
|
package/index.template.html
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
<link rel="stylesheet" href="ghmd.css" />
|
|
8
8
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" />
|
|
9
|
+
<style>
|
|
10
|
+
/* Closed sidebar must never intercept touches on mobile */
|
|
11
|
+
@media screen and (max-width: 599px) {
|
|
12
|
+
body.close .sidebar { pointer-events: none !important; }
|
|
13
|
+
}
|
|
14
|
+
</style>
|
|
9
15
|
</head>
|
|
10
16
|
<body>
|
|
11
17
|
<div id="app"></div>
|
|
@@ -15,10 +21,86 @@
|
|
|
15
21
|
|
|
16
22
|
var explicodePlugin = function(hook) {
|
|
17
23
|
var closedFolders = new Set();
|
|
18
|
-
var
|
|
24
|
+
var seenFolders = new Set();
|
|
19
25
|
var TRANSITION = '280ms cubic-bezier(0.4,0,0.2,1)';
|
|
20
26
|
var currentFilePath = 'README.md';
|
|
21
27
|
|
|
28
|
+
// These are set once in mounted and reused everywhere.
|
|
29
|
+
var sidebar, toggle, mobileBtn, drag;
|
|
30
|
+
// Source of truth for sidebar open/closed — never read body.close for logic.
|
|
31
|
+
var sidebarOpen = true;
|
|
32
|
+
|
|
33
|
+
function isMobile() { return window.innerWidth < 600; }
|
|
34
|
+
|
|
35
|
+
function updateDragVisibility(open) {
|
|
36
|
+
if (isMobile()) {
|
|
37
|
+
drag.style.opacity = '0';
|
|
38
|
+
drag.style.pointerEvents = 'none';
|
|
39
|
+
} else if (open) {
|
|
40
|
+
drag.style.opacity = '1';
|
|
41
|
+
drag.style.pointerEvents = '';
|
|
42
|
+
} else {
|
|
43
|
+
drag.style.opacity = '0';
|
|
44
|
+
drag.style.pointerEvents = 'none';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function syncPositions(w, animate) {
|
|
49
|
+
var content = document.querySelector('.content');
|
|
50
|
+
var dur = animate ? TRANSITION : 'none';
|
|
51
|
+
sidebar.style.transition = 'transform ' + dur + ', width ' + dur;
|
|
52
|
+
if (content) { content.style.transition = 'left ' + dur; content.style.left = w + 'px'; }
|
|
53
|
+
drag.style.transition = 'left ' + dur;
|
|
54
|
+
drag.style.left = w + 'px';
|
|
55
|
+
toggle.style.transition = 'left ' + dur;
|
|
56
|
+
toggle.style.left = (w - 1) + 'px';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function setOpen(open, animate) {
|
|
60
|
+
sidebarOpen = open;
|
|
61
|
+
var mobile = isMobile();
|
|
62
|
+
var dur = animate ? TRANSITION : 'none';
|
|
63
|
+
var content = document.querySelector('.content');
|
|
64
|
+
|
|
65
|
+
if (open) {
|
|
66
|
+
document.body.classList.remove('close');
|
|
67
|
+
toggle.innerHTML = '‹';
|
|
68
|
+
if (mobile) {
|
|
69
|
+
sidebar.style.transition = 'transform ' + dur;
|
|
70
|
+
sidebar.style.transform = 'translateX(0)';
|
|
71
|
+
sidebar.style.pointerEvents = '';
|
|
72
|
+
if (content) content.style.left = '';
|
|
73
|
+
} else {
|
|
74
|
+
var w = parseInt(sidebar.style.width) || sidebar.offsetWidth || 270;
|
|
75
|
+
// Animate drag left from 0 → w in sync with sidebar sliding in
|
|
76
|
+
drag.style.transition = animate ? 'left ' + TRANSITION + ', opacity ' + TRANSITION : 'none';
|
|
77
|
+
drag.style.left = w + 'px';
|
|
78
|
+
drag.style.opacity = '1';
|
|
79
|
+
drag.style.pointerEvents = '';
|
|
80
|
+
syncPositions(w, animate);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
document.body.classList.add('close');
|
|
84
|
+
toggle.innerHTML = '›';
|
|
85
|
+
if (mobile) {
|
|
86
|
+
sidebar.style.transition = 'transform ' + dur;
|
|
87
|
+
sidebar.style.transform = 'translateX(-100%)';
|
|
88
|
+
sidebar.style.pointerEvents = 'none';
|
|
89
|
+
if (content) content.style.left = '';
|
|
90
|
+
} else {
|
|
91
|
+
sidebar.style.transition = 'transform ' + dur;
|
|
92
|
+
toggle.style.transition = 'left ' + dur;
|
|
93
|
+
toggle.style.left = '0px';
|
|
94
|
+
if (content) { content.style.transition = 'left ' + dur; content.style.left = '0'; }
|
|
95
|
+
// Animate drag left from w → 0 in sync with sidebar sliding out
|
|
96
|
+
drag.style.transition = animate ? 'left ' + TRANSITION + ', opacity ' + TRANSITION : 'none';
|
|
97
|
+
drag.style.left = '0px';
|
|
98
|
+
drag.style.opacity = '0';
|
|
99
|
+
drag.style.pointerEvents = 'none';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
22
104
|
hook.beforeEach(function(content, next) {
|
|
23
105
|
var hash = window.location.hash.replace(/^#\/?/, '').replace(/\?.*$/, '');
|
|
24
106
|
if (!hash) {
|
|
@@ -40,7 +122,7 @@
|
|
|
40
122
|
var builtIn = document.querySelector('.sidebar-toggle');
|
|
41
123
|
if (builtIn) builtIn.style.display = 'none';
|
|
42
124
|
|
|
43
|
-
|
|
125
|
+
sidebar = document.querySelector('.sidebar');
|
|
44
126
|
sidebar.style.overflow = 'hidden';
|
|
45
127
|
sidebar.style.display = 'flex';
|
|
46
128
|
sidebar.style.flexDirection = 'column';
|
|
@@ -48,8 +130,7 @@
|
|
|
48
130
|
|
|
49
131
|
var scrollWrap = document.createElement('div');
|
|
50
132
|
scrollWrap.className = 'xp-sidebar-scroll';
|
|
51
|
-
|
|
52
|
-
nodes.forEach(function(n) {
|
|
133
|
+
Array.from(sidebar.childNodes).forEach(function(n) {
|
|
53
134
|
if (n.nodeName !== 'H1') scrollWrap.appendChild(n);
|
|
54
135
|
});
|
|
55
136
|
sidebar.appendChild(scrollWrap);
|
|
@@ -61,123 +142,71 @@
|
|
|
61
142
|
footer.appendChild(wmSpan);
|
|
62
143
|
sidebar.appendChild(footer);
|
|
63
144
|
|
|
64
|
-
|
|
145
|
+
toggle = document.createElement('button');
|
|
65
146
|
toggle.id = 'xp-toggle';
|
|
66
147
|
toggle.setAttribute('aria-label', 'Toggle sidebar');
|
|
67
148
|
toggle.innerHTML = '‹';
|
|
68
149
|
document.body.appendChild(toggle);
|
|
69
150
|
|
|
70
|
-
|
|
151
|
+
mobileBtn = document.createElement('button');
|
|
71
152
|
mobileBtn.id = 'xp-mobile-btn';
|
|
72
|
-
mobileBtn.setAttribute('aria-label', '
|
|
153
|
+
mobileBtn.setAttribute('aria-label', 'Open sidebar');
|
|
73
154
|
mobileBtn.innerHTML =
|
|
74
|
-
'<span class="xp-mb-bars"><span></span><span></span><span></span></span>'
|
|
75
|
-
'<span class="xp-mb-close">✕</span>';
|
|
155
|
+
'<span class="xp-mb-bars"><span></span><span></span><span></span></span>';
|
|
76
156
|
document.body.appendChild(mobileBtn);
|
|
77
157
|
|
|
78
|
-
var
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
function updateDragVisibility(open) {
|
|
89
|
-
if (isMobile() || !open) {
|
|
90
|
-
drag.style.transition = 'opacity 120ms ease';
|
|
91
|
-
drag.style.opacity = '0';
|
|
92
|
-
drag.style.pointerEvents = 'none';
|
|
93
|
-
} else {
|
|
94
|
-
drag.style.transition = 'opacity 200ms ease 260ms';
|
|
95
|
-
drag.style.opacity = '1';
|
|
96
|
-
drag.style.pointerEvents = '';
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function syncPositions(w, animate) {
|
|
101
|
-
if (isMobile()) return;
|
|
102
|
-
var content = document.querySelector('.content');
|
|
103
|
-
var dur = animate ? TRANSITION : 'none';
|
|
104
|
-
sidebar.style.transition = 'transform ' + dur + ', width ' + dur;
|
|
105
|
-
if (content) { content.style.transition = 'left ' + dur; content.style.left = w + 'px'; }
|
|
106
|
-
drag.style.left = w + 'px';
|
|
107
|
-
toggle.style.left = (w - 1) + 'px';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function setMobileBtnIcon(open) {
|
|
111
|
-
mobileBtn.setAttribute('data-open', open ? 'true' : 'false');
|
|
158
|
+
var closeBtn = document.createElement('button');
|
|
159
|
+
closeBtn.id = 'xp-sidebar-close';
|
|
160
|
+
closeBtn.setAttribute('aria-label', 'Close sidebar');
|
|
161
|
+
closeBtn.innerHTML = '✕';
|
|
162
|
+
var h1 = sidebar.querySelector('h1');
|
|
163
|
+
if (h1) {
|
|
164
|
+
h1.insertBefore(closeBtn, h1.firstChild);
|
|
165
|
+
} else {
|
|
166
|
+
sidebar.insertBefore(closeBtn, sidebar.firstChild);
|
|
112
167
|
}
|
|
113
168
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
var dur = animate ? TRANSITION : 'none';
|
|
118
|
-
var content = document.querySelector('.content');
|
|
169
|
+
closeBtn.addEventListener('click', function() {
|
|
170
|
+
setOpen(false, true);
|
|
171
|
+
});
|
|
119
172
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (mobile) {
|
|
124
|
-
sidebar.style.transition = 'transform ' + dur;
|
|
125
|
-
sidebar.style.transform = 'translateX(0)';
|
|
126
|
-
setMobileBtnIcon(true);
|
|
127
|
-
if (content) { content.style.left = ''; }
|
|
128
|
-
} else {
|
|
129
|
-
syncPositions(w, animate);
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
document.body.classList.add('close');
|
|
133
|
-
toggle.innerHTML = '›';
|
|
134
|
-
if (mobile) {
|
|
135
|
-
sidebar.style.transition = 'transform ' + dur;
|
|
136
|
-
sidebar.style.transform = 'translateX(-100%)';
|
|
137
|
-
setMobileBtnIcon(false);
|
|
138
|
-
if (content) { content.style.left = ''; }
|
|
139
|
-
} else {
|
|
140
|
-
sidebar.style.transition = 'transform ' + dur;
|
|
141
|
-
toggle.style.transition = 'left ' + dur;
|
|
142
|
-
toggle.style.left = '0px';
|
|
143
|
-
if (content) { content.style.transition = 'left ' + dur; content.style.left = '0'; }
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
updateDragVisibility(open);
|
|
147
|
-
}
|
|
173
|
+
drag = document.createElement('div');
|
|
174
|
+
drag.className = 'xp-drag';
|
|
175
|
+
document.body.appendChild(drag);
|
|
148
176
|
|
|
149
177
|
toggle.addEventListener('click', function() {
|
|
150
|
-
|
|
151
|
-
setOpen(!isOpen, true);
|
|
178
|
+
setOpen(!sidebarOpen, true);
|
|
152
179
|
});
|
|
153
|
-
|
|
154
180
|
mobileBtn.addEventListener('click', function() {
|
|
155
|
-
|
|
156
|
-
setOpen(!isOpen, true);
|
|
181
|
+
setOpen(!sidebarOpen, true);
|
|
157
182
|
});
|
|
158
183
|
|
|
184
|
+
// Single delegated listener for nav link taps/clicks closing the sidebar.
|
|
185
|
+
sidebar.addEventListener('click', function(e) {
|
|
186
|
+
if (!isMobile()) return;
|
|
187
|
+
var a = e.target.closest('a');
|
|
188
|
+
if (a && sidebar.contains(a) && !a.closest('.xp-sidebar-footer')) {
|
|
189
|
+
setOpen(false, true);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Resize handler
|
|
159
194
|
var lastMobile = isMobile();
|
|
160
195
|
window.addEventListener('resize', function() {
|
|
161
196
|
var nowMobile = isMobile();
|
|
162
|
-
var
|
|
163
|
-
var w = getSidebarWidth();
|
|
164
|
-
|
|
197
|
+
var w = parseInt(sidebar.style.width) || sidebar.offsetWidth || 270;
|
|
165
198
|
if (nowMobile !== lastMobile) {
|
|
166
199
|
lastMobile = nowMobile;
|
|
167
200
|
if (nowMobile) {
|
|
168
201
|
var content = document.querySelector('.content');
|
|
169
202
|
if (content) content.style.left = '';
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
setMobileBtnIcon(false);
|
|
174
|
-
} else {
|
|
175
|
-
sidebar.style.transform = 'translateX(0)';
|
|
176
|
-
setMobileBtnIcon(true);
|
|
177
|
-
}
|
|
203
|
+
sidebar.style.transition = 'none';
|
|
204
|
+
sidebar.style.transform = sidebarOpen ? 'translateX(0)' : 'translateX(-100%)';
|
|
205
|
+
sidebar.style.pointerEvents = sidebarOpen ? '' : 'none';
|
|
178
206
|
} else {
|
|
179
207
|
sidebar.style.transform = '';
|
|
180
|
-
|
|
208
|
+
sidebar.style.pointerEvents = '';
|
|
209
|
+
if (sidebarOpen) {
|
|
181
210
|
syncPositions(w, false);
|
|
182
211
|
} else {
|
|
183
212
|
var content = document.querySelector('.content');
|
|
@@ -185,43 +214,61 @@
|
|
|
185
214
|
toggle.style.left = '0px';
|
|
186
215
|
}
|
|
187
216
|
}
|
|
188
|
-
} else if (!nowMobile &&
|
|
217
|
+
} else if (!nowMobile && sidebarOpen) {
|
|
189
218
|
syncPositions(w, false);
|
|
190
219
|
}
|
|
191
|
-
|
|
220
|
+
drag.style.transition = 'none';
|
|
221
|
+
if (isMobile()) {
|
|
222
|
+
drag.style.opacity = '0';
|
|
223
|
+
drag.style.pointerEvents = 'none';
|
|
224
|
+
} else if (sidebarOpen) {
|
|
225
|
+
drag.style.opacity = '1';
|
|
226
|
+
drag.style.pointerEvents = '';
|
|
227
|
+
} else {
|
|
228
|
+
drag.style.left = '0px';
|
|
229
|
+
drag.style.opacity = '0';
|
|
230
|
+
drag.style.pointerEvents = 'none';
|
|
231
|
+
}
|
|
192
232
|
});
|
|
193
233
|
|
|
234
|
+
// Initial state
|
|
194
235
|
if (isMobile()) {
|
|
195
236
|
lastMobile = true;
|
|
237
|
+
sidebarOpen = false;
|
|
196
238
|
sidebar.style.transition = 'none';
|
|
197
239
|
sidebar.style.transform = 'translateX(-100%)';
|
|
240
|
+
sidebar.style.pointerEvents = 'none';
|
|
198
241
|
document.body.classList.add('close');
|
|
199
|
-
setMobileBtnIcon(false);
|
|
200
242
|
var content = document.querySelector('.content');
|
|
201
243
|
if (content) content.style.left = '';
|
|
244
|
+
drag.style.transition = 'none';
|
|
245
|
+
drag.style.opacity = '0';
|
|
246
|
+
drag.style.pointerEvents = 'none';
|
|
202
247
|
} else {
|
|
203
|
-
|
|
248
|
+
sidebarOpen = true;
|
|
249
|
+
syncPositions(parseInt(sidebar.style.width) || sidebar.offsetWidth || 270, false);
|
|
250
|
+
drag.style.transition = 'none';
|
|
251
|
+
drag.style.opacity = '1';
|
|
252
|
+
drag.style.pointerEvents = '';
|
|
204
253
|
}
|
|
205
|
-
updateDragVisibility(!document.body.classList.contains('close'));
|
|
206
254
|
|
|
207
|
-
|
|
255
|
+
// Drag to resize (desktop only)
|
|
208
256
|
drag.addEventListener('mousedown', function(e) {
|
|
209
|
-
if (isMobile()) return;
|
|
210
257
|
e.preventDefault();
|
|
211
|
-
startX = e.clientX;
|
|
212
|
-
startW =
|
|
258
|
+
var startX = e.clientX;
|
|
259
|
+
var startW = parseInt(sidebar.style.width) || sidebar.offsetWidth || 270;
|
|
213
260
|
document.body.style.userSelect = 'none';
|
|
214
261
|
document.body.style.cursor = 'col-resize';
|
|
215
262
|
sidebar.style.transition = 'none';
|
|
263
|
+
toggle.style.transition = 'none';
|
|
216
264
|
var content = document.querySelector('.content');
|
|
217
265
|
if (content) content.style.transition = 'none';
|
|
218
266
|
drag.style.transition = 'none';
|
|
219
|
-
toggle.style.transition = 'none';
|
|
220
267
|
|
|
221
268
|
function onMove(e) {
|
|
222
269
|
var w = Math.max(180, Math.min(600, startW + e.clientX - startX));
|
|
223
|
-
var content = document.querySelector('.content');
|
|
224
270
|
sidebar.style.width = w + 'px';
|
|
271
|
+
var content = document.querySelector('.content');
|
|
225
272
|
if (content) content.style.left = w + 'px';
|
|
226
273
|
drag.style.left = w + 'px';
|
|
227
274
|
toggle.style.left = (w - 1) + 'px';
|
|
@@ -238,47 +285,41 @@
|
|
|
238
285
|
});
|
|
239
286
|
|
|
240
287
|
hook.doneEach(function() {
|
|
241
|
-
var
|
|
288
|
+
var sb = document.querySelector('.sidebar');
|
|
242
289
|
|
|
243
290
|
if (repoUrl) {
|
|
244
|
-
var h1 =
|
|
291
|
+
var h1 = sb.querySelector('h1');
|
|
245
292
|
if (h1) {
|
|
246
293
|
var titleA = h1.querySelector('a');
|
|
247
294
|
if (titleA) titleA.target = '_blank';
|
|
248
295
|
}
|
|
249
296
|
}
|
|
250
297
|
|
|
251
|
-
|
|
252
|
-
if (!
|
|
253
|
-
scrollWrap = document.createElement('div');
|
|
298
|
+
// Ensure scroll wrapper exists
|
|
299
|
+
if (!sb.querySelector('.xp-sidebar-scroll')) {
|
|
300
|
+
var scrollWrap = document.createElement('div');
|
|
254
301
|
scrollWrap.className = 'xp-sidebar-scroll';
|
|
255
|
-
var footer =
|
|
256
|
-
|
|
257
|
-
|
|
302
|
+
var footer = sb.querySelector('.xp-sidebar-footer');
|
|
303
|
+
Array.from(sb.childNodes).forEach(function(n) {
|
|
304
|
+
if (!n.classList || !n.classList.contains('xp-sidebar-footer')) {
|
|
305
|
+
scrollWrap.appendChild(n);
|
|
306
|
+
}
|
|
258
307
|
});
|
|
259
|
-
|
|
260
|
-
sidebar.insertBefore(scrollWrap, footer || null);
|
|
308
|
+
sb.insertBefore(scrollWrap, footer || null);
|
|
261
309
|
}
|
|
262
310
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
drag.style.opacity = '1';
|
|
272
|
-
drag.style.pointerEvents = '';
|
|
273
|
-
} else {
|
|
274
|
-
drag.style.left = w + 'px';
|
|
275
|
-
toggle.style.left = '0px';
|
|
276
|
-
drag.style.opacity = '0';
|
|
277
|
-
drag.style.pointerEvents = 'none';
|
|
278
|
-
}
|
|
311
|
+
// Re-sync desktop drag/toggle positions
|
|
312
|
+
if (!isMobile() && drag && toggle) {
|
|
313
|
+
var w = parseInt(sb.style.width) || sb.offsetWidth || 270;
|
|
314
|
+
drag.style.transition = 'none';
|
|
315
|
+
drag.style.left = sidebarOpen ? w + 'px' : '0px';
|
|
316
|
+
drag.style.opacity = sidebarOpen ? '1' : '0';
|
|
317
|
+
drag.style.pointerEvents = sidebarOpen ? '' : 'none';
|
|
318
|
+
toggle.style.left = sidebarOpen ? (w - 1) + 'px' : '0px';
|
|
279
319
|
}
|
|
280
320
|
|
|
281
|
-
|
|
321
|
+
// GitHub source button, recreated on each navigation to update href
|
|
322
|
+
(function() {
|
|
282
323
|
var existing = document.getElementById('xp-gh-page-btn');
|
|
283
324
|
if (existing) existing.remove();
|
|
284
325
|
if (!githubBase || !currentFilePath) return;
|
|
@@ -290,41 +331,38 @@
|
|
|
290
331
|
btn.setAttribute('aria-label', 'View on GitHub');
|
|
291
332
|
btn.title = 'View on GitHub';
|
|
292
333
|
btn.innerHTML = '<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>';
|
|
293
|
-
document.body.
|
|
294
|
-
}
|
|
295
|
-
updateGhBtn();
|
|
334
|
+
document.body.insertBefore(btn, mobileBtn || null);
|
|
335
|
+
})();
|
|
296
336
|
|
|
297
|
-
var nav =
|
|
337
|
+
var nav = sb.querySelector('.sidebar-nav');
|
|
298
338
|
if (!nav) return;
|
|
299
339
|
|
|
340
|
+
// Reset Docsify collapse state
|
|
300
341
|
nav.querySelectorAll('li').forEach(function(li) {
|
|
301
342
|
li.classList.remove('collapse');
|
|
302
|
-
|
|
303
|
-
|
|
343
|
+
});
|
|
344
|
+
nav.querySelectorAll('li > ul').forEach(function(ul) {
|
|
345
|
+
ul.style.display = '';
|
|
304
346
|
});
|
|
305
347
|
|
|
348
|
+
// Folder buttons
|
|
306
349
|
nav.querySelectorAll('li').forEach(function(li) {
|
|
307
350
|
if (li.dataset.xpFolder) return;
|
|
308
351
|
var labelEl = li.querySelector(':scope > p > strong') || li.querySelector(':scope > strong');
|
|
309
352
|
if (!labelEl) return;
|
|
310
353
|
var subUl = li.querySelector(':scope > ul');
|
|
311
354
|
if (!subUl) return;
|
|
312
|
-
subUl.setAttribute('data-xp-folder-ul', '1');
|
|
313
355
|
|
|
314
356
|
var folderName = labelEl.textContent.trim();
|
|
315
|
-
|
|
316
357
|
li.dataset.xpFolder = '1';
|
|
317
|
-
li.classList.remove('collapse');
|
|
318
358
|
subUl.setAttribute('data-xp-folder-ul', '1');
|
|
319
359
|
|
|
320
360
|
var btn = document.createElement('button');
|
|
321
361
|
btn.className = 'xp-folder-btn';
|
|
322
|
-
|
|
323
362
|
var iconSpan = document.createElement('span');
|
|
324
363
|
var labelSpan = document.createElement('span');
|
|
325
364
|
labelSpan.className = 'xp-folder-label';
|
|
326
365
|
labelSpan.textContent = folderName;
|
|
327
|
-
|
|
328
366
|
btn.appendChild(iconSpan);
|
|
329
367
|
btn.appendChild(labelSpan);
|
|
330
368
|
|
|
@@ -332,14 +370,18 @@
|
|
|
332
370
|
li.insertBefore(btn, wrapper);
|
|
333
371
|
wrapper.remove();
|
|
334
372
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
373
|
+
// add to closedFolders so it starts closed
|
|
374
|
+
if (!seenFolders.has(folderName)) {
|
|
375
|
+
seenFolders.add(folderName);
|
|
376
|
+
closedFolders.add(folderName);
|
|
377
|
+
}
|
|
378
|
+
var folderOpen = !closedFolders.has(folderName);
|
|
379
|
+
btn.setAttribute('data-open', folderOpen ? 'true' : 'false');
|
|
380
|
+
iconSpan.className = 'xp-folder-icon ' + (folderOpen ? 'xp-folder-open' : 'xp-folder-closed');
|
|
381
|
+
subUl.style.display = folderOpen ? '' : 'none';
|
|
339
382
|
|
|
340
383
|
btn.addEventListener('click', function() {
|
|
341
|
-
var
|
|
342
|
-
var nowOpen = !open;
|
|
384
|
+
var nowOpen = btn.getAttribute('data-open') !== 'true';
|
|
343
385
|
btn.setAttribute('data-open', nowOpen ? 'true' : 'false');
|
|
344
386
|
iconSpan.className = 'xp-folder-icon ' + (nowOpen ? 'xp-folder-open' : 'xp-folder-closed');
|
|
345
387
|
subUl.style.display = nowOpen ? '' : 'none';
|
|
@@ -348,8 +390,7 @@
|
|
|
348
390
|
});
|
|
349
391
|
});
|
|
350
392
|
|
|
351
|
-
|
|
352
|
-
|
|
393
|
+
// File icons
|
|
353
394
|
nav.querySelectorAll('a').forEach(function(a) {
|
|
354
395
|
if (a.dataset.xpIcon) return;
|
|
355
396
|
if (a.closest('.app-sub-sidebar')) return;
|
|
@@ -367,32 +408,11 @@
|
|
|
367
408
|
a.insertBefore(icon, a.firstChild);
|
|
368
409
|
});
|
|
369
410
|
|
|
370
|
-
|
|
371
|
-
if (a.dataset.xpMobileClose) return;
|
|
372
|
-
a.dataset.xpMobileClose = '1';
|
|
373
|
-
a.addEventListener('click', function() {
|
|
374
|
-
if (window.innerWidth < 600) {
|
|
375
|
-
setTimeout(function() {
|
|
376
|
-
document.body.classList.add('close');
|
|
377
|
-
var sb = document.querySelector('.sidebar');
|
|
378
|
-
if (sb) {
|
|
379
|
-
sb.style.transition = 'transform 280ms cubic-bezier(0.4,0,0.2,1)';
|
|
380
|
-
sb.style.transform = 'translateX(-100%)';
|
|
381
|
-
}
|
|
382
|
-
var mb = document.getElementById('xp-mobile-btn');
|
|
383
|
-
if (mb) mb.setAttribute('data-open', 'false');
|
|
384
|
-
var tg = document.getElementById('xp-toggle');
|
|
385
|
-
if (tg) tg.innerHTML = '›';
|
|
386
|
-
}, 10);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
|
|
411
|
+
// Unrendered file GitHub links
|
|
391
412
|
if (githubBase) {
|
|
392
413
|
nav.querySelectorAll('span.xp-unrendered[data-path]').forEach(function(span) {
|
|
393
414
|
if (span.dataset.xpGh) return;
|
|
394
415
|
span.dataset.xpGh = '1';
|
|
395
|
-
span.style.cursor = 'pointer';
|
|
396
416
|
span.addEventListener('click', function() {
|
|
397
417
|
window.open(githubBase + '/' + span.dataset.path, '_blank', 'noopener noreferrer');
|
|
398
418
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "explicode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Turn your codebase into documentation.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"documentation",
|
|
7
|
+
"markdown",
|
|
8
|
+
"comments",
|
|
9
|
+
"docs",
|
|
10
|
+
"literate-programming",
|
|
11
|
+
"developer-tools",
|
|
12
|
+
"github-pages"
|
|
13
|
+
],
|
|
5
14
|
"bin": {
|
|
6
15
|
"explicode": "./cli.js"
|
|
7
16
|
},
|