kash-shell 0.3.17__py3-none-any.whl → 0.3.18__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/actions/core/minify_html.py +41 -0
- kash/commands/base/show_command.py +11 -1
- kash/config/colors.py +6 -2
- kash/docs/markdown/topics/a1_what_is_kash.md +52 -23
- kash/docs/markdown/topics/a2_installation.md +17 -30
- kash/docs/markdown/topics/a3_getting_started.md +5 -19
- kash/exec/action_exec.py +1 -1
- kash/exec/fetch_url_metadata.py +9 -0
- kash/exec/precondition_registry.py +3 -3
- kash/file_storage/file_store.py +18 -1
- kash/llm_utils/llm_features.py +5 -1
- kash/llm_utils/llms.py +18 -8
- kash/media_base/media_cache.py +48 -24
- kash/media_base/media_services.py +63 -14
- kash/media_base/services/local_file_media.py +9 -1
- kash/model/items_model.py +4 -5
- kash/model/media_model.py +9 -1
- kash/model/params_model.py +9 -3
- kash/utils/common/function_inspect.py +97 -1
- kash/utils/common/testing.py +58 -0
- kash/utils/common/url_slice.py +329 -0
- kash/utils/file_utils/file_formats.py +1 -1
- kash/utils/text_handling/markdown_utils.py +424 -16
- kash/web_gen/templates/base_styles.css.jinja +137 -15
- kash/web_gen/templates/base_webpage.html.jinja +13 -17
- kash/web_gen/templates/components/toc_scripts.js.jinja +319 -0
- kash/web_gen/templates/components/toc_styles.css.jinja +284 -0
- kash/web_gen/templates/components/tooltip_scripts.js.jinja +730 -0
- kash/web_gen/templates/components/tooltip_styles.css.jinja +482 -0
- kash/web_gen/templates/content_styles.css.jinja +13 -8
- kash/web_gen/templates/simple_webpage.html.jinja +15 -481
- kash/workspaces/workspaces.py +10 -1
- {kash_shell-0.3.17.dist-info → kash_shell-0.3.18.dist-info}/METADATA +75 -72
- {kash_shell-0.3.17.dist-info → kash_shell-0.3.18.dist-info}/RECORD +37 -30
- {kash_shell-0.3.17.dist-info → kash_shell-0.3.18.dist-info}/WHEEL +0 -0
- {kash_shell-0.3.17.dist-info → kash_shell-0.3.18.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.17.dist-info → kash_shell-0.3.18.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,7 +5,15 @@
|
|
|
5
5
|
<style>
|
|
6
6
|
/* Override Tailwind's bg-white in dark mode */
|
|
7
7
|
[data-theme="dark"] .bg-white {
|
|
8
|
-
background-color: var(--color-bg-alt-solid)
|
|
8
|
+
background-color: var(--color-bg-alt-solid);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* Fallback responsive padding for compatibility */
|
|
12
|
+
@media (min-width: 768px) {
|
|
13
|
+
.content-with-toc .long-text {
|
|
14
|
+
padding-left: 4rem;
|
|
15
|
+
padding-right: 4rem;
|
|
16
|
+
}
|
|
9
17
|
}
|
|
10
18
|
.long-text {
|
|
11
19
|
transition: background 0.4s ease-in-out, color 0.4s ease-in-out;
|
|
@@ -18,255 +26,8 @@
|
|
|
18
26
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 -2px 6px -1px rgba(0, 0, 0, 0.2);
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
}
|
|
269
|
-
}
|
|
29
|
+
{% include "components/toc_styles.css.jinja" %}
|
|
30
|
+
{% include "components/tooltip_styles.css.jinja" %}
|
|
270
31
|
</style>
|
|
271
32
|
{% endblock custom_styles %}
|
|
272
33
|
|
|
@@ -293,7 +54,7 @@ body.toc-open {
|
|
|
293
54
|
</div>
|
|
294
55
|
|
|
295
56
|
<!-- Mobile TOC toggle -->
|
|
296
|
-
<button class="button fixed-button toc-toggle" id="toc-toggle" aria-label="Toggle table of contents" style="display: none;">
|
|
57
|
+
<button class="button fixed-button floating-button toc-toggle" id="toc-toggle" aria-label="Toggle table of contents" style="display: none;">
|
|
297
58
|
<i data-feather="list"></i>
|
|
298
59
|
</button>
|
|
299
60
|
|
|
@@ -303,7 +64,7 @@ body.toc-open {
|
|
|
303
64
|
<!-- TOC Container -->
|
|
304
65
|
<aside class="toc-container" id="toc-container" aria-label="Table of contents">
|
|
305
66
|
<div class="toc">
|
|
306
|
-
<
|
|
67
|
+
<a href="#" class="toc-link toc-title" id="toc-title-link">Contents</a>
|
|
307
68
|
<ul class="toc-list" id="toc-list">
|
|
308
69
|
<!-- TOC items will be populated by JavaScript -->
|
|
309
70
|
</ul>
|
|
@@ -318,235 +79,8 @@ body.toc-open {
|
|
|
318
79
|
{{ super() }}
|
|
319
80
|
<!-- simple_webpage begin scripts_extra block -->
|
|
320
81
|
<script>
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
});
|
|
82
|
+
{% include "components/toc_scripts.js.jinja" %}
|
|
83
|
+
{% include "components/tooltip_scripts.js.jinja" %}
|
|
550
84
|
</script>
|
|
551
85
|
<!-- simple_webpage end scripts_extra block -->
|
|
552
86
|
{% endblock scripts_extra %}
|
kash/workspaces/workspaces.py
CHANGED
|
@@ -19,7 +19,11 @@ from kash.model.params_model import GLOBAL_PARAMS, RawParamValues
|
|
|
19
19
|
from kash.shell.output.shell_output import PrintHooks, cprint
|
|
20
20
|
from kash.utils.errors import FileNotFound, InvalidInput, InvalidState
|
|
21
21
|
from kash.utils.file_utils.ignore_files import IgnoreFilter, is_ignored_default
|
|
22
|
-
from kash.workspaces.workspace_dirs import
|
|
22
|
+
from kash.workspaces.workspace_dirs import (
|
|
23
|
+
check_strict_workspace_name,
|
|
24
|
+
is_global_ws_dir,
|
|
25
|
+
is_ws_dir,
|
|
26
|
+
)
|
|
23
27
|
from kash.workspaces.workspace_registry import WorkspaceInfo, get_ws_registry
|
|
24
28
|
|
|
25
29
|
if TYPE_CHECKING:
|
|
@@ -49,6 +53,11 @@ class Workspace(ABC):
|
|
|
49
53
|
def base_dir(self) -> Path:
|
|
50
54
|
"""The base directory for this workspace."""
|
|
51
55
|
|
|
56
|
+
@property
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def assets_dir(self) -> Path:
|
|
59
|
+
"""The directory for this workspace's assets."""
|
|
60
|
+
|
|
52
61
|
|
|
53
62
|
def resolve_ws(name: str | Path) -> WorkspaceInfo:
|
|
54
63
|
"""
|