Skip to content

Commit b8a0b80

Browse files
committed
Add collapsing chapter navigation to the book template
1 parent 4b88260 commit b8a0b80

6 files changed

Lines changed: 121 additions & 53 deletions

File tree

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
// Configured in `.prettierrc`
2727
"editor.defaultFormatter": "esbenp.prettier-vscode"
2828
},
29+
// Website: don't format Zola/Tera-templated HTML on save
30+
"[html]": {
31+
"editor.formatOnSave": false
32+
},
2933
// Handlebars: don't save on format
3034
// (`about.hbs` is used by Cargo About to encode license information)
3135
"[handlebars]": {

website/content/volunteer/guide/project-setup/_index.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ Clone the project to a convenient location:
3232

3333
```sh
3434
git clone https://github.com/GraphiteEditor/Graphite.git
35-
cd Graphite
3635
```
3736

3837
## Development builds
@@ -43,20 +42,27 @@ From either the `/` (root) or `/frontend` directories, you can run the project b
4342
npm start
4443
```
4544

46-
This spins up the dev server at <http://localhost:8080> with a file watcher that performs hot reloading of the web page. You should be able to start the server, edit and save web and Rust code, and shut it down by double pressing <kbd>Ctrl</kbd><kbd>C</kbd>. You sometimes may need to reload the browser's page if hot reloading didn't behave right— always refresh when Rust recompiles.
45+
This spins up the dev server at <http://localhost:8080> with a file watcher that performs hot reloading of the web page. You should be able to start the server, edit and save web and Rust code, and shut it down by double pressing <kbd>Ctrl</kbd><kbd>C</kbd>. TypeScript and HTML changes require a manual page reload to fix broken state.
4746

4847
This method compiles Graphite code in debug mode which includes debug symbols for viewing function names in stack traces. But be aware, it runs slower and the Wasm binary is much larger. (Having your browser's developer tools open will also significantly impact performance in both debug and release builds, so it's best to close that when not in use.)
4948

50-
To run the dev server in optimized mode, which is faster and produces a smaller Wasm binary:
49+
<details>
50+
<summary>Dev server optimized build instructions: click here</summary>
51+
52+
On rare occasions (like while running advanced performance profiles or proxying the dev server connection over a slow network where the >100 MB unoptimized binary size would pose an issue), you may need to run the dev server with release optimizations. To do that while keeping debug symbols:
5153

5254
```sh
53-
# Includes debug symbols
5455
npm run profiling
56+
```
57+
58+
To run the dev server without debug symbols, using the same release optimizations as production builds:
5559

56-
# Excludes (most) debug symbols, used in release builds
60+
```sh
5761
npm run production
5862
```
5963

64+
</details>
65+
6066
<details>
6167
<summary>Production build instructions: click here</summary>
6268

website/sass/base.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ body > .page {
375375
// ELEMENT SPACING RULES
376376
// =====================
377377

378-
:is(h1, h2, h3, h4, article > :first-child, details > summary) ~ :is(p, ul, ol, ol li p, img, a:has(> img:only-child)),
378+
:is(h1, h2, h3, h4, article > :first-child, details > summary) ~ :is(p, ul, ol, ol li p, img, details, a:has(> img:only-child)),
379379
:is(h1, h2, h3, h4, article > :first-child) ~ :is(ul, ol) li p + img,
380380
:is(h1, h2, h3, h4, p) ~ .feature-icons,
381381
p ~ :is(h1, h2, h3, h4, details summary, blockquote, .image-comparison, .video-background, .youtube-embed),

website/sass/template/book.scss

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@
110110
border-right: var(--border-thickness) solid var(--color-walnut);
111111
box-sizing: border-box;
112112
transition: left 0.25s ease-in-out;
113-
left: calc(-1 * (var(--aside-width) + 10px));
114-
width: var(--aside-width);
113+
left: calc(-1 * (Min(var(--aside-width), 100vw) + 10px));
114+
width: Min(var(--aside-width), 100vw);
115115

116116
&::after {
117117
content: "";
@@ -128,8 +128,9 @@
128128
overflow-y: auto;
129129
height: 100%;
130130
padding-right: var(--page-edge-padding);
131+
margin-left: -24px;
131132

132-
ul:first-of-type {
133+
> ul:first-of-type {
133134
margin-top: calc(120 * var(--variable-px) + var(--align-with-article-title-letter-cap-heights));
134135
}
135136

@@ -173,43 +174,54 @@
173174
align-self: flex-start;
174175
overflow-y: auto;
175176
top: 0;
176-
width: var(--aside-width);
177+
width: Min(var(--aside-width), 100vw);
177178
max-height: 100vh;
178-
margin-top: -40px;
179+
margin-top: calc(-40 * var(--variable-px));
179180
flex: 0 1 auto;
181+
--level-indent: 0.75rem;
180182

181183
&.contents > ul,
182184
.wrapper-inner > ul {
183185
&:first-of-type {
184-
margin-top: calc(40px + var(--align-with-article-title-letter-cap-heights));
186+
margin-top: calc(40 * var(--variable-px) + var(--align-with-article-title-letter-cap-heights));
185187
}
186188

187189
&:last-of-type {
188190
margin-bottom: calc(40 * var(--variable-px));
189191
}
192+
193+
> ul {
194+
margin-left: 0;
195+
}
196+
}
197+
198+
&.contents > ul > ul :is(ul, li),
199+
.wrapper-inner > ul > ul > ul,
200+
.wrapper-inner > ul > ul > ul :is(ul, li) {
201+
margin-top: 0.5rem;
190202
}
191203

192204
ul {
193205
list-style: none;
194206
padding: 0;
195207
margin: 0;
196-
margin-top: 40px;
197208

198-
ul {
199-
margin-top: 0;
200-
margin-left: 1em;
209+
&,
210+
ul,
211+
li {
212+
margin-top: calc(40 * var(--variable-px));
201213
}
202214

203-
li {
204-
margin-top: 0.5em;
215+
ul {
216+
margin-left: var(--level-indent);
217+
}
205218

206-
a {
207-
color: var(--color-walnut);
219+
li:has(> label > input:not(:checked)) + ul {
220+
display: none;
221+
}
208222

209-
&:hover {
210-
color: var(--color-crimson);
211-
}
212-
}
223+
li {
224+
font-size: 0;
213225

214226
&:not(.title) a {
215227
text-decoration: none;
@@ -219,6 +231,50 @@
219231
&.chapter {
220232
font-weight: 700;
221233
}
234+
235+
label {
236+
display: inline-block;
237+
position: relative;
238+
user-select: none;
239+
vertical-align: bottom;
240+
margin-right: 4px;
241+
width: 20px;
242+
height: calc(1rem * 1.5);
243+
244+
&:has(input):hover {
245+
background: var(--color-fog);
246+
}
247+
248+
&:has(input)::before {
249+
content: "";
250+
background: url('data:image/svg+xml;utf8,\
251+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><polygon fill="%2316323f" points="4,0 1,0 6,5 1,10 4,10 9,5 4,0" /></svg>\
252+
');
253+
position: absolute;
254+
margin: auto;
255+
inset: 0;
256+
width: 10px;
257+
height: 10px;
258+
}
259+
260+
&:has(input:checked)::before {
261+
transform: rotate(90deg);
262+
}
263+
264+
input {
265+
display: none;
266+
}
267+
}
268+
269+
a {
270+
color: var(--color-walnut);
271+
font-size: 1rem;
272+
273+
&:hover {
274+
color: var(--color-crimson);
275+
text-decoration: underline;
276+
}
277+
}
222278
}
223279
}
224280

@@ -230,8 +286,6 @@
230286

231287
ul a {
232288
display: inline-block;
233-
padding-left: 1em;
234-
text-indent: -1em;
235289
}
236290
}
237291

website/templates/book.html

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,7 @@
5757
<polygon points="20.7,4.7 19.3,3.3 12,10.6 4.7,3.3 3.3,4.7 10.6,12 3.3,19.3 4.7,20.7 12,13.4 19.3,20.7 20.7,19.3 13.4,12" />
5858
</svg>
5959
</button>
60-
<ul>
61-
<li class="title {%- if current_path == book.path %} active{%- endif -%}"><a href="{{ book.path | safe }}" title="{{ book.title | safe }}">{{ book.title }}</a></li>
62-
</ul>
63-
{%- for chapter in chapters %}
64-
<ul>
65-
<li class="chapter {%- if current_path == chapter.path %} active{%- endif -%}">
66-
<a href="{{ chapter.path | safe }}" title="{{ chapter.title | safe }}">{{ chapter.title }}</a>
67-
</li>
68-
{{- book_outline::render_book_outline(section = chapter, current_path = current_path, indents = 4) }}
69-
</ul>
70-
{%- endfor %}
60+
{{- book_outline::render_book_outline(parent = book, current_path = current_path, index = 0, indents = 3) }}
7161
</div>
7262
</div>
7363
</aside>
@@ -133,8 +123,8 @@ <h1>
133123
{% if page.toc | length > 0 %}Contents<span> (top ↑)</span>{% else %}Back to top ↑{% endif %}
134124
</a>
135125
</li>
126+
{{- book_outline::render_book_page_toc(children = page.toc, indents = 1) }}
136127
</ul>
137-
{{- book_outline::render_book_page_toc(children = page.toc, indents = 1) }}
138128
</aside>
139129
</section>
140130
{%- endblock content -%}

website/templates/macros/book-outline.html

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,46 @@
1616
{%- endmacro render_book_page_toc -%}
1717

1818
{# Recursively render a book's chapters table of contents #}
19-
{%- macro render_book_outline(section, current_path, indents) -%}
19+
{%- macro render_book_outline(parent, current_path, index, indents) -%}
2020
{#- Setup -#}
21-
{%- set items = [] -%}
22-
{%- if section.pages -%}
23-
{%- set_global items = items | concat(with = section.pages) -%}
21+
{%- set chapters = parent.pages | default(value = []) -%}
22+
{%- if index == 0 -%}
23+
{%- set_global chapters = [parent] -%}
24+
{%- else -%}
25+
{%- for subsection_path in parent.subsections -%}
26+
{%- set_global chapters = chapters | concat(with = get_section(path = subsection_path)) -%}
27+
{%- endfor -%}
2428
{%- endif -%}
25-
{%- if section.subsections -%}
26-
{%- for subsection_path in section.subsections -%}
27-
{%- set subsection = get_section(path = subsection_path) -%}
28-
{%- set_global items = items | concat(with = subsection) -%}
29-
{%- endfor -%}
29+
{%- if index > 0 -%}
30+
{%- set_global chapters = chapters | sort(attribute = "extra.order") -%}
3031
{%- endif -%}
31-
{%- set items = items | sort(attribute = "extra.order") -%}
3232
{#- End of setup -#}
3333

3434
{%- set tabs = "" -%}
3535
{%- for i in range(end = indents) -%}
3636
{%- set_global tabs = tabs ~ " " -%}
3737
{%- endfor -%}
3838

39-
{%- if items | length > 0 %}
39+
{%- if chapters | length > 0 %}
4040
{{ tabs }}<ul>
41-
{%- for item in items %}
42-
{{ tabs }}<li {%- if current_path == item.path %} class="active"{%- endif -%}><a href="{{ item.path | safe }}" title="{{ item.title | safe }}">{{ item.title }}</a></li>
43-
{%- if item.pages or item.subsections -%}
44-
{{ self::render_book_outline(section = item, current_path = current_path, indents = indents + 1) }}
41+
{%- for chapter in chapters %}
42+
{%- set children = chapter.pages or chapter.subsections | default(value = []) -%}
43+
{%- set_global classes = [] -%}
44+
{%- if index == 0 -%}
45+
{%- set_global classes = classes | concat(with = "title") -%}
46+
{%- endif -%}
47+
{%- if index == 1 -%}
48+
{%- set_global classes = classes | concat(with = "chapter") -%}
49+
{%- endif -%}
50+
{%- if current_path == chapter.path -%}
51+
{%- set_global classes = classes | concat(with = "active") -%}
52+
{%- endif %}
53+
{{ tabs }}<li {%- if classes | length > 0 %} class="{{ classes | join(sep = " ") }}"{% endif %}>
54+
{{ tabs }}<label>{% if children and not index == 0 %}<input type="checkbox" {%- if current_path is starting_with(chapter.path) %} checked{% endif %} />{% endif %}</label>
55+
{{ tabs }}<a href="{{ chapter.path | safe }}" title="{{ chapter.title | safe }}">{{ chapter.title }}</a>
56+
{{ tabs }}</li>
57+
{%- if children -%}
58+
{{ self::render_book_outline(parent = chapter, current_path = current_path, index = index + 1, indents = indents + 1) }}
4559
{%- endif %}
4660
{%- endfor %}
4761
{{ tabs }}</ul>

0 commit comments

Comments
 (0)