11# ## A Pluto.jl notebook ###
2- # v0.20.16
2+ # v0.20.17
33
44using Markdown
55using InteractiveUtils
@@ -170,14 +170,47 @@ md"""
170170NotebookCard
171171
172172# ╔═╡ 1b8ada7b-4996-4d75-baea-cc1f6ac74f5b
173+ # ╠═╡ skip_as_script = true
174+ #= ╠═╡
173175hint("Here is a secret tip!")
176+ ╠═╡ =#
174177
175178# ╔═╡ 3af20543-447f-4525-ad99-6f4ccdc2b96e
179+ # ╠═╡ skip_as_script = true
180+ #= ╠═╡
176181TODO ("I still need to do this!")
182+ ╠═╡ =#
183+
184+ # ╔═╡ f846b527-9cfc-4412-8b12-35dfec47840f
185+ # ╠═╡ skip_as_script = true
186+ #= ╠═╡
187+ keyconcept(
188+ "",
189+ md"""
190+ Here is something important that you should remember from this class.
191+ """
192+ )
193+ ╠═╡ =#
194+
195+ # ╔═╡ a0f06078-5caf-4312-9ad9-0719d40d29c3
196+ # ╠═╡ skip_as_script = true
197+ #= ╠═╡
198+ keyconcept(
199+ "Now with a title",
200+ md"""
201+ Here is something important that you should remember from this class.
202+ """
203+ )
204+ ╠═╡ =#
177205
178206# ╔═╡ 21016357-2813-4f74-adab-ddde0b8b704b
179207
180208
209+ # ╔═╡ 51cbb5ef-9f8f-4570-8a35-5f6415302b9c
210+ md """
211+ At the end of the lecture, you can use `keyconceptsummary` to generate an **automatic summary** of all key concepts in the lecture:
212+ """
213+
181214# ╔═╡ 9f42a11b-97bd-4a7d-94c9-ba74494ae4d0
182215md """
183216# Appendix
@@ -304,6 +337,8 @@ begin
304337end
305338
306339# ╔═╡ 5f298ea0-ce92-411d-9a50-6d7964ab51e2
340+ # ╠═╡ skip_as_script = true
341+ #= ╠═╡
307342md"""
308343It's trivial!
309344
@@ -312,6 +347,7 @@ x = x
312347```
313348
314349""" |> hide_proof(open=true)
350+ ╠═╡ =#
315351
316352# ╔═╡ 06051ef2-08b0-4d7d-bff9-9c2d407c65cc
317353begin
@@ -326,6 +362,8 @@ begin
326362end
327363
328364# ╔═╡ ed2f0fe9-0078-44c8-a0d2-4f25c50fddaa
365+ # ╠═╡ skip_as_script = true
366+ #= ╠═╡
329367hide_solution(md"""
330368It's trivial!
331369
@@ -334,9 +372,106 @@ x = x
334372```
335373
336374""")
375+ ╠═╡ =#
337376
338377# ╔═╡ 6c723aec-e620-4820-b5e3-f7d55c4bb1dc
378+ keyconceptsummary (; header_text= " " ) = @htl """
379+ <div>
380+ $(header_text === nothing || header_text == " " ? nothing : @htl (" <h1>$header_text </h1>" ))
381+
382+ <div class="key-concepts-repeat">
383+ </div>
384+
385+ <script>
386+ const wrapper = currentScript.parentElement
387+ const repeat = wrapper.querySelector(".key-concepts-repeat")
388+
389+
390+
391+
392+ const render = () => {
393+
394+ const nodes = [...document.querySelectorAll("div.key-concept")].filter(n => n.closest(".key-concepts-repeat") == null)
395+
396+ repeat.innerHTML= ""
397+ nodes.forEach((n) => {
398+ const div = document.createElement("div")
399+ div.style = "position: relative; margin-block-end: 2em;"
400+
401+ const a = document.createElement("a")
402+ a.href = "#" + n.closest("pluto-cell").id
403+ a.innerText = "↑ Jump to source"
404+ a.style = `
405+ position: absolute;
406+ box-shadow: 0 0 10px #0000001a;
407+ font-family: system-ui;
408+ font-weight: 600;
409+ text-decoration: none;
410+ display: inline-flex;
411+ background: var(--white);
412+ border-radius: 10rem;
413+ padding: 0.2em 0.8em;
414+ right: 5px;
415+ top: 5.5px;
416+ `
417+ div.appendChild(a)
418+ div.appendChild(n.cloneNode(true))
419+ repeat.appendChild(div)
420+ })
421+
422+ }
423+
424+
425+
426+
427+
428+
429+
430+
431+ // This mutationObserver code is from PlutoUI.TableOfContents. Check that code for the latest version with comments.
432+ const invalidated = { current: false }
433+ const updateCallback = () => setTimeout(render, 1000)
434+ render()
435+ updateCallback()
436+ const notebook = wrapper.closest("pluto-notebook")
437+ const mut_observers = { current: [] }
438+ const createCellObservers = () => {
439+ mut_observers.current.forEach((o) => o.disconnect())
440+ mut_observers.current = Array.from(notebook.querySelectorAll("pluto-cell")).map(el => {
441+ const o = new MutationObserver(updateCallback)
442+ o.observe(el, {attributeFilter: ["class"]})
443+ return o
444+ })
445+ }
446+ createCellObservers()
447+ const notebookObserver = new MutationObserver(() => {
448+ updateCallback()
449+ createCellObservers()
450+ })
451+ notebookObserver.observe(notebook, {childList: true})
452+
453+ const bodyClassObserver = new MutationObserver(updateCallback)
454+ bodyClassObserver.observe(document.body, {attributeFilter: ["class"]})
455+
456+ invalidation.then(() => {
457+ invalidated.current = true
458+ notebookObserver.disconnect()
459+ bodyClassObserver.disconnect()
460+ mut_observers.current.forEach((o) => o.disconnect())
461+ })
462+
463+ </script>
464+
465+ """
466+
467+ # ╔═╡ 88d8b652-95a2-4451-b7c3-50dec7d88ca0
468+ # ╠═╡ skip_as_script = true
469+ #= ╠═╡
470+ keyconceptsummary()
471+ ╠═╡ =#
339472
473+ # ╔═╡ d296808d-04be-483e-831c-32ef170e272b
474+ export keyconceptsummary
340475
341476# ╔═╡ Cell order:
342477# ╟─6ca174aa-6395-485d-a396-83e220dbfcb7
@@ -382,7 +517,11 @@ x = x
382517# ╠═73c6b1e4-52e7-42b4-82f7-c3ff0a951dfc
383518# ╠═1b8ada7b-4996-4d75-baea-cc1f6ac74f5b
384519# ╠═3af20543-447f-4525-ad99-6f4ccdc2b96e
520+ # ╠═f846b527-9cfc-4412-8b12-35dfec47840f
521+ # ╠═a0f06078-5caf-4312-9ad9-0719d40d29c3
385522# ╟─21016357-2813-4f74-adab-ddde0b8b704b
523+ # ╟─51cbb5ef-9f8f-4570-8a35-5f6415302b9c
524+ # ╠═88d8b652-95a2-4451-b7c3-50dec7d88ca0
386525# ╟─9f42a11b-97bd-4a7d-94c9-ba74494ae4d0
387526# ╟─45c6db01-38ac-4779-a724-af8ac3a0ac66
388527# ╠═90ad6438-7fd5-422c-a0f4-52a220919194
@@ -397,4 +536,5 @@ x = x
397536# ╠═a2704374-33c2-479e-bad0-1bac6c244db1
398537# ╠═d0931a54-3bff-4f2d-ad60-eb45721dfa0f
399538# ╠═06051ef2-08b0-4d7d-bff9-9c2d407c65cc
539+ # ╠═d296808d-04be-483e-831c-32ef170e272b
400540# ╠═6c723aec-e620-4820-b5e3-f7d55c4bb1dc
0 commit comments