kash-shell 0.3.9__py3-none-any.whl → 0.3.11__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/__init__.py +4 -4
- kash/actions/core/format_markdown_template.py +2 -5
- kash/actions/core/markdownify.py +7 -6
- kash/actions/core/readability.py +7 -6
- kash/actions/core/render_as_html.py +37 -0
- kash/actions/core/show_webpage.py +6 -11
- kash/actions/core/strip_html.py +2 -6
- kash/actions/core/tabbed_webpage_config.py +31 -0
- kash/actions/core/{webpage_generate.py → tabbed_webpage_generate.py} +5 -4
- kash/commands/__init__.py +8 -20
- kash/commands/base/basic_file_commands.py +15 -0
- kash/commands/base/debug_commands.py +13 -0
- kash/commands/base/files_command.py +28 -10
- kash/commands/base/general_commands.py +21 -16
- kash/commands/base/logs_commands.py +4 -2
- kash/commands/base/model_commands.py +8 -8
- kash/commands/base/search_command.py +3 -2
- kash/commands/base/show_command.py +5 -3
- kash/commands/extras/parse_uv_lock.py +186 -0
- kash/commands/help/doc_commands.py +2 -31
- kash/commands/help/welcome.py +33 -0
- kash/commands/workspace/selection_commands.py +11 -6
- kash/commands/workspace/workspace_commands.py +19 -17
- kash/config/colors.py +3 -1
- kash/config/env_settings.py +14 -1
- kash/config/init.py +2 -2
- kash/config/logger.py +59 -56
- kash/config/logger_basic.py +3 -3
- kash/config/settings.py +116 -57
- kash/config/setup.py +28 -12
- kash/config/text_styles.py +3 -13
- kash/docs/load_api_docs.py +2 -1
- kash/docs/markdown/topics/a3_getting_started.md +3 -2
- kash/{concepts → embeddings}/text_similarity.py +2 -2
- kash/exec/__init__.py +20 -3
- kash/exec/action_decorators.py +24 -10
- kash/exec/action_exec.py +41 -23
- kash/exec/action_registry.py +13 -48
- kash/exec/command_registry.py +2 -1
- kash/exec/fetch_url_metadata.py +4 -6
- kash/exec/importing.py +56 -0
- kash/exec/llm_transforms.py +12 -10
- kash/exec/precondition_registry.py +2 -1
- kash/exec/preconditions.py +22 -1
- kash/exec/resolve_args.py +4 -0
- kash/exec/shell_callable_action.py +33 -19
- kash/file_storage/file_store.py +42 -27
- kash/file_storage/item_file_format.py +5 -2
- kash/file_storage/metadata_dirs.py +11 -2
- kash/help/assistant.py +1 -1
- kash/help/assistant_instructions.py +2 -1
- kash/help/function_param_info.py +1 -1
- kash/help/help_embeddings.py +2 -2
- kash/help/help_printing.py +7 -11
- kash/llm_utils/clean_headings.py +1 -1
- kash/llm_utils/llm_api_keys.py +4 -4
- kash/llm_utils/llm_features.py +68 -0
- kash/llm_utils/llm_messages.py +1 -2
- kash/llm_utils/llm_names.py +1 -1
- kash/llm_utils/llms.py +8 -3
- kash/local_server/__init__.py +5 -2
- kash/local_server/local_server.py +8 -5
- kash/local_server/local_server_commands.py +2 -2
- kash/local_server/local_server_routes.py +1 -7
- kash/local_server/local_url_formatters.py +1 -1
- kash/mcp/__init__.py +5 -2
- kash/mcp/mcp_cli.py +5 -5
- kash/mcp/mcp_server_commands.py +5 -5
- kash/mcp/mcp_server_routes.py +5 -5
- kash/mcp/mcp_server_sse.py +4 -2
- kash/media_base/media_cache.py +8 -8
- kash/media_base/media_services.py +1 -1
- kash/media_base/media_tools.py +6 -6
- kash/media_base/services/local_file_media.py +2 -2
- kash/media_base/{speech_transcription.py → transcription_deepgram.py} +25 -110
- kash/media_base/transcription_format.py +73 -0
- kash/media_base/transcription_whisper.py +38 -0
- kash/model/__init__.py +73 -5
- kash/model/actions_model.py +38 -4
- kash/model/concept_model.py +30 -0
- kash/model/items_model.py +115 -32
- kash/model/params_model.py +24 -0
- kash/shell/completions/completion_scoring.py +37 -5
- kash/shell/output/kerm_codes.py +1 -2
- kash/shell/output/shell_formatting.py +14 -4
- kash/shell/shell_main.py +2 -2
- kash/shell/utils/exception_printing.py +6 -0
- kash/shell/utils/native_utils.py +26 -20
- kash/shell/utils/shell_function_wrapper.py +15 -15
- kash/text_handling/custom_sliding_transforms.py +12 -4
- kash/text_handling/doc_normalization.py +6 -2
- kash/text_handling/markdown_render.py +118 -0
- kash/text_handling/markdown_utils.py +226 -0
- kash/utils/common/function_inspect.py +360 -110
- kash/utils/common/import_utils.py +12 -3
- kash/utils/common/type_utils.py +0 -29
- kash/utils/common/url.py +27 -3
- kash/utils/errors.py +6 -0
- kash/utils/file_utils/file_ext.py +4 -0
- kash/utils/file_utils/file_formats.py +2 -2
- kash/utils/file_utils/file_formats_model.py +20 -1
- kash/web_content/dir_store.py +1 -2
- kash/web_content/file_cache_utils.py +37 -10
- kash/web_content/file_processing.py +68 -0
- kash/web_content/local_file_cache.py +12 -9
- kash/web_content/web_extract.py +8 -3
- kash/web_content/web_fetch.py +12 -4
- kash/web_gen/__init__.py +0 -4
- kash/web_gen/simple_webpage.py +52 -0
- kash/web_gen/tabbed_webpage.py +24 -14
- kash/web_gen/template_render.py +37 -2
- kash/web_gen/templates/base_styles.css.jinja +169 -43
- kash/web_gen/templates/base_webpage.html.jinja +110 -45
- kash/web_gen/templates/content_styles.css.jinja +4 -2
- kash/web_gen/templates/item_view.html.jinja +49 -39
- kash/web_gen/templates/simple_webpage.html.jinja +24 -0
- kash/web_gen/templates/tabbed_webpage.html.jinja +42 -33
- kash/workspaces/__init__.py +15 -2
- kash/workspaces/selections.py +18 -3
- kash/workspaces/source_items.py +0 -1
- kash/workspaces/workspaces.py +5 -11
- kash/xonsh_custom/command_nl_utils.py +40 -19
- kash/xonsh_custom/custom_shell.py +43 -11
- kash/xonsh_custom/customize_prompt.py +39 -21
- kash/xonsh_custom/load_into_xonsh.py +22 -25
- kash/xonsh_custom/shell_load_commands.py +2 -2
- kash/xonsh_custom/xonsh_completers.py +2 -249
- kash/xonsh_custom/xonsh_keybindings.py +282 -0
- kash/xonsh_custom/xonsh_modern_tools.py +3 -3
- kash/xontrib/kash_extension.py +5 -6
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/METADATA +10 -8
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/RECORD +137 -136
- kash/actions/core/webpage_config.py +0 -21
- kash/concepts/concept_formats.py +0 -23
- kash/shell/clideps/api_keys.py +0 -100
- kash/shell/clideps/dotenv_setup.py +0 -115
- kash/shell/clideps/dotenv_utils.py +0 -98
- kash/shell/clideps/pkg_deps.py +0 -257
- kash/shell/clideps/platforms.py +0 -11
- kash/shell/clideps/terminal_features.py +0 -56
- kash/shell/utils/osc_utils.py +0 -95
- kash/shell/utils/terminal_images.py +0 -133
- kash/text_handling/markdown_util.py +0 -167
- kash/utils/common/atomic_var.py +0 -171
- kash/utils/common/string_replace.py +0 -93
- kash/utils/common/string_template.py +0 -101
- /kash/{concepts → embeddings}/cosine.py +0 -0
- /kash/{concepts → embeddings}/embeddings.py +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/WHEEL +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/entry_points.txt +0 -0
- {kash_shell-0.3.9.dist-info → kash_shell-0.3.11.dist-info}/licenses/LICENSE +0 -0
kash/web_gen/template_render.py
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from contextvars import ContextVar
|
|
1
4
|
from pathlib import Path
|
|
2
5
|
|
|
3
6
|
from jinja2 import Environment, FileSystemLoader
|
|
4
7
|
|
|
5
8
|
from kash.config import colors
|
|
6
9
|
|
|
10
|
+
_base_templates_dir = Path(__file__).parent / "templates"
|
|
11
|
+
"""Common base web page templates."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_additional_template_dirs: ContextVar[list[Path] | None] = ContextVar(
|
|
15
|
+
"_additional_template_dirs", default=None
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_template_dirs(*dirs: Path) -> list[Path]:
|
|
20
|
+
"""
|
|
21
|
+
Returns template directories currently in context along with any
|
|
22
|
+
additional template directories.
|
|
23
|
+
"""
|
|
24
|
+
additional = _additional_template_dirs.get() or []
|
|
25
|
+
return list(dirs) + [*additional, _base_templates_dir]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@contextmanager
|
|
29
|
+
def additional_template_dirs(*dirs: Path) -> Iterator[None]:
|
|
30
|
+
"""
|
|
31
|
+
Context manager for temporarily adding template directories to the search path.
|
|
32
|
+
"""
|
|
33
|
+
original = _additional_template_dirs.get()
|
|
34
|
+
current = [] if not original else original.copy()
|
|
35
|
+
token = _additional_template_dirs.set(current + list(dirs))
|
|
36
|
+
try:
|
|
37
|
+
yield
|
|
38
|
+
finally:
|
|
39
|
+
_additional_template_dirs.reset(token)
|
|
40
|
+
|
|
7
41
|
|
|
8
42
|
def render_web_template(
|
|
9
|
-
templates_dir: Path,
|
|
10
43
|
template_filename: str,
|
|
11
44
|
data: dict,
|
|
12
45
|
autoescape: bool = True,
|
|
@@ -14,11 +47,13 @@ def render_web_template(
|
|
|
14
47
|
) -> str:
|
|
15
48
|
"""
|
|
16
49
|
Render a Jinja2 template file with the given data, returning an HTML string.
|
|
50
|
+
Uses template directories from the base directory and any added via context manager.
|
|
17
51
|
"""
|
|
18
52
|
if css_overrides is None:
|
|
19
53
|
css_overrides = {}
|
|
20
54
|
|
|
21
|
-
|
|
55
|
+
search_paths = get_template_dirs()
|
|
56
|
+
env = Environment(loader=FileSystemLoader(search_paths), autoescape=autoescape)
|
|
22
57
|
|
|
23
58
|
# Load and render the template.
|
|
24
59
|
template = env.get_template(template_filename)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
:root {
|
|
2
|
+
{% block root_variables %}
|
|
2
3
|
font-size: 16px;
|
|
3
|
-
|
|
4
|
-
--font-sans: "
|
|
4
|
+
/* Adding Hack Nerd Font to all fonts for icon support, if it is installed. */
|
|
5
|
+
--font-sans: "Source Sans 3 Variable", sans-serif, "Hack Nerd Font";
|
|
5
6
|
--font-serif: "PT Serif", serif, "Hack Nerd Font";
|
|
7
|
+
--font-weight-sans-bold: 625; /* Source Sans 3 Variable better at this weight. */
|
|
6
8
|
--font-mono: "Hack Nerd Font", "Menlo", "DejaVu Sans Mono", Consolas, "Lucida Console", monospace;
|
|
7
9
|
|
|
8
10
|
--font-size-large: 1.2rem;
|
|
@@ -15,14 +17,17 @@
|
|
|
15
17
|
|
|
16
18
|
--console-char-width: 88;
|
|
17
19
|
--console-width: calc(var(--console-char-width) + 2rem);
|
|
20
|
+
{% endblock root_variables %}
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
{{ color_defs|safe }}
|
|
21
24
|
|
|
25
|
+
{% block selection_styles %}
|
|
22
26
|
::selection {
|
|
23
27
|
background-color: var(--color-selection);
|
|
24
28
|
color: inherit;
|
|
25
29
|
}
|
|
30
|
+
{% endblock selection_styles %}
|
|
26
31
|
|
|
27
32
|
{# TODO: Fix PDF issues and re-enable for prettier emoji. #}
|
|
28
33
|
{# @font-face {
|
|
@@ -38,6 +43,7 @@
|
|
|
38
43
|
U+1F900-1F9FF; /* Supplemental Symbols and Pictographs */
|
|
39
44
|
} #}
|
|
40
45
|
|
|
46
|
+
{% block scrollbar_styles %}
|
|
41
47
|
/* Scrollbar coloring. */
|
|
42
48
|
/* For Webkit browsers (Chrome, Safari) */
|
|
43
49
|
::-webkit-scrollbar {
|
|
@@ -59,20 +65,40 @@
|
|
|
59
65
|
scrollbar-width: thin;
|
|
60
66
|
scrollbar-color: var(--color-scrollbar) var(--color-bg);
|
|
61
67
|
}
|
|
68
|
+
{% endblock scrollbar_styles %}
|
|
62
69
|
|
|
70
|
+
{% block body_styles %}
|
|
63
71
|
body {
|
|
64
72
|
font-family: var(--font-serif);
|
|
65
73
|
color: var(--color-text);
|
|
66
|
-
line-height: 1.
|
|
74
|
+
line-height: 1.4;
|
|
67
75
|
padding: 0; /* No padding so we can have full width elements. */
|
|
68
76
|
margin: auto;
|
|
69
77
|
background-color: var(--color-bg);
|
|
78
|
+
overflow-wrap: break-word; /* Don't let long words/URLs break layout. */
|
|
70
79
|
}
|
|
80
|
+
{% endblock body_styles %}
|
|
71
81
|
|
|
82
|
+
{% block typography %}
|
|
72
83
|
p {
|
|
73
84
|
margin-bottom: 1rem;
|
|
74
85
|
}
|
|
75
86
|
|
|
87
|
+
b, strong {
|
|
88
|
+
font-weight: var(--font-weight-sans-bold);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
a {
|
|
92
|
+
color: var(--color-primary);
|
|
93
|
+
text-decoration: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
a:hover {
|
|
97
|
+
color: var(--color-primary-light);
|
|
98
|
+
text-decoration: underline;
|
|
99
|
+
transition: all 0.15s ease-in-out;
|
|
100
|
+
}
|
|
101
|
+
|
|
76
102
|
h1,
|
|
77
103
|
h2,
|
|
78
104
|
h3,
|
|
@@ -88,49 +114,19 @@ h1 {
|
|
|
88
114
|
|
|
89
115
|
h2 {
|
|
90
116
|
font-size: 1.4rem;
|
|
91
|
-
margin-top:
|
|
117
|
+
margin-top: 2.5rem;
|
|
92
118
|
margin-bottom: 1rem;
|
|
93
119
|
}
|
|
94
120
|
|
|
95
121
|
h3 {
|
|
96
|
-
font-size: 1.
|
|
97
|
-
margin-top: 1.
|
|
98
|
-
margin-bottom:
|
|
122
|
+
font-size: 1.09rem;
|
|
123
|
+
margin-top: 1.7rem;
|
|
124
|
+
margin-bottom: 0.7rem;
|
|
99
125
|
}
|
|
100
126
|
|
|
101
127
|
h4 {
|
|
102
128
|
margin-top: 1rem;
|
|
103
|
-
margin-bottom:
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/* Long text stylings, for nicely formatting blog post length or longer texts. */
|
|
107
|
-
|
|
108
|
-
.long-text h1 {
|
|
109
|
-
font-family: var(--font-serif);
|
|
110
|
-
font-weight: 400;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.long-text h2 {
|
|
114
|
-
font-family: var(--font-serif);
|
|
115
|
-
font-weight: 400;
|
|
116
|
-
font-style: italic;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.long-text h3 {
|
|
120
|
-
font-family: var(--font-sans);
|
|
121
|
-
font-weight: 700;
|
|
122
|
-
text-transform: uppercase;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.long-text h4 {
|
|
126
|
-
font-family: var(--font-serif);
|
|
127
|
-
font-weight: 700;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.subtitle {
|
|
131
|
-
font-family: var(--font-serif);
|
|
132
|
-
font-style: italic;
|
|
133
|
-
font-size: 1rem;
|
|
129
|
+
margin-bottom: 0.7rem;
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
ul {
|
|
@@ -141,22 +137,31 @@ ul {
|
|
|
141
137
|
}
|
|
142
138
|
|
|
143
139
|
li {
|
|
144
|
-
margin-top: 0.
|
|
140
|
+
margin-top: 0.7rem;
|
|
145
141
|
margin-bottom: 0;
|
|
146
142
|
position: relative;
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
|
|
145
|
+
li > p {
|
|
146
|
+
margin-bottom: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
ul > li::before {
|
|
150
150
|
content: "▪︎";
|
|
151
151
|
position: absolute;
|
|
152
|
-
left:
|
|
153
|
-
|
|
152
|
+
left: -.85rem;
|
|
153
|
+
top: .25rem;
|
|
154
|
+
font-size: 0.62rem;
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
ol {
|
|
158
|
+
margin-bottom: 0.7rem;
|
|
157
159
|
list-style-type: decimal;
|
|
158
160
|
margin-left: 2rem;
|
|
159
|
-
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
ol > li {
|
|
164
|
+
padding-left: 0.25rem;
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
blockquote {
|
|
@@ -180,7 +185,86 @@ pre {
|
|
|
180
185
|
letter-spacing: -0.025em;
|
|
181
186
|
{# overflow-x: auto; #}
|
|
182
187
|
}
|
|
188
|
+
{% endblock typography %}
|
|
189
|
+
|
|
190
|
+
{% block long_text_styles %}
|
|
191
|
+
/* Long text stylings, for nicely formatting blog post length or longer texts. */
|
|
192
|
+
|
|
193
|
+
.long-text h1 {
|
|
194
|
+
font-family: var(--font-serif);
|
|
195
|
+
font-weight: 400;
|
|
196
|
+
}
|
|
183
197
|
|
|
198
|
+
.long-text h2 {
|
|
199
|
+
font-family: var(--font-serif);
|
|
200
|
+
font-weight: 400;
|
|
201
|
+
font-style: italic;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.long-text h3 {
|
|
205
|
+
font-family: var(--font-sans);
|
|
206
|
+
font-weight: var(--font-weight-sans-bold);
|
|
207
|
+
text-transform: uppercase;
|
|
208
|
+
letter-spacing: 0.02em;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.long-text h4 {
|
|
212
|
+
font-family: var(--font-serif);
|
|
213
|
+
font-weight: 700;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.subtitle {
|
|
217
|
+
font-family: var(--font-serif);
|
|
218
|
+
font-style: italic;
|
|
219
|
+
font-size: 1rem;
|
|
220
|
+
}
|
|
221
|
+
{% endblock long_text_styles %}
|
|
222
|
+
|
|
223
|
+
{% block table_styles %}
|
|
224
|
+
table {
|
|
225
|
+
font-family: var(--font-sans);
|
|
226
|
+
font-size: var(--font-size-small);
|
|
227
|
+
width: auto;
|
|
228
|
+
margin-left: auto;
|
|
229
|
+
margin-right: auto;
|
|
230
|
+
border-collapse: collapse;
|
|
231
|
+
word-break: break-word; /* long words/URLs wrap instead of inflating the column */
|
|
232
|
+
border: 1px solid var(--color-border-hint);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
th {
|
|
236
|
+
text-transform: uppercase;
|
|
237
|
+
letter-spacing: 0.02em;
|
|
238
|
+
border-bottom: 1px solid var(--color-border-hint);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
th, td {
|
|
242
|
+
padding: 0.3rem 0.6rem;
|
|
243
|
+
max-width: 40rem;
|
|
244
|
+
min-width: 6rem;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
th {
|
|
248
|
+
background-color: var(--color-bg-alt-solid);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
tbody tr:nth-child(even) {
|
|
252
|
+
background-color: var(--color-bg-alt-solid);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* Container for wide tables to allow tables to break out of parent width. */
|
|
256
|
+
.table-container {
|
|
257
|
+
{# max-width: calc(100vw - 6rem); #}
|
|
258
|
+
position: relative;
|
|
259
|
+
left: 50%;
|
|
260
|
+
transform: translateX(-50%);
|
|
261
|
+
box-sizing: border-box;
|
|
262
|
+
margin-bottom: 1rem;
|
|
263
|
+
background-color: var(--color-bg-solid);
|
|
264
|
+
}
|
|
265
|
+
{% endblock table_styles %}
|
|
266
|
+
|
|
267
|
+
{% block nav_styles %}
|
|
184
268
|
nav {
|
|
185
269
|
display: flex;
|
|
186
270
|
flex-wrap: wrap;
|
|
@@ -190,3 +274,45 @@ nav {
|
|
|
190
274
|
gap: 1rem;
|
|
191
275
|
/* Add some space between the buttons */
|
|
192
276
|
}
|
|
277
|
+
{% endblock nav_styles %}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
{% block footnote_styles %}
|
|
282
|
+
/* Footnotes. */
|
|
283
|
+
sup {
|
|
284
|
+
font-size: 80%;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.footnote-ref a, .footnote {
|
|
288
|
+
text-decoration: none;
|
|
289
|
+
padding: 0 0.15rem;
|
|
290
|
+
border-radius: 4px;
|
|
291
|
+
transition: all 0.15s ease-in-out;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.footnote-ref a:hover, .footnote:hover {
|
|
295
|
+
background-color: var(--color-hover-bg);
|
|
296
|
+
color: var(--color-primary-light);
|
|
297
|
+
text-decoration: none;
|
|
298
|
+
}
|
|
299
|
+
{% endblock footnote_styles %}
|
|
300
|
+
|
|
301
|
+
{% block responsive_styles %}
|
|
302
|
+
/* Bleed wide on larger screens. */
|
|
303
|
+
/* TODO: Don't make so wide if table itself isn't large? */
|
|
304
|
+
@media (min-width: 768px) {
|
|
305
|
+
table {
|
|
306
|
+
width: calc(100vw - 6rem);
|
|
307
|
+
}
|
|
308
|
+
.table-container {
|
|
309
|
+
width: calc(100vw - 6rem);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
@media (max-width: 768px) {
|
|
314
|
+
table {
|
|
315
|
+
font-size: var(--font-size-smaller);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
{% endblock responsive_styles %}
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
4
|
<head>
|
|
5
|
+
{% block meta %}
|
|
5
6
|
<meta charset="UTF-8" />
|
|
6
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
|
|
8
|
+
{% endblock meta %}
|
|
8
9
|
|
|
10
|
+
{% block title %}<title>{{ title }}</title>{% endblock title %}
|
|
11
|
+
|
|
12
|
+
{% block head_basic %}
|
|
9
13
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
10
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
15
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
@@ -20,12 +24,19 @@
|
|
|
20
24
|
<link rel="preload" as="font" type="font/woff2" crossorigin
|
|
21
25
|
href="https://cdn.jsdelivr.net/fontsource/fonts/pt-serif@latest/latin-700-italic.woff2" />
|
|
22
26
|
<link rel="preload" as="font" type="font/woff2" crossorigin
|
|
23
|
-
href="https://cdn.jsdelivr.net/fontsource/fonts/
|
|
27
|
+
href="https://cdn.jsdelivr.net/fontsource/fonts/source-sans-3:vf@latest/latin-wght-normal.woff2" />
|
|
28
|
+
<link rel="preload" as="font" type="font/woff2" crossorigin
|
|
29
|
+
href="https://cdn.jsdelivr.net/fontsource/fonts/source-sans-3:vf@latest/latin-wght-italic.woff2" />
|
|
24
30
|
|
|
25
31
|
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet" />
|
|
26
32
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js" defer></script>
|
|
33
|
+
{% endblock head_basic %}
|
|
34
|
+
|
|
35
|
+
{% block head_extra %}{% endblock head_extra %}
|
|
27
36
|
|
|
28
37
|
<style>
|
|
38
|
+
{% block font_faces %}
|
|
39
|
+
/* https://fontsource.org/fonts/pt-serif/cdn */
|
|
29
40
|
/* pt-serif-latin-400-normal */
|
|
30
41
|
@font-face {
|
|
31
42
|
font-family: 'PT Serif';
|
|
@@ -62,63 +73,117 @@
|
|
|
62
73
|
src: url(https://cdn.jsdelivr.net/fontsource/fonts/pt-serif@latest/latin-700-italic.woff2) format('woff2');
|
|
63
74
|
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
|
64
75
|
}
|
|
76
|
+
/* https://fontsource.org/fonts/source-sans-3/cdn */
|
|
77
|
+
/* source-sans-3-latin-wght-normal */
|
|
65
78
|
@font-face {
|
|
66
|
-
font-family: '
|
|
79
|
+
font-family: 'Source Sans 3 Variable';
|
|
67
80
|
font-style: normal;
|
|
68
81
|
font-display: block;
|
|
69
|
-
font-weight:
|
|
70
|
-
src: url(https://cdn.jsdelivr.net/fontsource/fonts/
|
|
71
|
-
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+
|
|
82
|
+
font-weight: 200 900;
|
|
83
|
+
src: url(https://cdn.jsdelivr.net/fontsource/fonts/source-sans-3:vf@latest/latin-wght-normal.woff2) format('woff2-variations');
|
|
84
|
+
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
|
72
85
|
}
|
|
86
|
+
/* source-sans-3-latin-wght-normal */
|
|
87
|
+
@font-face {
|
|
88
|
+
font-family: 'Source Sans 3 Variable';
|
|
89
|
+
font-style: italic;
|
|
90
|
+
font-display: block;
|
|
91
|
+
font-weight: 200 900;
|
|
92
|
+
src: url(https://cdn.jsdelivr.net/fontsource/fonts/source-sans-3:vf@latest/latin-wght-italic.woff2) format('woff2-variations');
|
|
93
|
+
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
|
94
|
+
}
|
|
95
|
+
{# Other decent sans serif options: Work Sans Variable, Nunito Sans Variable #}
|
|
96
|
+
{% endblock font_faces %}
|
|
73
97
|
|
|
98
|
+
{% block base_styles %}
|
|
74
99
|
{% include "base_styles.css.jinja" %}
|
|
100
|
+
{% endblock base_styles %}
|
|
101
|
+
|
|
102
|
+
{% block content_styles %}
|
|
75
103
|
{% include "content_styles.css.jinja" %}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{{
|
|
79
|
-
{% endif %}
|
|
104
|
+
{% endblock content_styles %}
|
|
105
|
+
|
|
106
|
+
{% block custom_styles %}{% endblock custom_styles %}
|
|
80
107
|
</style>
|
|
81
|
-
|
|
82
108
|
</head>
|
|
83
109
|
|
|
84
110
|
<body>
|
|
111
|
+
{% block body_header %}{% endblock body_header %}
|
|
112
|
+
|
|
113
|
+
{% block main_content %}
|
|
85
114
|
{{ content|safe }}
|
|
86
|
-
|
|
115
|
+
{% endblock main_content %}
|
|
116
|
+
|
|
117
|
+
{% block body_footer %}{% endblock body_footer %}
|
|
118
|
+
|
|
119
|
+
{% block scripts %}
|
|
120
|
+
<script>
|
|
121
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
122
|
+
// Send messages to the parent window, in case we are in a viewport where that matters
|
|
123
|
+
// (e.g. an iframe tooltip).
|
|
124
|
+
// Request a resize of the parent viewport. This iframe size message format isn't
|
|
125
|
+
// standardized by ResizeObserver, but is common. It is supported by Kerm.
|
|
126
|
+
const content = document.body;
|
|
127
|
+
console.log("Suggesting resize to parent:", content.offsetWidth, content.offsetHeight);
|
|
87
128
|
|
|
88
|
-
<script>
|
|
89
|
-
// Some messages are sent to the parent window, in case we are in a viewport like a
|
|
90
|
-
// tooltip that supports it.
|
|
91
|
-
|
|
92
|
-
// Request a resize of the parent viewport (e.g. tooltip).
|
|
93
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
94
|
-
const content = document.body;
|
|
95
|
-
console.log("Suggesting resize to parent:", content.offsetWidth, content.offsetHeight);
|
|
96
|
-
// This iframe size message format isn't standardized by ResizeObserver, but is common.
|
|
97
|
-
// It is supported by Kerm.
|
|
98
|
-
window.parent.postMessage({
|
|
99
|
-
type: 'resize',
|
|
100
|
-
width: Math.max(content.offsetWidth, 600),
|
|
101
|
-
height: Math.max(content.offsetHeight, 100)
|
|
102
|
-
}, '*');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Double-click to expand (e.g. expand tooltip to popover).
|
|
106
|
-
document.addEventListener('dblclick', () => {
|
|
107
|
-
console.log("Sending expand message to parent");
|
|
108
|
-
window.parent.postMessage({
|
|
109
|
-
type: 'expand'
|
|
110
|
-
}, '*');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Escape to close tooltip or popover.
|
|
114
|
-
document.addEventListener('keydown', (event) => {
|
|
115
|
-
if (event.key === 'Escape') {
|
|
116
|
-
console.log("Sending close message to parent");
|
|
117
129
|
window.parent.postMessage({
|
|
118
|
-
type: '
|
|
130
|
+
type: 'resize',
|
|
131
|
+
width: Math.max(content.offsetWidth, 600),
|
|
132
|
+
height: Math.max(content.offsetHeight, 100)
|
|
119
133
|
}, '*');
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
|
|
135
|
+
// Wrap tables within the main content area for horizontal scrolling.
|
|
136
|
+
const containers = [];
|
|
137
|
+
document.querySelectorAll('.long-text').forEach(el => {
|
|
138
|
+
const pane = el.querySelector('.tab-pane');
|
|
139
|
+
containers.push(pane || el);
|
|
140
|
+
});
|
|
141
|
+
containers.forEach(container => {
|
|
142
|
+
// Find all tables within the container.
|
|
143
|
+
const tables = Array.from(container.querySelectorAll('table'));
|
|
144
|
+
tables.forEach(table => {
|
|
145
|
+
// Skip tables already in table-container divs
|
|
146
|
+
if (table.parentNode.classList.contains('table-container')) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
// Create the wrapper.
|
|
151
|
+
const wrapper = document.createElement('div');
|
|
152
|
+
wrapper.className = 'table-container';
|
|
153
|
+
// Get the parent and insert the wrapper where the table is, then move the table into the wrapper.
|
|
154
|
+
const parent = table.parentNode;
|
|
155
|
+
parent.insertBefore(wrapper, table);
|
|
156
|
+
wrapper.appendChild(table);
|
|
157
|
+
} catch (e) {
|
|
158
|
+
console.error("Error wrapping table:", e);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Double-click to expand (e.g. expand tooltip to popover).
|
|
165
|
+
document.addEventListener('dblclick', () => {
|
|
166
|
+
console.log("Sending expand message to parent");
|
|
167
|
+
window.parent.postMessage({
|
|
168
|
+
type: 'expand'
|
|
169
|
+
}, '*');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Escape to close tooltip or popover.
|
|
173
|
+
document.addEventListener('keydown', (event) => {
|
|
174
|
+
if (event.key === 'Escape') {
|
|
175
|
+
console.log("Sending close message to parent");
|
|
176
|
+
window.parent.postMessage({
|
|
177
|
+
type: 'close'
|
|
178
|
+
}, '*');
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
{% block scripts_extra %}{% endblock scripts_extra %}
|
|
183
|
+
</script>
|
|
184
|
+
{% endblock scripts %}
|
|
185
|
+
|
|
186
|
+
{% block analytics %}{% endblock analytics %}
|
|
187
|
+
</body>
|
|
123
188
|
|
|
124
189
|
</html>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
padding: 0 0.4rem;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
{# More novel bracket ideas: [❲⟦⟪⟬〔〘〚〖 ]❳⟧⟫⟭ 〕〙〛〗 #}
|
|
19
19
|
.citation::before {
|
|
20
20
|
content: "[";
|
|
21
21
|
}
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
font-weight: 500;
|
|
58
58
|
font-size: 1.2rem;
|
|
59
59
|
text-transform: uppercase;
|
|
60
|
+
letter-spacing: 0.02em;
|
|
60
61
|
margin-bottom: 0.5rem;
|
|
61
62
|
}
|
|
62
63
|
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
font-weight: 500;
|
|
82
83
|
font-size: 1.2rem;
|
|
83
84
|
text-transform: uppercase;
|
|
85
|
+
letter-spacing: 0.02em;
|
|
84
86
|
margin-bottom: 0.5rem;
|
|
85
87
|
|
|
86
88
|
/* Hack to center the header above the columns */
|
|
@@ -107,7 +109,7 @@
|
|
|
107
109
|
font-size: var(--font-size-small);
|
|
108
110
|
font-weight: 600;
|
|
109
111
|
text-transform: uppercase;
|
|
110
|
-
letter-spacing: 0.
|
|
112
|
+
letter-spacing: 0.02em;
|
|
111
113
|
line-height: 1.2;
|
|
112
114
|
padding: 0 0.5rem;
|
|
113
115
|
border-bottom-width: 2px;
|