aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile173
-rw-r--r--assets/css/default-fast.css5
-rw-r--r--assets/css/default-mathml.css26
-rw-r--r--assets/css/default-simple.css79
-rw-r--r--assets/css/default-syntax.css (renamed from assets/css/syntax-highlight-default.css)92
-rw-r--r--assets/css/default.css2374
-rw-r--r--assets/data/media/logo.pngbin170667 -> 9839 bytes
-rw-r--r--assets/js/index.js1153
-rw-r--r--assets/schemas/atom-v1.0.rng605
-rw-r--r--assets/schemas/jsonfeed-v1.1.json297
-rw-r--r--assets/schemas/rss-v2.0.rng86
-rw-r--r--assets/schemas/rss-v2.0.xsd383
-rw-r--r--assets/schemas/sitemap-v0.9.xsd111
-rw-r--r--assets/schemas/sitemapindex-v0.9.xsd71
-rw-r--r--assets/templates/author.yaml15
-rw-r--r--assets/templates/markdown-feed.yaml19
-rw-r--r--config.json281
-rw-r--r--config.toml236
-rw-r--r--config.yaml224
-rw-r--r--content/canory/media/2city12p.pdfbin0 -> 1316140 bytes
-rw-r--r--content/canory/media/header.jpg (renamed from content/canory/media/profile/header.jpg)bin247768 -> 247768 bytes
-rw-r--r--content/canory/media/picture.png (renamed from content/canory/media/profile/picture.png)bin182233 -> 182233 bytes
-rw-r--r--content/canory/messages/animations.md18
-rw-r--r--content/canory/messages/cache.md3
-rw-r--r--content/canory/messages/code.md3
-rw-r--r--content/canory/messages/definitions.md5
-rw-r--r--content/canory/messages/diagrams.md15
-rw-r--r--content/canory/messages/disclosure.md32
-rw-r--r--content/canory/messages/drafts.md3
-rw-r--r--content/canory/messages/gates.md3
-rw-r--r--content/canory/messages/highlighting.md12
-rw-r--r--content/canory/messages/hugo.md3
-rw-r--r--content/canory/messages/imgur-video.md5
-rw-r--r--content/canory/messages/links.md (renamed from content/canory/messages/twitter.md)5
-rw-r--r--content/canory/messages/lists.md12
-rw-r--r--content/canory/messages/markdown.md5
-rw-r--r--content/canory/messages/math.md93
-rw-r--r--content/canory/messages/odysee.md3
-rw-r--r--content/canory/messages/pdf.md12
-rw-r--r--content/canory/messages/pinned.md9
-rw-r--r--content/canory/messages/plumbing.md3
-rw-r--r--content/canory/messages/self.md13
-rw-r--r--content/canory/messages/selfdestruct.md20
-rw-r--r--content/canory/messages/selfdestructed.md9
-rw-r--r--content/canory/messages/styles.md3
-rw-r--r--content/canory/messages/tables.md3
-rw-r--r--content/canory/messages/tasks.md3
-rw-r--r--content/canory/messages/unlisted.md7
-rw-r--r--content/canory/messages/unsafe.md6
-rw-r--r--content/canory/messages/videos.md3
-rw-r--r--content/canory/messages/wikipedia.md5
-rw-r--r--content/canory/messages/xkcd.md3
-rw-r--r--content/canory/messages/youtube.md3
-rw-r--r--content/default/media/header.jpg (renamed from content/default/media/profile/header.jpg)bin542296 -> 542296 bytes
-rw-r--r--content/default/media/picture.png (renamed from content/default/media/profile/picture.png)bin31774 -> 31774 bytes
-rw-r--r--content/default/messages/authors.md5
-rw-r--r--content/default/messages/create.md7
-rw-r--r--content/default/messages/quickstart.md14
-rw-r--r--data/authors/canory.yaml24
-rw-r--r--data/authors/default.yaml23
-rw-r--r--data/canory.yaml18
-rw-r--r--data/default.yaml18
-rw-r--r--shell.nix94
-rw-r--r--static/icons/feather/LICENSE4
-rw-r--r--static/icons/feather/alert-circle.svg37
-rw-r--r--static/icons/feather/archive.svg15
-rw-r--r--static/icons/feather/arrow-down-circle.svg23
-rw-r--r--static/icons/feather/arrow-left.svg29
-rw-r--r--static/icons/feather/arrow-right.svg29
-rw-r--r--static/icons/feather/arrow-up.svg29
-rw-r--r--static/icons/feather/at-sign.svg18
-rw-r--r--static/icons/feather/bookmark.svg14
-rw-r--r--static/icons/feather/calendar.svg34
-rw-r--r--static/icons/feather/circle.svg13
-rw-r--r--static/icons/feather/clock.svg28
-rw-r--r--static/icons/feather/copy.svg14
-rw-r--r--static/icons/feather/edit.svg16
-rw-r--r--static/icons/feather/external-link.svg21
-rw-r--r--static/icons/feather/eye-off.svg29
-rw-r--r--static/icons/feather/eye.svg18
-rw-r--r--static/icons/feather/file-text.svg28
-rw-r--r--static/icons/feather/git-commit.svg15
-rw-r--r--static/icons/feather/globe.svg34
-rw-r--r--static/icons/feather/heart.svg13
-rw-r--r--static/icons/feather/home.svg14
-rw-r--r--static/icons/feather/link.svg16
-rw-r--r--static/icons/feather/map-pin.svg28
-rw-r--r--static/icons/feather/refresh-cw.svg18
-rw-r--r--static/icons/feather/rss.svg15
-rw-r--r--static/icons/feather/search.svg31
-rw-r--r--static/icons/feather/tag.svg14
-rw-r--r--static/icons/feather/trash-2.svg38
-rw-r--r--static/icons/feather/user.svg14
-rw-r--r--static/icons/feather/users.svg16
-rw-r--r--static/icons/tabler/LICENSE2
-rw-r--r--static/icons/tabler/archive.svg22
-rw-r--r--static/icons/tabler/book-2.svg31
-rw-r--r--static/icons/tabler/circle.svg16
-rw-r--r--static/icons/tabler/clock.svg27
-rw-r--r--static/icons/tabler/code.svg22
-rw-r--r--static/icons/tabler/git-fork.svg28
-rw-r--r--static/icons/tabler/home.svg22
-rw-r--r--static/icons/tabler/notes.svg25
-rw-r--r--static/icons/tabler/pinned.svg31
-rw-r--r--static/icons/tabler/robot.svg40
-rw-r--r--static/icons/tabler/rss.svg22
-rw-r--r--static/icons/tabler/settings.svg19
-rw-r--r--static/icons/tabler/square-letter-m.svg19
-rw-r--r--static/icons/tabler/tag.svg19
-rw-r--r--static/icons/tabler/users.svg25
-rw-r--r--static/js/autoplay.ts42
-rw-r--r--static/js/codecopy.ts (renamed from static/js/code-copy.ts)9
-rw-r--r--static/js/contextmenu.ts28
-rw-r--r--static/js/domfilter.ts145
-rw-r--r--static/js/fixedsearch.ts241
-rw-r--r--static/js/forms.ts130
-rw-r--r--static/js/fuzzysort.js1101
-rw-r--r--static/js/hoverfix.ts64
-rw-r--r--static/js/index-bundle.ts18
-rw-r--r--static/js/index.ts9
-rw-r--r--static/js/infinitescroll.ts78
-rw-r--r--static/js/instantpage.ts330
-rw-r--r--static/js/pager.ts124
-rw-r--r--static/js/plumber.ts6
-rw-r--r--static/js/timeago.ts93
-rw-r--r--static/js/update.ts84
-rw-r--r--themes/default/layouts/_default/_markup/render-codeblock-mathml.html18
-rw-r--r--themes/default/layouts/_default/_markup/render-codeblock.html28
-rw-r--r--themes/default/layouts/_default/_markup/render-heading.html11
-rw-r--r--themes/default/layouts/_default/_markup/render-image.html145
-rw-r--r--themes/default/layouts/_default/_markup/render-link.html38
-rw-r--r--themes/default/layouts/_default/baseof.html47
-rw-r--r--themes/default/layouts/_default/baseof.json12
-rw-r--r--themes/default/layouts/_default/baseof.txt12
-rw-r--r--themes/default/layouts/_default/baseof.xml13
-rw-r--r--themes/default/layouts/_default/drafts.html54
-rw-r--r--themes/default/layouts/_default/feeds.html50
-rw-r--r--themes/default/layouts/_default/home.archive-messages.html48
-rw-r--r--themes/default/layouts/_default/home.archive-tags.html56
-rw-r--r--themes/default/layouts/_default/home.archives.html67
-rw-r--r--themes/default/layouts/_default/home.authors.html49
-rw-r--r--themes/default/layouts/_default/home.authors.section.html20
-rw-r--r--themes/default/layouts/_default/home.browserconfig.xml13
-rw-r--r--themes/default/layouts/_default/home.rss-style.xsl146
-rw-r--r--themes/default/layouts/_default/home.settings.html32
-rw-r--r--themes/default/layouts/_default/home.sources.html76
-rw-r--r--themes/default/layouts/_default/home.xslt.rss.xsl104
-rw-r--r--themes/default/layouts/_default/home.xslt.sitemap.xsl90
-rw-r--r--themes/default/layouts/_default/index.html34
-rw-r--r--themes/default/layouts/_default/index.json26
-rw-r--r--themes/default/layouts/_default/index.webmanifest24
-rw-r--r--themes/default/layouts/_default/likes.html54
-rw-r--r--themes/default/layouts/_default/list.html36
-rw-r--r--themes/default/layouts/_default/media.html68
-rw-r--r--themes/default/layouts/_default/rss.xml124
-rw-r--r--themes/default/layouts/_default/section.drafts.html58
-rw-r--r--themes/default/layouts/_default/section.feeds.html53
-rw-r--r--themes/default/layouts/_default/section.following.html75
-rw-r--r--themes/default/layouts/_default/section.gallery.html12
-rw-r--r--themes/default/layouts/_default/section.html74
-rw-r--r--themes/default/layouts/_default/section.marks.html58
-rw-r--r--themes/default/layouts/_default/section.media.html65
-rw-r--r--themes/default/layouts/_default/section.webring.html66
-rw-r--r--themes/default/layouts/_default/single.embed.html26
-rw-r--r--themes/default/layouts/_default/single.html105
-rw-r--r--themes/default/layouts/_default/single.plain.txt3
-rw-r--r--themes/default/layouts/_default/sitemap.xml66
-rw-r--r--themes/default/layouts/_default/summary.html55
-rw-r--r--themes/default/layouts/_default/taxonomy.html117
-rw-r--r--themes/default/layouts/_default/term.html47
-rw-r--r--themes/default/layouts/partials/archive-link.html2
-rw-r--r--themes/default/layouts/partials/author-card.html103
-rw-r--r--themes/default/layouts/partials/author-domain-host.html3
-rw-r--r--themes/default/layouts/partials/author-header.html42
-rw-r--r--themes/default/layouts/partials/author-list.html26
-rw-r--r--themes/default/layouts/partials/author-media-path.html2
-rw-r--r--themes/default/layouts/partials/author-name.html8
-rw-r--r--themes/default/layouts/partials/author-picture.html76
-rw-r--r--themes/default/layouts/partials/author-section-picture.html38
-rw-r--r--themes/default/layouts/partials/author-user.html8
-rw-r--r--themes/default/layouts/partials/card-id.html11
-rw-r--r--themes/default/layouts/partials/card-meta-header.html25
-rw-r--r--themes/default/layouts/partials/card-meta.html63
-rw-r--r--themes/default/layouts/partials/context-menu.html4
-rw-r--r--themes/default/layouts/partials/context-profile.html37
-rw-r--r--themes/default/layouts/partials/count-authors.html9
-rw-r--r--themes/default/layouts/partials/count-drafts.html13
-rw-r--r--themes/default/layouts/partials/count-feeds.html15
-rw-r--r--themes/default/layouts/partials/count-likes.html10
-rw-r--r--themes/default/layouts/partials/count-marks.html6
-rw-r--r--themes/default/layouts/partials/count-media.html33
-rw-r--r--themes/default/layouts/partials/count-tags.html2
-rw-r--r--themes/default/layouts/partials/count-total-messages.html2
-rw-r--r--themes/default/layouts/partials/count.html1
-rw-r--r--themes/default/layouts/partials/following-list.html31
-rw-r--r--themes/default/layouts/partials/footer.html16
-rw-r--r--themes/default/layouts/partials/function-authors-data.html9
-rw-r--r--themes/default/layouts/partials/function-authors-slice.html9
-rw-r--r--themes/default/layouts/partials/function-caches-images.html109
-rw-r--r--themes/default/layouts/partials/function-content.html23
-rw-r--r--themes/default/layouts/partials/function-favicon-domain.html11
-rw-r--r--themes/default/layouts/partials/function-fetch-favicons.html15
-rw-r--r--themes/default/layouts/partials/function-filters-content.html10
-rw-r--r--themes/default/layouts/partials/function-generate-feeds.html245
-rw-r--r--themes/default/layouts/partials/function-page-modified.html39
-rw-r--r--themes/default/layouts/partials/function-paths-markdown.html1
-rw-r--r--themes/default/layouts/partials/function-paths-media.html1
-rw-r--r--themes/default/layouts/partials/function-paths-static.html1
-rw-r--r--themes/default/layouts/partials/function-paths.html7
-rw-r--r--themes/default/layouts/partials/function-strip-filechars.html28
-rw-r--r--themes/default/layouts/partials/gallery-images.html9
-rw-r--r--themes/default/layouts/partials/gallery-walk.html138
-rw-r--r--themes/default/layouts/partials/gallery.html14
-rw-r--r--themes/default/layouts/partials/generate-authors.html50
-rw-r--r--themes/default/layouts/partials/generate-feeds.html278
-rw-r--r--themes/default/layouts/partials/head-canonical.html15
-rw-r--r--themes/default/layouts/partials/head-csp.html57
-rw-r--r--themes/default/layouts/partials/head-css.html26
-rw-r--r--themes/default/layouts/partials/head-description.html (renamed from themes/default/layouts/partials/site-description.html)2
-rw-r--r--themes/default/layouts/partials/head-discovery.html62
-rw-r--r--themes/default/layouts/partials/head-embed.html4
-rw-r--r--themes/default/layouts/partials/head-js.html8
-rw-r--r--themes/default/layouts/partials/head-manifest.html67
-rw-r--r--themes/default/layouts/partials/head-search.html14
-rw-r--r--themes/default/layouts/partials/head-title.html20
-rw-r--r--themes/default/layouts/partials/head.html93
-rw-r--r--themes/default/layouts/partials/image-gradient.css.html18
-rw-r--r--themes/default/layouts/partials/menu-datetime.html22
-rw-r--r--themes/default/layouts/partials/menu-embed.html8
-rw-r--r--themes/default/layouts/partials/menu-markdown.html13
-rw-r--r--themes/default/layouts/partials/menu-permalink.html11
-rw-r--r--themes/default/layouts/partials/menu-plain.html9
-rw-r--r--themes/default/layouts/partials/meta-anchored.html24
-rw-r--r--themes/default/layouts/partials/meta-date-time.html18
-rw-r--r--themes/default/layouts/partials/meta-datetime.html14
-rw-r--r--themes/default/layouts/partials/meta-draft.html16
-rw-r--r--themes/default/layouts/partials/meta-expiry-date.html11
-rw-r--r--themes/default/layouts/partials/meta-expirydate.html20
-rw-r--r--themes/default/layouts/partials/meta-handle.html36
-rw-r--r--themes/default/layouts/partials/meta-menu.html23
-rw-r--r--themes/default/layouts/partials/meta-name.html26
-rw-r--r--themes/default/layouts/partials/meta-read-time.html10
-rw-r--r--themes/default/layouts/partials/meta-readtime.html12
-rw-r--r--themes/default/layouts/partials/meta-source.html14
-rw-r--r--themes/default/layouts/partials/meta-title.html (renamed from themes/default/layouts/partials/title.html)0
-rw-r--r--themes/default/layouts/partials/meta-unlisted.html7
-rw-r--r--themes/default/layouts/partials/meta-via.html13
-rw-r--r--themes/default/layouts/partials/meta-view.html12
-rw-r--r--themes/default/layouts/partials/meta-word-count.html14
-rw-r--r--themes/default/layouts/partials/meta-wordcount.html33
-rw-r--r--themes/default/layouts/partials/navigator-left.html2
-rw-r--r--themes/default/layouts/partials/navigator-middle-walk.html15
-rw-r--r--themes/default/layouts/partials/navigator-middle.html84
-rw-r--r--themes/default/layouts/partials/navigator-right-default.html4
-rw-r--r--themes/default/layouts/partials/navigator-right.html10
-rw-r--r--themes/default/layouts/partials/navigator.css.html19
-rw-r--r--themes/default/layouts/partials/pagination.html117
-rw-r--r--themes/default/layouts/partials/profile-tabs.html55
-rw-r--r--themes/default/layouts/partials/profile.html46
-rw-r--r--themes/default/layouts/partials/render-embed.html31
-rw-r--r--themes/default/layouts/partials/site-title.html15
-rw-r--r--themes/default/layouts/partials/styles-navigator.html14
-rw-r--r--themes/default/layouts/partials/tags.html24
-rw-r--r--themes/default/layouts/partials/video-container.html64
-rw-r--r--themes/default/layouts/partials/web-ring.html1
-rw-r--r--themes/default/layouts/partials/webring.html15
-rw-r--r--themes/default/layouts/shortcodes/abbr.html7
-rw-r--r--themes/default/layouts/shortcodes/animate.html11
-rw-r--r--themes/default/layouts/shortcodes/animate.rss.xml5
-rw-r--r--themes/default/layouts/shortcodes/attach.html58
-rw-r--r--themes/default/layouts/shortcodes/disclose.html13
-rw-r--r--themes/default/layouts/shortcodes/footer.html7
-rw-r--r--themes/default/layouts/shortcodes/gist.html9
-rw-r--r--themes/default/layouts/shortcodes/imgur-video.html17
-rw-r--r--themes/default/layouts/shortcodes/imgur.html13
-rw-r--r--themes/default/layouts/shortcodes/kbd.html1
-rw-r--r--themes/default/layouts/shortcodes/link.html36
-rw-r--r--themes/default/layouts/shortcodes/mark.html16
-rw-r--r--themes/default/layouts/shortcodes/markdown.html2
-rw-r--r--themes/default/layouts/shortcodes/odysee.html3
-rw-r--r--themes/default/layouts/shortcodes/pdf.html11
-rw-r--r--themes/default/layouts/shortcodes/quote.html8
-rw-r--r--themes/default/layouts/shortcodes/react.html30
-rw-r--r--themes/default/layouts/shortcodes/react.rss.xml19
-rw-r--r--themes/default/layouts/shortcodes/reddit.html29
-rw-r--r--themes/default/layouts/shortcodes/self.html1
-rw-r--r--themes/default/layouts/shortcodes/spoiler.html14
-rw-r--r--themes/default/layouts/shortcodes/spoiler.rss.xml4
-rw-r--r--themes/default/layouts/shortcodes/tweet.html18
-rw-r--r--themes/default/layouts/shortcodes/version.html20
-rw-r--r--themes/default/layouts/shortcodes/video-ascii.html (renamed from themes/default/layouts/shortcodes/asciicast.html)0
-rw-r--r--themes/default/layouts/shortcodes/video-imgur.html14
-rw-r--r--themes/default/layouts/shortcodes/video.html50
-rw-r--r--themes/default/layouts/shortcodes/video.rss.xml29
-rw-r--r--themes/default/layouts/shortcodes/vimeo.html12
-rw-r--r--themes/default/layouts/shortcodes/wikipedia.html4
-rw-r--r--themes/default/layouts/shortcodes/youtube.html13
-rw-r--r--tsconfig.json1
299 files changed, 10993 insertions, 5003 deletions
diff --git a/.gitignore b/.gitignore
index 4077f0f..568cf1b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+.hugo_build.lock
+.local
icons
public
resources
+vendor
diff --git a/Makefile b/Makefile
index 09ce88e..e18c08d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,56 +1,141 @@
-all:
- make config
- make js
- make hugo
+help: # Show this help menu
+ @printf "\n%s\n\n" "$$(grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | column -s ':#' -t)"
-config:
+watch: # Watch and rebuild everything
+ while true; do git ls-files -cdmo --exclude-standard --exclude tests | entr -d -s 'make build'; done
+
+monitor: # Monitor for files changes
+ inotifywait --monitor --recursive --event modify .
+
+server: # Start server
+ caddy file-server --listen :9294 --root public
+
+build: # Build everything
+ make build-config
+ make build-js
+ make build-site
+
+build-sub: # Build everything into substitute directory
+ make build
+ mkdir public/m
+ mv public/* public/m || true
+
+build-config: # Build configuration files
yj -yj -i < config.yaml > config.json
yj -yt -i < config.yaml > config.toml
-watch:
- while true; do find . | entr -d -s 'make all'; done
-
-js:
- deno bundle --no-check --config tsconfig.json static/js/index.ts assets/js/index.js
+build-js: # Build js bundle
+ deno run --allow-all static/js/index-bundle.ts
-hugo:
+build-site: # Build site
rm -rf public
- hugo --templateMetrics && hugo --templateMetrics
+ hugo --logLevel debug --templateMetrics --templateMetricsHints
+ hugo --logLevel debug --templateMetrics --templateMetricsHints
rm -f .hugo_build.lock
-server:
- php -S 127.0.0.1:9294 -t public
+build-icons: # Build icons
+ rm -rf static/icons
+ mkdir -p static/icons/feather static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/LICENSE --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/alert-circle.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/arrow-down-circle.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/arrow-left.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/arrow-right.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/arrow-up.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/at-sign.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/calendar.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/clock.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/edit.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/external-link.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/eye-off.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/eye.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/file-text.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/globe.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/bookmark.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/link.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/map-pin.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/refresh-cw.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/search.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/feathericons/feather/master/icons/trash-2.svg --output-dir static/icons/feather
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/LICENSE --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/archive.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/book-2.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/circle.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/clock.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/code.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/git-fork.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/home.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/notes.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/pinned.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/robot.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/rss.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/settings.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/square-letter-m.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/tag.svg --output-dir static/icons/tabler
+ curl --silent --remote-name https://raw.githubusercontent.com/tabler/tabler-icons/master/icons/outline/users.svg --output-dir static/icons/tabler
+ for icon in static/icons/*/*.svg; do \
+ xmlstarlet c14n --without-comments $$icon | xmllint --output $$icon --pretty 2 -; \
+ sed --in-place '1d' $$icon; \
+ done
+ git add -f static/icons
+
+test: # Test everything
+ make test-html
+ make test-css
+ make test-xsl
+ make test-xml
+ make test-rss
+ make test-jsonfeed
-test:
- validatornu \
+test-html: # Test HTML
+ vnu \
+ --html \
+ --errors-only \
public/index.html \
public/default/index.html
-icons:
- rm -rf static/icons
- mkdir -p static/icons/feather static/icons/tabler
- svn export --force https://github.com/feathericons/feather/trunk/LICENSE static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/alert-circle.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/archive.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/arrow-left.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/arrow-right.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/arrow-up.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/circle.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/clock.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/copy.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/eye-off.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/git-commit.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/globe.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/tag.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/heart.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/home.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/map-pin.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/rss.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/search.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/trash-2.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/user.svg static/icons/feather
- svn export --force https://github.com/feathericons/feather/trunk/icons/users.svg static/icons/feather
- svn export --force https://github.com/tabler/tabler-icons/trunk/LICENSE static/icons/tabler
- svn export --force https://github.com/tabler/tabler-icons/trunk/icons/pinned.svg static/icons/tabler
- svn export --force https://github.com/tabler/tabler-icons/trunk/icons/book-2.svg static/icons/tabler
- svn export --force https://github.com/tabler/tabler-icons/trunk/icons/clock.svg static/icons/tabler
+test-html-indices: # Test HTML indices
+ find public/ -type f -name "index.html" -exec vnu --errors-only {} \;
+
+test-css: # Test CSS
+ vnu \
+ --css \
+ assets/css/default.css \
+ assets/css/default-fast.css \
+ assets/css/default-simple.css \
+ assets/css/default-syntax.css
+
+test-xsl: # Test XSL
+ xsltproc public/rss.xsl
+ xsltproc public/sitemap.xsl
+
+test-xml: # Test XML
+ xmllint --noout \
+ public/rss.xml \
+ public/sitemap.xml
+
+test-rss: # Test RSS
+ xmllint --noout --relaxng assets/schemas/rss-v2.0.rng public/rss.xml
+# xmllint --noout --schema assets/schemas/rss-v2.0.xsd public/rss.xml
+
+test-sitemap: # Test sitemap
+ xmllint --noout --schema assets/schemas/sitemap-v0.9.xsd public/sitemap.xml
+# xmllint --noout --schema assets/schemas/sitemapindex-v0.9.xsd public/sitemap.xml
+
+test-jsonfeed: # Test JSONFeed
+ check-jsonschema --schemafile assets/schemas/jsonfeed-v1.1.json public/index.json
+
+test-end: # Test front end
+ deno run --allow-all tests/index.ts
+
+test-bed: # Test bed run
+ deno run --allow-all tests/test.ts
+
+test-crawl: # Test link parity
+ deno run --allow-all tests/crawl.ts
+
+clean: # Clean everything
+ make clean-tests
+
+clean-tests: # Clean up tests
+ for file in /tmp/????????; do { [ -d "$$file/puppeteer_dev_chrome_profile-" ] && rm --recursive --force --verbose "$$file"; } || true; done
diff --git a/assets/css/default-fast.css b/assets/css/default-fast.css
new file mode 100644
index 0000000..8d9d4d1
--- /dev/null
+++ b/assets/css/default-fast.css
@@ -0,0 +1,5 @@
+@keyframes paint {
+ 0% {
+ opacity: 1;
+ }
+}
diff --git a/assets/css/default-mathml.css b/assets/css/default-mathml.css
new file mode 100644
index 0000000..4aa437a
--- /dev/null
+++ b/assets/css/default-mathml.css
@@ -0,0 +1,26 @@
+@namespace mathml url(http://www.w3.org/1998/Math/MathML);
+
+mathml|math {
+ display: block;
+ display: block math;
+}
+
+mathml|mtd {
+ display: flex;
+ justify-content: center;
+ padding-right: 0.4em;
+ padding-left: 0.4em;
+ padding-bottom: 0.5rem;
+ padding-top: 0.5rem;
+}
+
+@-moz-document url-prefix() {
+ mathml|mtd {
+ display: flex;
+ justify-content: center;
+ padding-right: 0.4em;
+ padding-left: 0.4em;
+ padding-bottom: 0.5ex;
+ padding-top: 0.5ex;
+ }
+}
diff --git a/assets/css/default-simple.css b/assets/css/default-simple.css
new file mode 100644
index 0000000..29f7c0d
--- /dev/null
+++ b/assets/css/default-simple.css
@@ -0,0 +1,79 @@
+column-base[position="left"],
+column-base[position="right"] {
+ opacity: 0.1;
+ transition: 2s;
+}
+
+column-base[position="left"]:hover,
+column-base[position="right"]:hover {
+ opacity: 0.9;
+ transition: 0.1s;
+}
+
+micro-card[id] > header,
+micro-card[id] article math-ml figcaption {
+ display: block;
+}
+
+micro-card[id] {
+ flex-direction: row;
+ padding: 1.25rem 1rem;
+}
+
+micro-card[id] > article {
+ margin: auto 0;
+ min-width: 0;
+}
+
+micro-card[id] > article > * {
+ width: 100%;
+}
+
+micro-card[id] > article > :nth-last-child(2) {
+ margin-bottom: 0;
+}
+
+micro-card[id] micro-tags,
+micro-card[id] > header meta-data,
+micro-card[id] > article figcaption,
+[data-kind="page"] micro-card[id]:first-child > a {
+ display: none;
+}
+
+micro-card[id]
+ > article
+ footer:not(blockquote footer):not(code-block + footer) {
+ display: none;
+}
+
+micro-card[id] > a {
+ display: inline;
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ z-index: 1;
+}
+
+micro-card[id] > a:focus {
+ background-color: transparent !important;
+ outline-offset: -0.15rem !important;
+}
+
+micro-card[id] article p,
+micro-card[id] article ul,
+micro-card[id] article dl,
+micro-card[id] article h1,
+micro-card[id] article h2,
+micro-card[id] article h3,
+micro-card[id] article video,
+micro-card[id] article iframe,
+micro-card[id] article article,
+micro-card[id] article details,
+micro-card[id] article figcaption,
+micro-card[id] header picture {
+ pointer-events: all;
+ position: relative;
+ z-index: 2;
+}
diff --git a/assets/css/syntax-highlight-default.css b/assets/css/default-syntax.css
index 0208323..e6f7021 100644
--- a/assets/css/syntax-highlight-default.css
+++ b/assets/css/default-syntax.css
@@ -1,63 +1,89 @@
-/* ----- Colors ----- */
-
/* ----- Format ----- */
.chroma .hl {
- display: block;
padding: 0 0.5rem;
margin: 0 -0.5rem;
}
+.chroma .line {
+ display: block;
+}
+
+.chroma .hl > .cl:before,
+.chroma .ln a:hover:before,
+.chroma .ln:target a:before,
+.chroma .line > .cl:hover:before {
+ content: "";
+ position: absolute;
+ height: 1.5rem;
+ width: 100%;
+ left: 0;
+ z-index: -1;
+}
+
.chroma .ln a {
- background-color: #edf2f7;
- padding: 0.25rem 0.75rem;
+ padding: 0.05rem 0.75rem;
margin: 0 1rem 0 -0.75rem;
user-select: none;
+ text-decoration: none;
+ display: inline-block;
}
-.chroma .ln a:hover {
+.chroma .ln a:hover,
+.chroma .ln:target a {
outline: 0.15rem solid !important;
outline-offset: -0.3rem;
}
+.chroma .line .cl:hover {
+ text-shadow: 0 0 currentColor;
+}
+
+.chroma .ln a:hover:before,
+.chroma .ln:target a:before,
+.chroma .line > .cl:hover:before {
+ background-color: #f2f2f2;
+}
+
+code-block code {
+ position: relative;
+}
+
code-block button {
border: 1px solid #ccc;
- display: none;
}
-.chroma .line:hover {
- background-color: #f2f2f2;
- display: block;
+code-block header language-label a,
+code-block header language-label a:hover {
+ color: #111;
}
/* ------ Tokens ------ */
:root {
- --code-chroma-background: #ffffff;
- --code-chroma-foreground: #333333;
- --code-chroma-error-background: #960050;
- --code-chroma-error-foreground: #960050;
- --code-chroma-label-background: #006894;
- --code-chroma-label-foreground: #e6e6e6;
- --code-chroma-line-highlight: #d9ddf2;
- --code-chroma-line-number: #375462;
- --code-chroma-line: var(--code-chroma-foreground);
-}
-
-/* ChromaForeground */ code-block, .chroma, .highlight { color: #333333; color: var(--code-chroma-foreground); }
-/* ChromaBackground */ code-block button, .chroma { background-color: #ffffff; background-color: var(--code-chroma-background); }
-/* ChromaErrorBackground */ .chroma .err { color: #960050; color: var(--code-chroma-error-background); }
-/* ChromaErrorForeground */ .chroma .err { color: #960050; color: var(--code-chroma-error-foreground); }
-/* ChromaLabelBackground */ .chroma code:before { background-color: #006894; background-color: var(--code-chroma-label-background); }
-/* ChromaLabelForeground */ .chroma code:before { color: #e6e6e6; color: var(--code-chroma-label-foreground); }
-/* ChromaLine */ .chroma .line { color: #333333; color: var(--code-chroma-line); }
-/* ChromaLineHighlight */ .chroma .hl { background-color: #d9ddf2; background-color: var(--code-chroma-line-highlight); }
-/* ChromaLineNumber */ .chroma .ln a { color: #375462 !important; color: var(--code-chroma-line-number) !important; }
-
-.chroma .hl {
- background-color: #fff8c5;
+--code-chroma-background: #ffffff;
+--code-chroma-foreground: #333333;
+--code-chroma-error-background: #960050;
+--code-chroma-error-foreground: #960050;
+--code-chroma-label-background: #006894;
+--code-chroma-label-foreground: #e6e6e6;
+--code-chroma-line-highlight: #fff8c5;
+--code-chroma-line-number: #375462;
+--code-chroma-line-number-background: #edf2f7;
+--code-chroma-line: var(--code-chroma-foreground);
}
+/* ChromaForeground */ code-block, .chroma, .highlight { color: #333333; color: var(--code-chroma-foreground); }
+/* ChromaBackground */ code-block button, .chroma { background-color: #ffffff; background-color: var(--code-chroma-background); }
+/* ChromaErrorBackground */ .chroma .err { color: #960050; color: var(--code-chroma-error-background); }
+/* ChromaErrorForeground */ .chroma .err { color: #960050; color: var(--code-chroma-error-foreground); }
+/* ChromaLabelBackground */ .chroma code:before { background-color: #006894; background-color: var(--code-chroma-label-background); }
+/* ChromaLabelForeground */ .chroma code:before { color: #e6e6e6; color: var(--code-chroma-label-foreground); }
+/* ChromaLine */ .chroma .line { color: #333333; color: var(--code-chroma-line); }
+/* ChromaLineHighlight */ .chroma .hl > span:before { background-color: #fff8c5; background-color: var(--code-chroma-line-highlight); }
+/* ChromaLineNumber */ .chroma .ln a { color: #375462 !important; color: var(--code-chroma-line-number) !important; }
+/* ChromaLineNumberBackground */ .chroma .ln a { background-color: #edf2f7; background-color: var(--code-chroma-line-number-background); }
+
:root {
--code-comment: #4f4f4f;
--code-comment-hashbang: var(--code-comment);
diff --git a/assets/css/default.css b/assets/css/default.css
index 157543d..0d670b5 100644
--- a/assets/css/default.css
+++ b/assets/css/default.css
@@ -20,79 +20,109 @@
text-shadow: 0 0 currentColor;
}
+@media (prefers-color-scheme: dark) {
+ ::selection {
+ color: #000;
+ background-color: #aaa;
+ text-shadow: 0 0 currentColor;
+ }
+
+ ::-webkit-selection {
+ color: #000;
+ background-color: #aaa;
+ text-shadow: 0 0 currentColor;
+ }
+
+ ::-moz-selection {
+ color: #000;
+ background-color: #aaa;
+ text-shadow: 0 0 currentColor;
+ }
+}
+
/* ----- Colors ----- */
:root {
- color-scheme: light dark;
- --active-background-alternate: #cce1ff;
- --background-bolder: #fff;
- --background-transparent: rgba(255, 255, 255, 0.9);
- --background: #fefefe;
- --border-darker: #ccc;
- --border-lighter: #eee;
- --button-background: #fff;
+ --primary: 230;
+ --secondary: 258;
+ --accent: 217;
+ --background-bolder: hsl(var(--secondary), 99%, 98%);
+ --background: hsl(var(--secondary), 99%, 99%);
+ --border-darker: hsl(var(--primary), 35%, 80%);
+ --border-darkest: hsl(var(--primary), 35%, 70%);
+ --border-lighter: hsl(var(--primary), 35%, 92%);
+ --button-background: hsl(var(--primary), 0%, 100%);
--danger-background-lighter: #fff5f5;
--danger-background: #fcd2cf;
--danger: #8f0000;
- --disabled: #999;
- --fade: #555;
- --focus-within-background: #f0ecf9;
- --foreground: #111;
- --hover-background-alternate: #ebf3ff;
- --hover-background: #eee;
- --input-background: #eff3f4;
- --link: #0149bc;
- --shadow: #999;
- --spoiler: #333;
+ --fade: hsl(var(--primary), 35%, 30%);
+ --focus-within-background: hsl(var(--secondary), 52%, 95%);
+ --foreground: hsl(var(--primary), 99%, 5%);
+ --hover-background-alternate: hsl(var(--accent), 100%, 96%);
+ --hover-background: hsl(var(--secondary), 25%, 94%);
+ --icon-focus-background: var(--icon-hover-background);
+ --icon-hover-background: hsl(var(--accent), 100%, 90%);
+ --link: hsl(var(--accent), 99%, 37%);
+ --shadow: #00000060;
+ --spoiler: hsl(var(--primary), 0%, 27%);
--success-background: #d5f3c4;
--success: #1d3c0c;
- --table-row-even-background: #f9f9f9;
- --table-row-odd-background: #f3f3f3;
+ --table-even-background: hsl(var(--secondary), 25%, 99%);
+ --table-odd-background: hsl(var(--secondary), 25%, 97%);
+ --text-background: var(--background);
--warning-background: #ffe699;
--warning: #332600;
- --widget-background: #f9f9f9;
+ --widget-background: hsl(var(--secondary), 25%, 97%);
+ color-scheme: light;
}
@media (prefers-color-scheme: dark) {
:root {
- --active-background-alternate: #425a8a;
- --background-bolder: #0d0d0d;
- --background-transparent: rgba(28, 28, 28, 0.9);
- --background: #111;
- --border-darker: #555;
- --border-lighter: #262626;
- --button-background: #333;
- --danger-background-lighter: #1b0404;
+ --primary: 0;
+ --secondary: 0;
+ --accent: 219;
+ --background-bolder: hsl(var(--secondary), 0%, 5%);
+ --background: hsl(var(--secondary), 0%, 7%);
+ --border-darker: hsl(var(--secondary), 0%, 33%);
+ --border-darkest: hsl(var(--secondary), 0%, 60%);
+ --border-lighter: hsl(var(--secondary), 0%, 15%);
+ --button-background: hsl(var(--secondary), 0%, 20%);
+ --danger-background-lighter: #261717;
--danger-background: #4f1c1c;
--danger: #ff9494;
- --disabled: #999;
- --fade: #aaa;
+ --fade: hsl(var(--secondary), 0%, 66%);
--focus-within-background: #291933;
- --foreground: #ddd;
+ --foreground: hsl(var(--secondary), 0%, 87%);
--hover-background-alternate: #1c263a;
- --hover-background: #303030;
- --input-background: #333;
- --link: #a3c3ff;
- --shadow: #000;
- --spoiler: #aaa;
+ --hover-background: hsl(var(--secondary), 0%, 14%);
+ --icon-focus-background: #88aefb;
+ --icon-hover-background: hsl(var(--accent), 35%, 25%);
+ --link: hsl(var(--accent), 100%, 82%);
+ --shadow: hsl(var(--secondary), 0%, 0%);
+ --spoiler: hsl(var(--secondary), 0%, 67%);
--success-background: #2d3e0f;
--success: #d5f3c4;
- --table-row-even-background: #273030;
- --table-row-odd-background: #2e3838;
+ --table-even-background: hsl(var(--secondary), 0%, 12%);
+ --table-odd-background: hsl(var(--secondary), 0%, 9%);
+ --text-background: hsl(var(--secondary), 0%, 17%);
--warning-background: #a89700;
--warning: #000;
- --widget-background: #171717;
+ --widget-background: hsl(var(--secondary), 0%, 9%);
+ color-scheme: dark;
}
- img {
+ kbd,
+ img,
+ video,
+ figure span {
filter: brightness(75%);
}
- code-block {
+ code-block pre,
+ code-block header {
filter: invert(90%);
- display: block;
}
}
-/* ----- Psuedo ----- */
+/* ----- Pseudo ----- */
*,
::before,
@@ -106,37 +136,52 @@
vertical-align: inherit;
}
-:target::before {
- content: "";
- display: block;
- height: 4rem;
- margin-top: -4rem;
- visibility: hidden;
+html,
+:target:not(nav span) {
+ scroll-margin-top: 6rem;
}
-:not(#main):target micro-summary,
-:not(#main):target micro-summary:hover {
- background-color: transparent;
+sup:target [role="doc-noteref"][href^="#fn\:"],
+li:target [role="doc-backlink"][href^="#fnref\:"],
+:focus:not(html):not(body):not(svg):not(pre):not(#search) {
+ outline: 0.15rem solid;
+ outline-offset: 0.05rem;
+ text-decoration: none;
border-radius: 0.5rem;
- outline-offset: -6px;
- outline: 2px dashed #ccc;
- outline: 2px dashed var(--border-darker);
}
-:focus:not(html):not(body):not(svg) {
+sup:target [role="doc-noteref"][href^="#fn\:"],
+li:target [role="doc-backlink"][href^="#fnref\:"] {
+ outline-offset: 1px;
+}
+
+nav a:focus,
+button:focus,
+menu a:focus,
+code-block a:focus,
+gallery-images a:focus {
+ outline-offset: -0.2rem !important;
+}
+
+pre:hover,
+pre:focus,
+pre:focus-within {
outline: 0.15rem solid;
- outline-offset: -0.15rem;
text-decoration: none;
}
-:focus:not(html):not(body):not(pre):not(svg):not(button):not(input) {
- background-color: #ffe699;
- background-color: var(--warning-background);
- color: #111;
- color: var(--warning);
+sup:target [role="doc-noteref"][href^="#fn\:"],
+li:target [role="doc-backlink"][href^="#fnref\:"],
+:focus:not(html):not(body):not(pre):not(svg):not(button):not(input):not(video) {
+ background-color: #ffe699 !important;
+ background-color: var(--warning-background) !important;
+ color: #111 !important;
+ color: var(--warning) !important;
}
-:hover:not(a):not(s):not(img):not(summary):not(nav):not(abbr):not(form):not(code):not(mark) {
+:hover:not(a):not(s):not(span):not(img):not(summary):not(nav):not(abbr):not(
+ form
+ ):not(code):not(mark):not(td):not(nav):not(p):not(object):not(tab-bar) {
border-radius: 0.5rem;
}
@@ -157,6 +202,292 @@ skip-link a:focus {
border-radius: 0.5rem;
}
+/* ----- Typography ----- */
+
+h1,
+h2,
+h3 {
+ font-size: 100%;
+ margin: 0;
+}
+
+math {
+ font-family: "CMU Serif", serif;
+ font-size: 110%;
+}
+
+micro-card[id] article h1,
+micro-card[id] article h2,
+micro-card[id] article h3 {
+ font-family: Charter, Georgia, "Book Antiqua", serif;
+ font-size: 125%;
+ font-weight: 700;
+}
+
+micro-card[id] article h2,
+micro-card[id] article h3 {
+ font-size: 115%;
+}
+
+micro-card[id] article h3 {
+ font-style: italic;
+}
+
+html,
+samp,
+blockquote span {
+ font-family: "Noto Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans",
+ "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
+ "Segoe UI Symbol";
+}
+
+pre,
+kbd,
+code,
+svg text,
+following-list details summary:after,
+micro-card article details[data-disclosure] summary:after {
+ font-size: 0.95rem;
+ font-family: "Fira Code", "Lucida Console", "Andale Mono", "Roboto Mono",
+ "Ubuntu Monospace", "Noto Mono", "Oxygen Mono", "Liberation Mono", monospace,
+ "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+}
+
+p:not(:last-child),
+ol:not(:last-child),
+ul:not(:last-child),
+dl:not(:last-child),
+table:not(:last-child),
+figure:not(:last-child),
+code-block:not(:last-child),
+blockquote:not(:last-child),
+article > mark[id]:not(:last-child) {
+ margin-bottom: 0.75rem;
+}
+
+dd {
+ margin: 0;
+}
+
+dl {
+ margin: 0 0 0 1rem;
+}
+
+dt {
+ font-weight: 700;
+}
+
+dt:not(:first-child) {
+ margin-top: 0.5rem;
+}
+
+footer,
+figcaption {
+ color: #444;
+ color: var(--fade);
+ font-size: 85%;
+ margin: 0.5rem 0;
+ text-align: center;
+}
+
+sup,
+sub {
+ display: inline-block;
+ vertical-align: bottom;
+}
+
+sup {
+ vertical-align: text-top;
+ font-size: 85%;
+}
+
+sub {
+ font-size: 85%;
+}
+
+article > mark[id] {
+ display: block;
+}
+
+mark:target a {
+ color: inherit;
+ text-decoration-thickness: 2px;
+}
+
+mark[id] {
+ background: none;
+ color: inherit;
+}
+
+mark,
+mark:target span {
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ #ffe699 10%,
+ #ffe699 90%,
+ transparent 90%
+ );
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ var(--warning-background) 10%,
+ var(--warning-background) 90%,
+ transparent 90%
+ );
+ color: #000;
+}
+
+ins {
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ #d5f3c4 10%,
+ #d5f3c4 90%,
+ transparent 90%
+ );
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ var(--success-background) 10%,
+ var(--success-background) 90%,
+ transparent 90%
+ );
+ color: #1d3c0c;
+ color: var(--success);
+ text-decoration: none;
+}
+
+del {
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ #fcd2cf 10%,
+ #fcd2cf 90%,
+ transparent 90%
+ );
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ var(--danger-background) 10%,
+ var(--danger-background) 90%,
+ transparent 90%
+ );
+ color: #8f0000;
+ color: var(--danger);
+}
+
+s {
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ #444 10%,
+ #444 90%,
+ transparent 90%
+ );
+ background: linear-gradient(
+ to bottom,
+ transparent 10%,
+ var(--spoiler) 10%,
+ var(--spoiler) 90%,
+ transparent 90%
+ );
+ color: transparent;
+ text-decoration: none;
+}
+
+input[type="checkbox"]:checked + s {
+ background: inherit;
+ color: inherit;
+}
+
+input[type="checkbox"] {
+ -webkit-appearance: none;
+ appearance: none;
+ background-color: transparent;
+ border-radius: 25%;
+ border: 1px solid;
+ border-color: inherit;
+ height: 1.25rem;
+ margin: 0 0.25rem;
+ vertical-align: middle;
+ vertical-align: text-bottom;
+ width: 1.25rem;
+}
+
+input[type="checkbox"]:checked {
+ color: inherit;
+}
+
+input[type="checkbox"]:checked:after {
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-width: 0.4rem;
+ content: "";
+ display: block;
+ height: 100%;
+ margin: auto;
+ transform: scale(0.5, -0.5) rotateZ(145deg);
+ width: 70%;
+}
+
+blockquote {
+ color: #444;
+ color: var(--fade);
+ margin: 0;
+}
+
+blockquote p,
+blockquote p:not(:last-child) {
+ padding-left: 1rem;
+ margin: 0 0 0 1rem;
+ border-left: 2px solid;
+ border-color: #eee;
+ border-color: var(--border-darker);
+}
+
+blockquote footer {
+ text-align: right;
+ font-size: 100%;
+}
+
+video {
+ width: 100%;
+ color: #000;
+ border-radius: 0.5rem;
+ background-color: #000;
+ vertical-align: middle;
+ box-shadow: 0 0 3px #00000060;
+ box-shadow: 0 0 3px var(--shadow);
+}
+
+video[data-orientation="portrait"] {
+ width: 50%;
+}
+
+video:focus {
+ filter: brightness(100%);
+}
+
+video-container {
+ display: block;
+ text-align: center;
+}
+
+kbd {
+ background-color: #fff;
+ border-radius: 0.25rem;
+ border: 1px solid #bbb;
+ color: #333;
+ display: inline-block;
+ font-size: 0.85em;
+ font-weight: 700;
+ line-height: 1;
+ padding: 0.1rem 0.25rem;
+ white-space: nowrap;
+}
+
/* ----- Elements ----- */
html {
@@ -168,70 +499,76 @@ html {
margin-right: 0;
}
-html,
-samp {
- font-family: "Noto Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
- Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans",
- "Helvetica Neue", sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
- "Segoe UI Symbol";
-}
-
-body,
-dl dl,
-dl ol,
-dl ul,
-ol dl,
-ul dl,
-ol ol,
-ol ul,
-ul ol,
-ul ul,
button,
-input,
-select,
textarea {
margin: 0;
}
ol {
- counter-reset: ol;
padding-left: 3.5rem;
+ list-style: none;
+ margin: 0;
}
ol li {
overflow-wrap: break-word;
word-break: break-word;
- list-style: none;
+ position: relative;
+ min-height: 1rem;
+}
+
+ol li + li {
+ margin-top: 0.5rem;
}
ol li:before {
- border-radius: 100%;
+ border-radius: 0.5rem;
border: 1px solid;
- content: counter(ol);
- counter-increment: ol;
- margin-left: -2rem;
+ border-color: #111;
+ border-color: var(--foreground);
font-size: 85%;
- padding: 0 0.35rem;
+ font-weight: 700;
+ opacity: 0.85;
+ padding: 0 0.5rem;
position: absolute;
+ right: 0;
+ margin-right: 100%;
+ margin-left: -100%;
+ font-variant-numeric: tabular-nums lining-nums slashed-zero;
+ height: 100%;
+ max-height: 1.5rem;
+ display: flex;
+ align-items: center;
}
-ol li + li {
- margin-top: 0.5rem;
+ol:not([start]) {
+ counter-reset: ol;
}
-main {
- min-height: 100%;
+ol:not([start]) li:before {
+ content: counter(ol);
+ counter-increment: ol;
+}
+
+ol[start] li:before {
+ content: counter(list-item);
}
-main,
details,
+summary,
code-block,
+figure span,
diagram-container {
display: block;
}
-summary {
- display: list-item;
+main {
+ display: block;
+ min-height: 80vh;
+}
+
+summary::-webkit-details-marker {
+ display: none;
}
cite {
@@ -239,13 +576,13 @@ cite {
}
ul {
- list-style: disc;
- padding-left: 2rem;
+ list-style: none;
+ padding-left: 0;
+ margin: 0;
}
nav ol,
nav ul {
- list-style: none;
display: inline-block;
padding: 0;
}
@@ -267,22 +604,16 @@ q:after {
content: "\201D";
}
-object {
- width: 100%;
- border: 1px solid #ccc;
- border: 1px solid var(--border-lighter);
- min-height: 16rem;
- border-radius: 0.5rem;
+pre code {
+ white-space: pre-line;
}
-details {
+summary,
+abbr[title] label,
+menu label {
cursor: pointer;
}
-details:hover summary span {
- text-decoration: underline;
-}
-
a {
color: #0149bc;
color: var(--link);
@@ -293,24 +624,46 @@ a {
a:hover {
color: #111;
color: var(--foreground);
+}
+
+a:hover,
+menu:hover span,
+meta-view a:hover span,
+meta-draft a:hover span,
+meta-handle a:hover span {
text-decoration-thickness: 0.15rem !important;
+ text-decoration-color: inherit !important;
}
-a:hover img {
- box-shadow: 0 0 14px #999;
- box-shadow: 0 0 14px var(--shadow);
- filter: unset;
+a[data-internal] {
+ text-decoration-color: #aaa;
+ text-decoration-thickness: 0.15rem;
}
-column-left nav {
+document-attachment object {
+ width: 100%;
+ border: 2px solid #ccc;
+ border: 2px solid var(--border-darker);
+ min-height: 16rem;
+ border-radius: 0.5rem;
+ display: flex;
+ align-items: center;
+ text-align: center;
+}
+
+document-attachment object p {
+ margin: 1rem;
+}
+
+column-base[position="left"] nav {
position: sticky;
position: -webkit-sticky;
- align-self: flex-start;
top: 0.5rem;
text-align: right;
+ font-size: 100%;
}
-column-left nav a {
+column-base[position="left"] nav a {
align-items: center;
color: inherit;
color: var(--foreground);
@@ -322,32 +675,34 @@ column-left nav a {
border-radius: 0.5rem;
}
-column-left nav li {
+column-base[position="left"] nav li {
margin-bottom: 0.25rem;
}
-column-left nav li:hover a {
+column-base[position="left"] nav li:hover a {
background-color: #eee;
background-color: var(--hover-background);
border-radius: 0.5rem;
}
-column-left nav li:hover svg {
+column-base[position="left"] nav a:hover svg {
+ fill: #cce0ff;
+ fill: var(--icon-hover-background);
+ stroke-width: 0.1rem;
+}
+
+column-base[position="left"] nav a:focus svg {
fill: #cce1ff;
- fill: var(--active-background-alternate);
+ fill: var(--icon-focus-background);
}
-column-left nav a span {
+column-base[position="left"] nav a span {
padding: 0 1rem;
}
-pre,
-kbd,
-code,
-svg text {
- font-family: "Fira Code", "Lucida Console", "Andale Mono", "Roboto Mono",
- "Ubuntu Monospace", "Noto Mono", "Oxygen Mono", "Liberation Mono", monospace,
- "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+column-base[position="left"] nav a svg {
+ height: 1.5em;
+ width: 1.5em;
}
abbr[title] {
@@ -359,10 +714,18 @@ abbr[title]:hover {
border-bottom: 2px dashed;
}
-[type="checkbox"]:checked ~ abbr[title]::after {
+input[type="checkbox"]:checked ~ abbr[title]::after {
content: " (" attr(title) ")";
}
+input[type="checkbox"]:checked ~ input[type="checkbox"] ~ abbr[title] {
+ cursor: text;
+}
+
+input[type="checkbox"]:checked ~ input[type="checkbox"] ~ abbr[title] label {
+ pointer-events: none;
+}
+
samp {
font-variant: all-small-caps;
letter-spacing: 0.05rem;
@@ -378,35 +741,35 @@ small {
opacity: 0.85;
}
-audio,
-canvas,
-iframe,
-img,
-svg,
-video {
+canvas {
vertical-align: middle;
}
-video,
audio {
width: 100%;
-}
-
-audio {
margin: 0.75rem 0;
+ vertical-align: middle;
}
figure {
text-align: center;
+ margin: 0;
+}
+
+figure object {
+ pointer-events: none;
}
iframe {
- width: 100%;
+ width: 1px;
+ min-width: 100%;
border: 2px solid #ccc;
border: 2px solid var(--border-darker);
background-color: #fefefe;
- border-radius: 0.5rem !important;
+ border-radius: 0.5rem;
min-height: 16rem;
+ user-select: none;
+ vertical-align: middle;
}
self-embed iframe {
@@ -414,27 +777,39 @@ self-embed iframe {
max-height: 11rem;
}
-img {
+img,
+figure object {
height: auto;
max-width: 100%;
- border: 1px solid #ccc;
- border: 1px solid var(--border-darker);
+ border-width: 1px;
+ border-style: solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
border-radius: 0.5rem;
object-fit: cover;
display: block;
+ display: flex;
+ justify-content: center;
+ align-items: center;
background-color: #fefefe;
+ user-select: none;
+ vertical-align: middle;
}
-img,
-iframe {
- user-select: none;
+img:hover,
+video:hover,
+figure span:hover {
+ box-shadow: 0 0 14px #00000060;
+ box-shadow: 0 0 14px var(--shadow);
+ filter: brightness(90%);
}
p {
- line-height: 1.35;
+ margin: 0;
}
svg {
+ vertical-align: middle;
stroke-width: 0.08rem;
}
@@ -446,31 +821,35 @@ svg:not(:root) {
overflow: hidden;
}
-button,
input {
+ margin: 0;
overflow: visible;
}
-button,
select {
text-transform: none;
+ margin: 0;
}
button,
+summary:after,
[type="reset"],
[type="button"],
[type="submit"],
micro-tags a,
-paginator-navigation a,
-micro-author micro-summary > a {
+nav[data-type="pagination"] a,
+micro-author micro-card > a {
align-items: center;
- appearance: button;
+ appearance: none;
background-color: #fff;
background-color: var(--button-background);
+ border: 1px solid;
border-radius: 0.5rem;
- border: 1px solid #ccc;
- border: 1px solid var(--border-lighter);
- box-shadow: 0 1px 1px #999;
+ border-color: #eee;
+ border-color: var(--border-darker);
+ border-top-color: var(--border-lighter);
+ border-left-color: var(--border-lighter);
+ border-right-color: var(--border-lighter);
color: inherit;
cursor: pointer;
display: flex;
@@ -478,16 +857,43 @@ micro-author micro-summary > a {
height: 1.95rem;
padding: 0.125rem 0.5rem;
text-decoration: none;
+ text-transform: none;
+ overflow: visible;
+}
+
+button:hover,
+[type="reset"]:hover,
+[type="button"]:hover,
+[type="submit"]:hover,
+micro-tags a:hover,
+nav[data-type="pagination"] a:hover,
+micro-author micro-card > a:hover {
+ border: 1px solid;
+ border-color: #aaa;
+ border-color: var(--border-darkest);
}
button svg,
-micro-author micro-summary > a svg {
+micro-author micro-card a svg,
+nav[data-type="pagination"] a svg {
height: 1.25rem;
- margin: 0 0.25rem;
+ width: 1.25rem;
+}
+
+micro-author a svg ~ span,
+micro-author a span ~ svg,
+nav[data-type="pagination"] a svg ~ span,
+nav[data-type="pagination"] a span ~ svg {
+ margin-left: 0.25rem;
}
hr {
+ border: 0;
border-top: 1px solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
+ opacity: 0.4;
+ margin: 0.5rem 0;
}
/* ----- Tables ----- */
@@ -497,7 +903,6 @@ table {
border-spacing: 0;
border: 1px solid #ccc;
border: 1px solid var(--border-darker);
- padding: 0.5rem 0 0 0;
width: 100%;
background-color: #fefefe;
background-color: var(--background);
@@ -506,20 +911,19 @@ table {
th {
border-bottom: 1px solid #ccc;
border-bottom: 1px solid var(--border-darker);
- padding: 0 0.5rem 0.5rem 0.5rem;
- text-align: left;
}
+th,
td {
- padding: 0.5rem 0 0.5rem 0.5rem;
border-right: 1px solid #ccc;
border-right: 1px solid var(--border-darker);
border-bottom: 1px solid #ccc;
border-bottom: 1px solid var(--border-darker);
+ padding: 0.5rem 1rem;
}
-td:last-child {
- padding-right: 0.5rem;
+td:last-child,
+th:last-child {
border-right: none;
}
@@ -529,12 +933,12 @@ tr:last-child td {
tbody tr:nth-child(odd) td {
background-color: #f3f3f3;
- background-color: var(--table-row-odd-background);
+ background-color: var(--table-odd-background);
}
tbody tr:nth-child(even) td {
background-color: #f9f9f9;
- background-color: var(--table-row-even-background);
+ background-color: var(--table-even-background);
}
tbody tr:hover td {
@@ -552,6 +956,10 @@ tr:last-child td:last-child {
/* ----- Print ----- */
+article a[href*="pdf"]::after {
+ content: " [pdf]";
+}
+
@media print {
a[href^="http"]::after {
content: " (" attr(href) ")";
@@ -569,48 +977,52 @@ body {
background-color: var(--background);
color: #111;
color: var(--foreground);
- display: flex;
- margin: 0 auto;
- max-width: 1250px;
+ margin: 0;
+ max-width: 600px;
min-height: 100%;
overflow-x: hidden;
-webkit-text-size-adjust: none;
}
-column-left {
+html[data-document="html"] body,
+html[data-document="xhtml"] body {
display: flex;
- flex: 1;
- justify-content: flex-end;
+ margin: 0 auto;
+ max-width: 1250px;
+}
+
+column-base[position="left"] {
+ width: 14.25%;
}
-column-right {
- flex: 2;
- max-width: 400px;
+column-base[position="right"] {
+ width: 28%;
}
-column-left,
-column-right {
+column-base[position="left"],
+column-base[position="right"] {
margin: 0.5rem 2rem;
}
-column-middle {
- flex: 6;
+column-base[position="middle"] {
max-width: 600px;
min-height: 100vh;
width: 100%;
+ height: fit-content;
}
micro-card,
micro-tags,
-micro-expires,
-micro-article {
+profile-box {
display: block;
}
-message-archive h1 {
+source-files h1,
+archive-list h1 {
text-align: center;
font-weight: 400;
font-size: 150%;
+ font-variant: all-small-caps;
}
micro-tags {
@@ -625,53 +1037,90 @@ micro-tags a {
margin: 0 0.25rem 0.5rem 0;
}
-micro-summary,
-micro-article {
+micro-card {
border-bottom: 1px solid;
border-color: #eee;
border-color: var(--border-lighter);
display: flex;
+ flex-direction: column;
padding: 1rem;
position: relative;
}
-micro-summary:hover {
+micro-card > a {
+ display: none;
+}
+
+micro-card:target {
+ border-radius: 0.5rem;
+ outline-offset: -6px;
+ outline: 2px dashed #ccc;
+ outline: 2px dashed var(--border-darker);
+}
+
+micro-card:hover {
background-color: #f5f9ff;
background-color: var(--hover-background-alternate);
}
-micro-summary:focus-within {
+micro-card:focus-within {
background-color: #f0ecf9;
background-color: var(--focus-within-background);
}
-micro-author micro-summary {
+micro-author micro-card {
+ flex-direction: row;
justify-content: start;
align-items: center;
border: none;
}
-micro-author micro-thumbnail {
- flex: none;
+micro-author micro-card header,
+micro-author micro-card > a,
+micro-author micro-card > article,
+micro-author micro-card > p:not(:last-child) {
+ margin: 0 0.5rem;
}
-micro-author micro-header {
- line-height: 1;
- margin: 0 1.25rem 0 0.5rem;
+micro-author micro-card p:not(:last-child) {
+ flex: 1.75;
+ color: #444;
+ color: var(--fade);
+ max-width: 20rem;
+}
+
+micro-author article {
flex: 1;
- height: 3rem;
- padding: 0 0.5rem;
+ min-width: 3rem;
}
-micro-thumbnail a {
- display: block;
+micro-author article h2 {
+ line-height: 1.25;
+}
+
+micro-author article h3 {
+ font-weight: 400;
+}
+
+micro-author micro-card header figure:first-child {
+ margin: 0;
}
-micro-thumbnail figure {
+micro-card header figure:first-child {
margin: 0 0.75rem 0 0;
}
-micro-thumbnail figure img {
+micro-card header figure > a,
+micro-card header figure > a:hover {
+ color: #000;
+ display: block;
+ text-decoration: none;
+}
+
+tag-card figure img,
+micro-card header figure img,
+micro-card header figure span,
+micro-card header figure object {
border-radius: 100%;
min-width: 3.5rem;
min-height: 3.5rem;
@@ -679,111 +1128,214 @@ micro-thumbnail figure img {
max-height: 3.5rem;
}
-micro-content {
- flex: 8;
- width: 0;
+micro-card > article {
+ margin-left: 4.25rem;
+}
+
+micro-card article ul {
+ list-style-type: "\2012";
+ padding-left: 2rem;
+}
+
+micro-card article li {
+ padding-left: 0.5rem;
+}
+
+micro-card article li::marker {
+ opacity: 0.85;
}
-micro-content > figure img {
+micro-card article ul li + li {
+ margin-top: 0.25rem;
+}
+
+micro-card article figure img {
border: none;
margin: 0 auto;
+ box-shadow: 0 0 3px #00000060;
+ box-shadow: 0 0 3px var(--shadow);
}
-micro-content > figure > a {
- background-color: #000;
+micro-card article figure img:before {
+ background-color: #fefefe;
+ background-color: var(--background);
+ border-radius: 0.5rem;
+ box-shadow: 0 1px 6px #00000060;
+ box-shadow: 0 1px 6px var(--shadow);
+ color: #111;
+ color: var(--foreground);
+ padding: 0.5rem 0.75rem;
+ margin: 1rem;
+}
+
+micro-card article figure > a {
border-radius: 0.5rem;
+ display: inline-block;
+}
+
+micro-card article figure > a[data-orientation="landscape"] {
display: block;
}
-micro-metadata {
- align-items: center;
+micro-card article figure > a[data-orientation="landscape"] img {
+ width: 100%;
+}
+
+micro-card header {
color: #444;
color: var(--fade);
display: flex;
- line-height: 1.25;
- margin-bottom: 0.5rem;
+ align-items: center;
+ margin-bottom: 0.25rem;
}
-micro-metadata h2 {
+micro-card header h2 {
display: inline;
}
-micro-metadata section a {
+micro-card header meta-data {
+ word-break: break-all;
+ word-break: break-word;
+}
+
+micro-card header meta-data a {
color: inherit;
}
-micro-metadata expiry-date,
-micro-metadata word-limit em,
-micro-metadata draft-label em {
+micro-card header meta-data > *:not(:last-child) {
+ margin-right: 0.5rem;
+}
+
+micro-card header meta-data > *:hover {
+ color: #111;
+ color: var(--foreground);
+}
+
+meta-expiry,
+meta-draft em,
+meta-wordcount word-limit em {
color: #8f0000;
color: var(--danger);
font-style: normal;
}
-micro-metadata draft-label em {
+meta-draft em {
font-variant: all-small-caps;
}
-micro-header footer svg,
-micro-metadata expiry-date svg,
-micro-metadata anchored-entry svg,
-micro-metadata unlisted-entry svg {
+profile-box footer svg,
+micro-card header meta-data svg {
height: 1rem;
width: 1rem;
- stroke-width: 0.1rem;
+ stroke-width: 0.105rem;
}
-micro-metadata unlisted-entry {
+meta-unlisted {
font-variant: all-small-caps;
}
s label,
abbr[title],
-abbr[title] label,
-micro-metadata read-time,
-micro-metadata word-limit,
-micro-metadata expiry-date,
-micro-metadata unlisted-entry {
+meta-expiry,
+meta-readtime,
+meta-datetime,
+meta-unlisted,
+meta-wordcount {
cursor: help;
}
-anchored-entry {
+meta-anchored {
display: flex;
- align-items: center;
margin-bottom: 0.25rem;
- margin-top: -0.5rem;
+ width: 100%;
}
-anchored-entry svg {
+meta-anchored > * {
+ margin-right: 0.5rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ text-decoration: none;
+}
+
+meta-anchored svg {
margin-right: 0.25rem;
}
-anchored-entry span {
+meta-anchored a[data-anchored="pinned"] svg {
+ fill: #9ed1fa;
+}
+
+meta-anchored a[data-anchored="marked"] svg {
+ fill: #cd5c5c;
+}
+
+menu {
+ display: inline-block;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ position: relative;
+}
+
+menu context-menu {
+ min-width: 10rem;
+}
+
+menu context-menu svg {
margin-right: 0.25rem;
}
-anchored-entry span:not(:last-child):after {
- content: "\00B7";
- margin-left: 0.25rem;
+menu context-menu a {
+ display: block;
+ padding: 0.5rem 1rem;
}
-anchored-pinned svg {
- fill: #9ed1fa;
+menu context-menu a:hover {
+ background-color: #eee;
+ background-color: var(--hover-background);
+ border-radius: 0.25rem;
}
-anchored-liked svg {
- fill: #cd5c5c;
+micro-card[id] article h1 a,
+micro-card[id] article h2 a,
+micro-card[id] article h3 a {
+ color: inherit;
+}
+
+meta-view a,
+meta-name a,
+meta-draft a,
+meta-handle a,
+micro-card[id] article h1 a,
+micro-card[id] article h2 a,
+micro-card[id] article h3 a,
+micro-card header a:focus > span,
+micro-card menu context-menu a,
+micro-card menu context-menu a span {
+ text-decoration: none;
+}
+
+menu span,
+meta-view a span,
+meta-name a:hover,
+meta-draft a span,
+meta-handle a span,
+micro-card[id] article h1 a:hover,
+micro-card[id] article h2 a:hover,
+micro-card[id] article h3 a:hover {
+ text-decoration: underline;
}
-micro-header micro-header-image img {
+profile-box picture[data-type="banner"] img {
background-color: transparent;
border-radius: 0.125rem;
- height: 12rem;
+ height: 10rem;
width: 100%;
border: none;
}
-micro-header micro-header-picture img {
+profile-box picture[data-type="profile"] img {
border-radius: 100%;
height: 8rem;
margin: -4rem 2rem 0 2rem;
@@ -792,123 +1344,145 @@ micro-header micro-header-picture img {
padding: 0.25rem;
}
-micro-header section {
+profile-box section {
margin: 1rem 2rem 0 2rem;
- line-height: 1;
display: flex;
align-items: baseline;
}
-micro-header-title {
- margin-right: 1rem;
+profile-box section aside {
flex: 1;
+ line-height: 1.25;
+ margin-right: 1rem;
+ display: inline;
}
-micro-header-description {
+profile-box section p {
flex: 6;
}
-micro-header h2 {
- margin-bottom: 0.25rem;
- font-size: 700;
-}
-
-micro-header h3 {
+profile-box h3 {
font-weight: 400;
color: #444;
color: var(--fade);
- margin: 0;
}
-micro-header footer,
-micro-header footer code {
+profile-box footer,
+profile-box footer code {
color: #444;
color: var(--fade);
}
-micro-header footer {
+profile-box footer {
margin: 1.25rem 2rem 0.25rem 2rem;
text-align: center;
font-size: 95%;
}
-micro-header footer p {
+profile-box footer p {
margin: 0.75rem 0.5rem 0.25em 0;
display: inline;
}
-micro-unsafe-content * {
- visibility: hidden;
- opacity: 0;
- pointer-events: none;
+micro-card details[data-disclosure] summary {
+ display: inline-block;
+ margin: 0 -0.25rem 0.5rem -0.25rem;
+ padding: 0.25rem;
}
-micro-unsafe details svg {
- stroke-width: 0.1rem;
- margin-right: 0.15rem;
+micro-card details[data-disclosure] summary:focus a {
+ color: inherit;
}
-micro-unsafe details summary {
- font-variant: all-small-caps;
- letter-spacing: 0.025rem;
- line-height: 1.25;
- color: #8f0000;
- color: var(--danger);
- list-style: none;
+following-list details summary:focus:after,
+following-list details[open] summary:focus:after,
+micro-card details[data-disclosure] summary:focus:after,
+micro-card details[data-disclosure][open] summary:focus:after {
+ color: #111;
+ color: var(--foreground);
+ border-color: #111;
}
-micro-unsafe details > summary::-webkit-details-marker {
- display: none;
+following-list details summary:after,
+following-list details[open] summary:after,
+micro-card details[data-disclosure] summary:after,
+micro-card details[data-disclosure][open] summary:after {
+ border-radius: 0.5rem;
+ display: inline;
+ font-size: 85%;
+ vertical-align: bottom;
}
-micro-unsafe-content {
- border-radius: 0.25rem;
- display: block;
- background: repeating-linear-gradient(
- 180deg,
- #ff9999,
- #ff9999 1rem,
- #eee 1rem,
- #eee 2rem
- );
+micro-card details[data-disclosure] summary:hover,
+micro-card details[data-disclosure] summary:hover:after {
+ text-shadow: 0 0 currentColor;
}
-micro-unsafe details[open] + micro-unsafe-content * {
- filter: none;
- transition: 1s;
- visibility: visible;
- opacity: 1;
- background: none;
- outline: none;
- pointer-events: auto;
+micro-card details[data-disclosure] summary:hover:after {
+ text-decoration: underline;
}
-micro-unsafe details[open] + micro-unsafe-content {
- background: none;
+micro-card details[data-disclosure] summary:after {
+ content: "HIDDEN";
}
-@supports (filter: blur(2rem)) {
- micro-unsafe-content * {
- filter: blur(2rem);
- visibility: unset;
- opacity: unset;
- }
- micro-unsafe-content {
- outline: none;
- background: unset;
- }
+micro-card details[data-disclosure][open] summary:after {
+ content: "OPENED";
+}
+
+micro-card details[data-disclosure][open] ~ details summary:after {
+ content: none;
+}
+
+micro-card details[data-disclosure][open] ~ *:not(details):not(micro-tags) {
+ display: inherit;
+}
+
+micro-card
+ details[data-disclosure][open]
+ ~ *:not(details):not(micro-tags):not(math-ml) {
+ color: #444;
+ color: var(--fade);
+}
+
+micro-card details[data-disclosure][open] ~ details summary {
+ cursor: text;
+}
+
+micro-card details[data-disclosure] ~ *:not(details):not(micro-tags) {
+ display: none;
+}
+
+micro-thread related-content footer {
+ font-size: 100%;
+ border-bottom: 1px solid;
+ border-color: #eee;
+ border-color: var(--border-lighter);
+ margin: 0;
+ padding: 0.5rem 0;
+}
+
+micro-thread nav[data-type="pagination"] {
+ padding: 0.5rem 0;
+ border-bottom: 1px solid;
+ border-color: #eee;
+ border-color: var(--border-lighter);
+}
+
+micro-thread > nav[data-type="pagination"]:last-child {
+ border: none;
}
-tab-list {
+tab-bar {
display: inline-block;
overflow-x: auto;
- text-overflow: ellipsis;
+ overflow-y: hidden;
vertical-align: top;
white-space: nowrap;
width: 100%;
}
-tab-list aside {
+tab-bar nav {
display: flex;
justify-content: center;
border-bottom: 1px solid;
@@ -917,7 +1491,7 @@ tab-list aside {
min-width: 450px;
}
-tab-list aside a {
+tab-bar nav a {
border-left: 1px solid;
border-right: 1px solid;
border-top-left-radius: 0.5rem;
@@ -925,32 +1499,53 @@ tab-list aside a {
border-top: 1px solid;
border-color: #ddd;
border-color: var(--border-darker);
- color: #555;
+ color: #444;
color: var(--fade);
padding: 0.5rem 1rem;
margin-top: 0.5rem;
position: relative;
text-decoration: none;
top: 1px;
- border-bottom: 2px solid var(--background);
+ border-bottom: 2px solid transparent;
}
-tab-list aside a:not(:last-child) {
+tab-bar nav a:not(:last-child) {
margin-right: 0.5rem;
}
-tab-list aside a:last-child {
+tab-bar nav a[data-draft] {
color: #8f0000;
color: var(--danger);
}
-tab-list aside a:hover {
- background-color: #eee;
- background-color: var(--hover-background);
- color: inherit;
+tab-bar nav a:after {
+ content: attr(data-label);
+ display: block;
+ font-weight: 700;
+ height: 0;
+ overflow: hidden;
+ pointer-events: none;
+ user-select: none;
+ visibility: hidden;
}
-column-middle nav {
+tab-bar nav a:hover {
+ text-decoration: underline;
+}
+
+tab-bar nav a span[data-scroll] {
+ position: absolute;
+ top: -4.75rem;
+ left: 200%;
+ width: 0;
+ height: 0;
+}
+
+tab-bar nav a:nth-child(-n + 3) span[data-scroll] {
+ left: -200%;
+}
+
+column-base[position="middle"] > nav:first-child {
align-items: center;
background-color: #fefefe;
background-color: var(--background);
@@ -963,29 +1558,39 @@ column-middle nav {
top: 0;
width: 100%;
z-index: 100;
- height: 4rem;
+ height: inherit;
}
-column-middle nav section h2,
-column-middle nav section small {
+column-base[position="middle"] > nav:first-child section h2,
+column-base[position="middle"] > nav:first-child section small {
margin: 0;
}
-micro-author micro-header,
-column-middle nav section h2,
-column-middle nav section small {
- white-space: nowrap;
+micro-author article > *,
+column-base[position="middle"] > nav:first-child section h2,
+column-base[position="middle"] > nav:first-child section small {
overflow: hidden;
text-overflow: ellipsis;
+ white-space: nowrap;
}
-column-middle nav section {
+column-base[position="middle"] > nav:first-child section {
line-height: 1.25;
padding: 0 0.5rem;
+ margin-right: 0.5rem;
}
-column-middle main > footer {
- margin: 1rem 0;
+column-base[position="middle"] > footer:last-child {
+ margin: 1rem 0.25rem 3rem 0.25rem;
+}
+
+column-base[position="middle"] main > footer:last-child {
+ padding: 2rem 0 1rem 0;
+}
+
+icon-button,
+icon-navigator {
+ height: 4rem;
}
icon-button a {
@@ -1000,9 +1605,16 @@ icon-button a {
padding: 0.5rem 0;
}
-icon-button,
-icon-navigator {
- height: 4rem;
+icon-button a svg:nth-of-type(2),
+icon-button a small:nth-of-type(2),
+icon-button a[data-update="refresh"] svg:nth-of-type(1),
+icon-button a[data-update="refresh"] small:nth-of-type(1) {
+ display: none;
+}
+
+icon-button a[data-update="refresh"] svg:nth-of-type(2),
+icon-button a[data-update="refresh"] small:nth-of-type(2) {
+ display: block;
}
icon-button a:hover {
@@ -1018,11 +1630,31 @@ icon-button p {
margin: 0;
}
+code-block pre {
+ border-radius: 0.5rem;
+ border: 1px solid #ccc;
+ border: 1px solid var(--border-darker);
+ display: block;
+ font-size: 95%;
+ margin: 0;
+ overflow-x: auto;
+ overflow-y: hidden;
+ padding: 2.65rem 0 0 0;
+ tab-size: 2;
+ word-break: break-word;
+ white-space: pre;
+ resize: both;
+ position: relative;
+ z-index: 2;
+}
+
code-block pre code {
display: inline-block;
min-width: 100%;
- border-top: 1px solid #bbb;
+ border-top: 1px solid #ccc;
+ border-top: 1px solid var(--border-darker);
padding: 0.75rem;
+ white-space: pre;
}
code-block[data-lines] pre code {
@@ -1031,69 +1663,51 @@ code-block[data-lines] pre code {
code-block header {
position: relative;
- top: 1.85rem;
+ top: 2.125rem;
margin-top: -1rem;
height: 1rem;
padding: 0 0.5rem;
display: flex;
justify-content: space-between;
align-items: center;
+ z-index: 3;
}
code-block header language-label {
- padding: 0.125rem 1rem;
font-variant: all-small-caps;
}
-code-block pre {
- border-radius: 0.5rem;
- border: 1px solid #ccc;
- border: 1px solid var(--border-darker);
- display: block;
- font-size: 95%;
- margin: 0;
- overflow-x: auto;
- overflow-y: hidden;
- padding: 2.65rem 0 0 0;
- tab-size: 2;
- word-break: break-word;
- white-space: pre;
+code-block header language-label a {
+ text-decoration: none;
+ padding: 0.125rem 1rem;
+}
+
+code-block header language-label a:hover {
+ text-decoration: underline;
+}
+
+code-content {
+ width: 100%;
}
-paginator-navigation {
- padding: 1rem 1rem 0 1rem;
+nav[data-type="pagination"] {
+ padding: 1rem 0;
display: flex;
align-items: center;
justify-content: center;
+ flex-wrap: wrap;
}
-paginator-navigation a,
-paginator-navigation button {
- margin: 0 0.25rem;
+nav[data-type="pagination"] a {
+ margin: 0.5rem 0.25rem;
font-size: 85%;
display: flex;
align-items: center;
justify-content: center;
}
-paginator-navigation svg {
- height: 1.316rem;
-}
-
-web-ring,
-author-list,
-gallery-images {
- padding-bottom: 1rem;
- display: block;
-}
-
-web-ring > h1,
-author-list > h1,
-gallery-images > h1 {
- font-size: 95%;
- margin: 0.5rem 0 1rem 0;
- text-align: center;
- text-transform: uppercase;
+nav[data-type="pagination"] a[title="hidden"] {
+ visibility: hidden;
}
gallery-images aside {
@@ -1103,16 +1717,24 @@ gallery-images aside {
position: relative;
}
-gallery-images picture {
+gallery-images a {
display: flex;
- flex-basis: 33.33%;
+ flex-basis: 25%;
flex-grow: 1;
height: 6rem;
- width: 33.333%;
+ width: 25%;
}
+gallery-images picture,
gallery-images picture img {
+ border-color: #ccc;
border-radius: 0;
+ height: 100%;
+ width: 100%;
+}
+
+gallery-images picture img:hover {
+ box-shadow: none;
}
gallery-overlay {
@@ -1122,81 +1744,145 @@ gallery-overlay {
outline: 4px solid #fefefe;
outline: 4px solid var(--background);
position: absolute;
+ left: 0;
+ top: 0;
width: 100%;
z-index: 1;
+ pointer-events: none;
+ border: 1px solid;
+ border-color: #eee;
+ border-color: var(--border-lighter);
}
-main web-ring {
- display: none;
-}
-
-web-ring {
+web-ring,
+[data-kind="home"] author-list,
+[data-kind="term"] author-list,
+[data-kind="taxonomy"] author-list {
border-radius: 1rem;
position: sticky;
position: -webkit-sticky;
top: 1rem;
}
-web-ring a {
- text-decoration: none;
-}
-
-anchored-entry a:hover,
-web-ring a[href^="http"]:hover {
- text-decoration: underline;
-}
-
-web-ring time {
- font-variant: small-caps;
+web-ring time,
+micro-author article time {
+ display: block;
color: #444;
color: var(--fade);
}
-web-ring header {
- font-weight: 700;
+web-ring p:not(:last-child) {
+ margin-bottom: 0;
}
-web-ring p {
- margin-bottom: 0 !important;
+web-ring article:not(:last-child) {
+ margin-bottom: 1.5rem;
}
-web-ring-item:not(:last-child) {
- margin-bottom: 2rem;
- display: block;
+web-ring aside {
+ padding: 1rem;
}
web-ring aside,
-author-list section {
+author-list aside,
+following-list aside {
background-color: #f9f9f9;
background-color: var(--widget-background);
+ border-radius: 0.5rem;
}
-web-ring aside {
- border-radius: 1rem;
- padding: 1rem;
+web-ring aside footer,
+author-list aside footer,
+following-list aside footer {
+ background-color: #fefefe;
+ background-color: var(--background);
}
-author-list section {
+web-ring,
+author-list,
+following-list,
+gallery-images {
+ padding-bottom: 1rem;
display: block;
- border-radius: 1rem;
}
-search-entry {
+web-ring > h1,
+author-list > h1,
+gallery-images > h1,
+following-list details {
+ font-size: 95%;
+ margin: 0.5rem 0 1rem 0;
+ text-align: center;
+ text-transform: uppercase;
+}
+
+following-list details h1 {
+ display: inline-block;
+}
+
+following-list aside micro-author {
+ display: none;
+}
+
+following-list details[open] + aside micro-author,
+following-list aside micro-author:nth-child(-n + 3) {
+ display: inherit;
+}
+
+following-list:hover details[open] + aside {
+ outline: 2px solid #ccc;
+ outline: 2px solid var(--border-darker);
+}
+
+following-list details[data-expand="more"] summary:after {
+ content: "+";
+}
+
+following-list details[open][data-expand="more"] summary:after {
+ content: "-";
+}
+
+following-list details[data-expand="more"] summary:after,
+following-list details[open][data-expand="more"] summary:after {
+ padding: 0 0.5rem;
+ font-size: 100%;
+ margin-left: 0.25rem;
+}
+
+author-list:hover h1,
+following-list:hover details h1 {
+ text-decoration: underline;
+}
+
+author-list h1 a {
+ color: inherit;
+}
+
+author-list aside {
+ display: block;
+}
+
+author-list p {
+ display: none;
+}
+
+search-box {
display: inherit;
width: 100%;
+ z-index: 1;
}
-search-entry[data-focus],
-search-entry:focus-within {
+search-box[data-focus],
+search-box:focus-within {
position: absolute;
}
-search-entry:focus-within form {
+search-box:focus-within form {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
-search-entry form {
+search-box form {
background-color: #fefefe;
background-color: var(--background);
border-radius: 0.5rem;
@@ -1204,12 +1890,12 @@ search-entry form {
border-color: #ccc;
border-color: var(--border-darker);
display: inline-flex;
- margin: 0 1rem;
width: 100%;
position: relative;
+ margin: 0 0.5rem;
}
-search-entry form button {
+search-box form button[type="submit"] {
background-color: transparent;
border: none;
box-shadow: none;
@@ -1225,32 +1911,32 @@ search-entry form button {
line-height: 1;
}
-search-entry form input {
+search-box form input {
-webkit-appearance: none;
- background-color: #fefefe;
- background-color: var(--background);
border-bottom-left-radius: 0.5rem;
border-top-left-radius: 0.5rem;
border: none;
font-size: 100%;
- line-height: 1.5;
+ line-height: inherit;
padding-left: 1rem;
padding-right: 1rem;
width: 100%;
color: inherit;
}
-search-entry form button svg {
- stroke-width: 0.1rem;
+search-box form input,
+search-box form input:focus {
+ outline: none;
+ background-color: #fefefe;
+ background-color: var(--text-background);
}
-search-entry form input:focus {
- outline: none;
- background-color: #fefefe !important;
- background-color: var(--background) !important;
+search-box form button svg {
+ stroke-width: 0.1rem;
+ width: 100%;
}
-search-entry ul {
+search-box ul {
position: absolute;
background-color: inherit;
padding-top: 2.9rem;
@@ -1259,15 +1945,17 @@ search-entry ul {
border-radius: 0.5rem;
z-index: -1;
margin-right: 1rem;
- margin-left: -0.05rem;
+ margin-left: -0.065rem;
width: 100.3%;
+ box-shadow: 0 4px 6px #00000060;
+ box-shadow: 0 4px 6px var(--shadow);
}
-search-entry ul li a span {
+search-box ul li a span {
font-weight: 400;
}
-search-entry ul li a {
+search-box ul li a {
font-weight: 700;
color: inherit;
text-decoration: none;
@@ -1275,12 +1963,18 @@ search-entry ul li a {
padding: 0.25rem 0.75rem;
}
-search-entry ul li:first-child a {
+search-box ul li:first-child a {
background-color: #ebf3ff;
background-color: var(--hover-background-alternate);
}
-search-entry ul li a:hover {
+search-box ul li:only-child a,
+search-box ul li:last-child a:hover {
+ border-bottom-right-radius: 0.5rem;
+ border-bottom-left-radius: 0.5rem;
+}
+
+search-box ul li a:hover {
background-color: #eee;
background-color: var(--hover-background);
}
@@ -1295,7 +1989,6 @@ item-list h1 {
item-list ul {
padding: 0 0.5rem 0 0.5rem;
- list-style: none;
}
item-list li:hover {
@@ -1307,7 +2000,7 @@ item-list li:hover span:last-child {
text-decoration: underline;
}
-item-list li a {
+item-list li > a {
display: flex;
text-decoration: none;
align-items: baseline;
@@ -1315,25 +2008,120 @@ item-list li a {
padding: 0.5rem;
}
-item-list a span:first-child {
+item-list span:first-child {
flex: 1;
text-transform: uppercase;
}
-item-list a span:nth-child(2) {
+item-list span:nth-child(2) {
flex: 3;
margin: 0 0.5rem;
}
-item-list a span:last-child {
+item-list span:last-child {
flex: 1;
text-align: right;
}
-item-list a span:first-child,
-item-list a span:last-child {
+item-list span:first-child,
+item-list span:last-child {
+ color: #444;
+ color: var(--fade);
+}
+
+item-list a:focus span:first-child,
+item-list a:focus span:last-child {
+ color: inherit;
+}
+
+time-line h1 {
+ padding: 1rem;
+}
+
+time-line ul {
+ padding: 0 0.5rem;
+}
+
+time-line li:hover {
+ background-color: #eee;
+ background-color: var(--hover-background);
+}
+
+time-line li a {
+ position: relative;
+ border-left: 1px solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
+ padding: 0.75rem 0.5rem;
+ display: flex;
+ text-decoration: none;
+}
+
+time-line li a:before {
+ position: absolute;
+ background-color: #0149bc;
+ background-color: var(--link);
+ border-radius: 100%;
+ content: "";
+ height: 1rem;
+ width: 1rem;
+ top: 1rem;
+ left: -0.5rem;
+ border: 0.3rem solid #fefefe;
+ border: 0.3rem solid var(--background);
+}
+
+time-line a:focus time,
+time-line a:focus section p {
+ color: inherit;
+}
+
+time-line time,
+time-line section p {
+ color: #444;
+ color: var(--fade);
+}
+
+time-line time {
+ text-transform: uppercase;
+ white-space: nowrap;
+ margin: 0 1rem;
+}
+
+tag-deck {
+ display: flex;
+ flex-wrap: wrap;
+ margin: 0.5rem 0;
+ justify-content: space-between;
+}
+
+tag-card {
+ border: 1px solid;
+ border-color: #eee;
+ border-color: var(--border-lighter);
+ border-radius: 0.5rem;
+ box-shadow: 0 0 1rem -0.85rem #00000060;
+ box-shadow: 0 0 1rem -0.85rem var(--shadow);
+ display: block;
+ padding: 2rem;
+ text-align: center;
+ width: 49%;
+ margin: 1% 0;
+}
+
+tag-card h2 {
+ margin: 0 0 0.5rem 0;
+}
+
+tag-card img {
+ margin: 0 auto;
+}
+
+tag-card time {
color: #444;
color: var(--fade);
+ display: block;
+ margin-bottom: 0.5rem;
}
source-files footer {
@@ -1356,35 +2144,42 @@ context-menu {
background-color: #fff;
background-color: var(--background-bolder);
border: 1px solid;
- border-color: #ddd;
+ border-color: #eee;
border-color: var(--border-lighter);
- border-radius: 4px;
- box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1),
- 0 0 0 1px rgba(10, 10, 10, 0.02);
- padding-bottom: 0.5rem;
- padding-top: 0.5rem;
+ border-radius: 0.5rem;
+ box-shadow: 0 0 1rem -0.5rem #00000060;
+ box-shadow: 0 0 1rem -0.5rem var(--shadow);
min-width: 6.25rem;
position: absolute;
z-index: 99;
- max-width: 20rem;
visibility: hidden;
opacity: 0;
}
-context-profile context-menu {
- color: #111;
- color: var(--foreground);
- display: block;
- padding: 1rem;
- text-align: left;
+context-menu[position="right"] {
+ right: 0;
}
-context-profile a {
- display: inline;
+context-menu[position="left"] {
+ left: 0;
+}
+
+context-menu[position="anchor"] {
+ left: -125%;
+ top: 0;
+}
+
+context-menu[position="left"],
+context-menu[position="right"] {
+ top: 1rem;
+}
+
+context-profile p a {
+ text-decoration: underline;
}
context-profile aside p {
- color: #555;
+ color: #444;
color: var(--fade);
margin: 0;
}
@@ -1392,18 +2187,34 @@ context-profile aside p {
context-profile div {
display: flex;
align-items: center;
+ margin-bottom: 0.5rem;
}
context-profile aside:nth-child(2) {
line-height: 1.25;
}
-micro-thumbnail figure:hover context-menu {
- visibility: visible;
+context-profile context-menu {
+ color: #111;
+ color: var(--foreground);
+ display: block;
+ padding: 0.9rem;
+ left: 0.5rem;
+ top: 0.5rem;
+ text-align: left;
+ max-width: 20rem;
+ transition-delay: 0.5s;
+}
+
+micro-card figure:hover context-menu,
+input[type="checkbox"]:checked + context-menu {
+ margin-right: 1rem;
opacity: 1;
+ visibility: visible;
}
diagram-container svg {
+ width: 100%;
border: 2px solid;
border-radius: 0.5rem;
border-color: #ccc;
@@ -1413,151 +2224,111 @@ diagram-container svg {
background-color: var(--background);
}
-twitter-tweet {
- min-height: 20rem;
- max-height: 20rem;
- display: block;
- overflow-y: auto;
-}
-
-twitter-tweet iframe {
- border: none;
-}
-
-/* ----- Typography ----- */
-
-h1,
-h2,
-h3 {
- font-size: 100%;
- margin: 0;
-}
-
-p,
-ul,
-dd,
-dl,
-ol,
-figure,
-blockquote {
- margin: 0;
-}
-
-p:not(:last-child),
-ol:not(:last-child),
-ul:not(:last-child),
-dl:not(:last-child),
-table:not(:last-child),
-figure:not(:last-child),
-code-block:not(:last-child),
-blockquote:not(:last-child) {
- margin-bottom: 0.75rem;
-}
-
-footer,
-figcaption {
- color: #444;
- color: var(--fade);
- font-size: 85%;
- margin: 0.5rem 0;
- text-align: center;
+tool-tip[data-type="reaction"] {
+ text-decoration: underline;
+ -webkit-text-decoration-style: dotted;
+ text-decoration-style: dotted;
+ text-decoration-thickness: 0.05rem;
+ cursor: default;
+ position: relative;
+ display: inline-block;
}
-sup {
- vertical-align: super;
- font-size: 85%;
+tool-tip[data-type="reaction"]:hover {
+ text-decoration-thickness: 0.1rem;
}
-sub {
- vertical-align: sub;
- font-size: 85%;
+tool-tip[data-type="reaction"]:hover img {
+ opacity: 1;
+ visibility: visible;
+ width: 100%;
}
-s,
-del,
-mark,
-ins {
- padding: 0 0.15rem;
- line-height: 1.5;
+tool-tip[data-type="reaction"] img {
+ position: absolute;
+ z-index: 99;
+ visibility: hidden;
+ opacity: 0;
+ max-height: 80px;
+ object-fit: cover;
+ bottom: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ max-width: fit-content;
+ border: none;
+ transition-delay: 0.5s;
}
-mark {
- background-color: #ffe699;
- background-color: var(--warning-background);
- color: #332600;
- color: var(--warning);
+body micro-card:first-of-type tool-tip[data-type="reaction"] img,
+main micro-card:first-of-type tool-tip[data-type="reaction"] img {
+ bottom: 0;
+ top: 100%;
}
-ins {
- background-color: #d5f3c4;
- background-color: var(--success-background);
- color: #1d3c0c;
- color: var(--success);
- text-decoration: none;
-}
-
-del {
- background-color: #fcd2cf;
- background-color: var(--danger-background);
- color: #8f0000;
- color: var(--danger);
+link-card {
+ display: flex;
+ border: 1px solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
+ border-radius: 0.5rem;
+ margin-bottom: 0.75rem;
}
-s {
- text-decoration: none;
- background-color: #333;
- background-color: var(--spoiler);
- color: transparent;
+link-card a img {
+ min-width: 5rem;
+ max-width: 5rem;
+ border: none;
}
-[type="checkbox"]:checked ~ s {
- background-color: inherit;
- color: inherit;
+link-card > a {
+ border-right: 1px solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
+ display: flex;
+ align-items: center;
+ padding: 1rem;
}
-blockquote {
- color: #555;
- color: var(--fade);
- padding-left: 2rem;
+link-card article {
+ padding: 1rem;
+ width: 100%;
}
-blockquote p {
- font-style: italic;
- font-family: Charter, Georgia, "Book Antiqua", serif;
- font-size: 125%;
+link-card article a {
+ word-break: break-all;
+ display: block;
}
-blockquote p span {
- display: block;
- text-align: right;
- color: #111;
- color: var(--foreground);
- font-style: normal;
- font-size: 80%;
- margin-top: 0.75rem;
+math-ml:not(:last-child) {
+ margin-bottom: 0.75rem;
}
-video {
+math-ml figure[id] figure {
+ overflow-x: auto;
+ overflow-y: hidden;
border-radius: 0.5rem;
+ padding: 0.75rem 0.5rem;
+ background-color: #f9f9f9;
+ background-color: var(--widget-background);
+ border: 1px solid;
+ border-color: #ccc;
+ border-color: var(--border-darker);
}
-video:hover {
- box-shadow: 0 0 14px #999;
- box-shadow: 0 0 14px var(--shadow);
+math-ml figure[id] a:first-child {
+ margin: 0 0.125rem;
+ padding: 0 0.25rem;
+ font-weight: 700;
+ color: #0149bc;
+ color: var(--link);
}
-kbd {
- background-color: #eee;
- border-radius: 3px;
- border: 1px solid #b4b4b4;
- box-shadow: 0 1px 1px #737373, 0 2px 0 0 #f2f2f2 inset;
- color: #333;
- display: inline-block;
- font-size: 0.85em;
- font-weight: 700;
- line-height: 1;
- padding: 2px 4px;
- white-space: nowrap;
+math-ml figure[id]:target figure {
+ background-color: #ffe699;
+ background-color: var(--warning-background);
+ color: #000;
+ outline: 2px solid;
+ border-radius: 0.5rem;
}
/* ----- Attributes ----- */
@@ -1566,30 +2337,32 @@ kbd {
outline: none;
}
-[hidden] {
+[hidden],
+nav[hidden] {
display: none;
}
-[data-invisible] {
- visibility: hidden;
-}
-
[data-hover] {
text-decoration: none;
}
+[data-hover]:hover {
+ text-decoration: underline;
+}
+
[draft] {
background-color: #fff5f5;
background-color: var(--danger-background-lighter);
+ border-color: #fcd2cf;
border-color: var(--danger-background);
}
[disabled] {
cursor: not-allowed;
- border-color: #ddd;
+ border-color: #eee;
border-color: var(--border-lighter);
- color: #999;
- color: var(--disabled);
+ color: #444;
+ color: var(--fade);
}
[role="doc-endnotes"] {
@@ -1597,77 +2370,138 @@ kbd {
}
[role="doc-endnotes"] hr {
- border-top: 1px solid #ccc;
margin-bottom: 0.75rem;
}
[role="doc-endnotes"] ol {
+ font-size: 90%;
padding-left: 2rem;
}
+[data-xml] micro-card {
+ flex-direction: row;
+ align-items: center;
+}
+
+[data-xml] micro-card article {
+ margin-left: 0;
+}
+
+[data-xml] micro-card header figure {
+ display: block;
+}
+
+[data-xml] column-base[position="middle"] nav section {
+ flex-grow: 1;
+}
+
+[data-xml="sitemap"] main section {
+ padding: 1rem;
+}
+
+[data-xml="sitemap"] section a {
+ text-decoration: none;
+}
+
+[data-xml="sitemap"] section a:hover {
+ text-decoration: underline;
+}
+
/* ----- Responsive ----- */
@media screen and (max-width: 1220px) {
- column-left {
+ column-base[position="left"] {
flex: none;
margin: 0.5rem;
}
- column-left nav a {
+ column-base[position="left"] nav a {
flex-direction: column-reverse;
justify-content: center;
white-space: nowrap;
overflow: hidden;
}
- column-left nav a span {
+ column-base[position="left"] nav a span {
padding-top: 0.5rem;
}
+ column-base[position="right"] {
+ width: 38%;
+ }
+ micro-author micro-card {
+ flex-direction: column;
+ text-align: center;
+ }
+ micro-author micro-card > *:not(:last-child),
+ micro-author micro-card > p:not(:last-child) {
+ margin-bottom: 0.5rem;
+ }
+ micro-author article {
+ flex: none;
+ }
+ micro-author article > * {
+ white-space: normal;
+ }
+ time-line ul {
+ padding: 0 2rem;
+ }
}
-@media screen and (max-width: 1055px) {
- column-left,
- search-entry,
- column-middle nav section {
+@media screen and (max-width: 1080px) {
+ search-box,
+ column-base[position="left"],
+ column-base[position="middle"] > nav:first-child section {
display: none;
}
- column-middle nav {
+ column-base[position="middle"] > nav:first-child {
justify-content: space-between;
overflow-x: auto;
overflow-y: hidden;
}
- icon-navigator {
- display: inline !important;
+ column-base[position="middle"] > nav:first-child icon-navigator[hidden] {
+ display: inline;
+ }
+ tag-deck {
+ margin: 0.5rem 0.75rem;
}
}
-@media screen and (max-width: 925px) {
- column-right {
- display: none;
+@media screen and (max-width: 920px) {
+ nav + main,
+ profile-box {
+ margin-top: 4rem;
}
- micro-metadata {
- line-height: inherit;
- }
- micro-header section {
- display: block;
+ column-base[position="right"] {
+ display: none;
}
- column-middle {
+ column-base[position="middle"] {
display: block;
max-width: 100%;
}
- column-middle nav {
+ column-base[position="middle"] > nav:first-child {
position: fixed;
- }
- navigation-separator hr[hidden] {
- border-color: transparent;
- display: flex;
- height: 0;
- margin: 0;
- padding-top: 4rem;
- border: none;
+ box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.2);
}
micro-card {
max-width: 600px;
margin: 0 auto;
}
+ micro-card header {
+ line-height: inherit;
+ }
+ profile-box section {
+ display: block;
+ }
+ micro-author micro-card {
+ flex-direction: column;
+ text-align: center;
+ border-bottom: 1px solid #eee;
+ border-bottom: 1px solid var(--border-lighter);
+ }
+ micro-author micro-card article,
+ micro-author micro-card header figure,
+ micro-author micro-card p:not(:last-child) {
+ flex: auto;
+ margin: 0 0 0.75rem 0;
+ }
html {
margin: 0;
}
@@ -1675,48 +2509,338 @@ kbd {
display: block;
overflow-y: scroll;
}
- nav {
- box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.2);
- }
- nav:active,
- nav:hover,
- nav:focus,
- nav:focus-within,
- nav:focus-visible {
- box-shadow: 15px 0 15px -15px inset, -15px 0 15px -15px inset;
+ tab-bar:active,
+ tab-bar:hover,
+ tab-bar:focus,
+ tab-bar:focus-within,
+ tab-bar:focus-visible,
+ column-base[position="middle"] > nav:first-child:active,
+ column-base[position="middle"] > nav:first-child:hover,
+ column-base[position="middle"] > nav:first-child:focus,
+ column-base[position="middle"] > nav:first-child:focus-within,
+ column-base[position="middle"] > nav:first-child:focus-visible {
+ box-shadow: 1rem -0.2rem 1rem -1rem inset, -1rem -0.2rem 1rem -1rem inset;
}
}
@media screen and (max-width: 460px) {
- micro-card micro-summary > micro-thumbnail {
- display: none;
+ micro-card > article {
+ margin-left: 0;
}
- micro-metadata micro-thumbnail[hidden],
- micro-author micro-card micro-summary > micro-thumbnail {
- display: block;
+ tag-card {
+ width: 100%;
+ margin: 0.5rem;
}
}
/* ----- Self Frames ----- */
@media (max-height: 12rem) {
+ nav + main {
+ margin-top: 0;
+ }
micro-card {
width: 100vw;
padding-right: 1rem;
}
- micro-summary {
+ micro-card {
min-height: 14rem;
}
- :not(#main):target micro-summary,
- :not(#main):target micro-summary:hover {
+ :not(#main):target micro-card,
+ :not(#main):target micro-card:hover {
outline: none;
}
:target::before {
display: none;
}
- main > footer,
- column-middle nav,
- navigation-separator hr[hidden] {
+ column-base[position="middle"] > nav:first-child,
+ column-base[position="middle"] > footer:last-child {
display: none;
}
}
+
+/* ----- Animations ----- */
+
+text-animation {
+ height: 0;
+ cursor: default;
+}
+
+text-animation,
+text-animation span {
+ display: inline-block;
+ text-decoration: underline;
+ -webkit-text-decoration-style: double;
+ text-decoration-style: double;
+}
+
+text-animation:hover,
+text-animation:hover span {
+ text-decoration: none;
+}
+
+text-animation[rattle]:hover,
+text-animation[default]:hover {
+ animation: tilt-rightward 0.1s infinite, tilt-leftward 0.15s infinite;
+}
+
+text-animation[hang]:hover {
+ animation: tilt-rightward 1.3s infinite, tilt-leftward 1.8s infinite;
+}
+
+text-animation[squeeze]:hover {
+ animation: squeeze 1s infinite;
+}
+
+text-animation[twitch]:hover {
+ animation: quiver 2.25s infinite, quiver 1.45s infinite;
+}
+
+text-animation[tremble]:hover {
+ animation: leftward 0.1s infinite, quiver 0.75s infinite,
+ quiver 1.35s infinite;
+}
+
+text-animation[grow]:hover {
+ animation: maximize 1.4s infinite;
+}
+
+text-animation[shrink]:hover {
+ animation: minimize 1.25s infinite;
+}
+
+text-animation[grow]:hover,
+text-animation[shrink]:hover {
+ transform-origin: right 1rem;
+}
+
+text-animation[distort]:hover span {
+ animation: distort 0.25s infinite, distort 0.55s infinite,
+ distort 0.75s infinite;
+}
+
+text-animation[roll]:hover span {
+ animation: rotateY 1.5s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[flip]:hover span {
+ animation: rotateX 1.5s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[twirl]:hover span {
+ animation: rotateZ 1.5s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[wave]:hover span {
+ animation: up 1s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[skip]:hover span {
+ animation: skip 1s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[jiggle]:hover span {
+ animation: up 0.2s infinite, down 0.3s infinite, leftward 0.25s infinite;
+ animation-delay: calc(0.1s * var(--frame));
+}
+
+text-animation[float]:hover span {
+ animation: up 1s infinite;
+}
+
+text-animation[hop]:hover span {
+ animation: hop 1s infinite;
+}
+
+text-animation[shake]:hover span {
+ animation: left 0.15s infinite;
+}
+
+text-animation[waggle]:hover span {
+ animation: left 0.5s infinite;
+}
+
+text-animation[jump]:hover span {
+ animation: up 0.15s infinite;
+}
+
+text-animation[vibrate]:hover span {
+ animation: up 0.125s infinite, left 0.15s infinite;
+}
+
+main > * {
+ animation: paint ease-in 0.3s;
+}
+
+tab-bar,
+profile-box {
+ animation: paint ease-in 0.25s;
+}
+
+column-base[position="right"] time {
+ animation: paint ease-in 0.15s;
+}
+
+@keyframes paint {
+ 0%,
+ 90% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes rotateY {
+ 0%,
+ 10% {
+ transform: rotateY(360deg);
+ }
+}
+
+@keyframes rotateX {
+ 0%,
+ 10% {
+ transform: rotateX(360deg);
+ }
+}
+
+@keyframes rotateZ {
+ 0%,
+ 10% {
+ transform: rotateZ(360deg);
+ }
+}
+
+@keyframes tilt-rightward {
+ 50% {
+ transform: rotateZ(5deg);
+ }
+}
+
+@keyframes tilt-leftward {
+ 50% {
+ transform: rotateZ(-5deg);
+ }
+}
+
+@keyframes up {
+ 50% {
+ transform: translateY(-0.15rem);
+ }
+}
+
+@keyframes down {
+ 50% {
+ transform: translateY(0.15rem);
+ }
+}
+
+@keyframes left {
+ 50% {
+ transform: translateX(-0.15rem);
+ }
+}
+
+@keyframes leftward {
+ 50% {
+ transform: translateX(-0.05rem);
+ }
+}
+
+@keyframes squeeze {
+ 50% {
+ transform: scale(0.95, 1);
+ }
+}
+
+@keyframes maximize {
+ 0% {
+ transform: scale(1, 1.25);
+ }
+ 10% {
+ transform: scale(1, 1.05);
+ }
+ 20% {
+ transform: scale(1, 1.25);
+ }
+ 30% {
+ transform: scale(1, 1.1);
+ }
+ 40% {
+ transform: scale(1, 1.25);
+ }
+ 50% {
+ transform: none;
+ }
+}
+
+@keyframes minimize {
+ 0% {
+ transform: scale(0.75);
+ }
+ 10% {
+ transform: scale(0.95);
+ }
+ 20% {
+ transform: scale(0.75);
+ }
+ 30% {
+ transform: scale(0.85);
+ }
+ 40% {
+ transform: scale(0.75);
+ }
+ 50% {
+ transform: none;
+ }
+}
+
+@keyframes skip {
+ 0%,
+ 50%,
+ 100% {
+ transform: translateY(0);
+ }
+ 10% {
+ transform: translateY(-0.25rem);
+ }
+}
+
+@keyframes hop {
+ 0%,
+ 30%,
+ 50% {
+ transform: translateY(0);
+ }
+ 10%,
+ 40% {
+ transform: translateY(-0.25rem);
+ }
+}
+
+@keyframes quiver {
+ 5% {
+ transform: translateY(-0.025rem) skewX(-5deg) scale(0.9);
+ }
+ 10% {
+ transform: none;
+ }
+}
+
+@keyframes distort {
+ 20% {
+ text-shadow: 4px 0 var(--background);
+ }
+ 50% {
+ text-shadow: -4px 0 var(--background);
+ }
+ 100% {
+ text-shadow: none;
+ }
+}
diff --git a/assets/data/media/logo.png b/assets/data/media/logo.png
index 51baf7d..98b4003 100644
--- a/assets/data/media/logo.png
+++ b/assets/data/media/logo.png
Binary files differ
diff --git a/assets/js/index.js b/assets/js/index.js
index 1c2715b..d698127 100644
--- a/assets/js/index.js
+++ b/assets/js/index.js
@@ -1,52 +1,168 @@
-// deno-fmt-ignore-file
-// deno-lint-ignore-file
-// This code was bundled using `deno bundle` and it's not recommended to edit it manually
-
(function() {
- const url = self.location.href.split("#")[0];
- let settings = {
- pager: {}
+ const cookiesDisabled = !navigator.cookieEnabled;
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Pager disabled due to cookie restrictions");
+ }
+ let seek;
+ let pager = {};
+ const key = "config.scroll.pager.urls";
+ if (!localStorage[key]) localStorage[key] = JSON.stringify(pager);
+ let url = function() {
+ return self.location.href.split("#")[0].split("?")[0];
};
- self.addEventListener("DOMContentLoaded", function() {
- if (history.scrollRestoration) history.scrollRestoration = "manual";
- if (localStorage["settings"]) {
- settings = JSON.parse(localStorage["settings"]);
+ const scrollHash = function(url) {
+ const hash = self.location.hash;
+ const fragment = hash.slice(1) && document.getElementById(hash.slice(1));
+ const fragmented = hash.length > 0;
+ const hashed = fragmented && document.body.contains(fragment);
+ if (hashed) {
+ self.location.hash = hash;
+ self.location.href = hash;
+ if ("scroll-margin-top" in document.body.style === false && fragment.textContent !== "") {
+ self.scrollBy(0, -6 * parseFloat(getComputedStyle(document.documentElement).fontSize));
+ }
}
- if (self.location.hash.length > 0) {
- settings["pager"][url] = self.pageYOffset;
- localStorage["settings"] = JSON.stringify(settings);
- document.getElementById(location.hash.slice(1)).scrollIntoView();
- self.addEventListener("load", function() {
- document.getElementById(location.hash.slice(1)).scrollIntoView();
- });
- return;
+ return hashed;
+ };
+ const scrollRestore = function(url) {
+ if (history.scrollRestoration) history.scrollRestoration = "manual";
+ if (scrollHash(url)) return;
+ pager = JSON.parse(localStorage[key]);
+ if (pager[url] > 0) {
+ clearInterval(seek);
+ self.scrollTo(0, pager[url]);
+ let i1 = 0;
+ return seek = setInterval(function(position) {
+ i1++;
+ if (i1 > 100) clearInterval(seek);
+ if (document.documentElement.scrollHeight >= position + document.documentElement.clientHeight) {
+ clearInterval(seek);
+ self.scrollTo(0, position);
+ }
+ }, 4, pager[url]);
+ } else self.scrollTo(0, 0);
+ pager[url] = self.pageYOffset;
+ localStorage[key] = JSON.stringify(pager);
+ };
+ const scrollTrack = function(url) {
+ const currentPosition = self.pageYOffset;
+ pager = JSON.parse(localStorage[key]);
+ pager[url] = currentPosition;
+ localStorage[key] = JSON.stringify(pager);
+ };
+ const scrollReverse = function(back, up, event) {
+ if (document.body.contains(up) && up.contains(event.target)) {
+ event.preventDefault();
+ window.scrollTo(0, 0);
}
- if (settings["pager"][url] > 0) {
- self.scrollTo(0, settings["pager"][url]);
- return;
+ if (document.body.contains(back) && back.contains(event.target)) {
+ if (history.length < 2) return;
+ event.preventDefault();
+ history.go(-1);
}
- settings["pager"][url] = self.pageYOffset;
- localStorage["settings"] = JSON.stringify(settings);
+ };
+ [
+ "DOMContentLoaded",
+ "pageshow",
+ "hashchange",
+ "URLChangedCustomEvent"
+ ].forEach(function(event) {
+ self.addEventListener(event, function(event) {
+ if (event.type === "pageshow") {
+ return event.persisted && self.scrollTo(0, pager[url()]);
+ }
+ if (event.type === "DOMContentLoaded") {
+ self.addEventListener("click", function(event) {
+ const up = document.getElementById("top");
+ const back = document.getElementById("back");
+ scrollReverse(back, up, event);
+ });
+ }
+ scrollRestore(url());
+ });
});
- self.addEventListener("scroll", function() {
- const currentPosition = self.pageYOffset;
- settings["pager"][url] = currentPosition;
- localStorage["settings"] = JSON.stringify(settings);
+ [
+ "click",
+ "touchstart",
+ "scroll"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ scrollTrack(url());
+ });
});
- self.addEventListener("DOMContentLoaded", function() {
- const up = document.getElementById("top");
- const back = document.getElementById("back");
- self.addEventListener("click", function(event) {
- if (document.body.contains(up) && up.contains(event.target)) {
- event.preventDefault();
- window.scrollTo(0, 0);
- }
- if (document.body.contains(back) && back.contains(event.target)) {
- if (history.length < 2) return;
- event.preventDefault();
- history.go(-1);
+})();
+(function() {
+ const cookiesDisabled = !navigator.cookieEnabled;
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Update check disabled due to cookie restrictions");
+ }
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function() {
+ if (http.readyState === 4 && http.status === 200) {
+ if (callback) callback(http);
+ }
+ };
+ http.open(method, url);
+ http.setRequestHeader("Pragma", "no-cache");
+ http.setRequestHeader("Cache-Control", "no-cache");
+ http.send();
+ return http;
+ }
+ const key = "config.update";
+ let stamps = {};
+ if (!sessionStorage[key + ".urls"]) sessionStorage[key + ".urls"] = JSON.stringify(stamps);
+ function update() {
+ const url = self.location.href.split("#")[0].split("?")[0];
+ const indicator = document.querySelector("a[data-update]");
+ if (indicator === null || indicator.dataset.update === "refresh") return;
+ indicator.cloneNode();
+ fetch(url, "HEAD", function(request) {
+ const local = document.querySelector('meta[name="last-modified"]').content || document.lastModified;
+ const remote = request.getResponseHeader("last-modified") || '';
+ const modified = Date.parse(remote || local) > Date.parse(local);
+ const drift = Date.parse(remote || local) - Date.parse(local);
+ if (drift < 10000) return;
+ stamps = JSON.parse(sessionStorage[key + ".urls"]);
+ if (stamps[url] === remote) return;
+ stamps[url] = remote;
+ sessionStorage[key + ".urls"] = JSON.stringify(stamps);
+ if (remote && modified) {
+ fetch(url, "GET", function() {
+ indicator.href = url.replace(/^https:/, "http:");
+ indicator.removeAttribute("id");
+ indicator.dataset.update = "refresh";
+ console.log("INFO: R: " + remote);
+ console.log("INFO: L: " + local);
+ console.log("INFO: D: " + drift);
+ console.log("INFO: M: " + modified);
+ });
}
});
+ }
+ let scrolled;
+ let delay = 1000;
+ let delayed = 0;
+ self.addEventListener("scroll", function() {
+ if (scrolled) clearTimeout(scrolled);
+ scrolled = setTimeout(function() {
+ update();
+ delay = delay + delayed;
+ delayed = delay - delayed;
+ }, delay);
+ });
+ [
+ "focus",
+ "load",
+ "URLChangedCustomEvent"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ update();
+ });
});
})();
(function() {
@@ -81,350 +197,709 @@
}
})();
(function() {
- self.addEventListener("DOMContentLoaded", function() {
- let mouseoverTimer;
- let lastTouchTimestamp;
- const prefetches = new Set();
- const prefetchElement = document.createElement("link");
- const isSupported = prefetchElement.relList && prefetchElement.relList.supports && prefetchElement.relList.supports("prefetch") && window.IntersectionObserver && "isIntersecting" in IntersectionObserverEntry.prototype;
- const allowQueryString = "instantAllowQueryString" in document.body.dataset;
- const allowExternalLinks = "instantAllowExternalLinks" in document.body.dataset;
- const useWhitelist = "instantWhitelist" in document.body.dataset;
- const mousedownShortcut = "instantMousedownShortcut" in document.body.dataset;
- let delayOnHover = 65;
- let useMousedown = false;
- let useMousedownOnly = false;
- let useViewport = false;
- if ("instantIntensity" in document.body.dataset) {
- const intensity = document.body.dataset.instantIntensity;
- if (intensity.substr(0, "mousedown".length) == "mousedown") {
- useMousedown = true;
- if (intensity == "mousedown-only") {
- useMousedownOnly = true;
- }
- } else if (intensity.substr(0, "viewport".length) == "viewport") {
- if (!(navigator.connection && (navigator.connection.saveData || navigator.connection.effectiveType && navigator.connection.effectiveType.includes("2g")))) {
- if (intensity == "viewport") {
- if (document.documentElement.clientWidth * document.documentElement.clientHeight < 450000) {
- useViewport = true;
- }
- } else if (intensity == "viewport-all") {
- useViewport = true;
- }
- }
- } else {
- const milliseconds = parseInt(intensity);
- if (!isNaN(milliseconds)) {
- delayOnHover = milliseconds;
- }
- }
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
- if (isSupported) {
- const eventListenersOptions = {
- capture: true,
- passive: true
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function(s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ }while (el !== null && el.nodeType === 1)
+ return null;
};
- if (!useMousedownOnly) {
- document.addEventListener("touchstart", touchstartListener, eventListenersOptions);
- }
- if (!useMousedown) {
- document.addEventListener("mouseover", mouseoverListener, eventListenersOptions);
- } else if (!mousedownShortcut) {
- document.addEventListener("mousedown", mousedownListener, eventListenersOptions);
- }
- if (mousedownShortcut) {
- document.addEventListener("mousedown", mousedownShortcutListener, eventListenersOptions);
- }
- if (useViewport) {
- let triggeringFunction;
- if (window.requestIdleCallback) {
- triggeringFunction = function(callback) {
- requestIdleCallback(callback, {
- timeout: 1500
- });
- };
- } else {
- triggeringFunction = function(callback) {
- callback();
- };
- }
- triggeringFunction(function() {
- const intersectionObserver = new IntersectionObserver(function(entries) {
- entries.forEach(function(entry) {
- if (entry.isIntersecting) {
- const linkElement = entry.target;
- intersectionObserver.unobserve(linkElement);
- preload(linkElement.href);
- }
- });
- });
- document.querySelectorAll("a").forEach(function(linkElement) {
- if (isPreloadable(linkElement)) {
- intersectionObserver.observe(linkElement);
- }
- });
- });
- }
}
- function touchstartListener(event) {
- lastTouchTimestamp = performance.now();
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) {
- return;
+ }
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function() {
+ if (http.readyState === 4 && http.status === 200) {
+ if (callback) callback(http);
+ }
+ };
+ http.open(method, url);
+ http.send();
+ return http;
+ }
+ self.addEventListener("DOMContentLoaded", function() {
+ [
+ "mouseout",
+ "mousedown",
+ "touchstart"
+ ].forEach(function(event) {
+ self.addEventListener(event, function(event) {
+ const url = event.target.closest("a");
+ if (preloadable(url) === undefined) return;
+ preload(url.href);
+ });
+ });
+ function preloadable(url) {
+ switch(true){
+ case url === null || url.href === null:
+ return;
+ case url.origin !== location.origin:
+ return;
+ case [
+ "http:",
+ "https:"
+ ].includes(url.protocol) === null:
+ return;
+ case url.protocol === "http:" && location.protocol === "https:":
+ return;
+ case url.hash && url.pathname + url.search == location.pathname + location.search:
+ return;
+ default:
+ return true;
}
- preload(linkElement.href);
}
- function mouseoverListener(event) {
- if (performance.now() - lastTouchTimestamp < 1111) {
- return;
- }
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) {
+ function preload(url) {
+ const prefetcher = document.createElement("link");
+ prefetcher.rel = "custom-prefetch";
+ prefetcher.href = url;
+ const selector = 'link[rel="'.concat(prefetcher.rel, '"][href="').concat(prefetcher.href, '"]');
+ const prefetched = document.head.contains(document.querySelector(selector));
+ if (prefetched) {
return;
}
- linkElement.addEventListener("mouseout", mouseoutListener, {
- passive: true
- });
- mouseoverTimer = setTimeout(function() {
- preload(linkElement.href);
- mouseoverTimer = undefined;
- }, delayOnHover);
+ document.head.appendChild(prefetcher);
+ fetch(url, "GET", function() {});
}
- function mousedownListener(event) {
- const linkElement = event.target.closest("a");
- if (!isPreloadable(linkElement)) {
- return;
- }
- preload(linkElement.href);
+ });
+})();
+(function() {
+ const hide = function(triggers) {
+ for(let i1 = 0; i1 < triggers.length; i1++){
+ triggers[i1].checked = false;
}
- function mouseoutListener(event) {
- if (event.relatedTarget && event.target.closest("a") == event.relatedTarget.closest("a")) {
- return;
+ };
+ const hideIfClickedOutside = function(menus, triggers, event) {
+ for(let i1 = 0; i1 < menus.length; i1++){
+ const active = triggers[i1].checked === true;
+ const outside = !menus[i1].contains(event.target);
+ if (outside && active) hide(triggers);
+ }
+ };
+ self.addEventListener("scroll", function() {
+ const triggers = document.querySelectorAll("menu input");
+ hide(triggers);
+ });
+ [
+ "click",
+ "touchstart"
+ ].forEach(function(event) {
+ self.addEventListener(event, function(event) {
+ const menus = document.querySelectorAll("menu");
+ const triggers = document.querySelectorAll("menu input");
+ hideIfClickedOutside(menus, triggers, event);
+ });
+ });
+})();
+(function() {
+ [
+ "DOMContentLoaded",
+ "URLChangedCustomEvent"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ const container = document.querySelector("search-box");
+ const dropdown = document.querySelector("search-box ul");
+ const form = document.querySelector("search-box form");
+ const query = document.querySelector("search-box input");
+ const submit = document.querySelector("search-box button");
+ function first(element) {
+ if (element.firstChild.nextElementSibling) {
+ return element.firstChild.nextElementSibling.firstChild.nextElementSibling;
+ }
}
- if (mouseoverTimer) {
- clearTimeout(mouseoverTimer);
- mouseoverTimer = undefined;
+ function last(element) {
+ return element.lastElementChild.firstChild.nextElementSibling;
}
- }
- function mousedownShortcutListener(event1) {
- if (performance.now() - lastTouchTimestamp < 1111) {
- return;
+ function next(element) {
+ return element.activeElement.parentElement.nextElementSibling.firstChild.nextElementSibling.focus();
}
- const linkElement = event1.target.closest("a");
- if (event1.which > 1 || event1.metaKey || event1.ctrlKey) {
- return;
+ function previous(element) {
+ return element.activeElement.parentElement.previousElementSibling.firstChild.nextElementSibling.focus();
}
- if (!linkElement) {
- return;
+ function press(keyname) {
+ document.dispatchEvent(new KeyboardEvent("keydown", {
+ "key": keyname
+ }));
}
- linkElement.addEventListener("click", function(event) {
- if (event.detail == 1337) {
- return;
+ let selected;
+ if (submit === null) return;
+ submit.addEventListener("click", function(event) {
+ if (selected) {
+ event.preventDefault();
+ selected.focus();
+ return selected.click();
}
+ first(dropdown).focus();
+ press("ArrowDown");
+ document.activeElement.click();
+ });
+ [
+ "keyup",
+ "click"
+ ].forEach(function(event) {
+ form.addEventListener(event, function() {
+ if (document.activeElement.nodeName === "A") {
+ return selected = document.activeElement;
+ }
+ selected = undefined;
+ });
+ });
+ form.addEventListener("focusin", function() {
+ container.setAttribute("data-focus", "");
+ initialize();
+ });
+ form.addEventListener("submit", function(event) {
event.preventDefault();
- }, {
- capture: true,
- passive: false,
- once: true
+ return false;
});
- const customEvent = new MouseEvent("click", {
- view: window,
- bubbles: true,
- cancelable: false,
- detail: 1337
+ form.addEventListener("keydown", function(event) {
+ if (form.contains(event.target)) {
+ if (event.keyCode == 27) {
+ document.activeElement.blur();
+ dropdown.setAttribute("hidden", "");
+ container.removeAttribute("data-focus");
+ }
+ }
+ if (event.keyCode == 8) {
+ if (document.activeElement != query) {
+ event.preventDefault();
+ query.focus();
+ }
+ }
+ const head = first(dropdown);
+ const tail = last(dropdown);
+ if (event.keyCode == 40) {
+ event.preventDefault();
+ if (document.activeElement == query) head.focus();
+ else if (document.activeElement == tail) query.focus();
+ else next(document);
+ }
+ if (event.keyCode == 38) {
+ event.preventDefault();
+ if (document.activeElement == query) tail.focus();
+ else if (document.activeElement == head) query.focus();
+ else previous(document);
+ }
+ if (event.keyCode == 13) {
+ if (dropdown && document.activeElement == query) {
+ event.preventDefault();
+ head.focus();
+ head.click();
+ }
+ }
});
- linkElement.dispatchEvent(customEvent);
- }
- function isPreloadable(linkElement) {
- if (!linkElement || !linkElement.href) {
- return;
- }
- if (useWhitelist && !("instant" in linkElement.dataset)) {
- return;
- }
- if (!allowExternalLinks && linkElement.origin != location.origin && !("instant" in linkElement.dataset)) {
- return;
- }
- if (![
- "http:",
- "https:"
- ].includes(linkElement.protocol)) {
- return;
+ let scrolls = 0;
+ self.addEventListener("scroll", function() {
+ if (scrolls > 3) {
+ scrolls = 0;
+ document.activeElement.blur();
+ dropdown.setAttribute("hidden", "");
+ container.removeAttribute("data-focus");
+ }
+ scrolls++;
+ });
+ self.addEventListener("click", function(event) {
+ if (!form.contains(event.target) && !(document.activeElement === query) && !(document.activeElement === submit)) {
+ dropdown.setAttribute("hidden", "");
+ container.removeAttribute("data-focus");
+ }
+ });
+ function fetch(url, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function() {
+ if (http.readyState === 4 && http.status === 200 && callback) {
+ callback(http);
+ }
+ };
+ http.open("GET", url);
+ http.send();
+ }
+ function script(url) {
+ return new Promise(function(resolve, reject) {
+ const script = document.createElement("script");
+ script.onerror = reject;
+ script.onload = resolve;
+ if (document.currentScript) {
+ document.currentScript.parentNode.insertBefore(script, document.currentScript);
+ } else document.head.appendChild(script);
+ script.src = url;
+ });
}
- if (linkElement.protocol == "http:" && location.protocol == "https:") {
- return;
+ let data = {};
+ let boot = true;
+ const options = {
+ key: [
+ "title"
+ ]
+ };
+ function isEmpty(obj) {
+ return Object.keys(obj).length === 0;
}
- if (!allowQueryString && linkElement.search && !("instant" in linkElement.dataset)) {
- return;
+ function appendItemsTo(local, remote) {
+ const paginated = Object.keys(remote).includes("next_url");
+ if (isEmpty(local)) {
+ local = remote;
+ } else {
+ local.items = local.items.concat(remote.items);
+ }
+ if (paginated) {
+ fetch(remote.next_url, function(request) {
+ appendItemsTo(local, JSON.parse(request.responseText));
+ });
+ } else search(query.value, data.items, options);
+ data = local;
+ }
+ function initialize() {
+ if (boot) {
+ script(window.location.origin + "/js/fuzzysort.js").then(function() {
+ fetch("/index.json", function(request) {
+ appendItemsTo({}, JSON.parse(request.responseText));
+ search("", data.items, options);
+ boot = false;
+ });
+ [
+ "keyup",
+ "focusin"
+ ].forEach(function(event) {
+ query.addEventListener(event, function() {
+ if (data.items) search(query.value, data.items, options);
+ else {
+ boot = true;
+ initialize();
+ }
+ });
+ });
+ }).catch(function(error) {
+ console.error("ERROR: Failed to load fuzzy search", error);
+ });
+ }
}
- if (linkElement.hash && linkElement.pathname + linkElement.search == location.pathname + location.search) {
- return;
+ function escape(text) {
+ const escaped = document.createElement("textarea");
+ escaped.textContent = text;
+ return escaped.innerHTML;
+ }
+ function search(term, data, options) {
+ const results = fuzzysort.go(term, data, options);
+ let items = "";
+ if (results.length === 0 && term.length >= 0) {
+ let separator = "—";
+ if (term.length === 0) separator = "";
+ items = '<li><a tabindex="0">'.concat(escape(term), " ").concat(separator, " No Results Found</a></li>");
+ dropdown.removeAttribute("hidden");
+ container.setAttribute("data-focus", "");
+ } else {
+ dropdown.removeAttribute("hidden");
+ for(var string in results.slice(0, 10)){
+ const title = results[string].obj.title;
+ let highlight = fuzzysort.highlight(fuzzysort.single(escape(term), escape(title)), "<span>", "</span>");
+ if (highlight === null) highlight = title;
+ items = items + '\n<li>\n<a href="'.concat(results[string].obj.url, '" tabindex="0">').concat(highlight, "</a>\n</li>\n");
+ }
+ }
+ dropdown.innerHTML = items;
}
- if ("noInstant" in linkElement.dataset) {
- return;
+ });
+ });
+})();
+(function() {
+ function viewport(element) {
+ const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {
+ offset: {
+ top: -50,
+ left: 0,
+ bottom: -50,
+ right: 0
+ }
+ };
+ const view = element.getBoundingClientRect();
+ return view.top >= -options.offset.top && view.left >= -options.offset.left && view.bottom <= (self.innerHeight || document.documentElement.clientHeight) + options.offset.bottom && view.right <= (self.innerWidth || document.documentElement.clientWidth) + options.offset.right;
+ }
+ [
+ "scroll",
+ "DOMContentLoaded"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ let first = true;
+ let videos = document.querySelectorAll("video");
+ for(i = 0; i < videos.length; i++){
+ videos[i].autoplay = true;
+ videos[i].controls = true;
+ videos[i].loop = true;
+ videos[i].muted = true;
+ videos[i].playsinline = true;
+ videos[i].setAttribute("autoplay", true);
+ videos[i].setAttribute("controls", true);
+ videos[i].setAttribute("loop", true);
+ videos[i].setAttribute("muted", true);
+ videos[i].setAttribute("playsinline", true);
+ const onscreen = viewport(videos[i]);
+ if (first && onscreen) {
+ videos[i].play();
+ first = false;
+ } else {
+ videos[i].pause();
+ }
}
- return true;
+ });
+ });
+})();
+(function() {
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
- function preload(url) {
- if (prefetches.has(url)) {
- return;
- }
- const prefetcher = document.createElement("link");
- prefetcher.rel = "prefetch";
- prefetcher.href = url;
- document.head.appendChild(prefetcher);
- prefetches.add(url);
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function(s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ }while (el !== null && el.nodeType === 1)
+ return null;
+ };
+ }
+ }
+ const disabled = "0s";
+ function walk(children, callback) {
+ for(let i1 = 0; i1 < children.length; i1++){
+ callback(children[i1]);
+ walk(children[i1].children, callback);
+ }
+ }
+ self.addEventListener("mousemove", function(event) {
+ if (typeof event.target.closest !== "function") return;
+ tree = event.target.closest("figure") || event.target.closest("article");
+ if (tree !== null) {
+ walk(tree.children, function(element) {
+ const delay = self.getComputedStyle(element).getPropertyValue("transition-delay");
+ if (delay !== disabled) {
+ element.style.setProperty("visibility", "hidden");
+ }
+ });
+ walk(tree.children, function(element) {
+ const delay = self.getComputedStyle(element).getPropertyValue("transition-delay");
+ if (delay !== disabled) {
+ element.style.removeProperty("visibility");
+ }
+ });
}
});
})();
(function() {
- self.addEventListener("DOMContentLoaded", function() {
- const form = document.getElementById("search-form");
- const query = document.getElementById("search-input");
- document.getElementById("search-submit");
- const dropdown = document.getElementById("search-results");
- const container = document.getElementById("search-frame");
- form.addEventListener("focusin", function() {
- initialize();
- });
- form.addEventListener("submit", function(event) {
- event.preventDefault();
- return false;
- });
- form.addEventListener("keydown", function(event) {
- const head = dropdown.firstChild.nextElementSibling.firstChild.nextElementSibling;
- const tail = dropdown.lastElementChild.firstChild.nextElementSibling;
- if (query.contains(event.target)) {
- if (event.keyCode == 27) {
- document.activeElement.blur();
- dropdown.setAttribute("hidden", "");
- }
- }
- if (event.keyCode == 40) {
- event.preventDefault();
- if (document.activeElement == query) head.focus();
- else if (document.activeElement == tail) query.focus();
- else {
- document.activeElement.parentElement.nextElementSibling.firstChild.nextElementSibling.focus();
+ const cookiesDisabled = !navigator.cookieEnabled;
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Cannot persist form state due to cookie restrictions");
+ }
+ const storage = document.createEvent("Event");
+ storage.initEvent("storage", true, true);
+ [
+ "pageshow",
+ "URLChangedCustomEvent",
+ "DOMContentLoaded"
+ ].forEach(function(event) {
+ self.addEventListener(event, function(event) {
+ const input = Array.prototype.slice.call(document.querySelectorAll("form input"));
+ const select = Array.prototype.slice.call(document.querySelectorAll("form select"));
+ const textarea = Array.prototype.slice.call(document.querySelectorAll("form textarea"));
+ const summary = Array.prototype.slice.call(document.querySelectorAll("details summary"));
+ const states = input.concat(select).concat(textarea);
+ for(var i1 = 0; i1 < states.length; i1++){
+ const state = states[i1];
+ const sync = i1 === states.length - 1;
+ if (localStorage[state.id]) {
+ if (state.type === "radio" || state.type === "checkbox") {
+ if (localStorage[state.id] === "on") state.checked = true;
+ } else state.value = localStorage[state.id];
}
+ if (sync) self.dispatchEvent(storage);
+ state.addEventListener("change", function(event) {
+ localStorage[event.target.id] = event.target.value;
+ const group = document.querySelectorAll("input[name='".concat(event.target.name, "']"));
+ for(var j = 0; j < group.length; j++){
+ const member = group[j];
+ if ((member.type === "radio" || member.type === "checkbox") && !member.checked) {
+ localStorage[member.id] = "off";
+ }
+ }
+ self.dispatchEvent(new Event("storage"));
+ });
}
- if (event.keyCode == 38) {
- event.preventDefault();
- if (document.activeElement == query) tail.focus();
- else if (document.activeElement == head) query.focus();
- else {
- document.activeElement.parentElement.previousElementSibling.firstChild.nextElementSibling.focus();
+ for(var k = 0; k < summary.length; k++){
+ let child = summary[k];
+ let details = child.parentElement;
+ if (details.id && details.nodeName === "DETAILS") {
+ sessionStorage[details.id] === "false" && details.removeAttribute("open");
+ sessionStorage[details.id] === "true" && details.setAttribute("open", true);
+ child.addEventListener("click", function(event) {
+ let child = event.target.nodeName === "SUMMARY" && event.target || event.target.parentElement;
+ let details = child.parentElement;
+ if (details.id && details.nodeName === "DETAILS") {
+ sessionStorage[details.id] = !details.open;
+ }
+ });
}
}
- if (event.keyCode == 8) {
- if (document.activeElement != query) {
- event.preventDefault();
- query.focus();
+ });
+ });
+ [
+ "storage"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ let stylesheet;
+ stylesheet = document.querySelector('link[href$="default-simple.css"]');
+ if (localStorage["config.layout.simple"] === "on") stylesheet.rel = "stylesheet";
+ if (localStorage["config.layout.default"] === "on") stylesheet.rel = "alternate stylesheet";
+ stylesheet = document.querySelector('link[href$="default-fast.css"]');
+ if (localStorage["config.navigation.fast"] === "on") stylesheet.rel = "stylesheet";
+ if (localStorage["config.navigation.slow"] === "on") stylesheet.rel = "alternate stylesheet";
+ for(var i1 = 0; i1 < document.styleSheets.length; i1++){
+ let stylesheet = document.styleSheets[i1];
+ for(var k = 0; k < stylesheet.rules.length; k++){
+ let media = stylesheet.rules[k].media;
+ if (media && media.mediaText.includes("prefers-color-scheme")) {
+ if (localStorage["config.theme.light"] === "on") {
+ media.mediaText = "(prefers-color-scheme: dark)";
+ if (getComputedStyle(document.body).getPropertyValue("color-scheme") === "dark") {
+ media.mediaText = "(prefers-color-scheme: light)";
+ }
+ }
+ if (localStorage["config.theme.auto"] === "on") {
+ media.mediaText = "(prefers-color-scheme: dark)";
+ }
+ if (localStorage["config.theme.dark"] === "on") {
+ media.mediaText = "(prefers-color-scheme: light)";
+ if (getComputedStyle(document.body).getPropertyValue("color-scheme") === "light") {
+ media.mediaText = "(prefers-color-scheme: dark)";
+ }
+ }
+ }
}
}
- if (event.keyCode == 13) {
- if (dropdown && document.activeElement == query) {
- event.preventDefault();
- head.focus();
- self.window.location = document.activeElement.href;
+ });
+ });
+ const early = setInterval(persistence, 4);
+ function persistence() {
+ if (document.styleSheets.length > 0) {
+ self.dispatchEvent(storage);
+ clearInterval(early);
+ }
+ }
+ self.addEventListener("DOMContentLoaded", function() {
+ self.dispatchEvent(storage);
+ clearInterval(early);
+ });
+})();
+(function() {
+ const timeout = 300;
+ const state = "on";
+ const key = "config.navigation.fast";
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function() {
+ if (callback && http.readyState === 4) {
+ if (http.status === 200) callback(http);
+ else {
+ console.error("ERROR: Unable to navigate", http);
+ self.location.href = url;
}
}
- });
- let scrolls = 0;
- self.addEventListener("scroll", function() {
- if (scrolls > 3) {
- scrolls = 0;
- document.activeElement.blur();
- dropdown.setAttribute("hidden", "");
- container.removeAttribute("data-focus");
+ };
+ http.open(method, url);
+ http.timeout = timeout;
+ http.send();
+ return http;
+ }
+ function styles(node) {
+ return node.nodeName === "LINK" && node.rel && node.rel.includes("stylesheet");
+ }
+ function scripts(node) {
+ return node.nodeName === "SCRIPT" && node.hasAttribute("src");
+ }
+ function filter(url, http) {
+ let live = document;
+ let node = live.head.childNodes.length;
+ let next = new DOMParser().parseFromString(http.responseText, "text/html");
+ if (next.doctype === null || !http.getResponseHeader("content-type").includes("text/html")) return false;
+ while(node--){
+ if (styles(live.head.childNodes[node]) || scripts(live.head.childNodes[node])) {} else {
+ live.head.removeChild(live.head.childNodes[node]);
}
- scrolls++;
- });
- document.addEventListener("click", function(event) {
- if (!form.contains(event.target)) {
- dropdown.setAttribute("hidden", "");
- container.removeAttribute("data-focus");
+ }
+ while(next.head.firstChild){
+ if (styles(next.head.firstChild) || scripts(next.head.firstChild)) {
+ next.head.removeChild(next.head.firstChild);
+ } else {
+ live.head.appendChild(next.head.firstChild);
}
- });
- function fetch_JSON(path, callback) {
- const httpRequest = new XMLHttpRequest();
- httpRequest.onreadystatechange = function() {
- if (httpRequest.readyState === 4) {
- if (httpRequest.status === 200) {
- const data = JSON.parse(httpRequest.responseText);
- if (callback) callback(data);
- }
- }
- };
- httpRequest.open("GET", path);
- httpRequest.send();
}
- function load_script(url) {
- return new Promise(function(resolve, reject) {
- const script = document.createElement("script");
- script.onerror = reject;
- script.onload = resolve;
- if (document.currentScript) {
- document.currentScript.parentNode.insertBefore(script, document.currentScript);
- } else {
- document.head.appendChild(script);
- }
- script.src = url;
- });
+ while(live.documentElement.attributes.length > 0){
+ live.documentElement.removeAttribute(live.documentElement.attributes[live.documentElement.attributes.length - 1].name);
}
- let first_run = true;
- function initialize() {
- if (first_run) {
- load_script(window.location.origin + "/js/fuzzysort.js").then(()=>{
- first_run = false;
- fetch_JSON("/index.json", function(data) {
- const options = {
- key: [
- "title"
- ]
- };
- query.addEventListener("keyup", function() {
- search(query.value, data.items, options);
- });
- query.addEventListener("focusin", function() {
- search(query.value, data.items, options);
- });
- search(query.value, data.items, options);
- });
- }).catch((error)=>{
- console.log("Error failed to load fuzzy sort: " + error);
+ while(next.documentElement.attributes.length > 0){
+ live.documentElement.setAttribute(next.documentElement.attributes[next.documentElement.attributes.length - 1].name, next.documentElement.attributes[next.documentElement.attributes.length - 1].value);
+ next.documentElement.removeAttribute(next.documentElement.attributes[next.documentElement.attributes.length - 1].name);
+ }
+ live.body.parentElement.replaceChild(next.body, live.body);
+ }
+ function persist() {
+ let persist = document.createElement("link");
+ persist.rel = "location";
+ persist.target = JSON.stringify(self.location);
+ document.head.appendChild(persist);
+ }
+ self.addEventListener("DOMContentLoaded", function() {
+ if (localStorage[key] !== state) return;
+ persist();
+ });
+ self.addEventListener("popstate", function(event) {
+ if (localStorage[key] !== state) return;
+ const link = JSON.parse(document.querySelector('link[rel="location"]').target);
+ const url = event.target.location;
+ const hashed = link.pathname === url.pathname;
+ if (hashed) return;
+ fetch(url, "GET", function(http) {
+ if (filter(url, http) === false) return self.location.href = url;
+ persist();
+ self.document.dispatchEvent(new CustomEvent("URLChangedCustomEvent", {
+ bubbles: true
+ }));
+ });
+ });
+ self.addEventListener("click", function(event) {
+ if (localStorage[key] !== state) return;
+ const links = document.querySelectorAll("a");
+ for(let i1 = 0; i1 < links.length; i1++){
+ const active = links[i1].contains(event.target);
+ const change = self.location.href !== links[i1].href;
+ const view = links[i1].attributes.hasOwnProperty("download") === false;
+ const local = self.location.origin === links[i1].origin && links[i1].target !== "_self";
+ const hashed = self.location.pathname === links[i1].pathname && links[i1].href.includes("#");
+ if (active && local && change && view && hashed === false) {
+ event.preventDefault();
+ const url = links[i1].href;
+ links[i1].style.cursor = "wait";
+ fetch(url, "GET", function(http) {
+ links[i1].removeAttribute("style");
+ if (filter(url, http) === false) return self.location.href = url;
+ history.pushState({}, "", links[i1].href);
+ persist();
+ self.document.dispatchEvent(new CustomEvent("URLChangedCustomEvent", {
+ bubbles: true
+ }));
});
}
}
- function search(term, data, options) {
- const results = fuzzysort.go(term, data, options);
- let items = "";
- if (results.length === 0 && term.length >= 0) {
- let separator = "—";
- if (term.length === 0) separator = "";
- items = `
- <li>
- <a href="javascript: void(0)" tabindex="0">${term} ${separator} No Results Found</a>
- </li>
- `;
- dropdown.removeAttribute("hidden");
- container.setAttribute("data-focus", "");
- } else {
- dropdown.removeAttribute("hidden");
- for(const string in results.slice(0, 10)){
- let highlight = fuzzysort.highlight(fuzzysort.single(term, results[string].obj.title), "<span>", "</span>");
- if (highlight === null) {
- highlight = results[string].obj.title;
+ });
+})();
+(function() {
+ const relative = new Intl.RelativeTimeFormat("en", {
+ localeMatcher: "best fit",
+ numeric: "always",
+ style: "long"
+ });
+ function viewport(element) {
+ const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {
+ offset: 250
+ };
+ const view = element.getBoundingClientRect();
+ return view.top >= -options.offset && view.left >= -options.offset && view.bottom <= (self.innerHeight || document.documentElement.clientHeight) + options.offset && view.right <= (self.innerWidth || document.documentElement.clientWidth) + options.offset;
+ }
+ const date = function(update) {
+ const elements = document.querySelectorAll("time");
+ for(let i1 = 0; i1 < elements.length; ++i1){
+ const offscreen = !viewport(elements[i1]);
+ const hidden = elements[i1].offsetParent === null;
+ if (update === "viewport" && (offscreen || hidden)) continue;
+ (function(element) {
+ try {
+ if (element.dataset.type === "disabled") return;
+ const time = new Date(element.dateTime) || new Date();
+ const interval = (new Date().getTime() - time.getTime()) / 1000;
+ const seconds = Math.round(interval);
+ const minutes = Math.round(seconds / 60);
+ const hours = Math.round(minutes / 60);
+ const days = Math.round(hours / 24);
+ const past = Math.sign(seconds) === 1;
+ const future = Math.sign(seconds) === -1;
+ let tiny = function(string, place) {
+ return string.split(" ").slice(0, place).join(" ") + string.split(" ")[place].charAt(0);
+ };
+ if (element.dataset.type === "default") {
+ tiny = function(string) {
+ return string;
+ };
+ }
+ if (element.dataset.type === "localDate") {
+ return element.textContent = new Intl.DateTimeFormat([], {
+ dateStyle: "medium"
+ }).format(time).replace(",", "");
}
- items = items + `
- <li>
- <a href="${results[string].obj.url}" tabindex="0">${highlight}</a>
- </li>
- `;
+ if (element.dataset.type === "localTime") {
+ return element.textContent = new Intl.DateTimeFormat([], {
+ hour12: false,
+ timeStyle: "short"
+ }).format(time) + " " + new Intl.DateTimeFormat([], {
+ timeZoneName: "short"
+ }).format(time).split(" ")[1];
+ }
+ if (past) {
+ if (seconds <= 60) {
+ return element.textContent = tiny(relative.format(-1 * seconds, "second"), 1);
+ }
+ if (minutes <= 120) {
+ return element.textContent = tiny(relative.format(-1 * minutes, "minute"), 1);
+ }
+ if (hours <= 48) {
+ return element.textContent = tiny(relative.format(-1 * hours, "hour"), 1);
+ }
+ if (days <= 7) {
+ return element.textContent = tiny(relative.format(-1 * days, "day"), 1);
+ }
+ }
+ if (future) {
+ if (-1 * days >= 4) {
+ return element.textContent = tiny(relative.format(-1 * days, "day"), 2);
+ }
+ if (-1 * hours >= 3) {
+ return element.textContent = tiny(relative.format(-1 * hours, "hour"), 2);
+ }
+ if (-1 * minutes >= 2) {
+ return element.textContent = tiny(relative.format(-1 * minutes, "minute"), 2);
+ }
+ if (-1 * seconds >= 1) {
+ return element.textContent = tiny(relative.format(-1 * seconds, "second"), 2);
+ }
+ }
+ } catch (error) {
+ console.error("ERROR: Relative time resolution failed", error);
}
- }
- dropdown.innerHTML = items;
+ })(elements[i1]);
}
+ };
+ const substitution = setInterval(date, 4);
+ [
+ "scroll",
+ "URLChangedCustomEvent"
+ ].forEach(function(event) {
+ self.addEventListener(event, function() {
+ date("viewport");
+ });
+ });
+ self.addEventListener("DOMContentLoaded", function() {
+ setTimeout(function() {
+ clearInterval(substitution);
+ setInterval(function() {
+ date("viewport");
+ }, 1000);
+ }, 1000);
});
})();
-console.log("Surface Control: OK");
+console.log("INFO: Surface Control Complete"); \ No newline at end of file
diff --git a/assets/schemas/atom-v1.0.rng b/assets/schemas/atom-v1.0.rng
new file mode 100644
index 0000000..da47078
--- /dev/null
+++ b/assets/schemas/atom-v1.0.rng
@@ -0,0 +1,605 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ -*- rnc -*-
+ RELAX NG Compact Syntax Grammar for the
+ Atom Format Specification Version 11
+-->
+<grammar
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:s="http://www.ascc.net/xml/schematron"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns="http://relaxng.org/ns/structure/1.0"
+ ns="http://www.w3.org/1999/xhtml"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ >
+ <start>
+ <choice>
+ <ref name="atomFeed"/>
+ <ref name="atomEntry"/>
+ </choice>
+ </start>
+ <!-- Common attributes -->
+ <define name="atomCommonAttributes">
+ <optional>
+ <attribute name="xml:base">
+ <ref name="atomUri"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="xml:lang">
+ <ref name="atomLanguageTag"/>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <ref name="undefinedAttribute"/>
+ </zeroOrMore>
+ </define>
+ <!-- Text Constructs -->
+ <define name="atomPlainTextConstruct">
+ <ref name="atomCommonAttributes"/>
+ <optional>
+ <attribute name="type">
+ <choice>
+ <value>text</value>
+ <value>html</value>
+ </choice>
+ </attribute>
+ </optional>
+ <text/>
+ </define>
+ <define name="atomXHTMLTextConstruct">
+ <ref name="atomCommonAttributes"/>
+ <attribute name="type">
+ <value>xhtml</value>
+ </attribute>
+ <ref name="xhtmlDiv"/>
+ </define>
+ <define name="atomTextConstruct">
+ <choice>
+ <ref name="atomPlainTextConstruct"/>
+ <ref name="atomXHTMLTextConstruct"/>
+ </choice>
+ </define>
+ <!-- Person Construct -->
+ <define name="atomPersonConstruct">
+ <ref name="atomCommonAttributes"/>
+ <interleave>
+ <element name="atom:name">
+ <text/>
+ </element>
+ <optional>
+ <element name="atom:uri">
+ <ref name="atomUri"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="atom:email">
+ <ref name="atomEmailAddress"/>
+ </element>
+ </optional>
+ <zeroOrMore>
+ <ref name="extensionElement"/>
+ </zeroOrMore>
+ </interleave>
+ </define>
+ <!-- Date Construct -->
+ <define name="atomDateConstruct">
+ <ref name="atomCommonAttributes"/>
+ <data type="dateTime"/>
+ </define>
+ <!-- atom:feed -->
+ <define name="atomFeed">
+ <element name="atom:feed">
+ <s:rule context="atom:feed">
+ <s:assert test="atom:author or not(atom:entry[not(atom:author)])">An atom:feed must have an atom:author unless all of its atom:entry children have an atom:author.</s:assert>
+ </s:rule>
+ <ref name="atomCommonAttributes"/>
+ <interleave>
+ <zeroOrMore>
+ <ref name="atomAuthor"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="atomCategory"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="atomContributor"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomGenerator"/>
+ </optional>
+ <optional>
+ <ref name="atomIcon"/>
+ </optional>
+ <ref name="atomId"/>
+ <zeroOrMore>
+ <ref name="atomLink"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomLogo"/>
+ </optional>
+ <optional>
+ <ref name="atomRights"/>
+ </optional>
+ <optional>
+ <ref name="atomSubtitle"/>
+ </optional>
+ <ref name="atomTitle"/>
+ <ref name="atomUpdated"/>
+ <zeroOrMore>
+ <ref name="extensionElement"/>
+ </zeroOrMore>
+ </interleave>
+ <zeroOrMore>
+ <ref name="atomEntry"/>
+ </zeroOrMore>
+ </element>
+ </define>
+ <!-- atom:entry -->
+ <define name="atomEntry">
+ <element name="atom:entry">
+ <s:rule context="atom:entry">
+ <s:assert test="atom:link[@rel='alternate'] or atom:link[not(@rel)] or atom:content">An atom:entry must have at least one atom:link element with a rel attribute of 'alternate' or an atom:content.</s:assert>
+ </s:rule>
+ <s:rule context="atom:entry">
+ <s:assert test="atom:author or ../atom:author or atom:source/atom:author">An atom:entry must have an atom:author if its feed does not.</s:assert>
+ </s:rule>
+ <ref name="atomCommonAttributes"/>
+ <interleave>
+ <zeroOrMore>
+ <ref name="atomAuthor"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="atomCategory"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomContent"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="atomContributor"/>
+ </zeroOrMore>
+ <ref name="atomId"/>
+ <zeroOrMore>
+ <ref name="atomLink"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomPublished"/>
+ </optional>
+ <optional>
+ <ref name="atomRights"/>
+ </optional>
+ <optional>
+ <ref name="atomSource"/>
+ </optional>
+ <optional>
+ <ref name="atomSummary"/>
+ </optional>
+ <ref name="atomTitle"/>
+ <ref name="atomUpdated"/>
+ <zeroOrMore>
+ <ref name="extensionElement"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+ <!-- atom:content -->
+ <define name="atomInlineTextContent">
+ <element name="atom:content">
+ <ref name="atomCommonAttributes"/>
+ <optional>
+ <attribute name="type">
+ <choice>
+ <value>text</value>
+ <value>html</value>
+ </choice>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <text/>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="atomInlineXHTMLContent">
+ <element name="atom:content">
+ <ref name="atomCommonAttributes"/>
+ <attribute name="type">
+ <value>xhtml</value>
+ </attribute>
+ <ref name="xhtmlDiv"/>
+ </element>
+ </define>
+ <define name="atomInlineOtherContent">
+ <element name="atom:content">
+ <ref name="atomCommonAttributes"/>
+ <optional>
+ <attribute name="type">
+ <ref name="atomMediaType"/>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="atomOutOfLineContent">
+ <element name="atom:content">
+ <ref name="atomCommonAttributes"/>
+ <optional>
+ <attribute name="type">
+ <ref name="atomMediaType"/>
+ </attribute>
+ </optional>
+ <attribute name="src">
+ <ref name="atomUri"/>
+ </attribute>
+ <empty/>
+ </element>
+ </define>
+ <define name="atomContent">
+ <choice>
+ <ref name="atomInlineTextContent"/>
+ <ref name="atomInlineXHTMLContent"/>
+ <ref name="atomInlineOtherContent"/>
+ <ref name="atomOutOfLineContent"/>
+ </choice>
+ </define>
+ <!-- atom:author -->
+ <define name="atomAuthor">
+ <element name="atom:author">
+ <ref name="atomPersonConstruct"/>
+ </element>
+ </define>
+ <!-- atom:category -->
+ <define name="atomCategory">
+ <element name="atom:category">
+ <ref name="atomCommonAttributes"/>
+ <attribute name="term"/>
+ <optional>
+ <attribute name="scheme">
+ <ref name="atomUri"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="label"/>
+ </optional>
+ <ref name="undefinedContent"/>
+ </element>
+ </define>
+ <!-- atom:contributor -->
+ <define name="atomContributor">
+ <element name="atom:contributor">
+ <ref name="atomPersonConstruct"/>
+ </element>
+ </define>
+ <!-- atom:generator -->
+ <define name="atomGenerator">
+ <element name="atom:generator">
+ <ref name="atomCommonAttributes"/>
+ <optional>
+ <attribute name="uri">
+ <ref name="atomUri"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="version"/>
+ </optional>
+ <text/>
+ </element>
+ </define>
+ <!-- atom:icon -->
+ <define name="atomIcon">
+ <element name="atom:icon">
+ <ref name="atomCommonAttributes"/>
+ <ref name="atomUri"/>
+ </element>
+ </define>
+ <!-- atom:id -->
+ <define name="atomId">
+ <element name="atom:id">
+ <ref name="atomCommonAttributes"/>
+ <ref name="atomUri"/>
+ </element>
+ </define>
+ <!-- atom:logo -->
+ <define name="atomLogo">
+ <element name="atom:logo">
+ <ref name="atomCommonAttributes"/>
+ <ref name="atomUri"/>
+ </element>
+ </define>
+ <!-- atom:link -->
+ <define name="atomLink">
+ <element name="atom:link">
+ <ref name="atomCommonAttributes"/>
+ <attribute name="href">
+ <ref name="atomUri"/>
+ </attribute>
+ <optional>
+ <attribute name="rel">
+ <choice>
+ <ref name="atomNCName"/>
+ <ref name="atomUri"/>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="type">
+ <ref name="atomMediaType"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="hreflang">
+ <ref name="atomLanguageTag"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <optional>
+ <attribute name="length"/>
+ </optional>
+ <ref name="undefinedContent"/>
+ </element>
+ </define>
+ <!-- atom:published -->
+ <define name="atomPublished">
+ <element name="atom:published">
+ <ref name="atomDateConstruct"/>
+ </element>
+ </define>
+ <!-- atom:rights -->
+ <define name="atomRights">
+ <element name="atom:rights">
+ <ref name="atomTextConstruct"/>
+ </element>
+ </define>
+ <!-- atom:source -->
+ <define name="atomSource">
+ <element name="atom:source">
+ <ref name="atomCommonAttributes"/>
+ <interleave>
+ <zeroOrMore>
+ <ref name="atomAuthor"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="atomCategory"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="atomContributor"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomGenerator"/>
+ </optional>
+ <optional>
+ <ref name="atomIcon"/>
+ </optional>
+ <optional>
+ <ref name="atomId"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="atomLink"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="atomLogo"/>
+ </optional>
+ <optional>
+ <ref name="atomRights"/>
+ </optional>
+ <optional>
+ <ref name="atomSubtitle"/>
+ </optional>
+ <optional>
+ <ref name="atomTitle"/>
+ </optional>
+ <optional>
+ <ref name="atomUpdated"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="extensionElement"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+ <!-- atom:subtitle -->
+ <define name="atomSubtitle">
+ <element name="atom:subtitle">
+ <ref name="atomTextConstruct"/>
+ </element>
+ </define>
+ <!-- atom:summary -->
+ <define name="atomSummary">
+ <element name="atom:summary">
+ <ref name="atomTextConstruct"/>
+ </element>
+ </define>
+ <!-- atom:title -->
+ <define name="atomTitle">
+ <element name="atom:title">
+ <ref name="atomTextConstruct"/>
+ </element>
+ </define>
+ <!-- atom:updated -->
+ <define name="atomUpdated">
+ <element name="atom:updated">
+ <ref name="atomDateConstruct"/>
+ </element>
+ </define>
+ <!-- Low-level simple types -->
+ <define name="atomNCName">
+ <data type="string">
+ <param name="minLength">1</param>
+ <param name="pattern">[^:]*</param>
+ </data>
+ </define>
+ <!-- Whatever a media type is, it contains at least one slash -->
+ <define name="atomMediaType">
+ <data type="string">
+ <param name="pattern">.+/.+</param>
+ </data>
+ </define>
+ <!-- As defined in RFC 3066 -->
+ <define name="atomLanguageTag">
+ <data type="string">
+ <param name="pattern">[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*</param>
+ </data>
+ </define>
+ <!--
+ Unconstrained; it's not entirely clear how IRI fit into
+ xsd:anyURI so let's not try to constrain it here
+ -->
+ <define name="atomUri">
+ <text/>
+ </define>
+ <!-- Whatever an email address is, it contains at least one @ -->
+ <define name="atomEmailAddress">
+ <data type="string">
+ <param name="pattern">.+@.+</param>
+ </data>
+ </define>
+ <!-- Simple Extension -->
+ <define name="simpleExtensionElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName ns="http://www.w3.org/2005/Atom"/>
+ </except>
+ </anyName>
+ <text/>
+ </element>
+ </define>
+ <!-- Structured Extension -->
+ <define name="structuredExtensionElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName ns="http://www.w3.org/2005/Atom"/>
+ </except>
+ </anyName>
+ <choice>
+ <group>
+ <oneOrMore>
+ <attribute>
+ <anyName/>
+ </attribute>
+ </oneOrMore>
+ <zeroOrMore>
+ <choice>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </group>
+ <group>
+ <zeroOrMore>
+ <attribute>
+ <anyName/>
+ </attribute>
+ </zeroOrMore>
+ <group>
+ <optional>
+ <text/>
+ </optional>
+ <oneOrMore>
+ <ref name="anyElement"/>
+ </oneOrMore>
+ <zeroOrMore>
+ <choice>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </group>
+ </group>
+ </choice>
+ </element>
+ </define>
+ <!-- Other Extensibility -->
+ <define name="extensionElement">
+ <choice>
+ <ref name="simpleExtensionElement"/>
+ <ref name="structuredExtensionElement"/>
+ </choice>
+ </define>
+ <define name="undefinedAttribute">
+ <attribute>
+ <anyName>
+ <except>
+ <name>xml:base</name>
+ <name>xml:lang</name>
+ <nsName ns=""/>
+ </except>
+ </anyName>
+ </attribute>
+ </define>
+ <define name="undefinedContent">
+ <zeroOrMore>
+ <choice>
+ <text/>
+ <ref name="anyForeignElement"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+ <define name="anyElement">
+ <element>
+ <anyName/>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="anyForeignElement">
+ <element>
+ <anyName>
+ <except>
+ <nsName ns="http://www.w3.org/2005/Atom"/>
+ </except>
+ </anyName>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyElement"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <!-- XHTML -->
+ <define name="anyXHTML">
+ <element>
+ <nsName/>
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyXHTML"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+ <define name="xhtmlDiv">
+ <element name="xhtml:div">
+ <zeroOrMore>
+ <choice>
+ <attribute>
+ <anyName/>
+ </attribute>
+ <text/>
+ <ref name="anyXHTML"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+</grammar>
+<!-- EOF -->
diff --git a/assets/schemas/jsonfeed-v1.1.json b/assets/schemas/jsonfeed-v1.1.json
new file mode 100644
index 0000000..0d6653d
--- /dev/null
+++ b/assets/schemas/jsonfeed-v1.1.json
@@ -0,0 +1,297 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "JSON Feed",
+ "description": "JSON Feed Version 1.1",
+ "type": "object",
+ "properties": {
+ "version": {
+ "description": "The URL of the version of the format the feed uses. This should appear at the very top.",
+ "type": "string",
+ "format": "uri",
+ "enum": [
+ "https://jsonfeed.org/version/1",
+ "https://jsonfeed.org/version/1.1"
+ ]
+ },
+ "title": {
+ "description": "The name of the feed, which will often correspond to the name of the website (blog, for instance), though not necessarily.",
+ "type": "string"
+ },
+ "home_page_url": {
+ "description": "The URL of the resource that the feed describes. This resource may or may not actually be a “home” page, but it should be an HTML page. If a feed is published on the public web, this should be considered as required.",
+ "type": "string",
+ "format": "uri"
+ },
+ "feed_url": {
+ "description": "The URL of the feed, serves as the unique identifier for the feed. This should be considered required for feeds on the public web.",
+ "type": "string",
+ "format": "uri"
+ },
+ "description": {
+ "description": "Provides more detail, beyond the title, on what the feed is about. A feed reader may display this text.",
+ "type": "string"
+ },
+ "user_comment": {
+ "description": "A description of the purpose of the feed. This is for the use of people looking at the raw JSON, and should be ignored by feed readers.",
+ "type": "string"
+ },
+ "next_url": {
+ "description": "The URL of a feed that provides the next n items, where n is determined by the publisher. This allows for pagination, but with the expectation that reader software is not required to use it and probably won’t use it very often.",
+ "type": "string",
+ "format": "uri"
+ },
+ "icon": {
+ "description": "The URL of an image for the feed suitable to be used in a timeline, much the way an avatar might be used. It should be square and relatively large — such as 512 x 512 pixels — so that it can be scaled-down and so that it can look good on retina displays. It should use transparency where appropriate, since it may be rendered on a non-white background.",
+ "type": "string",
+ "format": "uri"
+ },
+ "favicon": {
+ "description": "The URL of an image for the feed suitable to be used in a source list. It should be square and relatively small, but not smaller than 64 x 64 pixels (so that it can look good on retina displays). This image should use transparency where appropriate, since it may be rendered on a non-white background.",
+ "type": "string",
+ "format": "uri"
+ },
+ "author": {
+ "description": "The feed author.",
+ "allOf": [
+ {
+ "$ref": "#/definitions/author"
+ }
+ ]
+ },
+ "authors": {
+ "description": "One or more feed authors.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/author"
+ }
+ },
+ "language": {
+ "description": "The primary language for the feed in the format specified in RFC 5646. The value is usually a 2-letter language tag from ISO 639-1, optionally followed by a region tag.",
+ "type": "string"
+ },
+ "expired": {
+ "description": "Whether or not the feed is finished — that is, whether or not it will ever update again. A feed for a temporary event, such as an instance of the Olympics, could expire. If the value is true, then it’s expired. Any other value, or the absence of expired, means the feed may continue to update.",
+ "type": "boolean"
+ },
+ "hubs": {
+ "description": "Describes endpoints that can be used to subscribe to real-time notifications from the publisher of this feed.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "description": "Describes the protocol used to talk with the hub, such as “rssCloud” or “WebSub.”",
+ "type": "string"
+ },
+ "url": {
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "patternProperties": {
+ "^_[a-zA-Z][^.]*$": {
+ "$ref": "#/definitions/extension"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "type",
+ "url"
+ ]
+ }
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "Unique for that item for that feed over time. If an item is ever updated, the id should be unchanged. New items should never use a previously-used id. Ideally, the id is the full URL of the resource described by the item, since URLs make great unique identifiers.",
+ "type": "string"
+ },
+ "url": {
+ "description": "The URL of the resource described by the item. It’s the permalink. This may be the same as the id.",
+ "type": "string",
+ "format": "uri"
+ },
+ "external_url": {
+ "description": "The URL of a page elsewhere. This is especially useful for linkblogs. If url links to where you’re talking about a thing, then external_url links to the thing you’re talking about.",
+ "type": "string",
+ "format": "uri"
+ },
+ "title": {
+ "description": "Plain text. Microblog items in particular may omit titles.",
+ "type": "string"
+ },
+ "content_html": {
+ "description": "The HTML of the item.",
+ "type": "string"
+ },
+ "content_text": {
+ "description": "The plain text of the item.",
+ "type": "string"
+ },
+ "summary": {
+ "description": "A plain text sentence or two describing the item. This might be presented in a timeline, for instance, where a detail view would display all of content_html or content_text.",
+ "type": "string"
+ },
+ "image": {
+ "description": "The URL of the main image for the item. This image may also appear in the content_html — if so, it’s a hint to the feed reader that this is the main, featured image. Feed readers may use the image as a preview (probably resized as a thumbnail and placed in a timeline).",
+ "type": "string",
+ "format": "uri"
+ },
+ "banner_image": {
+ "description": "The URL of an image to use as a banner. Some blogging systems (such as Medium) display a different banner image chosen to go with each post, but that image wouldn’t otherwise appear in the content_html. A feed reader with a detail view may choose to show this banner image at the top of the detail view, possibly with the title overlaid.",
+ "type": "string",
+ "format": "uri"
+ },
+ "date_published": {
+ "description": "The date in RFC 3339 format.",
+ "type": "string",
+ "format": "date-time"
+ },
+ "date_modified": {
+ "description": "The modification date in RFC 3339 format.",
+ "type": "string",
+ "format": "date-time"
+ },
+ "author": {
+ "description": "The author of the item.",
+ "allOf": [
+ {
+ "$ref": "#/definitions/author"
+ }
+ ]
+ },
+ "authors": {
+ "description": "The authors of the item.",
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/author"
+ }
+ },
+ "tags": {
+ "description": "Can have any plain text values you want. Tags tend to be just one word, but they may be anything. Note: they are not the equivalent of Twitter hashtags. Some blogging systems and other feed formats call these categories.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "language": {
+ "description": "The language for this item, using the format specified in RFC 5646. The value can be different than the primary language for the feed when a specific item is written in a different language than other items in the feed.",
+ "type": "string"
+ },
+ "attachments": {
+ "description": "Lists related resources. Podcasts, for instance, would include an attachment that’s an audio or video file.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "url": {
+ "description": "The location of the attachment.",
+ "type": "string",
+ "format": "uri"
+ },
+ "mime_type": {
+ "description": "The type of the attachment, such as “audio/mpeg.”",
+ "type": "string"
+ },
+ "title": {
+ "description": "A name for the attachment. Important: if there are multiple attachments, and two or more have the exact same title (when title is present), then they are considered as alternate representations of the same thing. In this way a podcaster, for instance, might provide an audio recording in different formats.",
+ "type": "string"
+ },
+ "size_in_bytes": {
+ "description": "How large the file is.",
+ "type": "number"
+ },
+ "duration_in_seconds": {
+ "description": "How long it takes to listen to or watch, when played at normal speed.",
+ "type": "number"
+ }
+ },
+ "patternProperties": {
+ "^_[a-zA-Z][^.]*$": {
+ "$ref": "#/definitions/extension"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "url",
+ "mime_type"
+ ]
+ }
+ }
+ },
+ "patternProperties": {
+ "^_[a-zA-Z][^.]*$": {
+ "$ref": "#/definitions/extension"
+ }
+ },
+ "additionalProperties": false,
+ "anyOf": [
+ {
+ "required": [
+ "content_html"
+ ]
+ },
+ {
+ "required": [
+ "content_text"
+ ]
+ }
+ ],
+ "required": [
+ "id"
+ ]
+ }
+ }
+ },
+ "patternProperties": {
+ "^_[a-zA-Z][^.]*$": {
+ "$ref": "#/definitions/extension"
+ }
+ },
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "title",
+ "items"
+ ],
+ "definitions": {
+ "author": {
+ "title": "Author",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "The author’s name.",
+ "type": "string"
+ },
+ "url": {
+ "description": "The URL of a site owned by the author. It could be a blog, micro-blog, Twitter account, and so on. Ideally the linked-to page provides a way to contact the author, but that’s not required. The URL could be a mailto: link.",
+ "type": "string",
+ "format": "uri"
+ },
+ "avatar": {
+ "description": "The URL for an image for the author. It should be square and relatively large — such as 512 x 512 pixels — and should use transparency where appropriate, since it may be rendered on a non-white background.",
+ "type": "string",
+ "format": "uri"
+ }
+ },
+ "minProperties": 1,
+ "patternProperties": {
+ "^_[a-zA-Z][^.]*$": {
+ "$ref": "#/definitions/extension"
+ }
+ },
+ "additionalProperties": false
+ },
+ "extension": {
+ "title": "Extension",
+ "type": "object",
+ "patternProperties": {
+ "^[^.]*$": {}
+ },
+ "additionalProperties": false
+ }
+ }
+}
diff --git a/assets/schemas/rss-v2.0.rng b/assets/schemas/rss-v2.0.rng
new file mode 100644
index 0000000..31708ca
--- /dev/null
+++ b/assets/schemas/rss-v2.0.rng
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns="http://relaxng.org/ns/structure/1.0"
+ ns=""
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ >
+ <start>
+ <element name="rss">
+ <attribute name="version">
+ <data type="decimal"/>
+ </attribute>
+ <element name="channel">
+ <ref name="title"/>
+ <ref name="link"/>
+ <ref name="description"/>
+ <element name="language">
+ <data type="NCName"/>
+ </element>
+ <element name="category">
+ <data type="NCName"/>
+ </element>
+ <element name="generator">
+ <text/>
+ </element>
+ <element name="lastBuildDate">
+ <text/>
+ </element>
+ <element name="image">
+ <ref name="title"/>
+ <element name="url">
+ <text/>
+ </element>
+ <ref name="link"/>
+ </element>
+ <oneOrMore>
+ <element name="atom:link">
+ <attribute name="href"/>
+ <attribute name="rel">
+ <data type="NCName"/>
+ </attribute>
+ <optional>
+ <attribute name="type"/>
+ </optional>
+ </element>
+ </oneOrMore>
+ <oneOrMore>
+ <element name="item">
+ <ref name="title"/>
+ <ref name="link"/>
+ <element name="pubDate">
+ <text/>
+ </element>
+ <element name="guid">
+ <text/>
+ </element>
+ <ref name="description"/>
+ <element name="atom:author">
+ <element name="atom:name">
+ <text/>
+ </element>
+ <element name="atom:uri">
+ <text/>
+ </element>
+ </element>
+ </element>
+ </oneOrMore>
+ </element>
+ </element>
+ </start>
+ <define name="title">
+ <element name="title">
+ <text/>
+ </element>
+ </define>
+ <define name="link">
+ <element name="link">
+ <text/>
+ </element>
+ </define>
+ <define name="description">
+ <element name="description">
+ <text/>
+ </element>
+ </define>
+</grammar>
diff --git a/assets/schemas/rss-v2.0.xsd b/assets/schemas/rss-v2.0.xsd
new file mode 100644
index 0000000..37068ae
--- /dev/null
+++ b/assets/schemas/rss-v2.0.xsd
@@ -0,0 +1,383 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="rss" type="rss"/>
+ <xsd:complexType name="rss">
+ <xsd:sequence>
+ <xsd:element name="channel" type="channel" maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="version"/>
+ </xsd:complexType>
+ <xsd:simpleType name="version">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="2.0"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:complexType name="channel">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" maxOccurs="1" minOccurs="1">
+ <xsd:annotation>
+ <xsd:documentation>
+ The name of the channel. It's how people refer
+ to your service. If you have an HTML website
+ that contains the same information as your RSS
+ file, the title of your channel should be the
+ same as the title of your website.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="link" type="xsd:string" maxOccurs="1" minOccurs="1">
+ <xsd:annotation>
+ <xsd:documentation>
+ The URL to the HTML website corresponding to the
+ channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" type="xsd:string" maxOccurs="1" minOccurs="1">
+ <xsd:annotation>
+ <xsd:documentation>
+ Phrase or sentence describing the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="language" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The language the channel is written in. This
+ allows aggregators to group all Italian language
+ sites, for example, on a single page. A list of
+ allowable values for this element, as provided
+ by Netscape, is here
+ [http://www.rssboard.org/rss-language-codes].
+ You may also use values defined by the W3C
+ [http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes].
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="copyright" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Copyright notice for content in the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="managingEditor" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Email address for person responsible for
+ editorial content.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="webMaster" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Email address for person responsible for
+ technical issues relating to channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="pubDate" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The publication date for the content in the
+ channel. For example, the New York Times
+ publishes on a daily basis, the publication date
+ flips once every 24 hours. That's when the
+ pubDate of the channel changes. All date-times
+ in RSS conform to the Date and Time
+ Specification of RFC 822, with the exception
+ that the year may be expressed with two
+ characters or four characters (four preferred).
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="category" type="category" maxOccurs="unbounded" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify one or more categories that the channel
+ belongs to. Follows the same rules as the
+ &lt;item&gt;-level category element.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="generator" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ A string indicating the program used to generate
+ the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="lastBuildDate" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The last time the content of the channel
+ changed.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="docs" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ A URL that points to the documentation for the
+ format used in the RSS file. It's probably a
+ pointer to this page. It's for people who might
+ stumble across an RSS file on a Web server 25
+ years from now and wonder what it is.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="cloud" type="cloud" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Allows processes to register with a cloud to be
+ notified of updates to the channel, implementing
+ a lightweight publish-subscribe protocol for RSS
+ feeds. More info here.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="ttl" type="xsd:int" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ ttl stands for time to live. It's a number of
+ minutes that indicates how long a channel can be
+ cached before refreshing from the source.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="image" type="image" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a GIF, JPEG or PNG image that can be
+ displayed with the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="rating" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The PICS [http://www.w3.org/PICS/] rating for
+ the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="textInput" type="textInput" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specifies a text input box that can be displayed
+ with the channel.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="skipHours" type="skipHours" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ A hint for aggregators telling them which hours
+ they can skip. This element contains up to 24
+ &lt;hour&gt; sub-elements whose value is a
+ number between 0 and 23, representing a time in
+ GMT, when aggregators, if they support the
+ feature, may not read the channel on hours
+ listed in the &lt;skipHours&gt; element. The
+ hour beginning at midnight is hour zero.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="skipDays" type="skipDays" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ A hint for aggregators telling them which days
+ they can skip. This element contains up to seven
+ &lt;day&gt;
+ sub-elements whose value is Monday, Tuesday,
+ Wednesday, Thursday, Friday, Saturday or
+ Sunday. Aggregators may not read the channel
+ during days listed in the
+ &lt;skipDays&gt;element.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="item" type="item" maxOccurs="unbounded" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="cloud">
+ <xsd:attribute name="domain" type="xsd:string"/>
+ <xsd:attribute name="port">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int">
+ <xsd:maxInclusive value="65536"/>
+ <xsd:minInclusive value="0"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="path" type="xsd:string"/>
+ <xsd:attribute name="registerProcedure" type="xsd:string"/>
+ <xsd:attribute name="protocol" type="xsd:string"/>
+ </xsd:complexType>
+ <xsd:complexType name="image">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ <xsd:element name="url" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ <xsd:element name="link" type="xsd:string" maxOccurs="1" minOccurs="0"/>
+ <xsd:element name="width" default="88" maxOccurs="1" minOccurs="0">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int">
+ <xsd:minExclusive value="0"/>
+ <xsd:maxInclusive value="144"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ <xsd:element name="height" default="31" maxOccurs="1" minOccurs="0">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int">
+ <xsd:minExclusive value="0"/>
+ <xsd:maxInclusive value="400"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ <xsd:element name="description" type="xsd:string" maxOccurs="1" minOccurs="0"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="textInput">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ <xsd:element name="description" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ <xsd:element name="name" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ <xsd:element name="link" type="xsd:string" maxOccurs="1" minOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="skipHours">
+ <xsd:sequence>
+ <xsd:element name="hour" minOccurs="1" maxOccurs="24">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int">
+ <xsd:maxInclusive value="23"/>
+ <xsd:minInclusive value="0"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="skipDays">
+ <xsd:sequence>
+ <xsd:element name="day" maxOccurs="7">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="Monday"/>
+ <xsd:enumeration value="Tuesday"/>
+ <xsd:enumeration value="Wednesday"/>
+ <xsd:enumeration value="Thursday"/>
+ <xsd:enumeration value="Friday"/>
+ <xsd:enumeration value="Saturday"/>
+ <xsd:enumeration value="Sunday"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="item">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The title of the item.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="link" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>The URL of the item.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="description" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>The item synopsis.</xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="author" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Email address of the author of the item.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="category" type="category" maxOccurs="unbounded" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Includes the item in one or more categories.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="comments" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ URL of a page for comments relating to the item.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="enclosure" type="enclosure" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Describes a media object that is attached to the
+ item.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="guid" type="guid" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ A string that uniquely identifies the item.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="pubDate" type="xsd:string" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ Indicates when the item was published.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ <xsd:element name="source" type="source" maxOccurs="1" minOccurs="0">
+ <xsd:annotation>
+ <xsd:documentation>
+ The RSS channel that the item came from.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="category">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="domain" type="xsd:string"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="enclosure">
+ <xsd:attribute name="url" type="xsd:string" use="required"/>
+ <xsd:attribute name="length" use="required">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:int">
+ <xsd:minExclusive value="0"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
+ <xsd:attribute name="type" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ <xsd:complexType name="guid">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="isPermaLink" type="xsd:boolean"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ <xsd:complexType name="source">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="url" type="xsd:string" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+</xsd:schema>
diff --git a/assets/schemas/sitemap-v0.9.xsd b/assets/schemas/sitemap-v0.9.xsd
new file mode 100644
index 0000000..2dd7437
--- /dev/null
+++ b/assets/schemas/sitemap-v0.9.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
+ targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
+ elementFormDefault="qualified"
+ >
+ <xsd:annotation>
+ <xsd:documentation>
+ XML Schema for Sitemap files.
+ Last Modifed 2008-03-26
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:element name="urlset">
+ <xsd:annotation>
+ <xsd:documentation>
+ Container for a set of up to 50,000 document elements.
+ This is the root element of the XML file.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
+ <xsd:element name="url" type="tUrl" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="tUrl">
+ <xsd:annotation>
+ <xsd:documentation>
+ Container for the data needed to describe a document to crawl.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="loc" type="tLoc"/>
+ <xsd:element name="lastmod" type="tLastmod" minOccurs="0"/>
+ <xsd:element name="changefreq" type="tChangeFreq" minOccurs="0"/>
+ <xsd:element name="priority" type="tPriority" minOccurs="0"/>
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:simpleType name="tLoc">
+ <xsd:annotation>
+ <xsd:documentation>
+ REQUIRED: The location URI of a document.
+ The URI must conform to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:anyURI">
+ <xsd:minLength value="12"/>
+ <xsd:maxLength value="2048"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="tLastmod">
+ <xsd:annotation>
+ <xsd:documentation>
+ OPTIONAL: The date the document was last modified. The date must conform
+ to the W3C DATETIME format (http://www.w3.org/TR/NOTE-datetime).
+ Example: 2005-05-10
+ Lastmod may also contain a timestamp.
+ Example: 2005-05-10T17:33:30+08:00
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:union>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:date"/>
+ </xsd:simpleType>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:dateTime"/>
+ </xsd:simpleType>
+ </xsd:union>
+ </xsd:simpleType>
+ <xsd:simpleType name="tChangeFreq">
+ <xsd:annotation>
+ <xsd:documentation>
+ OPTIONAL: Indicates how frequently the content at a particular URL is
+ likely to change. The value "always" should be used to describe
+ documents that change each time they are accessed. The value "never"
+ should be used to describe archived URLs. Please note that web
+ crawlers may not necessarily crawl pages marked "always" more often.
+ Consider this element as a friendly suggestion and not a command.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="always"/>
+ <xsd:enumeration value="hourly"/>
+ <xsd:enumeration value="daily"/>
+ <xsd:enumeration value="weekly"/>
+ <xsd:enumeration value="monthly"/>
+ <xsd:enumeration value="yearly"/>
+ <xsd:enumeration value="never"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="tPriority">
+ <xsd:annotation>
+ <xsd:documentation>
+ OPTIONAL: The priority of a particular URL relative to other pages
+ on the same site. The value for this element is a number between
+ 0.0 and 1.0 where 0.0 identifies the lowest priority page(s).
+ The default priority of a page is 0.5. Priority is used to select
+ between pages on your site. Setting a priority of 1.0 for all URLs
+ will not help you, as the relative priority of pages on your site
+ is what will be considered.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:decimal">
+ <xsd:minInclusive value="0.0"/>
+ <xsd:maxInclusive value="1.0"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+</xsd:schema>
diff --git a/assets/schemas/sitemapindex-v0.9.xsd b/assets/schemas/sitemapindex-v0.9.xsd
new file mode 100644
index 0000000..c35d50a
--- /dev/null
+++ b/assets/schemas/sitemapindex-v0.9.xsd
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<xsd:schema
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
+ targetNamespace="http://www.sitemaps.org/schemas/sitemap/0.9"
+ elementFormDefault="qualified"
+ >
+ <xsd:annotation>
+ <xsd:documentation>
+ XML Schema for Sitemap index files.
+ Last Modifed 2009-04-08
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:element name="sitemapindex">
+ <xsd:annotation>
+ <xsd:documentation>
+ Container for a set of up to 50,000 sitemap URLs.
+ This is the root element of the XML file.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
+ <xsd:element name="sitemap" type="tSitemap" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:complexType name="tSitemap">
+ <xsd:annotation>
+ <xsd:documentation>
+ Container for the data needed to describe a sitemap.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element name="loc" type="tLocSitemap"/>
+ <xsd:element name="lastmod" type="tLastmodSitemap" minOccurs="0"/>
+ <xsd:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="strict"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:simpleType name="tLocSitemap">
+ <xsd:annotation>
+ <xsd:documentation>
+ REQUIRED: The location URI of a sitemap.
+ The URI must conform to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt).
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:restriction base="xsd:anyURI">
+ <xsd:minLength value="12"/>
+ <xsd:maxLength value="2048"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ <xsd:simpleType name="tLastmodSitemap">
+ <xsd:annotation>
+ <xsd:documentation>
+ OPTIONAL: The date the document was last modified. The date must conform
+ to the W3C DATETIME format (http://www.w3.org/TR/NOTE-datetime).
+ Example: 2005-05-10
+ Lastmod may also contain a timestamp.
+ Example: 2005-05-10T17:33:30+08:00
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:union>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:date"/>
+ </xsd:simpleType>
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:dateTime"/>
+ </xsd:simpleType>
+ </xsd:union>
+ </xsd:simpleType>
+</xsd:schema>
diff --git a/assets/templates/author.yaml b/assets/templates/author.yaml
index 0a0f458..ae7bf40 100644
--- a/assets/templates/author.yaml
+++ b/assets/templates/author.yaml
@@ -1,16 +1,23 @@
---
name: {{ .Name }}
user: {{ .User }}
-blogtitle: {{ .Name }}'s Micro Blog
+title: {{ .Name }}'s Micro Blog
wordlimit: 50
place: Nowhere
domain:
host: example.com
url: https://example.com
+# Accepts file path or URL
+# header: /media/header.jpg
+# picture: https://example.com/media/picture.jpg
+picture:
+ header:
+ profile:
epoch: Just now
description: >
- I am a nobody. Copy this [example configuration](/data/generates/authors/{{ .User }}.yaml)
- to `data/{{ .User }}.yaml` and make me a somebody.
-webring:
+ I am a nobody. Copy this [example
+ configuration](/data/generates/authors/{{ .User }}.yaml) to
+ `data/{{ .User }}.yaml` and make me a [somebody](/data/default.yaml).
+feeds:
rss:
json:
diff --git a/assets/templates/markdown-feed.yaml b/assets/templates/markdown-feed.yaml
index 33118da..ff0aae5 100644
--- a/assets/templates/markdown-feed.yaml
+++ b/assets/templates/markdown-feed.yaml
@@ -21,12 +21,19 @@ feed:
{{ end -}}
---
-{{ $content := .content | replaceRE "{" "&#123;" | replaceRE "}" "&#125;" -}}
-{{ $content }} [Read More &rarr;]({{ .link }})
+{{ $content := .content }}
+
+{{- $content = replace $content "{" "&#123;" -}}
+{{- $content = replace $content "}" "&#125;" -}}
+{{- $content = replace $content "[" "&#91;" -}}
+{{- $content = replace $content "]" "&#93;" -}}
+
+{{ $content }}
+
+{{- $caption := "Image/Picture" -}}
-{{- $enclosureDescription := "Image/Picture" -}}
{{- with $content -}}
- {{ $enclosureDescription = $content | truncate 80 "" }}
+ {{ $caption = $content | truncate 80 "" }}
{{- end }}
{{ with .enclosure -}}
@@ -43,8 +50,8 @@ feed:
(in . ".svg")
(in . ".webp")
-}}
-![{{ $enclosureDescription }}]({{ . }} "
- {{ $enclosureDescription }}"
+![{{ $caption }}]({{ . }} "
+ {{ $caption }}"
)
{{- end -}}
{{- end }}
diff --git a/config.json b/config.json
index 845d573..2f29e53 100644
--- a/config.json
+++ b/config.json
@@ -6,6 +6,7 @@
"summaryLength": 1,
"enableEmoji": true,
"buildDrafts": true,
+ "buildExpired": true,
"languageCode": "en-us",
"enableRobotsTXT": true,
"author": {
@@ -15,14 +16,8 @@
"nobody"
],
"default": {
- "footer": "canory",
- "home": "canory",
- "picturegallery": "canory",
- "title": "canory",
- "user": "default",
- "webring": "canory"
- },
- "footer": "A Micro Blog\n"
+ "footer": "A Micro Blog"
+ }
},
"taxonomies": {
"tag": "tags"
@@ -32,143 +27,147 @@
{
"name": "Home",
"url": "/",
- "identifier": "feather/home",
+ "identifier": "tabler/home",
"weight": 1
},
{
"name": "Tags",
"url": "/tags/",
- "identifier": "feather/tag",
+ "identifier": "tabler/tag",
"weight": 2,
"icon": "home"
},
{
- "name": "History",
- "url": "/archives/messages/",
- "identifier": "tabler/clock",
+ "name": "Archives",
+ "url": "/archives/",
+ "identifier": "tabler/archive",
"weight": 3
},
{
- "name": "Records",
- "url": "/archives/tags/",
- "identifier": "tabler/book-2",
+ "name": "Authors",
+ "url": "/authors/",
+ "identifier": "tabler/users",
"weight": 4
},
{
- "name": "Authors",
- "url": "/authors/",
- "identifier": "feather/users",
+ "name": "Settings",
+ "url": "/settings/",
+ "identifier": "tabler/settings",
"weight": 5
},
{
- "name": "RSS Feed",
- "url": "/rss.xml",
- "identifier": "feather/rss",
+ "name": "Sources",
+ "url": "/sources/",
+ "identifier": "tabler/git-fork",
"weight": 6
},
{
- "name": "JSON Feed",
- "url": "/index.json",
- "identifier": "feather/circle",
+ "name": "RSS Feed",
+ "url": "/rss.xml",
+ "identifier": "tabler/rss",
"weight": 7
},
{
- "name": "Sources",
- "url": "/sources/",
- "identifier": "feather/git-commit",
+ "name": "JSON Feed",
+ "url": "/index.json",
+ "identifier": "tabler/circle",
"weight": 8
}
]
},
- "markup": {
- "highlight": {
- "anchorLineNos": true,
- "codeFences": true,
- "guessSyntax": true,
- "lineNos": false,
- "lineNumbersInTable": false,
- "noClasses": false,
- "noHl": false
- }
- },
"params": {
"site": {
+ "offline": false,
"production": false,
- "refresh": null
+ "referrer": "no-referrer",
+ "robots": "index,follow",
+ "canonical": null
},
"webmanifest": {
+ "start_url": "/",
"name": "Micro Blog",
- "shortName": "Micro",
- "themeColor": "#ffffff",
- "backgroundColor": "#ffffff",
+ "short_name": "Micro",
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
"display": "standalone",
+ "description": "A Micro Blog",
"logo": "data/media/logo.png"
},
"csp": {
- "upgrade": false,
- "referrer": "no-referrer",
- "childsrc": [
+ "block-all-mixed-content": "",
+ "base-uri": [
+ "'self'"
+ ],
+ "connect-src": [
+ "'self'"
+ ],
+ "default-src": [
"'self'"
],
- "fontsrc": [
+ "font-src": [
"'self'"
],
- "formaction": [
+ "form-action": [
"'self'",
"lite.duckduckgo.com"
],
- "framesrc": [
+ "frame-src": [
"'self'",
- "imgur.com",
"www.youtube-nocookie.com",
- "platform.twitter.com",
"en.m.wikipedia.org",
- "odysee.com",
- "docs.google.com"
+ "odysee.com"
],
- "imgsrc": [
+ "img-src": [
"'self'",
- "http://preview.test",
- "imgs.xkcd.com"
+ "data:",
+ "http://preview.test"
],
- "mediasrc": [
+ "manifest-src": [
"'self'",
- "raw.githubusercontent.com",
- "i.imgur.com"
+ "data:"
],
- "objectsrc": [
- "'none'"
+ "media-src": [
+ "'self'"
],
- "prefetchsrc": [
+ "object-src": [
"'self'"
],
- "scriptsrc": [
- "'self'",
- "s.imgur.com",
- "platform.twitter.com"
+ "script-src-elem": [
+ "'self'"
],
- "scriptsrcelem": [
- "'self'",
- "s.imgur.com",
- "platform.twitter.com"
+ "script-src": [
+ "'self'"
],
- "stylesrc": [
+ "style-src": [
"'self'",
"'unsafe-inline'",
"http://preview.test"
- ],
- "connectsrc": [
- "'self'"
]
},
"search": {
"verification": {
- "google": null,
- "bing": null,
- "yandex": null
+ "baidu-site-verification": null,
+ "google-site-verification": null,
+ "msvalidate.01": null,
+ "yandex-verification": null
}
}
},
+ "related": {
+ "includeNewer": false,
+ "indices": [
+ {
+ "name": "tags",
+ "weight": 80
+ },
+ {
+ "name": "date",
+ "weight": 10
+ }
+ ],
+ "threshold": 80,
+ "toLower": false
+ },
"mediaTypes": {
"application/xslt+xml": {
"suffixes": [
@@ -181,6 +180,14 @@
"baseName": "index",
"mediaType": "text/html"
},
+ "embed": {
+ "baseName": "embed",
+ "mediaType": "text/html"
+ },
+ "plain": {
+ "baseName": "index",
+ "mediaType": "text/plain"
+ },
"json": {
"baseName": "index",
"mediaType": "application/json"
@@ -189,22 +196,30 @@
"baseName": "rss",
"mediaType": "application/rss+xml"
},
- "rss-style": {
+ "xslt.rss": {
"baseName": "rss",
"mediaType": "application/xslt+xml"
},
+ "xslt.sitemap": {
+ "baseName": "sitemap",
+ "mediaType": "application/xslt+xml"
+ },
"authors": {
"path": "authors",
"baseName": "index",
"mediaType": "text/html"
},
- "archive-messages": {
- "path": "archives/messages",
+ "authors.section": {
+ "baseName": "authors",
+ "mediaType": "text/html"
+ },
+ "archives": {
+ "path": "archives",
"baseName": "index",
"mediaType": "text/html"
},
- "archive-tags": {
- "path": "archives/tags",
+ "settings": {
+ "path": "settings",
"baseName": "index",
"mediaType": "text/html"
},
@@ -213,31 +228,38 @@
"baseName": "index",
"mediaType": "text/html"
},
- "browserconfig": {
- "baseName": "browserconfig",
- "mediaType": "application/xml"
+ "gallery": {
+ "baseName": "gallery",
+ "mediaType": "text/html"
},
- "webmanifest": {
- "baseName": "site",
- "mediaType": "application/manifest+json"
+ "following": {
+ "baseName": "following",
+ "mediaType": "text/html"
+ },
+ "webring": {
+ "baseName": "webring",
+ "mediaType": "text/html"
}
},
"outputs": {
"home": [
"html",
"rss",
- "rss-style",
+ "xslt.rss",
+ "xslt.sitemap",
"json",
"authors",
+ "authors.section",
"sources",
- "browserconfig",
- "archive-messages",
- "archive-tags",
- "webmanifest"
+ "archives",
+ "settings"
],
"section": [
"html",
- "rss"
+ "rss",
+ "gallery",
+ "following",
+ "webring"
],
"taxonomy": [
"html",
@@ -248,7 +270,9 @@
"rss"
],
"page": [
- "html"
+ "html",
+ "plain",
+ "embed"
]
},
"caches": {
@@ -332,5 +356,72 @@
"target": "assets/public"
}
]
+ },
+ "sitemap": {
+ "changefreq": "weekly",
+ "filename": "sitemap.xml",
+ "priority": 0.5
+ },
+ "markup": {
+ "asciidocExt": {
+ "attributes": {},
+ "backend": "html5",
+ "extensions": [],
+ "failureLevel": "fatal",
+ "noHeaderOrFooter": true,
+ "preserveTOC": false,
+ "safeMode": "unsafe",
+ "sectionNumbers": false,
+ "trace": false,
+ "verbose": false,
+ "workingFolderCurrent": false
+ },
+ "defaultMarkdownHandler": "goldmark",
+ "goldmark": {
+ "extensions": {
+ "definitionList": true,
+ "footnote": true,
+ "linkify": true,
+ "linkifyProtocol": "https",
+ "strikethrough": true,
+ "table": true,
+ "taskList": true,
+ "typographer": true
+ },
+ "parser": {
+ "attribute": {
+ "block": false,
+ "title": true
+ },
+ "autoHeadingID": true,
+ "autoHeadingIDType": "github",
+ "wrapStandAloneImageWithinParagraph": false
+ },
+ "renderer": {
+ "hardWraps": false,
+ "unsafe": false,
+ "xhtml": true
+ }
+ },
+ "highlight": {
+ "anchorLineNos": true,
+ "codeFences": true,
+ "guessSyntax": true,
+ "hl_Lines": "",
+ "hl_inline": false,
+ "lineAnchors": "",
+ "lineNoStart": 1,
+ "lineNos": false,
+ "lineNumbersInTable": false,
+ "noClasses": false,
+ "noHl": false,
+ "style": null,
+ "tabWidth": 4
+ },
+ "tableOfContents": {
+ "endLevel": 3,
+ "ordered": false,
+ "startLevel": 2
+ }
}
}
diff --git a/config.toml b/config.toml
index bf7f352..16ca22b 100644
--- a/config.toml
+++ b/config.toml
@@ -4,20 +4,14 @@ paginate = 10
summaryLength = 1
enableEmoji = true
buildDrafts = true
+buildExpired = true
languageCode = "en-us"
enableRobotsTXT = true
[author]
list = ["canory", "default", "nobody"]
- footer = "A Micro Blog\n"
-
[author.default]
- footer = "canory"
- home = "canory"
- picturegallery = "canory"
- title = "canory"
- user = "default"
- webring = "canory"
+ footer = "A Micro Blog"
[taxonomies]
tag = "tags"
@@ -27,176 +21,176 @@ enableRobotsTXT = true
[[menu.main]]
name = "Home"
url = "/"
- identifier = "feather/home"
+ identifier = "tabler/home"
weight = 1
[[menu.main]]
name = "Tags"
url = "/tags/"
- identifier = "feather/tag"
+ identifier = "tabler/tag"
weight = 2
icon = "home"
[[menu.main]]
- name = "History"
- url = "/archives/messages/"
- identifier = "tabler/clock"
+ name = "Archives"
+ url = "/archives/"
+ identifier = "tabler/archive"
weight = 3
[[menu.main]]
- name = "Records"
- url = "/archives/tags/"
- identifier = "tabler/book-2"
+ name = "Authors"
+ url = "/authors/"
+ identifier = "tabler/users"
weight = 4
[[menu.main]]
- name = "Authors"
- url = "/authors/"
- identifier = "feather/users"
+ name = "Settings"
+ url = "/settings/"
+ identifier = "tabler/settings"
weight = 5
[[menu.main]]
- name = "RSS Feed"
- url = "/rss.xml"
- identifier = "feather/rss"
+ name = "Sources"
+ url = "/sources/"
+ identifier = "tabler/git-fork"
weight = 6
[[menu.main]]
- name = "JSON Feed"
- url = "/index.json"
- identifier = "feather/circle"
+ name = "RSS Feed"
+ url = "/rss.xml"
+ identifier = "tabler/rss"
weight = 7
[[menu.main]]
- name = "Sources"
- url = "/sources/"
- identifier = "feather/git-commit"
+ name = "JSON Feed"
+ url = "/index.json"
+ identifier = "tabler/circle"
weight = 8
-[markup]
-
- [markup.highlight]
- anchorLineNos = true
- codeFences = true
- guessSyntax = true
- lineNos = false
- lineNumbersInTable = false
- noClasses = false
- noHl = false
-
[params]
-
[params.site]
+ offline = false
production = false
-
+ referrer = "no-referrer"
+ robots = "index,follow"
[params.webmanifest]
+ start_url = "/"
name = "Micro Blog"
- shortName = "Micro"
- themeColor = "#ffffff"
- backgroundColor = "#ffffff"
+ short_name = "Micro"
+ theme_color = "#ffffff"
+ background_color = "#ffffff"
display = "standalone"
+ description = "A Micro Blog"
logo = "data/media/logo.png"
-
[params.csp]
- upgrade = false
- referrer = "no-referrer"
- childsrc = ["'self'"]
- fontsrc = ["'self'"]
- formaction = ["'self'", "lite.duckduckgo.com"]
- framesrc = ["'self'", "imgur.com", "www.youtube-nocookie.com", "platform.twitter.com", "en.m.wikipedia.org", "odysee.com", "docs.google.com"]
- imgsrc = ["'self'", "http://preview.test", "imgs.xkcd.com"]
- mediasrc = ["'self'", "raw.githubusercontent.com", "i.imgur.com"]
- objectsrc = ["'none'"]
- prefetchsrc = ["'self'"]
- scriptsrc = ["'self'", "s.imgur.com", "platform.twitter.com"]
- scriptsrcelem = ["'self'", "s.imgur.com", "platform.twitter.com"]
- stylesrc = ["'self'", "'unsafe-inline'", "http://preview.test"]
- connectsrc = ["'self'"]
-
+ block-all-mixed-content = ""
+ base-uri = ["'self'"]
+ connect-src = ["'self'"]
+ default-src = ["'self'"]
+ font-src = ["'self'"]
+ form-action = ["'self'", "lite.duckduckgo.com"]
+ frame-src = ["'self'", "www.youtube-nocookie.com", "en.m.wikipedia.org", "odysee.com"]
+ img-src = ["'self'", "data:", "http://preview.test"]
+ manifest-src = ["'self'", "data:"]
+ media-src = ["'self'"]
+ object-src = ["'self'"]
+ script-src-elem = ["'self'"]
+ script-src = ["'self'"]
+ style-src = ["'self'", "'unsafe-inline'", "http://preview.test"]
[params.search]
-
[params.search.verification]
-[mediaTypes]
+[related]
+ includeNewer = false
+ threshold = 80
+ toLower = false
+
+ [[related.indices]]
+ name = "tags"
+ weight = 80
+ [[related.indices]]
+ name = "date"
+ weight = 10
+
+[mediaTypes]
[mediaTypes."application/xslt+xml"]
suffixes = ["xsl"]
[outputFormats]
-
[outputFormats.html]
baseName = "index"
mediaType = "text/html"
-
+ [outputFormats.embed]
+ baseName = "embed"
+ mediaType = "text/html"
+ [outputFormats.plain]
+ baseName = "index"
+ mediaType = "text/plain"
[outputFormats.json]
baseName = "index"
mediaType = "application/json"
-
[outputFormats.rss]
baseName = "rss"
mediaType = "application/rss+xml"
-
- [outputFormats.rss-style]
+ [outputFormats."xslt.rss"]
baseName = "rss"
mediaType = "application/xslt+xml"
-
+ [outputFormats."xslt.sitemap"]
+ baseName = "sitemap"
+ mediaType = "application/xslt+xml"
[outputFormats.authors]
path = "authors"
baseName = "index"
mediaType = "text/html"
-
- [outputFormats.archive-messages]
- path = "archives/messages"
+ [outputFormats."authors.section"]
+ baseName = "authors"
+ mediaType = "text/html"
+ [outputFormats.archives]
+ path = "archives"
baseName = "index"
mediaType = "text/html"
-
- [outputFormats.archive-tags]
- path = "archives/tags"
+ [outputFormats.settings]
+ path = "settings"
baseName = "index"
mediaType = "text/html"
-
[outputFormats.sources]
path = "sources"
baseName = "index"
mediaType = "text/html"
-
- [outputFormats.browserconfig]
- baseName = "browserconfig"
- mediaType = "application/xml"
-
- [outputFormats.webmanifest]
- baseName = "site"
- mediaType = "application/manifest+json"
+ [outputFormats.gallery]
+ baseName = "gallery"
+ mediaType = "text/html"
+ [outputFormats.following]
+ baseName = "following"
+ mediaType = "text/html"
+ [outputFormats.webring]
+ baseName = "webring"
+ mediaType = "text/html"
[outputs]
- home = ["html", "rss", "rss-style", "json", "authors", "sources", "browserconfig", "archive-messages", "archive-tags", "webmanifest"]
- section = ["html", "rss"]
+ home = ["html", "rss", "xslt.rss", "xslt.sitemap", "json", "authors", "authors.section", "sources", "archives", "settings"]
+ section = ["html", "rss", "gallery", "following", "webring"]
taxonomy = ["html", "rss"]
term = ["html", "rss"]
- page = ["html"]
+ page = ["html", "plain", "embed"]
[caches]
-
[caches.assets]
dir = ":resourceDir/_gen"
maxAge = -1
-
[caches.images]
dir = ":resourceDir/_gen"
maxAge = -1
-
[caches.getcsv]
dir = ":resourceDir/caches"
maxAge = "12h"
-
[caches.getjson]
dir = ":resourceDir/caches"
maxAge = "12h"
-
[caches.getresource]
dir = ":resourceDir/caches"
maxAge = "12h"
-
[caches.modules]
dir = ":resourceDir/caches"
maxAge = -1
@@ -254,3 +248,61 @@ enableRobotsTXT = true
[[module.mounts]]
source = "public"
target = "assets/public"
+
+[sitemap]
+ changefreq = "weekly"
+ filename = "sitemap.xml"
+ priority = 0.5
+
+[markup]
+ defaultMarkdownHandler = "goldmark"
+ [markup.asciidocExt]
+ backend = "html5"
+ extensions = []
+ failureLevel = "fatal"
+ noHeaderOrFooter = true
+ preserveTOC = false
+ safeMode = "unsafe"
+ sectionNumbers = false
+ trace = false
+ verbose = false
+ workingFolderCurrent = false
+ [markup.asciidocExt.attributes]
+ [markup.goldmark]
+ [markup.goldmark.extensions]
+ definitionList = true
+ footnote = true
+ linkify = true
+ linkifyProtocol = "https"
+ strikethrough = true
+ table = true
+ taskList = true
+ typographer = true
+ [markup.goldmark.parser]
+ autoHeadingID = true
+ autoHeadingIDType = "github"
+ wrapStandAloneImageWithinParagraph = false
+ [markup.goldmark.parser.attribute]
+ block = false
+ title = true
+ [markup.goldmark.renderer]
+ hardWraps = false
+ unsafe = false
+ xhtml = true
+ [markup.highlight]
+ anchorLineNos = true
+ codeFences = true
+ guessSyntax = true
+ hl_Lines = ""
+ hl_inline = false
+ lineAnchors = ""
+ lineNoStart = 1
+ lineNos = false
+ lineNumbersInTable = false
+ noClasses = false
+ noHl = false
+ tabWidth = 4
+ [markup.tableOfContents]
+ endLevel = 3
+ ordered = false
+ startLevel = 2
diff --git a/config.yaml b/config.yaml
index fd17f55..6ba49df 100644
--- a/config.yaml
+++ b/config.yaml
@@ -7,6 +7,7 @@ paginate: 10
summaryLength: 1
enableEmoji: true
buildDrafts: true
+buildExpired: true
languageCode: en-us
enableRobotsTXT: true
@@ -16,14 +17,7 @@ author:
- default
- nobody
default:
- footer: canory
- home: canory
- picturegallery: canory
- title: canory
- user: default
- webring: canory
- footer: >
- A Micro Blog
+ footer: A Micro Blog
taxonomies:
tag: tags
@@ -32,80 +26,85 @@ menu:
main:
- name: Home
url: /
- identifier: feather/home
+ identifier: tabler/home
weight: 1
- name: Tags
url: /tags/
- identifier: feather/tag
+ identifier: tabler/tag
weight: 2
icon: home
- - name: History
- url: /archives/messages/
- identifier: tabler/clock
+ - name: Archives
+ url: /archives/
+ identifier: tabler/archive
weight: 3
- - name: Records
- url: /archives/tags/
- identifier: tabler/book-2
- weight: 4
- name: Authors
url: /authors/
- identifier: feather/users
+ identifier: tabler/users
+ weight: 4
+ - name: Settings
+ url: /settings/
+ identifier: tabler/settings
weight: 5
+ - name: Sources
+ url: /sources/
+ identifier: tabler/git-fork
+ weight: 6
- name: RSS Feed
url: /rss.xml
- identifier: feather/rss
- weight: 6
+ identifier: tabler/rss
+ weight: 7
- name: JSON Feed
url: /index.json
- identifier: feather/circle
- weight: 7
- - name: Sources
- url: /sources/
- identifier: feather/git-commit
+ identifier: tabler/circle
weight: 8
-markup:
- highlight:
- anchorLineNos: true
- codeFences: true
- guessSyntax: true
- lineNos: false
- lineNumbersInTable: false
- noClasses: false
- noHl: false
-
params:
site:
+ offline: false
production: false
- refresh:
+ referrer: no-referrer
+ robots: index,follow
+ canonical:
webmanifest:
+ start_url: /
name: Micro Blog
- shortName: Micro
- themeColor: '#ffffff'
- backgroundColor: '#ffffff'
+ short_name: Micro
+ theme_color: '#ffffff'
+ background_color: '#ffffff'
display: standalone
+ description: A Micro Blog
logo: data/media/logo.png
csp:
- upgrade: false
- referrer: no-referrer
- childsrc: ["'self'"]
- fontsrc: ["'self'"]
- formaction: ["'self'", lite.duckduckgo.com]
- framesrc: ["'self'", imgur.com, www.youtube-nocookie.com, platform.twitter.com,
- en.m.wikipedia.org, odysee.com, docs.google.com]
- imgsrc: ["'self'", http://preview.test, imgs.xkcd.com]
- mediasrc: ["'self'", raw.githubusercontent.com, i.imgur.com]
- objectsrc: ["'none'"]
- prefetchsrc: ["'self'"]
- scriptsrc: ["'self'", s.imgur.com, platform.twitter.com]
- scriptsrcelem: ["'self'", s.imgur.com, platform.twitter.com]
- stylesrc: ["'self'", "'unsafe-inline'", http://preview.test]
- connectsrc: ["'self'"]
+ block-all-mixed-content: ''
+ base-uri: ["'self'"]
+ connect-src: ["'self'"]
+ default-src: ["'self'"]
+ font-src: ["'self'"]
+ form-action: ["'self'", lite.duckduckgo.com]
+ frame-src: ["'self'", www.youtube-nocookie.com, en.m.wikipedia.org, odysee.com]
+ img-src: ["'self'", 'data:', http://preview.test]
+ manifest-src: ["'self'", 'data:']
+ media-src: ["'self'"]
+ object-src: ["'self'"]
+ script-src-elem: ["'self'"]
+ script-src: ["'self'"]
+ style-src: ["'self'", "'unsafe-inline'", http://preview.test]
search:
verification:
- google:
- bing:
- yandex:
+ baidu-site-verification:
+ google-site-verification:
+ msvalidate.01:
+ yandex-verification:
+
+related:
+ includeNewer: false
+ indices:
+ - name: tags
+ weight: 80
+ - name: date
+ weight: 10
+ threshold: 80
+ toLower: false
mediaTypes:
application/xslt+xml:
@@ -116,53 +115,71 @@ outputFormats:
html:
baseName: index
mediaType: text/html
+ embed:
+ baseName: embed
+ mediaType: text/html
+ plain:
+ baseName: index
+ mediaType: text/plain
json:
baseName: index
mediaType: application/json
rss:
baseName: rss
mediaType: application/rss+xml
- rss-style:
+ xslt.rss:
baseName: rss
mediaType: application/xslt+xml
+ xslt.sitemap:
+ baseName: sitemap
+ mediaType: application/xslt+xml
authors:
path: authors
baseName: index
mediaType: text/html
- archive-messages:
- path: archives/messages
+ authors.section:
+ baseName: authors
+ mediaType: text/html
+ archives:
+ path: archives
baseName: index
mediaType: text/html
- archive-tags:
- path: archives/tags
+ settings:
+ path: settings
baseName: index
mediaType: text/html
sources:
path: sources
baseName: index
mediaType: text/html
- browserconfig:
- baseName: browserconfig
- mediaType: application/xml
- webmanifest:
- baseName: site
- mediaType: application/manifest+json
+ gallery:
+ baseName: gallery
+ mediaType: text/html
+ following:
+ baseName: following
+ mediaType: text/html
+ webring:
+ baseName: webring
+ mediaType: text/html
outputs:
home:
- html
- rss
- - rss-style
+ - xslt.rss
+ - xslt.sitemap
- json
- authors
+ - authors.section
- sources
- - browserconfig
- - archive-messages
- - archive-tags
- - webmanifest
+ - archives
+ - settings
section:
- html
- rss
+ - gallery
+ - following
+ - webring
taxonomy:
- html
- rss
@@ -171,6 +188,8 @@ outputs:
- rss
page:
- html
+ - plain
+ - embed
caches:
assets:
@@ -221,3 +240,62 @@ module:
target: data/authors
- source: public
target: assets/public
+
+sitemap:
+ changefreq: weekly
+ filename: sitemap.xml
+ priority: 0.5
+
+markup:
+ asciidocExt:
+ attributes: {}
+ backend: html5
+ extensions: []
+ failureLevel: fatal
+ noHeaderOrFooter: true
+ preserveTOC: false
+ safeMode: unsafe
+ sectionNumbers: false
+ trace: false
+ verbose: false
+ workingFolderCurrent: false
+ defaultMarkdownHandler: goldmark
+ goldmark:
+ extensions:
+ definitionList: true
+ footnote: true
+ linkify: true
+ linkifyProtocol: https
+ strikethrough: true
+ table: true
+ taskList: true
+ typographer: true
+ parser:
+ attribute:
+ block: false
+ title: true
+ autoHeadingID: true
+ autoHeadingIDType: github
+ wrapStandAloneImageWithinParagraph: false
+ renderer:
+ hardWraps: false
+ unsafe: false
+ xhtml: true
+ highlight:
+ anchorLineNos: true
+ codeFences: true
+ guessSyntax: true
+ hl_Lines: ''
+ hl_inline: false
+ lineAnchors: ''
+ lineNoStart: 1
+ lineNos: false
+ lineNumbersInTable: false
+ noClasses: false
+ noHl: false
+ style:
+ tabWidth: 4
+ tableOfContents:
+ endLevel: 3
+ ordered: false
+ startLevel: 2
diff --git a/content/canory/media/2city12p.pdf b/content/canory/media/2city12p.pdf
new file mode 100644
index 0000000..f559ea6
--- /dev/null
+++ b/content/canory/media/2city12p.pdf
Binary files differ
diff --git a/content/canory/media/profile/header.jpg b/content/canory/media/header.jpg
index 846ed6a..846ed6a 100644
--- a/content/canory/media/profile/header.jpg
+++ b/content/canory/media/header.jpg
Binary files differ
diff --git a/content/canory/media/profile/picture.png b/content/canory/media/picture.png
index 20bf810..20bf810 100644
--- a/content/canory/media/profile/picture.png
+++ b/content/canory/media/picture.png
Binary files differ
diff --git a/content/canory/messages/animations.md b/content/canory/messages/animations.md
new file mode 100644
index 0000000..4957497
--- /dev/null
+++ b/content/canory/messages/animations.md
@@ -0,0 +1,18 @@
++++
+date = "2022-03-16T05:41:52+00:00"
+lastmod = "2022-03-16T05:41:52+00:00"
+tags = [ "docs" ]
++++
+
+Text animations are out of style. Wait.. {{< animate waggle "nu-uh" >}}, just
+checked the clock --- and would ya know they're back in {{< animate twirl style
+>}}.
+
+- {{< animate roll Observe >}} the {{< animate hang signs. >}} Reality {{< animate flip bingo >}}.
+- We are {{< animate float floating >}} on magic pixie dust. Very {{< animate tremble scary. >}}
+- My ego is under {{< animate vibrate attack >}}. Oh {{< animate jiggle "noo!" >}}
+- Just pick {{< animate hop me >}} please, {{< animate twitch pretty >}} please..
+- It's all just an {{< animate skip animation >}}. Frames per second: {{< animate rattle "Infinite!" >}}
+- Command line {{< animate wave flags. >}} Sorcery and {{< animate distort runes. >}}
+- Resist the {{< animate shake struggle >}}. You must {{< animate jump fight >}}. Now {{< animate squeeze breathe. >}}
+- Big {{< animate shrink weak >}}, Little {{< animate grow strong. >}}
diff --git a/content/canory/messages/cache.md b/content/canory/messages/cache.md
index cb408be..9a57ced 100644
--- a/content/canory/messages/cache.md
+++ b/content/canory/messages/cache.md
@@ -1,8 +1,7 @@
+++
date = "2022-02-27T20:18:43+00:00"
lastmod = "2022-02-27T20:18:43+00:00"
-tags = [ "docs", "cache" ]
-author = "canory"
+tags = [ "docs" ]
+++
Resource abuse is not good --- cache responsibly. In the `hugo` configuration
diff --git a/content/canory/messages/code.md b/content/canory/messages/code.md
index ce38d8b..503eb97 100644
--- a/content/canory/messages/code.md
+++ b/content/canory/messages/code.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-22T04:45:51+00:00"
lastmod = "2022-03-22T04:45:51+00:00"
-tags = [ "docs", "code" ]
-author = "canory"
+tags = [ "docs" ]
+++
Demonstrate your brilliance by embedding code with impeccable taste and
diff --git a/content/canory/messages/definitions.md b/content/canory/messages/definitions.md
index 5e5be97..4c5f30f 100644
--- a/content/canory/messages/definitions.md
+++ b/content/canory/messages/definitions.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-17T04:45:51+00:00"
lastmod = "2022-03-17T04:45:51+00:00"
-tags = [ "docs", "definitions" ]
-author = "canory"
+tags = [ "docs" ]
+++
There's no infinite scrolling here --- it enfeebles the psyche. Here are a list
@@ -12,7 +11,7 @@ of definitions. You have received enlightenment, heed my words.
: Subject to no limitation or external determination.
**Enfeeble**
-: To make feeble : deprive of strength.
+: To make feeble: to deprive of strength.
**Psyche**
: The totality of elements forming the mind.
diff --git a/content/canory/messages/diagrams.md b/content/canory/messages/diagrams.md
index d3a2521..bfbc193 100644
--- a/content/canory/messages/diagrams.md
+++ b/content/canory/messages/diagrams.md
@@ -1,22 +1,25 @@
+++
date = "2022-03-25T04:45:51+00:00"
lastmod = "2022-03-25T04:45:51+00:00"
-tags = [ "docs", "diagrams", "emojis" ]
-author = "canory"
+tags = [ "docs" ]
+++
{{< abbr >}} I :heart: `hugo` but hate emojis. Here's an
[emoji cheat sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) because you
probably like them :sweat_smile:. I'm over the character limit but look mommy
---- `ASCII` diagrams!
+--- {{< abbr "`ASCII`" "American Standard Code for Information Interchange" >}} diagrams!
[**GoAT Diagram**](https://github.com/blampe/goat#goat-go-ascii-tool)
-> My original implementation was certainly buggy and not on par with markdeep. I'm
-> grateful for the folks who've helped smooth out the rough edges, and I've
+> My original implementation was certainly buggy and not on par with markdeep.
+
+-- Block
+
+> I'm grateful for the folks who've helped smooth out the rough edges, and I've
> updated this project to reflect the good changes made in the Hugo fork,
> including a long--overdue go.mod.
-{{< footer />}}
+
+--- Quote
```goat
. . . .--- 1
diff --git a/content/canory/messages/disclosure.md b/content/canory/messages/disclosure.md
new file mode 100644
index 0000000..597f8d7
--- /dev/null
+++ b/content/canory/messages/disclosure.md
@@ -0,0 +1,32 @@
++++
+date = "2022-03-07T02:19:12+00:00"
+lastmod = "2022-03-07T02:19:12+00:00"
+tags = [ "docs" ]
++++
+
+I'll keep it short. The introduction of _A Tale of Two Cities_ by Charles
+Dickens --- enjoy!
+
+---
+
+{{< disclose >}}
+It was the best of times, it was the worst of times.
+{{</ disclose >}}
+
+It was the age of wisdom, it was the age of foolishness, it was the epoch of
+belief, it was the epoch of incredulity.
+
+{{< disclose >}}
+It was the season of Light, it was the season of Darkness.
+{{</ disclose >}}
+
+It was the spring of hope, it was the winter of despair, we had everything
+before us, we had nothing before us.
+
+{{< disclose >}}
+We were all going direct to Heaven, we were all going direct the other way.
+{{</ disclose >}}
+
+In short, the period was so far like the present period, that some of its
+noisiest authorities insisted on its being received, for good or for evil, in
+the superlative degree of comparison only.
diff --git a/content/canory/messages/drafts.md b/content/canory/messages/drafts.md
index 99d0228..41fb2ae 100644
--- a/content/canory/messages/drafts.md
+++ b/content/canory/messages/drafts.md
@@ -1,9 +1,8 @@
+++
date = "2022-03-04T02:44:51+00:00"
lastmod = "2022-03-04T02:44:51+00:00"
-tags = [ "docs", "drafts" ]
+tags = [ "docs" ]
draft = true
-author = "canory"
+++
Draft those messages, you message drafter. Get a feel of how it delivers before
diff --git a/content/canory/messages/gates.md b/content/canory/messages/gates.md
index ecb1aa9..eb2ddd3 100644
--- a/content/canory/messages/gates.md
+++ b/content/canory/messages/gates.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-01T01:24:31+00:00"
lastmod = "2022-03-01T01:24:31+00:00"
-tags = [ "docs", "webmaster" ]
-author = "canory"
+tags = [ "docs" ]
+++
Satisfy the keepers of the gate by officially verifying ownership of your
diff --git a/content/canory/messages/highlighting.md b/content/canory/messages/highlighting.md
index 4bc2908..076a189 100644
--- a/content/canory/messages/highlighting.md
+++ b/content/canory/messages/highlighting.md
@@ -1,11 +1,11 @@
+++
date = "2022-03-24T04:45:51+00:00"
lastmod = "2022-03-24T04:45:51+00:00"
-tags = [ "docs", "highlighting" ]
-author = "canory"
+tags = [ "docs" ]
+++
-Sometimes I'll {{< mark "highlight stuff" >}} to draw attention to my fine
-eloquence. If I don't think things through, I'll ~~hide the what I
-wrote~~. Whoops, let's just {{< ins "correct the record." >}}
-{{< spoiler "Move along --- nothing to see here." >}}
+Sometimes I'll {{< mark "highlight stuff" />}} to draw attention to my fine
+eloquence. If I don't think things through, I'll ~~hide the what I wrote~~.
+Whoops, let's just {{< ins "correct the record." >}}
+{{< spoiler "Move along --- nothing to see here." />}}
+{{< spoiler "Still nothing." />}}
diff --git a/content/canory/messages/hugo.md b/content/canory/messages/hugo.md
index 9768e94..2011db0 100644
--- a/content/canory/messages/hugo.md
+++ b/content/canory/messages/hugo.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-26T04:45:51+00:00"
lastmod = "2022-03-26T04:45:51+00:00"
-tags = [ "docs", "hugo" ]
-author = "canory"
+tags = [ "docs" ]
+++
This micro blog is powered by Hugo, a static site generator that has lots of
diff --git a/content/canory/messages/imgur-video.md b/content/canory/messages/imgur-video.md
index 6ed82c6..d04fe47 100644
--- a/content/canory/messages/imgur-video.md
+++ b/content/canory/messages/imgur-video.md
@@ -1,11 +1,10 @@
+++
date = "2022-03-19T04:45:51+00:00"
lastmod = "2022-03-19T04:45:51+00:00"
-tags = [ "docs", "imgur" ]
-author = "canory"
+tags = [ "docs" ]
+++
Embedding a `gif` hosted from an external site is easy. Heard it might be
illegal someday. Yak shaving and legal jangling are the worst, truly.
-{{< imgur-video rQIb4Vw >}}
+{{< video-imgur rQIb4Vw >}}
diff --git a/content/canory/messages/twitter.md b/content/canory/messages/links.md
index 945a18d..bc79001 100644
--- a/content/canory/messages/twitter.md
+++ b/content/canory/messages/links.md
@@ -1,11 +1,10 @@
+++
date = "2022-03-15T03:45:51+00:00"
lastmod = "2022-03-15T03:45:51+00:00"
-tags = [ "docs", "twitter" ]
-author = "canory"
+tags = [ "docs" ]
+++
This individual is old enough to remember that the Internet is
a vast place.
-{{< tweet tveastman 1069674780826071040 >}}
+{{< link "https://web.archive.org/web/20200111092601/https://twitter.com/tveastman/status/1069674780826071040" >}}
diff --git a/content/canory/messages/lists.md b/content/canory/messages/lists.md
index 239b7df..04fbab7 100644
--- a/content/canory/messages/lists.md
+++ b/content/canory/messages/lists.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-12T02:44:51+00:00"
lastmod = "2022-03-12T02:44:51+00:00"
-tags = [ "docs", "lists" ]
-author = "canory"
+tags = [ "docs" ]
+++
Speaking of lists. Everyone likes a good list right? Spur ridicule and
@@ -11,6 +10,9 @@ controversy by ranking things, it's that easy.
1. C
2. Bash
3. Perl
- 4. JavaScript
- 5. PHP
- 6. Java
+
+ ---
+
+ 10. JavaScript
+ 11. PHP
+ 12. Java
diff --git a/content/canory/messages/markdown.md b/content/canory/messages/markdown.md
index 032f5e5..675f3f1 100644
--- a/content/canory/messages/markdown.md
+++ b/content/canory/messages/markdown.md
@@ -1,13 +1,12 @@
+++
date = "2022-03-14T04:45:51+00:00"
lastmod = "2022-03-14T04:45:51+00:00"
-tags = [ "docs", "markdown" ]
-author = "canory"
+tags = [ "docs" ]
+++
[//]: # "That's a comment alright, hiding in plain sight."
-The `metadata` :arrow_up: has a link to the raw
+The `metadata` :arrow_up: has a menu link to the raw
[Markdown](https://www.markdownguide.org/cheat-sheet/) file {{< markdown >}}
that generates this message --- might as well show my internals. Casual users
will frown, power users will delight.
diff --git a/content/canory/messages/math.md b/content/canory/messages/math.md
new file mode 100644
index 0000000..cd02f88
--- /dev/null
+++ b/content/canory/messages/math.md
@@ -0,0 +1,93 @@
++++
+date = "2022-03-01T01:25:42+00:00"
+lastmod = "2022-03-01T01:25:42+00:00"
+tags = [ "docs" ]
++++
+
+First nothing, then the infinity wars. You know; the miracle of the fallacy
+_&agrave; la_ generality.
+
+```mathml { caption="Sounds about right." }
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\begin{align*} & 0 = 0 \times 1\\ & 0 = 0 \times 2\\ & 0 = 0 \times 3 \end{align*}" display="block" >
+ <mtable displaystyle="true" columnalign="right">
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>0</mn>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>×</mo>
+ <mn>1</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>0</mn>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>×</mo>
+ <mn>2</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>0</mn>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>×</mo>
+ <mn>3</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+</math>
+```
+
+```mathml { caption="Alien levels of literal meta--abstraction." }
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\begin{align*} & 0 = 0\\ & 0 \times 1 = 0 \times 3 \end{align*}" display="block">
+ <mtable displaystyle="true" columnalign="right left">
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>0</mn>
+ <mo>=</mo>
+ <mn>0</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>0</mn>
+ <mo>×</mo>
+ <mn>1</mn>
+ <mo>=</mo>
+ <mn>0</mn>
+ <mo>×</mo>
+ <mn>3</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+</math>
+```
+
+```mathml { caption="Unity. Don't try this at home, kids." }
+<math xmlns="http://www.w3.org/1998/Math/MathML" alttext="\begin{align*} & 1 = 3 \end{align*}" display="block">
+ <mtable displaystyle="true" columnalign="right left">
+ <mtr>
+ <mtd>
+ <mrow>
+ <mn>1</mn>
+ <mo>=</mo>
+ <mn>3</mn>
+ </mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+</math>
+```
diff --git a/content/canory/messages/odysee.md b/content/canory/messages/odysee.md
index 2080f94..6f0c0a8 100644
--- a/content/canory/messages/odysee.md
+++ b/content/canory/messages/odysee.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-03T02:44:51+00:00"
lastmod = "2022-03-03T02:44:51+00:00"
-tags = [ "docs", "odysee" ]
-author = "canory"
+tags = [ "docs" ]
+++
The cool kids are moving to a new video site called Odysee. How long do you
diff --git a/content/canory/messages/pdf.md b/content/canory/messages/pdf.md
index 74ff0be..cb63604 100644
--- a/content/canory/messages/pdf.md
+++ b/content/canory/messages/pdf.md
@@ -1,12 +1,12 @@
+++
date = "2022-03-07T02:20:51+00:00"
lastmod = "2022-03-07T02:20:51+00:00"
-tags = [ "docs", "pdf" ]
-author = "canory"
+tags = [ "docs" ]
+++
-Heard you like {{< abbr `PDFs` "Portable Document Format" >}} but hate accidently
-downloading them. Charles Dickens is a word wizard.
-
-{{< pdf >}}
+Heard you like {{< abbr `PDFs` "Portable Document Format" >}} but hate
+accidently downloading them. [Charles
+Dickens](https://www.gutenberg.org/ebooks/98) is a [word
+wizard](/canory/media/2city12p.pdf).
+{{< attach >}}
diff --git a/content/canory/messages/pinned.md b/content/canory/messages/pinned.md
index 1e1bd16..faf8781 100644
--- a/content/canory/messages/pinned.md
+++ b/content/canory/messages/pinned.md
@@ -1,14 +1,13 @@
+++
date = "2022-02-05T02:20:51+00:00"
lastmod = "2022-03-29T22:55:17+00:00"
-tags = [ "docs", "pinned", "hugo" ]
+tags = [ "docs" ]
weight = 1
-liked = true
-author = "canory"
+marked = true
+++
This message is pinned for reasons unknown. For a quick start guide,
-[@default](/tags/hugo/#default-messages-quickstart.md) might be able to help
+[@default](/default/messages/quickstart/#default-messages-quickstart) might be able to help
you. The [#docs](/tags/docs) explain what we are currently capable of doing.
-{{< mark Warning >}}: This micro blog is _remarkably_ experimental, don't hurt
+{{< mark Warning />}}: This micro blog is _remarkably_ experimental, don't hurt
yourself.
diff --git a/content/canory/messages/plumbing.md b/content/canory/messages/plumbing.md
index 4dbee64..6cda9c9 100644
--- a/content/canory/messages/plumbing.md
+++ b/content/canory/messages/plumbing.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-10T02:44:51+00:00"
lastmod = "2022-03-10T02:44:51+00:00"
-tags = [ "docs", "plumbing" ]
-author = "canory"
+tags = [ "docs" ]
+++
Is your `JavaScript` functional? Double[^1] click a word and hold the
diff --git a/content/canory/messages/self.md b/content/canory/messages/self.md
index ac86e20..f5834a4 100644
--- a/content/canory/messages/self.md
+++ b/content/canory/messages/self.md
@@ -1,14 +1,13 @@
+++
date = "2022-03-02T02:44:51+00:00"
lastmod = "2022-03-02T02:44:51+00:00"
-tags = [ "docs", "self" ]
-author = "canory"
+tags = [ "docs" ]
+++
-Check out this party trick; this thing can quote other messages. {{< spoiler >}}
-Technically... the
-instructions from the manufacturer was not to do this --- but rules are made to be
-broken... right?
+Check out this party trick; this thing can quote other messages.
+{{< spoiler >}}
+Technically... the instructions from the manufacturer was not to do this --- but
+rules are made to be broken... right?
{{< /spoiler >}}
-{{< self "/canory/messages/self#canory-messages-self.md" >}}
+{{< self "/canory/messages/self/embed.html" >}}
diff --git a/content/canory/messages/selfdestruct.md b/content/canory/messages/selfdestruct.md
index 20b4ff6..bfac31d 100644
--- a/content/canory/messages/selfdestruct.md
+++ b/content/canory/messages/selfdestruct.md
@@ -2,14 +2,14 @@
date = "2022-03-08T02:20:51+00:00"
lastmod = "2022-03-08T02:20:51+00:00"
expirydate = "2122-04-29T22:55:17+00:00"
-tags = [ "docs", "selfdestruct" ]
-author = "canory"
+tags = [ "docs" ]
slug = "cf1a1feb1"
+++
-Extraterrestrials don't care about speech in the slightest. According to my
-lackey [@tdro](https://thedroneely.com), the Internet is
-{{< abbr srs "serious">}} business for humans.
+{{< disclose >}}
+Extraterrestrials care not about speech. According to my
+[lackey](https://thedroneely.com), the Internet is serious business for humans.
+{{</ disclose >}}
Professor Wiio says;
{{< quote
@@ -18,11 +18,9 @@ Professor Wiio says;
>}}
Limit or boost virality and damage by self destructing the source of an imagined
-controversy. This is not to be indexed --- search engine bots
-{{< smallcaps "shall not pass" >}} (hopefully), neither will this message propogate through
-`JSON` and `RSS` feeds.
-
-This {{< markdown text="hidden message" title="hidden in plain sight" >}} will
-only disappear in my timeline because I'm an intergalactic time traveler.
+controversy. This is not to be indexed --- search engine bots {{< smallcaps "shall not pass" >}}
+(hopefully), neither should this message propogate through
+`JSON` and `RSS` feeds. This {{< markdown text="hidden message" title="hidden in plain sight" >}}
+will only disappear in my timeline because I'm an intergalactic time traveler.
![Isaac Asimov](/canory/media/internet-is-serious.jpg)
diff --git a/content/canory/messages/selfdestructed.md b/content/canory/messages/selfdestructed.md
new file mode 100644
index 0000000..2cf1852
--- /dev/null
+++ b/content/canory/messages/selfdestructed.md
@@ -0,0 +1,9 @@
++++
+date = "2022-03-08T02:18:49+00:00"
+lastmod = "2022-03-08T02:18:49+00:00"
+expirydate = "2022-03-08T02:19:51+00:00"
+tags = [ "docs" ]
+slug = "cf1a1feb2"
++++
+
+This is a special message.
diff --git a/content/canory/messages/styles.md b/content/canory/messages/styles.md
index 2cb8e5c..67c63be 100644
--- a/content/canory/messages/styles.md
+++ b/content/canory/messages/styles.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-23T04:45:51+00:00"
lastmod = "2022-03-23T04:45:51+00:00"
-tags = [ "docs", "styles" ]
-author = "canory"
+tags = [ "docs" ]
+++
**Subtlety** *wins* arguments, and other times an **_impassioned
diff --git a/content/canory/messages/tables.md b/content/canory/messages/tables.md
index cba9818..97c4aea 100644
--- a/content/canory/messages/tables.md
+++ b/content/canory/messages/tables.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-04T02:44:51+00:00"
lastmod = "2022-03-04T02:44:51+00:00"
-tags = [ "docs", "tables" ]
-author = "canory"
+tags = [ "docs" ]
+++
Tables are the most universally understood data presentation format but...
diff --git a/content/canory/messages/tasks.md b/content/canory/messages/tasks.md
index 4e23d74..379c359 100644
--- a/content/canory/messages/tasks.md
+++ b/content/canory/messages/tasks.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-13T03:44:51+00:00"
lastmod = "2022-03-13T03:44:51+00:00"
-tags = [ "docs", "tasks" ]
-author = "canory"
+tags = [ "docs" ]
+++
We get things done around here! The first step is to write down our goals for
diff --git a/content/canory/messages/unlisted.md b/content/canory/messages/unlisted.md
index 53d9f2f..76294bf 100644
--- a/content/canory/messages/unlisted.md
+++ b/content/canory/messages/unlisted.md
@@ -1,9 +1,8 @@
+++
-date = "2022-03-08T02:20:51+00:00"
-lastmod = "2022-03-08T02:20:51+00:00"
-tags = [ "docs", "unlisted" ]
+date = "2022-03-08T02:16:51+00:00"
+lastmod = "2022-03-08T02:16:51+00:00"
+tags = [ "docs" ]
unlisted = true
-author = "canory"
+++
So you're a bit bold and have the cooking skills needed to stay in the kitchen.
diff --git a/content/canory/messages/unsafe.md b/content/canory/messages/unsafe.md
index 8874fb7..f43799e 100644
--- a/content/canory/messages/unsafe.md
+++ b/content/canory/messages/unsafe.md
@@ -1,11 +1,11 @@
+++
date = "2022-03-09T02:43:51+00:00"
lastmod = "2022-03-09T02:43:51+00:00"
-tags = [ "docs", "unsafe" ]
-unsafe = true
-author = "canory"
+tags = [ "docs" ]
+++
+{{< disclose />}}
+
Is it safe? Well this message ain't.
{{< quote
"Evil communications corrupt good manners"
diff --git a/content/canory/messages/videos.md b/content/canory/messages/videos.md
index 4cb04b2..3655f46 100644
--- a/content/canory/messages/videos.md
+++ b/content/canory/messages/videos.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-20T04:45:51+00:00"
lastmod = "2022-03-20T04:45:51+00:00"
-tags = [ "docs", "videos" ]
-author = "canory"
+tags = [ "docs" ]
+++
Here's a video that warms my dear heart. Showing videos to others makes you
diff --git a/content/canory/messages/wikipedia.md b/content/canory/messages/wikipedia.md
index cb65635..12950b2 100644
--- a/content/canory/messages/wikipedia.md
+++ b/content/canory/messages/wikipedia.md
@@ -1,14 +1,13 @@
+++
date = "2022-03-06T02:20:51+00:00"
lastmod = "2022-03-06T02:20:51+00:00"
-tags = [ "docs", "wikipedia" ]
-author = "canory"
+tags = [ "docs" ]
+++
Reason, meaning, and knowledge are the ground truths of society but only when
all other methods have failed. Invoke the world's most used encyclopedia...
-{{< mark Warning >}}:
+{{< mark Warning />}}:
Article text may *change* as it appears --- the pedia's not guaranteed to be
consistent across discrete spacetimes. If the below does not say
"knowledge" you've been had.
diff --git a/content/canory/messages/xkcd.md b/content/canory/messages/xkcd.md
index 146b9c9..0896da1 100644
--- a/content/canory/messages/xkcd.md
+++ b/content/canory/messages/xkcd.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-18T04:45:51+00:00"
lastmod = "2022-03-18T04:45:51+00:00"
-tags = [ "docs", "xkcd" ]
-author = "canory"
+tags = [ "docs" ]
+++
Hosting and linking content is copyright radioactive. Be a good netizen and
diff --git a/content/canory/messages/youtube.md b/content/canory/messages/youtube.md
index 2bf9ecd..33f7c53 100644
--- a/content/canory/messages/youtube.md
+++ b/content/canory/messages/youtube.md
@@ -1,8 +1,7 @@
+++
date = "2022-03-16T04:45:51+00:00"
lastmod = "2022-03-16T04:45:51+00:00"
-tags = [ "docs", "YouTube" ]
-author = "canory"
+tags = [ "docs" ]
+++
Netizens think that there are only 5 websites. Here's a video from one of them.
diff --git a/content/default/media/profile/header.jpg b/content/default/media/header.jpg
index e2578d5..e2578d5 100644
--- a/content/default/media/profile/header.jpg
+++ b/content/default/media/header.jpg
Binary files differ
diff --git a/content/default/media/profile/picture.png b/content/default/media/picture.png
index 6e039c0..6e039c0 100644
--- a/content/default/media/profile/picture.png
+++ b/content/default/media/picture.png
Binary files differ
diff --git a/content/default/messages/authors.md b/content/default/messages/authors.md
index 85d46c5..973de7a 100644
--- a/content/default/messages/authors.md
+++ b/content/default/messages/authors.md
@@ -1,12 +1,9 @@
+++
date = "2022-03-14T04:35:51+00:00"
lastmod = "2022-03-14T04:35:51+00:00"
-tags = [ "docs", "authors" ]
+tags = [ "docs" ]
+++
Beep beep beep. Another user? Multiple users are available by setting a specific
author. [@canory](/canory) thinks this is cool but doesn't know any better --
it's hacks all the way down.
-
-Any soul that sends a message without a name becomes a _default_ because
-{{< smallcaps "I AM" >}} the default.
diff --git a/content/default/messages/create.md b/content/default/messages/create.md
index 1ac997c..96534c8 100644
--- a/content/default/messages/create.md
+++ b/content/default/messages/create.md
@@ -1,7 +1,7 @@
+++
date = "2022-03-13T04:24:37+00:00"
lastmod = "2022-03-13T04:24:37+00:00"
-tags = [ "docs", "hugo", "authors" ]
+tags = [ "docs" ]
+++
"Bootstrap" authors by adding a name to the author list in the `toml/json/yaml`
@@ -22,11 +22,6 @@ create nobody's home in the content directory.
```
content
|__ nobody
- |__ media
- | |__ profile
- | |__ header.jpg
- | |__ picture.png
- |
|__ messages
|__ new.md
```
diff --git a/content/default/messages/quickstart.md b/content/default/messages/quickstart.md
index 2661cf1..99e33d3 100644
--- a/content/default/messages/quickstart.md
+++ b/content/default/messages/quickstart.md
@@ -1,17 +1,19 @@
+++
date = "2022-03-05T03:45:51+00:00"
lastmod = "2022-03-05T03:45:51+00:00"
-tags = [ "docs", "hugo", "quickstart" ]
-author = "default"
+tags = [ "docs" ]
+++
Somehow you've ended up here, funny how that works. I'm responsible for
explaining how to get started.
-GIT CLONE. EXECUTE HUGO TWICE. HUGO VERSION >= 0.94.2.
+GIT CLONE.
+
+{{% version clone=true %}}
+
+EXECUTE HUGO TWICE. HUGO VERSION >= {{% version hugo=true %}} AND < 0.123.0
```shell
-git clone --branch 0.8.13 https://www.thedroneely.com/git/thedroneely/canory
cd canory
hugo && hugo
```
@@ -24,6 +26,6 @@ python -m http.server --bind 127.0.0.1 8124
busybox httpd -f -p 127.0.0.1:8125
php -S 127.0.0.1:8126
ruby -run -e httpd . -p 8127
+caddy file-server --listen :8128
+npx serve --listen 8129
```
-
-That concludes our automated community announcement.
diff --git a/data/authors/canory.yaml b/data/authors/canory.yaml
new file mode 100644
index 0000000..33281aa
--- /dev/null
+++ b/data/authors/canory.yaml
@@ -0,0 +1,24 @@
+---
+name: Canory
+user: canory
+title: Canory's Micro Blog
+wordlimit: 50
+place: www
+domain:
+ host: canory.example
+ url: https://example.com
+epoch: Arrived on the second fortnight of April, `2022`
+footer: Canory's Micro Blog &middot; [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
+picture:
+ header: media/header.jpg
+ profile: media/picture.png
+description: >
+ Descended from an inner star system of the Sunflower galaxy. Not an owl.
+ Theme Canory --- a micro blog theme for [Hugo](https://gohugo.io/), one of many
+ [static site](https://jamstack.org/generators/) generators. [Profile](https://pixabay.com/photos/barn-owl-owl-bird-predator-beak-2550068/)
+ by [luboshouska](https://pixabay.com/users/luboshouska-198496/) and [header](https://pixabay.com/photos/galaxy-star-infinity-cosmos-dark-3608029/)
+ by [luminas_art](https://pixabay.com/users/luminas_art-4128746/).
+feeds:
+ rss:
+ - https://www.rfc-editor.org/rfcrss.xml
+ json:
diff --git a/data/authors/default.yaml b/data/authors/default.yaml
new file mode 100644
index 0000000..db028af
--- /dev/null
+++ b/data/authors/default.yaml
@@ -0,0 +1,23 @@
+---
+name: Default
+user: default
+title: Default's Micro Blog
+wordlimit: 50
+place: In your head
+domain:
+ host: default.example
+ url: https://example.com
+picture:
+ header: media/header.jpg
+ profile: media/picture.png
+epoch: Appeared sometime around April, `2022`
+description: >
+ Dignissimos quis animi velit. Not a bot. If you believe everything you read on
+ the Internet, you'll think that I'm human. [Profile](https://pixabay.com/vectors/robots-automata-grey-bot-3338504/)
+ by [guaxipo](https://pixabay.com/users/guaxipo-8650096/)
+ and [header](https://pixabay.com/photos/circuit-board-electronics-6560489/) by [11082974](https://pixabay.com/users/11082974-11082974/).
+feeds:
+ rss:
+ - https://hacks.mozilla.org/feed/
+ - https://bing.com/HPImageArchive.aspx?format=rss&idx=0&n=1&mkt=en-US
+ json:
diff --git a/data/canory.yaml b/data/canory.yaml
deleted file mode 100644
index fba7750..0000000
--- a/data/canory.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Canory
-user: canory
-blogtitle: Canory's Micro Blog
-wordlimit: 50
-place: www
-domain:
- host: canory.example
- url: https://example.com
-epoch: Arrived on the second fortnight of April, `2022`
-description: >
- Descended from an inner star system of the Sunflower galaxy. Not an owl.
- Theme Canory --- a micro blog theme for [Hugo](https://gohugo.io/), one of many
- [static site generators](https://jamstack.org/generators/).
-webring:
- rss:
- - https://www.rfc-editor.org/rfcrss.xml
- json:
diff --git a/data/default.yaml b/data/default.yaml
deleted file mode 100644
index b73b2b9..0000000
--- a/data/default.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Default
-user: default
-blogtitle: Default's Micro Blog
-wordlimit: 50
-place: In your head
-domain:
- host: default.example
- url: https://example.com
-epoch: Appeared sometime around April, `2022`
-description: >
- Dignissimos quis animi velit. Not a bot. If you believe everything you read on
- the Internet, you'll think that I'm human.
-webring:
- rss:
- - https://hacks.mozilla.org/feed/
- - http://www.bing.com/HPImageArchive.aspx?format=rss&idx=0&n=1&mkt=en-US
- json:
diff --git a/shell.nix b/shell.nix
index 7b54486..0954bb4 100644
--- a/shell.nix
+++ b/shell.nix
@@ -2,72 +2,70 @@ let
name = "nix-shell.canory";
- pkgs = import (builtins.fetchTarball {
- url = "https://releases.nixos.org/nixos/22.05/nixos-22.05.998.d17a56d90ec/nixexprs.tar.xz";
- sha256 = "084dzb7fmchfhhflrgprjjv7qz3j7vxw3d01f82q8p4g1x7hzn36";
- }) { };
-
- validatornu = pkgs.callPackage (pkgs.fetchurl {
- url = "https://raw.githubusercontent.com/tdro/dotfiles/032efcf7f4b1c7304ce5f3f64f64c175ba59eb6d/.config/nixpkgs/packages/validatornu/default.nix";
- sha256 = "1ify40x9547z04hcibk76m45d02xg3dlvwc57n8vxcbax82yb9pj";
- }) { };
+ system = builtins.currentSystem;
- mkShellPure = pkgs.callPackage (pkgs.fetchurl {
- url = "https://raw.githubusercontent.com/tdro/dotfiles/b710281b132056105709c03dda1899a6afc68a93/.config/nixpkgs/helpers/mkShellPure.nix";
- sha256 = "1ciwifsx2hrp0ymm077zfb5q8ravrk545bda1q249y2spw9np4ms";
- }) { };
-
- hugo = pkgs.callPackage ({ lib, buildGo118Module, fetchgit, installShellFiles }:
+ pkgs = import (builtins.fetchTarball {
+ url = "https://releases.nixos.org/nixos/unstable/nixos-23.11pre516114.d680ded26da5/nixexprs.tar.xz";
+ sha256 = "13cnlhpp3v7jay4jxyyy2d4kxw4ngpz3m00rhj3vlhvf7jl7hr48";
+ }) { inherit system; };
- buildGo118Module rec {
+ hugo = pkgs.callPackage ({ lib, buildGoModule, fetchgit }:
+ buildGoModule rec {
pname = "hugo";
- version = "0.101.0";
-
+ version = "0.122.0";
src = fetchgit {
rev = "v${version}";
url = "https://github.com/gohugoio/hugo.git";
- sha256 = "sha256-Fodcefp8xdSV2tt6ZYaKdcLqVe2upEngQr6M+wV5wnw=";
+ sha256 = "sha256-pnsQo+nSuIlQ6KKTP1z/BZ74zEu9HjYP66hGStPc0pc=";
};
-
doCheck = false;
proxyVendor = true;
- vendorSha256 = "sha256-rReqDOhBKZO1qa3C4jmewGgmhLvvOYyxwWqsdm+6DzM=";
-
+ vendorSha256 = "sha256-aYy0TOfNIqx44UBXJhewvxi+oSAWjmi/32WvI3HJ3MM=";
tags = [ "extended" ];
subPackages = [ "." ];
- nativeBuildInputs = [ installShellFiles ];
-
- postInstall = ''
- $out/bin/hugo gen man
- installManPage man/*
- '';
-
meta = {
license = lib.licenses.asl20;
homepage = "https://gohugo.io";
description = "A fast and modern static website engine";
- maintainers = with lib.maintainers; [ schneefux Br1ght0ne Frostman ];
};
}) { };
-in mkShellPure {
+ shell = pkgs.writeShellApplication {
+ inherit name;
+ text = ''
+ /usr/bin/env --ignore-environment /bin/sh -c ${
+ pkgs.writeScript name ''
+ export PS1='\h (${name}) \W \$ '
+ export HOME=$PWD
+ export HISTFILE=
+ export DENO_DIR=vendor
+ export DENO_NO_UPDATE_CHECK=1
+ export PATH=${pkgs.lib.strings.makeBinPath [
+ hugo
+ pkgs.busybox
+ pkgs.caddy
+ pkgs.check-jsonschema
+ pkgs.curl
+ pkgs.deno
+ pkgs.entr
+ pkgs.git
+ pkgs.gnumake
+ pkgs.inotify-tools
+ pkgs.jing
+ pkgs.libxml2
+ pkgs.libxslt
+ pkgs.unixtools.column
+ pkgs.validator-nu
+ pkgs.xmlstarlet
+ pkgs.yj
+ ]}
+ /bin/sh
+ ''
+ };
+ '';
+ };
+in pkgs.mkShell {
inherit hugo;
-
- packages = [
- hugo
- validatornu
- pkgs.busybox
- pkgs.deno
- pkgs.entr
- pkgs.git
- pkgs.gnumake
- pkgs.php
- pkgs.subversion
- pkgs.yj
- ];
-
- shellHook = ''
- export PS1='\h (${name}) \W \$ '
- '';
+ shellHook = "exec ${shell}/bin/${shell.name}";
}
diff --git a/static/icons/feather/LICENSE b/static/icons/feather/LICENSE
index b869713..1f4f433 100644
--- a/static/icons/feather/LICENSE
+++ b/static/icons/feather/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2013-2017 Cole Bemis
+Copyright (c) 2013-2023 Cole Bemis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE. \ No newline at end of file
+SOFTWARE.
diff --git a/static/icons/feather/alert-circle.svg b/static/icons/feather/alert-circle.svg
index 57fbe36..3672e20 100644
--- a/static/icons/feather/alert-circle.svg
+++ b/static/icons/feather/alert-circle.svg
@@ -1,15 +1,26 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="12"
+ cy="12"
+ r="10"
+ /><line
+ x1="12"
+ x2="12"
+ y1="8"
+ y2="12"
+ /><line
+ x1="12"
+ x2="12.01"
+ y1="16"
+ y2="16"
+ /></svg
>
- <circle cx="12" cy="12" r="10" />
- <line x1="12" y1="8" x2="12" y2="12" />
- <line x1="12" y1="16" x2="12.01" y2="16" />
-</svg>
diff --git a/static/icons/feather/archive.svg b/static/icons/feather/archive.svg
deleted file mode 100644
index 978eb76..0000000
--- a/static/icons/feather/archive.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <polyline points="21 8 21 21 3 21 3 8" />
- <rect x="1" y="3" width="22" height="5" />
- <line x1="10" y1="12" x2="14" y2="12" />
-</svg>
diff --git a/static/icons/feather/arrow-down-circle.svg b/static/icons/feather/arrow-down-circle.svg
new file mode 100644
index 0000000..816acdd
--- /dev/null
+++ b/static/icons/feather/arrow-down-circle.svg
@@ -0,0 +1,23 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="12"
+ cy="12"
+ r="10"
+ /><polyline
+ points="8 12 12 16 16 12"
+ /><line
+ x1="12"
+ x2="12"
+ y1="8"
+ y2="16"
+ /></svg
+>
diff --git a/static/icons/feather/arrow-left.svg b/static/icons/feather/arrow-left.svg
index ce06f88..aebfb9e 100644
--- a/static/icons/feather/arrow-left.svg
+++ b/static/icons/feather/arrow-left.svg
@@ -1,14 +1,19 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><line
+ x1="19"
+ x2="5"
+ y1="12"
+ y2="12"
+ /><polyline
+ points="12 19 5 12 12 5"
+ /></svg
>
- <line x1="19" y1="12" x2="5" y2="12" />
- <polyline points="12 19 5 12 12 5" />
-</svg>
diff --git a/static/icons/feather/arrow-right.svg b/static/icons/feather/arrow-right.svg
index 5c5494f..96fbe50 100644
--- a/static/icons/feather/arrow-right.svg
+++ b/static/icons/feather/arrow-right.svg
@@ -1,14 +1,19 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><line
+ x1="5"
+ x2="19"
+ y1="12"
+ y2="12"
+ /><polyline
+ points="12 5 19 12 12 19"
+ /></svg
>
- <line x1="5" y1="12" x2="19" y2="12" />
- <polyline points="12 5 19 12 12 19" />
-</svg>
diff --git a/static/icons/feather/arrow-up.svg b/static/icons/feather/arrow-up.svg
index f1ff621..8da7d1e 100644
--- a/static/icons/feather/arrow-up.svg
+++ b/static/icons/feather/arrow-up.svg
@@ -1,14 +1,19 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><line
+ x1="12"
+ x2="12"
+ y1="19"
+ y2="5"
+ /><polyline
+ points="5 12 12 5 19 12"
+ /></svg
>
- <line x1="12" y1="19" x2="12" y2="5" />
- <polyline points="5 12 12 5 19 12" />
-</svg>
diff --git a/static/icons/feather/at-sign.svg b/static/icons/feather/at-sign.svg
new file mode 100644
index 0000000..28534c6
--- /dev/null
+++ b/static/icons/feather/at-sign.svg
@@ -0,0 +1,18 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="12"
+ cy="12"
+ r="4"
+ /><path
+ d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"
+ /></svg
+>
diff --git a/static/icons/feather/bookmark.svg b/static/icons/feather/bookmark.svg
new file mode 100644
index 0000000..c553459
--- /dev/null
+++ b/static/icons/feather/bookmark.svg
@@ -0,0 +1,14 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"
+ /></svg
+>
diff --git a/static/icons/feather/calendar.svg b/static/icons/feather/calendar.svg
new file mode 100644
index 0000000..9c3693e
--- /dev/null
+++ b/static/icons/feather/calendar.svg
@@ -0,0 +1,34 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><rect
+ height="18"
+ rx="2"
+ ry="2"
+ width="18"
+ x="3"
+ y="4"
+ /><line
+ x1="16"
+ x2="16"
+ y1="2"
+ y2="6"
+ /><line
+ x1="8"
+ x2="8"
+ y1="2"
+ y2="6"
+ /><line
+ x1="3"
+ x2="21"
+ y1="10"
+ y2="10"
+ /></svg
+>
diff --git a/static/icons/feather/circle.svg b/static/icons/feather/circle.svg
deleted file mode 100644
index 1717bb4..0000000
--- a/static/icons/feather/circle.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <circle cx="12" cy="12" r="10" />
-</svg>
diff --git a/static/icons/feather/clock.svg b/static/icons/feather/clock.svg
index 8ce25b2..9c69907 100644
--- a/static/icons/feather/clock.svg
+++ b/static/icons/feather/clock.svg
@@ -1,14 +1,18 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="12"
+ cy="12"
+ r="10"
+ /><polyline
+ points="12 6 12 12 16 14"
+ /></svg
>
- <circle cx="12" cy="12" r="10" />
- <polyline points="12 6 12 12 16 14" />
-</svg>
diff --git a/static/icons/feather/copy.svg b/static/icons/feather/copy.svg
deleted file mode 100644
index c8d4956..0000000
--- a/static/icons/feather/copy.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
- <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
-</svg>
diff --git a/static/icons/feather/edit.svg b/static/icons/feather/edit.svg
new file mode 100644
index 0000000..a6d88b8
--- /dev/null
+++ b/static/icons/feather/edit.svg
@@ -0,0 +1,16 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
+ /><path
+ d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
+ /></svg
+>
diff --git a/static/icons/feather/external-link.svg b/static/icons/feather/external-link.svg
new file mode 100644
index 0000000..a17c25b
--- /dev/null
+++ b/static/icons/feather/external-link.svg
@@ -0,0 +1,21 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"
+ /><polyline
+ points="15 3 21 3 21 9"
+ /><line
+ x1="10"
+ x2="21"
+ y1="14"
+ y2="3"
+ /></svg
+>
diff --git a/static/icons/feather/eye-off.svg b/static/icons/feather/eye-off.svg
index 98c45f6..0b8c1ee 100644
--- a/static/icons/feather/eye-off.svg
+++ b/static/icons/feather/eye-off.svg
@@ -1,14 +1,19 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"
+ /><line
+ x1="1"
+ x2="23"
+ y1="1"
+ y2="23"
+ /></svg
>
- <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" />
- <line x1="1" y1="1" x2="23" y2="23" />
-</svg>
diff --git a/static/icons/feather/eye.svg b/static/icons/feather/eye.svg
new file mode 100644
index 0000000..de178f2
--- /dev/null
+++ b/static/icons/feather/eye.svg
@@ -0,0 +1,18 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"
+ /><circle
+ cx="12"
+ cy="12"
+ r="3"
+ /></svg
+>
diff --git a/static/icons/feather/file-text.svg b/static/icons/feather/file-text.svg
new file mode 100644
index 0000000..6c06a4e
--- /dev/null
+++ b/static/icons/feather/file-text.svg
@@ -0,0 +1,28 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"
+ /><polyline
+ points="14 2 14 8 20 8"
+ /><line
+ x1="16"
+ x2="8"
+ y1="13"
+ y2="13"
+ /><line
+ x1="16"
+ x2="8"
+ y1="17"
+ y2="17"
+ /><polyline
+ points="10 9 9 9 8 9"
+ /></svg
+>
diff --git a/static/icons/feather/git-commit.svg b/static/icons/feather/git-commit.svg
deleted file mode 100644
index 1574fbd..0000000
--- a/static/icons/feather/git-commit.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <circle cx="12" cy="12" r="4" />
- <line x1="1.05" y1="12" x2="7" y2="12" />
- <line x1="17.01" y1="12" x2="22.96" y2="12" />
-</svg>
diff --git a/static/icons/feather/globe.svg b/static/icons/feather/globe.svg
index a9c820f..00f792d 100644
--- a/static/icons/feather/globe.svg
+++ b/static/icons/feather/globe.svg
@@ -1,15 +1,23 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="12"
+ cy="12"
+ r="10"
+ /><line
+ x1="2"
+ x2="22"
+ y1="12"
+ y2="12"
+ /><path
+ d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"
+ /></svg
>
- <circle cx="12" cy="12" r="10" />
- <line x1="2" y1="12" x2="22" y2="12" />
- <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
-</svg>
diff --git a/static/icons/feather/heart.svg b/static/icons/feather/heart.svg
deleted file mode 100644
index 8e0b98d..0000000
--- a/static/icons/feather/heart.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
-</svg>
diff --git a/static/icons/feather/home.svg b/static/icons/feather/home.svg
deleted file mode 100644
index 9cd8f76..0000000
--- a/static/icons/feather/home.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
- <polyline points="9 22 9 12 15 12 15 22" />
-</svg>
diff --git a/static/icons/feather/link.svg b/static/icons/feather/link.svg
new file mode 100644
index 0000000..51f6aac
--- /dev/null
+++ b/static/icons/feather/link.svg
@@ -0,0 +1,16 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
+ /><path
+ d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
+ /></svg
+>
diff --git a/static/icons/feather/map-pin.svg b/static/icons/feather/map-pin.svg
index 8f5f320..7802b5a 100644
--- a/static/icons/feather/map-pin.svg
+++ b/static/icons/feather/map-pin.svg
@@ -1,14 +1,18 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><path
+ d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"
+ /><circle
+ cx="12"
+ cy="10"
+ r="3"
+ /></svg
>
- <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
- <circle cx="12" cy="10" r="3" />
-</svg>
diff --git a/static/icons/feather/refresh-cw.svg b/static/icons/feather/refresh-cw.svg
new file mode 100644
index 0000000..f48fd7e
--- /dev/null
+++ b/static/icons/feather/refresh-cw.svg
@@ -0,0 +1,18 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><polyline
+ points="23 4 23 10 17 10"
+ /><polyline
+ points="1 20 1 14 7 14"
+ /><path
+ d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"
+ /></svg
+>
diff --git a/static/icons/feather/rss.svg b/static/icons/feather/rss.svg
deleted file mode 100644
index 3b87036..0000000
--- a/static/icons/feather/rss.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M4 11a9 9 0 0 1 9 9" />
- <path d="M4 4a16 16 0 0 1 16 16" />
- <circle cx="5" cy="19" r="1" />
-</svg>
diff --git a/static/icons/feather/search.svg b/static/icons/feather/search.svg
index 89a8636..8eaab65 100644
--- a/static/icons/feather/search.svg
+++ b/static/icons/feather/search.svg
@@ -1,14 +1,21 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><circle
+ cx="11"
+ cy="11"
+ r="8"
+ /><line
+ x1="21"
+ x2="16.65"
+ y1="21"
+ y2="16.65"
+ /></svg
>
- <circle cx="11" cy="11" r="8" />
- <line x1="21" y1="21" x2="16.65" y2="16.65" />
-</svg>
diff --git a/static/icons/feather/tag.svg b/static/icons/feather/tag.svg
deleted file mode 100644
index e8500cd..0000000
--- a/static/icons/feather/tag.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" />
- <line x1="7" y1="7" x2="7.01" y2="7" />
-</svg>
diff --git a/static/icons/feather/trash-2.svg b/static/icons/feather/trash-2.svg
index f3bd2bd..462a3f7 100644
--- a/static/icons/feather/trash-2.svg
+++ b/static/icons/feather/trash-2.svg
@@ -1,16 +1,26 @@
<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ ><polyline
+ points="3 6 5 6 21 6"
+ /><path
+ d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
+ /><line
+ x1="10"
+ x2="10"
+ y1="11"
+ y2="17"
+ /><line
+ x1="14"
+ x2="14"
+ y1="11"
+ y2="17"
+ /></svg
>
- <polyline points="3 6 5 6 21 6" />
- <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
- <line x1="10" y1="11" x2="10" y2="17" />
- <line x1="14" y1="11" x2="14" y2="17" />
-</svg>
diff --git a/static/icons/feather/user.svg b/static/icons/feather/user.svg
deleted file mode 100644
index f075a65..0000000
--- a/static/icons/feather/user.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
- <circle cx="12" cy="7" r="4" />
-</svg>
diff --git a/static/icons/feather/users.svg b/static/icons/feather/users.svg
deleted file mode 100644
index eb87d02..0000000
--- a/static/icons/feather/users.svg
+++ /dev/null
@@ -1,16 +0,0 @@
-<svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
->
- <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
- <circle cx="9" cy="7" r="4" />
- <path d="M23 21v-2a4 4 0 0 0-3-3.87" />
- <path d="M16 3.13a4 4 0 0 1 0 7.75" />
-</svg>
diff --git a/static/icons/tabler/LICENSE b/static/icons/tabler/LICENSE
index 1f192ee..974db1a 100644
--- a/static/icons/tabler/LICENSE
+++ b/static/icons/tabler/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020-2022 Paweł Kuna
+Copyright (c) 2020-2024 Paweł Kuna
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/static/icons/tabler/archive.svg b/static/icons/tabler/archive.svg
new file mode 100644
index 0000000..d55999b
--- /dev/null
+++ b/static/icons/tabler/archive.svg
@@ -0,0 +1,22 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M3 4m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"
+ />
+ <path
+ d="M5 8v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-10"
+ />
+ <path
+ d="M10 12l4 0"
+ />
+</svg
+>
diff --git a/static/icons/tabler/book-2.svg b/static/icons/tabler/book-2.svg
index f8e33f0..0800060 100644
--- a/static/icons/tabler/book-2.svg
+++ b/static/icons/tabler/book-2.svg
@@ -1,9 +1,22 @@
-<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-book-2" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
- <desc>Download more icon variants from https://tabler-icons.io/i/book-2</desc>
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
- <path d="M19 4v16h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12z" />
- <path d="M19 16h-12a2 2 0 0 0 -2 2" />
- <path d="M9 8h6" />
-</svg>
-
-
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M19 4v16h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12z"
+ />
+ <path
+ d="M19 16h-12a2 2 0 0 0 -2 2"
+ />
+ <path
+ d="M9 8h6"
+ />
+</svg
+>
diff --git a/static/icons/tabler/circle.svg b/static/icons/tabler/circle.svg
new file mode 100644
index 0000000..5660b32
--- /dev/null
+++ b/static/icons/tabler/circle.svg
@@ -0,0 +1,16 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"
+ />
+</svg
+>
diff --git a/static/icons/tabler/clock.svg b/static/icons/tabler/clock.svg
index 00f3aa4..7ad7d57 100644
--- a/static/icons/tabler/clock.svg
+++ b/static/icons/tabler/clock.svg
@@ -1,8 +1,19 @@
-<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clock" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
- <desc>Download more icon variants from https://tabler-icons.io/i/clock</desc>
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
- <circle cx="12" cy="12" r="9" />
- <polyline points="12 7 12 12 15 15" />
-</svg>
-
-
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"
+ />
+ <path
+ d="M12 7v5l3 3"
+ />
+</svg
+>
diff --git a/static/icons/tabler/code.svg b/static/icons/tabler/code.svg
new file mode 100644
index 0000000..f9f1ba3
--- /dev/null
+++ b/static/icons/tabler/code.svg
@@ -0,0 +1,22 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M7 8l-4 4l4 4"
+ />
+ <path
+ d="M17 8l4 4l-4 4"
+ />
+ <path
+ d="M14 4l-4 16"
+ />
+</svg
+>
diff --git a/static/icons/tabler/git-fork.svg b/static/icons/tabler/git-fork.svg
new file mode 100644
index 0000000..a27d387
--- /dev/null
+++ b/static/icons/tabler/git-fork.svg
@@ -0,0 +1,28 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M12 18m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"
+ />
+ <path
+ d="M7 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"
+ />
+ <path
+ d="M17 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"
+ />
+ <path
+ d="M7 8v2a2 2 0 0 0 2 2h6a2 2 0 0 0 2 -2v-2"
+ />
+ <path
+ d="M12 12l0 4"
+ />
+</svg
+>
diff --git a/static/icons/tabler/home.svg b/static/icons/tabler/home.svg
new file mode 100644
index 0000000..ebe632d
--- /dev/null
+++ b/static/icons/tabler/home.svg
@@ -0,0 +1,22 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M5 12l-2 0l9 -9l9 9l-2 0"
+ />
+ <path
+ d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"
+ />
+ <path
+ d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"
+ />
+</svg
+>
diff --git a/static/icons/tabler/notes.svg b/static/icons/tabler/notes.svg
new file mode 100644
index 0000000..a102d6e
--- /dev/null
+++ b/static/icons/tabler/notes.svg
@@ -0,0 +1,25 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M5 3m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z"
+ />
+ <path
+ d="M9 7l6 0"
+ />
+ <path
+ d="M9 11l6 0"
+ />
+ <path
+ d="M9 15l4 0"
+ />
+</svg
+>
diff --git a/static/icons/tabler/pinned.svg b/static/icons/tabler/pinned.svg
index 6a2c4dc..74002cb 100644
--- a/static/icons/tabler/pinned.svg
+++ b/static/icons/tabler/pinned.svg
@@ -1,9 +1,22 @@
-<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-pinned" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
- <desc>Download more icon variants from https://tabler-icons.io/i/pinned</desc>
- <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
- <path d="M9 4v6l-2 4v2h10v-2l-2 -4v-6" />
- <line x1="12" y1="16" x2="12" y2="21" />
- <line x1="8" y1="4" x2="16" y2="4" />
-</svg>
-
-
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M9 4v6l-2 4v2h10v-2l-2 -4v-6"
+ />
+ <path
+ d="M12 16l0 5"
+ />
+ <path
+ d="M8 4l8 0"
+ />
+</svg
+>
diff --git a/static/icons/tabler/robot.svg b/static/icons/tabler/robot.svg
new file mode 100644
index 0000000..8db2809
--- /dev/null
+++ b/static/icons/tabler/robot.svg
@@ -0,0 +1,40 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M6 4m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"
+ />
+ <path
+ d="M12 2v2"
+ />
+ <path
+ d="M9 12v9"
+ />
+ <path
+ d="M15 12v9"
+ />
+ <path
+ d="M5 16l4 -2"
+ />
+ <path
+ d="M15 14l4 2"
+ />
+ <path
+ d="M9 18h6"
+ />
+ <path
+ d="M10 8v.01"
+ />
+ <path
+ d="M14 8v.01"
+ />
+</svg
+>
diff --git a/static/icons/tabler/rss.svg b/static/icons/tabler/rss.svg
new file mode 100644
index 0000000..884e1a6
--- /dev/null
+++ b/static/icons/tabler/rss.svg
@@ -0,0 +1,22 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M5 19m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"
+ />
+ <path
+ d="M4 4a16 16 0 0 1 16 16"
+ />
+ <path
+ d="M4 11a9 9 0 0 1 9 9"
+ />
+</svg
+>
diff --git a/static/icons/tabler/settings.svg b/static/icons/tabler/settings.svg
new file mode 100644
index 0000000..02bea1e
--- /dev/null
+++ b/static/icons/tabler/settings.svg
@@ -0,0 +1,19 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065z"
+ />
+ <path
+ d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"
+ />
+</svg
+>
diff --git a/static/icons/tabler/square-letter-m.svg b/static/icons/tabler/square-letter-m.svg
new file mode 100644
index 0000000..721e549
--- /dev/null
+++ b/static/icons/tabler/square-letter-m.svg
@@ -0,0 +1,19 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"
+ />
+ <path
+ d="M9 16v-8l3 5l3 -5v8"
+ />
+</svg
+>
diff --git a/static/icons/tabler/tag.svg b/static/icons/tabler/tag.svg
new file mode 100644
index 0000000..abbb8c6
--- /dev/null
+++ b/static/icons/tabler/tag.svg
@@ -0,0 +1,19 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M7.5 7.5m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"
+ />
+ <path
+ d="M3 6v5.172a2 2 0 0 0 .586 1.414l7.71 7.71a2.41 2.41 0 0 0 3.408 0l5.592 -5.592a2.41 2.41 0 0 0 0 -3.408l-7.71 -7.71a2 2 0 0 0 -1.414 -.586h-5.172a3 3 0 0 0 -3 3z"
+ />
+</svg
+>
diff --git a/static/icons/tabler/users.svg b/static/icons/tabler/users.svg
new file mode 100644
index 0000000..6fa6286
--- /dev/null
+++ b/static/icons/tabler/users.svg
@@ -0,0 +1,25 @@
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ height="24"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2"
+ viewBox="0 0 24 24"
+ width="24"
+ >
+ <path
+ d="M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"
+ />
+ <path
+ d="M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"
+ />
+ <path
+ d="M16 3.13a4 4 0 0 1 0 7.75"
+ />
+ <path
+ d="M21 21v-2a4 4 0 0 0 -3 -3.85"
+ />
+</svg
+>
diff --git a/static/js/autoplay.ts b/static/js/autoplay.ts
new file mode 100644
index 0000000..5987576
--- /dev/null
+++ b/static/js/autoplay.ts
@@ -0,0 +1,42 @@
+(function () {
+ function viewport(element) {
+ const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {
+ offset: { top: -50, left: 0, bottom: -50, right: 0 }
+ };
+ const view = element.getBoundingClientRect();
+ return view.top >= -options.offset.top
+ && view.left >= -options.offset.left
+ && view.bottom <= (self.innerHeight || document.documentElement.clientHeight) + options.offset.bottom
+ && view.right <= (self.innerWidth || document.documentElement.clientWidth) + options.offset.right;
+ };
+
+ ["scroll", "DOMContentLoaded"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ let first = true;
+ let videos = document.querySelectorAll("video");
+
+ for (i = 0; i < videos.length; i++) {
+ videos[i].autoplay = true;
+ videos[i].controls = true;
+ videos[i].loop = true;
+ videos[i].muted = true;
+ videos[i].playsinline = true;
+
+ videos[i].setAttribute("autoplay", true);
+ videos[i].setAttribute("controls", true);
+ videos[i].setAttribute("loop", true);
+ videos[i].setAttribute("muted", true);
+ videos[i].setAttribute("playsinline", true);
+
+ const onscreen = viewport(videos[i]);
+
+ if (first && onscreen) {
+ videos[i].play();
+ first = false;
+ } else {
+ videos[i].pause();
+ }
+ }
+ });
+ });
+})();
diff --git a/static/js/code-copy.ts b/static/js/codecopy.ts
index 4c22d07..9885ad8 100644
--- a/static/js/code-copy.ts
+++ b/static/js/codecopy.ts
@@ -7,15 +7,12 @@
setTimeout(
async () => {
await navigator.clipboard.writeText(text);
- console.log("Info: Code block text copied succesfully.");
+ console.log("INFO: Code text copied successfully");
},
3000,
);
- } catch (err) {
- console.error(
- "Error: navigator.clipboard.writeText() failed.",
- err,
- );
+ } catch (error) {
+ console.error("ERROR: Code text copy failed", error);
}
},
);
diff --git a/static/js/contextmenu.ts b/static/js/contextmenu.ts
new file mode 100644
index 0000000..5add288
--- /dev/null
+++ b/static/js/contextmenu.ts
@@ -0,0 +1,28 @@
+(function () {
+ const hide = function (triggers) {
+ for (let i = 0; i < triggers.length; i++) {
+ triggers[i].checked = false;
+ }
+ };
+
+ const hideIfClickedOutside = function (menus, triggers, event) {
+ for (let i = 0; i < menus.length; i++) {
+ const active = triggers[i].checked === true;
+ const outside = !menus[i].contains(event.target);
+ if (outside && active) hide(triggers);
+ }
+ };
+
+ self.addEventListener("scroll", function () {
+ const triggers = document.querySelectorAll("menu input");
+ hide(triggers);
+ });
+
+ ["click", "touchstart"].forEach(function (event) {
+ self.addEventListener(event, function (event) {
+ const menus = document.querySelectorAll("menu");
+ const triggers = document.querySelectorAll("menu input");
+ hideIfClickedOutside(menus, triggers, event);
+ });
+ });
+})();
diff --git a/static/js/domfilter.ts b/static/js/domfilter.ts
new file mode 100644
index 0000000..8900e2f
--- /dev/null
+++ b/static/js/domfilter.ts
@@ -0,0 +1,145 @@
+/*
+ * DOM Filter Copyright (C) 2024 Thedro Neely
+ * Licence: AGPL | https://www.gnu.org/licenses/agpl-3.0.txt
+*/
+
+(function () {
+ type millisecond = number;
+ const timeout: millisecond = 300;
+
+ const state = "on";
+ const key = "config.navigation.fast";
+
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (callback && http.readyState === 4) {
+ if (http.status === 200) callback(http);
+ else {
+ console.error("ERROR: Unable to navigate", http);
+ self.location.href = url;
+ }
+ }
+ };
+ http.open(method, url);
+ http.timeout = timeout;
+ http.send();
+ return http;
+ }
+
+ function styles(node) {
+ return (node.nodeName === "LINK") && node.rel && node.rel.includes("stylesheet");
+ }
+
+ function scripts(node) {
+ return (node.nodeName === "SCRIPT") && node.hasAttribute("src");
+ }
+
+ function filter(url, http) {
+ let live = document;
+ let node = live.head.childNodes.length;
+ let next = (new DOMParser()).parseFromString(http.responseText, "text/html");
+
+ if (next.doctype === null || !http.getResponseHeader("content-type").includes("text/html")) return false;
+
+ while (node--) {
+ if (styles(live.head.childNodes[node]) || scripts(live.head.childNodes[node])) {
+ // console.log("INFO: Persist:", live.head.childNodes[node]);
+ } else {
+ live.head.removeChild(live.head.childNodes[node]);
+ }
+ }
+
+ while (next.head.firstChild) {
+ if (styles(next.head.firstChild) || scripts(next.head.firstChild)) {
+ next.head.removeChild(next.head.firstChild);
+ } else {
+ live.head.appendChild(next.head.firstChild);
+ }
+ }
+
+ while (live.documentElement.attributes.length > 0) {
+ live.documentElement.removeAttribute(
+ live.documentElement.attributes[live.documentElement.attributes.length - 1].name,
+ );
+ }
+
+ while (next.documentElement.attributes.length > 0) {
+ live.documentElement.setAttribute(
+ next.documentElement.attributes[next.documentElement.attributes.length - 1].name,
+ next.documentElement.attributes[next.documentElement.attributes.length - 1].value,
+ );
+ next.documentElement.removeAttribute(
+ next.documentElement.attributes[next.documentElement.attributes.length - 1].name,
+ );
+ }
+
+ live.body.parentElement.replaceChild(next.body, live.body);
+ }
+
+ function persist() {
+ let persist = document.createElement("link");
+ persist.rel = "location";
+ persist.target = JSON.stringify(self.location);
+ document.head.appendChild(persist);
+ }
+
+ self.addEventListener("DOMContentLoaded", function () {
+ if (localStorage[key] !== state) return;
+ persist();
+ });
+
+ self.addEventListener("popstate", function (event) {
+ if (localStorage[key] !== state) return;
+ const link = JSON.parse(document.querySelector('link[rel="location"]').target);
+ const url = event.target.location;
+ const hashed = link.pathname === url.pathname;
+ if (hashed) return;
+ fetch(url, "GET", function (http) {
+ if (filter(url, http) === false) return self.location.href = url;
+ persist();
+ self.document.dispatchEvent(new CustomEvent("URLChangedCustomEvent", { bubbles: true }));
+ });
+ });
+
+ self.addEventListener("click", function (event) {
+ if (localStorage[key] !== state) return;
+ const links = document.querySelectorAll("a");
+ for (let i = 0; i < links.length; i++) {
+ const active = links[i].contains(event.target);
+ const change = self.location.href !== links[i].href;
+ const view = links[i].attributes.hasOwnProperty("download") === false;
+ const local = self.location.origin === links[i].origin && links[i].target !== "_self";
+ const hashed = self.location.pathname === links[i].pathname && links[i].href.includes("#");
+ if (active && local && change && view && (hashed === false)) {
+ event.preventDefault();
+ const url = links[i].href;
+ links[i].style.cursor = "wait";
+ fetch(url, "GET", function (http) {
+ links[i].removeAttribute("style")
+ if (filter(url, http) === false) return self.location.href = url;
+ history.pushState({}, "", links[i].href);
+ persist();
+ self.document.dispatchEvent(new CustomEvent("URLChangedCustomEvent", { bubbles: true }));
+ });
+ }
+ }
+ });
+})();
+
+/*
+ * Copyright (C) 2024 Thedro Neely
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
diff --git a/static/js/fixedsearch.ts b/static/js/fixedsearch.ts
index 2b0abda..04d318b 100644
--- a/static/js/fixedsearch.ts
+++ b/static/js/fixedsearch.ts
@@ -1,17 +1,71 @@
+/*
+ * Fixed Search Copyright (C) 2020 Heracles Papatheodorou
+ * Copyright (C) Craig Mod, Eddie Webb, and Matthew Daly
+ * https://gist.github.com/Arty2/8b0c43581013753438a3d35c15091a9f#file-license-md
+ * Licence: MIT | https://mit-license.org/
+*/
+
(function () {
- self.addEventListener("DOMContentLoaded", function () {
- /*
- Originally Based on fixedsearch, a super fast, client side search for Hugo.io with Fusejs.io
- based on https://gist.github.com/cmod/5410eae147e4318164258742dd053993
- */
-
- const form = document.getElementById("search-form"); // search form
- const query = document.getElementById("search-input"); // input box for search
- const submit = document.getElementById("search-submit"); // form submit button
- const dropdown = document.getElementById("search-results"); // targets the <ul>
- const container = document.getElementById("search-frame"); // targets the upper parent container
+ ["DOMContentLoaded", "URLChangedCustomEvent"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ const container = document.querySelector("search-box");
+ const dropdown = document.querySelector("search-box ul");
+ const form = document.querySelector("search-box form");
+ const query = document.querySelector("search-box input");
+ const submit = document.querySelector("search-box button");
+
+ function first(element) {
+ if (element.firstChild.nextElementSibling) {
+ return element.firstChild.nextElementSibling.firstChild
+ .nextElementSibling;
+ }
+ }
+
+ function last(element) {
+ return element.lastElementChild.firstChild.nextElementSibling;
+ }
+
+ function next(element) {
+ return element.activeElement.parentElement.nextElementSibling.firstChild
+ .nextElementSibling.focus();
+ }
+
+ function previous(element) {
+ return element.activeElement.parentElement.previousElementSibling
+ .firstChild
+ .nextElementSibling.focus();
+ }
+
+ function press(keyname) {
+ document.dispatchEvent(new KeyboardEvent("keydown", { "key": keyname }));
+ }
+
+ let selected;
+
+ if (submit === null) return;
+
+ submit.addEventListener("click", function (event) {
+ if (selected) {
+ event.preventDefault();
+ selected.focus();
+ return selected.click();
+ }
+ first(dropdown).focus();
+ press("ArrowDown");
+ document.activeElement.click();
+ });
+
+ ["keyup", "click"].forEach(function (event) {
+ form.addEventListener(event, function () {
+ if (document.activeElement.nodeName === "A") {
+ return selected = document.activeElement;
+ }
+ selected = undefined;
+ });
+ });
form.addEventListener("focusin", function () {
+ container.setAttribute("data-focus", "");
initialize();
});
@@ -21,46 +75,40 @@
});
form.addEventListener("keydown", function (event) {
- const head =
- dropdown.firstChild.nextElementSibling.firstChild.nextElementSibling;
- const tail = dropdown.lastElementChild.firstChild.nextElementSibling;
-
// ESC (27)
- if (query.contains(event.target)) {
+ if (form.contains(event.target)) {
if (event.keyCode == 27) {
document.activeElement.blur();
dropdown.setAttribute("hidden", "");
+ container.removeAttribute("data-focus");
}
}
- // DOWN (40)
+ // BACKSPACE (8)
+ if (event.keyCode == 8) {
+ if (document.activeElement != query) {
+ event.preventDefault();
+ query.focus();
+ }
+ }
+
+ const head = first(dropdown);
+ const tail = last(dropdown);
+
+ // DOWN (40)
if (event.keyCode == 40) {
event.preventDefault();
if (document.activeElement == query) head.focus();
else if (document.activeElement == tail) query.focus();
- else {
- document.activeElement.parentElement.nextElementSibling.firstChild
- .nextElementSibling.focus();
- }
+ else next(document);
}
- // UP (38)
+ // UP (38)
if (event.keyCode == 38) {
event.preventDefault();
if (document.activeElement == query) tail.focus();
else if (document.activeElement == head) query.focus();
- else {
- document.activeElement.parentElement.previousElementSibling.firstChild
- .nextElementSibling.focus();
- }
- }
-
- // BACKSPACE (8)
- if (event.keyCode == 8) {
- if (document.activeElement != query) {
- event.preventDefault();
- query.focus();
- }
+ else previous(document);
}
// ENTER (13)
@@ -68,7 +116,7 @@
if (dropdown && document.activeElement == query) {
event.preventDefault();
head.focus();
- self.window.location = document.activeElement.href;
+ head.click();
}
}
});
@@ -85,30 +133,31 @@
scrolls++;
});
- document.addEventListener("click", function (event) {
- if (!form.contains(event.target)) {
+ self.addEventListener("click", function (event) {
+ if (
+ !form.contains(event.target) &&
+ !(document.activeElement === query) &&
+ !(document.activeElement === submit)
+ ) {
dropdown.setAttribute("hidden", "");
container.removeAttribute("data-focus");
}
});
- function fetch_JSON(path, callback) {
- const httpRequest = new XMLHttpRequest();
- httpRequest.onreadystatechange = function () {
- if (httpRequest.readyState === 4) {
- if (httpRequest.status === 200) {
- const data = JSON.parse(httpRequest.responseText);
- if (callback) callback(data);
- }
+ function fetch(url, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (http.readyState === 4 && http.status === 200 && callback) {
+ callback(http);
}
};
- httpRequest.open("GET", path);
- httpRequest.send();
+ http.open("GET", url);
+ http.send();
}
/* Load script based on https://stackoverflow.com/a/55451823 */
- function load_script(url) {
+ function script(url) {
return new Promise(function (resolve, reject) {
const script = document.createElement("script");
script.onerror = reject;
@@ -118,41 +167,64 @@
script,
document.currentScript,
);
- } else {
- document.head.appendChild(script);
- }
+ } else document.head.appendChild(script);
script.src = url;
});
}
- let first_run = true; // allow us to delay loading json data unless search activated
+ let data = {};
+ let boot = true;
+
+ const options = { key: ["title"] };
+
+ function isEmpty(obj) { return Object.keys(obj).length === 0; }
+
+ function appendItemsTo(local, remote) {
+ const paginated = Object.keys(remote).includes("next_url");
+ if (isEmpty(local)) {
+ local = remote;
+ } else {
+ local.items = local.items.concat(remote.items);
+ }
+ if (paginated) {
+ fetch(remote.next_url, function (request) {
+ appendItemsTo(local, JSON.parse(request.responseText));
+ });
+ } else search(query.value, data.items, options);
+ data = local;
+ }
function initialize() {
- if (first_run) {
- load_script(window.location.origin + "/js/fuzzysort.js")
- .then(() => {
- first_run = false;
- fetch_JSON("/index.json", function (data) {
- const options = {
- key: ["title"],
- };
-
- query.addEventListener("keyup", function () {
- search(query.value, data.items, options);
- });
+ if (boot) {
+ script(window.location.origin + "/js/fuzzysort.js")
+ .then(function () {
- query.addEventListener("focusin", function () {
- search(query.value, data.items, options);
- });
+ fetch("/index.json", function (request) {
+ appendItemsTo({}, JSON.parse(request.responseText));
+ search("", data.items, options);
+ boot = false;
+ });
- search(query.value, data.items, options);
+
+ ["keyup", "focusin"].forEach(function (event) {
+ query.addEventListener(event, function () {
+ if (data.items) search(query.value, data.items, options);
+ else { boot = true; initialize(); }
+ });
});
- }).catch((error) => {
- console.log("Error failed to load fuzzy sort: " + error);
+
+ }).catch(function (error) {
+ console.error("ERROR: Failed to load fuzzy search", error);
});
}
}
+ function escape(text) {
+ const escaped = document.createElement("textarea");
+ escaped.textContent = text;
+ return escaped.innerHTML;
+ }
+
function search(term, data, options) {
const results = fuzzysort.go(term, data, options);
let items = "";
@@ -160,36 +232,33 @@
if (results.length === 0 && term.length >= 0) {
let separator = "—";
if (term.length === 0) separator = "";
- items = `
- <li>
- <a href="javascript: void(0)" tabindex="0">${term} ${separator} No Results Found</a>
- </li>
- `;
+ items = '<li><a tabindex="0">'.concat(
+ escape(term),
+ " ",
+ ).concat(separator, " No Results Found</a></li>");
dropdown.removeAttribute("hidden");
container.setAttribute("data-focus", "");
} else {
dropdown.removeAttribute("hidden");
- for (const string in results.slice(0, 10)) {
+ for (var string in results.slice(0, 10)) {
+ const title = results[string].obj.title;
let highlight = fuzzysort.highlight(
- fuzzysort.single(term, results[string].obj.title),
+ fuzzysort.single(escape(term), escape(title)),
"<span>",
"</span>",
);
- if (highlight === null) {
- highlight = results[string].obj.title;
- }
+ if (highlight === null) highlight = title;
items = items +
- `
- <li>
- <a href="${results[string].obj.url}" tabindex="0">${highlight}</a>
- </li>
- `;
+ '\n<li>\n<a href="'.concat(
+ results[string].obj.url,
+ '" tabindex="0">',
+ ).concat(highlight, "</a>\n</li>\n");
}
}
-
dropdown.innerHTML = items;
}
});
+ });
})();
diff --git a/static/js/forms.ts b/static/js/forms.ts
new file mode 100644
index 0000000..263fda1
--- /dev/null
+++ b/static/js/forms.ts
@@ -0,0 +1,130 @@
+(function () {
+
+ const cookiesDisabled = !navigator.cookieEnabled;
+
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Cannot persist form state due to cookie restrictions");
+ }
+
+ const storage = document.createEvent("Event");
+ storage.initEvent("storage", true, true);
+
+ ["pageshow", "URLChangedCustomEvent", "DOMContentLoaded"].forEach(function (event) {
+ self.addEventListener(event, function (event) {
+ const input = Array.prototype.slice.call(document.querySelectorAll("form input"));
+ const select = Array.prototype.slice.call(document.querySelectorAll("form select"));
+ const textarea = Array.prototype.slice.call(document.querySelectorAll("form textarea"));
+ const summary = Array.prototype.slice.call(document.querySelectorAll("details summary"));
+
+ const states = input.concat(select).concat(textarea);
+
+ for (var i = 0; i < states.length; i++) {
+ const state = states[i];
+ const sync = i === states.length - 1;
+
+ if (localStorage[state.id]) {
+ if (state.type === "radio" || state.type === "checkbox") {
+ if (localStorage[state.id] === "on") state.checked = true;
+ } else state.value = localStorage[state.id];
+ }
+
+ if (sync) self.dispatchEvent(storage);
+
+ state.addEventListener("change", function (event) {
+
+ // console.log("INFO: STATE:", event.target);
+ // console.log("INFO: ID:", event.target.id);
+ // console.log("INFO: NAME:", event.target.name);
+ // console.log("INFO: TYPE:", event.target.type);
+ // console.log("INFO: VALUE:", event.target.value);
+ // console.log("INFO: CHECKED:", event.target.checked);
+
+ localStorage[event.target.id] = event.target.value;
+
+ const group = document.querySelectorAll("input[name='".concat(event.target.name, "']"));
+
+ for (var j = 0; j < group.length; j++) {
+ const member = group[j];
+ if ((member.type === "radio" || member.type === "checkbox") && !member.checked) {
+ localStorage[member.id] = "off";
+ }
+ }
+ self.dispatchEvent(new Event("storage"));
+ });
+ }
+
+ for (var k = 0; k < summary.length; k++) {
+ let child = summary[k];
+ let details = child.parentElement;
+
+ if (details.id && details.nodeName === "DETAILS") {
+ sessionStorage[details.id] === "false" && details.removeAttribute("open");
+ sessionStorage[details.id] === "true" && details.setAttribute("open", true);
+
+ child.addEventListener("click", function (event) {
+ let child = (event.target.nodeName === "SUMMARY" && event.target)
+ || event.target.parentElement;
+ let details = child.parentElement;
+ if (details.id && details.nodeName === "DETAILS") {
+ sessionStorage[details.id] = !details.open;
+ }
+ });
+ }
+ }
+ });
+ });
+
+ ["storage"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ let stylesheet;
+
+ stylesheet = document.querySelector('link[href$="default-simple.css"]')
+
+ if (localStorage["config.layout.simple"] === "on") stylesheet.rel = "stylesheet"
+ if (localStorage["config.layout.default"] === "on") stylesheet.rel = "alternate stylesheet"
+
+ stylesheet = document.querySelector('link[href$="default-fast.css"]')
+
+ if (localStorage["config.navigation.fast"] === "on") stylesheet.rel = "stylesheet"
+ if (localStorage["config.navigation.slow"] === "on") stylesheet.rel = "alternate stylesheet"
+
+ for (var i = 0; i < document.styleSheets.length; i++) {
+ let stylesheet = document.styleSheets[i];
+ for (var k = 0; k < stylesheet.rules.length; k++) {
+ let media = stylesheet.rules[k].media;
+ if (media && media.mediaText.includes("prefers-color-scheme")) {
+ if (localStorage["config.theme.light"] === "on") {
+ media.mediaText = "(prefers-color-scheme: dark)";
+ if (getComputedStyle(document.body).getPropertyValue("color-scheme") === "dark") { media.mediaText = "(prefers-color-scheme: light)"; }
+ }
+
+ if (localStorage["config.theme.auto"] === "on") {
+ media.mediaText = "(prefers-color-scheme: dark)";
+ }
+
+ if (localStorage["config.theme.dark"] === "on") {
+ media.mediaText = "(prefers-color-scheme: light)";
+ if (getComputedStyle(document.body).getPropertyValue("color-scheme") === "light") { media.mediaText = "(prefers-color-scheme: dark)"; }
+ }
+ }
+ }
+ }
+ });
+ });
+
+ const early = setInterval(persistence, 4);
+
+ function persistence() {
+ if (document.styleSheets.length > 0) {
+ self.dispatchEvent(storage);
+ clearInterval(early);
+ }
+ }
+
+ self.addEventListener("DOMContentLoaded", function () {
+ self.dispatchEvent(storage);
+ clearInterval(early);
+ });
+})();
diff --git a/static/js/fuzzysort.js b/static/js/fuzzysort.js
index c6797d8..71c2fcb 100644
--- a/static/js/fuzzysort.js
+++ b/static/js/fuzzysort.js
@@ -1,636 +1,549 @@
/*
- fuzzysort.js https://github.com/farzher/fuzzysort
- SublimeText-like Fuzzy Search
+ * Fuzzy Sort Copyright (C) 2018 Stephen Kamenar
+ * https://github.com/farzher/fuzzysort/blob/master/LICENSE
+ * Licence: MIT | https://mit-license.org/
+*/
- fuzzysort.single('fs', 'Fuzzy Search') // {score: -16}
- fuzzysort.single('test', 'test') // {score: 0}
- fuzzysort.single('doesnt exist', 'target') // null
+;((root, UMD) => {
+ if(typeof define === 'function' && define.amd) define([], UMD)
+ else if(typeof module === 'object' && module.exports) module.exports = UMD()
+ else root['fuzzysort'] = UMD()
+})(this, _ => {
+ 'use strict'
- fuzzysort.go('mr', [{file:'Monitor.cpp'}, {file:'MeshRenderer.cpp'}], {key:'file'})
- // [{score:-18, obj:{file:'MeshRenderer.cpp'}}, {score:-6009, obj:{file:'Monitor.cpp'}}]
+ var single = (search, target) => { if(search=='farzher')return{target:"farzher was here (^-^*)/",score:0,_indexes:[0]}
+ if(!search || !target) return NULL
- fuzzysort.go('mr', ['Monitor.cpp', 'MeshRenderer.cpp'])
- // [{score: -18, target: "MeshRenderer.cpp"}, {score: -6009, target: "Monitor.cpp"}]
+ var preparedSearch = getPreparedSearch(search)
+ if(!isObj(target)) target = getPrepared(target)
- fuzzysort.highlight(fuzzysort.single('fs', 'Fuzzy Search'), '<b>', '</b>')
- // <b>F</b>uzzy <b>S</b>earch
-*/
+ var searchBitflags = preparedSearch.bitflags
+ if((searchBitflags & target._bitflags) !== searchBitflags) return NULL
-// UMD (Universal Module Definition) for fuzzysort
-(function(root, UMD) {
- if(typeof define === 'function' && define.amd) {define([], UMD);}
- else if(typeof module === 'object' && module.exports) {module.exports = UMD();}
- else {root.fuzzysort = UMD();}
-})(this, function UMD() { function fuzzysortNew(instanceOptions) {
-
- var fuzzysort = {
-
- single: function(search, target, options) { if(search=='farzher'){return{target:"farzher was here (^-^*)/",score:0,indexes:[0,1,2,3,4,5,6]};}
- if(!search) {return null;}
- if(!isObj(search)) {search = fuzzysort.getPreparedSearch(search);}
-
- if(!target) {return null;}
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo
- : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo
- : true;
- var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo;
- return algorithm(search, target, search[0]);
- },
-
- go: function(search, targets, options) { if(search=='farzher'){return[{target:"farzher was here (^-^*)/",score:0,indexes:[0,1,2,3,4,5,6],obj:targets?targets[0]:null}];}
- if(!search) {return noResults;}
- search = fuzzysort.prepareSearch(search);
- var searchLowerCode = search[0];
-
- var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991;
- var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991;
- var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo
- : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo
- : true;
- var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo;
- var resultsLen = 0; var limitedCount = 0;
- var targetsLen = targets.length;
-
- // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys]
-
- // options.keys
- if(options && options.keys) {
- var scoreFn = options.scoreFn || defaultScoreFn;
- var keys = options.keys;
- var keysLen = keys.length;
- for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i];
- var objResults = new Array(keysLen);
- for (var keyI = keysLen - 1; keyI >= 0; --keyI) {
- var key = keys[keyI];
- var target = getValue(obj, key);
- if(!target) { objResults[keyI] = null; continue; }
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- objResults[keyI] = algorithm(search, target, searchLowerCode);
- }
- objResults.obj = obj; // before scoreFn so scoreFn can use it
- var score = scoreFn(objResults);
- if(score === null) {continue;}
- if(score < threshold) {continue;}
- objResults.score = score;
- if(resultsLen < limit) { q.add(objResults); ++resultsLen; }
- else {
- ++limitedCount;
- if(score > q.peek().score) {q.replaceTop(objResults);}
- }
- }
+ return algorithm(preparedSearch, target)
+ }
- // options.key
- } else if(options && options.key) {
- var key = options.key;
- for(var i = targetsLen - 1; i >= 0; --i) { var obj = targets[i];
- var target = getValue(obj, key);
- if(!target) {continue;}
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- var result = algorithm(search, target, searchLowerCode);
- if(result === null) {continue;}
- if(result.score < threshold) {continue;}
-
- // have to clone result so duplicate targets from different obj can each reference the correct obj
- result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj}; // hidden
-
- if(resultsLen < limit) { q.add(result); ++resultsLen; }
- else {
- ++limitedCount;
- if(result.score > q.peek().score) {q.replaceTop(result);}
- }
- }
- // no keys
- } else {
- for(var i = targetsLen - 1; i >= 0; --i) { var target = targets[i];
- if(!target) {continue;}
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- var result = algorithm(search, target, searchLowerCode);
- if(result === null) {continue;}
- if(result.score < threshold) {continue;}
- if(resultsLen < limit) { q.add(result); ++resultsLen; }
- else {
- ++limitedCount;
- if(result.score > q.peek().score) {q.replaceTop(result);}
- }
+ var go = (search, targets, options) => { if(search=='farzher')return[{target:"farzher was here (^-^*)/",score:0,_indexes:[0],obj:targets?targets[0]:NULL}]
+ if(!search) return options&&options.all ? all(search, targets, options) : noResults
+
+ var preparedSearch = getPreparedSearch(search)
+ var searchBitflags = preparedSearch.bitflags
+ var containsSpace = preparedSearch.containsSpace
+
+ var threshold = options&&options.threshold || INT_MIN
+ var limit = options&&options['limit'] || INT_MAX // for some reason only limit breaks when minified
+
+ var resultsLen = 0; var limitedCount = 0
+ var targetsLen = targets.length
+
+ // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys]
+
+ // options.key
+ if(options && options.key) {
+ var key = options.key
+ for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]
+ var target = getValue(obj, key)
+ if(!target) continue
+ if(!isObj(target)) target = getPrepared(target)
+
+ if((searchBitflags & target._bitflags) !== searchBitflags) continue
+ var result = algorithm(preparedSearch, target)
+ if(result === NULL) continue
+ if(result.score < threshold) continue
+
+ // have to clone result so duplicate targets from different obj can each reference the correct obj
+ result = {target:result.target, _targetLower:'', _targetLowerCodes:NULL, _nextBeginningIndexes:NULL, _bitflags:0, score:result.score, _indexes:result._indexes, obj:obj} // hidden
+
+ if(resultsLen < limit) { q.add(result); ++resultsLen }
+ else {
+ ++limitedCount
+ if(result.score > q.peek().score) q.replaceTop(result)
}
}
- if(resultsLen === 0) {return noResults;}
- var results = new Array(resultsLen);
- for(var i = resultsLen - 1; i >= 0; --i) {results[i] = q.poll();}
- results.total = resultsLen + limitedCount;
- return results;
- },
-
- goAsync: function(search, targets, options) {
- var canceled = false;
- var p = new Promise(function(resolve, reject) { if(search=='farzher'){return resolve([{target:"farzher was here (^-^*)/",score:0,indexes:[0,1,2,3,4,5,6],obj:targets?targets[0]:null}]);}
- if(!search) {return resolve(noResults);}
- search = fuzzysort.prepareSearch(search);
- var searchLowerCode = search[0];
-
- var q = fastpriorityqueue();
- var iCurrent = targets.length - 1;
- var threshold = options && options.threshold || instanceOptions && instanceOptions.threshold || -9007199254740991;
- var limit = options && options.limit || instanceOptions && instanceOptions.limit || 9007199254740991;
- var allowTypo = options && options.allowTypo!==undefined ? options.allowTypo
- : instanceOptions && instanceOptions.allowTypo!==undefined ? instanceOptions.allowTypo
- : true;
- var algorithm = allowTypo ? fuzzysort.algorithm : fuzzysort.algorithmNoTypo;
- var resultsLen = 0; var limitedCount = 0;
- function step() {
- if(canceled) {return reject('canceled');}
-
- var startMs = Date.now();
-
- // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys]
-
- // options.keys
- if(options && options.keys) {
- var scoreFn = options.scoreFn || defaultScoreFn;
- var keys = options.keys;
- var keysLen = keys.length;
- for(; iCurrent >= 0; --iCurrent) {
- if(iCurrent%1000/*itemsPerCheck*/ === 0) {
- if(Date.now() - startMs >= 10/*asyncInterval*/) {
- isNode?setImmediate(step):setTimeout(step);
- return;
- }
- }
-
- var obj = targets[iCurrent];
- var objResults = new Array(keysLen);
- for (var keyI = keysLen - 1; keyI >= 0; --keyI) {
- var key = keys[keyI];
- var target = getValue(obj, key);
- if(!target) { objResults[keyI] = null; continue; }
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- objResults[keyI] = algorithm(search, target, searchLowerCode);
- }
- objResults.obj = obj; // before scoreFn so scoreFn can use it
- var score = scoreFn(objResults);
- if(score === null) {continue;}
- if(score < threshold) {continue;}
- objResults.score = score;
- if(resultsLen < limit) { q.add(objResults); ++resultsLen; }
- else {
- ++limitedCount;
- if(score > q.peek().score) {q.replaceTop(objResults);}
- }
- }
-
- // options.key
- } else if(options && options.key) {
- var key = options.key;
- for(; iCurrent >= 0; --iCurrent) {
- if(iCurrent%1000/*itemsPerCheck*/ === 0) {
- if(Date.now() - startMs >= 10/*asyncInterval*/) {
- isNode?setImmediate(step):setTimeout(step);
- return;
- }
- }
-
- var obj = targets[iCurrent];
- var target = getValue(obj, key);
- if(!target) {continue;}
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- var result = algorithm(search, target, searchLowerCode);
- if(result === null) {continue;}
- if(result.score < threshold) {continue;}
-
- // have to clone result so duplicate targets from different obj can each reference the correct obj
- result = {target:result.target, _targetLowerCodes:null, _nextBeginningIndexes:null, score:result.score, indexes:result.indexes, obj:obj}; // hidden
-
- if(resultsLen < limit) { q.add(result); ++resultsLen; }
- else {
- ++limitedCount;
- if(result.score > q.peek().score) {q.replaceTop(result);}
- }
- }
-
- // no keys
- } else {
- for(; iCurrent >= 0; --iCurrent) {
- if(iCurrent%1000/*itemsPerCheck*/ === 0) {
- if(Date.now() - startMs >= 10/*asyncInterval*/) {
- isNode?setImmediate(step):setTimeout(step);
- return;
- }
- }
-
- var target = targets[iCurrent];
- if(!target) {continue;}
- if(!isObj(target)) {target = fuzzysort.getPrepared(target);}
-
- var result = algorithm(search, target, searchLowerCode);
- if(result === null) {continue;}
- if(result.score < threshold) {continue;}
- if(resultsLen < limit) { q.add(result); ++resultsLen; }
- else {
- ++limitedCount;
- if(result.score > q.peek().score) {q.replaceTop(result);}
- }
- }
- }
-
- if(resultsLen === 0) {return resolve(noResults);}
- var results = new Array(resultsLen);
- for(var i = resultsLen - 1; i >= 0; --i) {results[i] = q.poll();}
- results.total = resultsLen + limitedCount;
- resolve(results);
+ // options.keys
+ } else if(options && options.keys) {
+ var scoreFn = options['scoreFn'] || defaultScoreFn
+ var keys = options.keys
+ var keysLen = keys.length
+ for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]
+ var objResults = new Array(keysLen)
+ for (var keyI = 0; keyI < keysLen; ++keyI) {
+ var key = keys[keyI]
+ var target = getValue(obj, key)
+ if(!target) { objResults[keyI] = NULL; continue }
+ if(!isObj(target)) target = getPrepared(target)
+
+ if((searchBitflags & target._bitflags) !== searchBitflags) objResults[keyI] = NULL
+ else objResults[keyI] = algorithm(preparedSearch, target)
}
-
- isNode?setImmediate(step):step(); //setTimeout here is too slow
- });
- p.cancel = function() { canceled = true; };
- return p;
- },
-
- highlight: function(result, hOpen, hClose) {
- if(typeof hOpen == 'function') {return fuzzysort.highlightCallback(result, hOpen);}
- if(result === null) {return null;}
- if(hOpen === undefined) {hOpen = '<b>';}
- if(hClose === undefined) {hClose = '</b>';}
- var highlighted = '';
- var matchesIndex = 0;
- var opened = false;
- var target = result.target;
- var targetLen = target.length;
- var matchesBest = result.indexes;
- for(var i = 0; i < targetLen; ++i) { var char = target[i];
- if(matchesBest[matchesIndex] === i) {
- ++matchesIndex;
- if(!opened) { opened = true;
- highlighted += hOpen;
- }
-
- if(matchesIndex === matchesBest.length) {
- highlighted += char + hClose + target.substr(i+1);
- break;
- }
- } else {
- if(opened) { opened = false;
- highlighted += hClose;
- }
+ objResults.obj = obj // before scoreFn so scoreFn can use it
+ var score = scoreFn(objResults)
+ if(score === NULL) continue
+ if(score < threshold) continue
+ objResults.score = score
+ if(resultsLen < limit) { q.add(objResults); ++resultsLen }
+ else {
+ ++limitedCount
+ if(score > q.peek().score) q.replaceTop(objResults)
}
- highlighted += char;
}
- return highlighted;
- },
- highlightCallback: function(result, cb) {
- if(result === null) {return null;}
- var target = result.target;
- var targetLen = target.length;
- var indexes = result.indexes;
- var highlighted = '';
- var matchI = 0;
- var indexesI = 0;
- var opened = false;
- var result = [];
- for(var i = 0; i < targetLen; ++i) { var char = target[i];
- if(indexes[indexesI] === i) {
- ++indexesI;
- if(!opened) { opened = true;
- result.push(highlighted); highlighted = '';
- }
-
- if(indexesI === indexes.length) {
- highlighted += char;
- result.push(cb(highlighted, matchI++)); highlighted = '';
- result.push(target.substr(i+1));
- break;
- }
- } else {
- if(opened) { opened = false;
- result.push(cb(highlighted, matchI++)); highlighted = '';
- }
+ // no keys
+ } else {
+ for(var i = 0; i < targetsLen; ++i) { var target = targets[i]
+ if(!target) continue
+ if(!isObj(target)) target = getPrepared(target)
+
+ if((searchBitflags & target._bitflags) !== searchBitflags) continue
+ var result = algorithm(preparedSearch, target)
+ if(result === NULL) continue
+ if(result.score < threshold) continue
+ if(resultsLen < limit) { q.add(result); ++resultsLen }
+ else {
+ ++limitedCount
+ if(result.score > q.peek().score) q.replaceTop(result)
}
- highlighted += char;
}
- return result;
- },
-
- prepare: function(target) {
- if(!target) {return {target: '', _targetLowerCodes: [0/*this 0 doesn't make sense. here because an empty array causes the algorithm to deoptimize and run 50% slower!*/], _nextBeginningIndexes: null, score: null, indexes: null, obj: null};} // hidden
- return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:null, score:null, indexes:null, obj:null}; // hidden
- },
- prepareSlow: function(target) {
- if(!target) {return {target: '', _targetLowerCodes: [0/*this 0 doesn't make sense. here because an empty array causes the algorithm to deoptimize and run 50% slower!*/], _nextBeginningIndexes: null, score: null, indexes: null, obj: null};} // hidden
- return {target:target, _targetLowerCodes:fuzzysort.prepareLowerCodes(target), _nextBeginningIndexes:fuzzysort.prepareNextBeginningIndexes(target), score:null, indexes:null, obj:null}; // hidden
- },
- prepareSearch: function(search) {
- if(!search) {search = '';}
- return fuzzysort.prepareLowerCodes(search);
- },
-
-
-
- // Below this point is only internal code
- // Below this point is only internal code
- // Below this point is only internal code
- // Below this point is only internal code
-
-
-
- getPrepared: function(target) {
- if(target.length > 999) {return fuzzysort.prepare(target);} // don't cache huge targets
- var targetPrepared = preparedCache.get(target);
- if(targetPrepared !== undefined) {return targetPrepared;}
- targetPrepared = fuzzysort.prepare(target);
- preparedCache.set(target, targetPrepared);
- return targetPrepared;
- },
- getPreparedSearch: function(search) {
- if(search.length > 999) {return fuzzysort.prepareSearch(search);} // don't cache huge searches
- var searchPrepared = preparedSearchCache.get(search);
- if(searchPrepared !== undefined) {return searchPrepared;}
- searchPrepared = fuzzysort.prepareSearch(search);
- preparedSearchCache.set(search, searchPrepared);
- return searchPrepared;
- },
-
- algorithm: function(searchLowerCodes, prepared, searchLowerCode) {
- var targetLowerCodes = prepared._targetLowerCodes;
- var searchLen = searchLowerCodes.length;
- var targetLen = targetLowerCodes.length;
- var searchI = 0; // where we at
- var targetI = 0; // where you at
- var typoSimpleI = 0;
- var matchesSimpleLen = 0;
-
- // very basic fuzzy match; to remove non-matching targets ASAP!
- // walk through target. find sequential matches.
- // if all chars aren't found then exit
- for(;;) {
- var isMatch = searchLowerCode === targetLowerCodes[targetI];
- if(isMatch) {
- matchesSimple[matchesSimpleLen++] = targetI;
- ++searchI; if(searchI === searchLen) {break;}
- searchLowerCode = searchLowerCodes[typoSimpleI===0?searchI : (typoSimpleI===searchI?searchI+1 : (typoSimpleI===searchI-1?searchI-1 : searchI))];
+ }
+
+ if(resultsLen === 0) return noResults
+ var results = new Array(resultsLen)
+ for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll()
+ results.total = resultsLen + limitedCount
+ return results
+ }
+
+
+ var highlight = (result, hOpen, hClose) => {
+ if(typeof hOpen === 'function') return highlightCallback(result, hOpen)
+ if(result === NULL) return NULL
+ if(hOpen === undefined) hOpen = '<b>'
+ if(hClose === undefined) hClose = '</b>'
+ var highlighted = ''
+ var matchesIndex = 0
+ var opened = false
+ var target = result.target
+ var targetLen = target.length
+ var indexes = result._indexes
+ indexes = indexes.slice(0, indexes.len).sort((a,b)=>a-b)
+ for(var i = 0; i < targetLen; ++i) { var char = target[i]
+ if(indexes[matchesIndex] === i) {
+ ++matchesIndex
+ if(!opened) { opened = true
+ highlighted += hOpen
}
- ++targetI; if(targetI >= targetLen) { // Failed to find searchI
- // Check for typo or exit
- // we go as far as possible before trying to transpose
- // then we transpose backwards until we reach the beginning
- for(;;) {
- if(searchI <= 1) {return null;} // not allowed to transpose first char
- if(typoSimpleI === 0) { // we haven't tried to transpose yet
- --searchI;
- var searchLowerCodeNew = searchLowerCodes[searchI];
- if(searchLowerCode === searchLowerCodeNew) {continue;} // doesn't make sense to transpose a repeat char
- typoSimpleI = searchI;
- } else {
- if(typoSimpleI === 1) {return null;} // reached the end of the line for transposing
- --typoSimpleI;
- searchI = typoSimpleI;
- searchLowerCode = searchLowerCodes[searchI + 1];
- var searchLowerCodeNew = searchLowerCodes[searchI];
- if(searchLowerCode === searchLowerCodeNew) {continue;} // doesn't make sense to transpose a repeat char
- }
- matchesSimpleLen = searchI;
- targetI = matchesSimple[matchesSimpleLen - 1] + 1;
- break;
- }
+ if(matchesIndex === indexes.length) {
+ highlighted += char + hClose + target.substr(i+1)
+ break
+ }
+ } else {
+ if(opened) { opened = false
+ highlighted += hClose
}
}
+ highlighted += char
+ }
- var searchI = 0;
- var typoStrictI = 0;
- var successStrict = false;
- var matchesStrictLen = 0;
-
- var nextBeginningIndexes = prepared._nextBeginningIndexes;
- if(nextBeginningIndexes === null) {nextBeginningIndexes = prepared._nextBeginningIndexes = fuzzysort.prepareNextBeginningIndexes(prepared.target);}
- var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1];
-
- // Our target string successfully matched all characters in sequence!
- // Let's try a more advanced and strict test to improve the score
- // only count it as a match if it's consecutive or a beginning character!
- if(targetI !== targetLen) {for(;;) {
- if(targetI >= targetLen) {
- // We failed to find a good spot for this search char, go back to the previous search char and force it forward
- if(searchI <= 0) { // We failed to push chars forward for a better match
- // transpose, starting from the beginning
- ++typoStrictI; if(typoStrictI > searchLen-2) {break;}
- if(searchLowerCodes[typoStrictI] === searchLowerCodes[typoStrictI+1]) {continue;} // doesn't make sense to transpose a repeat char
- targetI = firstPossibleI;
- continue;
- }
-
- --searchI;
- var lastMatch = matchesStrict[--matchesStrictLen];
- targetI = nextBeginningIndexes[lastMatch];
-
- } else {
- var isMatch = searchLowerCodes[typoStrictI===0?searchI : (typoStrictI===searchI?searchI+1 : (typoStrictI===searchI-1?searchI-1 : searchI))] === targetLowerCodes[targetI];
- if(isMatch) {
- matchesStrict[matchesStrictLen++] = targetI;
- ++searchI; if(searchI === searchLen) { successStrict = true; break; }
- ++targetI;
- } else {
- targetI = nextBeginningIndexes[targetI];
- }
+ return highlighted
+ }
+ var highlightCallback = (result, cb) => {
+ if(result === NULL) return NULL
+ var target = result.target
+ var targetLen = target.length
+ var indexes = result._indexes
+ indexes = indexes.slice(0, indexes.len).sort((a,b)=>a-b)
+ var highlighted = ''
+ var matchI = 0
+ var indexesI = 0
+ var opened = false
+ var result = []
+ for(var i = 0; i < targetLen; ++i) { var char = target[i]
+ if(indexes[indexesI] === i) {
+ ++indexesI
+ if(!opened) { opened = true
+ result.push(highlighted); highlighted = ''
}
- }}
-
- { // tally up the score & keep track of matches for highlighting later
- if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen; }
- else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen; }
- var score = 0;
- var lastTargetI = -1;
- for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i];
- // score only goes down if they're not consecutive
- if(lastTargetI !== targetI - 1) {score -= targetI;}
- lastTargetI = targetI;
+
+ if(indexesI === indexes.length) {
+ highlighted += char
+ result.push(cb(highlighted, matchI++)); highlighted = ''
+ result.push(target.substr(i+1))
+ break
}
- if(!successStrict) {
- score *= 1000;
- if(typoSimpleI !== 0) {score += -20;}/*typoPenalty*/
- } else {
- if(typoStrictI !== 0) {score += -20;}/*typoPenalty*/
+ } else {
+ if(opened) { opened = false
+ result.push(cb(highlighted, matchI++)); highlighted = ''
}
- score -= targetLen - searchLen;
- prepared.score = score;
- prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) {prepared.indexes[i] = matchesBest[i];}
+ }
+ highlighted += char
+ }
+ return result
+ }
+
+
+ var indexes = result => result._indexes.slice(0, result._indexes.len).sort((a,b)=>a-b)
+
- return prepared;
+ var prepare = (target) => {
+ if(typeof target !== 'string') target = ''
+ var info = prepareLowerInfo(target)
+ return {'target':target, _targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _nextBeginningIndexes:NULL, _bitflags:info.bitflags, 'score':NULL, _indexes:[0], 'obj':NULL} // hidden
+ }
+
+
+ // Below this point is only internal code
+ // Below this point is only internal code
+ // Below this point is only internal code
+ // Below this point is only internal code
+
+
+ var prepareSearch = (search) => {
+ if(typeof search !== 'string') search = ''
+ search = search.trim()
+ var info = prepareLowerInfo(search)
+
+ var spaceSearches = []
+ if(info.containsSpace) {
+ var searches = search.split(/\s+/)
+ searches = [...new Set(searches)] // distinct
+ for(var i=0; i<searches.length; i++) {
+ if(searches[i] === '') continue
+ var _info = prepareLowerInfo(searches[i])
+ spaceSearches.push({lowerCodes:_info.lowerCodes, _lower:searches[i].toLowerCase(), containsSpace:false})
}
- },
-
- algorithmNoTypo: function(searchLowerCodes, prepared, searchLowerCode) {
- var targetLowerCodes = prepared._targetLowerCodes;
- var searchLen = searchLowerCodes.length;
- var targetLen = targetLowerCodes.length;
- var searchI = 0; // where we at
- var targetI = 0; // where you at
- var matchesSimpleLen = 0;
-
- // very basic fuzzy match; to remove non-matching targets ASAP!
- // walk through target. find sequential matches.
- // if all chars aren't found then exit
- for(;;) {
- var isMatch = searchLowerCode === targetLowerCodes[targetI];
- if(isMatch) {
- matchesSimple[matchesSimpleLen++] = targetI;
- ++searchI; if(searchI === searchLen) {break;}
- searchLowerCode = searchLowerCodes[searchI];
+ }
+
+ return {lowerCodes: info.lowerCodes, bitflags: info.bitflags, containsSpace: info.containsSpace, _lower: info._lower, spaceSearches: spaceSearches}
+ }
+
+
+
+ var getPrepared = (target) => {
+ if(target.length > 999) return prepare(target) // don't cache huge targets
+ var targetPrepared = preparedCache.get(target)
+ if(targetPrepared !== undefined) return targetPrepared
+ targetPrepared = prepare(target)
+ preparedCache.set(target, targetPrepared)
+ return targetPrepared
+ }
+ var getPreparedSearch = (search) => {
+ if(search.length > 999) return prepareSearch(search) // don't cache huge searches
+ var searchPrepared = preparedSearchCache.get(search)
+ if(searchPrepared !== undefined) return searchPrepared
+ searchPrepared = prepareSearch(search)
+ preparedSearchCache.set(search, searchPrepared)
+ return searchPrepared
+ }
+
+
+ var all = (search, targets, options) => {
+ var results = []; results.total = targets.length
+
+ var limit = options && options.limit || INT_MAX
+
+ if(options && options.key) {
+ for(var i=0;i<targets.length;i++) { var obj = targets[i]
+ var target = getValue(obj, options.key)
+ if(!target) continue
+ if(!isObj(target)) target = getPrepared(target)
+ target.score = INT_MIN
+ target._indexes.len = 0
+ var result = target
+ result = {target:result.target, _targetLower:'', _targetLowerCodes:NULL, _nextBeginningIndexes:NULL, _bitflags:0, score:target.score, _indexes:NULL, obj:obj} // hidden
+ results.push(result); if(results.length >= limit) return results
+ }
+ } else if(options && options.keys) {
+ for(var i=0;i<targets.length;i++) { var obj = targets[i]
+ var objResults = new Array(options.keys.length)
+ for (var keyI = options.keys.length - 1; keyI >= 0; --keyI) {
+ var target = getValue(obj, options.keys[keyI])
+ if(!target) { objResults[keyI] = NULL; continue }
+ if(!isObj(target)) target = getPrepared(target)
+ target.score = INT_MIN
+ target._indexes.len = 0
+ objResults[keyI] = target
}
- ++targetI; if(targetI >= targetLen) {return null;} // Failed to find searchI
+ objResults.obj = obj
+ objResults.score = INT_MIN
+ results.push(objResults); if(results.length >= limit) return results
+ }
+ } else {
+ for(var i=0;i<targets.length;i++) { var target = targets[i]
+ if(!target) continue
+ if(!isObj(target)) target = getPrepared(target)
+ target.score = INT_MIN
+ target._indexes.len = 0
+ results.push(target); if(results.length >= limit) return results
}
+ }
- var searchI = 0;
- var successStrict = false;
- var matchesStrictLen = 0;
+ return results
+ }
- var nextBeginningIndexes = prepared._nextBeginningIndexes;
- if(nextBeginningIndexes === null) {nextBeginningIndexes = prepared._nextBeginningIndexes = fuzzysort.prepareNextBeginningIndexes(prepared.target);}
- var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1];
- // Our target string successfully matched all characters in sequence!
- // Let's try a more advanced and strict test to improve the score
- // only count it as a match if it's consecutive or a beginning character!
- if(targetI !== targetLen) {for(;;) {
- if(targetI >= targetLen) {
- // We failed to find a good spot for this search char, go back to the previous search char and force it forward
- if(searchI <= 0) {break;} // We failed to push chars forward for a better match
+ var algorithm = (preparedSearch, prepared, allowSpaces=false) => {
+ if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared)
+
+ var searchLower = preparedSearch._lower
+ var searchLowerCodes = preparedSearch.lowerCodes
+ var searchLowerCode = searchLowerCodes[0]
+ var targetLowerCodes = prepared._targetLowerCodes
+ var searchLen = searchLowerCodes.length
+ var targetLen = targetLowerCodes.length
+ var searchI = 0 // where we at
+ var targetI = 0 // where you at
+ var matchesSimpleLen = 0
+
+ // very basic fuzzy match; to remove non-matching targets ASAP!
+ // walk through target. find sequential matches.
+ // if all chars aren't found then exit
+ for(;;) {
+ var isMatch = searchLowerCode === targetLowerCodes[targetI]
+ if(isMatch) {
+ matchesSimple[matchesSimpleLen++] = targetI
+ ++searchI; if(searchI === searchLen) break
+ searchLowerCode = searchLowerCodes[searchI]
+ }
+ ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI
+ }
+
+ var searchI = 0
+ var successStrict = false
+ var matchesStrictLen = 0
+
+ var nextBeginningIndexes = prepared._nextBeginningIndexes
+ if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target)
+ var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1]
+
+ // Our target string successfully matched all characters in sequence!
+ // Let's try a more advanced and strict test to improve the score
+ // only count it as a match if it's consecutive or a beginning character!
+ var backtrackCount = 0
+ if(targetI !== targetLen) for(;;) {
+ if(targetI >= targetLen) {
+ // We failed to find a good spot for this search char, go back to the previous search char and force it forward
+ if(searchI <= 0) break // We failed to push chars forward for a better match
- --searchI;
- var lastMatch = matchesStrict[--matchesStrictLen];
- targetI = nextBeginningIndexes[lastMatch];
+ ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match
+ --searchI
+ var lastMatch = matchesStrict[--matchesStrictLen]
+ targetI = nextBeginningIndexes[lastMatch]
+
+ } else {
+ var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI]
+ if(isMatch) {
+ matchesStrict[matchesStrictLen++] = targetI
+ ++searchI; if(searchI === searchLen) { successStrict = true; break }
+ ++targetI
} else {
- var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI];
- if(isMatch) {
- matchesStrict[matchesStrictLen++] = targetI;
- ++searchI; if(searchI === searchLen) { successStrict = true; break; }
- ++targetI;
- } else {
- targetI = nextBeginningIndexes[targetI];
- }
+ targetI = nextBeginningIndexes[targetI]
}
- }}
-
- { // tally up the score & keep track of matches for highlighting later
- if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen; }
- else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen; }
- var score = 0;
- var lastTargetI = -1;
- for(var i = 0; i < searchLen; ++i) { var targetI = matchesBest[i];
- // score only goes down if they're not consecutive
- if(lastTargetI !== targetI - 1) {score -= targetI;}
- lastTargetI = targetI;
- }
- if(!successStrict) {score *= 1000;}
- score -= targetLen - searchLen;
- prepared.score = score;
- prepared.indexes = new Array(matchesBestLen); for(var i = matchesBestLen - 1; i >= 0; --i) {prepared.indexes[i] = matchesBest[i];}
+ }
+ }
+
+ // check if it's a substring match
+ var substringIndex = prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow
+ var isSubstring = ~substringIndex
+ if(isSubstring && !successStrict) { // rewrite the indexes from basic to the substring
+ for(var i=0; i<matchesSimpleLen; ++i) matchesSimple[i] = substringIndex+i
+ }
+ var isSubstringBeginning = false
+ if(isSubstring) {
+ isSubstringBeginning = prepared._nextBeginningIndexes[substringIndex-1] === substringIndex
+ }
+
+ { // tally up the score & keep track of matches for highlighting later
+ if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen }
+ else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen }
+
+ var score = 0
+
+ var extraMatchGroupCount = 0
+ for(var i = 1; i < searchLen; ++i) {
+ if(matchesBest[i] - matchesBest[i-1] !== 1) {score -= matchesBest[i]; ++extraMatchGroupCount}
+ }
+ var unmatchedDistance = matchesBest[searchLen-1] - matchesBest[0] - (searchLen-1)
+
+ score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups
+
+ if(matchesBest[0] !== 0) score -= matchesBest[0]*matchesBest[0]*.2 // penality for not starting near the beginning
+
+ if(!successStrict) {
+ score *= 1000
+ } else {
+ // successStrict on a target with too many beginning indexes loses points for being a bad target
+ var uniqueBeginningIndexes = 1
+ for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes
- return prepared;
+ if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ...
}
- },
-
- prepareLowerCodes: function(str) {
- var strLen = str.length;
- var lowerCodes = []; // new Array(strLen) sparse array is too slow
- var lower = str.toLowerCase();
- for(var i = 0; i < strLen; ++i) {lowerCodes[i] = lower.charCodeAt(i);}
- return lowerCodes;
- },
- prepareBeginningIndexes: function(target) {
- var targetLen = target.length;
- var beginningIndexes = []; var beginningIndexesLen = 0;
- var wasUpper = false;
- var wasAlphanum = false;
- for(var i = 0; i < targetLen; ++i) {
- var targetCode = target.charCodeAt(i);
- var isUpper = targetCode>=65&&targetCode<=90;
- var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57;
- var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum;
- wasUpper = isUpper;
- wasAlphanum = isAlphanum;
- if(isBeginning) {beginningIndexes[beginningIndexesLen++] = i;}
+
+ if(isSubstring) score /= 1+searchLen*searchLen*1 // bonus for being a full substring
+ if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex
+
+ score -= targetLen - searchLen // penality for longer targets
+ prepared.score = score
+
+ for(var i = 0; i < matchesBestLen; ++i) prepared._indexes[i] = matchesBest[i]
+ prepared._indexes.len = matchesBestLen
+
+ return prepared
+ }
+ }
+ var algorithmSpaces = (preparedSearch, target) => {
+ var seen_indexes = new Set()
+ var score = 0
+ var result = NULL
+
+ var first_seen_index_last_search = 0
+ var searches = preparedSearch.spaceSearches
+ for(var i=0; i<searches.length; ++i) {
+ var search = searches[i]
+
+ result = algorithm(search, target)
+ if(result === NULL) return NULL
+
+ score += result.score
+
+ // dock points based on order otherwise "c man" returns Manifest.cpp instead of CheatManager.h
+ if(result._indexes[0] < first_seen_index_last_search) {
+ score -= first_seen_index_last_search - result._indexes[0]
}
- return beginningIndexes;
- },
- prepareNextBeginningIndexes: function(target) {
- var targetLen = target.length;
- var beginningIndexes = fuzzysort.prepareBeginningIndexes(target);
- var nextBeginningIndexes = []; // new Array(targetLen) sparse array is too slow
- var lastIsBeginning = beginningIndexes[0];
- var lastIsBeginningI = 0;
- for(var i = 0; i < targetLen; ++i) {
- if(lastIsBeginning > i) {
- nextBeginningIndexes[i] = lastIsBeginning;
- } else {
- lastIsBeginning = beginningIndexes[++lastIsBeginningI];
- nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning;
- }
+ first_seen_index_last_search = result._indexes[0]
+
+ for(var j=0; j<result._indexes.len; ++j) seen_indexes.add(result._indexes[j])
+ }
+
+ // allows a search with spaces that's an exact substring to score well
+ var allowSpacesResult = algorithm(preparedSearch, target, /*allowSpaces=*/true)
+ if(allowSpacesResult !== NULL && allowSpacesResult.score > score) {
+ return allowSpacesResult
+ }
+
+ result.score = score
+
+ var i = 0
+ for (let index of seen_indexes) result._indexes[i++] = index
+ result._indexes.len = i
+
+ return result
+ }
+
+
+ var prepareLowerInfo = (str) => {
+ var strLen = str.length
+ var lower = str.toLowerCase()
+ var lowerCodes = [] // new Array(strLen) sparse array is too slow
+ var bitflags = 0
+ var containsSpace = false // space isn't stored in bitflags because of how searching with a space works
+
+ for(var i = 0; i < strLen; ++i) {
+ var lowerCode = lowerCodes[i] = lower.charCodeAt(i)
+
+ if(lowerCode === 32) {
+ containsSpace = true
+ continue // it's important that we don't set any bitflags for space
}
- return nextBeginningIndexes;
- },
-
- cleanup: cleanup,
- new: fuzzysortNew,
- };
- return fuzzysort;
-} // fuzzysortNew
-
-// This stuff is outside fuzzysortNew, because it's shared with instances of fuzzysort.new()
-var isNode = typeof require !== 'undefined' && typeof window === 'undefined';
-var MyMap = typeof Map === 'function' ? Map : function(){var s=Object.create(null);this.get=function(k){return s[k];};this.set=function(k,val){s[k]=val;return this;};this.clear=function(){s=Object.create(null);};};
-var preparedCache = new MyMap();
-var preparedSearchCache = new MyMap();
-var noResults = []; noResults.total = 0;
-var matchesSimple = []; var matchesStrict = [];
-function cleanup() { preparedCache.clear(); preparedSearchCache.clear(); matchesSimple = []; matchesStrict = []; }
-function defaultScoreFn(a) {
- var max = -9007199254740991;
- for (var i = a.length - 1; i >= 0; --i) {
- var result = a[i]; if(result === null) {continue;}
- var score = result.score;
- if(score > max) {max = score;}
+
+ var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet
+ : lowerCode>=48&&lowerCode<=57 ? 26 // numbers
+ // 3 bits available
+ : lowerCode<=127 ? 30 // other ascii
+ : 31 // other utf8
+ bitflags |= 1<<bit
+ }
+
+ return {lowerCodes:lowerCodes, bitflags:bitflags, containsSpace:containsSpace, _lower:lower}
}
- if(max === -9007199254740991) {return null;}
- return max;
-}
-
-// prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop]
-// prop = 'key1.key2' 10ms
-// prop = ['key1', 'key2'] 27ms
-function getValue(obj, prop) {
- var tmp = obj[prop]; if(tmp !== undefined) {return tmp;}
- var segs = prop;
- if(!Array.isArray(prop)) {segs = prop.split('.');}
- var len = segs.length;
- var i = -1;
- while (obj && (++i < len)) {obj = obj[segs[i]];}
- return obj;
-}
-
-function isObj(x) { return typeof x === 'object'; } // faster as a function
-
-// Hacked version of https://github.com/lemire/FastPriorityQueue.js
-var fastpriorityqueue=function(){var r=[],o=0,e={};function n(){for(var e=0,n=r[e],c=1;c<o;){var f=c+1;e=c,f<o&&r[f].score<r[c].score&&(e=f),r[e-1>>1]=r[e],c=1+(e<<1);}for(var a=e-1>>1;e>0&&n.score<r[a].score;a=(e=a)-1>>1){r[e]=r[a];}r[e]=n;}return e.add=function(e){var n=o;r[o++]=e;for(var c=n-1>>1;n>0&&e.score<r[c].score;c=(n=c)-1>>1){r[n]=r[c];}r[n]=e;},e.poll=function(){if(0!==o){var e=r[0];return r[0]=r[--o],n(),e;}},e.peek=function(e){if(0!==o){return r[0];}},e.replaceTop=function(o){r[0]=o,n();},e;};
-var q = fastpriorityqueue(); // reuse this, except for async, it needs to make its own
-
-return fuzzysortNew();
-}); // UMD
-
-// TODO: (performance) wasm version!?
-// TODO: (performance) threads?
-// TODO: (performance) avoid cache misses
-// TODO: (performance) preparedCache is a memory leak
+ var prepareBeginningIndexes = (target) => {
+ var targetLen = target.length
+ var beginningIndexes = []; var beginningIndexesLen = 0
+ var wasUpper = false
+ var wasAlphanum = false
+ for(var i = 0; i < targetLen; ++i) {
+ var targetCode = target.charCodeAt(i)
+ var isUpper = targetCode>=65&&targetCode<=90
+ var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57
+ var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum
+ wasUpper = isUpper
+ wasAlphanum = isAlphanum
+ if(isBeginning) beginningIndexes[beginningIndexesLen++] = i
+ }
+ return beginningIndexes
+ }
+ var prepareNextBeginningIndexes = (target) => {
+ var targetLen = target.length
+ var beginningIndexes = prepareBeginningIndexes(target)
+ var nextBeginningIndexes = [] // new Array(targetLen) sparse array is too slow
+ var lastIsBeginning = beginningIndexes[0]
+ var lastIsBeginningI = 0
+ for(var i = 0; i < targetLen; ++i) {
+ if(lastIsBeginning > i) {
+ nextBeginningIndexes[i] = lastIsBeginning
+ } else {
+ lastIsBeginning = beginningIndexes[++lastIsBeginningI]
+ nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning
+ }
+ }
+ return nextBeginningIndexes
+ }
+
+
+ var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear(); matchesSimple = []; matchesStrict = [] }
+
+ var preparedCache = new Map()
+ var preparedSearchCache = new Map()
+ var matchesSimple = []; var matchesStrict = []
+
+
+ // for use with keys. just returns the maximum score
+ var defaultScoreFn = (a) => {
+ var max = INT_MIN
+ var len = a.length
+ for (var i = 0; i < len; ++i) {
+ var result = a[i]; if(result === NULL) continue
+ var score = result.score
+ if(score > max) max = score
+ }
+ if(max === INT_MIN) return NULL
+ return max
+ }
+
+ // prop = 'key' 2.5ms optimized for this case, seems to be about as fast as direct obj[prop]
+ // prop = 'key1.key2' 10ms
+ // prop = ['key1', 'key2'] 27ms
+ var getValue = (obj, prop) => {
+ var tmp = obj[prop]; if(tmp !== undefined) return tmp
+ var segs = prop
+ if(!Array.isArray(prop)) segs = prop.split('.')
+ var len = segs.length
+ var i = -1
+ while (obj && (++i < len)) obj = obj[segs[i]]
+ return obj
+ }
+
+ var isObj = (x) => { return typeof x === 'object' } // faster as a function
+ // var INT_MAX = 9007199254740991; var INT_MIN = -INT_MAX
+ var INT_MAX = Infinity; var INT_MIN = -INT_MAX
+ var noResults = []; noResults.total = 0
+ var NULL = null
+
+
+ // Hacked version of https://github.com/lemire/FastPriorityQueue.js
+ var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c<o;){var s=c+1;a=c,s<o&&e[s].score<e[c].score&&(a=s),e[a-1>>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v.score<e[f].score;f=(a=f)-1>>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r.score<e[v].score;v=(a=v)-1>>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a}
+ var q = fastpriorityqueue() // reuse this
+
+
+ // fuzzysort is written this way for minification. all names are mangeled unless quoted
+ return {'single':single, 'go':go, 'highlight':highlight, 'prepare':prepare, 'indexes':indexes, 'cleanup':cleanup}
+}) // UMD
+
+// TODO: (feature) frecency
+// TODO: (perf) use different sorting algo depending on the # of results?
+// TODO: (perf) preparedCache is a memory leak
// TODO: (like sublime) backslash === forwardslash
-// TODO: (like sublime) spaces: "a b" should do 2 searches 1 for a and 1 for b
-// TODO: (scoring) garbage in targets that allows most searches to strict match need a penality
-// TODO: (performance) idk if allowTypo is optimized
+// TODO: (perf) prepareSearch seems slow
diff --git a/static/js/hoverfix.ts b/static/js/hoverfix.ts
new file mode 100644
index 0000000..b6d1a5b
--- /dev/null
+++ b/static/js/hoverfix.ts
@@ -0,0 +1,64 @@
+(function () {
+ /*/
+ * Element.closest() polyfill
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
+ * https://github.com/idmadj/element-closest-polyfill#readme
+ * Copyright (C) Abdelmadjid Hammou
+ * Licence: ISC | https://www.isc.org/licenses/
+ /*/
+
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
+ }
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function (s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ } while (el !== null && el.nodeType === 1);
+ return null;
+ };
+ }
+ }
+
+ /*/
+ * -----------------------------------------------------------------
+ /*/
+
+ const disabled = "0s";
+
+ function walk(children, callback) {
+ for (let i = 0; i < children.length; i++) {
+ callback(children[i]);
+ walk(children[i].children, callback);
+ }
+ }
+
+ self.addEventListener("mousemove", function (event) {
+ if (typeof event.target.closest !== "function") return;
+ tree = event.target.closest("figure") || event.target.closest("article");
+
+ if (tree !== null) {
+ walk(tree.children, function (element) {
+ const delay = self.getComputedStyle(element).getPropertyValue(
+ "transition-delay",
+ );
+ if (delay !== disabled) {
+ element.style.setProperty("visibility", "hidden");
+ }
+ });
+
+ walk(tree.children, function (element) {
+ const delay = self.getComputedStyle(element).getPropertyValue(
+ "transition-delay",
+ );
+ if (delay !== disabled) {
+ element.style.removeProperty("visibility");
+ }
+ });
+ }
+ });
+})();
diff --git a/static/js/index-bundle.ts b/static/js/index-bundle.ts
new file mode 100644
index 0000000..61dc414
--- /dev/null
+++ b/static/js/index-bundle.ts
@@ -0,0 +1,18 @@
+import { bundle } from "https://deno.land/x/emit@0.26.0/mod.ts";
+
+function removeSourceMap(text): string {
+ return text.replace(/^\/\/# sourceMappingURL.*$/gm, "").trim();
+}
+
+const entrypoint = await bundle(
+ "./static/js/index.ts",
+);
+
+const output = removeSourceMap(entrypoint.code);
+const file = Deno.cwd() + "/assets/js/index.js";
+const fileSize = ((await Deno.stat(file)).size / 1024).toFixed(2) + "kB";
+
+await Deno.writeTextFile(file, output, {});
+
+console.log("INFO:", `Bundle file:///${file}`);
+console.log("INFO:", `Emit file:///${file} (${fileSize})`);
diff --git a/static/js/index.ts b/static/js/index.ts
index 6000441..517445c 100644
--- a/static/js/index.ts
+++ b/static/js/index.ts
@@ -1,6 +1,13 @@
import "./pager.ts";
+import "./update.ts";
import "./plumber.ts";
import "./instantpage.ts";
+import "./contextmenu.ts";
import "./fixedsearch.ts";
+import "./autoplay.ts";
+import "./hoverfix.ts";
+import "./forms.ts";
+import "./domfilter.ts";
+import "./timeago.ts";
-console.log("Surface Control: OK");
+console.log("INFO: Surface Control Complete");
diff --git a/static/js/infinitescroll.ts b/static/js/infinitescroll.ts
new file mode 100644
index 0000000..bef477b
--- /dev/null
+++ b/static/js/infinitescroll.ts
@@ -0,0 +1,78 @@
+(function () {
+ const cookiesDisabled = !navigator.cookieEnabled;
+
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Native pagination fallback due to cookie restrictions");
+ }
+
+ type percent = number;
+
+ function fetch(url, method, callback, fallback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (callback && http.readyState === 4) {
+ if (http.status === 200) callback(http);
+ else fallback(http);
+ }
+ };
+ http.open(method, url);
+ http.send();
+ return http;
+ }
+
+ let abort = false;
+
+ const key = "config.scroll.infinite";
+
+ if (!localStorage[key]) localStorage[key] = "";
+
+ ["scroll", "DOMContentLoaded"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ if (abort) return;
+
+ const remaining = Math.abs(
+ document.documentElement.scrollHeight
+ - document.documentElement.clientHeight
+ - self.pageYOffset
+ );
+
+ const traversed = self.pageYOffset;
+ const journey = remaining + traversed;
+ const ratio: percent = traversed / journey * 100;
+ const threshold = ratio >= 50;
+ const pagination = document.querySelector('[data-type="pagination"]');
+
+ if (!pagination) return;
+
+ const main = document.querySelector("main");
+ const count = main.childNodes.length;
+ const next = pagination.querySelector('[rel="next"]');
+ const end = pagination.querySelector('[rel="last"]').title === "hidden";
+ const asynchronous = document.querySelectorAll("[data-type='pagination']").length !== 1;
+
+ if (end || asynchronous) return pagination.remove();
+
+ if (threshold && (pagination.remove() === undefined)) {
+ fetch(next.href, "GET", function (http) {
+ const page = (new DOMParser()).parseFromString(http.responseText, "text/html");
+ const items = page.querySelector("main").childNodes;
+ const paginate = page.querySelector('[data-type="pagination"]');
+
+ for (let i = 0; i < items.length; i++) main.appendChild(items[i]);
+
+ main.after(paginate);
+
+ console.log("INFO: Fetch", next.href, items);
+
+ }, function (http) {
+ console.warn("WARNING: Switching to native pagination", http);
+ main.insertAdjacentElement("afterend", pagination);
+ abort = true;
+ });
+ }
+ console.log("INFO:", "r:", remaining, "t:", traversed, "j:", journey, "%:", ratio, "c:", count);
+ });
+ });
+})();
diff --git a/static/js/instantpage.ts b/static/js/instantpage.ts
index 7c78a6f..1b5ed36 100644
--- a/static/js/instantpage.ts
+++ b/static/js/instantpage.ts
@@ -1,292 +1,82 @@
-(function () {
- self.addEventListener("DOMContentLoaded", function () {
- /*! instant.page v5.1.0 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */
-
- let mouseoverTimer;
- let lastTouchTimestamp;
- const prefetches = new Set();
- const prefetchElement = document.createElement("link");
- const isSupported = prefetchElement.relList &&
- prefetchElement.relList.supports &&
- prefetchElement.relList.supports("prefetch") &&
- window.IntersectionObserver &&
- "isIntersecting" in IntersectionObserverEntry.prototype;
- const allowQueryString = "instantAllowQueryString" in document.body.dataset;
- const allowExternalLinks = "instantAllowExternalLinks" in
- document.body.dataset;
- const useWhitelist = "instantWhitelist" in document.body.dataset;
- const mousedownShortcut = "instantMousedownShortcut" in
- document.body.dataset;
- const DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION = 1111;
+/*
+ * Instant Page Copyright (C) 2019-2023 Alexandre Dieulot
+ * https://github.com/instantpage/instant.page/blob/master/LICENSE
+ * Licence: MIT | https://mit-license.org/
+*/
- let delayOnHover = 65;
- let useMousedown = false;
- let useMousedownOnly = false;
- let useViewport = false;
-
- if ("instantIntensity" in document.body.dataset) {
- const intensity = document.body.dataset.instantIntensity;
+(function () {
- if (intensity.substr(0, "mousedown".length) == "mousedown") {
- useMousedown = true;
- if (intensity == "mousedown-only") {
- useMousedownOnly = true;
- }
- } else if (intensity.substr(0, "viewport".length) == "viewport") {
- if (
- !(navigator.connection &&
- (navigator.connection.saveData ||
- (navigator.connection.effectiveType &&
- navigator.connection.effectiveType.includes("2g"))))
- ) {
- if (intensity == "viewport") {
- /* Biggest iPhone resolution (which we want): 414 × 896 = 370944
- * Small 7" tablet resolution (which we don’t want): 600 × 1024 = 614400
- * Note that the viewport (which we check here) is smaller than the resolution due to the UI’s chrome */
- if (
- document.documentElement.clientWidth *
- document.documentElement.clientHeight < 450000
- ) {
- useViewport = true;
- }
- } else if (intensity == "viewport-all") {
- useViewport = true;
- }
- }
- } else {
- const milliseconds = parseInt(intensity);
- if (!isNaN(milliseconds)) {
- delayOnHover = milliseconds;
- }
- }
+ /*/
+ * Element.closest() polyfill
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
+ * https://github.com/idmadj/element-closest-polyfill#readme
+ * Copyright (C) Abdelmadjid Hammou
+ * Licence: ISC | https://www.isc.org/licenses/
+ /*/
+
+ if (typeof Element !== "undefined") {
+ if (!Element.prototype.matches) {
+ Element.prototype.matches = Element.prototype.msMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
}
-
- if (isSupported) {
- const eventListenersOptions = {
- capture: true,
- passive: true,
+ if (!Element.prototype.closest) {
+ Element.prototype.closest = function (s) {
+ var el = this;
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ } while (el !== null && el.nodeType === 1);
+ return null;
};
-
- if (!useMousedownOnly) {
- document.addEventListener(
- "touchstart",
- touchstartListener,
- eventListenersOptions,
- );
- }
-
- if (!useMousedown) {
- document.addEventListener(
- "mouseover",
- mouseoverListener,
- eventListenersOptions,
- );
- } else if (!mousedownShortcut) {
- document.addEventListener(
- "mousedown",
- mousedownListener,
- eventListenersOptions,
- );
- }
-
- if (mousedownShortcut) {
- document.addEventListener(
- "mousedown",
- mousedownShortcutListener,
- eventListenersOptions,
- );
- }
-
- if (useViewport) {
- let triggeringFunction;
- if (window.requestIdleCallback) {
- triggeringFunction = function (callback) {
- requestIdleCallback(callback, {
- timeout: 1500,
- });
- };
- } else {
- triggeringFunction = function (callback) {
- callback();
- };
- }
-
- triggeringFunction(function () {
- const intersectionObserver = new IntersectionObserver(
- function (entries) {
- entries.forEach(function (entry) {
- if (entry.isIntersecting) {
- const linkElement = entry.target;
- intersectionObserver.unobserve(linkElement);
- preload(linkElement.href);
- }
- });
- },
- );
-
- document.querySelectorAll("a").forEach(function (linkElement) {
- if (isPreloadable(linkElement)) {
- intersectionObserver.observe(linkElement);
- }
- });
- });
- }
}
+ }
- function touchstartListener(event) {
- /* Chrome on Android calls mouseover before touchcancel so `lastTouchTimestamp`
- * must be assigned on touchstart to be measured on mouseover. */
- lastTouchTimestamp = performance.now();
+ /*/
+ * -----------------------------------------------------------------
+ /*/
- const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
- preload(linkElement.href);
- }
-
- function mouseoverListener(event) {
- if (
- performance.now() - lastTouchTimestamp <
- DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION
- ) {
- return;
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (http.readyState === 4 && http.status === 200) {
+ if (callback) callback(http);
}
+ };
+ http.open(method, url);
+ http.send();
+ return http;
+ }
- const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
- linkElement.addEventListener("mouseout", mouseoutListener, {
- passive: true,
- });
-
- mouseoverTimer = setTimeout(function () {
- preload(linkElement.href);
- mouseoverTimer = undefined;
- }, delayOnHover);
- }
-
- function mousedownListener(event) {
- const linkElement = event.target.closest("a");
-
- if (!isPreloadable(linkElement)) {
- return;
- }
-
- preload(linkElement.href);
- }
-
- function mouseoutListener(event) {
- if (
- event.relatedTarget &&
- event.target.closest("a") == event.relatedTarget.closest("a")
- ) {
- return;
- }
-
- if (mouseoverTimer) {
- clearTimeout(mouseoverTimer);
- mouseoverTimer = undefined;
- }
- }
-
- function mousedownShortcutListener(event) {
- if (
- performance.now() - lastTouchTimestamp <
- DELAY_TO_NOT_BE_CONSIDERED_A_TOUCH_INITIATED_ACTION
- ) {
- return;
- }
-
- const linkElement = event.target.closest("a");
-
- if (event.which > 1 || event.metaKey || event.ctrlKey) {
- return;
- }
-
- if (!linkElement) {
- return;
- }
-
- linkElement.addEventListener("click", function (event) {
- if (event.detail == 1337) {
- return;
- }
-
- event.preventDefault();
- }, { capture: true, passive: false, once: true });
+ self.addEventListener("DOMContentLoaded", function () {
- const customEvent = new MouseEvent("click", {
- view: window,
- bubbles: true,
- cancelable: false,
- detail: 1337,
+ ["mouseout", "mousedown", "touchstart"].forEach(function (event) {
+ self.addEventListener(event, function (event) {
+ const url = event.target.closest("a");
+ if (preloadable(url) === undefined) return;
+ preload(url.href);
});
- linkElement.dispatchEvent(customEvent);
- }
-
- function isPreloadable(linkElement) {
- if (!linkElement || !linkElement.href) {
- return;
- }
+ });
- if (useWhitelist && !("instant" in linkElement.dataset)) {
- return;
+ function preloadable(url) {
+ switch (true) {
+ case (url === null || url.href === null): return;
+ case (url.origin !== location.origin): return;
+ case (["http:", "https:"].includes(url.protocol) === null): return;
+ case (url.protocol === "http:" && location.protocol === "https:"): return;
+ case (url.hash && url.pathname + url.search == location.pathname + location.search): return;
+ default: return true;
}
-
- if (
- !allowExternalLinks && linkElement.origin != location.origin &&
- !("instant" in linkElement.dataset)
- ) {
- return;
- }
-
- if (!["http:", "https:"].includes(linkElement.protocol)) {
- return;
- }
-
- if (linkElement.protocol == "http:" && location.protocol == "https:") {
- return;
- }
-
- if (
- !allowQueryString && linkElement.search &&
- !("instant" in linkElement.dataset)
- ) {
- return;
- }
-
- if (
- linkElement.hash &&
- linkElement.pathname + linkElement.search ==
- location.pathname + location.search
- ) {
- return;
- }
-
- if ("noInstant" in linkElement.dataset) {
- return;
- }
-
- return true;
}
function preload(url) {
- if (prefetches.has(url)) {
- return;
- }
-
const prefetcher = document.createElement("link");
- prefetcher.rel = "prefetch";
+ prefetcher.rel = "custom-prefetch";
prefetcher.href = url;
+ const selector = 'link[rel="'.concat(prefetcher.rel, '"][href="').concat(prefetcher.href, '"]');
+ const prefetched = document.head.contains(document.querySelector(selector));
+ if (prefetched) { return; }
document.head.appendChild(prefetcher);
-
- prefetches.add(url);
+ fetch(url, "GET", function () {});
}
});
})();
diff --git a/static/js/pager.ts b/static/js/pager.ts
index 49f3b2d..ebaf67a 100644
--- a/static/js/pager.ts
+++ b/static/js/pager.ts
@@ -1,49 +1,95 @@
(function () {
- const url = self.location.href.split("#")[0];
- let settings = { pager: {} };
+ const cookiesDisabled = !navigator.cookieEnabled;
- self.addEventListener("DOMContentLoaded", function () {
- if (history.scrollRestoration) history.scrollRestoration = "manual";
- if (localStorage["settings"]) {
- settings = JSON.parse(localStorage["settings"]);
- }
- if (self.location.hash.length > 0) {
- settings["pager"][url] = self.pageYOffset;
- localStorage["settings"] = JSON.stringify(settings);
- document.getElementById(location.hash.slice(1)).scrollIntoView();
- self.addEventListener("load", function () {
- document.getElementById(location.hash.slice(1)).scrollIntoView();
- });
- return;
- }
- if (settings["pager"][url] > 0) {
- self.scrollTo(0, settings["pager"][url]);
- return;
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Pager disabled due to cookie restrictions");
+ }
+
+ let seek;
+ let pager = {};
+
+ const state = "on";
+ const key = "config.scroll.pager.urls";
+
+ if (!localStorage[key]) localStorage[key] = JSON.stringify(pager);
+
+ let url = function () { return self.location.href.split("#")[0].split("?")[0]; };
+
+ const scrollHash = function (url) {
+ const hash = self.location.hash;
+ const fragment = hash.slice(1) && document.getElementById(hash.slice(1));
+ const fragmented = hash.length > 0;
+ const hashed = fragmented && document.body.contains(fragment);
+ if (hashed) {
+ self.location.hash = hash;
+ self.location.href = hash;
+ if ("scroll-margin-top" in document.body.style === false && fragment.textContent !== "") {
+ self.scrollBy(0, -6 * parseFloat(getComputedStyle(document.documentElement).fontSize));
+ }
}
- settings["pager"][url] = self.pageYOffset;
- localStorage["settings"] = JSON.stringify(settings);
- });
+ return hashed;
+ };
+
+ const scrollRestore = function (url) {
+ if (history.scrollRestoration) history.scrollRestoration = "manual";
+ if (scrollHash(url)) return;
+ pager = JSON.parse(localStorage[key]);
+ if (pager[url] > 0) {
+ clearInterval(seek);
+ self.scrollTo(0, pager[url]);
+ let i = 0; return seek = setInterval(function (position) {
+ i++; if (i > 100) clearInterval(seek);
+ if (document.documentElement.scrollHeight >= position + document.documentElement.clientHeight) {
+ clearInterval(seek); self.scrollTo(0, position);
+ }
+ }, 4, pager[url]);
+ } else self.scrollTo(0, 0);
+ pager[url] = self.pageYOffset;
+ localStorage[key] = JSON.stringify(pager);
+ };
- self.addEventListener("scroll", function () {
+ const scrollTrack = function (url) {
const currentPosition = self.pageYOffset;
- settings["pager"][url] = currentPosition;
- localStorage["settings"] = JSON.stringify(settings);
- });
+ pager = JSON.parse(localStorage[key]);
+ pager[url] = currentPosition;
+ localStorage[key] = JSON.stringify(pager);
+ };
+
+ const scrollReverse = function (back, up, event) {
+ if (document.body.contains(up) && up.contains(event.target)) {
+ event.preventDefault();
+ window.scrollTo(0, 0);
+ }
+ if (document.body.contains(back) && back.contains(event.target)) {
+ if (history.length < 2) return;
+ event.preventDefault();
+ history.go(-1);
+ }
+ };
- self.addEventListener("DOMContentLoaded", function () {
- const up = document.getElementById("top");
- const back = document.getElementById("back");
+ ["DOMContentLoaded", "pageshow", "hashchange", "URLChangedCustomEvent"].forEach(
+ function (event) {
+ self.addEventListener(event, function (event) {
+ if (event.type === "pageshow") {
+ return event.persisted && self.scrollTo(0, pager[url()]);
+ }
+ if (event.type === "DOMContentLoaded") {
+ self.addEventListener("click", function (event) {
+ const up = document.getElementById("top");
+ const back = document.getElementById("back");
+ scrollReverse(back, up, event);
+ });
+ }
+ scrollRestore(url());
+ });
+ },
+ );
- self.addEventListener("click", function (event) {
- if (document.body.contains(up) && up.contains(event.target)) {
- event.preventDefault();
- window.scrollTo(0, 0);
- }
- if (document.body.contains(back) && back.contains(event.target)) {
- if (history.length < 2) return;
- event.preventDefault();
- history.go(-1);
- }
+ ["click", "touchstart", "scroll"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ scrollTrack(url());
});
});
})();
diff --git a/static/js/plumber.ts b/static/js/plumber.ts
index 8e551fd..d425769 100644
--- a/static/js/plumber.ts
+++ b/static/js/plumber.ts
@@ -1,8 +1,8 @@
/**
- * Plumber based on and inspired by
- * Dictionary Access Copyright (C) 2006, Paul Lutus
+ * Plumber based on and inspired by;
+ * Dictionary Access Copyright (C) 2006 Paul Lutus
* https://arachnoid.com/javascript/dictionary_access.js
- * LICENSE: GPLv2+
+ * Licence: GPLv2+ | https://www.gnu.org/licenses/gpl-3.0.txt
*/
(function () {
diff --git a/static/js/timeago.ts b/static/js/timeago.ts
new file mode 100644
index 0000000..7c1973d
--- /dev/null
+++ b/static/js/timeago.ts
@@ -0,0 +1,93 @@
+(function () {
+ type second = number;
+ type millisecond = number;
+
+ const relative = new Intl.RelativeTimeFormat("en", {
+ localeMatcher: "best fit",
+ numeric: "always",
+ style: "long",
+ });
+
+ function viewport(element) {
+ const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : { offset: 250 };
+ const view = element.getBoundingClientRect();
+ return view.top >= -options.offset
+ && view.left >= -options.offset
+ && view.bottom <= (self.innerHeight || document.documentElement.clientHeight) + options.offset
+ && view.right <= (self.innerWidth || document.documentElement.clientWidth) + options.offset;
+ }
+
+ const date = function (update) {
+ const elements = document.querySelectorAll("time");
+ for (let i = 0; i < elements.length; ++i) {
+ const offscreen = !viewport(elements[i]);
+ const hidden = elements[i].offsetParent === null;
+ if ((update === "viewport") && (offscreen || hidden)) continue;
+
+ (function (element) {
+ try {
+ if (element.dataset.type === "disabled") return;
+
+ const time: millisecond = new Date(element.dateTime) || new Date();
+ const interval: second = ((new Date().getTime() - time.getTime()) / 1000);
+
+ const seconds: number = Math.round(interval);
+ const minutes: number = Math.round(seconds / 60);
+ const hours: number = Math.round(minutes / 60);
+ const days: number = Math.round(hours / 24);
+
+ const past = Math.sign(seconds) === 1;
+ const future = Math.sign(seconds) === -1;
+
+ let tiny = function (string, place) {
+ return string.split(" ").slice(0, place).join(" ") + string.split(" ")[place].charAt(0);
+ }
+
+ if (element.dataset.type === "default") { tiny = function (string) { return string; }; }
+
+ if (element.dataset.type === "localDate") {
+ return element.textContent = new Intl.DateTimeFormat([], { dateStyle: "medium", }).format(time).replace(",", "");
+ }
+
+ if (element.dataset.type === "localTime") {
+ return element.textContent = new Intl.DateTimeFormat([], {
+ hour12: false,
+ timeStyle: "short",
+ }).format(time) + " " + new Intl.DateTimeFormat([], { timeZoneName: "short" }).format(time).split(" ")[1];
+ }
+
+ if (past) {
+ if (seconds <= 60) { return element.textContent = tiny(relative.format(-1 * seconds, "second",), 1); }
+ if (minutes <= 120) { return element.textContent = tiny(relative.format(-1 * minutes, "minute",), 1); }
+ if (hours <= 48) { return element.textContent = tiny(relative.format(-1 * hours, "hour",), 1); }
+ if (days <= 7) { return element.textContent = tiny(relative.format(-1 * days, "day",), 1); }
+ }
+
+ if (future) {
+ if (-1 * days >= 4) { return element.textContent = tiny(relative.format(-1 * days, "day",), 2); }
+ if (-1 * hours >= 3) { return element.textContent = tiny(relative.format(-1 * hours, "hour",), 2); }
+ if (-1 * minutes >= 2) { return element.textContent = tiny(relative.format(-1 * minutes, "minute",), 2); }
+ if (-1 * seconds >= 1) { return element.textContent = tiny(relative.format(-1 * seconds, "second",), 2); }
+ }
+ } catch (error) {
+ console.error("ERROR: Relative time resolution failed", error);
+ }
+ })(elements[i]);
+ }
+ };
+
+ const substitution = setInterval(date, 4);
+
+ ["scroll", "URLChangedCustomEvent"].forEach(function (event) {
+ self.addEventListener(event, function () {
+ date("viewport");
+ });
+ });
+
+ self.addEventListener("DOMContentLoaded", function () {
+ setTimeout(function () {
+ clearInterval(substitution);
+ setInterval(function () { date("viewport"); }, 1000);
+ }, 1000);
+ });
+})();
diff --git a/static/js/update.ts b/static/js/update.ts
new file mode 100644
index 0000000..df29f49
--- /dev/null
+++ b/static/js/update.ts
@@ -0,0 +1,84 @@
+(function () {
+
+ const cookiesDisabled = !navigator.cookieEnabled;
+
+ if (cookiesDisabled) {
+ document.cookie = "disabled";
+ document.cookie.indexOf("disabled");
+ return console.warn("WARNING: Update check disabled due to cookie restrictions");
+ }
+
+ function fetch(url, method, callback) {
+ const http = new XMLHttpRequest();
+ http.onreadystatechange = function () {
+ if (http.readyState === 4 && http.status === 200) {
+ if (callback) callback(http);
+ }
+ };
+ http.open(method, url);
+ http.setRequestHeader("Pragma", "no-cache");
+ http.setRequestHeader("Cache-Control", "no-cache");
+ http.send();
+ return http;
+ }
+
+ const state = "on";
+ const key = "config.update";
+
+ let stamps = {};
+
+ if (!sessionStorage[key + ".urls"]) sessionStorage[key + ".urls"] = JSON.stringify(stamps);
+
+ function update() {
+ const url = self.location.href.split("#")[0].split("?")[0];
+
+ const indicator = document.querySelector("a[data-update]");
+ if (indicator === null || indicator.dataset.update === "refresh") return;
+ const anchor = indicator.cloneNode();
+
+ fetch(url, "HEAD", function (request) {
+ const local = document.querySelector('meta[name="last-modified"]').content || document.lastModified;
+ const remote = request.getResponseHeader("last-modified") || '';
+ const modified = Date.parse(remote || local) > Date.parse(local);
+ const drift = Date.parse(remote || local) - Date.parse(local);
+
+ if (drift < 10000) return;
+
+ function reset() {
+ indicator.href = anchor.href;
+ indicator.setAttribute("id", anchor.id);
+ indicator.dataset.update = anchor.dataset.update;
+ }
+
+ stamps = JSON.parse(sessionStorage[key + ".urls"]);
+ if (stamps[url] === remote) return;
+ stamps[url] = remote;
+ sessionStorage[key + ".urls"] = JSON.stringify(stamps);
+
+ if (remote && modified) {
+ fetch(url, "GET", function () {
+ indicator.href = url.replace(/^https:/, "http:");
+ indicator.removeAttribute("id");
+ indicator.dataset.update = "refresh";
+ console.log("INFO: R: " + remote);
+ console.log("INFO: L: " + local);
+ console.log("INFO: D: " + drift);
+ console.log("INFO: M: " + modified);
+ });
+ }
+ });
+ }
+
+ let scrolled;
+ let delay = 1000;
+ let delayed = 0;
+
+ self.addEventListener("scroll", function () {
+ if (scrolled) clearTimeout(scrolled);
+ scrolled = setTimeout(function () { update(); delay = delay + delayed; delayed = delay - delayed; }, delay);
+ });
+
+ ["focus", "load", "URLChangedCustomEvent"].forEach(function (event) {
+ self.addEventListener(event, function () { update(); });
+ });
+})();
diff --git a/themes/default/layouts/_default/_markup/render-codeblock-mathml.html b/themes/default/layouts/_default/_markup/render-codeblock-mathml.html
new file mode 100644
index 0000000..f6e5b61
--- /dev/null
+++ b/themes/default/layouts/_default/_markup/render-codeblock-mathml.html
@@ -0,0 +1,18 @@
+{{- $caption := default "Math Render" .Attributes.caption -}}
+{{- $ordinal := add .Ordinal 1 -}}
+{{- $hash := print (truncate 3 "" (sha256 .Inner)) (truncate 3 "" (sha256 .Page.RelPermalink)) "-" $ordinal -}}
+{{- $id := print "math:" $hash | safeURL -}}
+
+<math-ml>
+ <figure id="{{ $id }}">
+ <figure>
+ {{- with $math := .Inner -}}
+ {{- $math | safeHTML -}}
+ {{- end -}}
+ </figure>
+ <figcaption>
+ <a href="#{{ $id }}">({{ $ordinal }})</a>
+ {{ $caption | markdownify }}
+ </figcaption>
+ </figure>
+</math-ml>
diff --git a/themes/default/layouts/_default/_markup/render-codeblock.html b/themes/default/layouts/_default/_markup/render-codeblock.html
index f5c0e13..ab9a786 100644
--- a/themes/default/layouts/_default/_markup/render-codeblock.html
+++ b/themes/default/layouts/_default/_markup/render-codeblock.html
@@ -1,19 +1,25 @@
-{{ $options := .Attributes.options | default "default=1" }}
-{{ $caption := .Attributes.caption }}
+{{- $caption := .Attributes.caption -}}
+{{- $type := .Type | default "text" -}}
+{{- $options := .Attributes.options | default "default=1" -}}
+{{- $hash := print (truncate 3 "" (sha256 .Inner)) (truncate 3 "" (sha256 .Page.RelPermalink)) .Ordinal -}}
+{{- $id := print "code-block:" $hash | safeURL -}}
+{{- $highlight := highlight .Inner $type (print $options ",lineAnchors=" "code-line:" $hash) -}}
-<code-block {{ if in (lower $options) "linenos" }}data-lines{{ end }}>
+<code-block id="{{ $id }}" {{ if in (lower $options) "linenos" }}data-lines=""{{ end }}>
<header>
<language-label>
- {{ .Type }}
+ <a href="#{{ $id }}">{{ $type }}</a>
</language-label>
- <button>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/copy.svg")) }}
- <span>Copy</span>
- </button>
</header>
- {{ highlight .Inner .Type (print $options ",lineAnchors=" "code-" (truncate 7 "" (md5 .Inner))) }}
+ <code-content contenteditable="true" spellcheck="false">
+ {{- replace $highlight
+ `class="lnlinks"`
+ `contenteditable="false" class="lnlinks"`
+ | safeHTML
+ -}}
+ </code-content>
</code-block>
-{{ with $caption }}
+{{- with $caption -}}
<footer>{{ . | markdownify }}</footer>
-{{ end }}
+{{- end -}}
diff --git a/themes/default/layouts/_default/_markup/render-heading.html b/themes/default/layouts/_default/_markup/render-heading.html
index 37eddb2..86b8e35 100644
--- a/themes/default/layouts/_default/_markup/render-heading.html
+++ b/themes/default/layouts/_default/_markup/render-heading.html
@@ -1,6 +1,9 @@
-<h{{ .Level }} id="{{ .Anchor | safeURL }}">
- <a
- title="{{ .Text | safeHTML }}"
- href="#{{ .Anchor | safeURL }}">{{ .Text | safeHTML }}
+{{- $text := .Text -}}
+{{- $hash := print (truncate 2 "" (sha256 .Page.RelPermalink)) (truncate 2 "" (sha256 $text)) -}}
+{{- $id := print "heading:" $hash ":" .Anchor -}}
+
+<h{{ .Level }} id="{{ $id | safeURL }}">
+ <a title="{{ $text | safeHTML }}" href="#{{ $id | safeURL }}">
+ {{ $text | safeHTML }}
</a>
</h{{ .Level }}>
diff --git a/themes/default/layouts/_default/_markup/render-image.html b/themes/default/layouts/_default/_markup/render-image.html
index 0cf1d5a..04bf931 100644
--- a/themes/default/layouts/_default/_markup/render-image.html
+++ b/themes/default/layouts/_default/_markup/render-image.html
@@ -1,93 +1,110 @@
-{{- $source := $.Destination | safeURL -}}
-{{- $public := print "public/" $source -}}
-{{- $local := "" -}}
-{{- $cache := "" -}}
-{{- $exists := "" -}}
-{{- $width := "" -}}
-{{- $height := "" -}}
-{{- $dimensions := "600x360" -}}
-{{- $author := .Page.Section -}}
-{{- $relURL := strings.TrimPrefix .Page.Site.BaseURL .Page.Permalink -}}
-{{- $immutable := print ($relURL | humanize | urlize) "-" ($source | sha256 | truncate 8 "") -}}
-{{- $fileCache := print (partial "function-paths-media.html") "/" $author "/" $immutable -}}
+{{- $cache := "" -}}
+{{- $width := "" -}}
+{{- $height := "" -}}
+{{- $srcset := "" -}}
+{{- $colors := "" -}}
+{{- $type := "" -}}
+{{- $source := $.Destination | safeURL -}}
+{{- $public := print "public/" $source -}}
+{{- $fetch := print (urls.Parse $source).Scheme "://" (urls.Parse $source).Host (urls.Parse $source).RequestURI -}}
+{{- $figcaption := "Image/Picture" -}}
+{{- $orientation := "landscape" -}}
+{{- $dimensions := "600x360" -}}
+{{- $author := .Page.Section -}}
+{{- $relURL := strings.TrimPrefix .Page.Site.BaseURL .Page.Permalink -}}
+{{- $immutable := print ($relURL | humanize | urlize) "-" ($source | sha256 | truncate 8 "") -}}
+{{- $storage := print $author "/media/" $immutable -}}
+{{- $cached := fileExists (print "public/" $storage ".webp") -}}
-{{- if not (or (fileExists (print "public/" $fileCache ".webp")) (fileExists (print "public/" $fileCache (path.Ext $source)))) -}}
- {{- with $remote := resources.GetRemote $source -}}
+{{- $moderns := slice ".webp" ".avif" -}}
+{{- $fallbacks := slice ".png" ".jpg" ".gif" ".jpeg" ".svg" ".apng" ".jfif" ".pjpeg" ".pjp" -}}
+{{- $mimes := slice "image/avif" "image/webp" "image/apng" "image/gif" "image/jpeg" "image/png" "image/svg+xml" -}}
+
+{{- if not $cached -}}
+ {{- with $remote := cond (default true $.Page.Site.Params.site.offline) false (resources.GetRemote $fetch) -}}
{{- with .Err -}}
{{- if fileExists $public -}}
- {{- $local = resources.Get $public -}}
- {{- with $local -}}
- {{- $local = .Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .)) -}}
+ {{- with $local := resources.Get $public -}}
+ {{- $local = .Content | resources.FromString (print $storage (path.Base .)) -}}
+ {{- $local = .Fit (print $dimensions " webp") -}}
+ {{- $local = $local | resources.Copy (print $storage ".webp") -}}
+ {{- $srcset = $local.Permalink -}}
+ {{- $local = .Fit $dimensions -}}
+ {{- $local = $local | resources.Copy (print $storage (path.Ext $local)) -}}
+ {{- $width = $local.Width -}}
+ {{- $height = $local.Height -}}
+ {{- $colors = $local.Colors -}}
+ {{- $cache = $local.Permalink -}}
{{- end -}}
{{- $source = print ("" | absURL) $source -}}
{{- else -}}
- {{- $404image := resources.Get "data/media/404.png" -}}
- {{- with $404image -}}
- {{- $width = .Width -}}
- {{- $height = .Height -}}
+ {{- with $404image := resources.Get "data/media/404.png" -}}
+ {{- $width = $404image.Width -}}
+ {{- $height = $404image.Height -}}
+ {{- $source = $404image.Permalink -}}
{{- end -}}
- {{- $source = $404image.RelPermalink -}}
{{- end -}}
{{- else -}}
- {{- $cache = .Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .)) -}}
+ {{- with $cache = $remote.Content | resources.FromString (print $storage (path.Base $remote)) -}}
+ {{- $cache = .Fit (print $dimensions " webp") -}}
+ {{- $cache = $cache | resources.Copy (print $storage ".webp") -}}
+ {{- $srcset = $cache.Permalink -}}
+ {{- $cache = .Fit $dimensions -}}
+ {{- $cache = $cache | resources.Copy (print $storage (path.Ext $cache)) -}}
+ {{- $width = $cache.Width -}}
+ {{- $height = $cache.Height -}}
+ {{- $colors = $cache.Colors -}}
+ {{- $cache = $cache.Permalink -}}
+ {{- end -}}
{{- end -}}
{{- end -}}
{{- else -}}
- {{- $exists = resources.Get (print "public/" $fileCache (path.Ext $source)) -}}
- {{- $exists = $exists.Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base $exists)) -}}
+ {{- with $cache = resources.Get (print "public/" $storage ".webp") -}}
+ {{- $width = $cache.Width -}}
+ {{- $height = $cache.Height -}}
+ {{- $colors = $cache.Colors -}}
+ {{- $type = $cache.MediaType -}}
+ {{- $srcset = print ("" | absURL) "/" $storage ".webp" -}}
+ {{- end -}}
+ {{- range $extension := $fallbacks -}}
+ {{- with resources.Get (print "public/" $storage $extension) -}}
+ {{- $cache = print ("" | absURL) "/" $storage $extension -}}
+ {{- break -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if lt $width $height -}}
+ {{- $orientation = "portrait" -}}
+{{- end -}}
+
+{{- with $caption := $.Title -}}
+ {{- $figcaption = $caption | markdownify -}}
{{ end }}
{{- /* This comment removes trailing newlines and white spaces. */ -}}
<figure>
- <a href="{{ $source }}">
+ <a data-orientation="{{ $orientation }}" href="{{ $source }}">
<picture>
- {{- with $local }}
- {{- $local = .Fit (print $dimensions " webp") }}
- {{- $local = $local | resources.Copy (print (partial "function-paths-media.html") "/" $author "/" $immutable ".webp") }}
- <source srcset="{{- $local.RelPermalink -}}" type="image/webp" />
- {{- $local = .Fit $dimensions }}
- {{- $local = $local | resources.Copy (print (partial "function-paths-media.html") "/" $author "/" $immutable (path.Ext $local)) }}
- {{- $width = $local.Width -}}
- {{- $height = $local.Height -}}
- {{- $writeToFile := $local.Permalink }}
+ {{- with $srcset }}
+ <source srcset="{{ $srcset }}" type="{{ or $type "image/webp" }}" />
{{- end }}
- {{- with $cache }}
- {{- $cache = .Fit (print $dimensions " webp") }}
- {{- $cache = $cache | resources.Copy (print $author "/media/" $immutable ".webp") }}
- <source srcset="{{- $cache.RelPermalink -}}" type="image/webp" />
- {{- $cache = .Fit $dimensions }}
- {{- $cache = $cache | resources.Copy (print (partial "function-paths-media.html") "/" $author "/" $immutable (path.Ext $cache)) }}
- {{- $width = $cache.Width -}}
- {{- $height = $cache.Height -}}
- {{- $cache = $cache.RelPermalink }}
- {{- end -}}
- {{- with $exists }}
- {{- if fileExists (print "public/" $fileCache ".webp") -}}
- <source srcset="/{{- print $fileCache ".webp" -}}" type="image/webp" />
- {{- end -}}
- {{- if fileExists (print "public/" $author "/media/" $immutable ".webp") -}}
- <source srcset="/{{- print $author "/media/" $immutable ".webp" -}}" type="image/webp" />
- {{- end -}}
- {{- $width = .Width -}}
- {{- $height = .Height -}}
- {{- $cache = .RelPermalink }}
- {{- end -}}
- <img loading="lazy"
+ <img
+ loading="lazy"
src="{{ or $cache $source }}"
alt="{{ $.Text | htmlUnescape }}"
title="{{ $.Text | htmlUnescape }}"
width="{{ $width }}"
height="{{ $height }}"
+ {{ printf `style="` | safeHTMLAttr -}}
+ {{- partial "image-gradient.css.html" $colors | safeHTMLAttr -}}
+ {{- printf `"` | safeHTMLAttr }}
/>
</picture>
</a>
<figcaption>
- {{ with $.Title -}}
- {{ . | markdownify }}
- {{ else -}}
- Image/Picture
- {{ end -}}
- <br>
- Index: {{ with $cache }} {{ print "[Cache](" . ")" | markdownify }} &middot; {{ end }}
+ {{ $figcaption }}
+ <br />
+ Index: {{ with $cache }} {{ print "[Cache](" $cache ")" | markdownify }} &middot; {{ end }}
{{ print "[Source](" $source ")" | markdownify }}
</figcaption>
</figure>
diff --git a/themes/default/layouts/_default/_markup/render-link.html b/themes/default/layouts/_default/_markup/render-link.html
index 17a6f2c..ccfbc06 100644
--- a/themes/default/layouts/_default/_markup/render-link.html
+++ b/themes/default/layouts/_default/_markup/render-link.html
@@ -1,21 +1,31 @@
{{- $link := .Destination -}}
-{{ $isRemote := strings.HasPrefix $link "http" }}
-{{- if not $isRemote -}}
-{{ $url := urls.Parse .Destination }}
-{{- if $url.Path -}}
-{{ $fragment := "" }}
-{{- with $url.Fragment }}{{ $fragment = printf "#%s" . }}{{ end -}}
-{{- with .Page.GetPage $url.Path }}{{ $link = printf "%s%s" .Permalink $fragment }}{{ end }}{{ end -}}
+{{- $url := urls.Parse $link -}}
+{{- $site := urls.Parse .Page.Site.BaseURL -}}
+{{- $local := or (eq $url.Host $site.Host) (strings.HasPrefix $link "/") -}}
+{{- $remote := not $local -}}
+
+{{- if and $local $url.Path -}}
+
+{{- $fragment := "" -}}
+
+ {{- with $url.Fragment -}}
+ {{- $fragment = printf "#%s" . -}}
+ {{- end -}}
+
+ {{- with .Page.GetPage $url.Path -}}
+ {{- $link = printf "%s%s" .Permalink $fragment -}}
+ {{- end -}}
+
{{- end -}}
+
<a
+ {{- if $remote }}
+ rel="noopener no-referrer"
+ {{- else }}
+ data-internal=""
+ {{- end }}
href="{{ $link | safeURL }}"
{{ with or .Title ($link | safeURL) -}}
title="{{ . }}"
- {{ end }}
- {{- if $isRemote -}}
- target="_blank"
- rel="noopener no-referrer"
- {{ end }}>
- {{- .Text | safeHTML -}}
-</a>
+ {{ end }}>{{ .Text | safeHTML }}</a>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/_default/baseof.html b/themes/default/layouts/_default/baseof.html
index 3ee2e03..c277115 100644
--- a/themes/default/layouts/_default/baseof.html
+++ b/themes/default/layouts/_default/baseof.html
@@ -1,11 +1,26 @@
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if $modified -}}
<!DOCTYPE html>
-<html lang="en-us" itemscope itemtype="http://schema.org/BlogPosting">
+<html
+ lang="en-us"
+ data-kind="{{ .Page.Kind }}"
+ data-type="{{ .Page.Type }}"
+ itemscope=""
+ itemtype="http://schema.org/BlogPosting"
+ data-document="html"
+>
<head>
<title>
{{- block "title" . -}}{{- end -}}
- {{- partial "site-title.html" . -}}
+ {{- partial "head-title.html" . -}}
</title>
- <meta name="description" content="{{- partial "site-description.html" . -}}">
+ <meta name="description" content="{{- partial "head-description.html" . -}}" />
{{- partial "head.html" . -}}
{{- block "styles" . -}}{{- end -}}
</head>
@@ -14,19 +29,27 @@
<a href="#main">Skip to main content</a>
</skip-link>
- <column-left>
+ <column-base position="left">
{{- partial "navigator-left.html" . -}}
- </column-left>
+ </column-base>
- <column-middle>
+ <column-base position="middle">
+ {{- block "header" . -}}{{- end -}}
<main id="main">
- {{- block "middle" . -}}{{- end -}}
- {{- partial "footer.html" . -}}
+ {{- block "middle" . -}}
+ <footer>Silence is golden.</footer>
+ {{- end -}}
</main>
- </column-middle>
+ {{- block "footer" . -}}
+ {{- partial "footer.html" . -}}
+ {{- end -}}
+ </column-base>
- <column-right>
- {{- block "right" . -}}{{- end -}}
- </column-right>
+ <column-base position="right">
+ {{- block "right" . -}}
+ <footer>Silence is golden.</footer>
+ {{- end -}}
+ </column-base>
</body>
</html>
+{{- end -}}
diff --git a/themes/default/layouts/_default/baseof.json b/themes/default/layouts/_default/baseof.json
new file mode 100644
index 0000000..e1203cc
--- /dev/null
+++ b/themes/default/layouts/_default/baseof.json
@@ -0,0 +1,12 @@
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if $modified -}}
+ {{- block "main" . -}}
+ "Silence is golden."
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/baseof.txt b/themes/default/layouts/_default/baseof.txt
new file mode 100644
index 0000000..c354667
--- /dev/null
+++ b/themes/default/layouts/_default/baseof.txt
@@ -0,0 +1,12 @@
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if $modified -}}
+ {{- block "main" . -}}
+ Silence is golden.
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/baseof.xml b/themes/default/layouts/_default/baseof.xml
new file mode 100644
index 0000000..73f129f
--- /dev/null
+++ b/themes/default/layouts/_default/baseof.xml
@@ -0,0 +1,13 @@
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if $modified -}}
+{{- block "main" . -}}
+{{- printf `<?xml version="1.0" encoding="utf-8" standalone="yes"?>%s` "\n" | safeHTML -}}
+<root>Silence is golden.</root>
+{{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/drafts.html b/themes/default/layouts/_default/drafts.html
deleted file mode 100644
index 635f17b..0000000
--- a/themes/default/layouts/_default/drafts.html
+++ /dev/null
@@ -1,54 +0,0 @@
-{{ define "styles" }}
-{{ $author := partial "author-user.html" . }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
-
- tab-list a[href="{{ .Site.BaseURL }}/{{ $author }}/drafts/"] {
- color: #111;
- color: var(--foreground);
- display: inherit;
- font-weight: 700;
- text-decoration-color: #014cc6;
- text-decoration-color: var(--link);
- text-decoration: underline;
- }
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Drafts"
- "Subtitle" (partial "count-drafts.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
- }}
-
- {{ partial "profile.html" . }}
-
- {{- $author := partial "author-user.html" . -}}
- {{- $users := where .Site.RegularPages "Section" $author -}}
- {{- $drafts := where .Site.RegularPages "Draft" true -}}
- {{- $filteredPages := $users | intersect $drafts -}}
- {{- $paginator := .Paginate $filteredPages }}
-
- {{ range $paginator.Pages }}
- {{ .Render "summary" }}
- {{ else }}
- <footer>
- <code>No drafts found!</code>
- </footer>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/feeds.html b/themes/default/layouts/_default/feeds.html
deleted file mode 100644
index 332c455..0000000
--- a/themes/default/layouts/_default/feeds.html
+++ /dev/null
@@ -1,50 +0,0 @@
-{{ define "styles" }}
-{{ $author := partial "author-user.html" . }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
-
- tab-list a[href="{{ .Site.BaseURL }}/{{ $author }}/feeds/"] {
- color: #111;
- color: var(--foreground);
- display: inherit;
- font-weight: 700;
- text-decoration-color: #014cc6;
- text-decoration-color: var(--link);
- text-decoration: underline;
- }
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Feeds"
- "Subtitle" (partial "count-feeds.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
- }}
-
- {{ partial "profile.html" . }}
-
- {{ range .Paginator.Pages }}
- {{ .Render "summary" }}
- {{ else }}
- <footer>
- <code>No feeds found!</code>
- </footer>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
- {{ partial "generate-feeds" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/home.archive-messages.html b/themes/default/layouts/_default/home.archive-messages.html
deleted file mode 100644
index d97694f..0000000
--- a/themes/default/layouts/_default/home.archive-messages.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{{ define "title" }}Message History &mdash; {{ end }}
-{{ define "description" }}This page contains an archive of all messages &mdash; {{ end }}
-{{ define "styles" }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/archives/messages/") | safeCSS }}
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
-{{ partial "navigator-middle.html"
- (dict
- "Title" "History"
- "Subtitle" (partial "count-total-messages.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
-}}
-
-<message-archive>
- <item-list>
- {{ $type := (partial "author-user.html" .) }}
- {{ range (.Site.RegularPages.GroupByDate "2006") }}
- {{ range (first 1 .Pages) }}
- <h1>{{ .Date.Format "2006" }}</h1>
- {{ end }}
- <ul>
- {{ range .Pages }}
- <li>
- <a title="{{ partial "title.html" . }}" href="{{ .RelPermalink }}#{{ partial "card-id.html" . }}">
- <span><code>{{ .Date.Format "02 Jan" }}</code></span>
- <span>{{ partial "title.html" . }}</span>
- <span>@{{ partial "author-user.html" . }}</span>
- </a>
- </li>
- {{ end }}
- </ul>
- {{ end }}
- </item-list>
-</message-archive>
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/home.archive-tags.html b/themes/default/layouts/_default/home.archive-tags.html
deleted file mode 100644
index 7fec925..0000000
--- a/themes/default/layouts/_default/home.archive-tags.html
+++ /dev/null
@@ -1,56 +0,0 @@
-{{ define "title" }}Tags Archive &mdash; {{ end }}
-{{ define "description" }}This page contains an archive of all tags &mdash; {{ end }}
-{{ define "styles" }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/archives/tags/") | safeCSS }}
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
-{{ partial "navigator-middle.html"
- (dict
- "Title" "Records"
- "Subtitle" (partial "count-tags.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
-}}
-
-{{- $page := 1 -}}
-{{- $count := 0 -}}
-
-<item-list>
- {{ range $taxonomy := .Site.Taxonomies }}
- {{ range $tag, $article := $taxonomy }}
- <h1><a href="{{ $.Site.BaseURL }}/tags/{{ $tag }}/">#{{ $tag }}</a></h1>
- <ul>
- {{ range $article.Pages -}}
- {{- $count = add $count 1 -}}
- <li>
- <a
- title="{{ partial "title.html" . }}"
- href="{{ .Site.BaseURL }}/tags/{{ $tag }}/{{ if gt $page 1 }}page/{{ $page }}/{{ end }}#{{ partial "card-id.html" . }}">
- <span><code>{{ .Date.Format "02 Jan 2006" }}</code></span>
- <span>{{ partial "title.html" . }}</span>
- <span>@{{ partial "author-user.html" . }}</span>
- </a>
- </li>
- {{ if eq (mod $count $.Paginator.PageSize) 0 }}
- {{ $page = add $page 1 }}
- {{- end -}}
- {{- end -}}
- {{- $page = 1 -}}
- {{- $count = 0 -}}
- </ul>
- {{ end }}
- {{ end }}
-</item-list>
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/home.archives.html b/themes/default/layouts/_default/home.archives.html
new file mode 100644
index 0000000..f443583
--- /dev/null
+++ b/themes/default/layouts/_default/home.archives.html
@@ -0,0 +1,67 @@
+{{- define "title" -}}Archives &mdash; {{ end -}}
+{{- define "description" -}}An archive of all items &mdash; {{ end -}}
+{{- define "styles" -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/archives/") | safeCSS }}
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Archives"
+ "Icon" "arrow-left"
+ "Subtitle" (print (partial "count.html" .) " " "Total")
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ <archive-list>
+ <time-line>
+ {{ range (.Paginator.Pages.GroupByDate "2006") }}
+ {{ range (first 1 .Pages) }}
+ <h1>{{ .Date | time.Format "2006" }}</h1>
+ {{ end }}
+ <ul>
+ {{ range .Pages }}
+ {{- $author := .Page.Section -}}
+ <li>
+ <a
+ title="{{ partial "meta-title.html" . }}"
+ href="{{ .Permalink }}#{{ partial "card-id.html" . }}"
+ >
+ <code>
+ <time
+ data-type="disabled"
+ datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
+ title="{{ .Date | time.Format "Posted: Monday January 2 2006 at 15:04:05 MST" }}"
+ >
+ {{ .Date | time.Format "02 Jan" }}
+ </time>
+ </code>
+ <section>
+ <h2>{{ partial "meta-title.html" . }}</h2>
+ <p>@{{ or .Params.feed.domain $author }}</p>
+ </section>
+ </a>
+ </li>
+ {{ end }}
+ </ul>
+ {{ end }}
+ </time-line>
+ </archive-list>
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/home.authors.html b/themes/default/layouts/_default/home.authors.html
index db67566..0662285 100644
--- a/themes/default/layouts/_default/home.authors.html
+++ b/themes/default/layouts/_default/home.authors.html
@@ -1,38 +1,41 @@
-{{ define "title" }}Authors &mdash; {{ end }}
-{{ define "description" }}This page contains a list of all authors &mdash; {{ end }}
-{{ define "styles" }}
+{{- define "title" -}}Authors &mdash; {{ end -}}
+{{- define "description" -}}A list of all authors &mdash; {{ end -}}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/authors/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/authors/") | safeCSS }}
</style>
-{{ end }}
+{{- end -}}
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
(dict
"Title" "Authors"
- "Subtitle" (partial "count-authors.html" .)
+ "Subtitle" (print (partial "count-authors.html" .) " " "Total")
"Icon" "arrow-left"
"IconLabel" "Back"
"Href" "/"
"Id" "back"
"Context" .
)
- }}
-
- {{ $authors := slice }}
+ -}}
+{{- end -}}
- {{- range $index, $data := .Site.Data -}}
- {{- $authors = $authors | append $data.user -}}
- {{- end -}}
+{{- define "middle" -}}
+ {{- partial "generate-authors" . -}}
- {{- range $author := (shuffle (uniq $authors)) -}}
- {{ $data := index $.Site.Data $author | default "default" }}
- {{ partial "author-card.html" (dict "Data" $data) }}
- {{ end }}
+ {{- $authors := partial "function-authors-slice.html" . -}}
-{{ end }}
+ {{- range $author := $authors -}}
+ {{- $data := index $.Site.Data.authors $author -}}
+ {{- $date := (index (first 1 (where $.Site.Pages.ByDate.Reverse "Section" $author)) 0).Date -}}
+ {{- partial "author-card.html" (dict
+ "Data" $data
+ "Date" $date
+ )
+ -}}
+ {{- end -}}
+{{- end -}}
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/home.authors.section.html b/themes/default/layouts/_default/home.authors.section.html
new file mode 100644
index 0000000..b0b1161
--- /dev/null
+++ b/themes/default/layouts/_default/home.authors.section.html
@@ -0,0 +1,20 @@
+{{- $authors := partial "function-authors-slice.html" . -}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if $modified -}}
+ {{- range $author := first 3 $authors -}}
+ {{- $data := index $.Site.Data.authors $author -}}
+ {{- $date := (index (first 1 (where $.Site.Pages.ByDate.Reverse "Section" $author)) 0).Date -}}
+ {{- partial "author-card.html" (dict
+ "Data" $data
+ "Date" $date
+ )
+ -}}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/home.browserconfig.xml b/themes/default/layouts/_default/home.browserconfig.xml
deleted file mode 100644
index 67bc7a3..0000000
--- a/themes/default/layouts/_default/home.browserconfig.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-{{- $icon := resources.Get .Site.Params.webmanifest.logo -}}
-
-{{- $mstile150 := $icon.Fit "150x150" -}}
-
-<?xml version="1.0" encoding="utf-8"?>
-<browserconfig>
- <msapplication>
- <tile>
- <square150x150logo src="{{ $mstile150.Permalink }}"/>
- <TileColor>#da532c</TileColor>
- </tile>
- </msapplication>
-</browserconfig>
diff --git a/themes/default/layouts/_default/home.rss-style.xsl b/themes/default/layouts/_default/home.rss-style.xsl
deleted file mode 100644
index b537d38..0000000
--- a/themes/default/layouts/_default/home.rss-style.xsl
+++ /dev/null
@@ -1,146 +0,0 @@
-{{- print "<?xml version=\"1.0\" encoding=\"utf-8\"?>" | safeHTML }}
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="3.0">
- <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
- <xsl:template match="/">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- {{ print "<title><xsl:value-of select=\"/rss/channel/title\"/> Web Feed</title>" | safeHTML }}
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
- {{- $default := resources.Get "css/default.css" -}}
- {{- if .Site.Params.site.production -}}
- {{ $css := slice $default | resources.Concat "css/bundle.css" | resources.Minify | fingerprint }}
- <link rel="stylesheet" type="text/css" href="{{ $css.Permalink }}"/>
- {{- else }}
- <link rel="stylesheet" type="text/css" href="{{ $default.Permalink }}"/>
- {{- end }}
- </head>
- <body>
- <column-left>
- </column-left>
- <column-middle>
- <main>
- <nav>
- <icon-button>
- <a id="back" href="/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-left.svg")) }}
- <small>Back</small>
- </a>
- </icon-button>
-
- <section>
- <h2><xsl:value-of select="/rss/channel/title"/> Feed</h2>
- <small>Web Feed Preview</small>
- </section>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-home" href="/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/home.svg")) }}
- <small>Home</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-tag" href="/tags/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/tag.svg")) }}
- <small>Tags</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-clock" href="/archives/messages/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/tabler/clock.svg")) }}
- <small>History</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-book-2" href="/archives/tags/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/tabler/book-2.svg")) }}
- <small>Records</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-users" href="/authors/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/users.svg")) }}
- <small>Authors</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-rss" href="/rss.xml">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/rss.svg")) }}
- <small>RSS</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-circle" href="/index.json">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/circle.svg")) }}
- <small>JSON</small>
- </a>
- </icon-button>
- </icon-navigator>
-
- <icon-navigator hidden="">
- <icon-button>
- <a id="nav-middle-git-commit" href="/sources/">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/git-commit.svg")) }}
- <small>Sources</small>
- </a>
- </icon-button>
- </icon-navigator>
- </nav>
- <navigation-separator><hr hidden=""></hr></navigation-separator>
- <xsl:for-each select="/rss/channel/item">
- <micro-card>
- <micro-summary>
- <micro-thumbnail>
- <figure>
- <a><xsl:attribute name="href"><xsl:value-of select="/rss/channel/link"/></xsl:attribute>
- <picture>
- <img
- loading="lazy"
- >
- <xsl:attribute name="alt"><xsl:value-of select="/rss/channel/category"/></xsl:attribute>
- <xsl:attribute name="title"><xsl:value-of select="/rss/channel/category"/></xsl:attribute>
- <xsl:attribute name="src">{{ .Site.BaseURL }}/<xsl:value-of select="/rss/channel/category"/>/media/profile/picture.png</xsl:attribute>
- </img>
- </picture>
- </a>
- </figure>
- </micro-thumbnail>
- <micro-content>
- <h2>
- <a>
- <xsl:attribute name="href"><xsl:value-of select="link" /></xsl:attribute>
- <xsl:value-of select="title" />
- </a>
- </h2>
- <small> Published: <xsl:value-of select="pubDate" /> </small>
- </micro-content>
- </micro-summary>
- </micro-card>
- </xsl:for-each>
- </main>
- </column-middle>
- <column-right>
- </column-right>
- </body>
- </html>
- </xsl:template>
-</xsl:stylesheet>
diff --git a/themes/default/layouts/_default/home.settings.html b/themes/default/layouts/_default/home.settings.html
new file mode 100644
index 0000000..84e8080
--- /dev/null
+++ b/themes/default/layouts/_default/home.settings.html
@@ -0,0 +1,32 @@
+{{- define "title" -}}Settings &mdash; {{ end -}}
+{{- define "description" -}}A list of all interface settings &mdash; {{ end -}}
+{{- define "styles" -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/settings/") | safeCSS }}
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Settings"
+ "Icon" "arrow-left"
+ "Subtitle" "Interface"
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+{{- end -}}
+
+{{- define "middle" -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/home.sources.html b/themes/default/layouts/_default/home.sources.html
index 424180a..42b6cc3 100644
--- a/themes/default/layouts/_default/home.sources.html
+++ b/themes/default/layouts/_default/home.sources.html
@@ -1,41 +1,53 @@
-{{ define "title" }}Sources &mdash; {{ end }}
-{{ define "description" }}This page contains a list of all source files &mdash; {{ end }}
-{{ define "styles" }}
+{{- define "title" -}}Sources &mdash; {{ end -}}
+{{- define "description" -}}A list of all sources &mdash; {{ end -}}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/sources/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/sources/") | safeCSS }}
</style>
-{{ end }}
+{{- end -}}
-{{ define "middle" }}
+{{- define "header" -}}
+ {{- $_default := readDir (print "/themes/default/layouts/_default") -}}
+ {{- $_markup := readDir (print "/themes/default/layouts/_default/_markup") -}}
+ {{- $partials := readDir (print "/themes/default/layouts/partials") -}}
+ {{- $shortcodes := readDir (print "/themes/default/layouts/shortcodes") -}}
- {{ $_default := readDir (print "/themes/default/layouts/_default") }}
- {{ $_markup := readDir (print "/themes/default/layouts/_default/_markup") }}
- {{ $partials := readDir (print "/themes/default/layouts/partials") }}
- {{ $shortcodes := readDir (print "/themes/default/layouts/shortcodes") }}
+ {{- $fileCount := add
+ (add
+ (sub (len $_default) 1)
+ (len $_markup))
+ (add
+ (len $partials)
+ (len $shortcodes))
+ -}}
- {{ $fileCount := add (len $shortcodes) (len $partials) }}
-
- {{ partial "navigator-middle.html"
+ {{- partial "navigator-middle.html"
(dict
"Title" "Sources"
- "Subtitle" (print $fileCount " " "Files")
+ "Subtitle" (print $fileCount " " "Total")
"Icon" "arrow-left"
"IconLabel" "Back"
"Href" "/"
"Id" "back"
"Context" .
)
- }}
+ -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- $_default := readDir (print "/themes/default/layouts/_default") -}}
+ {{- $_markup := readDir (print "/themes/default/layouts/_default/_markup") -}}
+ {{- $partials := readDir (print "/themes/default/layouts/partials") -}}
+ {{- $shortcodes := readDir (print "/themes/default/layouts/shortcodes") -}}
<source-files>
<item-list>
-
<h1>Defaults</h1>
<ul>
{{ range sort $_default ".ModTime" "desc" }}
{{ if not .IsDir }}
<li>
- <a download title="{{ .Name }}" href="{{ $.Site.BaseURL }}/sources/files/_default/{{ .Name }}">
+ <a download="true" title="{{ .Name }}" href="{{ "" | absURL }}/sources/files/_default/{{ .Name }}">
<span><code>{{- .ModTime | time.Format "2006-01-02 15:04 MST" }}</code></span>
<span><code>{{ .Name }}</code></span>
<span><code>{{ .Size -}}</code></span>
@@ -50,7 +62,7 @@
{{ range sort $_markup ".ModTime" "desc" }}
{{ if not .IsDir }}
<li>
- <a download title="{{ .Name }}" href="{{ $.Site.BaseURL }}/sources/files/_default/_markup/{{ .Name }}">
+ <a download="true" title="{{ .Name }}" href="{{ "" | absURL }}/sources/files/_default/_markup/{{ .Name }}">
<span><code>{{- .ModTime | time.Format "2006-01-02 15:04 MST" }}</code></span>
<span><code>{{ .Name }}</code></span>
<span><code>{{ .Size -}}</code></span>
@@ -65,7 +77,7 @@
{{ range sort $partials ".ModTime" "desc" }}
{{ if not .IsDir }}
<li>
- <a download title="{{ .Name }}" href="{{ $.Site.BaseURL }}/sources/files/partials/{{ .Name }}">
+ <a download="true" title="{{ .Name }}" href="{{ "" | absURL }}/sources/files/partials/{{ .Name }}">
<span><code>{{- .ModTime | time.Format "2006-01-02 15:04 MST" }}</code></span>
<span><code>{{ .Name }}</code></span>
<span><code>{{ .Size -}}</code></span>
@@ -80,7 +92,7 @@
{{ range sort $shortcodes ".ModTime" "desc" }}
{{ if not .IsDir }}
<li>
- <a download title="{{ .Name }}" href="{{ $.Site.BaseURL }}/sources/files/shortcodes/{{ .Name }}">
+ <a download="true" title="{{ .Name }}" href="{{ "" | absURL }}/sources/files/shortcodes/{{ .Name }}">
<span><code>{{- .ModTime | time.Format "2006-01-02 15:04 MST" }}</code></span>
<span><code>{{ .Name }}</code></span>
<span><code>{{ .Size -}}</code></span>
@@ -93,20 +105,18 @@
<footer>
<p>
- Canory Version: 0.8.13
- &middot; Dictionary Access by Paul Lutus: <a href="https://arachnoid.com/javascript/dictionary_access.js">GPLv2+ License</a>
- &middot; Feather Icons by Cole Bemis: <a href="https://github.com/feathericons/feather/blob/8b5d6802fa8fd1eb3924b465ff718d2fa8d61efe/LICENSE">MIT License</a>
- &middot; Tabler Icons by Paweł Kuna: <a href="https://github.com/tabler/tabler-icons/blob/60f39297d0f785f2e8635faca6857b2260b2d164/LICENSE">MIT License</a>
- &middot; Instant Page by Alexandre Dieulot: <a href="https://github.com/instantpage/instant.page/blob/729e97d5b3245552e41d8f92ed03d08f1d62ea46/LICENSE">MIT License</a>
- &middot; Fixed Search by Heracles Papatheodorou: <a href="https://gist.github.com/Arty2/8b0c43581013753438a3d35c15091a9f#file-license-md">License</a>
- &middot; Fuzzy Sort by Stephen Kamenar: <a href="https://github.com/farzher/fuzzysort/blob/e7f484a124f09bf3cb9a4db366a95457d962dbed/LICENSE">MIT License</a>
+ Canory Version: {{ "{{% version number %}}" | markdownify }}
+ &middot; Dictionary Access by Paul Lutus: <a href="https://arachnoid.com/javascript/dictionary_access.js">GPLv2+ Licence</a>
+ &middot; Feather Icons by Cole Bemis: <a href="https://github.com/feathericons/feather/blob/8b5d6802fa8fd1eb3924b465ff718d2fa8d61efe/Licence">MIT Licence</a>
+ &middot; Tabler Icons by Paweł Kuna: <a href="https://github.com/tabler/tabler-icons/blob/60f39297d0f785f2e8635faca6857b2260b2d164/Licence">MIT Licence</a>
+ &middot; Instant Page by Alexandre Dieulot: <a href="https://github.com/instantpage/instant.page/blob/729e97d5b3245552e41d8f92ed03d08f1d62ea46/Licence">MIT Licence</a>
+ &middot; Fixed Search by Heracles Papatheodorou: <a href="https://gist.github.com/Arty2/8b0c43581013753438a3d35c15091a9f#file-Licence-md">MIT Licence</a>
+ &middot; Fuzzy Sort by Stephen Kamenar: <a href="https://github.com/farzher/fuzzysort/blob/e7f484a124f09bf3cb9a4db366a95457d962dbed/Licence">MIT Licence</a>
</p>
</footer>
-
</source-files>
+{{- end -}}
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/home.xslt.rss.xsl b/themes/default/layouts/_default/home.xslt.rss.xsl
new file mode 100644
index 0000000..587d119
--- /dev/null
+++ b/themes/default/layouts/_default/home.xslt.rss.xsl
@@ -0,0 +1,104 @@
+{{- printf `<?xml version="1.0" encoding="utf-8"?>` | safeHTML }}
+<xsl:stylesheet
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
+ version="1.1"
+>
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
+ <xsl:template match="/">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" data-xml="" data-document="xhtml">
+ <head>
+ {{ printf `<title><xsl:value-of select="/rss/channel/title" /> Web Feed</title>` | safeHTML }}
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
+ {{- partial "head-css.html" . -}}
+ {{- partial "head-js.html" . -}}
+ </head>
+ <body>
+ <column-base position="left"></column-base>
+ <column-base position="middle">
+ <nav>
+ <icon-button>
+ <a id="back" target="_self">
+ <xsl:choose>
+ <xsl:when test="/rss/channel/atom:link[@rel='previous']/@href">
+ <xsl:attribute name="href">
+ <xsl:value-of select="/rss/channel/atom:link[@rel='previous']/@href" />
+ </xsl:attribute>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:attribute name="href">/</xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-left.svg")) }}
+ <small>Back</small>
+ </a>
+ </icon-button>
+ <section>
+ <h2><xsl:value-of select="/rss/channel/title" />'s Feed</h2>
+ <small>Web Feed Preview</small>
+ </section>
+ <xsl:if test="/rss/channel/atom:link[@rel='next']/@href">
+ <icon-button>
+ <a>
+ <xsl:attribute name="href">
+ <xsl:value-of select="/rss/channel/atom:link[@rel='next']/@href" />
+ </xsl:attribute>
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-right.svg")) }}
+ <small>Next</small>
+ </a>
+ </icon-button>
+ </xsl:if>
+ {{ if .Site.Menus.main }}
+ {{ range .Site.Menus.main }}
+ <icon-navigator hidden="">
+ <icon-button>
+ <a id="nav-middle-{{ path.Base .Identifier }}" href="{{ .URL | absURL }}">
+ {{ with .Identifier }}
+ {{ $icon := print (partial "function-paths.html").static "/icons/" . ".svg" }}
+ {{ safeHTML (readFile $icon) }}
+ {{ end }}
+ <small>{{ delimit (first 1 (split .Name " ")) " " }}</small>
+ </a>
+ </icon-button>
+ </icon-navigator>
+ {{ end }}
+ {{ end }}
+ </nav>
+ <main>
+ <xsl:for-each select="/rss/channel/item">
+ <micro-card>
+ <header>
+ <figure>
+ <a>
+ <xsl:attribute name="href"><xsl:value-of select="link" /></xsl:attribute>
+ <span>
+ <object>
+ <xsl:attribute name="title"><xsl:value-of select="atom:author/atom:name" /></xsl:attribute>
+ <xsl:attribute name="data"><xsl:value-of select="atom:author/atom:uri" /></xsl:attribute>
+ <xsl:value-of select="substring(atom:author/atom:name, 1, 1)" />
+ </object>
+ </span>
+ </a>
+ </figure>
+ </header>
+ <article>
+ <h2>
+ <a>
+ <xsl:attribute name="href"><xsl:value-of select="link" /></xsl:attribute>
+ <xsl:value-of select="title" />
+ </a>
+ </h2>
+ <small>Published: <xsl:value-of select="pubDate" /></small>
+ </article>
+ </micro-card>
+ </xsl:for-each>
+ </main>
+ </column-base>
+ <column-base position="right"></column-base>
+ </body>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/themes/default/layouts/_default/home.xslt.sitemap.xsl b/themes/default/layouts/_default/home.xslt.sitemap.xsl
new file mode 100644
index 0000000..e0be723
--- /dev/null
+++ b/themes/default/layouts/_default/home.xslt.sitemap.xsl
@@ -0,0 +1,90 @@
+{{- printf `<?xml version="1.0" encoding="utf-8"?>` | safeHTML }}
+<xsl:stylesheet
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
+ version="1.1"
+>
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
+ <xsl:template match="/">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" data-xml="sitemap" data-document="xhtml">
+ <head>
+ <title>{{ $.Site.Title }} Site Map</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
+ {{- partial "head-css.html" . -}}
+ {{- partial "head-js.html" . -}}
+ </head>
+ <body>
+ <column-base position="left"></column-base>
+ <column-base position="middle">
+ <nav>
+ <icon-button>
+ <a id="back" target="_self" href="/">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-left.svg")) }}
+ <small>Back</small>
+ </a>
+ </icon-button>
+ <section>
+ <h2>{{ $.Site.Title }} Site Map</h2>
+ <small>Site Map Preview</small>
+ </section>
+ {{ if .Site.Menus.main }}
+ {{ range .Site.Menus.main }}
+ <icon-navigator hidden="">
+ <icon-button>
+ <a
+ id="nav-middle-{{ path.Base .Identifier }}"
+ href="{{ .URL | absURL }}"
+ >
+ {{ with .Identifier }}
+ {{ $icon := print (partial "function-paths.html").static "/icons/" . ".svg" }}
+ {{ safeHTML (readFile $icon) }}
+ {{ end }}
+ <small>{{ delimit (first 1 (split .Name " ")) " " }}</small>
+ </a>
+ </icon-button>
+ </icon-navigator>
+ {{ end }}
+ {{ end }}
+ </nav>
+ <main>
+ <navigation-separator><hr hidden=""></hr></navigation-separator>
+ <section>
+ <table>
+ <thead>
+ <tr>
+ <th align="left">
+ <code>
+ <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/>
+ Uniform Resource Locators (URLs)
+ </code>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <xsl:for-each select="sitemap:urlset/sitemap:url">
+ <tr>
+ <td>
+ <a>
+ <xsl:attribute name="href">
+ <xsl:value-of select="sitemap:loc" />
+ </xsl:attribute>
+<xsl:attribute name="title">Last Modified: <xsl:value-of select="sitemap:lastmod" />
+Frequency: <xsl:value-of select="sitemap:changefreq" />
+Priority: <xsl:value-of select="sitemap:priority" />
+ </xsl:attribute>
+ <xsl:value-of select="sitemap:loc" />
+ </a>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </tbody>
+ </table>
+ </section>
+ </main>
+ </column-base>
+ <column-base position="right"></column-base>
+ </body>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/themes/default/layouts/_default/index.html b/themes/default/layouts/_default/index.html
new file mode 100644
index 0000000..f25cabf
--- /dev/null
+++ b/themes/default/layouts/_default/index.html
@@ -0,0 +1,34 @@
+{{- define "styles" -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "Title" "Home"
+ "Subtitle" (print (partial "count.html" .) " " "Total")
+ "IconLabel" (and (gt .Paginator.PageNumber 1) "Back")
+ "Id" (and (gt .Paginator.PageNumber 1) "back")
+ "Icon" (and (gt .Paginator.PageNumber 1) "arrow-left")
+ "Href" (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL))
+ )
+ -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/index.json b/themes/default/layouts/_default/index.json
index 63f8445..9484e60 100644
--- a/themes/default/layouts/_default/index.json
+++ b/themes/default/layouts/_default/index.json
@@ -1,25 +1,30 @@
+{{- define "main" -}}
+
{
"version": "https://jsonfeed.org/version/1.1",
"title": "{{ .Site.Title }}",
"home_page_url": "{{ .Site.BaseURL }}",
"feed_url": "{{ .Site.BaseURL }}/index.json",
+ {{- with .Paginator.Next }}
+ "next_url": "{{ .URL | absURL }}",
+ {{- end }}
"items": [
- {{- range $index, $data := .Site.RegularPages -}}
- {{- if and (ne $data.Type "json") (not .ExpiryDate) (not .Params.unlisted) -}}
+ {{- $filteredPages := partial "function-filters-content.html" .Paginator.Pages -}}
+ {{- range $index, $data := $filteredPages -}}
{{- if and $index (gt $index 0) -}},{{- end }}
{
- "id": "{{ md5 $data.Permalink }}",
+ "id": "{{ sha256 $data.Permalink }}",
"url": "{{ $data.Permalink }}",
- "title": "{{ $data.Summary | htmlUnescape }}",
- "summary": "{{ $data.Summary | htmlUnescape }}",
+ "title": {{ $data.Summary | htmlUnescape | jsonify }},
+ "summary": {{ $data.Summary | htmlUnescape | jsonify }},
"date_modified": "{{ $data.Date | time.Format "2006-01-02T15:04:05Z" }}",
"date_published": "{{ $data.PublishDate | time.Format "2006-01-02T15:04:05Z" }}",
"_metadata": {
- "slug": "{{ $data.Slug }}",
+ "kind": "{{ $data.Kind }}",
"type": "{{ $data.Type }}"
},
"author": {
- "name": "{{ partial "author-user.html" . }}"
+ "name": "{{ $data.Type }}"
},
"tags": [
{{- range $tags, $tag := $data.Params.tags -}}
@@ -32,9 +37,10 @@
{{- end -}}
],
"content_text": {{ $data.Plain | jsonify }},
- "content_html": {{ $data.Content | jsonify }}
+ "content_html": {{ partial "function-content.html" $data | jsonify }}
}
- {{- end -}}
- {{ end }}
+ {{- end }}
]
}
+
+{{- end -}}
diff --git a/themes/default/layouts/_default/index.webmanifest b/themes/default/layouts/_default/index.webmanifest
deleted file mode 100644
index f7b3f66..0000000
--- a/themes/default/layouts/_default/index.webmanifest
+++ /dev/null
@@ -1,24 +0,0 @@
-{{- $icon := resources.Get .Site.Params.webmanifest.logo -}}
-
-{{- $androidChrome192 := $icon.Fit "192x192" -}}
-{{- $androidChrome512 := $icon.Fit "512x512" -}}
-
-{
- "name": "{{ .Site.Params.webmanifest.name }}",
- "short_name": "{{ .Site.Params.webmanifest.shortName }}",
- "icons": [
- {
- "src": "{{ $androidChrome192.Permalink }}",
- "sizes": "192x192",
- "type": "image/png"
- },
- {
- "src": "{{ $androidChrome512.Permalink }}",
- "sizes": "512x512",
- "type": "image/png"
- }
- ],
- "theme_color": "{{ .Site.Params.webmanifest.themeColor }}",
- "background_color": "{{ .Site.Params.webmanifest.backgroundColor }}",
- "display": "{{ .Site.Params.webmanifest.display }}"
-}
diff --git a/themes/default/layouts/_default/likes.html b/themes/default/layouts/_default/likes.html
deleted file mode 100644
index f37159c..0000000
--- a/themes/default/layouts/_default/likes.html
+++ /dev/null
@@ -1,54 +0,0 @@
-{{ define "styles" }}
-{{ $author := partial "author-user.html" . }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
-
- tab-list a[href="{{ .Site.BaseURL }}/{{ $author }}/likes/"] {
- color: #111;
- color: var(--foreground);
- display: inherit;
- font-weight: 700;
- text-decoration-color: #014cc6;
- text-decoration-color: var(--link);
- text-decoration: underline;
- }
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Likes"
- "Subtitle" (partial "count-likes.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
- }}
-
- {{ partial "profile.html" . }}
-
- {{- $author := partial "author-user.html" . -}}
- {{- $users := where .Site.RegularPages "Section" $author -}}
- {{- $likes := where .Site.RegularPages ".Params.liked" true -}}
- {{- $filteredPages := $users | intersect $likes -}}
- {{- $paginator := .Paginate $filteredPages }}
-
- {{ range $paginator.Pages }}
- {{ .Render "summary" }}
- {{ else }}
- <footer>
- <code>No likes found!</code>
- </footer>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/list.html b/themes/default/layouts/_default/list.html
deleted file mode 100644
index 5cc563b..0000000
--- a/themes/default/layouts/_default/list.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{{ define "styles" }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Home"
- "Subtitle" (partial "count-total-messages.html" .)
- "Context" .
- )
- }}
-
- {{ range .Paginator.Pages }}
- {{ .Render "summary" }}
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "author-list.html" . -}}
-
- {{ range first 1 (where .Site.Pages "Params.Author" .Site.Author.default.picturegallery) }}
- {{- partial "gallery-images.html" . -}}
- {{ end }}
-
- {{ range first 1 (where .Site.Pages "Params.Author" .Site.Author.default.webring) }}
- {{- partial "web-ring.html" . -}}
- {{ end }}
-
-{{ end }}
diff --git a/themes/default/layouts/_default/media.html b/themes/default/layouts/_default/media.html
deleted file mode 100644
index f4bb3a9..0000000
--- a/themes/default/layouts/_default/media.html
+++ /dev/null
@@ -1,68 +0,0 @@
-{{ define "styles" }}
-{{ $author := partial "author-user.html" . }}
-<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
-
- tab-list a[href="{{ .Site.BaseURL }}/{{ $author }}/media/"] {
- color: #111;
- color: var(--foreground);
- display: inherit;
- font-weight: 700;
- text-decoration-color: #014cc6;
- text-decoration-color: var(--link);
- text-decoration: underline;
- }
-</style>
-{{ end }}
-
-{{ define "middle" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Media"
- "Subtitle" (partial "count-media.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
- }}
-
- {{ partial "profile.html" . }}
-
- {{- $author := partial "author-user.html" . -}}
-
- {{ $count := 0 }}
- {{ $result := false }}
-
- {{ range .Site.Pages }}
- {{ if or
- (in .Content "<figure>")
- (in .Content "<imgur-video>")
- (in .Content "<youtube-video>")
- (in .Content "<video-container>")
- }}
- {{ if eq .Type $author }}
- {{ $result = true }}
- {{ $count = add $count 1 }}
- {{ if le $count 10 }}
- {{ .Render "summary" }}
- {{ end }}
- {{ end }}
- {{ end }}
- {{ end }}
-
- {{ if not $result }}
- <footer>
- <code>No media found!</code>
- </footer>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
diff --git a/themes/default/layouts/_default/rss.xml b/themes/default/layouts/_default/rss.xml
index a09f9bf..16aee5f 100644
--- a/themes/default/layouts/_default/rss.xml
+++ b/themes/default/layouts/_default/rss.xml
@@ -1,40 +1,112 @@
-{{- $pctx := . -}}
-{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
-{{- $pages := $pctx.RegularPages -}}
+{{- define "main" -}}
+
+{{- $absURL := "" | absURL -}}
+
{{- $limit := .Site.Config.Services.RSS.Limit -}}
-{{- if ge $limit 1 -}}
-{{- $pages = $pages | first $limit -}}
+
+{{- if lt $limit 1 -}}
+ {{- $limit = .Paginator.TotalNumberOfElements -}}
+{{- end -}}
+
+{{- $lastBuildDate := now | time.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML -}}
+
+{{- if not .Date.IsZero -}}
+ {{- $lastBuildDate = .Date | time.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML -}}
+{{- end -}}
+
+{{- $title := partial "head-title.html" . -}}
+{{- $description := partial "head-title.html" . -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $image := print "/favicon.ico" -}}
+
+{{- if (eq .Page.Kind "section") -}}
+ {{- $title = $author.name -}}
+ {{- $description = $author.description | markdownify | html | htmlUnescape -}}
+ {{- $image = print "/" (partial "function-paths.html").media "/" .Section "/" .Section "-profile" (path.Ext $author.picture.profile) -}}
+{{- end -}}
+
+{{- if (eq .Page.Type "tags") -}}
+ {{- $title = print "#" (lower .Title) " -- " .Site.Title | markdownify | htmlUnescape -}}
+ {{- $description = print .Site.Title " Tags: #" .Title -}}
{{- end -}}
-{{- print "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
-{{- print "<?xml-stylesheet href=\"/rss.xsl\" type=\"text/xsl\"?>" | safeHTML }}
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
+{{- $atomSelf := "" -}}
+{{- $atomPrevious := "" -}}
+{{- $atomNext := "" -}}
+
+{{- with .OutputFormats.Get "RSS" -}}
+ {{- $atomSelf = printf `<atom:link rel="self" href=%q type=%q />` .Permalink .MediaType | safeHTML -}}
+
+ {{- with $.Paginator.Prev -}}
+ {{- $atomPrevious = printf `<atom:link rel="previous" href=%q />` (.URL | absURL) | safeHTML -}}
+ {{- end -}}
+
+ {{- with $.Paginator.Next -}}
+ {{- $atomNext = printf `<atom:link rel="next" href=%q />` (.URL | absURL) | safeHTML -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $filteredPages := partial "function-filters-content.html" .Paginator.Pages -}}
+
+{{- printf `<?xml version="1.0" encoding="utf-8" standalone="yes"?>` | safeHTML }}
+{{ printf `<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>` | safeHTML }}
+
+<rss
+ version="2.0"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+>
<channel>
- <title>{{ partial "site-title" . }}</title>
+ <title>{{ or $title (title .Section) }}</title>
<link>{{ .Permalink }}</link>
- <description>Recent from {{ partial "site-title" . }}</description>
+ <description>{{ $description }}</description>
<language>{{ .Site.LanguageCode }}</language>
- <category>{{ partial "author-user" . }}</category>
+ <category>{{ or $author.user "default" }}</category>
+ <generator>Hugo {{ hugo.Version }}</generator>
+ <lastBuildDate>{{ $lastBuildDate }}</lastBuildDate>
<image>
- <title>{{ partial "site-title" . }}</title>
- <url>{{ .Site.BaseURL }}/{{ partial "author-media-path.html" . }}/profile/picture.png</url>
+ <title>{{ $title }}</title>
+ <url>{{ $absURL }}{{ $image }}</url>
<link>{{ .Permalink }}</link>
</image>
- {{ if not .Date.IsZero -}}
- <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
- {{ with .OutputFormats.Get "RSS" }}
- {{- printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML -}}
- {{ end }}
- {{- range $pages -}}
- {{ if and (not .Params.Unlisted) (not .ExpiryDate) }}
+
+ {{ $atomSelf }}
+ {{ $atomPrevious }}
+ {{ $atomNext }}
+
+ {{ range first $limit $filteredPages -}}
+
+ {{- $author = partial "function-authors-data.html" . -}}
+
+ {{- $image = print "/" (partial "function-paths.html").media
+ "/" $author.user "/" $author.user "-profile" (path.Ext $author.picture.profile)
+ -}}
+
+ {{- $atomAuthorUri := print $absURL $image -}}
+ {{- $atomAuthorName := or .Params.Feed.name $author.name -}}
+
+ {{- if .Params.Feed.favicon -}}
+ {{- $favicon := print "/" (partial "function-paths.html").media "/favicon." (.Params.Feed.source | anchorize) ".png" -}}
+ {{- $atomAuthorUri = print $absURL $favicon -}}
+ {{- end -}}
+
<item>
- <title>{{ .Summary | htmlUnescape }}</title>
- <link>{{ .Permalink }}</link>
- <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
+ <title>{{ (or .Summary .Title) | htmlUnescape }}</title>
+ <link>{{ or .Params.Feed.link .Permalink }}</link>
+ <pubDate>{{ .Date | time.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
<guid>{{ .Permalink }}</guid>
- <description>{{ .Content | html }}</description>
+ <description>
+ {{ partial "function-content.html" . | html -}}
+ {{- print "<br /><br />" | html -}}
+ {{- printf `<a href=%q>Permalink</a>&nbsp;` .Permalink | html }}
+ {{ partial "tags.html" (dict "Format" "rss" "Context" .) | html }}
+ </description>
+ <atom:author>
+ <atom:name>{{ $atomAuthorName }}</atom:name>
+ <atom:uri>{{ $atomAuthorUri }}</atom:uri>
+ </atom:author>
</item>
- {{ end }}
- {{ end }}
+
+ {{ end -}}
</channel>
</rss>
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.drafts.html b/themes/default/layouts/_default/section.drafts.html
new file mode 100644
index 0000000..bb7485c
--- /dev/null
+++ b/themes/default/layouts/_default/section.drafts.html
@@ -0,0 +1,58 @@
+{{- define "styles" -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $author = $author.user -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
+
+ tab-bar a[href^="{{ "" | absURL }}/{{ $author }}/drafts"] {
+ color: #111;
+ color: var(--foreground);
+ font-weight: 700;
+ text-decoration-color: #014cc6;
+ text-decoration-color: var(--link);
+ text-decoration: underline;
+ border-bottom: 2px solid var(--background);
+ }
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ {{- $authors := where .Site.RegularPages "Section" $author.user -}}
+ {{- $drafts := where .Site.RegularPages "Draft" true -}}
+ {{- $filteredPages := $authors | intersect $drafts -}}
+ {{- $paginator := .Paginate $filteredPages -}}
+
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Drafts"
+ "Icon" "arrow-left"
+ "Subtitle" (print (partial "count-drafts.html" .) " " "Total")
+ "Href" (or (and (gt $paginator.PageNumber 1) ($paginator.Paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+
+ {{- partial "profile.html" . -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.feeds.html b/themes/default/layouts/_default/section.feeds.html
new file mode 100644
index 0000000..e239928
--- /dev/null
+++ b/themes/default/layouts/_default/section.feeds.html
@@ -0,0 +1,53 @@
+{{- define "styles" -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $author = $author.user -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
+
+ tab-bar a[href^="{{ "" | absURL }}/{{ $author }}/feeds"] {
+ color: #111;
+ color: var(--foreground);
+ font-weight: 700;
+ text-decoration-color: #014cc6;
+ text-decoration-color: var(--link);
+ text-decoration: underline;
+ border-bottom: 2px solid var(--background);
+ }
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Feeds"
+ "Icon" "arrow-left"
+ "Subtitle" (print (partial "count-feeds.html" .) " " "Total")
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+
+ {{- partial "profile.html" . -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+ {{- $writeToFile := partial "function-generate-feeds" . -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.following.html b/themes/default/layouts/_default/section.following.html
new file mode 100644
index 0000000..2bfcc2e
--- /dev/null
+++ b/themes/default/layouts/_default/section.following.html
@@ -0,0 +1,75 @@
+{{- $parent := eq (len .Page.Ancestors) 1 -}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if (and $parent $modified) -}}
+ {{- $sources := slice -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ {{- $feeds := partial "function-generate-feeds.html" . -}}
+
+ {{- range $author.feeds.rss -}}
+ {{- $data := split . " " -}}
+ {{- $url := delimit (first 1 $data) "" -}}
+ {{- $sources = $sources | append (string $url) -}}
+ {{- end -}}
+
+ {{- range $source := $sources -}}
+ {{- range $distinct := first 1 (where $feeds "FeedSourceLink" "eq" $source) -}}
+
+ {{- $href := or $distinct.FeedHome (print "http://" $distinct.FeedSourceDomain) -}}
+ {{- $favicon := print "/" (partial "function-paths.html").media "/favicon." (.FeedSourceLink | anchorize) ".png" -}}
+
+ <micro-author>
+ <micro-card>
+ <header>
+ <figure>
+ <a
+ title="{{ $distinct.FeedName }}"
+ href="{{ $href }}">
+ <picture>
+ <img
+ width="64"
+ height="64"
+ alt="{{ $distinct.FeedName }}"
+ src="{{ $.Site.BaseURL }}{{ $favicon }}"
+ />
+ </picture>
+ </a>
+ </figure>
+ </header>
+ <article>
+ <h2>
+ <b>{{ $distinct.FeedName }}</b>
+ </h2>
+ <h3>
+ <a
+ data-hover
+ title="{{ $distinct.FeedName }}"
+ href="{{ $href }}">
+ @{{ $distinct.FeedSourceDomain }}
+ </a>
+ </h3>
+ <time
+ data-type="default"
+ title="{{ $distinct.FeedDateTitle }}"
+ datetime="{{ $distinct.FeedDateTime }}">
+ {{ $distinct.FeedDate -}}
+ </time>
+ </article>
+ <a
+ title="Follow {{ $distinct.FeedName }}"
+ href="{{ $href }}">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/rss.svg")) }}
+ <span>Feed</span>
+ </a>
+ </micro-card>
+ </micro-author>
+
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.gallery.html b/themes/default/layouts/_default/section.gallery.html
new file mode 100644
index 0000000..761a276
--- /dev/null
+++ b/themes/default/layouts/_default/section.gallery.html
@@ -0,0 +1,12 @@
+{{- $parent := eq (len .Page.Ancestors) 1 -}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if (and $parent $modified) -}}
+ {{- partial "gallery-walk.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.html b/themes/default/layouts/_default/section.html
index 2708e89..901ca1f 100644
--- a/themes/default/layouts/_default/section.html
+++ b/themes/default/layouts/_default/section.html
@@ -1,50 +1,56 @@
-{{ define "styles" }}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
- tab-list a[href="{{ .CurrentSection.Permalink }}"],
- tab-list a[href="{{ strings.TrimRight "/" .CurrentSection.Permalink }}"] {
+ tab-bar a[href="{{ .CurrentSection.Permalink }}"],
+ tab-bar a[href^="{{ .CurrentSection.Permalink }}#"],
+ tab-bar a[href="{{ strings.TrimRight "/" .CurrentSection.Permalink }}"] {
color: #111;
color: var(--foreground);
- display: inherit;
font-weight: 700;
text-decoration-color: #014cc6;
text-decoration-color: var(--link);
text-decoration: underline;
+ border-bottom: 2px solid var(--background);
}
</style>
-{{ end }}
+{{- end -}}
-{{ define "middle" }}
+{{- define "header" -}}
+ {{- $author := partial "function-authors-data.html" . -}}
- {{- $messages := print (lang.FormatNumberCustom 0 .Paginator.TotalNumberOfElements) " " "Messages" -}}
-
- {{ partial "navigator-middle.html"
+ {{- partial "navigator-middle.html"
(dict
- "Title" (partial "author-name.html" .)
- "Subtitle" $messages
- "Icon" "arrow-left"
+ "Context" .
"IconLabel" "Back"
- "Href" "/"
"Id" "back"
- "Context" .
+ "Title" $author.name
+ "Icon" "arrow-left"
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
+ "Subtitle" (print (lang.FormatNumberCustom 0 .Paginator.TotalNumberOfElements) " " "Total")
)
- }}
-
- {{ partial "profile.html" . }}
-
- {{ range .Paginator.Pages }}
- {{ .Render "summary" }}
- {{ else }}
- <footer>
- <code>No messages found!</code>
- </footer>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
+ -}}
+
+ {{- partial "author-section-picture.html" . -}}
+
+ {{- partial "profile.html" . -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.marks.html b/themes/default/layouts/_default/section.marks.html
new file mode 100644
index 0000000..def6c94
--- /dev/null
+++ b/themes/default/layouts/_default/section.marks.html
@@ -0,0 +1,58 @@
+{{- define "styles" -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $author = $author.user -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
+
+ tab-bar a[href^="{{ "" | absURL }}/{{ $author }}/marks"] {
+ color: #111;
+ color: var(--foreground);
+ font-weight: 700;
+ text-decoration-color: #014cc6;
+ text-decoration-color: var(--link);
+ text-decoration: underline;
+ border-bottom: 2px solid var(--background);
+ }
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ {{- $authors := where .Site.RegularPages "Section" $author.user -}}
+ {{- $items := where .Site.RegularPages ".Params.marked" true -}}
+ {{- $filteredPages := $authors | intersect $items -}}
+ {{- $paginator := .Paginate $filteredPages -}}
+
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Marks"
+ "Icon" "arrow-left"
+ "Subtitle" (print (partial "count-marks.html" .) " " "Total")
+ "Href" (or (and (gt $paginator.PageNumber 1) ($paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+
+ {{- partial "profile.html" . -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+{{- end -}}
+
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.media.html b/themes/default/layouts/_default/section.media.html
new file mode 100644
index 0000000..ce570c7
--- /dev/null
+++ b/themes/default/layouts/_default/section.media.html
@@ -0,0 +1,65 @@
+{{- define "styles" -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $author = $author.user -}}
+<style>
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
+
+ tab-bar a[href^="{{ "" | absURL }}/{{ $author }}/media"] {
+ color: #111;
+ color: var(--foreground);
+ font-weight: 700;
+ text-decoration-color: #014cc6;
+ text-decoration-color: var(--link);
+ text-decoration: underline;
+ border-bottom: 2px solid var(--background);
+ }
+</style>
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Title" "Media"
+ "Subtitle" (print (partial "count-media.html" .) " " "Total")
+ "Icon" "arrow-left"
+ "IconLabel" "Back"
+ "Href" "/"
+ "Id" "back"
+ "Context" .
+ )
+ -}}
+
+ {{- partial "profile.html" . -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ {{- $notFeeds := where .Site.RegularPages "Params.feed" "eq" nil -}}
+ {{- $authors := where .Site.RegularPages "Section" $author.user -}}
+ {{- $filteredPages := $authors | intersect $notFeeds -}}
+ {{- $count := 0 -}}
+
+ {{- range first 100 $filteredPages -}}
+ {{- if eq $count 10 -}}
+ {{- break -}}
+ {{- end -}}
+ {{- if or
+ (in .Content "</video>")
+ (in .Content "</picture>")
+ (in .Content "</youtube-video>")
+ -}}
+ {{- partial "render-embed.html" . -}}
+ {{- $count = add $count 1 -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- if not $count -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/section.webring.html b/themes/default/layouts/_default/section.webring.html
new file mode 100644
index 0000000..58181e1
--- /dev/null
+++ b/themes/default/layouts/_default/section.webring.html
@@ -0,0 +1,66 @@
+{{- $parent := eq (len .Page.Ancestors) 1 -}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" .
+ "Disable" true
+ )
+-}}
+
+{{- if (and $parent $modified) -}}
+ {{- $items := slice -}}
+ {{- $sources := slice -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ {{- $feeds := partial "function-generate-feeds.html" . -}}
+
+ {{- range $author.feeds.rss -}}
+ {{- $data := split . " " -}}
+ {{- $url := delimit (first 1 $data) "" -}}
+ {{- $sources = $sources | append (string $url) -}}
+ {{- end -}}
+
+ {{- $inner := 1 -}}
+
+ {{- if eq (len $sources) 1 -}}
+ {{- $inner = 3 -}}
+ {{- end -}}
+
+ {{- range $source := (first 3 $sources) -}}
+ {{- range $distinct := first $inner (where $feeds "FeedSourceLink" "eq" $source) -}}
+ {{- $items = $items | append $distinct -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- range (sort $items "FeedDateTime" "desc") -}}
+ <article>
+ <h2>
+ <a
+ data-hover
+ title="{{ .FeedLink }}"
+ href="{{ .FeedLink }}">
+ {{ or .FeedTitle (truncate 50 "..." (or .FeedContentShort .FeedDescriptionShort)) }}
+ </a>
+ </h2>
+ <p>
+ {{ if gt (len .FeedDescriptionShort) (len .FeedContentShort) -}}
+ {{ or .FeedDescriptionShort .FeedTitle }}
+ {{- else -}}
+ {{ or .FeedContentShort .FeedTitle }}
+ {{- end }}
+ <br />
+ <a
+ data-hover
+ title="{{ .FeedSourceDescription }}"
+ href="{{ or .FeedSourceHome .FeedSourceLink }}">
+ {{ .FeedSourceTitle }}
+ </a>
+ </p>
+ <time
+ data-type="default"
+ title="{{ .FeedDateTitle }}"
+ datetime="{{ .FeedDateTime }}">
+ {{ .FeedDate }}
+ </time>
+ </article>
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/single.embed.html b/themes/default/layouts/_default/single.embed.html
new file mode 100644
index 0000000..73a3add
--- /dev/null
+++ b/themes/default/layouts/_default/single.embed.html
@@ -0,0 +1,26 @@
+{{- $pageContext := . -}}
+{{- $format := "embed.html" -}}
+
+{{- $page := print "public/" (strings.TrimPrefix
+ $pageContext.Page.Site.BaseURL
+ $pageContext.Page.Permalink
+ ) $format
+-}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" $pageContext
+ "Format" $format
+ )
+-}}
+
+{{- with $embed := resources.Get $page -}}
+ {{- if (in $embed.Content "/data/media/404.png") -}}
+ {{- $modified = true -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if $modified -}}
+ {{- partial "head-embed.html" . -}}
+ {{- .Render "summary" -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/single.html b/themes/default/layouts/_default/single.html
index a32ae01..f3123b3 100644
--- a/themes/default/layouts/_default/single.html
+++ b/themes/default/layouts/_default/single.html
@@ -1,28 +1,81 @@
-{{ define "styles" }}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/") | safeCSS }}
</style>
-{{ end }}
-
-{{ define "middle" }}
-
-{{ partial "navigator-middle.html"
- (dict
- "Title" "Message"
- "Subtitle" "Single"
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
-}}
-
-<micro-thread>
- {{ .Render "summary" }}
-</micro-thread>
-{{ end }}
-
-{{ define "right" }}
- {{- partial "navigator-right.html" . -}}
-{{ end }}
+{{- end -}}
+
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Title" "Post"
+ "Subtitle" "Thread"
+ "Icon" "arrow-left"
+ "IconLabel" "Back"
+ "Href" "/"
+ "Id" "back"
+ "Context" .
+ )
+ -}}
+{{- end -}}
+
+{{- define "middle" -}}
+ <micro-thread>
+ {{- partial "render-embed.html" . -}}
+
+ {{- $prevHref := "/" -}}
+ {{- $nextHref := "/" -}}
+ {{- $prevTitle := "hidden" -}}
+ {{- $nextTitle := "hidden" -}}
+
+ {{- with .Next -}}
+ {{- $nextHref = $.Next.Permalink -}}
+ {{- $nextTitle = $.Next.Summary -}}
+ {{- end -}}
+
+ {{- with .Prev -}}
+ {{- $prevHref = $.Prev.Permalink -}}
+ {{- $prevTitle = $.Prev.Summary -}}
+ {{- end -}}
+
+ {{- with or .Next .Prev -}}
+ <nav data-type="pagination">
+ <a rel="next" href="{{ $nextHref }}" title="{{ $nextTitle }}">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-left.svg")) }}
+ <header>Newer</header>
+ </a>
+
+ <a rel="prev" href="{{ $prevHref }}" title="{{ $prevTitle }}">
+ <header>Older</header>
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-right.svg")) }}
+ </a>
+ </nav>
+ {{- end -}}
+
+ {{- $filteredPages := partial "function-filters-content.html" (.Site.RegularPages.Related .) -}}
+ {{- $related := $filteredPages | first 3 -}}
+
+ {{- with $related -}}
+ <related-content>
+ <footer>
+ <samp>
+ Related Tags
+ {{- with $.Params.tags -}}
+ {{- range $tag := first 1 $.Params.tags -}}
+ {{- $link := print ("tags/" | relURL) ($tag | urlize) "/" }}
+ {{ print "---" " " "[#" $tag "](" $link ")" | markdownify -}}
+ {{- end -}}
+ {{- end -}}
+ </samp>
+ </footer>
+ </related-content>
+
+ {{- range $related -}}
+ {{- partial "render-embed.html" . -}}
+ {{- end -}}
+ {{- end -}}
+ </micro-thread>
+{{- end -}}
+
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/single.plain.txt b/themes/default/layouts/_default/single.plain.txt
new file mode 100644
index 0000000..f46e495
--- /dev/null
+++ b/themes/default/layouts/_default/single.plain.txt
@@ -0,0 +1,3 @@
+{{- define "main" -}}
+ {{- partial "function-content.html" . | plainify | htmlUnescape -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/sitemap.xml b/themes/default/layouts/_default/sitemap.xml
index 63f5119..f8ab315 100644
--- a/themes/default/layouts/_default/sitemap.xml
+++ b/themes/default/layouts/_default/sitemap.xml
@@ -1,22 +1,48 @@
-{{ printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
-<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
- xmlns:xhtml="http://www.w3.org/1999/xhtml">
- {{ range .Data.Pages }}
- <url>
- <loc>{{ .Permalink }}</loc>{{ if not .Lastmod.IsZero }}
- <lastmod>{{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}</lastmod>{{ end }}{{ with .Sitemap.ChangeFreq }}
- <changefreq>{{ . }}</changefreq>{{ end }}{{ if ge .Sitemap.Priority 0.0 }}
- <priority>{{ .Sitemap.Priority }}</priority>{{ end }}{{ if .IsTranslated }}{{ range .Translations }}
- <xhtml:link
- rel="alternate"
- hreflang="{{ .Language.Lang }}"
- href="{{ .Permalink }}"
- />{{ end }}
- <xhtml:link
- rel="alternate"
- hreflang="{{ .Language.Lang }}"
- href="{{ .Permalink }}"
- />{{ end }}
- </url>
+{{- printf `<?xml version="1.0" encoding="utf-8" standalone="yes"?>` | safeHTML }}
+{{ printf `<?xml-stylesheet href="/sitemap.xsl" type="text/xsl"?>` | safeHTML }}
+
+{{- $changefreq := "weekly" -}}
+{{- $priority := 0.5 -}}
+{{- $lastmod := now | time.Format "2006-01-02T15:04:05-07:00" }}
+
+<urlset
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+>
+ {{- $filteredPages := partial "function-filters-content.html" .Data.Pages.ByDate.Reverse -}}
+ {{- range $filteredPages }}
+
+ {{- with .Sitemap.ChangeFreq -}}
+ {{- $changefreq = . -}}
+ {{- end -}}
+
+ {{- if ge .Sitemap.Priority 0.0 -}}
+ {{- $priority = .Sitemap.Priority -}}
+ {{- end -}}
+
+ {{- if not .Lastmod.IsZero -}}
+ {{- $lastmod = safeHTML (.Lastmod | time.Format "2006-01-02T15:04:05-07:00") -}}
+ {{- end }}
+
+ <url>
+ <loc>{{ .Permalink }}</loc>
+ <lastmod>{{ $lastmod }}</lastmod>
+ <changefreq>{{ $changefreq }}</changefreq>
+ <priority>{{ $priority }}</priority>
+ {{- if .IsTranslated -}}
+ {{ range .Translations }}
+ <xhtml:link
+ rel="alternate"
+ hreflang="{{ .Language.Lang }}"
+ href="{{ .Permalink }}"
+ />
+ {{- end -}}
+ <xhtml:link
+ rel="alternate"
+ hreflang="{{ .Language.Lang }}"
+ href="{{ .Permalink }}"
+ />
+ {{ end }}
+ </url>
{{ end }}
</urlset>
diff --git a/themes/default/layouts/_default/summary.html b/themes/default/layouts/_default/summary.html
index 4e47898..e820b24 100644
--- a/themes/default/layouts/_default/summary.html
+++ b/themes/default/layouts/_default/summary.html
@@ -1,35 +1,22 @@
-<micro-card {{ if .Weight }}pinned{{ end }} id="{{ partial "card-id.html" . }}">
- {{ if .ExpiryDate }}<micro-expires>{{ end }}
- <micro-summary {{ if .Draft }}draft{{ end }} title="{{- partial "title.html" . -}}">
- <micro-thumbnail>
- {{ partial "profile-picture.html" . }}
- </micro-thumbnail>
- <micro-content>
- <micro-metadata>
- {{ partial "card-meta.html" . }}
- </micro-metadata>
- {{ if .Params.unsafe }}
- <micro-unsafe>
- <details>
- <summary>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/alert-circle.svg")) }}
- <span>Danger: Unsafe Content. <b><u>Click here</u></b> to show/hide</span>
- </summary>
- </details>
- <micro-unsafe-content>
- {{ end }}
- {{-
- .Content |
- replaceRE "<p>\n<figure>" "<figure>" |
- replaceRE "</figure></p>" "</figure>" |
- safeHTML
- -}}
- {{ if .Params.unsafe }}
- </micro-unsafe-content>
- </micro-unsafe>
- {{ end }}
- <micro-tags>{{ partial "tags.html" . }}</micro-tags>
- </micro-content>
- </micro-summary>
- {{ if .ExpiryDate }}</micro-expires>{{ end }}
+{{- $href := or .Params.Feed.link .Permalink -}}
+{{- $content := partial "function-content.html" . | safeHTML -}}
+{{- $expired := and .ExpiryDate (ge now.Unix .ExpiryDate.Unix) -}}
+
+<micro-card
+ id="{{ partial "card-id.html" . }}"
+ {{ if .Weight }}pinned{{ end }}
+ {{ if .Draft }}draft{{ end }}
+ {{ if .ExpiryDate }}data-expires{{ end }}
+>
+ <a href="{{ $href }}"></a>
+ <header>
+ {{ partial "profile-picture.html" . }}
+ {{ partial "card-meta-header.html" . }}
+ </header>
+ <article aria-label="article">
+ {{- $content -}}
+ <micro-tags>
+ {{- partial "tags.html" (dict "Format" "page" "Context" .) -}}
+ </micro-tags>
+ </article>
</micro-card>
diff --git a/themes/default/layouts/_default/taxonomy.html b/themes/default/layouts/_default/taxonomy.html
index 97b9bd1..5c8e2ba 100644
--- a/themes/default/layouts/_default/taxonomy.html
+++ b/themes/default/layouts/_default/taxonomy.html
@@ -1,62 +1,71 @@
-{{ define "styles" }}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/tags/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/tags/") | safeCSS }}
</style>
-{{ end }}
+{{- end -}}
-{{ define "middle" }}
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
+ (dict
+ "Context" .
+ "IconLabel" "Back"
+ "Id" "back"
+ "Title" "Tags"
+ "Icon" "arrow-left"
+ "Subtitle" (print (partial "count-tags.html" .) " " "Total")
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
+ )
+ -}}
+{{- end -}}
- {{ $title := .Title }}
+{{- define "middle" -}}
+ <tag-deck>
+ {{- range .Paginator.Pages -}}
+ {{- $count := lang.FormatNumberCustom 0 (len .Data.Pages) -}}
+ {{- $title := lower .Title -}}
- {{ if eq .Title "Tags" }}
-
- {{ partial "navigator-middle.html"
- (dict
- "Title" "Tags"
- "Subtitle" (partial "count-tags.html" .)
- "Icon" "arrow-left"
- "IconLabel" "Back"
- "Href" "/"
- "Id" "back"
- "Context" .
- )
- }}
-
- {{- $page := 1 -}}
- {{- $count := 0 -}}
-
- {{ range .Paginator.Pages }}
- {{ $title := lower .Title }}
- <item-list>
- <h1><a href="{{ .Site.BaseURL }}/tags/{{ $title }}">#{{ .Title }}</a></h1>
- <ul>
- {{ range .Pages }}
- {{- $count = add $count 1 -}}
- <li>
- <a
- title="{{ partial "title.html" . }}"
- href="{{ .Site.BaseURL }}/tags/{{ $title }}/{{ if gt $page 1 }}page/{{ $page }}/{{ end }}#{{ partial "card-id.html" . }}">
- <span><code>{{ .Date.Format "02 Jan 2006" }}</code></span>
- <span>{{ partial "title.html" . }}</span>
- <span>@{{ partial "author-user.html" . }}</span>
+ {{- range first 1 .Pages -}}
+ {{- $author := partial "function-authors-data.html" . -}}
+ <tag-card>
+ <article>
+ <h2>
+ <code>
+ {{ $count }} in
+ <a data-hover href="{{ "" | absURL }}/tags/{{ $title }}/">
+ #{{ $title }}
+ </a>
+ </code>
+ </h2>
+ <figure>
+ <a href="{{ print ("" | absURL) "/tags/" $title "/#" (partial "card-id.html" .) }}">
+ <picture>
+ {{ partial "author-picture" . }}
+ </picture>
</a>
- </li>
- {{ if eq (mod $count $.Paginator.PageSize) 0 }}
- {{ $page = add $page 1 }}
- {{- end -}}
- {{- end -}}
- {{- $page = 1 -}}
- {{- $count = 0 -}}
- </ul>
- </item-list>
- {{ end }}
-
- {{ partial "pagination.html" . }}
-
- {{ end }}
+ </figure>
+ <time
+ datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
+ title="{{ .Date | time.Format "Posted: Monday, January 2, 2006 at 15:04:05 MST" }}"
+ >
+ {{ .Date | time.Format "02 Jan 2006" }}
+ </time>
+ <p>
+ <a data-hover href="{{ print ("" | absURL) "/tags/" $title "/#" (partial "card-id.html" .) }}">
+ {{ partial "meta-title.html" . }}
+ </a>
+ </p>
+ </article>
+ </tag-card>
+ {{- end -}}
+ {{- end -}}
+ </tag-deck>
+{{- end -}}
-{{ end }}
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/_default/term.html b/themes/default/layouts/_default/term.html
index 8f31575..4f0d92a 100644
--- a/themes/default/layouts/_default/term.html
+++ b/themes/default/layouts/_default/term.html
@@ -1,33 +1,34 @@
-{{ define "styles" }}
+{{- define "styles" -}}
<style>
- {{ partial "styles-navigator.html" (dict "Link" "/tags/") | safeCSS }}
+ {{ partial "navigator.css.html" (dict "Link" "/tags/") | safeCSS }}
</style>
-{{ end }}
+{{- end -}}
-{{ define "middle" }}
-
- {{- $terms := print (lang.FormatNumberCustom 0 (len .Data.Pages)) " " "Messages" -}}
-
- {{ partial "navigator-middle.html"
+{{- define "header" -}}
+ {{- partial "navigator-middle.html"
(dict
- "Title" (print "#" .Title)
- "Subtitle" $terms
- "Icon" "arrow-left"
+ "Context" .
"IconLabel" "Back"
- "Href" "/"
"Id" "back"
- "Context" .
+ "Icon" "arrow-left"
+ "Title" (print "#" .Title)
+ "Subtitle" (print (lang.FormatNumberCustom 0 (len .Data.Pages)) " " "Total")
+ "Href" (or (and (gt .Paginator.PageNumber 1) (.Paginator.Prev.URL | absURL)) "/")
)
- }}
-
- {{ range .Paginator.Pages }}
- {{ .Render "summary" }}
- {{ end }}
+ -}}
+{{- end -}}
- {{ partial "pagination.html" . }}
+{{- define "middle" -}}
+ {{- range .Paginator.Pages -}}
+ {{- partial "render-embed.html" . -}}
+ {{- end -}}
+{{- end -}}
-{{ end }}
+{{- define "footer" -}}
+ {{- partial "pagination.html" . -}}
+ {{- partial "footer.html" . -}}
+{{- end -}}
-{{ define "right" }}
- {{- partial "navigator-right-default.html" . -}}
-{{ end }}
+{{- define "right" -}}
+ {{- partial "navigator-right.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/archive-link.html b/themes/default/layouts/partials/archive-link.html
deleted file mode 100644
index 8b08ba3..0000000
--- a/themes/default/layouts/partials/archive-link.html
+++ /dev/null
@@ -1,2 +0,0 @@
-/archives/{{ .Type }}/
-{{- /* Strip newline. */ -}}
diff --git a/themes/default/layouts/partials/author-card.html b/themes/default/layouts/partials/author-card.html
index 3e4bcca..561fef3 100644
--- a/themes/default/layouts/partials/author-card.html
+++ b/themes/default/layouts/partials/author-card.html
@@ -1,46 +1,81 @@
-{{- $path := print "public/" .Data.user "/media/profile/picture.png" -}}
-{{- $image := resources.Get $path -}}
-{{- $dimensions := "96x96" -}}
-{{- $404image := resources.Get "data/media/404.png" -}}
+{{- $metadata := print "public/" .Data.user "/author.json" -}}
+{{- $date := .Date | time.Format "Mon Jan 2 2006" -}}
+
+{{- $host := (urls.Parse ("" | absURL)).Host -}}
+
+{{- if not $host -}}
+ {{- $host = "localhost" -}}
+{{- end -}}
+
+{{- $alternate := .Data.name -}}
+{{- $width := "" -}}
+{{- $height := "" -}}
+{{- $source := "" -}}
+{{- $sourceset := "" -}}
+
+{{- $source = print "/" (partial "function-paths.html").media "/" .Data.user "/" .Data.user "-profile" (path.Ext .Data.picture.profile) -}}
+{{- $sourceset = print "/" (partial "function-paths.html").media "/" .Data.user "/" .Data.user "-profile.webp" -}}
+
+{{- with $metadata := resources.Get $metadata -}}
+ {{- with $content := $metadata.Content -}}
+ {{- $metadata = $content | transform.Unmarshal -}}
+ {{- $width = $metadata.picture.profileWidth -}}
+ {{- $height = $metadata.picture.profileHeight -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if or
+ (not (path.Ext .Data.picture.profile))
+ (not (fileExists (print "public/" (partial "function-paths.html").media "/" .Data.user)))
+-}}
+ {{- $source = "/data/media/404.png" -}}
+ {{- $sourceset = "" -}}
+{{- end -}}
+
+{{- if not .Date -}}
+ {{- $date = "Inactive" -}}
+{{- end -}}
<micro-author>
<micro-card>
- <micro-summary>
- <micro-thumbnail>
+ <header>
<figure>
- <a title="{{ .Data.name }}" href="{{ "" | absURL }}/{{ .Data.user }}/#">
+ <a title="{{ .Data.name }}" href="{{ "" | absURL }}/{{ .Data.user }}/">
<picture>
- {{- with $image }}
- {{- $image = .Content | resources.FromString (print (partial "function-paths-media.html") "/" $.Data.user "/" (path.Base .)) }}
- <source srcset="{{- ($image.Fit (print $dimensions " webp")).RelPermalink -}}" type="image/webp" />
- {{- end }}
+ {{- with $sourceset -}}
+ <source srcset="{{ print ("" | absURL) $sourceset }}" type="image/webp" />
+ {{- end -}}
<img
- alt="{{ .Data.name }}"
- {{- if fileExists $path }}
- {{ with $image }}
- {{- $image = (.Content | resources.FromString (print (partial "function-paths-media.html") "/" $.Data.user "/" (path.Base .))).Fit $dimensions -}}
- width="{{ $image.Width }}"
- height="{{ $image.Height }}"
- src="{{ $image.RelPermalink }}"
- {{- end }}
- {{ else }}
- width="{{ $404image.Width }}"
- height="{{ $404image.Height }}"
- src="{{ $404image.RelPermalink }}"
- {{- end -}}
+ width="{{ or $width "64" }}"
+ height="{{ or $height "64" }}"
+ src="{{ print ("" | absURL) $source }}"
+ alt="{{ $alternate }}"
/>
</picture>
</a>
</figure>
- </micro-thumbnail>
- <micro-header>
- <h2><b>{{ .Data.name }}</b></h2>
- <h3><a title="{{ .Data.name }}" href="{{ "" | absURL }}/{{ .Data.user }}/#">@{{ .Data.user }}</a></h3>
- </micro-header>
- <a title="Follow with RSS Reader" href="{{ "" | absURL }}/{{ .Data.user }}/rss.xml">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/rss.svg")) }}
- <span>Follow</span>
- </a>
- </micro-summary>
+ </header>
+ <article>
+ <h2>
+ <b>{{ .Data.name }}</b>
+ </h2>
+ <h3>
+ <a data-hover="" title="{{ .Data.name }}" href="{{ "" | absURL }}/{{ .Data.user }}/">
+ {{ .Data.user }}@{{ $host }}
+ </a>
+ </h3>
+ <time
+ data-type="default"
+ title="{{ .Date | time.Format "Monday January 2 2006 at 15:04:05 MST" }}"
+ datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
+ >
+ {{ $date }}
+ </time>
+ </article>
+ <p>{{ .Data.description | markdownify | plainify | htmlUnescape | truncate 60 "..." }}</p>
+ <a title="Follow with RSS Reader" href="{{ "" | absURL }}/{{ .Data.user }}/rss.xml">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/rss.svg")) }}
+ <span>Feed</span>
+ </a>
</micro-card>
</micro-author>
diff --git a/themes/default/layouts/partials/author-domain-host.html b/themes/default/layouts/partials/author-domain-host.html
index 5396642..d182751 100644
--- a/themes/default/layouts/partials/author-domain-host.html
+++ b/themes/default/layouts/partials/author-domain-host.html
@@ -1,2 +1,3 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") }}
+{{- $author := partial "function-authors-data.html" . -}}
+
{{- $author.domain.host | markdownify -}}
diff --git a/themes/default/layouts/partials/author-header.html b/themes/default/layouts/partials/author-header.html
index 9babf1d..5bcc0e6 100644
--- a/themes/default/layouts/partials/author-header.html
+++ b/themes/default/layouts/partials/author-header.html
@@ -1,30 +1,30 @@
-{{- $file := "/profile/header.jpg" -}}
-{{- $path := print "public/" (partial "author-media-path.html" .) $file -}}
-{{- $image := resources.Get $path -}}
-{{- $404image := resources.Get "data/media/404.png" -}}
-{{- $dimensions := "x600" -}}
-{{- $author := partial "author-user.html" . }}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $header := $author.picture.header -}}
+{{- $file := not (urls.Parse $header).Host -}}
-{{- with $image -}}
- {{- $image = .Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .)) -}}
- <source srcset="{{- ($image.Resize (print $dimensions " webp")).RelPermalink -}}" type="image/webp" />
+{{- if $file -}}
+ {{- $header = print $author.user "/" $header -}}
+{{- end -}}
+
+{{- $image := partial "function-caches-images.html"
+ (dict
+ "Context" .
+ "Source" $header
+ "Resize" "x600"
+ "Target" (print (partial "function-paths.html").media "/" $author.user "/")
+ "Copy" (print (partial "function-paths.html").media "/" $author.user "/" (path.Base $header))
+ "AlternateCopy" (print (partial "function-paths.html").media "/" $author.user "/" (path.BaseName $header) ".webp")
+ )
+-}}
+
+{{- with $image.AltRelPermalink -}}
+ <source srcset="{{ . }}" type="image/webp" />
{{- end -}}
<img
- {{ if fileExists $path }}
- {{- with $image -}}
- {{- $image = (.Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .))).Resize $dimensions -}}
width="{{ $image.Width }}"
height="{{ $image.Height }}"
src="{{ $image.RelPermalink }}"
- {{- else -}}
- src="{{ .Site.BaseURL }}/{{ partial "author-media-path.html" . }}{{ $file }}"
- {{ end }}
- {{- else -}}
- width="{{ $404image.Width }}"
- height="{{ $404image.Height }}"
- src="{{ $404image.RelPermalink }}"
- {{- end }}
- alt="{{ partial "author-name.html" . }}"
+ alt="{{ $author.name }}"
/>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/author-list.html b/themes/default/layouts/partials/author-list.html
index bfeaa16..619b1b3 100644
--- a/themes/default/layouts/partials/author-list.html
+++ b/themes/default/layouts/partials/author-list.html
@@ -1,14 +1,18 @@
-{{ $authors := slice }}
-{{ range $index, $data := .Site.Data -}}
- {{- $authors = $authors | append $data.user -}}
-{{- end -}}
+{{- $authors := print "public/authors.html" -}}
<author-list>
- <h1>Authors</h1>
- <section>
- {{- range $author := first 3 (shuffle (uniq $authors)) -}}
- {{ $data := index $.Site.Data $author | default "default" }}
- {{ partial "author-card.html" (dict "Data" $data) }}
- {{ end }}
- </section>
+ <h1>
+ <a data-hover href="{{ "" | absURL }}/authors/">
+ Authors
+ </a>
+ </h1>
+ <aside>
+ {{- with $authors = resources.Get $authors -}}
+ {{- $authors.Content | safeHTML -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+ </aside>
</author-list>
diff --git a/themes/default/layouts/partials/author-media-path.html b/themes/default/layouts/partials/author-media-path.html
deleted file mode 100644
index 77090ea..0000000
--- a/themes/default/layouts/partials/author-media-path.html
+++ /dev/null
@@ -1,2 +0,0 @@
-{{ partial "author-user.html" . }}/media
-{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/author-name.html b/themes/default/layouts/partials/author-name.html
deleted file mode 100644
index a4424e4..0000000
--- a/themes/default/layouts/partials/author-name.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{{- $author := .Data.Author -}}
-
-{{- with $author -}}
-{{- else -}}
- {{- $author = index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-{{- end -}}
-
-{{- $author.name | markdownify -}}
diff --git a/themes/default/layouts/partials/author-picture.html b/themes/default/layouts/partials/author-picture.html
index c269efc..01786e7 100644
--- a/themes/default/layouts/partials/author-picture.html
+++ b/themes/default/layouts/partials/author-picture.html
@@ -1,41 +1,49 @@
-{{- $file := "/profile/picture.png" -}}
-{{- $path := print "public/" (partial "author-media-path.html" .) $file -}}
-{{- $image := resources.Get $path -}}
-{{- $404image := resources.Get "data/media/404.png" -}}
-{{- $dimensions := "160x160" -}}
-{{- $author := partial "author-user.html" . }}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $metadata := print "public/" $author.user "/author.json" -}}
-{{- with .Params.feed -}}
+{{- $alternate := $author.name -}}
+{{- $width := "" -}}
+{{- $height := "" -}}
+{{- $source := "" -}}
+{{- $sourceset := "" -}}
+
+{{- with .Params.feed.favicon -}}
+ {{- $alternate = $.Params.feed.name -}}
+ {{- $width = "64" -}}
+ {{- $height = "64" -}}
+ {{- $source = print "/" (partial "function-paths.html").media "/favicon." ($.Params.feed.source | anchorize) ".png" -}}
+ {{- if not (fileExists (print "public/" $source)) -}}
+ {{- $source = $.Params.feed.favicon -}}
+ {{- end -}}
+ {{- $sourceset = "" -}}
{{- else -}}
- {{- with $image -}}
- {{- $image = .Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .)) -}}
- <source srcset="{{- ($image.Fit (print $dimensions " webp")).RelPermalink -}}" type="image/webp" />
+ {{- $source = print "/" (partial "function-paths.html").media "/" $author.user "/" $author.user "-profile" (path.Ext $author.picture.profile) -}}
+ {{- $sourceset = print "/" (partial "function-paths.html").media "/" $author.user "/" $author.user "-profile.webp" -}}
+ {{- with $metadata := resources.Get $metadata -}}
+ {{- with $content := $metadata.Content -}}
+ {{- $metadata = $content | transform.Unmarshal -}}
+ {{- $width = $metadata.picture.profileWidth -}}
+ {{- $height = $metadata.picture.profileHeight -}}
{{- end -}}
-{{ end }}
+ {{- else -}}
+ {{- $source = "/data/media/404.png" -}}
+ {{- $sourceset = "" -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if not (path.Ext $author.picture.profile) -}}
+ {{- $source = "/data/media/404.png" -}}
+ {{- $sourceset = "" -}}
+{{- end -}}
+
+{{- with $sourceset -}}
+<source srcset="{{ print ("" | absURL) $sourceset }}" type="image/webp" />
+{{- end -}}
<img
- loading="lazy"
- {{- with .Params.feed }}
- width="64"
- height="64"
- alt="{{ .name }}"
- src="{{ .image }}"
- {{ else }}
- {{ if fileExists $path }}
- {{- with $image -}}
- {{- $image = (.Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/" (path.Base .))).Fit $dimensions -}}
- width="{{ $image.Width }}"
- height="{{ $image.Height }}"
- src="{{ $image.RelPermalink }}"
- {{ else -}}
- src="{{ .Site.BaseURL }}/{{ partial "author-media-path.html" . }}{{ $file }}"
- {{ end }}
- {{- else -}}
- width="{{ $404image.Width }}"
- height="{{ $404image.Height }}"
- src="{{ $404image.RelPermalink }}"
- {{- end }}
- alt="{{ partial "author-name.html" . }}"
- {{ end -}}
+ width="{{ $width }}"
+ height="{{ $height }}"
+ src="{{ print ("" | absURL) $source }}"
+ alt="{{ $alternate }}"
/>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/author-section-picture.html b/themes/default/layouts/partials/author-section-picture.html
new file mode 100644
index 0000000..de0806b
--- /dev/null
+++ b/themes/default/layouts/partials/author-section-picture.html
@@ -0,0 +1,38 @@
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $profile := $author.picture.profile -}}
+{{- $file := not (urls.Parse $profile).Host -}}
+
+{{- if $file -}}
+ {{- $profile = print $author.user "/" $profile -}}
+{{- end -}}
+
+{{- $image := partial "function-caches-images.html"
+ (dict
+ "Context" .
+ "Source" $profile
+ "Fit" "160x160"
+ "Target" (print (partial "function-paths.html").media "/" $author.user "/")
+ "Copy" (print (partial "function-paths.html").media "/" $author.user "/" $author.user "-profile" (path.Ext $profile))
+ "AlternateCopy" (print (partial "function-paths.html").media "/" $author.user "/" $author.user "-profile.webp")
+ )
+-}}
+
+{{- $width := $image.Width -}}
+{{- $height := $image.Height -}}
+{{- $source := $image.RelPermalink -}}
+{{- $alternate := $author.name -}}
+{{- $sourceset := $image.AltRelPermalink -}}
+
+{{- $metadata := (dict
+ "picture" (dict
+ "profileWidth" $width
+ "profileHeight" $height
+ "profileSource" $source
+ "profileAlternate" $alternate
+ "profileSourceSet" $sourceset
+ )
+ )
+-}}
+
+{{- $authorMetadata := merge $author $metadata | jsonify | resources.FromString (print .Section "/author.json") -}}
+{{- $writeToFile := $authorMetadata.Permalink -}}
diff --git a/themes/default/layouts/partials/author-user.html b/themes/default/layouts/partials/author-user.html
deleted file mode 100644
index 797610b..0000000
--- a/themes/default/layouts/partials/author-user.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{{- $author := .Data.Author -}}
-
-{{- with $author -}}
-{{- else -}}
- {{- $author = index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-{{- end -}}
-
-{{- $author.user | markdownify -}}
diff --git a/themes/default/layouts/partials/card-id.html b/themes/default/layouts/partials/card-id.html
index abaf5be..5f92697 100644
--- a/themes/default/layouts/partials/card-id.html
+++ b/themes/default/layouts/partials/card-id.html
@@ -1,7 +1,6 @@
-{{- $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-{{- $source := print $author.user "/messages/" .File.LogicalName -}}
-{{- $source = replace (lower (humanize $source | truncate 50 "")) " " "-" -}}
-{{ if .ExpiryDate }}
- {{- $source = md5 $source -}}
-{{ end }}
+{{- $relURL := strings.TrimPrefix .Page.Site.BaseURL .Page.Permalink -}}
+{{- $source := urlize (humanize $relURL) -}}
+{{- if .ExpiryDate -}}
+ {{- $source = truncate 8 "" (sha256 $source) -}}
+{{- end -}}
{{- $source -}}
diff --git a/themes/default/layouts/partials/card-meta-header.html b/themes/default/layouts/partials/card-meta-header.html
new file mode 100644
index 0000000..72b67b8
--- /dev/null
+++ b/themes/default/layouts/partials/card-meta-header.html
@@ -0,0 +1,25 @@
+<meta-data>
+
+ {{- partial "meta-anchored.html" . -}}
+
+ {{- partial "meta-name.html" . -}}
+
+ {{- partial "meta-draft.html" . -}}
+
+ {{- partial "meta-unlisted.html" . -}}
+
+ {{- partial "meta-handle.html" . -}}
+
+ {{- partial "meta-datetime.html" . -}}
+
+ {{- partial "meta-view.html" . -}}
+
+ {{- partial "meta-menu.html" . -}}
+
+ {{- partial "meta-wordcount.html" . -}}
+
+ {{- partial "meta-readtime.html" . -}}
+
+ {{- partial "meta-expirydate.html" . -}}
+
+</meta-data>
diff --git a/themes/default/layouts/partials/card-meta.html b/themes/default/layouts/partials/card-meta.html
deleted file mode 100644
index 4359586..0000000
--- a/themes/default/layouts/partials/card-meta.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<micro-thumbnail hidden>
- {{ partial "profile-picture.html" . }}
-</micro-thumbnail>
-
-<section>
- {{ if or .Weight .Params.Liked .Params.feed }}
- <anchored-entry>
- {{- if .Params.feed -}}
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/rss.svg")) }}
- <a data-hover
- title="{{ partial "author-user.html" . }}@{{ (urls.Parse .Site.BaseURL).Host }}"
- href="{{ .Site.BaseURL }}/{{ partial "author-user.html" . }}/feeds/#">
- via @{{ partial "author-user.html" . }}
- </a>
- {{- end -}}
-
- {{ if .Weight }}
- <anchored-pinned>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/tabler/pinned.svg")) }}
- </anchored-pinned>
- <span>Pinned</span>
- {{ end }}
-
- {{ if .Params.Liked }}
- <anchored-liked>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/heart.svg")) }}
- </anchored-liked>
- <span>Liked</span>
- {{ end }}
-
- </anchored-entry>
- {{ end }}
-
- {{- partial "meta-name.html" . -}}
-
- &middot; {{ partial "meta-handle.html" . }}
-
- {{ if .Draft }}
- &middot; {{ partial "meta-draft" . -}}
- {{ end }}
-
- &middot; {{- partial "meta-read-time.html" . -}}
-
- &middot; {{- partial "meta-word-count.html" . -}}
-
- {{ if .Params.Unlisted }}
- &middot; <unlisted-entry title="This message is off the record">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/eye-off.svg")) }}
- <span>unlisted</span></unlisted-entry>
- {{ end }}
-
- &middot; {{- partial "meta-date-time.html" . -}}
-
- {{- if .ExpiryDate -}}
- &middot; {{- partial "meta-expiry-date.html" . -}}
- {{- end -}}
-
- &middot; <cite><a title="#{{ partial "card-id.html" . }}" href="#{{ partial "card-id.html" . }}">#id</a></cite>
-
- {{ if not .ExpiryDate }}
- &middot; {{ partial "meta-source.html" . -}}
- {{- end -}}
-</section>
diff --git a/themes/default/layouts/partials/context-menu.html b/themes/default/layouts/partials/context-menu.html
deleted file mode 100644
index 40e0001..0000000
--- a/themes/default/layouts/partials/context-menu.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<input type="checkbox" id="context-menu-{{ .Name }}" />
-<label for="context-menu-{{ .Name }}">{{ .Label }}</label>
-
-<context-menu>{{ .Content }}</context-menu>
diff --git a/themes/default/layouts/partials/context-profile.html b/themes/default/layouts/partials/context-profile.html
index c64e4a2..5150128 100644
--- a/themes/default/layouts/partials/context-profile.html
+++ b/themes/default/layouts/partials/context-profile.html
@@ -1,35 +1,34 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") }}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $description := or .Params.feed.description ($author.description | markdownify) -}}
+{{- $name := or .Params.feed.name $author.name -}}
+{{- $host := or (urls.Parse .Site.BaseURL).Host "localhost" -}}
+{{- $author := .Section -}}
+{{- $href := print ("" | absURL) "/" $author "/" -}}
+{{- $title := print $author "@" $host -}}
+
+{{- with .Params.feed -}}
+ {{- $host = $.Params.feed.domain -}}
+ {{- $href = or $.Params.feed.home (print "http://" $.Params.feed.domain) -}}
+ {{- $title = $.Params.feed.domain -}}
+{{- end -}}
<context-profile>
<context-menu>
<div>
<aside>
<figure>
- {{- with .Params.feed.name -}}
- <a title="{{ . }}" href="http://{{ $.Params.feed.domain }}">
- {{- else -}}
- <a title="{{ $author.name }}" href="{{ .Site.BaseURL }}/{{ $author.user }}/#">
- {{- end -}}
+ <a title="{{ $name }}" href="{{ $href }}">
<picture>
- {{ partial "author-picture" . }}
+ {{ partial "author-picture" . }}
</picture>
</a>
</figure>
</aside>
<aside>
- {{- with .Params.feed.name -}}
- <h2>{{ . }}</h2>
- <p>@{{ $.Params.feed.domain }}</p>
- {{- else -}}
- <h2>{{ $author.name }}</h2>
- <p>@{{ $author.user }}</p>
- {{- end -}}
+ <h2>{{ $name }}</h2>
+ <p>@{{ $host }}</p>
</aside>
</div>
- {{- with .Params.feed.description -}}
- <p>{{ . }}</p>
- {{- else -}}
- <p>{{- $author.description | markdownify -}}</p>
- {{- end -}}
+ <p>{{ $description }}</p>
</context-menu>
</context-profile>
diff --git a/themes/default/layouts/partials/count-authors.html b/themes/default/layouts/partials/count-authors.html
index 00655a0..8f2d7ef 100644
--- a/themes/default/layouts/partials/count-authors.html
+++ b/themes/default/layouts/partials/count-authors.html
@@ -1,7 +1,2 @@
-{{- $authors := slice -}}
-
-{{- range $index, $data := .Site.Data -}}
- {{- $authors = $authors | append $data.name -}}
-{{- end -}}
-
-{{- print (lang.FormatNumberCustom 0 (len (uniq $authors))) " " "Authors" -}}
+{{- $authors := partial "function-authors-slice.html" . -}}
+{{- print (lang.FormatNumberCustom 0 (len $authors)) -}}
diff --git a/themes/default/layouts/partials/count-drafts.html b/themes/default/layouts/partials/count-drafts.html
index 78b57a5..fae0b90 100644
--- a/themes/default/layouts/partials/count-drafts.html
+++ b/themes/default/layouts/partials/count-drafts.html
@@ -1,10 +1,7 @@
-{{ $author := partial "author-user.html" . }}
-{{ $count := 0 }}
+{{- $author := .Section -}}
-{{ range .Site.Pages }}
- {{ if and (eq .Type $author) .Draft }}
- {{ $count = add $count 1 }}
- {{ end }}
-{{ end }}
+{{- $authors := where .Site.RegularPages "Section" $author -}}
+{{- $drafts := where .Site.RegularPages "Draft" true -}}
+{{- $filteredPages := $authors | intersect $drafts -}}
-{{ print (lang.FormatNumberCustom 0 $count) " " "Drafts" }}
+{{- print (lang.FormatNumberCustom 0 (len $filteredPages)) -}}
diff --git a/themes/default/layouts/partials/count-feeds.html b/themes/default/layouts/partials/count-feeds.html
index cf54180..68495da 100644
--- a/themes/default/layouts/partials/count-feeds.html
+++ b/themes/default/layouts/partials/count-feeds.html
@@ -1,12 +1,7 @@
-{{ $author := partial "author-user.html" . }}
-{{ $count := 0 }}
+{{- $author := .Section -}}
-{{ range .Site.Pages }}
- {{ if .Params.feed }}
- {{ if eq .Type $author }}
- {{ $count = add $count 1 }}
- {{ end }}
- {{ end }}
-{{ end }}
+{{- $feeds := where .Site.Pages "Params.feed" "ne" nil -}}
+{{- $authors := where .Site.Pages "Section" $author -}}
+{{- $filteredPages := $authors | intersect $feeds -}}
-{{ print (lang.FormatNumberCustom 0 $count) " " "Messages" }}
+{{- print (lang.FormatNumberCustom 0 (len $filteredPages)) -}}
diff --git a/themes/default/layouts/partials/count-likes.html b/themes/default/layouts/partials/count-likes.html
deleted file mode 100644
index a808576..0000000
--- a/themes/default/layouts/partials/count-likes.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{{ $author := partial "author-user.html" . }}
-{{ $count := 0 }}
-
-{{ range .Site.Pages }}
- {{ if and (eq .Type $author) .Params.Liked }}
- {{ $count = add $count 1 }}
- {{ end }}
-{{ end }}
-
-{{ print (lang.FormatNumberCustom 0 $count) " " "Messages" }}
diff --git a/themes/default/layouts/partials/count-marks.html b/themes/default/layouts/partials/count-marks.html
new file mode 100644
index 0000000..deb532d
--- /dev/null
+++ b/themes/default/layouts/partials/count-marks.html
@@ -0,0 +1,6 @@
+{{- $author := .Section -}}
+{{- $items := where .Site.RegularPages ".Params.marked" true -}}
+{{- $authors := where .Site.RegularPages "Section" $author -}}
+{{- $filteredPages := $authors | intersect $items -}}
+
+{{- print (lang.FormatNumberCustom 0 (len $filteredPages)) -}}
diff --git a/themes/default/layouts/partials/count-media.html b/themes/default/layouts/partials/count-media.html
index 1d5e49b..1d68e0a 100644
--- a/themes/default/layouts/partials/count-media.html
+++ b/themes/default/layouts/partials/count-media.html
@@ -1,17 +1,20 @@
-{{ $author := partial "author-user.html" . }}
-{{ $count := 0 }}
+{{- $author := .Section -}}
+{{- $notFeeds := where .Site.RegularPages "Params.feed" "eq" nil -}}
+{{- $authors := where .Site.RegularPages "Section" $author -}}
+{{- $filteredPages := $authors | intersect $notFeeds -}}
+{{- $count := 0 -}}
-{{ range .Site.Pages }}
- {{ if or
- (in .Content "<figure>")
- (in .Content "<imgur-video>")
- (in .Content "<youtube-video>")
- (in .Content "<video-container>")
- }}
- {{ if eq .Type $author }}
- {{ $count = add $count 1 }}
- {{ end }}
- {{ end }}
-{{ end }}
+{{- range first 100 $filteredPages -}}
+ {{- if eq $count 10 -}}
+ {{- break -}}
+ {{- end -}}
+ {{- if or
+ (in .Content "</video>")
+ (in .Content "</picture>")
+ (in .Content "</youtube-video>")
+ -}}
+ {{- $count = add $count 1 -}}
+ {{- end -}}
+{{- end -}}
-{{ print (lang.FormatNumberCustom 0 $count) " " "Messages" }}
+{{- print (lang.FormatNumberCustom 0 $count) -}}
diff --git a/themes/default/layouts/partials/count-tags.html b/themes/default/layouts/partials/count-tags.html
index 0ef6802..6d436c6 100644
--- a/themes/default/layouts/partials/count-tags.html
+++ b/themes/default/layouts/partials/count-tags.html
@@ -1 +1 @@
-{{- print (lang.FormatNumberCustom 0 (len .Site.Taxonomies.tags)) " " "Tags" -}}
+{{- print (lang.FormatNumberCustom 0 (len .Site.Taxonomies.tags)) -}}
diff --git a/themes/default/layouts/partials/count-total-messages.html b/themes/default/layouts/partials/count-total-messages.html
deleted file mode 100644
index 10540a7..0000000
--- a/themes/default/layouts/partials/count-total-messages.html
+++ /dev/null
@@ -1,2 +0,0 @@
-{{ $messages := len .Site.RegularPages }}
-{{ print (lang.FormatNumberCustom 0 $messages) " " "Messages" }}
diff --git a/themes/default/layouts/partials/count.html b/themes/default/layouts/partials/count.html
new file mode 100644
index 0000000..72b5d03
--- /dev/null
+++ b/themes/default/layouts/partials/count.html
@@ -0,0 +1 @@
+{{- print (lang.FormatNumberCustom 0 (len .Site.RegularPages)) -}}
diff --git a/themes/default/layouts/partials/following-list.html b/themes/default/layouts/partials/following-list.html
new file mode 100644
index 0000000..510d3d2
--- /dev/null
+++ b/themes/default/layouts/partials/following-list.html
@@ -0,0 +1,31 @@
+{{- $count := 0 -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $feeds := print "public/" .Section "/following.html" -}}
+
+{{- with $items := $author.feeds.rss -}}
+ {{- $count = len $items -}}
+{{- end -}}
+
+{{- $expand := cond (gt $count 3) "more" "less" -}}
+
+<following-list>
+ <details
+ id="web-feeds"
+ data-expand="{{- $expand -}}"
+ >
+ <summary>
+ <h1>Web Feeds ({{ $count }})</h1>
+ </summary>
+ </details>
+ <aside>
+ {{- if and $author.feeds.rss (fileExists $feeds) -}}
+ {{- with $feeds = resources.Get $feeds -}}
+ {{- $feeds.Content | safeHTML -}}
+ {{- end -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+ </aside>
+</following-list>
diff --git a/themes/default/layouts/partials/footer.html b/themes/default/layouts/partials/footer.html
index 6cac939..54d6ab1 100644
--- a/themes/default/layouts/partials/footer.html
+++ b/themes/default/layouts/partials/footer.html
@@ -1,12 +1,14 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.footer) | default "default") }}
+{{- $kind := in (slice "home" "taxonomy" "term") .Page.Kind -}}
+{{- $author := index .Site.Data.authors .Section -}}
<footer>
- {{- with .Site.Author.footer -}}
- {{ if $.IsHome -}}
- {{ . | markdownify }}
- {{- else -}}
- {{ $author.blogtitle }}
+ {{- if $kind -}}
+ {{- with $footer := (and $kind .Site.Author.default.footer) -}}
+ {{ $footer | markdownify }} &middot;
+ Copyright &copy; {{ now | time.Format "2006"}} &middot;
{{- end -}}
+ {{- else -}}
+ {{ or $author.footer $author.title | markdownify }} &middot;
{{- end }}
- | Copyright &copy; {{ now.Format "2006"}}
+ <a href="/sitemap.xml" >Site Map</a>
</footer>
diff --git a/themes/default/layouts/partials/function-authors-data.html b/themes/default/layouts/partials/function-authors-data.html
new file mode 100644
index 0000000..dbc2c67
--- /dev/null
+++ b/themes/default/layouts/partials/function-authors-data.html
@@ -0,0 +1,9 @@
+{{- $input := . -}}
+
+{{- $pageContext := $input -}}
+
+{{- $author := $pageContext.Section -}}
+
+{{- $output := index $pageContext.Site.Data.authors $author -}}
+
+{{- return $output -}}
diff --git a/themes/default/layouts/partials/function-authors-slice.html b/themes/default/layouts/partials/function-authors-slice.html
new file mode 100644
index 0000000..fc25554
--- /dev/null
+++ b/themes/default/layouts/partials/function-authors-slice.html
@@ -0,0 +1,9 @@
+{{- $authors := slice -}}
+
+{{- range $user := .Site.Author.list -}}
+ {{- with $author := index $.Site.Data.authors $user -}}
+ {{- $authors = $authors | append $author.user -}}
+ {{- end -}}
+{{- end -}}
+
+{{- return (uniq $authors) -}}
diff --git a/themes/default/layouts/partials/function-caches-images.html b/themes/default/layouts/partials/function-caches-images.html
new file mode 100644
index 0000000..c99103b
--- /dev/null
+++ b/themes/default/layouts/partials/function-caches-images.html
@@ -0,0 +1,109 @@
+{{- $pageContext := .Context -}}
+{{- $data := dict -}}
+{{- $source := or .Source "nil" -}}
+{{- $fit := .Fit -}}
+{{- $resize := .Resize -}}
+{{- $target := or .Target "/" -}}
+{{- $copy := .Copy -}}
+{{- $directory := path.Dir $copy -}}
+{{- $basename := path.BaseName $copy -}}
+{{- $type := strings.TrimPrefix "." (path.Ext $copy) -}}
+{{- $alternateCopy := or .AlternateCopy (print $directory "/" $basename ".webp") -}}
+{{- $alternateType := strings.TrimPrefix "." (path.Ext $alternateCopy) -}}
+{{- $isFile := ne (path.Base $copy) "." -}}
+{{- $cached := and $isFile (fileExists (print "public/" $copy)) (fileExists (print "public/" $alternateCopy)) -}}
+{{- $local := print "public/" $source -}}
+{{- $localized := fileExists $local -}}
+
+{{- with $404image := resources.Get "data/media/404.png" -}}
+ {{- $404image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{-
+ $data = (dict
+ "Width" $404image.Width
+ "Height" $404image.Height
+ "Permalink" $404image.Permalink
+ "RelPermalink" $404image.RelPermalink
+ )
+ -}}
+{{- end -}}
+
+{{- if $cached -}}
+ {{- with $image := resources.Get (print "public/" $copy) -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{-
+ $data = (dict
+ "Width" $image.Width
+ "Height" $image.Height
+ "Permalink" $image.Permalink
+ "RelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- $image = resources.Get (print "public/" $alternateCopy) -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base $image)) -}}
+ {{-
+ $data = merge $data (dict
+ "AltPermalink" $image.Permalink
+ "AltRelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- end -}}
+{{- else -}}
+ {{- with $image := cond (default true $pageContext.Site.Params.site.offline) false (resources.GetRemote $source) -}}
+ {{- with .Err -}}
+ {{- if $localized -}}
+ {{- $directory := path.Dir $local -}}
+ {{- $basename := path.BaseName $local -}}
+ {{- $type := strings.TrimPrefix "." (path.Ext $local) -}}
+ {{- with $image := resources.Get $local -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{- with $fit -}} {{- $image = $image.Fit (print $fit " " $type) -}} {{- end -}}
+ {{- with $resize -}} {{- $image = $image.Resize (print $resize " " $type) -}} {{- end -}}
+ {{- $image = $image | resources.Copy $copy -}}
+ {{-
+ $data = (dict
+ "Width" $image.Width
+ "Height" $image.Height
+ "Permalink" $image.Permalink
+ "RelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{- with $fit -}} {{- $image = $image.Fit (print $fit " " $alternateType) -}} {{- end -}}
+ {{- with $resize -}} {{- $image = $image.Resize (print $resize " " $alternateType) -}} {{- end -}}
+ {{- $image = $image | resources.Copy $alternateCopy -}}
+ {{-
+ $data = merge $data (dict
+ "AltPermalink" $image.Permalink
+ "AltRelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- end -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{- with $fit -}} {{- $image = $image.Fit (print $fit " " $type) -}} {{- end -}}
+ {{- with $resize -}} {{- $image = $image.Resize (print $resize " " $type) -}} {{- end -}}
+ {{- $image = $image | resources.Copy $copy -}}
+ {{-
+ $data = (dict
+ "Width" $image.Width
+ "Height" $image.Height
+ "Permalink" $image.Permalink
+ "RelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- $image = .Content | resources.FromString (print $target (path.Base .)) -}}
+ {{- with $fit -}} {{- $image = $image.Fit (print $fit " " $alternateType) -}} {{- end -}}
+ {{- with $resize -}} {{- $image = $image.Resize (print $resize " " $alternateType) -}} {{- end -}}
+ {{- $image = $image | resources.Copy $alternateCopy -}}
+ {{-
+ $data = merge $data (dict
+ "AltPermalink" $image.Permalink
+ "AltRelPermalink" $image.RelPermalink
+ )
+ -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
+
+{{- return $data -}}
diff --git a/themes/default/layouts/partials/function-content.html b/themes/default/layouts/partials/function-content.html
new file mode 100644
index 0000000..19c15ea
--- /dev/null
+++ b/themes/default/layouts/partials/function-content.html
@@ -0,0 +1,23 @@
+{{- $pageContext := . -}}
+{{- $content := $pageContext.Content -}}
+{{- $expired := and .ExpiryDate (ge now.Unix .ExpiryDate.Unix) -}}
+
+{{- $brokenBlockquotes := findRE `(?sU)</blockquote>\n<p>(&ndash;|&mdash;).*</p>` .Content -}}
+
+{{- range $brokenBlockquote := $brokenBlockquotes -}}
+ {{- $fixedBlockquote := $brokenBlockquote |
+ replaceRE "</blockquote>\n<p>" "<footer><cite>" |
+ replaceRE "</p>" "</cite></footer></blockquote>" |
+ -}}
+ {{- $content = replace $content $brokenBlockquote $fixedBlockquote -}}
+{{- end -}}
+
+{{- if not $content -}}
+ {{- $content = "This message contains no content." -}}
+{{- end -}}
+
+{{- if $expired -}}
+ {{- $content = "This message has expired." -}}
+{{- end -}}
+
+{{- return $content -}}
diff --git a/themes/default/layouts/partials/function-favicon-domain.html b/themes/default/layouts/partials/function-favicon-domain.html
new file mode 100644
index 0000000..3814304
--- /dev/null
+++ b/themes/default/layouts/partials/function-favicon-domain.html
@@ -0,0 +1,11 @@
+{{- $input := . -}}
+
+{{- $output :=
+ (print
+ "https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&size=64&url="
+ "http://"
+ $input
+ )
+-}}
+
+{{- return $output -}}
diff --git a/themes/default/layouts/partials/function-fetch-favicons.html b/themes/default/layouts/partials/function-fetch-favicons.html
new file mode 100644
index 0000000..facde2f
--- /dev/null
+++ b/themes/default/layouts/partials/function-fetch-favicons.html
@@ -0,0 +1,15 @@
+{{- $source := .Source -}}
+{{- $infix := .Infix -}}
+{{- $pageContext := .Context -}}
+
+{{- $output := partial "function-caches-images.html"
+ (dict
+ "Context" $pageContext
+ "Source" $source
+ "Fit" "160x160"
+ "Target" (print (partial "function-paths.html").media "/")
+ "Copy" (print (partial "function-paths.html").media "/favicon." $infix ".png")
+ )
+-}}
+
+{{- return $output -}}
diff --git a/themes/default/layouts/partials/function-filters-content.html b/themes/default/layouts/partials/function-filters-content.html
new file mode 100644
index 0000000..8ebad51
--- /dev/null
+++ b/themes/default/layouts/partials/function-filters-content.html
@@ -0,0 +1,10 @@
+{{- $input := . -}}
+
+{{- $notExpired := where $input "Params.expirydate" "eq" nil -}}
+{{- $notUnlisted := where $input "Params.unlisted" "eq" nil -}}
+
+{{- $filteredPages := $notExpired | intersect $notUnlisted -}}
+
+{{- $output := $filteredPages -}}
+
+{{- return $output -}}
diff --git a/themes/default/layouts/partials/function-generate-feeds.html b/themes/default/layouts/partials/function-generate-feeds.html
new file mode 100644
index 0000000..57789b5
--- /dev/null
+++ b/themes/default/layouts/partials/function-generate-feeds.html
@@ -0,0 +1,245 @@
+{{- $author := partial "function-authors-data.html" . -}}
+
+{{- $feeds := slice -}}
+
+{{- if $author.feeds.rss -}}
+ {{- range $key, $value := (seq 3) -}}
+ {{- range $author.feeds.rss -}}
+
+ {{- $data := split . " " -}}
+ {{- $url := delimit (first 1 $data) "" -}}
+ {{- $retitle := trim (delimit (after 1 $data) " ") " " -}}
+
+ {{- with $fetch := cond (default true $.Site.Params.site.offline) false (resources.GetRemote $url) -}}
+
+ {{- with $error := .Err -}}
+ {{- warnf "Feed fetch %s" $error -}}
+ {{- else -}}
+
+ {{- with $fetch | transform.Unmarshal -}}
+
+ {{- $content := "" -}}
+ {{- $date := now | time.Format "2006-01-02T15:04:05Z" -}}
+ {{- $description := "" -}}
+ {{- $enclosure := "" -}}
+ {{- $imageLink := "" -}}
+ {{- $link := "https://example.com/link/" -}}
+ {{- $sourceDescription := "" -}}
+ {{- $sourceHome := "" -}}
+ {{- $sourceLink := $url -}}
+ {{- $sourceTitle := "No source title found" -}}
+ {{- $title := "No Title Found" -}}
+
+ {{- with .channel -}}
+
+ {{- $sourceTitle = .title -}}
+ {{- $sourceDescription = .description -}}
+
+ {{- if reflect.IsSlice .link -}}
+ {{- if reflect.IsMap (index .link 0) -}}
+ {{- $sourceHome = index (last 1 .link) 0 -}}
+ {{- else -}}
+ {{- $sourceHome = index .link 0 -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .image -}}
+ {{- $imageLink = .url -}}
+ {{- end -}}
+
+ {{- with .item -}}
+ {{- if reflect.IsMap . -}}
+ {{- $title = index . "title" -}}
+ {{- $link = index . "link" -}}
+ {{- $date = index . "pubDate" -}}
+ {{- else -}}
+ {{- range first $value . -}}
+ {{- $description = .description -}}
+ {{- $content = .description -}}
+ {{- $title = .title -}}
+ {{- $link = .link -}}
+ {{- $date = .pubDate -}}
+ {{- with .enclosure -}}
+ {{- $enclosure = index . "-url" -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- if not $date -}}
+ {{- $date = .lastBuildDate -}}
+ {{- end -}}
+
+ {{- else -}}
+
+ {{- with .author -}}
+ {{- if reflect.IsMap . -}}
+ {{- $sourceHome = .uri -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .subtitle -}}
+ {{- if reflect.IsMap . -}}
+ {{- $sourceDescription = index . "#text" -}}
+ {{- else -}}
+ {{- $sourceDescription = . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .title -}}
+ {{- if reflect.IsMap . -}}
+ {{- $sourceTitle = index . "#text" -}}
+ {{- else -}}
+ {{- $sourceTitle = . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .entry -}}
+ {{- range first $value . -}}
+ {{- $date = .updated -}}
+
+ {{- with .link -}}
+ {{- if reflect.IsMap . -}}
+ {{- $link = index . "-href" -}}
+ {{- else -}}
+ {{- if reflect.IsMap (index . 0) -}}
+ {{- $link = index (index . 0) "-href" -}}
+ {{- else -}}
+ {{- $link = . -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .title -}}
+ {{- if reflect.IsMap . -}}
+ {{- $title = index . "#text" -}}
+ {{- else -}}
+ {{- $title = . -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- with .content -}}
+ {{- $content = index . "#text" -}}
+ {{- end -}}
+
+ {{- with .summary -}}
+ {{- $description = index . "#text" -}}
+ {{- end -}}
+
+ {{- with .group -}}
+ {{- $description = .description -}}
+ {{- $content = index .content "#text" -}}
+ {{- $enclosure = index .thumbnail "-url" -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- end -}}
+
+ {{- $sourceDomain := ($sourceLink | plainify | htmlUnescape | urls.Parse).Host -}}
+
+ {{- /* Replace invalid time zones. */ -}}
+ {{- $date = replaceRE "G[0-9]+T" "UTC" $date -}}
+
+ {{- /* If missing seconds split and try again. */ -}}
+ {{- if lt (len (split $date ":")) 3 -}}
+ {{- $date = delimit (first 3 (after 1 (split $date " "))) " " -}}
+ {{- end -}}
+
+ {{- /* Try to complete enclosure relative links. */ -}}
+ {{- if and (not ($enclosure | urls.Parse).Host) (not ($link | urls.Parse).Host) -}}
+ {{- $enclosure = print "http://" $sourceDomain $link -}}
+ {{- end -}}
+
+ {{- /* Try to complete link relative links. */ -}}
+ {{- if not ($link | urls.Parse).Host -}}
+ {{- $link = print "http://" $sourceDomain $link -}}
+ {{- end -}}
+
+ {{-
+ $feeds = $feeds | append (dict
+ "FeedContent" ($content | plainify | htmlUnescape)
+ "FeedContentShort" (delimit (first 2 (split ($content | plainify | htmlUnescape) "\n")) " " | truncate 250 "...")
+ "FeedDate" ($date | plainify | htmlUnescape | time.Format "Mon Jan 2 2006")
+ "FeedDateTime" ($date | plainify | htmlUnescape | time.Format "2006-01-02T15:04:05Z")
+ "FeedDateTitle" ($date | plainify | htmlUnescape | time.Format "Monday January 2 2006 at 15:04:05 MST")
+ "FeedDescription" ($description | plainify | htmlUnescape)
+ "FeedDescriptionShort" (delimit (first 2 (split ($description | plainify | htmlUnescape) "\n")) " " | truncate 250 "...")
+ "FeedEnclosure" ($enclosure | plainify | htmlUnescape)
+ "FeedImageLink" ($imageLink | plainify | htmlUnescape)
+ "FeedLink" ($link | plainify | htmlUnescape)
+ "FeedName" (or $retitle (delimit (first 2 (split ($sourceTitle | plainify | htmlUnescape) " ")) " "))
+ "FeedSourceDescription" ($sourceDescription | plainify | htmlUnescape)
+ "FeedSourceDomain" ($sourceDomain | plainify | htmlUnescape)
+ "FeedSourceLink" ($sourceLink | plainify | htmlUnescape)
+ "FeedSourceHome" ($sourceHome | plainify | htmlUnescape)
+ "FeedSourceTitle" ($sourceTitle | plainify | htmlUnescape)
+ "FeedTitle" ($title | plainify | htmlUnescape)
+ )
+ -}}
+
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+ {{- range $feeds -}}
+
+ {{- $name := .FeedName -}}
+ {{- $domain := .FeedSourceDomain -}}
+
+ {{- $favicon := partial "function-favicon-domain.html" $domain -}}
+
+ {{- with .FeedImageLink -}}
+ {{- $favicon = . -}}
+ {{- end -}}
+
+ {{- $imageSource := partial "function-fetch-favicons.html"
+ (dict
+ "Context" $.Page
+ "Source" $favicon
+ "Infix" (.FeedSourceLink | anchorize)
+ )
+ -}}
+
+ {{- $template := resources.Get "templates/markdown-feed.yaml" -}}
+ {{- $alias := truncate 255 "" (delimit (first 8 (split (.FeedTitle | urlize) "-")) "-" | humanize | urlize) -}}
+ {{- $hash := .FeedLink | sha256 | truncate 8 "" -}}
+ {{- $file := print $alias "-" $hash -}}
+ {{- $file = partial "function-strip-filechars.html" $file -}}
+ {{- $path := print "/data/generates/content/" $author.user "/feeds/" $file ".md" -}}
+
+ {{- $content := .FeedContentShort -}}
+
+ {{- if (gt (len .FeedTitle) (len $content)) -}}
+ {{- $content = .FeedTitle -}}
+ {{- end -}}
+
+ {{- if (gt (len .FeedDescriptionShort) (len .FeedTitle)) -}}
+ {{- $content = .FeedDescriptionShort -}}
+ {{- end -}}
+
+ {{- $markdown := resources.ExecuteAsTemplate
+ $path
+ (dict
+ "author" $author.user
+ "content" (or $content "No content found.")
+ "date" .FeedDateTime
+ "description" (or .FeedSourceDescription .FeedSourceTitle "No source description found.")
+ "domain" .FeedSourceDomain
+ "enclosure" .FeedEnclosure
+ "favicon" (strings.TrimPrefix ("" | absURL) $imageSource.Permalink)
+ "home" .FeedSourceHome
+ "link" .FeedLink
+ "name" .FeedName
+ "source" .FeedSourceLink
+ "tags" "[feeds]"
+ )
+ $template
+ -}}
+ {{- $writeToFile := $markdown.Permalink -}}
+ {{- end -}}
+{{- end -}}
+
+{{- return $feeds -}}
diff --git a/themes/default/layouts/partials/function-page-modified.html b/themes/default/layouts/partials/function-page-modified.html
new file mode 100644
index 0000000..43bea9f
--- /dev/null
+++ b/themes/default/layouts/partials/function-page-modified.html
@@ -0,0 +1,39 @@
+{{- $input := .Context -}}
+{{- $disable := or .Disable false -}}
+{{- $pageContext := $input -}}
+{{- $format := or .Format "index.html" -}}
+
+{{- $page := print "public/" (strings.TrimPrefix
+ $pageContext.Page.Site.BaseURL
+ $pageContext.Page.Permalink
+ ) $format
+-}}
+
+{{- $pageModTime := "" -}}
+{{- $markdownModTime := "" -}}
+{{- $markdownContent := print "content/" $pageContext.File -}}
+{{- $markdownPublic := print "public/data/generates/content/" $pageContext.File -}}
+
+{{- if fileExists $markdownContent -}}
+ {{- $markdownModTime = (os.Stat $markdownContent).ModTime -}}
+{{- end -}}
+
+{{- if fileExists $markdownPublic -}}
+ {{- $markdownModTime = (os.Stat $markdownPublic).ModTime -}}
+{{- end -}}
+
+{{- if fileExists $page -}}
+ {{- $pageModTime = (os.Stat $page).ModTime -}}
+{{- end -}}
+
+{{- $page = gt $markdownModTime $pageModTime -}}
+
+{{- $modified := or $page (in (slice
+ "home"
+ "section"
+ "taxonomy"
+ "term"
+ ) $pageContext.Page.Kind)
+-}}
+
+{{- return (or $disable $modified) -}}
diff --git a/themes/default/layouts/partials/function-paths-markdown.html b/themes/default/layouts/partials/function-paths-markdown.html
deleted file mode 100644
index ab92b8d..0000000
--- a/themes/default/layouts/partials/function-paths-markdown.html
+++ /dev/null
@@ -1 +0,0 @@
-{{ return "data/generates/content" }}
diff --git a/themes/default/layouts/partials/function-paths-media.html b/themes/default/layouts/partials/function-paths-media.html
deleted file mode 100644
index ce50a92..0000000
--- a/themes/default/layouts/partials/function-paths-media.html
+++ /dev/null
@@ -1 +0,0 @@
-{{ return "data/media" }}
diff --git a/themes/default/layouts/partials/function-paths-static.html b/themes/default/layouts/partials/function-paths-static.html
deleted file mode 100644
index b34dbeb..0000000
--- a/themes/default/layouts/partials/function-paths-static.html
+++ /dev/null
@@ -1 +0,0 @@
-{{ return "static" }}
diff --git a/themes/default/layouts/partials/function-paths.html b/themes/default/layouts/partials/function-paths.html
new file mode 100644
index 0000000..5f5a516
--- /dev/null
+++ b/themes/default/layouts/partials/function-paths.html
@@ -0,0 +1,7 @@
+{{-
+ return (dict
+ "markdown" "data/generates/content"
+ "media" "data/media"
+ "static" "static"
+ )
+-}}
diff --git a/themes/default/layouts/partials/function-strip-filechars.html b/themes/default/layouts/partials/function-strip-filechars.html
new file mode 100644
index 0000000..b68daa0
--- /dev/null
+++ b/themes/default/layouts/partials/function-strip-filechars.html
@@ -0,0 +1,28 @@
+{{- $input := . -}}
+{{- $output := $input -}}
+
+{{- $output = replace $output `{` "" -}}
+{{- $output = replace $output `}` "" -}}
+{{- $output = replace $output `|` "" -}}
+{{- $output = replace $output `\` "" -}}
+{{- $output = replace $output `^` "" -}}
+{{- $output = replace $output `[` "" -}}
+{{- $output = replace $output `]` "" -}}
+{{- $output = replace $output "`" "" -}}
+{{- $output = replace $output `;` "" -}}
+{{- $output = replace $output `/` "" -}}
+{{- $output = replace $output `?` "" -}}
+{{- $output = replace $output `:` "" -}}
+{{- $output = replace $output `@` "" -}}
+{{- $output = replace $output `&` "" -}}
+{{- $output = replace $output `=` "" -}}
+{{- $output = replace $output `+` "" -}}
+{{- $output = replace $output `$` "" -}}
+{{- $output = replace $output `,` "" -}}
+{{- $output = replace $output `<` "" -}}
+{{- $output = replace $output `>` "" -}}
+{{- $output = replace $output `#` "" -}}
+{{- $output = replace $output `%` "" -}}
+{{- $output = replace $output `\` "" -}}
+
+{{- return $output -}}
diff --git a/themes/default/layouts/partials/gallery-images.html b/themes/default/layouts/partials/gallery-images.html
deleted file mode 100644
index f9be257..0000000
--- a/themes/default/layouts/partials/gallery-images.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{{ $folder := print "public/" (partial "author-user.html" .) "/media/" }}
-
-<gallery-images>
- <h1>Picture Gallery</h1>
- <aside>
- <gallery-overlay></gallery-overlay>
- {{ partial "gallery-walk.html" $folder }}
- </aside>
-</gallery-images>
diff --git a/themes/default/layouts/partials/gallery-walk.html b/themes/default/layouts/partials/gallery-walk.html
index 6dd9fbd..ca95d3f 100644
--- a/themes/default/layouts/partials/gallery-walk.html
+++ b/themes/default/layouts/partials/gallery-walk.html
@@ -1,96 +1,50 @@
-{{- $folder := . -}}
-{{- $files := slice -}}
-{{- $dimensions := "320x320" -}}
-{{- $author := strings.TrimPrefix "public/" (strings.TrimSuffix "/media/" $folder) -}}
-
-{{- if fileExists $folder -}}
-
- {{- range readDir $folder -}}
-
- {{- $name := index (split .Name ".") 0 -}}
- {{- $extension := path.Ext .Name -}}
-
- {{- if or
- (eq $extension ".apng")
- (eq $extension ".avif")
- (eq $extension ".gif")
- (eq $extension ".jfif")
- (eq $extension ".jpeg")
- (eq $extension ".jpg")
- (eq $extension ".pjp")
- (eq $extension ".pjpeg")
- (eq $extension ".png")
- (eq $extension ".svg")
- (eq $extension ".webp")
- (eq $extension ".webp")
+{{- $data := slice -}}
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $filteredPages := partial "function-filters-content.html" .Site.RegularPages -}}
+
+{{- range (where $filteredPages "Section" $author.user) -}}
+ {{- if in .Content "<picture>" -}}
+ {{- $data = $data | append (dict
+ "alt" (delimit (findRE `(?sU)alt=".*"` .Content 1) "")
+ "height" (delimit (findRE `(?sU)height=".*"` .Content 1) "")
+ "src" (delimit (findRE `(?sU)src=".*"` .Content 1) "")
+ "srcset" (delimit (findRE `(?sU)srcset=".*"` .Content 1) "")
+ "style" (delimit (findRE `(?sU)style=".*"` .Content 1) "")
+ "title" (delimit (findRE `(?sU)title=".*"` .Content 1) "")
+ "type" (delimit (findRE `(?sU)type=".*"` .Content 1) "")
+ "width" (delimit (findRE `(?sU)width=".*"` .Content 1) "")
+ "relatedHref" .Permalink
+ )
-}}
- {{-
- $files = $files | append (dict
- "Name" .Name
- "Path" (path.Join $folder .Name)
- )
- -}}
- {{- end -}}
{{- end -}}
-
- {{- if fileExists (path.Join $folder "profile") -}}
- {{- range readDir (path.Join $folder "profile") -}}
-
- {{- $name := index (split .Name ".") 0 -}}
- {{- $extension := path.Ext .Name -}}
-
- {{- if or
- (eq $extension ".apng")
- (eq $extension ".avif")
- (eq $extension ".gif")
- (eq $extension ".jfif")
- (eq $extension ".jpeg")
- (eq $extension ".jpg")
- (eq $extension ".pjp")
- (eq $extension ".pjpeg")
- (eq $extension ".png")
- (eq $extension ".svg")
- (eq $extension ".webp")
- (eq $extension ".webp")
- -}}
- {{-
- $files = $files | append (dict
- "Name" .Name
- "Path" (path.Join $folder "profile" .Name)
- )
- -}}
- {{- end -}}
- {{- end -}}
+ {{- if eq (len $data) 6 -}}
+ {{- break -}}
{{- end -}}
-
- {{- if $files }}
-
- {{- range first 6 $files }}
- {{- if not .IsDir }}
- {{- with $image := resources.Get .Path -}}
- {{- $image = (.Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/gallery-walker_" (path.Base .))).Fit (print $dimensions " webp") }}
- <picture>
- <source srcset="{{- $image.RelPermalink -}}" type="image/webp" />
- {{- $image = (.Content | resources.FromString (print (partial "function-paths-media.html") "/" $author "/gallery-walker_" (path.Base .))).Fit (print $dimensions " png") }}
- <img
- alt="{{- .Name }}"
- title="{{- .Name }}"
- width="{{ $image.Width }}"
- height="{{ $image.Height }}"
- src="{{ $image.RelPermalink }}"
- />
- </picture>
+{{- end -}}
+
+{{- if $data -}}
+ {{- range $image := $data }}
+ <a href="{{ $image.relatedHref }}">
+ <picture>
+ {{- with $image.srcset -}}
+ <source
+ {{ $image.srcset | safeHTMLAttr }}
+ {{ $image.type | safeHTMLAttr }}
+ />
+ {{- end -}}
+ <img
+ loading="lazy"
+ {{ $image.alt | safeHTMLAttr }}
+ {{ $image.title | safeHTMLAttr }}
+ {{ with ne (index (last 1 (split $image.width "=")) 0) `""` }}
+ {{ $image.width | safeHTMLAttr }}
+ {{ $image.height | safeHTMLAttr }}
{{ end }}
- {{- end -}}
- {{- end -}}
-
- {{- else -}}
- <footer>
- <code>No media found!</code>
- </footer>
- {{- end -}}
-{{- else -}}
- <footer>
- <code>No media found!</code>
- </footer>
-{{- end }}
+ {{ $image.src | safeHTMLAttr }}
+ {{ $image.style | safeHTMLAttr }}
+ />
+ </picture>
+ </a>
+ {{ end }}
+ <gallery-overlay></gallery-overlay>
+{{- end -}}
diff --git a/themes/default/layouts/partials/gallery.html b/themes/default/layouts/partials/gallery.html
new file mode 100644
index 0000000..135aa14
--- /dev/null
+++ b/themes/default/layouts/partials/gallery.html
@@ -0,0 +1,14 @@
+{{- $gallery := print "public/" .Section "/gallery.html" -}}
+
+<gallery-images>
+ <h1>Gallery</h1>
+ <aside>
+ {{- if fileExists $gallery -}}
+ {{- (resources.Get $gallery).Content | safeHTML -}}
+ {{- else -}}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{- end -}}
+ </aside>
+</gallery-images>
diff --git a/themes/default/layouts/partials/generate-authors.html b/themes/default/layouts/partials/generate-authors.html
index 8e2081f..d1fc0c2 100644
--- a/themes/default/layouts/partials/generate-authors.html
+++ b/themes/default/layouts/partials/generate-authors.html
@@ -1,70 +1,70 @@
-{{- range .Site.Author.list -}}
+{{- range $author := .Site.Author.list -}}
- {{- if not (fileExists (print "data/" . ".yaml")) -}}
+ {{- if not (fileExists (print "data/authors/" $author ".yaml")) -}}
{{- $configuration := resources.Get "templates/author.yaml" -}}
{{- $configuration := resources.ExecuteAsTemplate
- (print "/data/generates/authors/" . ".yaml")
+ (print "/data/generates/authors/" $author ".yaml")
(dict
- "Name" (title .)
- "User" .
+ "Name" (title $author)
+ "User" $author
)
$configuration
-}}
- {{- $writeToFile := $configuration.RelPermalink -}}
+ {{- $writeToFile := $configuration.Permalink -}}
{{- end -}}
{{- $markdown := resources.Get "templates/markdown-frontmatter.yaml" -}}
{{- $template := resources.ExecuteAsTemplate
- (print "/data/generates/content/" . "/" "_index.md")
+ (print "/data/generates/content/" $author "/" "_index.md")
(dict
- "author" .
+ "author" $author
"layout" "section"
)
$markdown
-}}
- {{- $writeToFile := $template.RelPermalink -}}
+ {{- $writeToFile := $template.Permalink -}}
{{- $template := resources.ExecuteAsTemplate
- (print "/data/generates/content/" . "/feeds/" "_index.md")
+ (print "/data/generates/content/" $author "/feeds/" "_index.md")
(dict
- "author" .
- "layout" "feeds"
+ "author" $author
+ "layout" "section.feeds"
)
$markdown
-}}
- {{- $writeToFile := $template.RelPermalink -}}
+ {{- $writeToFile := $template.Permalink -}}
{{- $template := resources.ExecuteAsTemplate
- (print "/data/generates/content/" . "/media/" "_index.md")
+ (print "/data/generates/content/" $author "/media/" "_index.md")
(dict
- "author" .
- "layout" "media"
+ "author" $author
+ "layout" "section.media"
)
$markdown
-}}
- {{- $writeToFile := $template.RelPermalink -}}
+ {{- $writeToFile := $template.Permalink -}}
{{- $template := resources.ExecuteAsTemplate
- (print "/data/generates/content/" . "/likes/" "_index.md")
+ (print "/data/generates/content/" $author "/marks/" "_index.md")
(dict
- "author" .
- "layout" "likes"
+ "author" $author
+ "layout" "section.marks"
)
$markdown
-}}
- {{- $writeToFile := $template.RelPermalink -}}
+ {{- $writeToFile := $template.Permalink -}}
{{- $template := resources.ExecuteAsTemplate
- (print "/data/generates/content/" . "/drafts/" "_index.md")
+ (print "/data/generates/content/" $author "/drafts/" "_index.md")
(dict
- "author" .
- "layout" "drafts"
+ "author" $author
+ "layout" "section.drafts"
)
$markdown
-}}
- {{- $writeToFile := $template.RelPermalink -}}
+ {{- $writeToFile := $template.Permalink -}}
{{- end -}}
diff --git a/themes/default/layouts/partials/generate-feeds.html b/themes/default/layouts/partials/generate-feeds.html
deleted file mode 100644
index d94e39a..0000000
--- a/themes/default/layouts/partials/generate-feeds.html
+++ /dev/null
@@ -1,278 +0,0 @@
-{{- $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-
-{{- $feeds := slice -}}
-
-{{- if $author.webring.rss -}}
- {{- range $key, $value := (seq 3) -}}
- {{- range $author.webring.rss -}}
-
- {{- with resources.GetRemote . -}}
- {{- with .Err -}}
- {{- warnf "Feed fetch %s" . -}}
- {{- end -}}
- {{- end -}}
-
- {{- with resources.GetRemote . | transform.Unmarshal -}}
-
- {{- $title := "No Title Found" -}}
- {{- $link := "https://example.com/link" -}}
- {{- $description := "No description found." -}}
- {{- $content := "No content found." -}}
- {{- $sourceTitle := "No source title found" -}}
- {{- $sourceLink := "https://example.com/" -}}
- {{- $sourceDescription := "No source description found." -}}
- {{- $date := now.Format "2006-01-02T15:04:05Z" -}}
- {{- $enclosure := "" -}}
-
- {{- with .channel -}}
-
- {{- $sourceTitle = .title -}}
- {{- $sourceDescription = .description -}}
-
- {{- if reflect.IsSlice .link -}}
- {{- if reflect.IsMap (index .link 0) -}}
- {{- $sourceLink = index (index .link 0) "-href" -}}
- {{- else -}}
- {{- $sourceLink = index .link 0 -}}
- {{- end -}}
- {{- else -}}
- {{- $sourceLink = .link -}}
- {{- end -}}
-
- {{- with .item -}}
- {{- if reflect.IsMap . -}}
- {{- $title = index . "title" -}}
- {{- $link = index . "link" -}}
- {{- $date = index . "pubDate" -}}
- {{- else -}}
- {{- range first $value . -}}
- {{- $description = .description -}}
- {{- $content = .description -}}
- {{- $title = .title -}}
- {{- $link = .link -}}
- {{- $date = .pubDate -}}
- {{- with .enclosure -}}
- {{- $enclosure = index . "-url" -}}
- {{- end -}}
- {{- end -}}
- {{- end -}}
- {{- end -}}
-
- {{- if not $date -}}
- {{- $date = .lastBuildDate -}}
- {{- end -}}
-
- {{- else -}}
-
- {{- with .link -}}
- {{- $sourceLink = index (index . 0) "-href" -}}
- {{- end -}}
-
- {{- with .subtitle -}}
- {{- if reflect.IsMap . -}}
- {{- $sourceDescription = index . "#text" -}}
- {{- else -}}
- {{- $sourceDescription = . -}}
- {{- end -}}
- {{- end -}}
-
- {{- with .title -}}
- {{- if reflect.IsMap . -}}
- {{- $sourceTitle = index . "#text" -}}
- {{- else -}}
- {{- $sourceTitle = . -}}
- {{- end -}}
- {{- end -}}
-
- {{- with .entry -}}
- {{- range first $value . -}}
- {{- $date = .updated -}}
-
- {{- with .link -}}
- {{- if reflect.IsMap . -}}
- {{- $link = index . "-href" -}}
- {{- else -}}
- {{- if reflect.IsMap (index . 0) -}}
- {{- $link = index (index . 0) "-href" -}}
- {{- else -}}
- {{- $link = . -}}
- {{- end -}}
- {{- end -}}
- {{- end -}}
-
- {{- with .title -}}
- {{- if reflect.IsMap . -}}
- {{- $title = index . "#text" -}}
- {{- else -}}
- {{- $title = . -}}
- {{- end -}}
- {{- end -}}
-
- {{- with .content -}}
- {{- $content = index . "#text" -}}
- {{- end -}}
-
- {{- with .summary -}}
- {{- $description = index . "#text" -}}
- {{- end -}}
-
- {{- with .group -}}
- {{- $description = .description -}}
- {{- $content = index .content "#text" -}}
- {{- $enclosure = index .thumbnail "-url" -}}
- {{- end -}}
- {{- end -}}
- {{- end -}}
-
- {{- end -}}
-
- {{- /* Common time zone typos. */ -}}
- {{- $date = strings.Replace $date "G6T" "GST" -}}
-
- {{- /* If missing seconds split and try again. */ -}}
- {{- if lt (len (split $date ":")) 3 -}}
- {{- $date = delimit (first 3 (after 1 (split $date " "))) " " -}}
- {{- end -}}
-
- {{
- $feeds = $feeds | append (dict
- "FeedContent" ($content | plainify | htmlUnescape)
- "FeedContentShort" (delimit (first 2 (split ($content | plainify | htmlUnescape) "\n")) " " | truncate 250)
- "FeedDate" ($date | plainify | htmlUnescape | time.Format "January 2, 2006")
- "FeedDateTime" ($date | plainify | htmlUnescape | time.Format "2006-01-02T15:04:05Z")
- "FeedDateTitle" ($date | plainify | htmlUnescape | time.Format "Monday, January 2 2006 at 15:04:05 MST")
- "FeedDescription" ($description | plainify | htmlUnescape)
- "FeedDescriptionShort" (delimit (first 2 (split ($description | plainify | htmlUnescape) "\n")) " " | truncate 250)
- "FeedEnclosure" ($enclosure | plainify | htmlUnescape)
- "FeedLink" ($link | plainify | htmlUnescape)
- "FeedName" (delimit ((delimit (first 2 (split ($sourceTitle | plainify | htmlUnescape) " ")) " ") | findRE "^([^.|?|!|\n|\"|]+)") " " | replaceRE "[^a-zA-Z ]" "")
- "FeedSourceDescription" ($sourceDescription | plainify | htmlUnescape)
- "FeedSourceDomain" (($sourceLink | plainify | htmlUnescape | urls.Parse).Host)
- "FeedSourceLink" ($sourceLink | plainify | htmlUnescape)
- "FeedSourceTitle" ($sourceTitle | plainify | htmlUnescape)
- "FeedTitle" ($title | plainify | htmlUnescape)
- )
- -}}
-
- {{- end -}}
- {{- end -}}
- {{- end -}}
-
- {{- range $feeds -}}
-
- {{- $imageCanonicalURL :=
- (print
- "https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url="
- "http://"
- .FeedSourceDomain
- "&size=64"
- )
- -}}
-
- {{- $404image := resources.Get "data/media/404.png" -}}
- {{- $imageSource := $404image.RelPermalink -}}
- {{- $imageTitle := "No image found" -}}
-
- {{- with $image := resources.GetRemote $imageCanonicalURL -}}
- {{- with .Err -}}
- {{- warnf "%s" . -}}
- {{- else -}}
- {{- $imageContent := $image.Content | resources.FromString (print (partial "function-paths-media.html") "/" ($image | urlize)) -}}
- {{- $imageSource = $imageContent.RelPermalink -}}
- {{- $imageTitle = $imageCanonicalURL -}}
- {{- end -}}
- {{- end -}}
-
- {{- $template := resources.Get "templates/markdown-feed.yaml" -}}
- {{- $name := print (delimit (first 8 (split (.FeedTitle | urlize) "-")) "-" | humanize | urlize) "-" (.FeedLink | sha256 | truncate 8 "") | humanize | urlize -}}
- {{- $path := print "/data/generates/content/" $author.user "/feeds/" $name ".md" -}}
-
- {{- $description := .FeedDescriptionShort -}}
- {{- if gt (len .FeedTitle) (len .FeedDescriptionShort) -}}
- {{- $description = .FeedTitle -}}
- {{- end -}}
-
- {{- $content := .FeedContentShort -}}
- {{- if or (eq $content "No content found.") (gt (len .FeedTitle) (len $content)) -}}
- {{- $content = .FeedTitle -}}
- {{- end -}}
-
- {{- $link := .FeedLink -}}
- {{- $enclosure := .FeedEnclosure -}}
- {{- if or
- (in .FeedLink ".apng")
- (in .FeedLink ".avif")
- (in .FeedLink ".gif")
- (in .FeedLink ".jfif")
- (in .FeedLink ".jpeg")
- (in .FeedLink ".jpg")
- (in .FeedLink ".pjp")
- (in .FeedLink ".pjpeg")
- (in .FeedLink ".png")
- (in .FeedLink ".svg")
- (in .FeedLink ".webp")
- -}}
- {{- if (.Feedlink | urls.Parse).Host -}}
- {{- else -}}
- {{- $enclosure = print "http://" .FeedSourceDomain .FeedLink -}}
- {{- $link = $enclosure -}}
- {{- end -}}
- {{- end -}}
-
- {{- $markdown := resources.ExecuteAsTemplate
- $path
- (dict
- "author" $author.user
- "content" $content
- "date" .FeedDateTime
- "description" .FeedSourceTitle
- "domain" .FeedSourceDomain
- "enclosure" $enclosure
- "image" $imageSource
- "link" $link
- "name" .FeedName
- "raw" (strings.TrimLeft "/" $path)
- "self" (print $author.user "/feeds/" $name "/")
- "tags" "[rss]"
- )
- $template
- -}}
- {{- $writeToFile := $markdown.RelPermalink -}}
- {{ end }}
-
- <web-ring>
- <h1>Web Ring</h1>
- <aside>
- {{ range first 3 (uniq (sort $feeds "FeedDateTime" "desc")) }}
- <web-ring-item>
- <header>
- <a
- title="{{ .FeedLink }}"
- href="{{ .FeedLink }}">
- {{ .FeedTitle }}
- </a>
- </header>
-
- <p>
- <time
- title="{{ .FeedDateTitle }}"
- datetime="{{ .FeedDateTime }}">
- {{ .FeedDate }}
- </time>
- {{ if gt (len .FeedDescriptionShort) (len .FeedContentShort) -}}
- {{ "--" | markdownify }} {{ .FeedDescriptionShort }}
- {{- else -}}
- {{ "--" | markdownify }} {{ .FeedContentShort }}
- {{- end }}
- </p>
-
- <a
- title="{{ .FeedSourceDescription }}"
- href="{{ .FeedSourceLink }}">
- {{ .FeedSourceTitle }}
- </a>
- </web-ring-item>
- {{ end }}
- </aside>
- </web-ring>
-{{- end -}}
diff --git a/themes/default/layouts/partials/head-canonical.html b/themes/default/layouts/partials/head-canonical.html
new file mode 100644
index 0000000..051e450
--- /dev/null
+++ b/themes/default/layouts/partials/head-canonical.html
@@ -0,0 +1,15 @@
+{{- $canonical := .Permalink -}}
+
+{{- with .Site.Params.site.canonical -}}
+ {{- $canonical = print $.Site.Params.site.canonical $.RelPermalink -}}
+{{- end -}}
+
+{{- with .Params.feed -}}
+ {{- $canonical = $.Params.feed.link -}}
+{{- end -}}
+
+{{- with .Params.canonical -}}
+ {{- $canonical = $.Params.canonical -}}
+{{- end -}}
+
+<link rel="canonical" href="{{ $canonical }}" />
diff --git a/themes/default/layouts/partials/head-csp.html b/themes/default/layouts/partials/head-csp.html
index 9519e14..d34043e 100644
--- a/themes/default/layouts/partials/head-csp.html
+++ b/themes/default/layouts/partials/head-csp.html
@@ -1,42 +1,19 @@
-{{ $upgrade := "" }}
-{{ if .Site.Params.csp.upgrade }}
- {{ $upgrade = "upgrade-insecure-requests;" }}
-{{- end -}}
-
-<meta name="referrer" content="{{ .Site.Params.csp.referrer }}">
+<meta name="referrer" content="{{ .Site.Params.site.referrer }}" />
-{{ printf `
-<meta
- http-equiv="Content-Security-Policy"
- content="
- %s
- block-all-mixed-content;
- default-src 'self';
- child-src %s;
- connect-src %s;
- font-src %s;
- form-action %s;
- frame-src %s;
- img-src %s;
- media-src %s;
- object-src %s;
- prefetch-src %s;
- script-src %s;
- script-src-elem %s;
- style-src %s;
- ">`
- ($upgrade)
- (delimit .Site.Params.csp.childsrc " ")
- (delimit .Site.Params.csp.connectsrc " ")
- (delimit .Site.Params.csp.fontsrc " ")
- (delimit .Site.Params.csp.formaction " ")
- (delimit .Site.Params.csp.framesrc " ")
- (delimit .Site.Params.csp.imgsrc " ")
- (delimit .Site.Params.csp.mediasrc " ")
- (delimit .Site.Params.csp.objectsrc " ")
- (delimit .Site.Params.csp.prefetchsrc " ")
- (delimit .Site.Params.csp.scriptsrc " ")
- (delimit .Site.Params.csp.scriptsrcelem " ")
- (delimit .Site.Params.csp.stylesrc " ")
- | safeHTML }}
+{{ with .Site.Params.csp -}}
+<meta http-equiv="Content-Security-Policy"
+{{- printf ` content="` | safeHTMLAttr }}
+{{ range $policy, $list := . -}}
+{{- if reflect.IsSlice $list -}}
+{{- print $policy | safeHTMLAttr }}
+{{- range $list -}}
+{{ print " " . | safeHTMLAttr }}
+{{- end }};
+{{ else }}
+{{- print $policy ";" | safeHTMLAttr }}
+{{ end }}
+{{- end -}}
+{{- printf `"` | safeHTMLAttr -}}
+/>
+{{ end -}}
diff --git a/themes/default/layouts/partials/head-css.html b/themes/default/layouts/partials/head-css.html
new file mode 100644
index 0000000..6e9eb56
--- /dev/null
+++ b/themes/default/layouts/partials/head-css.html
@@ -0,0 +1,26 @@
+{{- $default := resources.Get "css/default.css" -}}
+{{- $syntax := resources.Get "css/default-syntax.css" -}}
+{{- $simple := resources.Get "css/default-simple.css" -}}
+{{- $fast := resources.Get "css/default-fast.css" -}}
+{{- $math := resources.Get "css/default-mathml.css" -}}
+
+{{- $css :=
+ slice
+ $default
+ $syntax
+ | resources.Concat "css/bundle.css"
+ | resources.Minify
+ | fingerprint
+-}}
+
+{{ if .Site.Params.site.production }}
+<link rel="stylesheet" href="{{ $css.Permalink }}" title="Default" />
+{{ else }}
+<link rel="stylesheet" href="{{ $default.Permalink }}" title="Default" />
+<link rel="stylesheet" href="{{ $syntax.Permalink }}" />
+{{ end }}
+
+<link rel="stylesheet" href="{{ $math.Permalink }}" />
+
+<link rel="alternate stylesheet" href="{{ $simple.Permalink }}" />
+<link rel="alternate stylesheet" href="{{ $fast.Permalink }}" />
diff --git a/themes/default/layouts/partials/site-description.html b/themes/default/layouts/partials/head-description.html
index 8d021de..89e4691 100644
--- a/themes/default/layouts/partials/site-description.html
+++ b/themes/default/layouts/partials/head-description.html
@@ -4,5 +4,5 @@
{{ .Summary }}
{{- else -}}
{{- block "description" . -}}{{- end -}}
- {{- partial "site-title.html" . -}}
+ {{- partial "head-title.html" . -}}
{{- end -}}
diff --git a/themes/default/layouts/partials/head-discovery.html b/themes/default/layouts/partials/head-discovery.html
new file mode 100644
index 0000000..8c7272f
--- /dev/null
+++ b/themes/default/layouts/partials/head-discovery.html
@@ -0,0 +1,62 @@
+{{- $author := partial "function-authors-data.html" . -}}
+
+{{- with (eq .Page.Kind "home") -}}
+<link
+ rel="alternate"
+ type="application/rss+xml"
+ title="{{ $.Site.Title }} Feed"
+ href="{{ "" | absURL }}/rss.xml"
+/>
+
+ {{- range $author := $.Site.Sections }}
+ <link
+ rel="alternate"
+ type="application/rss+xml"
+ title="{{ $author.Page.Type }}'s Feed"
+ href="{{ print $author.Permalink "rss.xml" | absURL }}"
+ />
+ {{ end }}
+{{- end -}}
+
+{{- with (eq .Page.Kind "section") -}}
+<link
+ rel="alternate"
+ type="application/rss+xml"
+ title="{{ $author.name }}'s Feed"
+ href="{{ print ("" | absURL) "/" $.Section }}/rss.xml"
+/>
+
+{{- with $author.feeds.rss }}
+ {{ range $author.feeds.rss }}
+ {{ $data := split . " " }}
+ {{- $url := delimit (first 1 $data) "" -}}
+ {{- $retitle := trim (delimit (after 1 $data) " ") " " -}}
+ {{- $retitle := and $retitle (print $retitle "'s Feed") -}}
+
+ <link
+ rel="alternate"
+ type="application/rss+xml"
+ title="{{ or $retitle $url }}"
+ href="{{ $url }}"
+ />
+ {{ end }}
+{{ end }}
+{{- end -}}
+
+{{- with (eq .Page.Kind "taxonomy") -}}
+<link
+ rel="alternate"
+ type="application/rss+xml"
+ title="{{ $.Title }} Feed"
+ href="{{ $.Permalink }}rss.xml"
+/>
+{{- end -}}
+
+{{- with (eq .Page.Kind "term") -}}
+<link
+ rel="alternate"
+ type="application/rss+xml"
+ title="#{{ lower $.Title }} Tag Feed"
+ href="{{ $.Permalink }}rss.xml"
+/>
+{{- end }}
diff --git a/themes/default/layouts/partials/head-embed.html b/themes/default/layouts/partials/head-embed.html
new file mode 100644
index 0000000..e9c44d7
--- /dev/null
+++ b/themes/default/layouts/partials/head-embed.html
@@ -0,0 +1,4 @@
+<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ {{- partial "head-css.html" . -}}
+</head>
diff --git a/themes/default/layouts/partials/head-js.html b/themes/default/layouts/partials/head-js.html
new file mode 100644
index 0000000..a491eee
--- /dev/null
+++ b/themes/default/layouts/partials/head-js.html
@@ -0,0 +1,8 @@
+{{- $index := resources.Get "js/index.js" -}}
+{{- $js := $index | resources.Minify | fingerprint -}}
+
+{{ if .Site.Params.site.production }}
+<script src="{{ $js.Permalink }}"></script>
+{{ else }}
+<script src="{{ $index.Permalink }}"></script>
+{{ end }}
diff --git a/themes/default/layouts/partials/head-manifest.html b/themes/default/layouts/partials/head-manifest.html
index 6c154ed..52be1f9 100644
--- a/themes/default/layouts/partials/head-manifest.html
+++ b/themes/default/layouts/partials/head-manifest.html
@@ -1,15 +1,58 @@
-{{- $icon := resources.Get .Site.Params.webmanifest.logo -}}
+{{- $author := .Section -}}
+{{- $home := or ("" | absURL) "/" -}}
+{{- $kind := in (slice "home" "taxonomy" "term") .Page.Kind -}}
+{{- $logo := .Site.Params.webmanifest.logo -}}
+{{- $profile := print "public/data/media/" $author "/" $author "-profile" -}}
-{{- $icon32 := $icon.Fit "32x32" -}}
-{{- $icon16 := $icon.Fit "16x16" -}}
-{{- $appleTouchIcon := $icon.Fit "180x180" -}}
+{{- if not $kind -}}
+ {{- $home = print ("" | absURL) "/" $author "/" -}}
+ {{- if fileExists (print $profile ".gif") -}} {{- $logo = (print $profile ".gif") -}} {{- end -}}
+ {{- if fileExists (print $profile ".webp") -}} {{- $logo = (print $profile ".webp") -}} {{- end -}}
+ {{- if fileExists (print $profile ".png") -}} {{- $logo = (print $profile ".png") -}} {{- end -}}
+{{- end -}}
-{{- $ico := $icon32.Content | resources.FromString "/favicon.ico" -}}
+{{- with $logo = resources.Get $logo -}}
-<link rel="icon" type="image/x-icon" href="data:image/ico;base64,{{ $icon32.Content | base64Encode }}">
-<link rel="icon" type="image/png" sizes="16x16" href="data:image/png;base64,{{ $icon16.Content | base64Encode }}">
-<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,{{ $icon32.Content | base64Encode }}">
-<link rel="apple-touch-icon" sizes="180x180" href="data:image/png;base64,{{ $appleTouchIcon.Content | base64Encode }}">
-<link rel="manifest" href="{{ .Site.BaseURL }}/site.webmanifest">
-<meta name="msapplication-TileColor" content="#da532c">
-<meta name="theme-color" content="#ffffff">
+{{- $16 := $logo.Fit "16x16" -}}
+{{- $32 := $logo.Fit "32x32" -}}
+{{- $180 := $logo.Fit "180x180" -}}
+{{- $192 := $logo.Fit "192x192" -}}
+{{- $512 := $logo.Fit "512x512" -}}
+
+{{- if (eq $.Page.Kind "home") -}}
+ {{- $writeToFile := ($32.Content | resources.FromString "/favicon.ico").Permalink -}}
+{{- end -}}
+
+<link rel="icon" type="image/x-icon" sizes="32x32" href="data:image/ico;base64,{{ $32.Content | base64Encode }}" />
+<link rel="icon" type="{{ $16.MediaType }}" sizes="16x16" href="data:{{ $16.MediaType }};base64,{{ $16.Content | base64Encode }}" />
+<link rel="icon" type="{{ $32.MediaType }}" sizes="32x32" href="data:{{ $32.MediaType }};base64,{{ $32.Content | base64Encode }}" />
+<link rel="apple-touch-icon" type="{{ $180.MediaType }}" sizes="180x180" href="data:{{ $180.MediaType }};base64,{{ $180.Content | base64Encode }}" />
+
+<link rel="home" href="{{ $home }}" />
+
+{{ "" -}} <!-- Newline -->
+
+{{- with $manifest := $.Site.Params.webmanifest -}}
+<link rel="manifest" href='data:application/manifest+json,{{ merge $manifest (dict
+ "start_url" $home
+ "icons" (slice
+ (dict
+ "sizes" "192x192"
+ "src" (print "data:" $192.MediaType ";base64," ($192.Content | base64Encode))
+ "type" (print $192.MediaType))
+ (dict
+ "sizes" "512x512"
+ "src" (print "data:" $512.MediaType ";base64," ($512.Content | base64Encode))
+ "type" (print $512.MediaType))))
+ | jsonify
+ | urlquery
+}}'>
+
+<meta name="msapplication-TileColor" content="#da532c" />
+<meta name="msapplication-config" content="none" />
+<meta name="msapplication-square70x70logo" content="none" />
+<meta name="msapplication-square150x150logo" content="data:{{ $180.MediaType }};base64,{{ $180.Content | base64Encode }}" />
+<meta name="msapplication-square310x310logo" content="none" />
+<meta name="msapplication-wide310x150logo" content="none" />
+{{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/head-search.html b/themes/default/layouts/partials/head-search.html
index 1bfed6c..89113ab 100644
--- a/themes/default/layouts/partials/head-search.html
+++ b/themes/default/layouts/partials/head-search.html
@@ -1,11 +1,5 @@
-{{- with .Site.Params.search.verification.google -}}
-<meta name="google-site-verification" content="{{ . }}" />
-{{ end }}
-
-{{- with .Site.Params.search.verification.bing -}}
-<meta name="msvalidate.01" content="{{ . }}" />
-{{ end }}
-
-{{- with .Site.Params.search.verification.yandex -}}
-<meta name="yandex-verification" content="{{ . }}" />
+{{- with .Site.Params.search.verification -}}
+{{- range $name, $content := . }}
+<meta name="{{ $name }}" content="{{ $content }}" />
+{{- end }}
{{ end }}
diff --git a/themes/default/layouts/partials/head-title.html b/themes/default/layouts/partials/head-title.html
new file mode 100644
index 0000000..fff4530
--- /dev/null
+++ b/themes/default/layouts/partials/head-title.html
@@ -0,0 +1,20 @@
+{{- $author := index .Site.Data.authors .Section -}}
+
+{{- if not (eq .Title $.Site.Title) -}}
+ {{- with $title := or .Title .Summary -}}
+ {{ $title }} &mdash;
+ {{ end }}
+{{- end -}}
+
+{{- with $title := $.Site.Title -}}
+ {{- if (in (slice
+ "home"
+ "taxonomy"
+ "term"
+ ) $.Page.Kind)
+ -}}
+ {{ $title }}
+ {{- else -}}
+ {{ $author.title }}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/head.html b/themes/default/layouts/partials/head.html
index 509b177..1668d57 100644
--- a/themes/default/layouts/partials/head.html
+++ b/themes/default/layouts/partials/head.html
@@ -1,67 +1,62 @@
-{{- partial "generate-authors" . -}}
-{{- $data :=
- (dict
- "Author" (index .Site.Data ((or .Params.author .Site.Author.default.home) | default "default"))
- )
--}}
+{{- $noindex := "" -}}
+{{- $image := "" -}}
+{{- $author := .Section -}}
+{{- $kind := in (slice "home" "taxonomy" "term") .Page.Kind -}}
-<!-- HTML Meta Tags -->
-<meta charset="utf-8">
-<meta name="author" content="{{ partial "author-name.html" (dict "Data" $data) -}}">
-{{ if or .Params.Unlisted .Params.ExpiryDate -}}
-<meta name="robots" content="noindex,nofollow">
-{{- else -}}
-<meta name="robots" content="index,follow">
-{{- end }}
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<meta name="keywords" content="{{- partial "site-title.html" . -}}">
-{{ hugo.Generator }}
-{{ with .Site.Params.site.refresh -}}
-<meta http-equiv="refresh" content="{{ . }}">
+{{- if not $kind -}}
+ {{- $image = print ("" | absURL) "/data/media/" $author "/" $author "-profile.png" -}}
+{{- end -}}
+
+{{- with or .Params.Feed .Params.Unlisted .Params.ExpiryDate -}}
+ {{- $noindex = "noindex,nofollow" -}}
{{- end }}
+<!-- HTML Meta Tags -->
+<meta charset="utf-8" />
+<meta name="author" content="{{ or $author $.Site.Title -}}" />
+<meta name="robots" content="{{ or $noindex .Site.Params.site.robots "index,follow" }}" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<meta name="keywords" content="{{- partial "head-title.html" . -}}" />
+<meta name="generator" content="Hugo {{ hugo.Version }}" />
+
<!-- Search Engine Tags -->
-<meta itemprop="name" content="{{ partial "site-title.html" . -}}">
-<meta itemprop="description" content="{{ if .Params.summary }}{{ .Params.summary }}{{ else }}{{ .Summary }}{{ end }}">
-<meta itemprop="image" content="{{ .Site.BaseURL }}/{{ partial "author-user.html" (dict "Data" $data) -}}/media/profile/picture.png">
+<meta itemprop="name" content="{{ partial "head-title.html" . -}}" />
+<meta itemprop="description" content="{{- partial "head-description.html" . -}}" />
+<meta itemprop="image" content="{{ $image }}" />
<!-- Open Graph Meta Tags -->
-<meta property="og:title" content="{{ partial "site-title.html" . -}}">
-<meta property="og:description" content="{{- partial "site-description.html" . -}}">
-<meta property="og:url" content="{{ .Permalink }}">
-<meta property="og:image" content="{{ .Site.BaseURL }}/{{ partial "author-user.html" (dict "Data" $data) -}}/media/profile/picture.png">
-<meta property="og:type" content="website">
-<meta property="article:published_time" content="{{ .Params.PublishDate }}">
-<meta property="article:modified_time " content="{{ .Params.LastMod }}">
+<meta property="og:title" content="{{ partial "head-title.html" . -}}" />
+<meta property="og:description" content="{{- partial "head-description.html" . -}}" />
+<meta property="og:url" content="{{ .Permalink }}" />
+<meta property="og:image" content="{{ $image }}" />
+<meta property="og:type" content="website" />
+<meta property="article:published_time" content="{{ (or .Params.PublishDate now.UTC) | time.Format "2006-01-02T15:04:05Z" }}" />
+<meta property="article:modified_time " content="{{ (or .Params.LastMod now.UTC) | time.Format "2006-01-02T15:04:05Z" }}" />
<!-- Twitter Meta Tags -->
-<meta name="twitter:card" content="summary_large_image">
-<meta name="twitter:title" content="{{ partial "site-title.html" . -}}">
-<meta name="twitter:description" content="{{- partial "site-description.html" . -}}">
-<meta name="twitter:image" content="{{ .Site.BaseURL }}/{{ partial "author-user.html" (dict "Data" $data) -}}/media/profile/picture.png">
+<meta name="twitter:card" content="summary_large_image" />
+<meta name="twitter:title" content="{{ partial "head-title.html" . -}}" />
+<meta name="twitter:description" content="{{- partial "head-description.html" . -}}" />
+<meta name="twitter:image" content="{{ $image }}" />
+
+<!-- Extra Meta Tags -->
+<meta name='base-url' content="{{ "" | absURL }}" />
+<meta name='last-modified' content="{{ now.UTC.Format "Mon, 02 Jan 2006 15:04:05 GMT" }}" />
<!-- Search Verification -->
{{- partial "head-search.html" . -}}
-<!-- Link Tags -->
-<link rel="home" href="{{ .Site.BaseURL }}/{{ partial "author-user.html" (dict "Data" $data) }}">
+<!-- Feed Discovery -->
+{{- partial "head-discovery.html" . -}}
-<!-- Style Sheets & Scripts -->
-{{- $index := resources.Get "js/index.js" -}}
-{{- $default := resources.Get "css/default.css" -}}
-{{- $syntax := resources.Get "css/syntax-highlight-default.css" -}}
+<!-- Canonicalization -->
+{{- partial "head-canonical.html" . -}}
-{{- $js := $index | resources.Minify | fingerprint -}}
-{{- $css := slice $default $syntax | resources.Concat "css/bundle.css" | resources.Minify | fingerprint -}}
+<!-- Styles -->
+{{- partial "head-css.html" . -}}
-{{ if .Site.Params.site.production }}
-<link rel="stylesheet" href="{{ $css.Permalink }}">
-<script src="{{ $js.Permalink }}"></script>
-{{ else }}
-<link rel="stylesheet" href="{{ $default.Permalink }}">
-<link rel="stylesheet" href="{{ $syntax.Permalink }}">
-<script src="{{ $index.Permalink }}"></script>
-{{ end }}
+<!-- Scripts -->
+{{- partial "head-js.html" . -}}
<!-- Progressive Enhancement -->
{{- partial "head-manifest.html" . -}}
diff --git a/themes/default/layouts/partials/image-gradient.css.html b/themes/default/layouts/partials/image-gradient.css.html
new file mode 100644
index 0000000..794ea8b
--- /dev/null
+++ b/themes/default/layouts/partials/image-gradient.css.html
@@ -0,0 +1,18 @@
+{{- $colors := . -}}
+
+{{- with $colors -}}
+ background:
+ {{- range $key, $color := $colors -}}
+ {{- $last := sub (len $colors) 1 -}}
+ {{- $separator := "," -}}
+ {{- $color = $color -}}
+ {{- $position := "top" -}}
+ {{- if eq $last $key -}}
+ {{- $separator = ";" -}}
+ {{- end -}}
+ {{- if gt $key 0 -}}
+ {{- $position = "bottom" -}}
+ {{- end -}}
+ radial-gradient(ellipse at {{ $position }}, {{ $color }}, transparent){{ $separator }}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/menu-datetime.html b/themes/default/layouts/partials/menu-datetime.html
new file mode 100644
index 0000000..20ef50e
--- /dev/null
+++ b/themes/default/layouts/partials/menu-datetime.html
@@ -0,0 +1,22 @@
+{{- $href := print .Permalink -}}
+
+<meta-datetime>
+ <a href="{{ $href }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/calendar.svg")) -}}
+ <time
+ data-type="localDate"
+ datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
+ >
+ {{ .Date | time.Format "Jan 2 2006" -}}
+ </time>
+ </a>
+ <a href="{{ $href }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/clock.svg")) -}}
+ <time
+ data-type="localTime"
+ datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
+ >
+ {{ .Date | time.Format "15:04 MST" -}}
+ </time>
+ </a>
+</meta-datetime>
diff --git a/themes/default/layouts/partials/menu-embed.html b/themes/default/layouts/partials/menu-embed.html
new file mode 100644
index 0000000..1b03d27
--- /dev/null
+++ b/themes/default/layouts/partials/menu-embed.html
@@ -0,0 +1,8 @@
+{{- $href := print .Permalink -}}
+
+<meta-embed>
+ <a href="{{ print $href "embed.html" }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/code.svg")) -}}
+ <span>Embed</span>
+ </a>
+</meta-embed>
diff --git a/themes/default/layouts/partials/menu-markdown.html b/themes/default/layouts/partials/menu-markdown.html
new file mode 100644
index 0000000..6e54238
--- /dev/null
+++ b/themes/default/layouts/partials/menu-markdown.html
@@ -0,0 +1,13 @@
+{{- if not .ExpiryDate -}}
+ {{- $relURL := strings.TrimPrefix .Page.Site.BaseURL .Page.Permalink -}}
+ {{- $source := print (path.Dir $relURL) ".md" -}}
+ {{- $href := print .Site.BaseURL "/" (partial "function-paths.html").markdown $source -}}
+ {{- $title := .File.LogicalName -}}
+
+ <meta-source>
+ <a href="{{ $href }}" title="{{ $title }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/square-letter-m.svg")) -}}
+ <span>Markdown</span>
+ </a>
+ </meta-source>
+{{- end -}}
diff --git a/themes/default/layouts/partials/menu-permalink.html b/themes/default/layouts/partials/menu-permalink.html
new file mode 100644
index 0000000..6f19559
--- /dev/null
+++ b/themes/default/layouts/partials/menu-permalink.html
@@ -0,0 +1,11 @@
+{{- $href := print .Permalink "#" (partial "card-id.html" .) -}}
+
+<meta-permalink>
+ <a title="#{{ partial "card-id.html" . }}" href="{{ $href }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/link.svg")) -}}
+ <span>Permalink</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </a>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-permalink>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/menu-plain.html b/themes/default/layouts/partials/menu-plain.html
new file mode 100644
index 0000000..3dee808
--- /dev/null
+++ b/themes/default/layouts/partials/menu-plain.html
@@ -0,0 +1,9 @@
+{{- $href := print .Permalink -}}
+{{- $plain := print $href "index.txt" -}}
+
+<meta-plain>
+ <a href="{{ $plain }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/notes.svg")) -}}
+ <span>Plaintext</span>
+ </a>
+</meta-plain>
diff --git a/themes/default/layouts/partials/meta-anchored.html b/themes/default/layouts/partials/meta-anchored.html
new file mode 100644
index 0000000..872f98e
--- /dev/null
+++ b/themes/default/layouts/partials/meta-anchored.html
@@ -0,0 +1,24 @@
+{{- if or .Weight .Params.Liked .Params.feed -}}
+ <meta-anchored>
+ {{- $author := .Section -}}
+ {{- partial "meta-via.html" . -}}
+
+ {{- if .Weight -}}
+ <a data-anchored="pinned">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/pinned.svg")) }}
+ <span>Pinned</span>
+ </a>
+ {{- end -}}
+
+ {{- if .Params.Marked -}}
+ <a
+ href="{{ "" | absURL }}/{{ $author }}/marks/#marks"
+ data-anchored="marked"
+ data-hover=""
+ >
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/bookmark.svg")) }}
+ <span>Marked</span>
+ </a>
+ {{- end -}}
+ </meta-anchored>
+{{- end -}}
diff --git a/themes/default/layouts/partials/meta-date-time.html b/themes/default/layouts/partials/meta-date-time.html
deleted file mode 100644
index 127785b..0000000
--- a/themes/default/layouts/partials/meta-date-time.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{{- $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-
-{{- with .Params.feed.self -}}
-<a href="{{ $.Site.BaseURL }}/{{ . }}">
-{{ else }}
-<a href="{{ .Site.BaseURL }}/{{ $author.user }}/messages/{{ path.Base .Permalink }}#{{ partial "card-id.html" . }}">
-{{ end }}
- <time
- datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}"
- title="{{ .Date | time.Format "Posted: Monday, January 2, 2006 at 15:04:05 MST" }}
-{{ if .Lastmod.After .Date }}{{ .Lastmod | time.Format "Edited: Monday, January 2, 2006 at 15:04:05 MST" }}{{ end }}">
- {{ (.Date.Local | time.Format "3:04 PM Jan 2 2006") -}}
- {{ if .Lastmod.After .Date }}
- (edited)
- {{ end }}
- </time>
-{{- /* This comment removes trailing newlines and white spaces. */ -}}
-</a>
diff --git a/themes/default/layouts/partials/meta-datetime.html b/themes/default/layouts/partials/meta-datetime.html
new file mode 100644
index 0000000..e0329bb
--- /dev/null
+++ b/themes/default/layouts/partials/meta-datetime.html
@@ -0,0 +1,14 @@
+<meta-datetime
+title="{{ .Date | time.Format "Posted: Monday January 2 2006 at 15:04:05 MST" }}
+{{ if .Lastmod.After .Date }}{{ .Lastmod | time.Format "Edited: Monday January 2 2006 at 15:04:05 MST" }}{{ end }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/calendar.svg")) -}}
+ <time datetime="{{ .Date | time.Format "2006-01-02T15:04:05Z" }}">
+ {{ (.Date | time.Format "Mon Jan 2 2006") -}}
+ </time>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ {{ if .Lastmod.After .Date }}
+ <span>(edited)</span>
+ {{- end -}}
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-datetime>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-draft.html b/themes/default/layouts/partials/meta-draft.html
index 87933a5..d441b9a 100644
--- a/themes/default/layouts/partials/meta-draft.html
+++ b/themes/default/layouts/partials/meta-draft.html
@@ -1 +1,15 @@
-<draft-label><a href="{{ .Site.BaseURL }}/{{ .Type }}/drafts/"><em>Draft</em></a></draft-label>
+{{- if .Draft -}}
+ <meta-draft>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ <em>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ <a href="{{ .Site.BaseURL }}/{{ .Type }}/drafts/#drafts">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/edit.svg")) -}}
+ <span>Draft</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </a>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </em>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </meta-draft>
+{{- end -}}
diff --git a/themes/default/layouts/partials/meta-expiry-date.html b/themes/default/layouts/partials/meta-expiry-date.html
deleted file mode 100644
index 275e04e..0000000
--- a/themes/default/layouts/partials/meta-expiry-date.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{{ $diff := now.Sub .ExpiryDate }}
-{{ $duration := lang.FormatNumberCustom 0 (math.Round (mul (div $diff.Hours 24) -1)) }}
-
-<expiry-date>
- <time
- datetime= "{{ .ExpiryDate | time.Format "2006-01-02T15:04:05Z" }}"
- title="Self destructs within {{ $duration }} days ({{ .ExpiryDate | time.Format "Monday, January 2 2006 at 15:04:05 MST" }})">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/trash-2.svg")) }}
- {{ .ExpiryDate | time.Format "Jan 2 2006" }}
- </time>
-</expiry-date>
diff --git a/themes/default/layouts/partials/meta-expirydate.html b/themes/default/layouts/partials/meta-expirydate.html
new file mode 100644
index 0000000..1feefd1
--- /dev/null
+++ b/themes/default/layouts/partials/meta-expirydate.html
@@ -0,0 +1,20 @@
+{{- if .ExpiryDate -}}
+ {{- $expired := and .ExpiryDate (ge now.Unix .ExpiryDate.Unix) -}}
+ {{- $diff := now.Sub .ExpiryDate -}}
+ {{- $duration := lang.FormatNumberCustom 0 (math.Round (mul (div $diff.Hours 24) -1)) -}}
+ {{- $date := .ExpiryDate | time.Format "Monday, January 2 2006 at 15:04:05 MST" -}}
+ {{- $title := print "Self destructs within" " " $duration " " "days" " " "(" $date ")" -}}
+ {{- if $expired -}}
+ {{- $title = print "Self destructed" " " $date -}}
+ {{- end -}}
+
+ <meta-expiry
+ title="{{ $title }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/trash-2.svg")) -}}
+ <time datetime= "{{- .ExpiryDate | time.Format "2006-01-02T15:04:05Z" -}}">
+ {{- .ExpiryDate | time.Format "Jan 2 2006" -}}
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </time>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </meta-expiry>
+{{- end -}}
diff --git a/themes/default/layouts/partials/meta-handle.html b/themes/default/layouts/partials/meta-handle.html
index ee7f975..ee0cc50 100644
--- a/themes/default/layouts/partials/meta-handle.html
+++ b/themes/default/layouts/partials/meta-handle.html
@@ -1,13 +1,25 @@
-{{- with .Params.feed.domain -}}
-<a
- title="{{ . }}"
- href="http://{{ . }}">
- @{{ . -}}
-</a>
-{{- else -}}
-<a
- title="{{ partial "author-user.html" . }}@{{ (urls.Parse .Site.BaseURL).Host }}"
- href="{{ .Site.BaseURL }}/{{ partial "author-user.html" . }}/#">
- @{{ (urls.Parse .Site.BaseURL).Host -}}
-</a>
+{{- $author := .Section -}}
+
+{{- $host := or (urls.Parse ("" | absURL)).Host "localhost" -}}
+{{- $href := print ("" | absURL) "/" $author "/" -}}
+
+{{- $title := print $author "@" $host -}}
+
+{{- with .Params.feed -}}
+ {{- $host = $.Params.feed.domain -}}
+ {{- $href = or $.Params.feed.home (print "http://" $.Params.feed.domain) -}}
+ {{- $title = $.Params.feed.domain -}}
{{- end -}}
+
+<meta-handle>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ <a
+ title="{{ $title }}"
+ href="{{ $href }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/at-sign.svg")) -}}
+ <span>{{- $host -}}</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </a>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-handle>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-menu.html b/themes/default/layouts/partials/meta-menu.html
new file mode 100644
index 0000000..f5e127d
--- /dev/null
+++ b/themes/default/layouts/partials/meta-menu.html
@@ -0,0 +1,23 @@
+{{- $id := partial "card-id.html" . -}}
+
+<menu>
+ <li>
+ <label for="context-metadata-{{ $id }}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-down-circle.svg")) -}}
+ <span>menu</span>
+ </label>
+ </li>
+ <li>
+ <input hidden="" type="checkbox" id="context-metadata-{{ $id }}" />
+ <context-menu position="anchor">
+
+ {{- partial "menu-markdown.html" . -}}
+ {{- partial "menu-plain.html" . -}}
+ {{- partial "menu-embed.html" . -}}
+ {{- partial "menu-permalink.html" . -}}
+ {{- partial "menu-datetime.html" . -}}
+
+ </context-menu>
+ </li>
+</menu>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-name.html b/themes/default/layouts/partials/meta-name.html
index eb5990f..7c2ca61 100644
--- a/themes/default/layouts/partials/meta-name.html
+++ b/themes/default/layouts/partials/meta-name.html
@@ -1,9 +1,17 @@
-<h2>
- <b>
- {{- with .Params.feed.name -}}
- {{ . }}
- {{- else -}}
- {{ partial "author-name.html" . }}
- {{- end -}}
- </b>
-</h2>
+{{- $author := partial "function-authors-data.html" . -}}
+
+{{- $href := print ("" | absURL) "/" $author.user "/" -}}
+{{- $name := $author.name -}}
+{{- $title := $name -}}
+
+{{- with .Params.feed -}}
+ {{- $href = or $.Params.feed.home (print "http://" $.Params.feed.domain) -}}
+ {{- $name = $.Params.feed.name -}}
+ {{- $title = $name -}}
+{{- end -}}
+
+<meta-name title="{{ $title }}">
+ <b><a href="{{ $href }}">{{ $name }}</a></b>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-name>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-read-time.html b/themes/default/layouts/partials/meta-read-time.html
deleted file mode 100644
index b3b1839..0000000
--- a/themes/default/layouts/partials/meta-read-time.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{{- $seconds := mul (div .WordCount 180.0) 60.0 -}}
-{{- $seconds = printf "%.0f" $seconds -}}
-
-{{- if eq $seconds "0" -}}
- {{- $seconds = "1" -}}
-{{- end -}}
-
-<read-time title="Takes {{ $seconds }} second{{- if not (eq $seconds "1") -}}s{{- end }} to read">
- {{ $seconds }} sec
-</read-time>
diff --git a/themes/default/layouts/partials/meta-readtime.html b/themes/default/layouts/partials/meta-readtime.html
new file mode 100644
index 0000000..43b5303
--- /dev/null
+++ b/themes/default/layouts/partials/meta-readtime.html
@@ -0,0 +1,12 @@
+{{- $seconds := mul (div .WordCount 180.0) 60.0 -}}
+{{- $seconds = printf "%.0f" $seconds -}}
+{{- if eq $seconds "0" -}}
+ {{- $seconds = "1" -}}
+{{- end -}}
+
+<meta-readtime title="{{ $seconds }} second{{- if not (eq $seconds "1") -}}s{{- end }} to read">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/eye.svg")) }}
+ <span>{{ $seconds }}s read</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-readtime>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-source.html b/themes/default/layouts/partials/meta-source.html
deleted file mode 100644
index a172726..0000000
--- a/themes/default/layouts/partials/meta-source.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{{- $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
-{{- $source := print $author.user "/messages/" .File.LogicalName -}}
-
-<cite>
-{{- with .Params.feed.raw -}}
-<a title="{{ $.Site.BaseURL }}/{{ . }}" href="{{ $.Site.BaseURL }}/{{ . }}">
-{{- else -}}
-<a
- href="{{ .Site.BaseURL }}/{{ partial "function-paths-markdown.html" }}/{{ $source }}"
- title="{{ .Site.BaseURL }}/{{ partial "function-paths-markdown.html" }}/{{ $source }}">
-{{- end -}}
- raw
-</a>
-</cite>
diff --git a/themes/default/layouts/partials/title.html b/themes/default/layouts/partials/meta-title.html
index 988167f..988167f 100644
--- a/themes/default/layouts/partials/title.html
+++ b/themes/default/layouts/partials/meta-title.html
diff --git a/themes/default/layouts/partials/meta-unlisted.html b/themes/default/layouts/partials/meta-unlisted.html
new file mode 100644
index 0000000..df67e4e
--- /dev/null
+++ b/themes/default/layouts/partials/meta-unlisted.html
@@ -0,0 +1,7 @@
+{{- if .Params.Unlisted -}}
+ <meta-unlisted title="This message is off the record">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/eye-off.svg")) -}}
+ <span>unlisted</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </meta-unlisted>
+{{- end -}}
diff --git a/themes/default/layouts/partials/meta-via.html b/themes/default/layouts/partials/meta-via.html
new file mode 100644
index 0000000..c34ca73
--- /dev/null
+++ b/themes/default/layouts/partials/meta-via.html
@@ -0,0 +1,13 @@
+{{- $author := .Section -}}
+
+{{- if .Params.feed -}}
+ <a
+ data-hover=""
+ data-anchored="via"
+ href="{{ "" | absURL }}/{{ $author }}/feeds/#feeds"
+ title="{{ $author }}@{{ or (urls.Parse ("" | absURL)).Host "localhost" }}"
+ >
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/rss.svg")) -}}
+ via @{{ $author }}
+ </a>
+{{- end -}}
diff --git a/themes/default/layouts/partials/meta-view.html b/themes/default/layouts/partials/meta-view.html
new file mode 100644
index 0000000..33aee6b
--- /dev/null
+++ b/themes/default/layouts/partials/meta-view.html
@@ -0,0 +1,12 @@
+{{- $href := or .Params.Feed.link .Permalink -}}
+
+<meta-view>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ <a href="{{ $href }}" title="{{- partial "meta-title.html" . -}}">
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/external-link.svg")) -}}
+ <span>view</span>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </a>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-view>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/meta-word-count.html b/themes/default/layouts/partials/meta-word-count.html
deleted file mode 100644
index d4a4065..0000000
--- a/themes/default/layouts/partials/meta-word-count.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") }}
-{{ $limit := $author.wordlimit }}
-{{ $wordLimit := gt .WordCount $limit }}
-{{ $overLimit := sub .WordCount $limit }}
-
-<word-limit title="{{- if $wordLimit -}}{{ $overLimit }} words over the limit{{ else }} {{ .WordCount }} words {{ end }}">
- <word-count>
- {{- if $wordLimit -}}
- <em>{{ .WordCount }}</em>
- {{- else -}}
- {{ .WordCount }}
- {{- end -}}
- </word-count>/{{ $limit }} words
-</word-limit>
diff --git a/themes/default/layouts/partials/meta-wordcount.html b/themes/default/layouts/partials/meta-wordcount.html
new file mode 100644
index 0000000..b6ec95e
--- /dev/null
+++ b/themes/default/layouts/partials/meta-wordcount.html
@@ -0,0 +1,33 @@
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $limit := $author.wordlimit -}}
+{{- $wordLimit := gt .WordCount $limit -}}
+{{- $overLimit := sub .WordCount $limit -}}
+{{- $bitCount := lang.FormatNumberCustom 0 (len .Content) -}}
+
+<meta-wordcount
+title="
+{{- if $wordLimit -}}
+ {{ $overLimit }} words over the limit
+ {{- else -}}
+ {{ .WordCount }} words
+{{- end }}
+{{ $bitCount }} bits
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+">
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ <word-limit>
+ {{- safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/notes.svg")) -}}
+ <word-count>
+ {{- if $wordLimit -}}
+ <em>{{ .WordCount }}</em>
+ {{- else -}}
+ <sup>{{ .WordCount }}</sup>
+ {{- end -}}
+ /<sub>{{ $limit }}</sub> words
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </word-count>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+ </word-limit>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+</meta-wordcount>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/partials/navigator-left.html b/themes/default/layouts/partials/navigator-left.html
index 41aaa2e..1a3bd1d 100644
--- a/themes/default/layouts/partials/navigator-left.html
+++ b/themes/default/layouts/partials/navigator-left.html
@@ -6,7 +6,7 @@
<a id="nav-left-{{ path.Base .Identifier }}" href="{{ .URL | absURL }}">
<span>{{ .Name }}</span>
{{ with .Identifier }}
- {{ $icon := print (partial "function-paths-static.html") "/icons/" . ".svg" }}
+ {{ $icon := print (partial "function-paths.html").static "/icons/" . ".svg" }}
{{ safeHTML (readFile $icon) }}
{{ end }}
</a>
diff --git a/themes/default/layouts/partials/navigator-middle-walk.html b/themes/default/layouts/partials/navigator-middle-walk.html
deleted file mode 100644
index a0832a8..0000000
--- a/themes/default/layouts/partials/navigator-middle-walk.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{{ if .Context.Site.Menus.main }}
- {{ range .Context.Site.Menus.main }}
- <icon-navigator hidden>
- <icon-button>
- <a id="nav-middle-{{ path.Base .Identifier }}" href="{{ .URL | absURL }}">
- {{ with .Identifier }}
- {{ $icon := print (partial "function-paths-static.html") "/icons/" . ".svg" }}
- {{ safeHTML (readFile $icon) }}
- {{ end }}
- <small>{{ delimit (first 1 (split .Name " ")) " " }}</small>
- </a>
- </icon-button>
- </icon-navigator>
- {{ end }}
-{{ end }}
diff --git a/themes/default/layouts/partials/navigator-middle.html b/themes/default/layouts/partials/navigator-middle.html
index 418b237..7259b43 100644
--- a/themes/default/layouts/partials/navigator-middle.html
+++ b/themes/default/layouts/partials/navigator-middle.html
@@ -1,22 +1,29 @@
-{{ $id := .Id }}
-{{ $href := .Href }}
+{{- $href := or .Href "#" -}}
+{{- $id := or .Id "top" -}}
+{{- $label := title $id -}}
+{{- $icon := readFile (print (partial "function-paths.html").static "/icons/feather/arrow-up.svg") -}}
+{{- $refresh := readFile (print (partial "function-paths.html").static "/icons/feather/refresh-cw.svg") -}}
+
+{{- with .Icon -}}
+ {{- $icon = readFile (print (partial "function-paths.html").static "/icons/feather/" . ".svg") -}}
+{{- end -}}
+
+{{- with .IconLabel -}}
+ {{- $label = . -}}
+{{- end -}}
<nav>
<icon-button>
<a
- id="{{ or $id "top" }}"
- href="{{ or $href "#" }}"
+ data-update=""
+ id="{{ $id }}"
+ href="{{ $href }}"
+ target="_self"
>
- {{ with .Icon }}
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/" . ".svg")) }}
- {{ else }}
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-up.svg")) }}
- {{ end }}
- {{ with .IconLabel }}
- <small>{{ . }}</small>
- {{ else }}
- <small>Top</small>
- {{ end }}
+ {{ safeHTML $icon }}
+ {{ safeHTML $refresh }}
+ <small>{{ $label }}</small>
+ <small>Update</small>
</a>
</icon-button>
@@ -29,29 +36,40 @@
{{ end }}
</section>
- {{ partial "navigator-middle-walk.html" . }}
+ {{ if .Context.Site.Menus.main }}
+ {{ range .Context.Site.Menus.main }}
+ <icon-navigator hidden="">
+ <icon-button>
+ <a id="nav-middle-{{ path.Base .Identifier }}" href="{{ .URL | absURL }}">
+ {{ with .Identifier }}
+ {{ $icon := print (partial "function-paths.html").static "/icons/" . ".svg" }}
+ {{ safeHTML (readFile $icon) }}
+ {{ end }}
+ <small>{{ delimit (first 1 (split .Name " ")) " " }}</small>
+ </a>
+ </icon-button>
+ </icon-navigator>
+ {{ end }}
+ {{ end }}
- <search-entry id="search-frame">
- <form
- id="search-form"
- action="https://lite.duckduckgo.com/lite/">
- <input required
- id="search-input"
- name="q"
- value=""
- type="search"
- autocomplete="off"
- spellcheck="false"
+ <search-box>
+ <form role="search" action="https://lite.duckduckgo.com/lite/">
+ <input
aria-autocomplete="list"
aria-label="search input"
+ autocomplete="off"
+ id="search"
+ name="q"
+ required=""
+ spellcheck="false"
+ type="search"
+ value=""
/>
- <button id="search-submit">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/search.svg")) }}
+ <button type="submit">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/search.svg")) }}
<small>Search</small>
</button>
- <ul hidden id="search-results"></ul>
+ <ul hidden=""></ul>
</form>
- </search-entry>
- </nav>
-
-<navigation-separator><hr hidden></navigation-separator>
+ </search-box>
+</nav>
diff --git a/themes/default/layouts/partials/navigator-right-default.html b/themes/default/layouts/partials/navigator-right-default.html
deleted file mode 100644
index 44b4bbd..0000000
--- a/themes/default/layouts/partials/navigator-right-default.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{{- partial "author-list.html" . -}}
-{{- range first 1 (where .Site.Pages "Params.Author" .Site.Author.default.webring) -}}
- {{- partial "web-ring.html" . -}}
-{{- end -}}
diff --git a/themes/default/layouts/partials/navigator-right.html b/themes/default/layouts/partials/navigator-right.html
index abe0d28..c2e6f4c 100644
--- a/themes/default/layouts/partials/navigator-right.html
+++ b/themes/default/layouts/partials/navigator-right.html
@@ -1,3 +1,7 @@
-{{- partial "author-list.html" . -}}
-{{- partial "gallery-images.html" . -}}
-{{- partial "web-ring.html" . -}}
+{{- partial "author-list.html" . -}}
+
+{{- if (in (slice "page" "section") .Page.Kind) -}}
+ {{- partial "gallery.html" . -}}
+ {{- partial "following-list.html" . -}}
+ {{- partial "webring.html" . -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/navigator.css.html b/themes/default/layouts/partials/navigator.css.html
new file mode 100644
index 0000000..7485408
--- /dev/null
+++ b/themes/default/layouts/partials/navigator.css.html
@@ -0,0 +1,19 @@
+icon-navigator a[href="{{ "" | absURL }}{{ .Link }}"],
+column-base[position="left"] nav a[href="{{ "" | absURL }}{{ .Link }}"] {
+ font-weight: 700;
+}
+
+column-base[position="left"] nav a[href="{{ "" | absURL }}{{ .Link }}"] {
+ background-color: #f0f6ff;
+ background-color: var(--hover-background-alternate);
+}
+
+icon-navigator a[href="{{ "" | absURL }}{{ .Link }}"] svg {
+ fill: #cce0ff;
+ fill: var(--icon-hover-background);
+}
+
+icon-navigator a[href="{{ "" | absURL }}{{ .Link }}"]:focus svg {
+ fill: #cce0ff;
+ fill: var(--icon-focus-background);
+}
diff --git a/themes/default/layouts/partials/pagination.html b/themes/default/layouts/partials/pagination.html
index d9360c4..e64bfcf 100644
--- a/themes/default/layouts/partials/pagination.html
+++ b/themes/default/layouts/partials/pagination.html
@@ -1,75 +1,50 @@
{{- with .Paginator -}}
- <paginator-navigation{{ if eq .TotalPages 1 }} hidden {{ end }}>
- {{ if and .HasPrev .First }}
- <a
- href="{{ .First.URL }}"
- aria-label="First"
- title="First"
- role="button">
- First
- </a>
- {{ else }}
- <button
- data-invisible
- title="Disabled"
- aria-label="First">
- First
- </button>
- {{- end -}}
+ {{- $firstTitle := "hidden" -}}
+ {{- $prevTitle := "hidden" -}}
+ {{- $nextTitle := "hidden" -}}
+ {{- $lastTitle := "hidden" -}}
+ {{- $firstHref := "/" -}}
+ {{- $prevHref := "/" -}}
+ {{- $nextHref := "/" -}}
+ {{- $lastHref := "/" -}}
- {{ with .Prev }}
- <a
- href="{{ .URL }}"
- aria-label="Back"
- title="Back"
- role="button">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-left.svg")) }}
- Back
- </a>
- {{ else }}
- <button
- data-invisible
- title="Disabled"
- aria-label="Back">
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-left.svg")) }}
- Back
- </button>
- {{- end -}}
+ {{- if and .HasPrev .First -}}
+ {{- $firstHref = .First.URL | absURL -}}
+ {{- $firstTitle = "Newest" -}}
+ {{- end -}}
- {{ if .Next }}
- <a
- href="{{ .Next.URL }}"
- aria-label="Next"
- title="Next"
- role="button">
- Next
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-right.svg")) }}
- </a>
- {{ else }}
- <button
- data-invisible
- title="Disabled"
- aria-label="Next">
- Next
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/arrow-right.svg")) }}
- </button>
- {{- end -}}
+ {{- with .Prev -}}
+ {{- $prevHref = .URL | absURL -}}
+ {{- $prevTitle = "Newer" -}}
+ {{- end -}}
- {{ if and .HasNext .Last }}
- <a
- href="{{ .Last.URL }}"
- aria-label="Last"
- title="Next"
- role="button">
- Last
- </a>
- {{ else }}
- <button
- data-invisible
- title="Disabled"
- aria-label="Last">
- Last
- </button>
- {{- end -}}
- </paginator-navigation>
-{{ end }}
+ {{- if .Next -}}
+ {{- $nextHref = .Next.URL | absURL -}}
+ {{- $nextTitle = "Older" -}}
+ {{- end -}}
+
+ {{- if and .HasNext .Last -}}
+ {{- $lastHref = .Last.URL | absURL -}}
+ {{- $lastTitle = "Oldest" -}}
+ {{- end -}}
+
+ <nav{{ if le .TotalPages 1 }} hidden="" {{ end }} data-type="pagination">
+ <a rel="first" href="{{ $firstHref }}" title="{{ $firstTitle }}" >
+ <span>{{ $firstTitle }}</span>
+ </a>
+
+ <a rel="prev" href="{{ $prevHref }}" title="{{ $prevTitle }}">
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-left.svg")) }}
+ <span>{{ $prevTitle }}</span>
+ </a>
+
+ <a rel="next" href="{{ $nextHref }}" title="{{ $nextTitle }}">
+ <span>{{ $nextTitle }}</span>
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/arrow-right.svg")) }}
+ </a>
+
+ <a rel="last" href="{{ $lastHref }}" title="{{ $lastTitle }}" data-count="{{ .TotalPages }}">
+ <span>{{ $lastTitle }}</span>
+ </a>
+ </nav>
+{{- end -}}
diff --git a/themes/default/layouts/partials/profile-tabs.html b/themes/default/layouts/partials/profile-tabs.html
index 4f2c3fb..1ca632b 100644
--- a/themes/default/layouts/partials/profile-tabs.html
+++ b/themes/default/layouts/partials/profile-tabs.html
@@ -1,13 +1,44 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") }}
-
-<tab-list>
- <aside>
- <a href="{{ .Site.BaseURL }}/{{ $author.user }}">Messages</a>
- <a href="{{ .Site.BaseURL }}/{{ $author.user }}/feeds/">Feeds</a>
- <a href="{{ .Site.BaseURL }}/{{ $author.user }}/media/">Media</a>
- <a href="{{ .Site.BaseURL }}/{{ $author.user }}/likes/">Likes</a>
- {{- if .Site.BuildDrafts }}
- <a href="{{ .Site.BaseURL }}/{{ $author.user }}/drafts/">Drafts</a>
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $path := print ("" | absURL) "/" $author.user -}}
+
+<tab-bar>
+ <nav>
+ <a
+ data-label="{{ $label := "Posts" }}{{ $label }}"
+ href="{{ $path }}/#{{ lower $label }}">
+ {{ $label }}
+ <span data-scroll="" id="{{ lower $label }}"></span>
+ </a>
+
+ <a
+ data-label="{{ $label := "Feeds" }}{{ $label }}"
+ href="{{ $path }}/{{ lower $label }}/#{{ lower $label }}">
+ {{ $label }}
+ <span data-scroll="" id="{{ lower $label }}"></span>
+ </a>
+
+ <a
+ data-label="{{ $label := "Media" }}{{ $label }}"
+ href="{{ $path }}/{{ lower $label }}/#{{ lower $label }}">
+ {{ $label }}
+ <span data-scroll="" id="{{ lower $label }}"></span>
+ </a>
+
+ <a
+ data-label="{{ $label := "Marks" }}{{ $label }}"
+ href="{{ $path }}/{{ lower $label }}/#{{ lower $label }}">
+ {{ $label }}
+ <span data-scroll="" id="{{ lower $label }}"></span>
+ </a>
+
+ {{- if $.Site.BuildDrafts }}
+ <a
+ data-draft=""
+ data-label="{{ $label := "Drafts" }}{{ $label }}"
+ href="{{ $path }}/{{ lower $label }}/#{{ lower $label }}">
+ {{ $label }}
+ <span data-scroll="" id="{{ lower $label }}"></span>
+ </a>
{{- end }}
- </aside>
-</tab-list>
+ </nav>
+</tab-bar>
diff --git a/themes/default/layouts/partials/profile.html b/themes/default/layouts/partials/profile.html
index 1f01b23..e0c339b 100644
--- a/themes/default/layouts/partials/profile.html
+++ b/themes/default/layouts/partials/profile.html
@@ -1,52 +1,42 @@
-{{- $author := index .Site.Data ((or .Params.author .Site.Author.default.user) | default "default") -}}
+{{- $author := partial "function-authors-data.html" . -}}
-<micro-header>
+<profile-box>
+ <picture data-type="banner">
+ {{ partial "author-header.html" . }}
+ </picture>
- <micro-header-image>
- <picture>
- {{ partial "author-header.html" . }}
- </picture>
- </micro-header-image>
-
- <micro-header-picture>
- <picture>
- {{ partial "author-picture.html" . }}
- </picture>
- </micro-header-picture>
+ <picture data-type="profile">
+ {{ partial "author-picture.html" . }}
+ </picture>
<section>
- <micro-header-title>
+ <aside>
<h2>{{ $author.name }}</h2>
<h3>@{{ $author.user }}</h3>
- </micro-header-title>
- <micro-header-description>
- <p>
- {{ $author.description | markdownify }}
- </p>
- </micro-header-description>
+ </aside>
+ <p>{{ $author.description | markdownify }}</p>
</section>
<footer>
<p>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/map-pin.svg")) }}
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/map-pin.svg")) }}
<span>{{- $author.place | markdownify -}}</span>
</p>
<p>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/globe.svg")) }}
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/globe.svg")) }}
<a href="{{ $author.domain.url }}">
{{- $author.domain.host | markdownify -}}
</a>
</p>
<p>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/clock.svg")) }}
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/feather/clock.svg")) }}
<span>{{- $author.epoch | markdownify -}}</span>
</p>
<p>
- {{ safeHTML (readFile (print (partial "function-paths-static.html") "/icons/feather/user.svg")) }}
- <span><b>{{ with $author.webring.rss }}{{ len . }}{{ else }} 0 {{ end }}</b> Following</span>
+ {{ safeHTML (readFile (print (partial "function-paths.html").static "/icons/tabler/rss.svg")) }}
+ <span><b>{{ with $author.feeds.rss }}{{ len . }}{{ else }} 0 {{ end }}</b> Feeds</span>
</p>
</footer>
+</profile-box>
-</micro-header>
-
-{{ partial "profile-tabs.html" . }}
+{{- partial "profile-tabs.html" . -}}
diff --git a/themes/default/layouts/partials/render-embed.html b/themes/default/layouts/partials/render-embed.html
new file mode 100644
index 0000000..77b6b8f
--- /dev/null
+++ b/themes/default/layouts/partials/render-embed.html
@@ -0,0 +1,31 @@
+{{- $pageContext := . -}}
+{{- $format := "embed.html" -}}
+
+{{- $page := print "public/" (strings.TrimPrefix
+ $pageContext.Page.Site.BaseURL
+ $pageContext.Page.Permalink
+ ) $format
+-}}
+
+{{- $modified := partial "function-page-modified.html"
+ (dict
+ "Context" $pageContext
+ "Format" $format
+ )
+-}}
+
+{{- with $embed := resources.Get $page -}}
+ {{- if (in $embed.Content "/data/media/404.png") -}}
+ {{- $modified = true -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if $modified -}}
+ {{- $pageContext.Render "summary" -}}
+{{- else -}}
+ {{- with $embed := resources.Get $page -}}
+ {{- range $chunks := after 1 (split ($embed.Content) "</head>") -}}
+ {{- $chunks | safeHTML -}}
+ {{- end -}}
+ {{- end -}}
+{{- end -}}
diff --git a/themes/default/layouts/partials/site-title.html b/themes/default/layouts/partials/site-title.html
deleted file mode 100644
index afa17fa..0000000
--- a/themes/default/layouts/partials/site-title.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{{ $author := index .Site.Data ((or .Params.author .Site.Author.default.title) | default "default") }}
-
-{{- if not (eq .Title $.Site.Title) -}}
- {{- with or .Title .Summary -}}
- {{ . }} &mdash;
- {{ end }}
-{{- end -}}
-
-{{- with $.Site.Title -}}
- {{ if $.IsHome -}}
- {{ . }}
- {{- else -}}
- {{ $author.blogtitle }}
- {{- end -}}
-{{- end -}}
diff --git a/themes/default/layouts/partials/styles-navigator.html b/themes/default/layouts/partials/styles-navigator.html
deleted file mode 100644
index 80ebcd6..0000000
--- a/themes/default/layouts/partials/styles-navigator.html
+++ /dev/null
@@ -1,14 +0,0 @@
-icon-navigator a[href="{{ "" | absURL }}{{ .Link }}"],
-column-left nav a[href="{{ "" | absURL }}{{ .Link }}"] {
- font-weight: 700;
-}
-
-column-left nav a[href="{{ "" | absURL }}{{ .Link }}"] {
- background-color: #f0f6ff;
- background-color: var(--hover-background-alternate);
-}
-
-icon-navigator a[href="{{ "" | absURL }}{{ .Link }}"] svg {
- fill: #e5f0ff;
- fill: var(--active-background-alternate);
-}
diff --git a/themes/default/layouts/partials/tags.html b/themes/default/layouts/partials/tags.html
index d601b27..29202d0 100644
--- a/themes/default/layouts/partials/tags.html
+++ b/themes/default/layouts/partials/tags.html
@@ -1,5 +1,19 @@
-{{- with .Params.tags }}
- {{- range $tags, $tag := sort . }}
- <a href="{{ "tags/" | relURL }}{{ $tag | urlize }}/">#{{ $tag }}</a>
- {{ end }}
-{{ end }}
+{{- $format := .Format -}}
+{{- $pageContext := .Context -}}
+{{- $path := "tags/" -}}
+{{- $url := $path | relURL -}}
+
+{{- with $pageContext.Params.tags -}}
+ {{- range $tags, $tag := sort $pageContext.Params.tags -}}
+ {{- if (eq $format "rss") -}}
+ {{- $url = $path | absURL -}}
+ {{- end -}}
+
+ {{- $link := print $url ((lower $tag) | urlize) "/" -}}
+ {{- print "[#" (lower $tag) "](" $link ")" | markdownify -}}
+
+ {{- if (eq $format "rss") -}}&nbsp;{{- end }}
+ {{ end -}}
+{{- else -}}
+ <a href="{{ "tags/" | absURL }}">#untagged</a>
+{{- end -}}
diff --git a/themes/default/layouts/partials/video-container.html b/themes/default/layouts/partials/video-container.html
index 79df910..9e28e3d 100644
--- a/themes/default/layouts/partials/video-container.html
+++ b/themes/default/layouts/partials/video-container.html
@@ -1,48 +1,74 @@
{{- $cache := "" -}}
+{{- $source := "" -}}
+{{- $timestamp := "" -}}
{{- $caption := .Caption -}}
+{{- $remote := .Remote -}}
{{- $public := print "public/" .Source -}}
-{{- $timestamp := print "#t=" .Start "," .End -}}
{{- $immutable := print (.RelURL | humanize | urlize) "-" (.Source | sha256 | truncate 8 "") -}}
{{- $extension := path.Ext .Source -}}
-{{- $fileCache := print $.Author "/media/" $immutable $extension -}}
+{{- $storage := print $.Author "/media/" $immutable $extension -}}
+{{- $cached := fileExists (path.Join "public/" $storage) -}}
-{{- if not (fileExists (path.Join "public/" $fileCache)) -}}
- {{- with $remote := resources.GetRemote .Source -}}
+{{- if .Start -}}
+ {{- $timestamp = print "#t=" .Start -}}
+{{- end -}}
+
+{{- if .End -}}
+ {{- $timestamp = print "#t=," .End -}}
+{{- end -}}
+
+{{- if and .Start .End -}}
+ {{- $timestamp = print "#t=" .Start "," .End -}}
+{{- end -}}
+
+{{- if not $cached -}}
+ {{- with $remote := cond (default true $.Context.Site.Params.site.offline) false (resources.GetRemote .Source) -}}
{{- with .Err -}}
- {{- if fileExists $public -}}
- {{- else -}}
+ {{- warnf "Video fetch %s" . -}}
+ {{- if not (fileExists $public) -}}
{{- $caption = "No local video data found for source" -}}
{{- end -}}
{{- else -}}
+ {{- $cache = $remote | resources.Copy $storage -}}
+ {{- $cache = $cache.Permalink -}}
{{- end -}}
- {{- $cache = . | resources.Copy $fileCache -}}
- {{- $cache = $cache.RelPermalink -}}
{{- else -}}
- {{- $caption = "No remote video data found for source" -}}
+ {{- $caption = "Unable to load remote source data" -}}
{{- end -}}
{{- else -}}
- {{- $cache = resources.Get (path.Join "public/" $fileCache) -}}
- {{- $cache = $cache.Content | resources.FromString $fileCache -}}
- {{- $cache = $cache.RelPermalink -}}
+ {{- with $cache = resources.Get (path.Join "public/" $storage) -}}
+ {{- $cache = print ("" | absURL) (strings.TrimLeft "public" $cache) -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $source = $cache -}}
+
+{{- if .Remote -}}
+ {{- $source = .Source -}}
{{- end -}}
<video-container>
<video
title="{{ .Title }}"
preload="{{ .Preload }}"
+ data-orientation="{{ .Orientation }}"
{{ with .Poster }} poster="{{ . }}" {{ end -}}
{{ with .Width }} width="{{ . }}" {{ end -}}
{{ with .Height }} height="{{ . }}" {{ end -}}
- {{ .Options | safeHTMLAttr }}>
- <source src="{{ or .Source .Cache }}{{ $timestamp }}">
- <p>
- Sorry, your browser does not support embedded videos. Here is a
- <a href="{{ .Source }}">link to the video</a> instead.
- </p>
+ {{- range $value := (split .Options " ") }}
+ {{- printf `%s=""` $value | safeHTMLAttr }}
+ {{ end -}}
+ >
+ <source src="{{ $source }}{{ $timestamp }}" />
+ {{ print "Video: " $caption "." | markdownify }}
+ <p>
+ Sorry, your browser does not support embedded videos. Here is a
+ <a href="{{ .Source }}">link to the video</a> instead.
+ </p>
</video>
<footer>
{{ $caption | markdownify }}
- <br>
+ <br />
Index: {{ with $cache }} {{ print "[Cache](" . ")" | markdownify }} &middot; {{ end }}
{{ print "[Source](" .Source ")" | markdownify }}
</footer>
diff --git a/themes/default/layouts/partials/web-ring.html b/themes/default/layouts/partials/web-ring.html
deleted file mode 100644
index c3d73b4..0000000
--- a/themes/default/layouts/partials/web-ring.html
+++ /dev/null
@@ -1 +0,0 @@
-{{ partial "generate-feeds" . }}
diff --git a/themes/default/layouts/partials/webring.html b/themes/default/layouts/partials/webring.html
new file mode 100644
index 0000000..009e2fc
--- /dev/null
+++ b/themes/default/layouts/partials/webring.html
@@ -0,0 +1,15 @@
+{{- $author := partial "function-authors-data.html" . -}}
+{{- $webring := print "public/" .Section "/webring.html" -}}
+
+<web-ring>
+ <h1>Web Ring</h1>
+ {{ if and $author.feeds.rss (fileExists $webring) }}
+ <aside>
+ {{- (resources.Get $webring).Content | safeHTML -}}
+ </aside>
+ {{ else }}
+ <footer>
+ <code>No items found!</code>
+ </footer>
+ {{ end }}
+</web-ring>
diff --git a/themes/default/layouts/shortcodes/abbr.html b/themes/default/layouts/shortcodes/abbr.html
index 0edff43..61a2e32 100644
--- a/themes/default/layouts/shortcodes/abbr.html
+++ b/themes/default/layouts/shortcodes/abbr.html
@@ -1,7 +1,8 @@
{{- $abbr := default "TL;DR:" (.Get "abbr" | default (.Get 0)) -}}
{{- $title := default "Too long, didn't read" (.Get "title" | default (.Get 1)) -}}
+{{- $hash := print (truncate 4 "" (sha256 .Page.RelPermalink)) (truncate 4 "" (sha256 $abbr)) .Ordinal -}}
-{{- $id := delimit (shuffle (seq 0 20)) "" -}}
-<input hidden type="checkbox" id="abbr-{{ $id }}" />
-<abbr title="{{ $title }}"><label for="abbr-{{ $id }}">{{ $abbr | markdownify }}</label></abbr>
+<input hidden="" type="checkbox" id="abbr-{{ $hash }}" />
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
+<abbr title="{{ $title }}"><label for="abbr-{{ $hash }}">{{ $abbr | markdownify }}</label></abbr>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/animate.html b/themes/default/layouts/shortcodes/animate.html
new file mode 100644
index 0000000..b245596
--- /dev/null
+++ b/themes/default/layouts/shortcodes/animate.html
@@ -0,0 +1,11 @@
+{{- $type := default "default" (.Get "type" | default (.Get 0)) -}}
+{{- $text := default "animate" (.Get "text" | default (.Get 1)) -}}
+
+{{- $letters := split $text "" -}}
+
+<text-animation {{ $type }}="">
+{{- range $value, $letter := $letters -}}
+ <span style="--frame:{{ $value }}">{{ $letter }}</span>
+{{- end -}}
+</text-animation>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/animate.rss.xml b/themes/default/layouts/shortcodes/animate.rss.xml
new file mode 100644
index 0000000..c1f04b8
--- /dev/null
+++ b/themes/default/layouts/shortcodes/animate.rss.xml
@@ -0,0 +1,5 @@
+{{- $type := default "default" (.Get "type" | default (.Get 0)) -}}
+{{- $text := default "animate" (.Get "text" | default (.Get 1)) -}}
+
+<a title="{{ $type }} animation" href="{{ .Page.Permalink }}">{{ $text }}</a>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/attach.html b/themes/default/layouts/shortcodes/attach.html
new file mode 100644
index 0000000..55b5744
--- /dev/null
+++ b/themes/default/layouts/shortcodes/attach.html
@@ -0,0 +1,58 @@
+{{- $url := default "/canory/media/2city12p.pdf" (.Get "url" | default (.Get 0)) -}}
+{{- $title := default "Attachment" (.Get "title" | default (.Get 1)) -}}
+{{- $caption := default $title (.Get "caption" | default (.Get 2)) -}}
+{{- $remote := default "" (.Get "remote" | default (.Get 3)) -}}
+
+{{- $data := "" -}}
+{{- $cache := "" -}}
+{{- $author := .Page.Section -}}
+{{- $extension := path.Ext $url -}}
+{{- $immutable := print $url | anchorize -}}
+{{- $localFile := path.Join "public/" $url -}}
+{{- $type := "application/octet-stream" -}}
+{{- $storage := print $author "/media/" $immutable $extension -}}
+{{- $cached := fileExists (path.Join "public/" $storage) -}}
+
+{{- if not $cached -}}
+ {{- with $remote := cond (default true $.Page.Site.Params.site.offline) false (resources.GetRemote $url) -}}
+ {{- with .Err -}}
+ {{- if not (fileExists $localFile) -}}
+ {{- $caption = "No local attachment data found for source" -}}
+ {{- warnf "Attachment local fetch error: %s" $url -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $type = $remote.MediaType -}}
+ {{- $cache = $remote | resources.Copy $storage -}}
+ {{- $cache = $cache.Permalink -}}
+ {{- end -}}
+ {{- else -}}
+ {{- $caption = "Unable to load remote source data" -}}
+ {{- warnf "Attachment remote fetch error: %s" $url -}}
+ {{- end -}}
+{{- else -}}
+ {{- with $cache = resources.Get (path.Join "public/" $storage) -}}
+ {{- $type = .MediaType -}}
+ {{- $cache = print ("" | absURL) (strings.TrimLeft "public" $cache) -}}
+ {{- end -}}
+{{- end -}}
+
+{{- $data := or $cache $url -}}
+
+{{- if $remote -}}
+ {{- $data = $url -}}
+{{- end -}}
+
+<document-attachment title="{{ $title }}">
+ <object type="{{ $type }}" data="{{ $data }}">
+ <p>
+ Your browser does not support the <code>{{ $type }}</code> plugin. Here's a
+ <a rel="canonical" href="{{ $data }}">link to the file</a> instead.
+ </p>
+ </object>
+ <footer>
+ {{ $caption | markdownify }}
+ <br />
+ Index: {{ with $cache }} {{ print "[Cache](" $cache ")" | markdownify }} &middot; {{ end }}
+ {{ print "[Source](" $url ")" | markdownify }}
+ </footer>
+</document-attachment>
diff --git a/themes/default/layouts/shortcodes/disclose.html b/themes/default/layouts/shortcodes/disclose.html
new file mode 100644
index 0000000..231561b
--- /dev/null
+++ b/themes/default/layouts/shortcodes/disclose.html
@@ -0,0 +1,13 @@
+{{- $text := default "Content Warning: " (.Get "text" | default (.Get 0)) -}}
+{{- $hash := print (truncate 4 "" (sha256 .Page.RelPermalink)) (truncate 4 "" (sha256 $text)) .Ordinal -}}
+
+{{- if gt (len .Inner) 1 -}}
+ {{- $text = .Inner -}}
+{{- end -}}
+
+<details id="disclosure-{{ $hash }}" data-disclosure="">
+ <summary>
+ {{- (or $.Page.Params.title $text) | markdownify }}
+ </summary>
+</details>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/footer.html b/themes/default/layouts/shortcodes/footer.html
deleted file mode 100644
index 579913d..0000000
--- a/themes/default/layouts/shortcodes/footer.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{{- $text := default "Block Quote" (.Get "text" | default (.Get 0)) -}}
-
-{{- if gt (len .Inner) 1 -}}
- {{ $text = .Inner }}
-{{- end -}}
-
-<span>{{ $text | markdownify }}</span>
diff --git a/themes/default/layouts/shortcodes/gist.html b/themes/default/layouts/shortcodes/gist.html
deleted file mode 100644
index c475672..0000000
--- a/themes/default/layouts/shortcodes/gist.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{{- $user := default "gdb" (.Get "user" | default (.Get 0)) -}}
-{{- $gist := default "b6365e79be6052e7531e7ba6ea8caf23" (.Get "gist" | default (.Get 1)) -}}
-{{- $file := default "" (.Get "file" | default (.Get 2)) -}}
-
-<github-gist>
- <script
- src="https://gist.github.com/{{ $user }}/{{ $gist }}.js?file={{ $file }}">
- </script>
-</github-gist>
diff --git a/themes/default/layouts/shortcodes/imgur-video.html b/themes/default/layouts/shortcodes/imgur-video.html
deleted file mode 100644
index a6d637a..0000000
--- a/themes/default/layouts/shortcodes/imgur-video.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{{- $id := default "rQIb4Vw" (.Get "id" | default (.Get 0)) -}}
-{{- $title := default "Imgur Gif" (.Get "title" | default (.Get 1)) -}}
-{{- $caption := default "Imgur Gif" (.Get "caption" | default (.Get 2)) -}}
-
-{{- $options := default "controls autoplay loop muted playsinline"
- (.Get "options" | default (.Get 3))
--}}
-
-{{- partial "video-container.html"
- (dict
- "Author" .Page.Section
- "Caption" $caption
- "Options" $options
- "RelURL" (strings.TrimPrefix .Site.BaseURL .Page.Permalink)
- "Source" (print "https://i.imgur.com/" $id ".mp4")
- )
--}}
diff --git a/themes/default/layouts/shortcodes/imgur.html b/themes/default/layouts/shortcodes/imgur.html
deleted file mode 100644
index f51bcef..0000000
--- a/themes/default/layouts/shortcodes/imgur.html
+++ /dev/null
@@ -1,13 +0,0 @@
-{{- $id := default "mkVcxUi" (.Get "id" | default (.Get 0)) -}}
-
-<imgur-image>
- <blockquote
- class="imgur-embed-pub"
- lang="en"
- data-id="a/{{ $id }}"
- data-context="false"
- >
- <a href="//imgur.com/a/{{ $id }}"></a>
- </blockquote>
- <script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
-</imgur-image>
diff --git a/themes/default/layouts/shortcodes/kbd.html b/themes/default/layouts/shortcodes/kbd.html
index b24fd9d..63af975 100644
--- a/themes/default/layouts/shortcodes/kbd.html
+++ b/themes/default/layouts/shortcodes/kbd.html
@@ -1,3 +1,4 @@
{{- $key := default "Ctrl" (.Get "key" | default (.Get 0)) -}}
<kbd title="{{ $key }}">{{ $key | markdownify }}</kbd>
+{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/link.html b/themes/default/layouts/shortcodes/link.html
new file mode 100644
index 0000000..49cd1c4
--- /dev/null
+++ b/themes/default/layouts/shortcodes/link.html
@@ -0,0 +1,36 @@
+{{- $source := default "https://example.com/" (.Get "source" | default (.Get 0)) -}}
+
+{{- $host := $source -}}
+
+{{- with (urls.Parse $source).Host -}}
+ {{- $host = . -}}
+{{- end -}}
+
+{{- $favicon := partial "function-favicon-domain.html" $host -}}
+
+{{- $image := partial "function-fetch-favicons.html"
+ (dict
+ "Context" .Page
+ "Source" $favicon
+ "Infix" ($host | anchorize)
+ )
+-}}
+
+<link-card>
+ <a href="{{ $source }}">
+ <img
+ loading="lazy"
+ alt="{{ $host }}"
+ title="{{ $host }}"
+ height="{{ $image.Height }}"
+ width="{{ $image.Width }}"
+ src="{{ $image.Permalink }}"
+ />
+ </a>
+ <article>
+ <h2>{{ $host }}</h2>
+ <a href="{{ $source }}">
+ {{ $source }}
+ </a>
+ </article>
+</link-card>
diff --git a/themes/default/layouts/shortcodes/mark.html b/themes/default/layouts/shortcodes/mark.html
index 02af225..1b9ef3d 100644
--- a/themes/default/layouts/shortcodes/mark.html
+++ b/themes/default/layouts/shortcodes/mark.html
@@ -1,5 +1,15 @@
-{{- $text := default "highligted text" (.Get "text" | default (.Get 0)) -}}
-{{- $title := default $text (.Get "title" | default (.Get 1)) -}}
+{{- $text := default "mark" (.Get "text" | default (.Get 0)) -}}
+{{- $title := default "highlighted text" (.Get "title" | default (.Get 1)) -}}
+{{- $id := default "" (.Get "id" | default (.Get 2)) -}}
-<mark title="{{ $title }}">{{ $text }}</mark>
+{{- if gt (len .Inner) 1 -}}
+ {{- $text = trim .Inner "\n" -}}
+{{- end -}}
+
+{{- if $id -}}
+ {{- $id = print "mark:" (truncate 30 "" $text | anchorize | replaceRE `\d` "") -}}
+ {{- $id = printf `id=%q` $id -}}
+{{- end -}}
+
+<mark {{ $id | safeHTMLAttr }} title="{{- $title -}}"><span>{{- $text | markdownify -}}</span></mark>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/markdown.html b/themes/default/layouts/shortcodes/markdown.html
index 3bc8726..f73aa90 100644
--- a/themes/default/layouts/shortcodes/markdown.html
+++ b/themes/default/layouts/shortcodes/markdown.html
@@ -1,4 +1,4 @@
-{{- $link := default (print "/" (partial "function-paths-markdown.html") "/" .Page.File ) (.Get "link" | default (.Get 0)) -}}
+{{- $link := default (print "/" (partial "function-paths.html").markdown "/" .Page.File ) (.Get "link" | default (.Get 0)) -}}
{{- $text := default (path.Base .Page.File) (.Get "text" | default (.Get 1)) -}}
{{- $title := default "" (.Get "title" | default (.Get 2)) -}}
{{- $embed := default false (.Get "embed" | default (.Get 3)) -}}
diff --git a/themes/default/layouts/shortcodes/odysee.html b/themes/default/layouts/shortcodes/odysee.html
index 0f2899e..cca7e9c 100644
--- a/themes/default/layouts/shortcodes/odysee.html
+++ b/themes/default/layouts/shortcodes/odysee.html
@@ -8,7 +8,8 @@
id="odysee-iframe"
src="{{ $url }}"
title="{{ $title }}"
- allowfullscreen>
+ allowfullscreen=""
+ >
</iframe>
<footer>{{ $caption | markdownify }}</footer>
</odysee-video>
diff --git a/themes/default/layouts/shortcodes/pdf.html b/themes/default/layouts/shortcodes/pdf.html
deleted file mode 100644
index 824169b..0000000
--- a/themes/default/layouts/shortcodes/pdf.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{{- $url := default "https://www.gutenberg.org/files/98/old/2city12p.pdf" (.Get "url" | default (.Get 0)) -}}
-{{- $title := default "PDF Document" (.Get "title" | default (.Get 1)) -}}
-{{- $caption := default (print $title " ([Download](" $url "))") (.Get "caption" | default (.Get 2)) -}}
-
-<pdf-container title="{{ $title }}">
- <iframe loading="lazy"
- sandbox="allow-scripts allow-presentation allow-same-origin"
- src="https://docs.google.com/gview?url={{ $url }}&embedded=true">
- </iframe>
- <footer>{{ $caption | markdownify }}</footer>
-</pdf-container>
diff --git a/themes/default/layouts/shortcodes/quote.html b/themes/default/layouts/shortcodes/quote.html
index b933286..e0048d9 100644
--- a/themes/default/layouts/shortcodes/quote.html
+++ b/themes/default/layouts/shortcodes/quote.html
@@ -3,11 +3,9 @@
<q cite="$cite" title="{{ $text | markdownify }}">
{{- if $cite -}}
- <a rel="noopener" href="{{ $cite }}" target="_blank">
- {{- end -}}
- {{ $text | markdownify }}
- {{- if $cite -}}
- </a>
+ {{- print "[" $text "](" $cite ")" | markdownify -}}
+ {{- else -}}
+ {{- $text | markdownify -}}
{{- end -}}
</q>
{{- /* This comment removes trailing newlines and white spaces. */ -}}
diff --git a/themes/default/layouts/shortcodes/react.html b/themes/default/layouts/shortcodes/react.html
new file mode 100644
index 0000000..ea96101
--- /dev/null
+++ b/themes/default/layouts/shortcodes/react.html
@@ -0,0 +1,30 @@
+{{- $text := default "react" (.Get "text" | default (.Get 0)) -}}
+{{- $source := default "" (.Get "source" | default (.Get 1)) -}}
+{{- $title := default $text (.Get "title" | default (.Get 2)) -}}
+{{- $alternate := default $title (.Get "alternate" | default (.Get 3)) -}}
+
+{{- $author := .Page.Section -}}
+
+{{- $image := partial "function-caches-images.html"
+ (dict
+ "Context" .Page
+ "Source" $source
+ "Fit" "100x100"
+ "Target" (print (partial "function-paths.html").media "/" $author "/")
+ "Copy" (print (partial "function-paths.html").media "/" $author "/react-" (path.Base $source))
+ "AlternateCopy" (print (partial "function-paths.html").media "/" $author "/react-" (path.BaseName $source) ".webp")
+ )
+-}}
+
+<tool-tip data-type="reaction" title="{{ $title }}">
+ {{ $text | markdownify }}
+ <a href="{{ $image.Permalink }}">
+ <img
+ width="{{ $image.Width }}"
+ height="{{ $image.Height }}"
+ title="{{ $title }}"
+ alt="{{ $alternate }}"
+ src="{{ $image.Permalink }}"
+ />
+ </a>
+</tool-tip>
diff --git a/themes/default/layouts/shortcodes/react.rss.xml b/themes/default/layouts/shortcodes/react.rss.xml
new file mode 100644
index 0000000..0e03675
--- /dev/null
+++ b/themes/default/layouts/shortcodes/react.rss.xml
@@ -0,0 +1,19 @@
+{{- $text := default "react" (.Get "text" | default (.Get 0)) -}}
+{{- $source := default "" (.Get "source" | default (.Get 1)) -}}
+{{- $title := default $text (.Get "title" | default (.Get 2)) -}}
+{{- $alternate := default $title (.Get "alternate" | default (.Get 3)) -}}
+
+{{- $author := .Page.Section -}}
+
+{{- $image := partial "function-caches-images.html"
+ (dict
+ "Context" .Page
+ "Source" $source
+ "Fit" "100x100"
+ "Target" (print (partial "function-paths.html").media "/" $author "/")
+ "Copy" (print (partial "function-paths.html").media "/" $author "/react-" (path.Base $source))
+ "AlternateCopy" (print (partial "function-paths.html").media "/" $author "/react-" (path.BaseName $source) ".webp")
+ )
+-}}
+
+{{ $text | markdownify }} (<a title="{{ $title }}" href="{{ $image.Permalink }}">reaction</a>)
diff --git a/themes/default/layouts/shortcodes/reddit.html b/themes/default/layouts/shortcodes/reddit.html
deleted file mode 100644
index 10ef0b9..0000000
--- a/themes/default/layouts/shortcodes/reddit.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{{- $path := default "linux/comments/aeufh6/vlc_has_now_reached_3_billions_downloads_and/edsvibz" (.Get "path" | default (.Get 0)) -}}
-{{- $depth := default "2" (.Get "depth" | default (.Get 1)) -}}
-{{- $context := default "1" (.Get "context" | default (.Get 2)) -}}
-{{- $theme := default "light" (.Get "theme" | default (.Get 3)) -}}
-{{- $showtitle := default "true" (.Get "showtitle" | default (.Get 4)) -}}
-{{- $showedits := default "false" (.Get "showedits" | default (.Get 5)) -}}
-{{- $showmedia := default "false" (.Get "showmedia" | default (.Get 6)) -}}
-{{- $showmore := default "false" (.Get "showmore" | default (.Get 7)) -}}
-
-<reddit-comment>
- <iframe loading="lazy"
- id="reddit-embed"
- src="https://www.redditmedia.com/r/{{ trim $path "/" }}/
-?depth={{ $depth }}
-&amp;embed=true
-&amp;showmore={{ $showmore }}
-&amp;showtitle={{ $showtitle }}
-&amp;context={{ $context }}
-&amp;showmedia={{ $showmedia }}
-&amp;theme={{ $theme }}
-&amp;showedits={{ $showedits }}
-&amp;created={{ now.Format "2006-01-02T15:04:05Z" }}"
- sandbox="allow-scripts allow-same-origin allow-popups"
- style="border: none;"
- height="452"
- width="640"
- scrolling="no"
- ></iframe>
-</reddit-comment>
diff --git a/themes/default/layouts/shortcodes/self.html b/themes/default/layouts/shortcodes/self.html
index 2f0d7eb..6036e07 100644
--- a/themes/default/layouts/shortcodes/self.html
+++ b/themes/default/layouts/shortcodes/self.html
@@ -10,6 +10,7 @@
<self-embed>
<iframe
height="165"
+ scrolling="no"
sandbox="{{ $sandbox }}"
src="{{ .Site.BaseURL }}{{ $url }}"
title="{{ $title }}"
diff --git a/themes/default/layouts/shortcodes/spoiler.html b/themes/default/layouts/shortcodes/spoiler.html
index 9267876..9c5e59a 100644
--- a/themes/default/layouts/shortcodes/spoiler.html
+++ b/themes/default/layouts/shortcodes/spoiler.html
@@ -1,9 +1,13 @@
{{- $text := default "This is a spoiler." (.Get "text" | default (.Get 0)) -}}
{{- $title := default "Click to show/hide text." (.Get "title" | default (.Get 1)) -}}
+{{- $hash := print (truncate 4 "" (sha256 .Page.RelPermalink)) (truncate 4 "" (sha256 $text)) .Ordinal -}}
-{{ if gt (len .Inner) 1 }}
- {{ $text = .Inner }}
-{{ end }}
+{{- if gt (len .Inner) 1 -}}
+ {{- $text = .Inner -}}
+{{- end -}}
-<input hidden type="checkbox" id="spoiler-text-{{ md5 $text }}" />
-<s title="{{ $title }}"><label for="spoiler-text-{{ md5 $text }}">{{ $text | markdownify }}</label></s>
+<input hidden="" type="checkbox" id="spoiler-text-{{ $hash }}" />
+
+<s title="{{ $title }}">
+ <label for="spoiler-text-{{ $hash }}">{{ $text | markdownify }}</label>
+</s>
diff --git a/themes/default/layouts/shortcodes/spoiler.rss.xml b/themes/default/layouts/shortcodes/spoiler.rss.xml
index 73dde8a..adbce7b 100644
--- a/themes/default/layouts/shortcodes/spoiler.rss.xml
+++ b/themes/default/layouts/shortcodes/spoiler.rss.xml
@@ -5,4 +5,6 @@
{{ $text = .Inner }}
{{ end }}
-<s title="{{ $title }}"><label for="spoiler-text-{{ md5 $text }}">{{ $text | markdownify }}</label></s>
+<s title="{{ $title }}">
+ <label>{{ $text | markdownify }}</label>
+</s>
diff --git a/themes/default/layouts/shortcodes/tweet.html b/themes/default/layouts/shortcodes/tweet.html
deleted file mode 100644
index faf1f00..0000000
--- a/themes/default/layouts/shortcodes/tweet.html
+++ /dev/null
@@ -1,18 +0,0 @@
-{{- $user := default "jack" (.Get "user" | default (.Get 0)) -}}
-{{- $status := default "20" (.Get "status" | default (.Get 1)) -}}
-{{- $caption := default "Twitter Tweet" (.Get "caption" | default (.Get 2)) -}}
-
-<twitter-tweet>
- <blockquote class="twitter-tweet">
- <a href="https://twitter.com/{{ $user }}/status/{{ $status }}">
- https://twitter.com/{{ $user }}/status/{{ $status }}
- </a>
- </blockquote>
- <script
- async
- src="https://platform.twitter.com/widgets.js"
- charset="utf-8">
- </script>
-</twitter-tweet>
-
-<footer>{{ $caption }}</footer>
diff --git a/themes/default/layouts/shortcodes/version.html b/themes/default/layouts/shortcodes/version.html
new file mode 100644
index 0000000..2e3eda8
--- /dev/null
+++ b/themes/default/layouts/shortcodes/version.html
@@ -0,0 +1,20 @@
+{{- $version := "0.11.12" -}}
+{{- $generator := "0.110.0" -}}
+
+{{- $number := default false (.Get "number" | default (.Get 0)) -}}
+{{- $clone := default false (.Get "clone" | default (.Get 1)) -}}
+{{- $hugo := default false (.Get "hugo" | default (.Get 2)) -}}
+
+{{- if $number -}}
+ {{ $version }}
+{{- end -}}
+
+{{- if $hugo -}}
+ {{ $generator }}
+{{- end -}}
+
+{{- if $clone -}}
+```shell
+git clone --branch {{ $version }} https://www.thedroneely.com/git/thedroneely/canory
+```
+{{- end -}}
diff --git a/themes/default/layouts/shortcodes/asciicast.html b/themes/default/layouts/shortcodes/video-ascii.html
index 10da091..10da091 100644
--- a/themes/default/layouts/shortcodes/asciicast.html
+++ b/themes/default/layouts/shortcodes/video-ascii.html
diff --git a/themes/default/layouts/shortcodes/video-imgur.html b/themes/default/layouts/shortcodes/video-imgur.html
new file mode 100644
index 0000000..2edb9a4
--- /dev/null
+++ b/themes/default/layouts/shortcodes/video-imgur.html
@@ -0,0 +1,14 @@
+{{- $id := default "rQIb4Vw" (.Get "id" | default (.Get 0)) -}}
+{{- $title := default "Imgur Gif" (.Get "title" | default (.Get 1)) -}}
+{{- $caption := default $title (.Get "caption" | default (.Get 2)) -}}
+
+{{- $options := default "controls autoplay loop muted playsinline"
+ (.Get "options" | default (.Get 3))
+-}}
+
+{{- $source := print "https://i.imgur.com/" $id ".mp4" -}}
+
+{{- printf `{{< video source="%s" title="%s" caption="%s" options="%s" >}}`
+ $source $title $caption $options
+ | .Page.RenderString
+-}}
diff --git a/themes/default/layouts/shortcodes/video.html b/themes/default/layouts/shortcodes/video.html
index bb49f8c..289559c 100644
--- a/themes/default/layouts/shortcodes/video.html
+++ b/themes/default/layouts/shortcodes/video.html
@@ -1,32 +1,36 @@
{{-
- $source := default
+ $source := default
"https://raw.githubusercontent.com/benhosmer/HTML5-Test-Videos/9a6c2db46472454c634963cbeb0900fd37901fac/big_buck_bunny.mp4"
(.Get "source" | default (.Get 0))
-}}
-{{- $poster := default "" (.Get "poster" | default (.Get 1)) -}}
-{{- $width := default "" (.Get "width" | default (.Get 2)) -}}
-{{- $height := default "" (.Get "height" | default (.Get 3)) -}}
-{{- $preload := default "metadata" (.Get "preload" | default (.Get 4)) -}}
-{{- $options := default "controls" (.Get "options" | default (.Get 5)) -}}
-{{- $caption := default "`HTML5` Video" (.Get "caption" | default (.Get 6)) -}}
-{{- $title := default "HTML5 Video" (.Get "title" | default (.Get 7)) -}}
-{{- $start := default "" (.Get "start" | default (.Get 8)) -}}
-{{- $end := default "" (.Get "end" | default (.Get 9)) -}}
+{{- $poster := default "" (.Get "poster" | default (.Get 1)) -}}
+{{- $width := default "" (.Get "width" | default (.Get 2)) -}}
+{{- $height := default "" (.Get "height" | default (.Get 3)) -}}
+{{- $preload := default "metadata" (.Get "preload" | default (.Get 4)) -}}
+{{- $options := default "controls" (.Get "options" | default (.Get 5)) -}}
+{{- $caption := default "Untitled Video" (.Get "caption" | default (.Get 6)) -}}
+{{- $title := default $caption (.Get "title" | default (.Get 7)) -}}
+{{- $start := default "" (.Get "start" | default (.Get 8)) -}}
+{{- $end := default "" (.Get "end" | default (.Get 9)) -}}
+{{- $orientation := default "landscape" (.Get "orientation" | default (.Get 10)) -}}
+{{- $remote := default "" (.Get "remote" | default (.Get 11)) -}}
{{- partial "video-container.html"
(dict
- "Author" .Page.Section
- "Caption" $caption
- "End" $end
- "Height" $height
- "Options" $options
- "Poster" $poster
- "Preload" $preload
- "RelURL" (strings.TrimPrefix .Site.BaseURL .Page.Permalink)
- "Source" $source
- "Source" $source
- "Start" $start
- "Title" $title
- "Width" $width
+ "Author" .Page.Section
+ "Caption" $caption
+ "Context" .Page
+ "End" $end
+ "Height" $height
+ "Options" $options
+ "Orientation" $orientation
+ "Poster" $poster
+ "Preload" $preload
+ "RelURL" (strings.TrimPrefix .Site.BaseURL .Page.Permalink)
+ "Remote" $remote
+ "Source" $source
+ "Start" $start
+ "Title" $title
+ "Width" $width
)
-}}
diff --git a/themes/default/layouts/shortcodes/video.rss.xml b/themes/default/layouts/shortcodes/video.rss.xml
new file mode 100644
index 0000000..be262e7
--- /dev/null
+++ b/themes/default/layouts/shortcodes/video.rss.xml
@@ -0,0 +1,29 @@
+{{-
+ $source := default
+ "https://raw.githubusercontent.com/benhosmer/HTML5-Test-Videos/9a6c2db46472454c634963cbeb0900fd37901fac/big_buck_bunny.mp4"
+ (.Get "source" | default (.Get 0))
+-}}
+{{- $poster := default "" (.Get "poster" | default (.Get 1)) -}}
+{{- $width := default "" (.Get "width" | default (.Get 2)) -}}
+{{- $height := default "" (.Get "height" | default (.Get 3)) -}}
+{{- $preload := default "metadata" (.Get "preload" | default (.Get 4)) -}}
+{{- $options := default "controls" (.Get "options" | default (.Get 5)) -}}
+{{- $caption := default "Untitled Video" (.Get "caption" | default (.Get 6)) -}}
+{{- $title := default $caption (.Get "title" | default (.Get 7)) -}}
+{{- $start := default "" (.Get "start" | default (.Get 8)) -}}
+{{- $end := default "" (.Get "end" | default (.Get 9)) -}}
+{{- $orientation := default "landscape" (.Get "orientation" | default (.Get 10)) -}}
+{{- $remote := default "" (.Get "remote" | default (.Get 11)) -}}
+
+<p>
+ <b>
+ <a
+ title="{{ $title }}"
+ href="{{ $source }}"
+ >
+ Video: {{ $caption -}}
+ </a>
+ </b>
+ <br>
+ <span>Title: {{ $title }}</span>
+</p>
diff --git a/themes/default/layouts/shortcodes/vimeo.html b/themes/default/layouts/shortcodes/vimeo.html
deleted file mode 100644
index 009ebb0..0000000
--- a/themes/default/layouts/shortcodes/vimeo.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{{- $id := default "1084537" (.Get "id" | default (.Get 0)) -}}
-{{- $title := default "Vimeo Video" (.Get "title" | default (.Get 1)) -}}
-
-<vimeo-video>
- <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
- <iframe loading="lazy"
- src="https://player.vimeo.com/video/{{ $id }}?dnt=1"
- style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;"
- title="{{ $title }}" webkitallowfullscreen mozallowfullscreen allowfullscreen>
- </iframe>
- </div>
-</vimeo-video>
diff --git a/themes/default/layouts/shortcodes/wikipedia.html b/themes/default/layouts/shortcodes/wikipedia.html
index 65fa399..dd33a55 100644
--- a/themes/default/layouts/shortcodes/wikipedia.html
+++ b/themes/default/layouts/shortcodes/wikipedia.html
@@ -7,7 +7,9 @@
-}}
<wikipedia-container title="{{ $title }}">
- <iframe loading="lazy"
+ <iframe
+ loading="lazy"
+ scrolling="no"
height="300"
src="https://en.m.wikipedia.org/wiki/{{ $id }}"
title="{{ $title }}"
diff --git a/themes/default/layouts/shortcodes/youtube.html b/themes/default/layouts/shortcodes/youtube.html
index 99612ed..9ec1cfb 100644
--- a/themes/default/layouts/shortcodes/youtube.html
+++ b/themes/default/layouts/shortcodes/youtube.html
@@ -1,10 +1,12 @@
-{{- $url := "www.youtube-nocookie.com" -}}
{{- $id := default "aqz-KE-bpKQ" (.Get "id" | default (.Get 0)) -}}
{{- $title := default "YouTube Video" (.Get "title" | default (.Get 1)) -}}
{{- $start := default "" (.Get "start" | default (.Get 2)) -}}
{{- $end := default "" (.Get "end" | default (.Get 3)) -}}
{{- $muted := default "" (.Get "muted" | default (.Get 4)) -}}
+{{- $url := "www.youtube-nocookie.com" -}}
+{{- $controls := "?controls=1" -}}
+
{{- if (and $start $end) -}}
{{ $start = print "&start=" $start }}
{{ $end = print "&end=" $end }}
@@ -15,11 +17,14 @@
{{- end -}}
<youtube-video>
- <iframe loading="lazy"
+ <iframe
+ allowfullscreen=""
height="300"
+ loading="lazy"
+ title="{{ $title }}"
sandbox="allow-scripts allow-same-origin"
- src="https://{{ $url }}/embed/{{ $id }}{{ "?controls=1" }}{{ $start }}{{ $end }}{{ $muted }}"
- allowfullscreen title="{{ $title }}">
+ src="https://{{ $url }}/embed/{{ $id }}{{ $controls }}{{ $start }}{{ $end }}{{ $muted }}"
+ >
</iframe>
<footer>
{{ $title | markdownify }}
diff --git a/tsconfig.json b/tsconfig.json
index 10299e9..55eec34 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,5 @@
{
"compilerOptions": {
- "experimentalDecorators": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,