explicode 1.0.1 → 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/ghmd-dark.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /* Explicode — GitHub Dark theme for Docsify */
2
2
 
3
- /* ── Reset & base ── */
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
- /* ── Layout ── */
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
- /* ── Scrollable nav area ── */
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
- /* ── Mobile nav button ── */
49
- #xp-mobile-btn { display: none; position: fixed; top: 14px; left: 14px; z-index: 31; width: 36px; height: 36px; background: none; border: none; cursor: pointer; align-items: center; justify-content: center; padding: 0; }
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: #8b949e; border-radius: 2px; }
53
- .xp-mb-close { font-size: 14px; color: #8b949e; line-height: 1; }
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
- /* ── Drag handle ── */
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
- /* ── Reset & base ── */
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%; z-index: 0; }
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
- #xp-mobile-btn { display: none; position: fixed; top: 14px; left: 14px; z-index: 31; width: 36px; height: 36px; background: none; border: none; cursor: pointer; align-items: center; justify-content: center; padding: 0; }
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: #57606a; border-radius: 2px; }
43
- .xp-mb-close { font-size: 14px; color: #57606a; line-height: 1; }
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
- .sidebar > h1 { position: relative; display: flex; align-items: center; justify-content: center; }
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
- @media screen and (max-width: 599px) { body:not(.close) #xp-gh-page-btn { display: none; } }
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; } }
@@ -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 foldersInitialized = false;
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 = '&#x2039;';
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 = '&#x203a;';
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
- var sidebar = document.querySelector('.sidebar');
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
- var nodes = Array.from(sidebar.childNodes);
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
- var toggle = document.createElement('button');
145
+ toggle = document.createElement('button');
65
146
  toggle.id = 'xp-toggle';
66
147
  toggle.setAttribute('aria-label', 'Toggle sidebar');
67
148
  toggle.innerHTML = '&#x2039;';
68
149
  document.body.appendChild(toggle);
69
150
 
70
- var mobileBtn = document.createElement('button');
151
+ mobileBtn = document.createElement('button');
71
152
  mobileBtn.id = 'xp-mobile-btn';
72
- mobileBtn.setAttribute('aria-label', 'Toggle sidebar');
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">&#x2715;</span>';
155
+ '<span class="xp-mb-bars"><span></span><span></span><span></span></span>';
76
156
  document.body.appendChild(mobileBtn);
77
157
 
78
- var drag = document.createElement('div');
79
- drag.className = 'xp-drag';
80
- document.body.appendChild(drag);
81
-
82
- var isMobile = function() { return window.innerWidth < 600; };
83
-
84
- function getSidebarWidth() {
85
- return parseInt(sidebar.style.width) || sidebar.offsetWidth || 270;
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 = '&#x2715;';
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
- function setOpen(open, animate) {
115
- var w = getSidebarWidth();
116
- var mobile = isMobile();
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
- if (open) {
121
- document.body.classList.remove('close');
122
- toggle.innerHTML = '&#x2039;';
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 = '&#x203a;';
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
- var isOpen = !document.body.classList.contains('close');
151
- setOpen(!isOpen, true);
178
+ setOpen(!sidebarOpen, true);
152
179
  });
153
-
154
180
  mobileBtn.addEventListener('click', function() {
155
- var isOpen = !document.body.classList.contains('close');
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 isOpen = !document.body.classList.contains('close');
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
- if (!isOpen) {
171
- sidebar.style.transition = 'none';
172
- sidebar.style.transform = 'translateX(-100%)';
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
- if (isOpen) {
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 && isOpen) {
217
+ } else if (!nowMobile && sidebarOpen) {
189
218
  syncPositions(w, false);
190
219
  }
191
- updateDragVisibility(isOpen);
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
- syncPositions(getSidebarWidth(), false);
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
- var startX, startW;
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 = getSidebarWidth();
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 sidebar = document.querySelector('.sidebar');
288
+ var sb = document.querySelector('.sidebar');
242
289
 
243
290
  if (repoUrl) {
244
- var h1 = sidebar.querySelector('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
- var scrollWrap = sidebar.querySelector('.xp-sidebar-scroll');
252
- if (!scrollWrap) {
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 = sidebar.querySelector('.xp-sidebar-footer');
256
- var nodes = Array.from(sidebar.childNodes).filter(function(n) {
257
- return !n.classList || !n.classList.contains('xp-sidebar-footer');
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
- nodes.forEach(function(n) { scrollWrap.appendChild(n); });
260
- sidebar.insertBefore(scrollWrap, footer || null);
308
+ sb.insertBefore(scrollWrap, footer || null);
261
309
  }
262
310
 
263
- var drag = document.querySelector('.xp-drag');
264
- var toggle = document.getElementById('xp-toggle');
265
- var isOpen = !document.body.classList.contains('close');
266
- if (drag && toggle) {
267
- var w = parseInt(sidebar.style.width) || sidebar.offsetWidth || 270;
268
- if (isOpen && window.innerWidth >= 600) {
269
- drag.style.left = w + 'px';
270
- toggle.style.left = (w - 1) + 'px';
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
- function updateGhBtn() {
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.appendChild(btn);
294
- }
295
- updateGhBtn();
334
+ document.body.insertBefore(btn, mobileBtn || null);
335
+ })();
296
336
 
297
- var nav = sidebar.querySelector('.sidebar-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
- var ul = li.querySelector(':scope > ul');
303
- if (ul && !ul.closest('[data-xp-folder-ul]')) ul.style.display = '';
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
- var isOpen = foldersInitialized ? !closedFolders.has(folderName) : false;
336
- btn.setAttribute('data-open', isOpen ? 'true' : 'false');
337
- iconSpan.className = 'xp-folder-icon ' + (isOpen ? 'xp-folder-open' : 'xp-folder-closed');
338
- subUl.style.display = isOpen ? '' : 'none';
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 open = btn.getAttribute('data-open') === 'true';
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
- foldersInitialized = true;
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
- nav.querySelectorAll('a').forEach(function(a) {
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 = '&#x203a;';
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,6 +1,6 @@
1
1
  {
2
2
  "name": "explicode",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Turn your codebase into documentation.",
5
5
  "keywords": [
6
6
  "documentation",