kash-shell 0.3.16__py3-none-any.whl → 0.3.17__py3-none-any.whl
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.
- kash/commands/base/files_command.py +2 -2
- kash/config/colors.py +15 -7
- kash/model/actions_model.py +2 -2
- kash/web_gen/templates/base_styles.css.jinja +73 -16
- kash/web_gen/templates/base_webpage.html.jinja +45 -19
- kash/web_gen/templates/simple_webpage.html.jinja +523 -19
- kash/web_gen/templates/tabbed_webpage.html.jinja +4 -2
- {kash_shell-0.3.16.dist-info → kash_shell-0.3.17.dist-info}/METADATA +1 -1
- {kash_shell-0.3.16.dist-info → kash_shell-0.3.17.dist-info}/RECORD +12 -12
- {kash_shell-0.3.16.dist-info → kash_shell-0.3.17.dist-info}/WHEEL +0 -0
- {kash_shell-0.3.16.dist-info → kash_shell-0.3.17.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.16.dist-info → kash_shell-0.3.17.dist-info}/licenses/LICENSE +0 -0
|
@@ -64,7 +64,6 @@ def _print_listing_tallies(
|
|
|
64
64
|
f"{EMOJI_WARN} {file_listing.files_ignored} files and {file_listing.dirs_ignored} dirs were ignored",
|
|
65
65
|
style=COLOR_EXTRA,
|
|
66
66
|
)
|
|
67
|
-
cprint("(use --no_ignore to show hidden files)", style=STYLE_HINT)
|
|
68
67
|
|
|
69
68
|
if file_listing.total_skipped > 0:
|
|
70
69
|
cprint(
|
|
@@ -72,7 +71,8 @@ def _print_listing_tallies(
|
|
|
72
71
|
f"at max_files={max_files}, max_depth={max_depth}, max_per_subdir={max_per_subdir}",
|
|
73
72
|
style=COLOR_EXTRA,
|
|
74
73
|
)
|
|
75
|
-
|
|
74
|
+
if file_listing.total_ignored + file_listing.total_skipped > 0:
|
|
75
|
+
cprint("(use --all to show all files)", style=STYLE_HINT)
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
DEFAULT_MAX_PER_GROUP = 50
|
kash/config/colors.py
CHANGED
|
@@ -133,22 +133,26 @@ web_light_translucent = SimpleNamespace(
|
|
|
133
133
|
primary=hsl_to_hex("hsl(188, 31%, 41%)"),
|
|
134
134
|
primary_light=hsl_to_hex("hsl(188, 40%, 62%)"),
|
|
135
135
|
secondary=hsl_to_hex("hsl(188, 12%, 28%)"),
|
|
136
|
+
tertiary=hsl_to_hex("hsl(188, 7%, 64%)"),
|
|
136
137
|
bg=hsl_to_hex("hsla(44, 6%, 100%, 0.75)"),
|
|
137
138
|
bg_solid=hsl_to_hex("hsla(44, 6%, 100%, 1)"),
|
|
138
139
|
bg_header=hsl_to_hex("hsla(188, 42%, 70%, 0.2)"),
|
|
139
140
|
bg_alt=hsl_to_hex("hsla(39, 24%, 90%, 0.3)"),
|
|
140
141
|
bg_alt_solid=hsl_to_hex("hsla(39, 24%, 97%, 1)"),
|
|
141
142
|
text=hsl_to_hex("hsl(188, 39%, 11%)"),
|
|
143
|
+
code=hsl_to_hex("hsl(44, 38%, 23%)"),
|
|
142
144
|
border=hsl_to_hex("hsl(188, 8%, 50%)"),
|
|
143
|
-
border_hint=hsl_to_hex("hsla(188, 8%, 72%, 0.
|
|
145
|
+
border_hint=hsl_to_hex("hsla(188, 8%, 72%, 0.3)"),
|
|
144
146
|
border_accent=hsl_to_hex("hsla(305, 18%, 65%, 0.85)"),
|
|
145
147
|
hover=hsl_to_hex("hsl(188, 12%, 84%)"),
|
|
146
|
-
hover_bg=hsl_to_hex("hsla(188,
|
|
148
|
+
hover_bg=hsl_to_hex("hsla(188, 12%, 94%, 0.8)"),
|
|
147
149
|
hint=hsl_to_hex("hsl(188, 11%, 65%)"),
|
|
150
|
+
hint_gentle=hsl_to_hex("hsla(188, 11%, 65%, 0.2)"),
|
|
148
151
|
tooltip_bg=hsl_to_hex("hsla(188, 6%, 37%, 0.7)"),
|
|
149
152
|
popover_bg=hsl_to_hex("hsla(188, 6%, 37%, 0.7)"),
|
|
150
153
|
bright=hsl_to_hex("hsl(134, 43%, 60%)"),
|
|
151
|
-
success=hsl_to_hex("hsl(134,
|
|
154
|
+
success=hsl_to_hex("hsl(134, 70%, 37%)"),
|
|
155
|
+
failure=hsl_to_hex("hsl(7, 70%, 37%)"),
|
|
152
156
|
selection="hsla(225, 61%, 82%, 0.80)",
|
|
153
157
|
scrollbar=hsl_to_hex("hsla(189, 12%, 55%, 0.9)"),
|
|
154
158
|
scrollbar_hover=hsl_to_hex("hsla(190, 12%, 38%, 0.9)"),
|
|
@@ -160,22 +164,26 @@ web_dark_translucent = SimpleNamespace(
|
|
|
160
164
|
primary=hsl_to_hex("hsl(188, 40%, 62%)"),
|
|
161
165
|
primary_light=hsl_to_hex("hsl(188, 50%, 72%)"),
|
|
162
166
|
secondary=hsl_to_hex("hsl(188, 12%, 65%)"),
|
|
167
|
+
tertiary=hsl_to_hex("hsl(188, 7%, 40%)"),
|
|
163
168
|
bg=hsl_to_hex("hsla(220, 14%, 7%, 0.95)"),
|
|
164
169
|
bg_solid=hsl_to_hex("hsl(220, 14%, 7%)"),
|
|
165
170
|
bg_header=hsl_to_hex("hsla(188, 42%, 20%, 0.3)"),
|
|
166
171
|
bg_alt=hsl_to_hex("hsla(220, 14%, 12%, 0.5)"),
|
|
167
172
|
bg_alt_solid=hsl_to_hex("hsl(220, 14%, 12%)"),
|
|
168
|
-
text=hsl_to_hex("hsl(188,
|
|
173
|
+
text=hsl_to_hex("hsl(188, 10%, 90%)"),
|
|
174
|
+
code=hsl_to_hex("hsl(44, 38%, 72%)"),
|
|
169
175
|
border=hsl_to_hex("hsl(188, 8%, 25%)"),
|
|
170
|
-
border_hint=hsl_to_hex("hsla(188, 8%, 35%, 0.
|
|
176
|
+
border_hint=hsl_to_hex("hsla(188, 8%, 35%, 0.3)"),
|
|
171
177
|
border_accent=hsl_to_hex("hsla(305, 30%, 55%, 0.85)"),
|
|
172
178
|
hover=hsl_to_hex("hsl(188, 12%, 35%)"),
|
|
173
179
|
hover_bg=hsl_to_hex("hsla(188, 20%, 25%, 0.4)"),
|
|
174
180
|
hint=hsl_to_hex("hsl(188, 11%, 55%)"),
|
|
181
|
+
hint_gentle=hsl_to_hex("hsla(188, 11%, 55%, 0.2)"),
|
|
175
182
|
tooltip_bg=hsl_to_hex("hsla(188, 6%, 20%, 0.9)"),
|
|
176
183
|
popover_bg=hsl_to_hex("hsla(188, 6%, 20%, 0.9)"),
|
|
177
|
-
bright=hsl_to_hex("hsl(134,
|
|
178
|
-
success=hsl_to_hex("hsl(134,
|
|
184
|
+
bright=hsl_to_hex("hsl(134, 52%, 65%)"),
|
|
185
|
+
success=hsl_to_hex("hsl(134, 72%, 73%)"),
|
|
186
|
+
failure=hsl_to_hex("hsl(7, 46%, 53%)"),
|
|
179
187
|
selection=hsl_to_hex("hsla(225, 61%, 40%, 0.40)"),
|
|
180
188
|
scrollbar=hsl_to_hex("hsla(189, 12%, 35%, 0.9)"),
|
|
181
189
|
scrollbar_hover=hsl_to_hex("hsla(190, 12%, 50%, 0.9)"),
|
kash/model/actions_model.py
CHANGED
|
@@ -102,9 +102,9 @@ class ActionResult:
|
|
|
102
102
|
shell_result: ShellResult | None = None
|
|
103
103
|
"""Customize control of how the action's result is displayed in the shell."""
|
|
104
104
|
|
|
105
|
-
def get_by_format(self,
|
|
105
|
+
def get_by_format(self, *formats: Format) -> Item:
|
|
106
106
|
"""Convenience method to get an item for actions that return multiple formats."""
|
|
107
|
-
return next(item for item in self.items if item.format
|
|
107
|
+
return next(item for item in self.items if item.format in formats)
|
|
108
108
|
|
|
109
109
|
def has_hints(self) -> bool:
|
|
110
110
|
return bool(
|
|
@@ -187,20 +187,34 @@ code {
|
|
|
187
187
|
font-family: var(--font-mono);
|
|
188
188
|
font-size: var(--font-size-mono);
|
|
189
189
|
letter-spacing: -0.025em;
|
|
190
|
+
|
|
190
191
|
transition: color 0.4s ease-in-out;
|
|
191
192
|
}
|
|
193
|
+
/* For code inside pre we style the pre tag */
|
|
194
|
+
code:not(pre code) {
|
|
195
|
+
background-color: var(--color-bg-alt);
|
|
196
|
+
border-radius: 3px;
|
|
197
|
+
border: 1px solid var(--color-hint-gentle);
|
|
198
|
+
padding: 0.25em 0.2em 0.1em 0.2em;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Code block wrapper for positioning copy button */
|
|
202
|
+
.code-block-wrapper {
|
|
203
|
+
position: relative;
|
|
204
|
+
}
|
|
192
205
|
|
|
193
206
|
/* Code blocks (pre + code) */
|
|
194
207
|
pre {
|
|
195
208
|
font-family: var(--font-mono);
|
|
196
209
|
font-size: var(--font-size-mono);
|
|
197
210
|
letter-spacing: -0.025em;
|
|
211
|
+
|
|
198
212
|
background-color: var(--color-bg-alt);
|
|
199
|
-
border-radius:
|
|
200
|
-
border: 1px
|
|
201
|
-
padding: 0.
|
|
213
|
+
border-radius: 3px;
|
|
214
|
+
border: 1px solid var(--color-hint-gentle);
|
|
215
|
+
padding: 0.25rem 0.2rem 0.1rem 0.2rem;
|
|
202
216
|
overflow-x: auto; /* Enable horizontal scrolling */
|
|
203
|
-
|
|
217
|
+
margin: 0;
|
|
204
218
|
transition: background-color 0.4s ease-in-out, border-color 0.4s ease-in-out;
|
|
205
219
|
}
|
|
206
220
|
|
|
@@ -215,11 +229,12 @@ pre > code {
|
|
|
215
229
|
position: absolute;
|
|
216
230
|
top: 0;
|
|
217
231
|
right: 0;
|
|
218
|
-
|
|
232
|
+
margin: 1px;
|
|
233
|
+
background: var(--color-bg-alt-solid);
|
|
219
234
|
color: var(--color-hint);
|
|
220
235
|
border: none;
|
|
221
236
|
border-radius: 0.25rem;
|
|
222
|
-
padding: 0
|
|
237
|
+
padding: 0;
|
|
223
238
|
cursor: pointer;
|
|
224
239
|
font-size: 0.75rem;
|
|
225
240
|
z-index: 10;
|
|
@@ -229,7 +244,7 @@ pre > code {
|
|
|
229
244
|
justify-content: center;
|
|
230
245
|
width: 1.5rem;
|
|
231
246
|
height: 1.5rem;
|
|
232
|
-
opacity: 0.
|
|
247
|
+
opacity: 0.9;
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
.code-copy-button:hover {
|
|
@@ -240,7 +255,6 @@ pre > code {
|
|
|
240
255
|
|
|
241
256
|
.code-copy-button.copied {
|
|
242
257
|
color: var(--color-success);
|
|
243
|
-
opacity: 1;
|
|
244
258
|
}
|
|
245
259
|
|
|
246
260
|
.code-copy-button svg {
|
|
@@ -337,7 +351,7 @@ hr:before {
|
|
|
337
351
|
font-weight: var(--font-weight-sans-bold);
|
|
338
352
|
text-transform: uppercase;
|
|
339
353
|
letter-spacing: 0.03em;
|
|
340
|
-
margin-top:
|
|
354
|
+
margin-top: 1rem;
|
|
341
355
|
margin-bottom: 0.8rem;
|
|
342
356
|
}
|
|
343
357
|
{% endblock long_text_styles %}
|
|
@@ -378,13 +392,21 @@ tbody tr:nth-child(even) {
|
|
|
378
392
|
|
|
379
393
|
/* Container for wide tables to allow tables to break out of parent width. */
|
|
380
394
|
.table-container {
|
|
381
|
-
{# max-width: calc(100vw - 6rem); #}
|
|
382
395
|
position: relative;
|
|
383
|
-
left: 50%;
|
|
384
|
-
transform: translateX(-50%);
|
|
385
396
|
box-sizing: border-box;
|
|
386
397
|
margin: 2rem 0;
|
|
387
398
|
background-color: var(--color-bg-solid);
|
|
399
|
+
/* Default: center tables within their container */
|
|
400
|
+
left: 50%;
|
|
401
|
+
transform: translateX(-50%);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/* When TOC is present, simplify table container positioning */
|
|
405
|
+
.content-with-toc.has-toc .table-container {
|
|
406
|
+
/* Within grid layout, position relative to the grid column */
|
|
407
|
+
left: 50%;
|
|
408
|
+
transform: translateX(-50%);
|
|
409
|
+
/* Let the table width be controlled by the responsive styles */
|
|
388
410
|
}
|
|
389
411
|
{% endblock table_styles %}
|
|
390
412
|
|
|
@@ -438,16 +460,50 @@ sup {
|
|
|
438
460
|
|
|
439
461
|
/* Apply shadow to long-text containers on larger screens */
|
|
440
462
|
.long-text {
|
|
463
|
+
border: 1px solid var(--color-hint-gentle);
|
|
441
464
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 -2px 6px -1px rgba(0, 0, 0, 0.07);
|
|
442
465
|
}
|
|
443
466
|
/* But remove shadow when wrapped in no-shadow class */
|
|
444
467
|
.no-shadow .long-text {
|
|
445
|
-
box-shadow: none
|
|
468
|
+
box-shadow: none;
|
|
469
|
+
border: none;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* Handle TOC layouts specially - tables should bleed within their grid column */
|
|
474
|
+
@media (min-width: 1200px) {
|
|
475
|
+
/* When TOC is present, tables should bleed within the content grid column */
|
|
476
|
+
.content-with-toc.has-toc table {
|
|
477
|
+
/* Calculate available width: full viewport minus TOC column width minus margins */
|
|
478
|
+
width: calc(100vw - var(--toc-width, 16rem) - 8rem);
|
|
479
|
+
max-width: none;
|
|
480
|
+
}
|
|
481
|
+
.content-with-toc.has-toc .table-container {
|
|
482
|
+
width: calc(100vw - var(--toc-width, 16rem) - 8rem);
|
|
483
|
+
max-width: none;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* But ensure tables don't exceed their grid column space */
|
|
487
|
+
.content-with-toc.has-toc .long-text {
|
|
488
|
+
/* The content area needs to allow tables to bleed beyond the text width */
|
|
489
|
+
overflow: visible;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/* Medium screens (768px - TOC breakpoint) - no TOC, tables should bleed but not as wide */
|
|
494
|
+
@media (min-width: 768px) and (max-width: 1199px) {
|
|
495
|
+
table {
|
|
496
|
+
width: calc(100vw - 6rem);
|
|
497
|
+
max-width: calc(100vw - 6rem);
|
|
498
|
+
}
|
|
499
|
+
.table-container {
|
|
500
|
+
width: calc(100vw - 6rem);
|
|
501
|
+
max-width: calc(100vw - 6rem);
|
|
446
502
|
}
|
|
447
503
|
}
|
|
448
504
|
|
|
449
505
|
/* Make narrower screens more usable for lists and tables. */
|
|
450
|
-
@media (max-width:
|
|
506
|
+
@media (max-width: 767px) {
|
|
451
507
|
/* Prevent horizontal scrolling on the body */
|
|
452
508
|
body {
|
|
453
509
|
overflow-x: hidden;
|
|
@@ -461,7 +517,7 @@ sup {
|
|
|
461
517
|
|
|
462
518
|
/* Make table containers scrollable without affecting page layout */
|
|
463
519
|
.table-container {
|
|
464
|
-
max-width:
|
|
520
|
+
max-width: calc(100vw - 3rem);
|
|
465
521
|
overflow-x: auto;
|
|
466
522
|
transform: none;
|
|
467
523
|
left: 0;
|
|
@@ -472,9 +528,10 @@ sup {
|
|
|
472
528
|
|
|
473
529
|
table {
|
|
474
530
|
font-size: var(--font-size-smaller);
|
|
475
|
-
/* Tables can be wider than container */
|
|
531
|
+
/* Tables can be wider than container on mobile */
|
|
476
532
|
width: auto;
|
|
477
533
|
min-width: 100%;
|
|
534
|
+
max-width: none;
|
|
478
535
|
}
|
|
479
536
|
|
|
480
537
|
ul, ol {
|
|
@@ -64,43 +64,58 @@
|
|
|
64
64
|
transition: background 0.4s ease-in-out, color 0.4s ease-in-out;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
.
|
|
68
|
-
position: fixed;
|
|
69
|
-
top: 1rem;
|
|
70
|
-
right: 1rem;
|
|
71
|
-
background: transparent;
|
|
67
|
+
.button {
|
|
72
68
|
color: var(--color-hint);
|
|
69
|
+
background: var(--color-bg);
|
|
73
70
|
border: none;
|
|
74
71
|
padding: 0;
|
|
75
72
|
border-radius: 0.3rem;
|
|
76
73
|
cursor: pointer;
|
|
77
74
|
font-size: 1rem;
|
|
78
|
-
z-index: 100;
|
|
79
|
-
transition: all 0.2s ease-in-out;
|
|
80
75
|
display: flex;
|
|
81
76
|
align-items: center;
|
|
82
77
|
justify-content: center;
|
|
83
78
|
width: 2.5rem;
|
|
84
79
|
height: 2.5rem;
|
|
80
|
+
|
|
81
|
+
/* Separate transitions for theme vs interaction */
|
|
82
|
+
transition: background-color 0.4s ease-in-out,
|
|
83
|
+
color 0.4s ease-in-out,
|
|
84
|
+
transform 0.2s ease-in-out,
|
|
85
|
+
box-shadow 0.2s ease-in-out;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
.
|
|
88
|
+
.button:hover {
|
|
88
89
|
background: var(--color-hover-bg);
|
|
89
90
|
color: var(--color-primary);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
.button svg {
|
|
94
|
+
width: 1rem;
|
|
95
|
+
height: 1rem;
|
|
96
|
+
transition: inherit; /* Inherit the color transition */
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Dark mode styles for buttons */
|
|
100
|
+
[data-theme="dark"] .button {
|
|
93
101
|
color: var(--color-primary-light);
|
|
94
102
|
}
|
|
95
103
|
|
|
96
|
-
[data-theme="dark"] .
|
|
97
|
-
color: var(--color-bright);
|
|
104
|
+
[data-theme="dark"] .button:hover {
|
|
98
105
|
background: var(--color-hover-bg);
|
|
106
|
+
color: var(--color-bright);
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
/* Positioning class for fixed buttons */
|
|
110
|
+
.fixed-button {
|
|
111
|
+
position: fixed;
|
|
112
|
+
top: 1rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Specific positioning and z-index for theme toggle */
|
|
116
|
+
.theme-toggle {
|
|
117
|
+
right: 1rem;
|
|
118
|
+
z-index: 100;
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
{% block font_faces %}
|
|
@@ -178,7 +193,7 @@
|
|
|
178
193
|
<body>
|
|
179
194
|
{% block theme_toggle %}
|
|
180
195
|
{% if show_theme_toggle %}
|
|
181
|
-
<button class="theme-toggle" aria-label="toggle dark mode">
|
|
196
|
+
<button class="button fixed-button theme-toggle" aria-label="toggle dark mode">
|
|
182
197
|
<i data-feather="moon"></i>
|
|
183
198
|
</button>
|
|
184
199
|
{% endif %}
|
|
@@ -197,11 +212,20 @@
|
|
|
197
212
|
document.addEventListener('DOMContentLoaded', () => {
|
|
198
213
|
// Add copy buttons to code blocks
|
|
199
214
|
document.querySelectorAll('pre').forEach(pre => {
|
|
200
|
-
// Skip if already has a copy button
|
|
201
|
-
if (pre.
|
|
215
|
+
// Skip if already has a copy button (check parent for wrapper)
|
|
216
|
+
if (pre.parentElement.classList.contains('code-block-wrapper')) {
|
|
202
217
|
return;
|
|
203
218
|
}
|
|
204
219
|
|
|
220
|
+
// Create wrapper div
|
|
221
|
+
const wrapper = document.createElement('div');
|
|
222
|
+
wrapper.className = 'code-block-wrapper';
|
|
223
|
+
|
|
224
|
+
// Insert wrapper before pre and move pre inside it
|
|
225
|
+
pre.parentNode.insertBefore(wrapper, pre);
|
|
226
|
+
wrapper.appendChild(pre);
|
|
227
|
+
|
|
228
|
+
// Create copy button
|
|
205
229
|
const copyButton = document.createElement('button');
|
|
206
230
|
copyButton.className = 'code-copy-button';
|
|
207
231
|
copyButton.setAttribute('aria-label', 'Copy code');
|
|
@@ -229,7 +253,8 @@
|
|
|
229
253
|
});
|
|
230
254
|
});
|
|
231
255
|
|
|
232
|
-
pre
|
|
256
|
+
// Add button to wrapper, not to pre
|
|
257
|
+
wrapper.appendChild(copyButton);
|
|
233
258
|
});
|
|
234
259
|
|
|
235
260
|
// Theme toggle (if present on page)
|
|
@@ -307,8 +332,9 @@
|
|
|
307
332
|
}
|
|
308
333
|
});
|
|
309
334
|
|
|
310
|
-
|
|
335
|
+
|
|
311
336
|
</script>
|
|
337
|
+
{% block scripts_extra %}{% endblock scripts_extra %}
|
|
312
338
|
{% endblock scripts %}
|
|
313
339
|
|
|
314
340
|
{% block analytics %}{% endblock analytics %}
|
|
@@ -15,34 +15,538 @@
|
|
|
15
15
|
[data-theme="dark"] .long-text {
|
|
16
16
|
background-color: var(--color-bg-alt-solid);
|
|
17
17
|
color: var(--color-text);
|
|
18
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 -2px 6px -1px rgba(0, 0, 0, 0.2);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
/*
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
/* Table of Contents Styles */
|
|
22
|
+
:root {
|
|
23
|
+
--toc-width: max(21vw, 15rem);
|
|
24
|
+
--toc-breakpoint: {{ toc_breakpoint | default(1200) }}px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@media (min-width: 1536px) {
|
|
28
|
+
:root {
|
|
29
|
+
--toc-width: min(21vw, 30rem);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Desktop: Always use grid layout, adjust TOC column width */
|
|
34
|
+
@media (min-width: {{ toc_breakpoint | default(1200) }}px) {
|
|
35
|
+
.content-with-toc {
|
|
36
|
+
display: grid;
|
|
37
|
+
grid-template-columns: calc(var(--toc-width) + 4rem) 1fr;
|
|
38
|
+
max-width: none;
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.content-with-toc.has-toc {
|
|
43
|
+
grid-template-columns: calc(var(--toc-width) + 4rem) 1fr;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Content goes in the second column (right side) */
|
|
47
|
+
.content-with-toc .long-text {
|
|
48
|
+
max-width: 48rem;
|
|
49
|
+
margin: 0 auto;
|
|
50
|
+
order: 2;
|
|
51
|
+
grid-column: 2;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* TOC goes in the first column (left side) */
|
|
55
|
+
.toc-container {
|
|
56
|
+
order: 1;
|
|
57
|
+
grid-column: 1;
|
|
58
|
+
align-self: start;
|
|
59
|
+
width: var(--toc-width);
|
|
60
|
+
position: sticky;
|
|
61
|
+
top: 2rem;
|
|
62
|
+
max-height: calc(100vh - 4rem);
|
|
63
|
+
overflow-y: auto;
|
|
64
|
+
padding: 1rem 0.7rem;
|
|
65
|
+
margin: 0 0 0 2rem;
|
|
66
|
+
border: 1px solid var(--color-border-hint);
|
|
67
|
+
opacity: 0;
|
|
68
|
+
transform: translateX(-100%);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.content-with-toc.has-toc .toc-container {
|
|
72
|
+
transform: translateX(0);
|
|
73
|
+
opacity: 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Hide mobile toggle on desktop */
|
|
77
|
+
.toc-toggle {
|
|
78
|
+
display: none !important;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* More minimal TOC scrollbar */
|
|
82
|
+
.toc-container::-webkit-scrollbar {
|
|
83
|
+
width: 2px;
|
|
84
|
+
}
|
|
85
|
+
.toc-container::-webkit-scrollbar-track {
|
|
86
|
+
background: transparent; /* Invisible track */
|
|
87
|
+
}
|
|
88
|
+
.toc-container::-webkit-scrollbar-thumb {
|
|
89
|
+
background: var(--color-hint-gentle);
|
|
90
|
+
border-radius: 2px;
|
|
91
|
+
opacity: 0.1;
|
|
92
|
+
}
|
|
93
|
+
.toc-container::-webkit-scrollbar-thumb:hover {
|
|
94
|
+
opacity: 0.2;
|
|
95
|
+
}
|
|
96
|
+
.toc-container {
|
|
97
|
+
/* For Firefox */
|
|
98
|
+
scrollbar-width: thin;
|
|
99
|
+
scrollbar-color: var(--color-hint-gentle) transparent;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* TOC Styling */
|
|
104
|
+
.toc {
|
|
105
|
+
font-family: var(--font-sans);
|
|
106
|
+
color: var(--color-tertiary);
|
|
107
|
+
font-variant-numeric: tabular-nums;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.toc-title {
|
|
111
|
+
font-size: var(--font-size-small);
|
|
112
|
+
font-weight: 550;
|
|
113
|
+
text-transform: uppercase;
|
|
114
|
+
letter-spacing: 0.025em;
|
|
115
|
+
margin: 0 0 0.5rem 0.3rem;
|
|
116
|
+
padding-bottom: 0.5rem;
|
|
117
|
+
border-bottom: 1px solid var(--color-border-hint);
|
|
118
|
+
transition: color 0.4s ease-in-out, border-bottom-color 0.4s ease-in-out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.toc-list {
|
|
122
|
+
list-style: none;
|
|
123
|
+
margin: 0;
|
|
124
|
+
padding: 0;
|
|
125
|
+
font-size: var(--font-size-small);
|
|
126
|
+
line-height: 1.2;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.toc-list li {
|
|
130
|
+
margin: 0;
|
|
131
|
+
padding: 0 0.3rem 0 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.toc-list li::before {
|
|
135
|
+
display: none; /* Remove custom bullet points */
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.toc-link {
|
|
139
|
+
display: block;
|
|
140
|
+
color: var(--color-tertiary);
|
|
141
|
+
text-decoration: none;
|
|
142
|
+
padding: 0.2rem 0;
|
|
143
|
+
transition: background 0.4s ease-in-out, all 0.15s ease-in-out;
|
|
144
|
+
border-left: 2px solid transparent;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.toc-link:hover {
|
|
148
|
+
color: var(--color-secondary);
|
|
149
|
+
background-color: var(--color-hover-bg);
|
|
150
|
+
text-decoration: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.toc-link.active {
|
|
154
|
+
color: var(--color-secondary);
|
|
155
|
+
border-left: 2px solid var(--color-primary);
|
|
156
|
+
background-color: var(--color-hover-bg);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Hanging indent and styles for each TOC heading */
|
|
160
|
+
.toc-h1 {
|
|
161
|
+
padding-left: 1.3rem;
|
|
162
|
+
text-indent: -1em;
|
|
163
|
+
font-weight: 550;
|
|
164
|
+
}
|
|
165
|
+
.toc-h2 {
|
|
166
|
+
padding-left: 2.0rem;
|
|
167
|
+
text-indent: -1em;
|
|
168
|
+
font-weight: 550;
|
|
169
|
+
}
|
|
170
|
+
.toc-h3 {
|
|
171
|
+
padding-left: 2.7rem;
|
|
172
|
+
text-indent: -1em;
|
|
173
|
+
font-weight: 380;
|
|
174
|
+
}
|
|
175
|
+
.toc-h4 {
|
|
176
|
+
padding-left: 3.4rem;
|
|
177
|
+
text-indent: -1em;
|
|
178
|
+
font-weight: 380;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Prevent body scroll when TOC is open */
|
|
182
|
+
body.toc-open {
|
|
183
|
+
overflow: hidden;
|
|
184
|
+
position: fixed;
|
|
185
|
+
width: 100%;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Mobile TOC Layout */
|
|
189
|
+
@media (max-width: {{ toc_breakpoint | default(1200) - 1 }}px) {
|
|
190
|
+
/* Specific positioning and z-index for TOC toggle */
|
|
191
|
+
.toc-toggle {
|
|
192
|
+
left: 1rem;
|
|
193
|
+
z-index: 101;
|
|
194
|
+
opacity: 0; /* Hidden by default */
|
|
195
|
+
visibility: hidden; /* Start hidden for FOUC prevention on mobile */
|
|
196
|
+
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* Show TOC toggle when user has scrolled past top */
|
|
200
|
+
.toc-toggle.show-toggle {
|
|
201
|
+
opacity: 1;
|
|
202
|
+
visibility: visible;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Show backdrop when visible */
|
|
206
|
+
.toc-backdrop.visible {
|
|
207
|
+
opacity: 1;
|
|
208
|
+
visibility: visible;
|
|
209
|
+
pointer-events: auto;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* Mobile TOC state: always rendered but hidden by default */
|
|
213
|
+
.toc-container {
|
|
214
|
+
display: block !important; /* Override base rule and any JS inline styles */
|
|
215
|
+
position: fixed;
|
|
216
|
+
top: 4rem;
|
|
217
|
+
left: 1rem;
|
|
218
|
+
width: calc(100vw - 2rem);
|
|
219
|
+
max-height: calc(100vh - 5rem);
|
|
220
|
+
/* Keep background and darker text on mobile since it's primary UI */
|
|
221
|
+
color: var(--color-text);
|
|
222
|
+
background: var(--color-bg-alt-solid);
|
|
223
|
+
border: 1px solid var(--color-border-hint);
|
|
224
|
+
padding: 1rem 0.7rem;
|
|
225
|
+
z-index: 200;
|
|
226
|
+
|
|
227
|
+
/* Ensure TOC itself is scrollable */
|
|
228
|
+
overflow-y: auto;
|
|
229
|
+
-webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
|
|
230
|
+
overscroll-behavior: contain; /* Prevent scroll chaining */
|
|
231
|
+
|
|
232
|
+
/* Initial hidden state for mobile FOUC and animation */
|
|
233
|
+
opacity: 0;
|
|
234
|
+
transform: translateY(-0.5rem);
|
|
235
|
+
visibility: hidden;
|
|
236
|
+
pointer-events: none; /* Prevent interaction when hidden */
|
|
237
|
+
|
|
238
|
+
transition: opacity 0.3s ease-in-out,
|
|
239
|
+
transform 0.3s ease-in-out,
|
|
240
|
+
visibility 0.3s ease-in-out,
|
|
241
|
+
pointer-events 0.3s ease-in-out,
|
|
242
|
+
background-color 0.4s ease-in-out,
|
|
243
|
+
border-color 0.4s ease-in-out,
|
|
244
|
+
box-shadow 0.4s ease-in-out;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Darker text on mobile */
|
|
248
|
+
.toc {
|
|
249
|
+
color: var(--color-secondary);
|
|
250
|
+
}
|
|
251
|
+
.toc-link {
|
|
252
|
+
color: var(--color-secondary);
|
|
253
|
+
}
|
|
254
|
+
.toc-link:hover {
|
|
255
|
+
color: var(--color-text);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.toc-link.active {
|
|
259
|
+
color: var(--color-text);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.toc-container.mobile-visible {
|
|
263
|
+
/* Visible state */
|
|
264
|
+
opacity: 1;
|
|
265
|
+
transform: translateY(0);
|
|
266
|
+
visibility: visible;
|
|
267
|
+
pointer-events: auto; /* Re-enable interaction */
|
|
268
|
+
}
|
|
23
269
|
}
|
|
24
270
|
</style>
|
|
25
271
|
{% endblock custom_styles %}
|
|
26
272
|
|
|
27
|
-
<!-- simple_webpage begin main_content block -->
|
|
28
273
|
{% block main_content %}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<div>
|
|
37
|
-
{% block page_content %}
|
|
38
|
-
{% if thumbnail_url %}
|
|
39
|
-
<img class="thumbnail" src="{{ thumbnail_url }}" alt="{{ title }}" />
|
|
274
|
+
<!-- simple_webpage begin main_content block -->
|
|
275
|
+
<div class="content-with-toc" id="content-container">
|
|
276
|
+
<div class="long-text container max-w-3xl mx-auto bg-white py-4 px-6 md:px-16" id="main-content">
|
|
277
|
+
{% block page_title %}
|
|
278
|
+
{% if title and add_title_h1 %}
|
|
279
|
+
<h1 class="text-center text-4xl mt-6 mb-6">{{ title }}</h1>
|
|
40
280
|
{% endif %}
|
|
41
|
-
|
|
42
|
-
|
|
281
|
+
{% endblock page_title %}
|
|
282
|
+
|
|
283
|
+
<div>
|
|
284
|
+
{% block page_content %}
|
|
285
|
+
{% if thumbnail_url %}
|
|
286
|
+
<img class="thumbnail" src="{{ thumbnail_url }}" alt="{{ title }}" />
|
|
287
|
+
{% endif %}
|
|
288
|
+
<div class="content">
|
|
289
|
+
{{ content_html | safe }}
|
|
290
|
+
</div>
|
|
291
|
+
{% endblock page_content %}
|
|
43
292
|
</div>
|
|
44
|
-
{% endblock page_content %}
|
|
45
293
|
</div>
|
|
294
|
+
|
|
295
|
+
<!-- Mobile TOC toggle -->
|
|
296
|
+
<button class="button fixed-button toc-toggle" id="toc-toggle" aria-label="Toggle table of contents" style="display: none;">
|
|
297
|
+
<i data-feather="list"></i>
|
|
298
|
+
</button>
|
|
299
|
+
|
|
300
|
+
<!-- Mobile TOC Backdrop -->
|
|
301
|
+
<div class="toc-backdrop" id="toc-backdrop"></div>
|
|
302
|
+
|
|
303
|
+
<!-- TOC Container -->
|
|
304
|
+
<aside class="toc-container" id="toc-container" aria-label="Table of contents">
|
|
305
|
+
<div class="toc">
|
|
306
|
+
<h2 class="toc-title">Contents</h2>
|
|
307
|
+
<ul class="toc-list" id="toc-list">
|
|
308
|
+
<!-- TOC items will be populated by JavaScript -->
|
|
309
|
+
</ul>
|
|
310
|
+
</div>
|
|
311
|
+
</aside>
|
|
46
312
|
</div>
|
|
313
|
+
<!-- simple_webpage end main_content block -->
|
|
47
314
|
{% endblock main_content %}
|
|
48
|
-
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
{% block scripts_extra %}
|
|
318
|
+
{{ super() }}
|
|
319
|
+
<!-- simple_webpage begin scripts_extra block -->
|
|
320
|
+
<script>
|
|
321
|
+
// Table of Contents functionality
|
|
322
|
+
function initTOC() {
|
|
323
|
+
const tocContainer = document.getElementById('toc-container');
|
|
324
|
+
const tocList = document.getElementById('toc-list');
|
|
325
|
+
const tocToggle = document.getElementById('toc-toggle');
|
|
326
|
+
const contentContainer = document.getElementById('content-container');
|
|
327
|
+
const mainContent = document.getElementById('main-content');
|
|
328
|
+
|
|
329
|
+
if (!tocContainer || !tocList || !mainContent) {
|
|
330
|
+
console.debug("TOC not initialized: missing elements");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const tocBreakpoint = parseInt(
|
|
335
|
+
getComputedStyle(document.documentElement)
|
|
336
|
+
.getPropertyValue('--toc-breakpoint')
|
|
337
|
+
.replace('px', '')
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
// Find all headings in the main content
|
|
341
|
+
const headings = mainContent.querySelectorAll('{{ toc_headings | default("h1, h2, h3") }}');
|
|
342
|
+
// Only show TOC if we have toc_min_headings (default 10) or more headings
|
|
343
|
+
const tocThreshold = {{ toc_min_headings | default(10) }};
|
|
344
|
+
|
|
345
|
+
if (headings.length < tocThreshold) {
|
|
346
|
+
// TOC is disabled
|
|
347
|
+
if (tocToggle) {
|
|
348
|
+
tocToggle.style.display = 'none';
|
|
349
|
+
}
|
|
350
|
+
console.debug("TOC hidden: not enough headings");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// TOC is enabled
|
|
355
|
+
contentContainer.classList.add('has-toc'); // This triggers grid layout
|
|
356
|
+
mainContent.classList.add('with-toc');
|
|
357
|
+
document.body.classList.add('page-has-toc');
|
|
358
|
+
|
|
359
|
+
if (tocToggle) {
|
|
360
|
+
tocToggle.style.display = 'flex';
|
|
361
|
+
// Ensure feather icon is rendered after making visible
|
|
362
|
+
if (typeof feather !== 'undefined') {
|
|
363
|
+
feather.replace();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Generate TOC items
|
|
368
|
+
tocList.innerHTML = '';
|
|
369
|
+
|
|
370
|
+
// If there is only one h1, skip it as it is the title of the page.
|
|
371
|
+
let filteredHeadings = Array.from(headings);
|
|
372
|
+
if (headings.length > 0) {
|
|
373
|
+
const firstHeading = headings[0];
|
|
374
|
+
const h1Count = filteredHeadings.filter(h => h.tagName.toLowerCase() === 'h1').length;
|
|
375
|
+
|
|
376
|
+
if (firstHeading.tagName.toLowerCase() === 'h1' && h1Count === 1) {
|
|
377
|
+
filteredHeadings = filteredHeadings.slice(1);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
filteredHeadings.forEach((heading, index) => {
|
|
382
|
+
// Ensure heading has an ID
|
|
383
|
+
if (!heading.id) {
|
|
384
|
+
const text = heading.textContent.trim().toLowerCase()
|
|
385
|
+
.replace(/[^\w\s-]/g, '')
|
|
386
|
+
.replace(/\s+/g, '-')
|
|
387
|
+
.replace(/-+/g, '-')
|
|
388
|
+
.replace(/^-|-$/g, '');
|
|
389
|
+
heading.id = text || `heading-${index}`;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const level = heading.tagName.toLowerCase();
|
|
393
|
+
const text = heading.textContent.trim();
|
|
394
|
+
|
|
395
|
+
const li = document.createElement('li');
|
|
396
|
+
const a = document.createElement('a');
|
|
397
|
+
a.href = `#${heading.id}`;
|
|
398
|
+
a.textContent = text;
|
|
399
|
+
a.className = `toc-link toc-${level}`;
|
|
400
|
+
|
|
401
|
+
li.appendChild(a);
|
|
402
|
+
tocList.appendChild(li);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Mobile TOC toggle functionality
|
|
406
|
+
if (tocToggle) {
|
|
407
|
+
const tocBackdrop = document.getElementById('toc-backdrop');
|
|
408
|
+
let scrollPosition = 0;
|
|
409
|
+
|
|
410
|
+
const openTOC = () => {
|
|
411
|
+
// Save current scroll position
|
|
412
|
+
scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
|
|
413
|
+
|
|
414
|
+
// Add classes to show TOC and prevent body scroll
|
|
415
|
+
tocContainer.classList.add('mobile-visible');
|
|
416
|
+
if (tocBackdrop) tocBackdrop.classList.add('visible');
|
|
417
|
+
document.body.classList.add('toc-open');
|
|
418
|
+
|
|
419
|
+
// Set body position to maintain scroll position while fixed
|
|
420
|
+
document.body.style.top = `-${scrollPosition}px`;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const closeTOC = () => {
|
|
424
|
+
// Remove classes
|
|
425
|
+
tocContainer.classList.remove('mobile-visible');
|
|
426
|
+
if (tocBackdrop) tocBackdrop.classList.remove('visible');
|
|
427
|
+
document.body.classList.remove('toc-open');
|
|
428
|
+
|
|
429
|
+
// Restore body position and scroll
|
|
430
|
+
document.body.style.top = '';
|
|
431
|
+
window.scrollTo(0, scrollPosition);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
tocToggle.addEventListener('click', () => {
|
|
435
|
+
if (tocContainer.classList.contains('mobile-visible')) {
|
|
436
|
+
closeTOC();
|
|
437
|
+
} else {
|
|
438
|
+
openTOC();
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Close TOC when clicking backdrop
|
|
443
|
+
if (tocBackdrop) {
|
|
444
|
+
tocBackdrop.addEventListener('click', closeTOC);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Update the existing click handler to use closeTOC
|
|
448
|
+
document.addEventListener('click', (e) => {
|
|
449
|
+
if (window.innerWidth < tocBreakpoint &&
|
|
450
|
+
tocContainer.classList.contains('mobile-visible') &&
|
|
451
|
+
!tocContainer.contains(e.target) &&
|
|
452
|
+
!tocToggle.contains(e.target)) {
|
|
453
|
+
closeTOC();
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Prevent touch events from propagating through TOC
|
|
458
|
+
tocContainer.addEventListener('touchmove', (e) => {
|
|
459
|
+
e.stopPropagation();
|
|
460
|
+
}, { passive: false });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Add smooth scrolling and active state management
|
|
464
|
+
const tocLinks = tocList.querySelectorAll('.toc-link');
|
|
465
|
+
tocLinks.forEach(link => {
|
|
466
|
+
link.addEventListener('click', (e) => {
|
|
467
|
+
e.preventDefault();
|
|
468
|
+
const targetId = link.getAttribute('href').substring(1);
|
|
469
|
+
const target = document.getElementById(targetId);
|
|
470
|
+
|
|
471
|
+
if (target) {
|
|
472
|
+
// Close TOC first on mobile
|
|
473
|
+
if (window.innerWidth < tocBreakpoint) {
|
|
474
|
+
tocContainer.classList.remove('mobile-visible');
|
|
475
|
+
document.getElementById('toc-backdrop')?.classList.remove('visible');
|
|
476
|
+
document.body.classList.remove('toc-open');
|
|
477
|
+
document.body.style.top = '';
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
target.scrollIntoView({
|
|
481
|
+
behavior: 'smooth',
|
|
482
|
+
block: 'start'
|
|
483
|
+
});
|
|
484
|
+
tocLinks.forEach(l => l.classList.remove('active'));
|
|
485
|
+
link.classList.add('active');
|
|
486
|
+
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// Helper function to check if TOC toggle should be visible
|
|
492
|
+
const updateTocToggleVisibility = () => {
|
|
493
|
+
if (tocToggle && tocLinks.length > 0) {
|
|
494
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
495
|
+
const activeLink = tocList.querySelector('.toc-link.active');
|
|
496
|
+
const firstTocLink = tocLinks[0];
|
|
497
|
+
|
|
498
|
+
// Only show toggle if:
|
|
499
|
+
// 1. We've scrolled down at least 100px from the top, AND
|
|
500
|
+
// 2. We're past the first section (activeLink exists and is not the first)
|
|
501
|
+
const hasScrolled = scrollTop > 100;
|
|
502
|
+
const isPastFirstSection = activeLink && activeLink !== firstTocLink;
|
|
503
|
+
const showToggle = hasScrolled && isPastFirstSection;
|
|
504
|
+
|
|
505
|
+
tocToggle.classList.toggle('show-toggle', showToggle);
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// Intersection Observer for active state
|
|
510
|
+
const observerOptions = {
|
|
511
|
+
rootMargin: '-20% 0% -70% 0%',
|
|
512
|
+
threshold: 0
|
|
513
|
+
};
|
|
514
|
+
const observer = new IntersectionObserver((entries) => {
|
|
515
|
+
entries.forEach(entry => {
|
|
516
|
+
if (entry.isIntersecting) {
|
|
517
|
+
tocLinks.forEach(link => link.classList.remove('active'));
|
|
518
|
+
const activeLink = tocList.querySelector(`a[href="#${entry.target.id}"]`);
|
|
519
|
+
if (activeLink) {
|
|
520
|
+
activeLink.classList.add('active');
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// Update toggle visibility after intersection changes
|
|
526
|
+
updateTocToggleVisibility();
|
|
527
|
+
}, observerOptions);
|
|
528
|
+
|
|
529
|
+
filteredHeadings.forEach(heading => observer.observe(heading));
|
|
530
|
+
|
|
531
|
+
// Update toggle visibility on scroll
|
|
532
|
+
let scrollTimeout;
|
|
533
|
+
window.addEventListener('scroll', () => {
|
|
534
|
+
// Throttle scroll events for performance
|
|
535
|
+
clearTimeout(scrollTimeout);
|
|
536
|
+
scrollTimeout = setTimeout(updateTocToggleVisibility, 16); // ~60fps
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Initial check
|
|
540
|
+
updateTocToggleVisibility();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Initialize immediately, no setTimeout
|
|
544
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
545
|
+
initTOC();
|
|
546
|
+
if (typeof feather !== 'undefined') {
|
|
547
|
+
feather.replace();
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
</script>
|
|
551
|
+
<!-- simple_webpage end scripts_extra block -->
|
|
552
|
+
{% endblock scripts_extra %}
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
{% endblock page_content %}
|
|
41
41
|
<!-- tabbed_webpage end page_content block -->
|
|
42
42
|
|
|
43
|
-
<!-- tabbed_webpage begin scripts_extra block -->
|
|
44
43
|
{% block scripts_extra %}
|
|
44
|
+
<!-- tabbed_webpage begin scripts_extra block -->
|
|
45
|
+
<script>
|
|
45
46
|
function showTab(tabId, element) {
|
|
46
47
|
document.querySelectorAll(".tab-pane").forEach((tab) => {
|
|
47
48
|
tab.classList.add("hidden");
|
|
@@ -54,5 +55,6 @@
|
|
|
54
55
|
element.classList.add("tab-button-active");
|
|
55
56
|
element.classList.remove("tab-button-inactive");
|
|
56
57
|
}
|
|
58
|
+
</script>
|
|
59
|
+
<!-- tabbed_webpage end scripts_extra block -->
|
|
57
60
|
{% endblock scripts_extra %}
|
|
58
|
-
<!-- tabbed_webpage end scripts_extra block -->
|
|
@@ -19,7 +19,7 @@ kash/commands/base/basic_file_commands.py,sha256=7xQreY3oewiJKYZYqcMZtClhqyKirg1
|
|
|
19
19
|
kash/commands/base/browser_commands.py,sha256=iYvpW4D_tlhW_p0cq3A6YO9UGCdHtvzIQiNMDwCY07A,1574
|
|
20
20
|
kash/commands/base/debug_commands.py,sha256=9I5W3SMQvsnpcs-b6CJCYu1Ydl6gIoTUcDZxvn1dN3g,7643
|
|
21
21
|
kash/commands/base/diff_commands.py,sha256=gOeSyCPg95LBnL6JobCR7lQHNS_c-29bDo1aIJkfyGw,4913
|
|
22
|
-
kash/commands/base/files_command.py,sha256=
|
|
22
|
+
kash/commands/base/files_command.py,sha256=fBuZ8sLqmfH8QekGe-P11mZ4jPxRLi3rLKhZqpdwQ5g,16759
|
|
23
23
|
kash/commands/base/general_commands.py,sha256=KaCbzk7o-ejwXE_H3PB3MrN00uTinP3T8uHKYrGPrIw,6946
|
|
24
24
|
kash/commands/base/logs_commands.py,sha256=IyNgxaAoa5LlS-VxD_x8bXTVbD04pT8qEHlIJNM09UU,2963
|
|
25
25
|
kash/commands/base/model_commands.py,sha256=d17a2NvfDbwV1y8gyZVsOtX-j5H5we5OEXM9TxTqvBs,1790
|
|
@@ -37,7 +37,7 @@ kash/commands/workspace/selection_commands.py,sha256=nZzA-H7Pk8kqSJVRlX7j1m6cZX-
|
|
|
37
37
|
kash/commands/workspace/workspace_commands.py,sha256=ZJ3aPsnQ0FOkaA6stpV4YPEOQRCOKTazbMCIQkk9Cmk,25119
|
|
38
38
|
kash/config/__init__.py,sha256=ytly9Typ1mWV4CXfV9G3CIPtPQ02u2rpZ304L3GlFro,148
|
|
39
39
|
kash/config/capture_output.py,sha256=ud3uUVNuDicHj3mI_nBUBO-VmOrxtBdA3z-I3D1lSCU,2398
|
|
40
|
-
kash/config/colors.py,sha256=
|
|
40
|
+
kash/config/colors.py,sha256=v8JTALJnjtSQVodfqCBkzC1a2gTrGUCjpIQmyp4u4cY,13208
|
|
41
41
|
kash/config/env_settings.py,sha256=uhCdfs9-TzJ15SzbuIQP1yIORaLUqYXCxh9qq_Z8cJc,996
|
|
42
42
|
kash/config/init.py,sha256=aE4sZ6DggBmmoZEx9C5mQKrEbcDiswX--HF7pfCFKzc,526
|
|
43
43
|
kash/config/lazy_imports.py,sha256=MCZXLnKvNyfHi0k7MU5rNwcdJtUF28naCixuogsAOAA,805
|
|
@@ -158,7 +158,7 @@ kash/media_base/transcription_format.py,sha256=rOVPTpwvW22c27BRwYF-Tc_xzqK_wOtUZ
|
|
|
158
158
|
kash/media_base/transcription_whisper.py,sha256=GqvroW9kBAH4-gcbYkMgNCfs2MpMIgm1ip3NMWtJ0IE,1169
|
|
159
159
|
kash/media_base/services/local_file_media.py,sha256=-A-tK6XP7XDCqXQIAoohesFZ3OIvpXWsDoktYBvBuNA,5399
|
|
160
160
|
kash/model/__init__.py,sha256=kFfBKb5N70NWYUfpRRxn_Sb9p_vXlB6BBaTCqWmSReo,2978
|
|
161
|
-
kash/model/actions_model.py,sha256=
|
|
161
|
+
kash/model/actions_model.py,sha256=iEp8QSB7My5xT4lurv03vXG6COD8aTLpgiSh5GT7Cr4,22088
|
|
162
162
|
kash/model/assistant_response_model.py,sha256=6eDfC27nyuBDFjv5nCYMa_Qb2mPbKwDzZy7uLOIyskI,2653
|
|
163
163
|
kash/model/compound_actions_model.py,sha256=HiDK5wwCu3WwZYHATZoLEguiqwR9V6V296wiKtGIX8s,6926
|
|
164
164
|
kash/model/concept_model.py,sha256=we2qOcy9Mv1q7XPfkDLp_CyO_-8DwAUfUYlpgy_jrFs,1011
|
|
@@ -251,13 +251,13 @@ kash/web_gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
251
251
|
kash/web_gen/simple_webpage.py,sha256=ks_0ljxCeS2-gAAEaUc1JEnzY3JY0nzqGFiyyqyRuZs,1537
|
|
252
252
|
kash/web_gen/tabbed_webpage.py,sha256=DiZV48TVvcjOf31g3nzTAtGKpH5Cek1Unksr7Cwcwog,4949
|
|
253
253
|
kash/web_gen/template_render.py,sha256=aypo6UanouftV4RpxgNm6JdquelI52fV0IlihdA3yjE,1908
|
|
254
|
-
kash/web_gen/templates/base_styles.css.jinja,sha256=
|
|
255
|
-
kash/web_gen/templates/base_webpage.html.jinja,sha256=
|
|
254
|
+
kash/web_gen/templates/base_styles.css.jinja,sha256=_lSVO7VxY2abKUh230lrzmxMitg6mw1iRV653tlcsvY,11712
|
|
255
|
+
kash/web_gen/templates/base_webpage.html.jinja,sha256=V3Xl8swCHjS9Ea6Fb8jch6uu9Ws7vG82TK_qz5Jps4Q,12935
|
|
256
256
|
kash/web_gen/templates/content_styles.css.jinja,sha256=3qcIwIt3DipCDJa9z6oIM_BMxmwoT7E_loTK0F3L9Vo,3629
|
|
257
257
|
kash/web_gen/templates/explain_view.html.jinja,sha256=DNw5Iw5SrhIUFRGB4qNvfcKXsBHVbEJVURGdhvyC75Q,949
|
|
258
258
|
kash/web_gen/templates/item_view.html.jinja,sha256=cYGyGKFcX8-5L2SM7-BC5oK6GLuH6blrzcxw2DxX-Q8,6828
|
|
259
|
-
kash/web_gen/templates/simple_webpage.html.jinja,sha256=
|
|
260
|
-
kash/web_gen/templates/tabbed_webpage.html.jinja,sha256=
|
|
259
|
+
kash/web_gen/templates/simple_webpage.html.jinja,sha256=R70mqQWXsJAQ1SGNw26dmMCDcaSOE49TBAkeZNUE2HY,15525
|
|
260
|
+
kash/web_gen/templates/tabbed_webpage.html.jinja,sha256=umkipUXW-lDGnbV-tlDroCfCx_385PFnpbzsvwmityo,1843
|
|
261
261
|
kash/workspaces/__init__.py,sha256=q1gFERRZLJMA9-XSUKvB1ulauHDKqyzzc86GFLbxAuk,700
|
|
262
262
|
kash/workspaces/param_state.py,sha256=vT_eGWqg2SRviIM5jqEAauznX2B5Xt2nHHu2oRxTcIU,746
|
|
263
263
|
kash/workspaces/selections.py,sha256=rEUuQlrQ3C_54bzBSKDTTptgX8oZPqN0Ao4uaXSWA-Q,12003
|
|
@@ -279,8 +279,8 @@ kash/xonsh_custom/xonsh_modern_tools.py,sha256=mj_b34LZXfE8MJe9EpDmp5JZ0tDM1biYN
|
|
|
279
279
|
kash/xonsh_custom/xonsh_ranking_completer.py,sha256=ZRGiAfoEgqgnlq2-ReUVEaX5oOgW1DQ9WxIv2OJLuTo,5620
|
|
280
280
|
kash/xontrib/fnm.py,sha256=V2tsOdmIDgbFbZSfMLpsvDIwwJJqiYnOkOySD1cXNXw,3700
|
|
281
281
|
kash/xontrib/kash_extension.py,sha256=FLIMlgR3C_6A1fwKE-Ul0nmmpJSszVPbAriinUyQ8Zg,1896
|
|
282
|
-
kash_shell-0.3.
|
|
283
|
-
kash_shell-0.3.
|
|
284
|
-
kash_shell-0.3.
|
|
285
|
-
kash_shell-0.3.
|
|
286
|
-
kash_shell-0.3.
|
|
282
|
+
kash_shell-0.3.17.dist-info/METADATA,sha256=Y6Ye4cgPa3d7YZ3sxJecXNxuN176GgkMz3Q5EIZMYsw,31258
|
|
283
|
+
kash_shell-0.3.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
284
|
+
kash_shell-0.3.17.dist-info/entry_points.txt,sha256=SQraWDAo8SqYpthLXThei0mf_hGGyhYBUO-Er_0HcwI,85
|
|
285
|
+
kash_shell-0.3.17.dist-info/licenses/LICENSE,sha256=rCh2PsfYeiU6FK_0wb58kHGm_Fj5c43fdcHEexiVzIo,34562
|
|
286
|
+
kash_shell-0.3.17.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|