From c3b2bfe836f2b454970a56df0f7fdfd8c8534218 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sun, 12 Feb 2023 00:30:53 -0800 Subject: [PATCH] switch to Quartz --- .github/ISSUE_TEMPLATE/bug_report.md | 14 +- .github/ISSUE_TEMPLATE/feature_request.md | 20 + .github/workflows/deploy.yaml | 39 ++ .github/workflows/jekyll.yml | 63 -- .gitignore | 16 +- .hugo_build.lock | 0 404.html | 11 - Dockerfile | 10 + Gemfile | 10 - Gemfile.lock | 86 --- LICENSE | 9 - LICENSE.txt | 21 + Makefile | 24 + _config.yml | 45 -- _includes/footer.html | 1 - _includes/head.html | 54 -- _includes/link-previews.html | 140 ---- _includes/nav.html | 3 - _includes/notes_graph.html | 306 --------- _layouts/default.html | 13 - _layouts/note.html | 58 -- _layouts/page.html | 7 - _notes/colophon.md | 11 - _notes/conveners.md | 12 - _notes/digital-garden-jekyll-template.md | 43 -- _notes/explore.md | 22 - _notes/organizations.md | 14 - _notes/your-first-note.md | 112 ---- _plugins/bidirectional_links_generator.rb | 111 ---- _plugins/embed_tweets.rb | 22 - _plugins/empty_front_matter_note_injector.rb | 18 - _plugins/last_modified_at_generator.rb | 18 - _plugins/markdown-highlighter.rb | 18 - _plugins/open_external_links_in_new_tab.rb | 28 - _sass/_code.scss | 76 --- _sass/_normalize.scss | 338 ---------- _sass/_style.scss | 167 ----- assets/indices/.gitkeep | 0 assets/js/callouts.js | 6 + assets/js/clipboard.js | 45 ++ assets/js/code-title.js | 17 + assets/js/darkmode.js | 37 ++ assets/js/full-text-search.js | 61 ++ assets/js/graph.js | 279 ++++++++ assets/js/popover.js | 79 +++ assets/js/router.js | 25 + assets/js/semantic-search.js | 54 ++ assets/js/util.js | 226 +++++++ assets/styles/_callouts.scss | 170 +++++ assets/styles/_dark_syntax.scss | 85 +++ assets/styles/_light_syntax.scss | 85 +++ assets/styles/base.scss | 625 ++++++++++++++++++ assets/styles/clipboard.scss | 47 ++ assets/styles/code-title.scss | 20 + assets/styles/custom.scss | 31 + assets/styles/darkmode.scss | 44 ++ assets/styles/syntax.scss | 66 ++ config.toml | 33 + _notes/about.md => content/About.md | 0 _notes/bmann.md => content/Boris Mann.md | 6 +- _notes/calendar.md => content/Calendar.md | 2 +- .../Code of Conduct.md | 0 content/Colophon.md | 10 + .../Contributing.md | 0 .../DWeb Principles.md | 0 .../dweb.md => content/Decentralized Web.md | 0 .../Digital Garden.md | 0 _notes/emcgill.md => content/Emily McGill.md | 3 +- content/Explore.md | 6 + .../Feb 2023 Flash Talks & Tea.md | 3 +- _notes/github.md => content/Github.md | 0 _notes/holochain.md => content/Holochain.md | 2 + .../Infrastructure.md | 0 _notes/luma.md => content/Luma.md | 0 .../Open Collective.md | 0 .../The Permanent.md | 4 +- .../Vancouver DWeb Social, January 2023.md | 5 +- _pages/index.md => content/_index.md | 22 +- {_notes => content}/contact.md | 0 {_notes => content}/multipotentialite.md | 0 content/tags/Convener/_index.md | 4 + content/tags/Event/_index.md | 4 + content/tags/Organization/_index.md | 4 + content/templates/post.md | 3 + .../thepermanent_historic.jpeg | Bin data/config.yaml | 28 + data/graphConfig.yaml | 37 ++ i18n/en.toml | 65 ++ layouts/404.html | 15 + .../_markup/render-codeblock-mermaid.html | 4 + layouts/_default/_markup/render-image.html | 9 + layouts/_default/_markup/render-link.html | 16 + layouts/_default/baseof.html | 10 + layouts/_default/section.html | 21 + layouts/_default/single.html | 34 + layouts/_default/taxonomy.html | 30 + layouts/_default/term.html | 21 + layouts/index.html | 20 + layouts/partials/backlinks.html | 30 + layouts/partials/contact.html | 19 + layouts/partials/darkmode.html | 15 + layouts/partials/date-fmt.html | 7 + layouts/partials/footer.html | 16 + layouts/partials/footerIndex.html | 24 + layouts/partials/github.html | 3 + layouts/partials/graph.html | 19 + layouts/partials/head.html | 252 +++++++ layouts/partials/header.html | 11 + layouts/partials/katex.html | 14 + layouts/partials/mermaid.html | 8 + layouts/partials/page-list.html | 20 + layouts/partials/recent.html | 12 + layouts/partials/search.html | 18 + layouts/partials/textprocessing.html | 162 +++++ layouts/partials/toc.html | 9 + static/icon.png | Bin 0 -> 17368 bytes styles.scss | 6 - 117 files changed, 3176 insertions(+), 1852 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/workflows/deploy.yaml delete mode 100644 .github/workflows/jekyll.yml create mode 100644 .hugo_build.lock delete mode 100644 404.html create mode 100644 Dockerfile delete mode 100644 Gemfile delete mode 100644 Gemfile.lock delete mode 100644 LICENSE create mode 100644 LICENSE.txt create mode 100644 Makefile delete mode 100644 _config.yml delete mode 100644 _includes/footer.html delete mode 100644 _includes/head.html delete mode 100644 _includes/link-previews.html delete mode 100644 _includes/nav.html delete mode 100644 _includes/notes_graph.html delete mode 100644 _layouts/default.html delete mode 100644 _layouts/note.html delete mode 100644 _layouts/page.html delete mode 100644 _notes/colophon.md delete mode 100644 _notes/conveners.md delete mode 100644 _notes/digital-garden-jekyll-template.md delete mode 100644 _notes/explore.md delete mode 100644 _notes/organizations.md delete mode 100644 _notes/your-first-note.md delete mode 100644 _plugins/bidirectional_links_generator.rb delete mode 100644 _plugins/embed_tweets.rb delete mode 100644 _plugins/empty_front_matter_note_injector.rb delete mode 100644 _plugins/last_modified_at_generator.rb delete mode 100644 _plugins/markdown-highlighter.rb delete mode 100644 _plugins/open_external_links_in_new_tab.rb delete mode 100644 _sass/_code.scss delete mode 100644 _sass/_normalize.scss delete mode 100644 _sass/_style.scss create mode 100644 assets/indices/.gitkeep create mode 100644 assets/js/callouts.js create mode 100644 assets/js/clipboard.js create mode 100644 assets/js/code-title.js create mode 100644 assets/js/darkmode.js create mode 100644 assets/js/full-text-search.js create mode 100644 assets/js/graph.js create mode 100644 assets/js/popover.js create mode 100644 assets/js/router.js create mode 100644 assets/js/semantic-search.js create mode 100644 assets/js/util.js create mode 100644 assets/styles/_callouts.scss create mode 100644 assets/styles/_dark_syntax.scss create mode 100644 assets/styles/_light_syntax.scss create mode 100644 assets/styles/base.scss create mode 100644 assets/styles/clipboard.scss create mode 100644 assets/styles/code-title.scss create mode 100644 assets/styles/custom.scss create mode 100644 assets/styles/darkmode.scss create mode 100644 assets/styles/syntax.scss create mode 100644 config.toml rename _notes/about.md => content/About.md (100%) rename _notes/bmann.md => content/Boris Mann.md (91%) rename _notes/calendar.md => content/Calendar.md (98%) rename _notes/code-of-conduct.md => content/Code of Conduct.md (100%) create mode 100644 content/Colophon.md rename _notes/contributing.md => content/Contributing.md (100%) rename _notes/dweb-principles.md => content/DWeb Principles.md (100%) rename _drafts/dweb.md => content/Decentralized Web.md (100%) rename _notes/digital-garden.md => content/Digital Garden.md (100%) rename _notes/emcgill.md => content/Emily McGill.md (97%) create mode 100644 content/Explore.md rename _notes/feb15th-2023-flash-talks-tea.md => content/Feb 2023 Flash Talks & Tea.md (99%) rename _notes/github.md => content/Github.md (100%) rename _notes/holochain.md => content/Holochain.md (91%) rename _notes/infrastructure.md => content/Infrastructure.md (100%) rename _notes/luma.md => content/Luma.md (100%) rename _notes/open-collective.md => content/Open Collective.md (100%) rename _notes/the-permanent.md => content/The Permanent.md (91%) rename _notes/jan25th-2023-vancouver-dweb-social.md => content/Vancouver DWeb Social, January 2023.md (98%) rename _pages/index.md => content/_index.md (50%) rename {_notes => content}/contact.md (100%) rename {_notes => content}/multipotentialite.md (100%) create mode 100644 content/tags/Convener/_index.md create mode 100644 content/tags/Event/_index.md create mode 100644 content/tags/Organization/_index.md create mode 100644 content/templates/post.md rename {assets => content}/thepermanent_historic.jpeg (100%) create mode 100644 data/config.yaml create mode 100644 data/graphConfig.yaml create mode 100644 i18n/en.toml create mode 100644 layouts/404.html create mode 100644 layouts/_default/_markup/render-codeblock-mermaid.html create mode 100644 layouts/_default/_markup/render-image.html create mode 100644 layouts/_default/_markup/render-link.html create mode 100644 layouts/_default/baseof.html create mode 100644 layouts/_default/section.html create mode 100644 layouts/_default/single.html create mode 100644 layouts/_default/taxonomy.html create mode 100644 layouts/_default/term.html create mode 100644 layouts/index.html create mode 100644 layouts/partials/backlinks.html create mode 100644 layouts/partials/contact.html create mode 100644 layouts/partials/darkmode.html create mode 100644 layouts/partials/date-fmt.html create mode 100644 layouts/partials/footer.html create mode 100644 layouts/partials/footerIndex.html create mode 100644 layouts/partials/github.html create mode 100644 layouts/partials/graph.html create mode 100644 layouts/partials/head.html create mode 100644 layouts/partials/header.html create mode 100644 layouts/partials/katex.html create mode 100644 layouts/partials/mermaid.html create mode 100644 layouts/partials/page-list.html create mode 100644 layouts/partials/recent.html create mode 100644 layouts/partials/search.html create mode 100644 layouts/partials/textprocessing.html create mode 100644 layouts/partials/toc.html create mode 100644 static/icon.png delete mode 100644 styles.scss diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index c82886f3..189648d9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,18 +1,16 @@ --- name: Bug report -about: Something's broken with the template +about: Something about Quartz isn't working the way you expect title: '' labels: bug assignees: '' --- - - **Describe the bug** A clear and concise description of what the bug is. -**To reproduce** +**To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' @@ -26,5 +24,9 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - Operating system: [e.g. macOS 11.4] - - Ruby version: [e.g. Ruby 2.7.1] + - Device: [e.g. iPhone6] + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..2c9c226d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea or improvement for Quartz +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 00000000..dbe1aadd --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,39 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - hugo + +jobs: + deploy: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod + + - name: Build Link Index + uses: jackyzha0/hugo-obsidian@v2.18 + with: + index: true + input: content + output: assets/indices + root: . + + - name: Setup Hugo + uses: peaceiris/actions-hugo@v2 + with: + hugo-version: '0.96.0' + extended: true + + - name: Build + run: hugo --minify + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public + publish_branch: main # deploying branch + cname: quartz.jzhao.xyz diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml deleted file mode 100644 index 4a8c3133..00000000 --- a/.github/workflows/jekyll.yml +++ /dev/null @@ -1,63 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: Deploy Jekyll site to Pages - -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow one concurrent deployment -concurrency: - group: "pages" - cancel-in-progress: true - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Setup Ruby - uses: ruby/setup-ruby@ee2113536afb7f793eed4ce60e8d3b26db912da4 # v1.127.0 - with: - ruby-version: '3.0' # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - cache-version: 0 # Increment this number if you need to re-download cached gems - - name: Setup Pages - id: pages - uses: actions/configure-pages@v3 - - name: Build with Jekyll - # Outputs to the './_site' directory by default - run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}" - env: - JEKYLL_ENV: production - - name: Upload artifact - # Automatically uploads an artifact from the './_site' directory by default - uses: actions/upload-pages-artifact@v1 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v1 diff --git a/.gitignore b/.gitignore index 302d1062..5b0c2497 100644 --- a/.gitignore +++ b/.gitignore @@ -7,15 +7,17 @@ _site/ # Sass cache .sass-cache/ -# Jekyll cache & metadata -.jekyll-cache/ -.jekyll-metadata - -# Notes graph metadata -_includes/notes_graph.json - # Obsidian config *.obsidian/ # TinaCMS node_modules + +# generate files +public +resources + +# note metadata +assets/indices/linkIndex.json +assets/indices/contentIndex.json +linkmap diff --git a/.hugo_build.lock b/.hugo_build.lock new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html deleted file mode 100644 index 6343fd79..00000000 --- a/404.html +++ /dev/null @@ -1,11 +0,0 @@ ---- -permalink: 404.html -layout: default -title: "404" -id: "not-found" ---- - -
-

Oops, that's a 404. πŸ™ˆ

-

Looks like this page doesn't exist. Return home to get a fresh start.

-
diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..ac5e8de2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM alpine:3.16 + +RUN apk add --no-cache go hugo git make perl +RUN go install github.com/jackyzha0/hugo-obsidian@latest +ENV PATH="/root/go/bin:$PATH" +RUN git clone https://github.com/jackyzha0/quartz.git /quartz + +WORKDIR /quartz + +CMD ["make", "serve"] diff --git a/Gemfile b/Gemfile deleted file mode 100644 index fc56880d..00000000 --- a/Gemfile +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } - -gem "jekyll", "~> 4.0" -gem "jekyll-last-modified-at", git: "https://github.com/maximevaillancourt/jekyll-last-modified-at", branch: "add-support-for-files-in-git-submodules" -gem "webrick", "~> 1.7" -gem "nokogiri" diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 212b0910..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,86 +0,0 @@ -GIT - remote: https://github.com/maximevaillancourt/jekyll-last-modified-at - revision: e0c918691db625401ef5850a030da59d0124d356 - branch: add-support-for-files-in-git-submodules - specs: - jekyll-last-modified-at (1.3.0) - jekyll (>= 3.7, < 5.0) - posix-spawn (~> 0.3.9) - -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - colorator (1.1.0) - concurrent-ruby (1.1.7) - em-websocket (0.5.2) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - eventmachine (1.2.7) - ffi (1.14.2) - forwardable-extended (2.6.0) - http_parser.rb (0.6.0) - i18n (1.8.5) - concurrent-ruby (~> 1.0) - jekyll (4.2.0) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (~> 2.0) - jekyll-watch (~> 2.0) - kramdown (~> 2.3) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.4.0) - pathutil (~> 0.9) - rouge (~> 3.0) - safe_yaml (~> 1.0) - terminal-table (~> 2.0) - jekyll-sass-converter (2.1.0) - sassc (> 2.0.1, < 3.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - kramdown (2.3.1) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.3) - listen (3.3.3) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - mini_portile2 (2.8.0) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) - racc (~> 1.4) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - posix-spawn (0.3.15) - public_suffix (4.0.6) - racc (1.6.1) - rb-fsevent (0.10.4) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.5) - rouge (3.26.0) - safe_yaml (1.0.5) - sassc (2.4.0) - ffi (~> 1.9) - terminal-table (2.0.0) - unicode-display_width (~> 1.1, >= 1.1.1) - unicode-display_width (1.7.0) - webrick (1.7.0) - -PLATFORMS - ruby - -DEPENDENCIES - jekyll (~> 4.0) - jekyll-last-modified-at! - nokogiri - webrick (~> 1.7) - -BUNDLED WITH - 2.2.3 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 46741053..00000000 --- a/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -# Released under MIT License - -Copyright (c) 2020 Maxime Vaillancourt. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 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 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..147e2ca1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 jackyzha0 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +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. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..bbd3be7a --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.DEFAULT_GOAL := serve + +help: ## Show all Makefile targets + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +update: ## Update Quartz to the latest version on Github + go install github.com/jackyzha0/hugo-obsidian@latest + @git remote show upstream || (echo "remote 'upstream' not present, setting 'upstream'" && git remote add upstream https://github.com/jackyzha0/quartz.git) + git fetch upstream + git log --oneline --decorate --graph ..upstream/hugo + git checkout -p upstream/hugo -- layouts .github Makefile assets/js assets/styles/base.scss assets/styles/darkmode.scss config.toml data + +update-force: ## Forcefully pull all changes and don't ask to patch + go install github.com/jackyzha0/hugo-obsidian@latest + @git remote show upstream || (echo "remote 'upstream' not present, setting 'upstream'" && git remote add upstream https://github.com/jackyzha0/quartz.git) + git fetch upstream + git checkout upstream/hugo -- layouts .github Makefile assets/js assets/styles/base.scss assets/styles/darkmode.scss config.toml data + +serve: ## Serve Quartz locally + hugo-obsidian -input=content -output=assets/indices -index -root=. + hugo server --enableGitInfo --minify --bind=$(or $(HUGO_BIND),0.0.0.0) --baseURL=$(or $(HUGO_BASEURL),http://localhost) --port=$(or $(HUGO_PORT),1313) --appendPort=$(or $(HUGO_APPENDPORT),true) --liveReloadPort=$(or $(HUGO_LIVERELOADPORT),-1) + +docker: ## Serve locally using Docker + docker run -it --volume=$(shell pwd):/quartz -p 1313:1313 ghcr.io/jackyzha0/quartz:hugo diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 31cd8507..00000000 --- a/_config.yml +++ /dev/null @@ -1,45 +0,0 @@ -title: DWeb YVR -include: ['_pages'] -exclude: ['_includes/notes_graph.json', '_notes/.obsidian/'] -# You may need to change the base URL depending on your deploy configuration. -# Specifically, when using GitHub Pages, the baseurl should point to where GitHub -# Pages deploys your repository (which is usually the repository name). -baseurl: '' - -# If you are using a host that cannot resolve URLs that do -# not end with .html (such as Neocities), set this to 'true'. -use_html_extension: false - -# Set to `true` to open non-internal links in new tabs, or -# set to `false` to open non-internal links in current tab. -open_external_links_in_new_tab: true - -# Set to `true` to replace tweet URLs with Twitter embeds. -# Note that doing so will negatively the reader's privacy -# as their browser will communicate with Twitter's servers. -embed_tweets: false - -permalink: pretty -relative_permalinks: false - -plugins: - - jekyll-last-modified-at - -sass: - sass_dir: _sass - style: :compressed - -collections: - notes: - output: true - permalink: /:slug - -defaults: - - scope: - path: "**/*" - values: - layout: "default" - - scope: - path: "_notes/**/*.md" - values: - layout: "note" diff --git a/_includes/footer.html b/_includes/footer.html deleted file mode 100644 index 9de51d9d..00000000 --- a/_includes/footer.html +++ /dev/null @@ -1 +0,0 @@ -About β€’ Contact β€’ Calendar diff --git a/_includes/head.html b/_includes/head.html deleted file mode 100644 index dc202cf9..00000000 --- a/_includes/head.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - {% if page.excerpt %} - - {% else %} - - {% endif %} - - {% if page.title %} - - - {% else %} - - - {% endif %} - - {% if page.date %} - - - {% endif %} - - - - {% if page.image %} - - {% endif %} - - {% comment %} Littlefoot https://github.com/goblindegook/littlefoot {% endcomment %} - - - - {% if page.id == "home" %} - {{ site.title }} - {% else %} - {{ page.title }} — {{ site.title }} - {% endif %} - - diff --git a/_includes/link-previews.html b/_includes/link-previews.html deleted file mode 100644 index b9eb370a..00000000 --- a/_includes/link-previews.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - diff --git a/_includes/nav.html b/_includes/nav.html deleted file mode 100644 index 4f638f98..00000000 --- a/_includes/nav.html +++ /dev/null @@ -1,3 +0,0 @@ -
- {{ site.title }} -
diff --git a/_includes/notes_graph.html b/_includes/notes_graph.html deleted file mode 100644 index 23db0a2f..00000000 --- a/_includes/notes_graph.html +++ /dev/null @@ -1,306 +0,0 @@ - - -
- -
diff --git a/_layouts/default.html b/_layouts/default.html deleted file mode 100644 index dc744782..00000000 --- a/_layouts/default.html +++ /dev/null @@ -1,13 +0,0 @@ - - - {% include head.html %} - - -
-
{{ content }}
-
{% include footer.html %}
-
- - {% include link-previews.html wrapperQuerySelector="content" %} - - diff --git a/_layouts/note.html b/_layouts/note.html deleted file mode 100644 index 352df854..00000000 --- a/_layouts/note.html +++ /dev/null @@ -1,58 +0,0 @@ ---- -layout: default ---- - -
-
-

{{ page.title }}

-
- -
- - {{ content }} - {% comment %} Put content here that you want at the end of every note {% endcomment %} - - - -

Notes mentioning this note

- {% if page.backlinks.size > 0 %} -
- {% for backlink in page.backlinks %} - - {% endfor %} -
- {% else %} - -
-

- There are no notes linking to this note. -

-
- {% endif %} -
-
-
- -
- - - -{% comment %} -

Here are all the notes in this garden, along with their links, visualized as a graph.

- -{% include notes_graph.html %} -{% endcomment %} - - - diff --git a/_layouts/page.html b/_layouts/page.html deleted file mode 100644 index c8c70f50..00000000 --- a/_layouts/page.html +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: default ---- - - - {{ content }} - diff --git a/_notes/colophon.md b/_notes/colophon.md deleted file mode 100644 index a38bbd8b..00000000 --- a/_notes/colophon.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Colophon ---- - -This is a [Jekyll](https://jekyllrb.com/) powered website, built using the [[Digital Garden Jekyll Template]]. From the features of that template, [[wikilinks]] -- double square brackets around words -- can be used to easily link between notes, and show which notes link to each other in the sidebar. - -The [Littlefoot JS library](https://github.com/goblindegook/littlefoot) powers inline footnotes. - -This site is built and hosted using [[Github]]. For every commit, a Github Action runs and builds a Jekyll site, and then publishes to Github Pages. The `dwebyvr.org` domain is hosted on [[Google Domains]]. - -Issues related to the website can be [submitted on GitHub](https://github.com/DWebYVR/notes/issues). \ No newline at end of file diff --git a/_notes/conveners.md b/_notes/conveners.md deleted file mode 100644 index fadacaca..00000000 --- a/_notes/conveners.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: Conveners ---- - -Conveners is what we call the organizers who bring people and events together. - -* [[Emily McGill]] -* [[Boris Mann]] - -# How to get involved - -[[contact|Get in touch]] using one of the many channels we have. \ No newline at end of file diff --git a/_notes/digital-garden-jekyll-template.md b/_notes/digital-garden-jekyll-template.md deleted file mode 100644 index 81c07cd1..00000000 --- a/_notes/digital-garden-jekyll-template.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Digital Garden Jekyll Template ---- - -> This was originally the README for the template used to start this site. You can find the template repo here: -> -> The [[Your first seed]] note is also kept as an example of the different ways to link notes, various config options, Markdown syntax, and more. -> -> More details about [[colophon|this site Β»]] - -# Digital garden Jekyll template - -Use this template repository to get started with your own digital garden. - -**I wrote a tutorial explaining how to set it up: [Setting up your own digital garden with Jekyll](https://maximevaillancourt.com/blog/setting-up-your-own-digital-garden-with-jekyll)** - -Preview the template here: https://digital-garden-jekyll-template.netlify.app/ - -- Based on Jekyll, a static website generator -- Supports Roam-style double bracket link syntax to other notes -- Creates backlinks to other notes automatically -- Features link previews on hover -- Includes graph visualization of the notes and their links -- Features a simple and responsive design -- Supports Markdown or HTML notes - -Screen Shot 2020-05-19 at 23 05 46 - -## A note about GitHub Pages - -**Update (January 2023)**: it seems that GitHub Pages supports custom plugins now, thanks to GitHub Actions ([view relevant discussion](https://github.com/maximevaillancourt/digital-garden-jekyll-template/discussions/144)). - -GitHub Pages only partially supports this template: to power the interactive notes graph, this template uses a custom Jekyll plugin to generate the graph data in [`notes_graph.json`](https://github.com/maximevaillancourt/digital-garden-jekyll-template/blob/7ac331a4113bac77c993856562acc2bfbde9f2f7/_plugins/bidirectional_links_generator.rb#L102), and [GitHub Pages doesn't support custom Jekyll plugins](https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll#plugins). - -If you want to use the graph with GitHub Pages, you may try building your garden locally using Jekyll then pushing the result to GitHub Pages. - -Alternatively, you may deploy your garden to Netlify and it'll work out of the box. [I wrote a guide explaining how to set this up](https://maximevaillancourt.com/blog/setting-up-your-own-digital-garden-with-jekyll). - -If you don't care about the graph, you can simply remove it from this layout, [as explained here](https://github.com/maximevaillancourt/digital-garden-jekyll-template/discussions/132#discussioncomment-3625772). - -## License - -Source code is available under the [MIT license](LICENSE.md). diff --git a/_notes/explore.md b/_notes/explore.md deleted file mode 100644 index 9c721317..00000000 --- a/_notes/explore.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Explore Notes ---- - -This website is organized as a [[Digital Garden]] -- an organic collection of notes that link to each other. - -## Recently updated notes - - - -## Notes Graph - -This is a graph of all of the notes on the site, and how they connect to each other. You can highlight notes to see what they are connected to. - -{% include notes_graph.html %} \ No newline at end of file diff --git a/_notes/organizations.md b/_notes/organizations.md deleted file mode 100644 index f8541033..00000000 --- a/_notes/organizations.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Local Vancouver Organizations ---- - -A list of Vancouver regional organizations, projects, and people that support [[DWeb Principles]]. - -* [[Internet Archive Canada]] / [[The Permanent]] -* [[Fission]] -* [[Living Systems Network]] -* [[Holochain]] - -_TODO: Work in Progress page! probably good to make this a programmatic page and get basic name, link, logo, description as a pull request_ - -Feel free to add yourself to this page by making a pull request or filing an issue on [[Github]]. diff --git a/_notes/your-first-note.md b/_notes/your-first-note.md deleted file mode 100644 index 30584a79..00000000 --- a/_notes/your-first-note.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Your first seed ---- - -### Welcome! - -This is your first note. You'll find it in the [`notes/`](https://github.com/maximevaillancourt/digital-garden-jekyll-template/tree/master/_notes) directory. - -### Link syntax - -To link to another note, you can use multiple syntaxes. The following four use the "double-bracket" notation ([view the Markdown source file](https://github.com/maximevaillancourt/digital-garden-jekyll-template/blob/master/_notes/your-first-note.md#link-syntax) to see the underlying syntax). - -- Using the note title: [[a note about cats]] -- Using the note's filename: [[cats]] -- Using the note's title, with a label: [[A note about cats|link to the note about cats using the note title]] -- Using the note's filename, with a label: [[cats|link to the note about cats using the note's filename]] - -You can organize notes in subdirectories and link them normally. For example, the links above all point to the `_notes/animals/cats.md` file. Here's another example: [[tigers]]. - -Non-latin languages are supported: [[μ•ˆλ…•ν•˜μ„Έμš”]]; so are accents/diacritics: [[bon appΓ©tit!]] - -Dashes and underscores in file names are supported, and may be omitted in the bracket link syntax. As an example, the `your-first-note.md` file can be linked to with [[your first note]] or [[your-first-note]], or even [[yOuR-FiRsT Note]]. - -In all cases, if the double-bracket link does not point to a valid note, the double brackets will still be shown, like this: [[there is no note that matches this link]]. - -Alternatively, you can use regular [Markdown syntax](https://www.markdownguide.org/getting-started/) for links, with a relative link to the other note, like this: [this is a Markdown link to the note about cats](/cats){: .internal-link}. Don't forget to use the `.internal-link` class to make sure the link is styled as an internal link (without the little arrow). - -Since the Web is all about HTML, you can always use plain HTML if you want, like this: This is a link to the note about cats with HTML. - -Of course, you can also link to external websites, like this: [this is a link to Wikipedia](https://wikipedia.org/). Again, you can use plain HTML if you prefer. Footnotes are also supported and will be treated like internal links.[^1] You can point to other notes in your footnotes.[^2] - -[^1]: This is a footnote. For more information about using footnotes, check out the [Markdown Guide](https://www.markdownguide.org/extended-syntax/#footnotes). -[^2]: This is another footnote that links to the note about [[cats]]. You may also point to [[notes that do not exist]] if you wish. - -### Tweet embedding - -Note: This behavior is disabled by default for privacy reasons. See "Site configuration" section below to enable it. - -You may include a tweet URL on its own line (like below), and it would be replaced with an official Twitter embed if the site configuration demands it. - -https://twitter.com/jack/status/20 - -### Site configuration - -Some behavior is configurable by tweaking the `_config.yml` file. - -**`use_html_extension`**: if you use a static host that doesn't support URLs that don't end with `.html` (such as Neocities), try changing the `use_html_extension` value to `true` in the `_config.yml` file and restart the Jekyll server (or re-build the site). This adds a `.html` extension to note URLs and may resolve issues with links. If you're still having trouble, I recommend using Netlify to host your digital garden: it's free, easy to use, and fully supports this template's features out of the box. - -**`open_external_links_in_new_tab`**: when set to `true`, this makes external links open in new tabs. Set to `false` to open all links in the current tab. - -**`embed_tweets`**: when set to `true`, tweet URLs on their own lines will be replaced with a Twitter embed. Default value is `false`. - -### Automatic bi-directional links - -Notice in the "Notes mentioning this note" section that there is another note linking to this note. This is a bi-directional link, and those are automatically created when you create links to other notes. - -### Link previews - -If you're on a device with mouse support, try hovering your mouse on internal links to preview the notes: [[a note about cats]]. - -Links that have been previewed will be cached to avoid redundant requests. - -### Images and other Markdown goodies - -Finally, because you have the full power of Markdown in this template, you can use regular Markdown syntax for various formatting options. - -Lists work as expected: - -- List element A -- List element B -- List element C - -1. List element -2. List element -3. List element - -If you'd like to quote other people, consider using quote blocks: - -> Lorem ipsum dolor sit amet - -You can also ==highlight some content== by wrapping it with `==`. - -Non-latin languages are supported too: ==δ½ ε₯½==, ==μ•ˆλ…•ν•˜μ„Έμš”==, ==こんにけは==. - -### Code syntax highlighting - -You can add code blocks with full syntax color highlighting by wrapping code snippet in triple backticks and specifying the type of the code (`js`, `rb`, `sh`, etc.): - -```js -// Here's a bit of JavaScript: -console.log('hello!') -``` - -```rb -# And now some Ruby -def foo(bar) - "baz" -end -``` - -```sh -$ cat /dev/urandom | grep "the answer to life" # shell scripts look nice too -``` - - -### Next steps - -This digital garden template is free, open-source, and [available on GitHub here](https://github.com/maximevaillancourt/digital-garden-jekyll-template). - -The easiest way to build your own digital garden based on this template is to read this [step-by-step guide explaining how to set this up from scratch](https://maximevaillancourt.com/blog/setting-up-your-own-digital-garden-with-jekyll). - -Go forth, have fun, and learn new something every day! ✌️ diff --git a/_plugins/bidirectional_links_generator.rb b/_plugins/bidirectional_links_generator.rb deleted file mode 100644 index 918c6624..00000000 --- a/_plugins/bidirectional_links_generator.rb +++ /dev/null @@ -1,111 +0,0 @@ -# frozen_string_literal: true -class BidirectionalLinksGenerator < Jekyll::Generator - def generate(site) - graph_nodes = [] - graph_edges = [] - - all_notes = site.collections['notes'].docs - all_pages = site.pages - - all_docs = all_notes + all_pages - - link_extension = !!site.config["use_html_extension"] ? '.html' : '' - - # Convert all Wiki/Roam-style double-bracket link syntax to plain HTML - # anchor tag elements () with "internal-link" CSS class - all_docs.each do |current_note| - all_docs.each do |note_potentially_linked_to| - note_title_regexp_pattern = Regexp.escape( - File.basename( - note_potentially_linked_to.basename, - File.extname(note_potentially_linked_to.basename) - ) - ).gsub('\_', '[ _]').gsub('\-', '[ -]').capitalize - - title_from_data = note_potentially_linked_to.data['title'] - if title_from_data - title_from_data = Regexp.escape(title_from_data) - end - - new_href = "#{site.baseurl}#{note_potentially_linked_to.url}#{link_extension}" - anchor_tag = "\\1" - - # Replace double-bracketed links with label using note title - # [[A note about cats|this is a link to the note about cats]] - current_note.content.gsub!( - /\[\[#{note_title_regexp_pattern}\|(.+?)(?=\])\]\]/i, - anchor_tag - ) - - # Replace double-bracketed links with label using note filename - # [[cats|this is a link to the note about cats]] - current_note.content.gsub!( - /\[\[#{title_from_data}\|(.+?)(?=\])\]\]/i, - anchor_tag - ) - - # Replace double-bracketed links using note title - # [[a note about cats]] - current_note.content.gsub!( - /\[\[(#{title_from_data})\]\]/i, - anchor_tag - ) - - # Replace double-bracketed links using note filename - # [[cats]] - current_note.content.gsub!( - /\[\[(#{note_title_regexp_pattern})\]\]/i, - anchor_tag - ) - end - - # At this point, all remaining double-bracket-wrapped words are - # pointing to non-existing pages, so let's turn them into disabled - # links by greying them out and changing the cursor - current_note.content = current_note.content.gsub( - /\[\[([^\]]+)\]\]/i, # match on the remaining double-bracket links - <<~HTML.delete("\n") # replace with this HTML (\\1 is what was inside the brackets) - - [[ - \\1 - ]] - HTML - ) - end - - # Identify note backlinks and add them to each note - all_notes.each do |current_note| - # Nodes: Jekyll - notes_linking_to_current_note = all_notes.filter do |e| - e.content.include?(current_note.url) - end - - # Nodes: Graph - graph_nodes << { - id: note_id_from_note(current_note), - path: "#{site.baseurl}#{current_note.url}#{link_extension}", - label: current_note.data['title'], - } unless current_note.path.include?('_notes/index.html') - - # Edges: Jekyll - current_note.data['backlinks'] = notes_linking_to_current_note - - # Edges: Graph - notes_linking_to_current_note.each do |n| - graph_edges << { - source: note_id_from_note(n), - target: note_id_from_note(current_note), - } - end - end - - File.write('_includes/notes_graph.json', JSON.dump({ - edges: graph_edges, - nodes: graph_nodes, - })) - end - - def note_id_from_note(note) - note.data['title'].bytes.join - end -end diff --git a/_plugins/embed_tweets.rb b/_plugins/embed_tweets.rb deleted file mode 100644 index 19c1b334..00000000 --- a/_plugins/embed_tweets.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true -class TweetEmbedGenerator < Jekyll::Generator - def generate(site) - return if !site.config["embed_tweets"] - - all_notes = site.collections['notes'].docs - all_pages = site.pages - all_docs = all_notes + all_pages - - all_docs.each do |current_note| - current_note.content.gsub!( - /^https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$/i, - <<~HTML - - - HTML - ) - end - end -end diff --git a/_plugins/empty_front_matter_note_injector.rb b/_plugins/empty_front_matter_note_injector.rb deleted file mode 100644 index 83fd4b2e..00000000 --- a/_plugins/empty_front_matter_note_injector.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -EMPTY_FRONT_MATTER = <<~JEKYLL - --- - --- - -JEKYLL - -# Inject empty front matter in notes that don't have any -Jekyll::Hooks.register :site, :after_init do |site| - Dir.glob(site.collections['notes'].relative_directory + '/**/*.md').each do |filename| - raw_note_content = File.read(filename) - unless raw_note_content.start_with?('---') - raw_note_content.prepend(EMPTY_FRONT_MATTER) - File.write(filename, raw_note_content) - end - end -end diff --git a/_plugins/last_modified_at_generator.rb b/_plugins/last_modified_at_generator.rb deleted file mode 100644 index ea9b1f43..00000000 --- a/_plugins/last_modified_at_generator.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'fileutils' -require 'pathname' -require 'jekyll-last-modified-at' - -module Recents - # Generate change information for all markdown pages - class Generator < Jekyll::Generator - def generate(site) - items = site.collections['notes'].docs - items.each do |page| - timestamp = Jekyll::LastModifiedAt::Determinator.new(site.source, page.path, '%FT%T%:z').to_s - page.data['last_modified_at_timestamp'] = timestamp - end - end - end -end diff --git a/_plugins/markdown-highlighter.rb b/_plugins/markdown-highlighter.rb deleted file mode 100644 index b14ae84c..00000000 --- a/_plugins/markdown-highlighter.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -# Turns ==something== in Markdown to something in output HTML - -Jekyll::Hooks.register [:notes], :post_convert do |doc| - replace(doc) -end - -Jekyll::Hooks.register [:pages], :post_convert do |doc| - # jekyll considers anything at the root as a page, - # we only want to consider actual pages - next unless doc.path.start_with?('_pages/') - replace(doc) -end - -def replace(doc) - doc.content.gsub!(/==+([^ ](.*?)?[^ .=]?)==+/, "\\1") -end diff --git a/_plugins/open_external_links_in_new_tab.rb b/_plugins/open_external_links_in_new_tab.rb deleted file mode 100644 index e0496a24..00000000 --- a/_plugins/open_external_links_in_new_tab.rb +++ /dev/null @@ -1,28 +0,0 @@ -# If the configuration sets `open_external_links_in_new_tab` to a truthy value, -# add 'target=_blank' to anchor tags that don't have `internal-link` class - -# frozen_string_literal: true -require 'nokogiri' - -Jekyll::Hooks.register [:notes], :post_convert do |doc| - convert_links(doc) -end - -Jekyll::Hooks.register [:pages], :post_convert do |doc| - # jekyll considers anything at the root as a page, - # we only want to consider actual pages - next unless doc.path.start_with?('_pages/') - convert_links(doc) -end - -def convert_links(doc) - open_external_links_in_new_tab = !!doc.site.config["open_external_links_in_new_tab"] - - if open_external_links_in_new_tab - parsed_doc = Nokogiri::HTML(doc.content) - parsed_doc.css("a:not(.internal-link):not(.footnote):not(.reversefootnote)").each do |link| - link.set_attribute('target', '_blank') - end - doc.content = parsed_doc.inner_html - end -end diff --git a/_sass/_code.scss b/_sass/_code.scss deleted file mode 100644 index c7a18d83..00000000 --- a/_sass/_code.scss +++ /dev/null @@ -1,76 +0,0 @@ -.highlight { - background: #f8f8f8; - padding: 1px 1em; - border-radius: 3px; - font-size: 1em; - font-size: 0.9em; - overflow: auto; - margin: 1em -1em; - code{ - padding: 0; - } -} - -div.highlight { - display: grid; -} - -.highlight .c { color: #999988; font-style: italic } /* Comment */ -.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ -.highlight .k { font-weight: bold } /* Keyword */ -.highlight .o { font-weight: bold } /* Operator */ -.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ -.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ -.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #aa0000 } /* Generic.Error */ -.highlight .gh { color: #999999 } /* Generic.Heading */ -.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ -.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #555555 } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ -.highlight .gt { color: #aa0000 } /* Generic.Traceback */ -.highlight .kc { font-weight: bold } /* Keyword.Constant */ -.highlight .kd { font-weight: bold } /* Keyword.Declaration */ -.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #009999 } /* Literal.Number */ -.highlight .s { color: #d14 } /* Literal.String */ -.highlight .na { color: #008080 } /* Name.Attribute */ -.highlight .nb { color: #0086B3 } /* Name.Builtin */ -.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ -.highlight .no { color: #008080 } /* Name.Constant */ -.highlight .ni { color: #800080 } /* Name.Entity */ -.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ -.highlight .nn { color: #555555 } /* Name.Namespace */ -.highlight .nt { color: #000080 } /* Name.Tag */ -.highlight .nv { color: #008080 } /* Name.Variable */ -.highlight .ow { font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mf { color: #009999 } /* Literal.Number.Float */ -.highlight .mh { color: #009999 } /* Literal.Number.Hex */ -.highlight .mi { color: #009999 } /* Literal.Number.Integer */ -.highlight .mo { color: #009999 } /* Literal.Number.Oct */ -.highlight .sb { color: #d14 } /* Literal.String.Backtick */ -.highlight .sc { color: #d14 } /* Literal.String.Char */ -.highlight .sd { color: #d14 } /* Literal.String.Doc */ -.highlight .s2 { color: #d14 } /* Literal.String.Double */ -.highlight .se { color: #d14 } /* Literal.String.Escape */ -.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ -.highlight .si { color: #d14 } /* Literal.String.Interpol */ -.highlight .sx { color: #d14 } /* Literal.String.Other */ -.highlight .sr { color: #009926 } /* Literal.String.Regex */ -.highlight .s1 { color: #d14 } /* Literal.String.Single */ -.highlight .ss { color: #990073 } /* Literal.String.Symbol */ -.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #008080 } /* Name.Variable.Class */ -.highlight .vg { color: #008080 } /* Name.Variable.Global */ -.highlight .vi { color: #008080 } /* Name.Variable.Instance */ -.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/_sass/_normalize.scss b/_sass/_normalize.scss deleted file mode 100644 index 3a07a444..00000000 --- a/_sass/_normalize.scss +++ /dev/null @@ -1,338 +0,0 @@ -/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ - - html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers. - */ - -body { - margin: 0; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Remove the gray background on active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove the border on images inside links in IE 10. - */ - -img { - border-style: none; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * Correct the inability to style clickable types in iOS and Safari. - */ - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - vertical-align: baseline; -} - -/** - * Remove the default vertical scrollbar in IE 10+. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in Edge, IE 10+, and Firefox. - */ - -details { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Misc - ========================================================================== */ - -/** - * Add the correct display in IE 10+. - */ - -template { - display: none; -} - -/** - * Add the correct display in IE 10. - */ - -[hidden] { - display: none; -} diff --git a/_sass/_style.scss b/_sass/_style.scss deleted file mode 100644 index 30d8549a..00000000 --- a/_sass/_style.scss +++ /dev/null @@ -1,167 +0,0 @@ -$color-primary: hsl(0, 0%, 10%); -$color-text: hsl(0, 0%, 20%); -$color-subtext: hsl(0, 0%, 30%); -$color-border: hsl(0, 0%, 85%); -$color-box-background: mix($color-primary, white, 4%); -$border-radius: 4px; -$font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, - sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol; - -body { - box-sizing: content-box; - font-family: $font-family; - margin: 0 auto; - line-height: 1.7; - padding: 4vh 6vw; - overflow-x: hidden; - color: $color-text; - font-size: 1rem; - max-width: 63em; - - @media (min-width: 820px) { - font-size: 1.2rem; - } -} - -time { - display: block; - color: $color-subtext; - margin: 0.5em 0 1em; - font-size: 0.9rem; -} - -footer { - margin: 2em 0; - font-size: 0.8em; - color: mix($color-text, white, 80%); - padding-top: 1em; -} - -img { - max-width: 100%; - display: block; - margin: 0 auto; - max-height: 75vh; - border-radius: $border-radius; -} - -blockquote { - padding: 1.5em; - margin: 0; - font-size: 0.88em; - background: $color-box-background; - border-radius: $border-radius; - - p { - margin: 0; - } -} - -hr { - width: 100%; - border: 0; - height: 1px; - margin: 1.5em 0; - background: $color-border; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - line-height: 1.3; - margin-bottom: 0; - padding-bottom: 0; -} - -h1 { - padding-bottom: 15px; -} - -a { - transition: background 300ms; - padding: 0 0.1em; - text-decoration: none; - border-bottom: 1px solid $color-border; - color: $color-primary; - &:hover { - color: black !important; - background: #fffaf1; - } - &:after { - position: relative; - top: -0.5em; - font-size: 0.7em; - content: "β†—"; - color: #aaaaaa; - } - &.internal-link:after, - &.footnote:after, - &.reversefootnote:after { - content: ""; - } -} - -content a.internal-link:before { - content: "[[" -} - -content a.internal-link:after { - content: "]]"; - color: $color-text; - top: auto; - font-size: 1rem; -} - -div.footnotes { - font-size: 0.8em; - border-top: 1px solid $color-border -} - -*:focus { - background: #ffe8bc !important; - color: black !important; -} - -nav { - margin: 1em 0 3em; -} - -#notes-entry-container { - display: grid; - grid-gap: 2em; - grid-template-areas: - "content" - "side"; - - @media (min-width: 700px) { - grid-template-columns: 3fr 1fr; - grid-template-areas: "content side"; - } -} - -.backlink-box { - background: $color-box-background; - padding: 1em; - border-radius: $border-radius; -} - -code { - background: #f5f5f5; - padding: 0.1em 0.2em; - border-radius: 4px; -} - -.invalid-link { - color: #444444; - cursor: help; - background: #fafafa; - padding: 0 0.1em; -} - -.invalid-link-brackets { - color: #ccc; - cursor: help; -} diff --git a/assets/indices/.gitkeep b/assets/indices/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/assets/js/callouts.js b/assets/js/callouts.js new file mode 100644 index 00000000..080bbb48 --- /dev/null +++ b/assets/js/callouts.js @@ -0,0 +1,6 @@ +const addCollapsibleCallouts = () => { + const collapsibleCallouts = document.querySelectorAll("blockquote.callout-collapsible"); + collapsibleCallouts.forEach(el => el.addEventListener('click', event => { + event.currentTarget.classList.toggle("callout-collapsed"); + })); +} diff --git a/assets/js/clipboard.js b/assets/js/clipboard.js new file mode 100644 index 00000000..10e02c68 --- /dev/null +++ b/assets/js/clipboard.js @@ -0,0 +1,45 @@ +const svgCopy = + ''; +const svgCheck = + ''; + + +const addCopyButtons = () => { + let els = document.getElementsByClassName("highlight"); + // for each highlight + for (let i = 0; i < els.length; i++) { + try { + if (els[i].getElementsByClassName("clipboard-button").length) continue; + + // find pre > code inside els[i] + let codeBlocks = els[i].getElementsByTagName("code"); + + // line numbers are inside first code block + let lastCodeBlock = codeBlocks[codeBlocks.length - 1]; + const button = document.createElement("button"); + button.className = "clipboard-button"; + button.type = "button"; + button.innerHTML = svgCopy; + button.ariaLabel = "opy the shown code"; + // remove every second newline from lastCodeBlock.innerText + button.addEventListener("click", () => { + navigator.clipboard.writeText(lastCodeBlock.innerText.replace(/\n\n/g, "\n")).then( + () => { + button.blur(); + button.innerHTML = svgCheck; + setTimeout(() => { + button.innerHTML = svgCopy + button.style.borderColor = "" + }, 2000); + }, + (error) => (button.innerHTML = "Error") + ); + }); + // find chroma inside els[i] + let chroma = els[i].getElementsByClassName("chroma")[0]; + els[i].insertBefore(button, chroma); + } catch(error) { + console.debug(error); + } + } +} diff --git a/assets/js/code-title.js b/assets/js/code-title.js new file mode 100644 index 00000000..325e16d5 --- /dev/null +++ b/assets/js/code-title.js @@ -0,0 +1,17 @@ + +function addTitleToCodeBlocks() { + const els = document.getElementsByClassName("highlight"); + for (let i = 0; i < els.length; i++) { + try { + if (els[i].title.length) { + let div = document.createElement("div"); + if (els[i].getElementsByClassName("code-title").length) continue; + div.textContent = els[i].title; + div.classList.add("code-title") + els[i].insertBefore(div, els[i].firstChild); + } + } catch (error) { + console.debug(error); + } + } +} diff --git a/assets/js/darkmode.js b/assets/js/darkmode.js new file mode 100644 index 00000000..8168d77e --- /dev/null +++ b/assets/js/darkmode.js @@ -0,0 +1,37 @@ +const userPref = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark' +const currentTheme = localStorage.getItem('theme') ?? userPref +const syntaxTheme = document.querySelector("#theme-link"); + + +{{ $darkSyntax := resources.Get "styles/_dark_syntax.scss" | resources.ToCSS (dict "outputStyle" "compressed") | resources.Fingerprint "md5" | resources.Minify }} +{{ $lightSyntax := resources.Get "styles/_light_syntax.scss" | resources.ToCSS (dict "outputStyle" "compressed") | resources.Fingerprint "md5" | resources.Minify }} + +if (currentTheme) { + document.documentElement.setAttribute('saved-theme', currentTheme); + syntaxTheme.href = currentTheme === 'dark' ? '{{ $darkSyntax.Permalink }}' : '{{ $lightSyntax.Permalink }}'; +} + +const switchTheme = (e) => { + if (e.target.checked) { + document.documentElement.setAttribute('saved-theme', 'dark'); + localStorage.setItem('theme', 'dark'); + syntaxTheme.href = '{{ $darkSyntax.Permalink }}'; + } + else { + document.documentElement.setAttribute('saved-theme', 'light') + localStorage.setItem('theme', 'light') + syntaxTheme.href = '{{ $lightSyntax.Permalink }}'; + } +} + +window.addEventListener('DOMContentLoaded', () => { + // Darkmode toggle + const toggleSwitch = document.querySelector('#darkmode-toggle') + + // listen for toggle + toggleSwitch.addEventListener('change', switchTheme, false) + + if (currentTheme === 'dark') { + toggleSwitch.checked = true + } +}) diff --git a/assets/js/full-text-search.js b/assets/js/full-text-search.js new file mode 100644 index 00000000..709a3b36 --- /dev/null +++ b/assets/js/full-text-search.js @@ -0,0 +1,61 @@ +; (async function() { + const encoder = (str) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])/) + const contentIndex = new FlexSearch.Document({ + cache: true, + charset: "latin:extra", + optimize: true, + index: [ + { + field: "content", + tokenize: "reverse", + encode: encoder, + }, + { + field: "title", + tokenize: "forward", + encode: encoder, + }, + ], + }) + + const { content } = await fetchData + for (const [key, value] of Object.entries(content)) { + contentIndex.add({ + id: key, + title: value.title, + content: removeMarkdown(value.content), + }) + } + + const formatForDisplay = (id) => ({ + id, + url: id, + title: content[id].title, + content: content[id].content, + }) + + registerHandlers((e) => { + const term = e.target.value + const searchResults = contentIndex.search(term, [ + { + field: "content", + limit: 10, + }, + { + field: "title", + limit: 5, + }, + ]) + const getByField = (field) => { + const results = searchResults.filter((x) => x.field === field) + if (results.length === 0) { + return [] + } else { + return [...results[0].result] + } + } + const allIds = new Set([...getByField("title"), ...getByField("content")]) + const finalResults = [...allIds].map(formatForDisplay) + displayResults(term, finalResults, true) + }) +})() diff --git a/assets/js/graph.js b/assets/js/graph.js new file mode 100644 index 00000000..ce0c73b7 --- /dev/null +++ b/assets/js/graph.js @@ -0,0 +1,279 @@ +async function drawGraph(baseUrl, isHome, pathColors, graphConfig) { + + let { + depth, + enableDrag, + enableLegend, + enableZoom, + opacityScale, + scale, + repelForce, + fontSize } = graphConfig; + + const container = document.getElementById("graph-container") + const { index, links, content } = await fetchData + + // Use .pathname to remove hashes / searchParams / text fragments + const cleanUrl = window.location.origin + window.location.pathname + + const curPage = cleanUrl.replace(/\/$/g, "").replace(baseUrl, "") + + const parseIdsFromLinks = (links) => [ + ...new Set(links.flatMap((link) => [link.source, link.target])), + ] + + // Links is mutated by d3. We want to use links later on, so we make a copy and pass that one to d3 + // Note: shallow cloning does not work because it copies over references from the original array + const copyLinks = JSON.parse(JSON.stringify(links)) + + const neighbours = new Set() + const wl = [curPage || "/", "__SENTINEL"] + if (depth >= 0) { + while (depth >= 0 && wl.length > 0) { + // compute neighbours + const cur = wl.shift() + if (cur === "__SENTINEL") { + depth-- + wl.push("__SENTINEL") + } else { + neighbours.add(cur) + const outgoing = index.links[cur] || [] + const incoming = index.backlinks[cur] || [] + wl.push(...outgoing.map((l) => l.target), ...incoming.map((l) => l.source)) + } + } + } else { + parseIdsFromLinks(copyLinks).forEach((id) => neighbours.add(id)) + } + + const data = { + nodes: [...neighbours].map((id) => ({ id })), + links: copyLinks.filter((l) => neighbours.has(l.source) && neighbours.has(l.target)), + } + + const color = (d) => { + if (d.id === curPage || (d.id === "/" && curPage === "")) { + return "var(--g-node-active)" + } + + for (const pathColor of pathColors) { + const path = Object.keys(pathColor)[0] + const colour = pathColor[path] + if (d.id.startsWith(path)) { + return colour + } + } + + return "var(--g-node)" + } + + const drag = (simulation) => { + function dragstarted(event, d) { + if (!event.active) simulation.alphaTarget(1).restart() + d.fx = d.x + d.fy = d.y + } + + function dragged(event, d) { + d.fx = event.x + d.fy = event.y + } + + function dragended(event, d) { + if (!event.active) simulation.alphaTarget(0) + d.fx = null + d.fy = null + } + + const noop = () => { } + return d3 + .drag() + .on("start", enableDrag ? dragstarted : noop) + .on("drag", enableDrag ? dragged : noop) + .on("end", enableDrag ? dragended : noop) + } + + const height = Math.max(container.offsetHeight, isHome ? 500 : 250) + const width = container.offsetWidth + + const simulation = d3 + .forceSimulation(data.nodes) + .force("charge", d3.forceManyBody().strength(-100 * repelForce)) + .force( + "link", + d3 + .forceLink(data.links) + .id((d) => d.id) + .distance(40), + ) + .force("center", d3.forceCenter()) + + const svg = d3 + .select("#graph-container") + .append("svg") + .attr("width", width) + .attr("height", height) + .attr('viewBox', [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale]) + + if (enableLegend) { + const legend = [{ Current: "var(--g-node-active)" }, { Note: "var(--g-node)" }, ...pathColors] + legend.forEach((legendEntry, i) => { + const key = Object.keys(legendEntry)[0] + const colour = legendEntry[key] + svg + .append("circle") + .attr("cx", -width / 2 + 20) + .attr("cy", height / 2 - 30 * (i + 1)) + .attr("r", 6) + .style("fill", colour) + svg + .append("text") + .attr("x", -width / 2 + 40) + .attr("y", height / 2 - 30 * (i + 1)) + .text(key) + .style("font-size", "15px") + .attr("alignment-baseline", "middle") + }) + } + + // draw links between nodes + const link = svg + .append("g") + .selectAll("line") + .data(data.links) + .join("line") + .attr("class", "link") + .attr("stroke", "var(--g-link)") + .attr("stroke-width", 2) + .attr("data-source", (d) => d.source.id) + .attr("data-target", (d) => d.target.id) + + // svg groups + const graphNode = svg.append("g").selectAll("g").data(data.nodes).enter().append("g") + + // calculate radius + const nodeRadius = (d) => { + const numOut = index.links[d.id]?.length || 0 + const numIn = index.backlinks[d.id]?.length || 0 + return 2 + Math.sqrt(numOut + numIn) + } + + // draw individual nodes + const node = graphNode + .append("circle") + .attr("class", "node") + .attr("id", (d) => d.id) + .attr("r", nodeRadius) + .attr("fill", color) + .style("cursor", "pointer") + .on("click", (_, d) => { + // SPA navigation + const targ = `${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/` + window.Million.navigate(new URL(targ), ".singlePage") + plausible("Link Click", { + props: { + href: targ, + broken: false, + internal: true, + graph: true, + } + }) + }) + .on("mouseover", function(_, d) { + d3.selectAll(".node").transition().duration(100).attr("fill", "var(--g-node-inactive)") + + const neighbours = parseIdsFromLinks([ + ...(index.links[d.id] || []), + ...(index.backlinks[d.id] || []), + ]) + const neighbourNodes = d3.selectAll(".node").filter((d) => neighbours.includes(d.id)) + const currentId = d.id + window.Million.prefetch(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`)) + const linkNodes = d3 + .selectAll(".link") + .filter((d) => d.source.id === currentId || d.target.id === currentId) + + // highlight neighbour nodes + neighbourNodes.transition().duration(200).attr("fill", color) + + // highlight links + linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)") + + const bigFont = fontSize * 1.5 + + // show text for self + d3.select(this.parentNode) + .raise() + .select("text") + .transition() + .duration(200) + .attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity")) + .style('opacity', 1) + .style('font-size', bigFont + 'em') + .attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px + }) + .on("mouseleave", function(_, d) { + d3.selectAll(".node").transition().duration(200).attr("fill", color) + + const currentId = d.id + const linkNodes = d3 + .selectAll(".link") + .filter((d) => d.source.id === currentId || d.target.id === currentId) + + linkNodes.transition().duration(200).attr("stroke", "var(--g-link)") + + d3.select(this.parentNode) + .select("text") + .transition() + .duration(200) + .style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld")) + .style('font-size', fontSize + 'em') + .attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px + }) + .call(drag(simulation)) + + // draw labels + const labels = graphNode + .append("text") + .attr("dx", 0) + .attr("dy", (d) => nodeRadius(d) + 8 + "px") + .attr("text-anchor", "middle") + .text((d) => content[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " ")) + .style('opacity', (opacityScale - 1) / 3.75) + .style("pointer-events", "none") + .style('font-size', fontSize + 'em') + .raise() + .call(drag(simulation)) + + // set panning + + if (enableZoom) { + svg.call( + d3 + .zoom() + .extent([ + [0, 0], + [width, height], + ]) + .scaleExtent([0.25, 4]) + .on("zoom", ({ transform }) => { + link.attr("transform", transform) + node.attr("transform", transform) + const scale = transform.k * opacityScale; + const scaledOpacity = Math.max((scale - 1) / 3.75, 0) + labels.attr("transform", transform).style("opacity", scaledOpacity) + }), + ) + } + + // progress the simulation + simulation.on("tick", () => { + link + .attr("x1", (d) => d.source.x) + .attr("y1", (d) => d.source.y) + .attr("x2", (d) => d.target.x) + .attr("y2", (d) => d.target.y) + node.attr("cx", (d) => d.x).attr("cy", (d) => d.y) + labels.attr("x", (d) => d.x).attr("y", (d) => d.y) + }) +} diff --git a/assets/js/popover.js b/assets/js/popover.js new file mode 100644 index 00000000..101d1c0c --- /dev/null +++ b/assets/js/popover.js @@ -0,0 +1,79 @@ +function htmlToElement(html) { + const template = document.createElement("template") + html = html.trim() + template.innerHTML = html + return template.content.firstChild +} + +function initPopover(baseURL, useContextualBacklinks) { + const basePath = baseURL.replace(window.location.origin, "") + fetchData.then(({ content }) => { + const links = [...document.getElementsByClassName("internal-link")] + links + .filter(li => li.dataset.src || (li.dataset.idx && useContextualBacklinks)) + .forEach(li => { + let el + if (li.dataset.ctx) { + const linkDest = content[li.dataset.src] + const popoverElement = `
+

${linkDest.title}

+

${highlight(removeMarkdown(linkDest.content), li.dataset.ctx)}...

+

${new Date(linkDest.lastmodified).toLocaleDateString()}

+
` + el = htmlToElement(popoverElement) + } else { + const linkDest = content[li.dataset.src.replace(/\/$/g, "").replace(basePath, "")] + if (linkDest) { + let splitLink = li.href.split("#") + let cleanedContent = removeMarkdown(linkDest.content) + if (splitLink.length > 1) { + let headingName = decodeURIComponent(splitLink[1]).replace(/\-/g, " ") + let headingIndex = cleanedContent.toLowerCase().indexOf("" + headingName + "") + cleanedContent = cleanedContent.substring(headingIndex, cleanedContent.length) + } + const popoverElement = `
+

${linkDest.title}

+

${cleanedContent.split(" ", 20).join(" ")}...

+

${new Date(linkDest.lastmodified).toLocaleDateString()}

+
` + el = htmlToElement(popoverElement) + } + } + + if (el) { + li.appendChild(el) + if (LATEX_ENABLED) { + renderMathInElement(el, { + delimiters: [ + { left: '$$', right: '$$', display: false }, + { left: '$', right: '$', display: false }, + ], + throwOnError: false + }) + } + + li.addEventListener("mouseover", () => { + // fix tooltip positioning + window.FloatingUIDOM.computePosition(li, el, { + middleware: [window.FloatingUIDOM.offset(10), window.FloatingUIDOM.inline(), window.FloatingUIDOM.shift()], + }).then(({ x, y }) => { + Object.assign(el.style, { + left: `${x}px`, + top: `${y}px`, + }) + }) + + el.classList.add("visible") + plausible("Popover Hover", { + props: { + href: li.dataset.src + } + }) + }) + li.addEventListener("mouseout", () => { + el.classList.remove("visible") + }) + } + }) + }) +} diff --git a/assets/js/router.js b/assets/js/router.js new file mode 100644 index 00000000..c29ab773 --- /dev/null +++ b/assets/js/router.js @@ -0,0 +1,25 @@ +import { + apply, + navigate, + prefetch, + router, +} from "https://unpkg.com/million@1.11.5/dist/router.mjs" + +export const attachSPARouting = (init, rerender) => { + // Attach SPA functions to the global Million namespace + window.Million = { + apply, + navigate, + prefetch, + router, + } + + const render = () => requestAnimationFrame(rerender) + window.addEventListener("DOMContentLoaded", () => { + apply((doc) => init(doc)) + init() + router(".singlePage") + render() + }) + window.addEventListener("million:navigate", render) +} diff --git a/assets/js/semantic-search.js b/assets/js/semantic-search.js new file mode 100644 index 00000000..fca2851e --- /dev/null +++ b/assets/js/semantic-search.js @@ -0,0 +1,54 @@ +// Note: Currently, we use the REST API for Operand because of some unpkg/webpack issues. +// In the future, we'd like to use the SDK (https://github.com/operandinc/typescript-sdk). +// If someone knows how to do this w/o breaking the Operand typescript-sdk for npm users, +// please let Morgan (@morgallant) and/or (@_jzhao) know! <3 + +const apiKey = "{{$.Site.Data.config.search.operandApiKey}}" +const indexId = "{{$.Site.Data.config.search.operandIndexId}}" + +function parseSearchResults(searchResults) { + return searchResults.matches.map((m) => ({ + content: m.content, + title: searchResults.objects[m.objectId].properties.properties._title.text, + url: searchResults.objects[m.objectId].properties.properties._url.text, + })) +} + +async function searchContents(query) { + const result = await fetch("https://api.operand.ai/operand.v1.ObjectService/SearchWithin", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `${apiKey}`, + "Operand-Index-ID": `${indexId}`, + }, + body: JSON.stringify({ + query: query, + limit: 10, + }), + }) + if (result.ok) { + return parseSearchResults(await result.json()) + } else { + console.error(result) + } +} + +function debounce(func, timeout = 200) { + let timer + return (...args) => { + clearTimeout(timer) + timer = setTimeout(() => { + func.apply(this, args) + }, timeout) + } +} + +registerHandlers( + debounce((e) => { + let term = e.target.value + if (term !== "") { + searchContents(term).then((results) => displayResults(term, results)) + } + }), +) diff --git a/assets/js/util.js b/assets/js/util.js new file mode 100644 index 00000000..530bd7dc --- /dev/null +++ b/assets/js/util.js @@ -0,0 +1,226 @@ +// code from https://github.com/danestves/markdown-to-text +const removeMarkdown = ( + markdown, + options = { + listUnicodeChar: false, + stripListLeaders: true, + gfm: true, + useImgAltText: false, + preserveLinks: false, + }, +) => { + let output = markdown || "" + output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, "") + + try { + if (options.stripListLeaders) { + if (options.listUnicodeChar) + output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, options.listUnicodeChar + " $1") + else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, "$1") + } + if (options.gfm) { + output = output + .replace(/\n={2,}/g, "\n") + .replace(/~{3}.*\n/g, "") + .replace(/~~/g, "") + .replace(/`{3}.*\n/g, "") + } + if (options.preserveLinks) { + output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, "$1 ($2)") + } + output = output + .replace(/<[^>]*>/g, "") + .replace(/^[=\-]{2,}\s*$/g, "") + .replace(/\[\^.+?\](\: .*?$)?/g, "") + .replace(/(#{1,6})\s+(.+)\1?/g, "$2") + .replace(/\s{0,2}\[.*?\]: .*?$/g, "") + .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "") + .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, "$1") + .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, "$1") + .replace(/^\s{0,3}>\s?/g, "") + .replace(/(^|\n)\s{0,3}>\s?/g, "\n\n") + .replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "") + .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2") + .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2") + .replace(/(`{3,})(.*?)\1/gm, "$2") + .replace(/`(.+?)`/g, "$1") + .replace(/\n{2,}/g, "\n\n") + .replace(/\[![a-zA-Z]+\][-\+]? /g, "") + } catch (e) { + console.error(e) + return markdown + } + return output +} + +const highlight = (content, term) => { + const highlightWindow = 20 + // try to find direct match first + const directMatchIdx = content.indexOf(term) + if (directMatchIdx !== -1) { + const h = highlightWindow + const before = content.substring(0, directMatchIdx).split(" ").slice(-h) + const after = content + .substring(directMatchIdx + term.length, content.length - 2) + .split(" ") + .slice(0, h) + return ( + (before.length === h ? `...${before.join(" ")}` : before.join(" ")) + + `${term}` + + after.join(" ") + ) + } + + const tokenizedTerm = term.split(/\s+/).filter((t) => t !== "") + const splitText = content.split(/\s+/).filter((t) => t !== "") + const includesCheck = (token) => + tokenizedTerm.some((term) => token.toLowerCase().startsWith(term.toLowerCase())) + + const occurrencesIndices = splitText.map(includesCheck) + + // calculate best index + let bestSum = 0 + let bestIndex = 0 + for (let i = 0; i < Math.max(occurrencesIndices.length - highlightWindow, 0); i++) { + const window = occurrencesIndices.slice(i, i + highlightWindow) + const windowSum = window.reduce((total, cur) => total + cur, 0) + if (windowSum >= bestSum) { + bestSum = windowSum + bestIndex = i + } + } + + const startIndex = Math.max(bestIndex - highlightWindow, 0) + const endIndex = Math.min(startIndex + 2 * highlightWindow, splitText.length) + const mappedText = splitText + .slice(startIndex, endIndex) + .map((token) => { + if (includesCheck(token)) { + return `${token}` + } + return token + }) + .join(" ") + .replaceAll(' ', " ") + return `${startIndex === 0 ? "" : "..."}${mappedText}${endIndex === splitText.length ? "" : "..." + }` +} + +// Common utilities for search +const resultToHTML = ({ url, title, content }) => { + return `` +} + +const redir = (id, term) => { + const shouldTrim = PRODUCTION && SEARCH_ENABLED + const baseURLPrefix = shouldTrim ? "" : BASE_URL.replace(/\/$/g, "") + const urlString = `${baseURLPrefix}${id}#:~:text=${encodeURIComponent(term)}/` + window.Million.navigate( + new URL(urlString), + ".singlePage", + ) + closeSearch() + plausible("Search", { + props: { + term + } + }) +} + +function openSearch() { + const source = document.getElementById("search-bar") + const results = document.getElementById("results-container") + const searchContainer = document.getElementById("search-container") + if (searchContainer.style.display === "none" || searchContainer.style.display === "") { + source.value = "" + results.innerHTML = "" + searchContainer.style.display = "block" + source.focus() + } else { + searchContainer.style.display = "none" + } +} + +function closeSearch() { + const searchContainer = document.getElementById("search-container") + searchContainer.style.display = "none" +} + +const registerHandlers = (onInputFn) => { + const source = document.getElementById("search-bar") + const searchContainer = document.getElementById("search-container") + let term + source.addEventListener("keyup", (e) => { + if (e.key === "Enter") { + const anchor = document.getElementsByClassName("result-card")[0] + redir(anchor.id, term) + } + }) + source.addEventListener("input", onInputFn) + document.addEventListener("keydown", (event) => { + if (event.key === "k" && (event.ctrlKey || event.metaKey)) { + event.preventDefault() + openSearch() + } + if (event.key === "Escape") { + event.preventDefault() + closeSearch() + } + }) + + const searchButton = document.getElementById("search-icon") + searchButton.addEventListener("click", (_) => { + openSearch() + }) + searchButton.addEventListener("keydown", (_) => { + openSearch() + }) + searchContainer.addEventListener("click", (_) => { + closeSearch() + }) + document.getElementById("search-space").addEventListener("click", (evt) => { + evt.stopPropagation() + }) +} + +const displayResults = (term, finalResults, extractHighlight = false) => { + const results = document.getElementById("results-container") + if (finalResults.length === 0) { + results.innerHTML = `` + } else { + results.innerHTML = finalResults + .map((result) => { + if (extractHighlight) { + return resultToHTML({ + url: result.url, + title: highlight(result.title, term), + content: highlight(removeMarkdown(result.content), term) + }) + } else { + return resultToHTML(result) + } + } + ) + .join("\n") + if (LATEX_ENABLED) { + renderMathInElement(results, { + delimiters: [ + { left: '$$', right: '$$', display: false }, + { left: '$', right: '$', display: false }, + ], + throwOnError: false + }) + } + + const anchors = [...document.getElementsByClassName("result-card")] + anchors.forEach((anchor) => { + anchor.onclick = () => redir(anchor.id, term) + }) + } +} diff --git a/assets/styles/_callouts.scss b/assets/styles/_callouts.scss new file mode 100644 index 00000000..04fd2f66 --- /dev/null +++ b/assets/styles/_callouts.scss @@ -0,0 +1,170 @@ +:root { + --callout-summary: #00b0ff; + --callout-summary-accent: #7fd7ff; + --callout-bug: #f50057; + --callout-bug-accent: #ff7aa9; + --callout-danger: #ff1744; + --callout-danger-accent: #ff8aa1; + --callout-example: #7c4dff; + --callout-example-accent: #bda5ff; + --callout-fail: #ff5252; + --callout-fail-accent: #ffa8a8; + --callout-info: #00b8d4; + --callout-info-accent: #69ebff; + --callout-note: #448aff; + --callout-note-accent: #a1c4ff; + --callout-question: #64dd17; + --callout-question-accent: #b0f286; + --callout-quote: #9e9e9e; + --callout-quote-accent: #cecece; + --callout-done: #00c853; + --callout-done-accent: #63ffa4; + --callout-important: #00bfa5; + --callout-important-accent: #5fffe9; + --callout-warning: #ff9100; + --callout-warning-accent: #ffc87f; +} + +[saved-theme=dark] { + --callout-summary: #00b0ff !important; + --callout-summary-accent: #00587f !important; + --callout-bug: #f50057 !important; + --callout-bug-accent: #7a002b !important; + --callout-danger: #ff1744 !important; + --callout-danger-accent: #8b001a !important; + --callout-example: #7c4dff !important; + --callout-example-accent: #2b00a6 !important; + --callout-fail: #ff5252 !important; + --callout-fail-accent: #a80000 !important; + --callout-info: #00b8d4 !important; + --callout-info-accent: #005c6a !important; + --callout-note: #448aff !important; + --callout-note-accent: #003ca1 !important; + --callout-question: #64dd17 !important; + --callout-question-accent: #006429 !important; + --callout-quote: #9e9e9e !important; + --callout-quote-accent: #4f4f4f !important; + --callout-done: #00c853 !important; + --callout-done-accent: #006429 !important; + --callout-important: #00bfa5 !important; + --callout-important-accent: #005f52 !important; + --callout-warning: #ff9100 !important; + --callout-warning-accent: #7f4800 !important; +} + +blockquote.callout-collapsible { + cursor: pointer; + + &.callout-collapsible::after { + content: '-'; + right: 6px; + font-weight: bolder; + font-family: Courier New, Courier, monospace; + } +} + +blockquote.callout-collapsed { + & > p { border-bottom-right-radius: 5px !important; } + padding-bottom: 0 !important; + &::after { + content: '+' !important; + } + & > *:not(:first-child) { + display: none !important; + } +} + +blockquote[class*="-callout"] { + margin-right: 0; + border-radius: 5px; + position: relative; + padding-left: 0 !important; + padding-bottom: 0.25em; + color: var(--dark); + background-color: var(--lightgray); + border-left: 6px solid var(--primary) !important; + & > p { + border-top-right-radius: 5px; + padding: 0.5em 1em; + margin: 0; + color: var(--gray); + &:first-child { + font-weight: 600; + color: var(--dark); + padding: 0.4em 30px; + } + } +} + +blockquote[class*="-callout"] > p:first-child::after, blockquote.callout-collapsible::after { + display: inline-block; + height: 18px; + width: 18px; + position: absolute; + top: 0.4em; + margin: 0.2em 0.4em; +} + +blockquote[class*="-callout"] > p:first-child { + font-weight: bold; + padding: 0.4em 35px; + + &::after { + left: 0; + } +} + +$summary: summary, abstract, tldr; +$bug: bug; +$danger: danger, error; +$example: example; +$fail: fail, failure, missing; +$info: info, todo; +$note: note; +$question: question, help, faq; +$quote: quote, cite; +$done: done, success, check; +$important: important, tip, hint; +$warning: warning, caution, attention; +$types: $summary, $bug, $danger, $example, $fail, $info, $note, $question, $quote, $done, $important, $warning; +$svgs: (); +$svgs: map-merge($svgs, ($summary: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='book' class='svg-inline--callout-fa fa-book fa-w-14' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath fill='currentColor' d='M448 360V24c0-13.3-10.7-24-24-24H96C43 0 0 43 0 96v320c0 53 43 96 96 96h328c13.3 0 24-10.7 24-24v-16c0-7.5-3.5-14.3-8.9-18.7-4.2-15.4-4.2-59.3 0-74.7 5.4-4.3 8.9-11.1 8.9-18.6zM128 134c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm0 64c0-3.3 2.7-6 6-6h212c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H134c-3.3 0-6-2.7-6-6v-20zm253.4 250H96c-17.7 0-32-14.3-32-32 0-17.6 14.4-32 32-32h285.4c-1.9 17.1-1.9 46.9 0 64z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($bug: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='bug' class='svg-inline--callout-fa fa-bug fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M511.988 288.9c-.478 17.43-15.217 31.1-32.653 31.1H424v16c0 21.864-4.882 42.584-13.6 61.145l60.228 60.228c12.496 12.497 12.496 32.758 0 45.255-12.498 12.497-32.759 12.496-45.256 0l-54.736-54.736C345.886 467.965 314.351 480 280 480V236c0-6.627-5.373-12-12-12h-24c-6.627 0-12 5.373-12 12v244c-34.351 0-65.886-12.035-90.636-32.108l-54.736 54.736c-12.498 12.497-32.759 12.496-45.256 0-12.496-12.497-12.496-32.758 0-45.255l60.228-60.228C92.882 378.584 88 357.864 88 336v-16H32.666C15.23 320 .491 306.33.013 288.9-.484 270.816 14.028 256 32 256h56v-58.745l-46.628-46.628c-12.496-12.497-12.496-32.758 0-45.255 12.498-12.497 32.758-12.497 45.256 0L141.255 160h229.489l54.627-54.627c12.498-12.497 32.758-12.497 45.256 0 12.496 12.497 12.496 32.758 0 45.255L424 197.255V256h56c17.972 0 32.484 14.816 31.988 32.9zM257 0c-61.856 0-112 50.144-112 112h224C369 50.144 318.856 0 257 0z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($danger: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='bolt' class='svg-inline--callout-fa fa-bolt fa-w-10' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 512'%3E%3Cpath fill='currentColor' d='M296 160H180.6l42.6-129.8C227.2 15 215.7 0 200 0H56C44 0 33.8 8.9 32.2 20.8l-32 240C-1.7 275.2 9.5 288 24 288h118.7L96.6 482.5c-3.6 15.2 8 29.5 23.3 29.5 8.4 0 16.4-4.4 20.8-12l176-304c9.3-15.9-2.2-36-20.7-36z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($example: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='list-ol' class='svg-inline--callout-fa fa-list-ol fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M61.77 401l17.5-20.15a19.92 19.92 0 0 0 5.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h22.83a157.41 157.41 0 0 0-11 12.31l-5.61 7c-4 5.07-5.25 10.13-2.8 14.88l1.05 1.93c3 5.76 6.29 7.88 12.25 7.88h4.73c10.33 0 15.94 2.44 15.94 9.09 0 4.72-4.2 8.22-14.36 8.22a41.54 41.54 0 0 1-15.47-3.12c-6.49-3.88-11.74-3.5-15.6 3.12l-5.59 9.31c-3.72 6.13-3.19 11.72 2.63 15.94 7.71 4.69 20.38 9.44 37 9.44 34.16 0 48.5-22.75 48.5-44.12-.03-14.38-9.12-29.76-28.73-34.88zM496 224H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM16 160h64a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H64V40a8 8 0 0 0-8-8H32a8 8 0 0 0-7.14 4.42l-8 16A8 8 0 0 0 24 64h8v64H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8zm-3.91 160H80a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H41.32c3.29-10.29 48.34-18.68 48.34-56.44 0-29.06-25-39.56-44.47-39.56-21.36 0-33.8 10-40.46 18.75-4.37 5.59-3 10.84 2.8 15.37l8.58 6.88c5.61 4.56 11 2.47 16.12-2.44a13.44 13.44 0 0 1 9.46-3.84c3.33 0 9.28 1.56 9.28 8.75C51 248.19 0 257.31 0 304.59v4C0 316 5.08 320 12.09 320z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($fail: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='times-circle' class='svg-inline--callout-fa fa-times-circle fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($info: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='info-circle' class='svg-inline--callout-fa fa-info-circle fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($note: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='pencil-alt' class='svg-inline--callout-fa fa-pencil-alt fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($question: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='question-circle' class='svg-inline--callout-fa fa-question-circle fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zM262.655 90c-54.497 0-89.255 22.957-116.549 63.758-3.536 5.286-2.353 12.415 2.715 16.258l34.699 26.31c5.205 3.947 12.621 3.008 16.665-2.122 17.864-22.658 30.113-35.797 57.303-35.797 20.429 0 45.698 13.148 45.698 32.958 0 14.976-12.363 22.667-32.534 33.976C247.128 238.528 216 254.941 216 296v4c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12v-1.333c0-28.462 83.186-29.647 83.186-106.667 0-58.002-60.165-102-116.531-102zM256 338c-25.365 0-46 20.635-46 46 0 25.364 20.635 46 46 46s46-20.636 46-46c0-25.365-20.635-46-46-46z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($quote: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='quote-right' class='svg-inline--callout-fa fa-quote-right fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M464 32H336c-26.5 0-48 21.5-48 48v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48zm-288 0H48C21.5 32 0 53.5 0 80v128c0 26.5 21.5 48 48 48h80v64c0 35.3-28.7 64-64 64h-8c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h8c88.4 0 160-71.6 160-160V80c0-26.5-21.5-48-48-48z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($done: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='check-circle' class='svg-inline--callout-fa fa-check-circle fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='currentColor' d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($important: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='fire' class='svg-inline--callout-fa fa-fire fa-w-12' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath fill='currentColor' d='M216 23.86c0-23.8-30.65-32.77-44.15-13.04C48 191.85 224 200 224 288c0 35.63-29.11 64.46-64.85 63.99-35.17-.45-63.15-29.77-63.15-64.94v-85.51c0-21.7-26.47-32.23-41.43-16.5C27.8 213.16 0 261.33 0 320c0 105.87 86.13 192 192 192s192-86.13 192-192c0-170.29-168-193-168-296.14z'%3E%3C/path%3E%3C/svg%3E"))); +$svgs: map-merge($svgs, ($warning: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-icon='exclamation-triangle' class='svg-inline--callout-fa fa-exclamation-triangle fa-w-18' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 576 512'%3E%3Cpath fill='currentColor' d='M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z'%3E%3C/path%3E%3C/svg%3E"))); + +@function getstr($l) { + $v: nth($l, 1); + @return $v; +} + +@each $type in $types { + @each $s in $type { + blockquote.#{$s}-callout { + border-left: 6px solid var(--callout-#{getstr($type)}) !important; + & > p:first-child { + background-color: var(--callout-#{getstr($type)}-accent) !important; + &::after { + content: ''; + -webkit-mask: map-get($svgs, $type); + mask: map-get($svgs, $type); + background-color: var(--callout-#{getstr($type)}) !important; + -webkit-mask-size: contain; + mask-size: contain; + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + } + } + } + } +} diff --git a/assets/styles/_dark_syntax.scss b/assets/styles/_dark_syntax.scss new file mode 100644 index 00000000..9d2019a8 --- /dev/null +++ b/assets/styles/_dark_syntax.scss @@ -0,0 +1,85 @@ +/* Background */ .bg { color: #f8f8f2; background-color: #282a36; } +/* PreWrapper */ .chroma { color: #f8f8f2; background-color: #282a36; } +/* Other */ .chroma .x { } +/* Error */ .chroma .err { } +/* CodeLine */ .chroma .cl { } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } +/* LineHighlight */ .chroma .hl { background-color: #ffffcc } +/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Line */ .chroma .line { display: flex; } +/* Keyword */ .chroma .k { color: #ff79c6 } +/* KeywordConstant */ .chroma .kc { color: #ff79c6 } +/* KeywordDeclaration */ .chroma .kd { color: #8be9fd; font-style: italic } +/* KeywordNamespace */ .chroma .kn { color: #ff79c6 } +/* KeywordPseudo */ .chroma .kp { color: #ff79c6 } +/* KeywordReserved */ .chroma .kr { color: #ff79c6 } +/* KeywordType */ .chroma .kt { color: #8be9fd } +/* Name */ .chroma .n { } +/* NameAttribute */ .chroma .na { color: #50fa7b } +/* NameBuiltin */ .chroma .nb { color: #8be9fd; font-style: italic } +/* NameBuiltinPseudo */ .chroma .bp { } +/* NameClass */ .chroma .nc { color: #50fa7b } +/* NameConstant */ .chroma .no { } +/* NameDecorator */ .chroma .nd { } +/* NameEntity */ .chroma .ni { } +/* NameException */ .chroma .ne { } +/* NameFunction */ .chroma .nf { color: #50fa7b } +/* NameFunctionMagic */ .chroma .fm { } +/* NameLabel */ .chroma .nl { color: #8be9fd; font-style: italic } +/* NameNamespace */ .chroma .nn { } +/* NameOther */ .chroma .nx { } +/* NameProperty */ .chroma .py { } +/* NameTag */ .chroma .nt { color: #ff79c6 } +/* NameVariable */ .chroma .nv { color: #8be9fd; font-style: italic } +/* NameVariableClass */ .chroma .vc { color: #8be9fd; font-style: italic } +/* NameVariableGlobal */ .chroma .vg { color: #8be9fd; font-style: italic } +/* NameVariableInstance */ .chroma .vi { color: #8be9fd; font-style: italic } +/* NameVariableMagic */ .chroma .vm { } +/* Literal */ .chroma .l { } +/* LiteralDate */ .chroma .ld { } +/* LiteralString */ .chroma .s { color: #f1fa8c } +/* LiteralStringAffix */ .chroma .sa { color: #f1fa8c } +/* LiteralStringBacktick */ .chroma .sb { color: #f1fa8c } +/* LiteralStringChar */ .chroma .sc { color: #f1fa8c } +/* LiteralStringDelimiter */ .chroma .dl { color: #f1fa8c } +/* LiteralStringDoc */ .chroma .sd { color: #f1fa8c } +/* LiteralStringDouble */ .chroma .s2 { color: #f1fa8c } +/* LiteralStringEscape */ .chroma .se { color: #f1fa8c } +/* LiteralStringHeredoc */ .chroma .sh { color: #f1fa8c } +/* LiteralStringInterpol */ .chroma .si { color: #f1fa8c } +/* LiteralStringOther */ .chroma .sx { color: #f1fa8c } +/* LiteralStringRegex */ .chroma .sr { color: #f1fa8c } +/* LiteralStringSingle */ .chroma .s1 { color: #f1fa8c } +/* LiteralStringSymbol */ .chroma .ss { color: #f1fa8c } +/* LiteralNumber */ .chroma .m { color: #bd93f9 } +/* LiteralNumberBin */ .chroma .mb { color: #bd93f9 } +/* LiteralNumberFloat */ .chroma .mf { color: #bd93f9 } +/* LiteralNumberHex */ .chroma .mh { color: #bd93f9 } +/* LiteralNumberInteger */ .chroma .mi { color: #bd93f9 } +/* LiteralNumberIntegerLong */ .chroma .il { color: #bd93f9 } +/* LiteralNumberOct */ .chroma .mo { color: #bd93f9 } +/* Operator */ .chroma .o { color: #ff79c6 } +/* OperatorWord */ .chroma .ow { color: #ff79c6 } +/* Punctuation */ .chroma .p { } +/* Comment */ .chroma .c { color: #6272a4 } +/* CommentHashbang */ .chroma .ch { color: #6272a4 } +/* CommentMultiline */ .chroma .cm { color: #6272a4 } +/* CommentSingle */ .chroma .c1 { color: #6272a4 } +/* CommentSpecial */ .chroma .cs { color: #6272a4 } +/* CommentPreproc */ .chroma .cp { color: #ff79c6 } +/* CommentPreprocFile */ .chroma .cpf { color: #ff79c6 } +/* Generic */ .chroma .g { } +/* GenericDeleted */ .chroma .gd { color: #ff5555 } +/* GenericEmph */ .chroma .ge { text-decoration: underline } +/* GenericError */ .chroma .gr { } +/* GenericHeading */ .chroma .gh { font-weight: bold } +/* GenericInserted */ .chroma .gi { color: #50fa7b; font-weight: bold } +/* GenericOutput */ .chroma .go { color: #44475a } +/* GenericPrompt */ .chroma .gp { } +/* GenericStrong */ .chroma .gs { } +/* GenericSubheading */ .chroma .gu { font-weight: bold } +/* GenericTraceback */ .chroma .gt { } +/* GenericUnderline */ .chroma .gl { text-decoration: underline } +/* TextWhitespace */ .chroma .w { } diff --git a/assets/styles/_light_syntax.scss b/assets/styles/_light_syntax.scss new file mode 100644 index 00000000..d0f452e0 --- /dev/null +++ b/assets/styles/_light_syntax.scss @@ -0,0 +1,85 @@ +/* Background */ .bg { color: #272822; background-color: #fafafa; } +/* PreWrapper */ .chroma { color: #272822; background-color: #fafafa; } +/* Other */ .chroma .x { } +/* Error */ .chroma .err { } +/* CodeLine */ .chroma .cl { } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } +/* LineHighlight */ .chroma .hl { background-color: #ffffcc } +/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Line */ .chroma .line { display: flex; } +/* Keyword */ .chroma .k { color: #00a8c8 } +/* KeywordConstant */ .chroma .kc { color: #00a8c8 } +/* KeywordDeclaration */ .chroma .kd { color: #00a8c8 } +/* KeywordNamespace */ .chroma .kn { color: #f92672 } +/* KeywordPseudo */ .chroma .kp { color: #00a8c8 } +/* KeywordReserved */ .chroma .kr { color: #00a8c8 } +/* KeywordType */ .chroma .kt { color: #00a8c8 } +/* Name */ .chroma .n { color: #111111 } +/* NameAttribute */ .chroma .na { color: #75af00 } +/* NameBuiltin */ .chroma .nb { color: #111111 } +/* NameBuiltinPseudo */ .chroma .bp { color: #111111 } +/* NameClass */ .chroma .nc { color: #75af00 } +/* NameConstant */ .chroma .no { color: #00a8c8 } +/* NameDecorator */ .chroma .nd { color: #75af00 } +/* NameEntity */ .chroma .ni { color: #111111 } +/* NameException */ .chroma .ne { color: #75af00 } +/* NameFunction */ .chroma .nf { color: #75af00 } +/* NameFunctionMagic */ .chroma .fm { color: #111111 } +/* NameLabel */ .chroma .nl { color: #111111 } +/* NameNamespace */ .chroma .nn { color: #111111 } +/* NameOther */ .chroma .nx { color: #75af00 } +/* NameProperty */ .chroma .py { color: #111111 } +/* NameTag */ .chroma .nt { color: #f92672 } +/* NameVariable */ .chroma .nv { color: #111111 } +/* NameVariableClass */ .chroma .vc { color: #111111 } +/* NameVariableGlobal */ .chroma .vg { color: #111111 } +/* NameVariableInstance */ .chroma .vi { color: #111111 } +/* NameVariableMagic */ .chroma .vm { color: #111111 } +/* Literal */ .chroma .l { color: #ae81ff } +/* LiteralDate */ .chroma .ld { color: #d88200 } +/* LiteralString */ .chroma .s { color: #d88200 } +/* LiteralStringAffix */ .chroma .sa { color: #d88200 } +/* LiteralStringBacktick */ .chroma .sb { color: #d88200 } +/* LiteralStringChar */ .chroma .sc { color: #d88200 } +/* LiteralStringDelimiter */ .chroma .dl { color: #d88200 } +/* LiteralStringDoc */ .chroma .sd { color: #d88200 } +/* LiteralStringDouble */ .chroma .s2 { color: #d88200 } +/* LiteralStringEscape */ .chroma .se { color: #8045ff } +/* LiteralStringHeredoc */ .chroma .sh { color: #d88200 } +/* LiteralStringInterpol */ .chroma .si { color: #d88200 } +/* LiteralStringOther */ .chroma .sx { color: #d88200 } +/* LiteralStringRegex */ .chroma .sr { color: #d88200 } +/* LiteralStringSingle */ .chroma .s1 { color: #d88200 } +/* LiteralStringSymbol */ .chroma .ss { color: #d88200 } +/* LiteralNumber */ .chroma .m { color: #ae81ff } +/* LiteralNumberBin */ .chroma .mb { color: #ae81ff } +/* LiteralNumberFloat */ .chroma .mf { color: #ae81ff } +/* LiteralNumberHex */ .chroma .mh { color: #ae81ff } +/* LiteralNumberInteger */ .chroma .mi { color: #ae81ff } +/* LiteralNumberIntegerLong */ .chroma .il { color: #ae81ff } +/* LiteralNumberOct */ .chroma .mo { color: #ae81ff } +/* Operator */ .chroma .o { color: #f92672 } +/* OperatorWord */ .chroma .ow { color: #f92672 } +/* Punctuation */ .chroma .p { color: #111111 } +/* Comment */ .chroma .c { color: #75715e } +/* CommentHashbang */ .chroma .ch { color: #75715e } +/* CommentMultiline */ .chroma .cm { color: #75715e } +/* CommentSingle */ .chroma .c1 { color: #75715e } +/* CommentSpecial */ .chroma .cs { color: #75715e } +/* CommentPreproc */ .chroma .cp { color: #75715e } +/* CommentPreprocFile */ .chroma .cpf { color: #75715e } +/* Generic */ .chroma .g { } +/* GenericDeleted */ .chroma .gd { } +/* GenericEmph */ .chroma .ge { font-style: italic } +/* GenericError */ .chroma .gr { } +/* GenericHeading */ .chroma .gh { } +/* GenericInserted */ .chroma .gi { } +/* GenericOutput */ .chroma .go { } +/* GenericPrompt */ .chroma .gp { } +/* GenericStrong */ .chroma .gs { font-weight: bold } +/* GenericSubheading */ .chroma .gu { } +/* GenericTraceback */ .chroma .gt { } +/* GenericUnderline */ .chroma .gl { } +/* TextWhitespace */ .chroma .w { } diff --git a/assets/styles/base.scss b/assets/styles/base.scss new file mode 100644 index 00000000..85eb8bcf --- /dev/null +++ b/assets/styles/base.scss @@ -0,0 +1,625 @@ +// Replace this with your own font imports! +@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Inter:wght@400;600;700&family=Source+Sans+Pro:wght@400;600&display=swap'); +:root { + --font-body: "Source Sans Pro"; + --font-header: "Inter"; + --font-mono: "Fira Code" +} + +// typography +html { + scroll-behavior: smooth; + &:lang(ar) { + & p, & h1, & h2, & h3, article, header { + direction: rtl; + text-align: right; + } + } + & footer > p { + text-align: center !important; + } +} + +.singlePage { + padding: 4em 30vw; + margin: 0 auto; + max-width: 1000px; + @media all and (max-width: 1200px) { + padding: 25px 5vw; + } +} + + +body { + margin: 0; + height: 100vh; + width: 100vw; + max-width: 100%; + box-sizing: border-box; + background-color: var(--light); +} + +h1, h2, h3, h4, h5, h6, thead { + font-family: var(--font-header); + color: var(--dark); + font-weight: revert; + margin: 2rem 0 0; + padding: 2rem auto 1rem; + + &:hover > .hanchor { + color: var(--secondary); + } +} + +.hanchor { + font-family: var(--font-header); + opacity: 0.8; + transition: color 0.3s ease; + color: var(--dark); +} + +p, ul, text, a, tr, td, li, ol, ul { + font-family: var(--font-body); + color: var(--gray); + fill: var(--gray); + font-weight: revert; + margin: revert; + padding: revert; +} + +tbody, li, p { + line-height: 1.5em; +} + +.mainTOC { + border-radius: 5px; + padding: 0.75em 0; + + & details { + & summary { + cursor: zoom-in; + font-family: var(--font-header); + color: var(--dark); + font-weight: 700; + } + + &[open] summary { + cursor: zoom-out; + } + } +} + +#TableOfContents > ol { + counter-reset: section; + margin-left: 0; + padding-left: 1.5em; + & > li { + counter-increment: section; + & > ol { + counter-reset: subsection; + & > li { + counter-increment: subsection; + &::marker { + content: counter(section) "." counter(subsection) " "; + } + } + } + } + + & > li::marker { + content: counter(section) " "; + } + + & > li::marker, & > li > ol > li::marker { + font-family: var(--font-body); + font-weight: 700; + } +} + +table { + border: 1px solid var(--outlinegray); + width: 100%; + padding: 1.5em; + border-collapse: collapse; +} + +td, th { + padding: 0.2em 1em; + border: 1px solid var(--outlinegray); +} + +img { + max-width: 100%; + border-radius: 3px; + margin: 1em 0; +} + +p > img + em { + display: block; + transform: translateY(-1em); +} + +sup { + line-height: 0 +} + +blockquote { + margin-left: 0; + border-left: 3px solid var(--secondary); + padding-left: 1em; + transition: border-color 0.2s ease; +} + +.footnotes p { + margin: 0.5em 0; +} + +.pagination { + list-style: none; + padding-left: 0; + display: flex; + margin-top: 2em; + gap: 1.5em; + justify-content: center; + + .disabled { + opacity: 0.2; + } + + & > li { + text-align: center; + display: inline-block; + + & a { + background-color: transparent !important; + } + + & a[href$="#"], &.active a { + opacity: 0.2; + } + } +} + +article { + & > h1 { + margin-top: 2em; + font-size: 2em; + } + + & > .meta { + margin: 0 0 1em 0; + opacity: 0.7; + } + + & a { + font-weight: 600; + + &.internal-link { + text-decoration: none; + background-color: transparentize(#8f9fa9, 0.85); + padding: 0 0.1em; + margin: auto -0.1em; + border-radius: 3px; + + &.broken { + opacity: 0.5; + background-color: transparent; + } + } + } + + & p { + overflow-wrap: anywhere; + } +} + +.tags { + list-style: none; + padding-left: 0; + + & .meta { + margin: 1.5em 0; + & > h1 { + margin: 0; + } + & > p { + margin: 0; + } + } + + & > li { + display: inline-block; + margin: 0.4em 0.2em; + } + + & > li > a { + border-radius: 8px; + border: var(--outlinegray) 1px solid; + padding: 0.2em 0.5em; + &::before { + content: "#"; + margin-right: 0.3em; + color: var(--outlinegray); + } + } +} + +.backlinks a { + font-weight: 600; + font-size: 0.9rem; +} + +sup > a { + text-decoration: none; + padding: 0 0.1em 0 0.2em; +} + +#page-title { + margin: 0; + & > a { + font-family: var(--font-header); + } +} + +a { + font-size: 1em; + font-weight: 700; + text-decoration: none; + transition: all 0.2s ease; + color: var(--secondary); + &:hover { + color: var(--tertiary) !important; + } +} + +pre { + font-family: var(--font-mono); + padding: 0.75em; + border-radius: 3px; + overflow-x: scroll; +} + +code { + font-family: var(--font-mono); + font-size: 0.85em; + padding: 0.15em 0.3em; + border-radius: 5px; + background: var(--lightgray); +} + +@keyframes fadeIn { + 0% {opacity:0;} + 100% {opacity:1;} +} + +footer { + margin-top: 4em; + text-align: center; + & ul { + padding-left: 0; + } +} + +hr { + width: 100%; + margin: 2em auto; + height: 1px; + border: none; + background-color: var(--outlinegray); +} + +.page-end { + display: flex; + flex-direction: row; + gap: 2em; + + @media all and (max-width: 780px) { + flex-direction: column; + } + + & > * { + flex: 1 0 0; + } + + & > .backlinks-container { + & > ul { + list-style: none; + padding: 0; + margin: 0; + + & > li { + margin: 0.5em 0; + padding: 0.25em 1em; + border: var(--outlinegray) 1px solid; + border-radius: 5px + } + } + } + + & #graph-container { + border: var(--outlinegray) 1px solid; + border-radius: 5px; + box-sizing: border-box; + min-height: 250px; + margin: 0.5em 0; + + & > svg { + margin-bottom: -5px; + + } + } +} + +.centered { + margin-top: 30vh; +} + +.spacer { + flex: 1 1 auto; +} + +header { + display: flex; + flex-direction: row; + align-items: center; + margin: 1em 0 2em; + + & > h1 { + font-size: 2em; + } + + & > nav { + @media all and (max-width: 600px) { + display: none; + } + } + + #search-icon { + background-color: var(--lightgray); + border-radius: 4px; + height: 2em; + display: flex; + align-items: center; + cursor: pointer; + & > p { + display: inline; + padding: 0 1.5em 0 2em; + } + } + + & svg { + cursor: pointer; + width: 18px; + min-width: 18px; + margin: 0 0.5em; + + &:hover .search-path { + stroke: var(--tertiary); + } + + .search-path { + stroke: var(--gray); + stroke-width: 2px; + transition: stroke 0.5s ease; + } + } +} + +#search-container { + position: fixed; + z-index: 9999; + left: 0; + top: 0; + width: 100vw; + height: 100%; + overflow: scroll; + display: none; + backdrop-filter: blur(4px); + -webkit-backdrop-filter: blur(4px); + + & > div { + width: 50%; + margin-top: 15vh; + margin-left: auto; + margin-right: auto; + + @media all and (max-width: 1200px) { + width: 90%; + } + + & > * { + width: 100%; + border-radius: 4px; + background: var(--light); + box-shadow: 0 14px 50px rgba(27, 33, 48, 0.12), 0 10px 30px rgba(27, 33, 48, 0.16); + margin-bottom: 2em; + } + + & > input { + box-sizing: border-box; + padding: 0.5em 1em; + font-family: var(--font-body); + color: var(--dark); + font-size: 1.1em; + border: 1px solid var(--outlinegray); + + &:focus { + outline: none; + } + } + + & > #results-container { + & .result-card { + padding: 1em; + cursor: pointer; + transition: background 0.2s ease; + border: 1px solid var(--outlinegray); + border-bottom: none; + width: 100%; + + // normalize button props + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; + overflow: visible; + text-transform: none; + text-align: left; + background: var(--light); + outline: none; + + &:hover, &:focus { + background: rgba(180, 180, 180, 0.15); + } + + &:first-of-type { + border-top-left-radius: 5px; + border-top-right-radius: 5px; + } + + &:last-of-type { + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border-bottom: 1px solid var(--outlinegray); + } + + & > h3, & > p { + margin: 0; + } + } + } + } +} + +.search-highlight { + background-color: #afbfc966; + padding: 0.05em 0.2em; + border-radius: 3px; +} + +.section-ul { + list-style: none; + margin-top: 2em; + padding-left: 0; + +} + +.section-li { + margin-bottom: 1em; + + & > .section { + display: flex; + align-items: center; + + @media all and (max-width: 600px) { + & .tags { + display: none; + } + } + + & h3 > a { + font-weight: 700; + margin: 0; + } + + & p { + margin: 0; + padding-right: 1em; + flex-basis: 6em; + } + } + + & h3 { + opacity: 1; + font-weight: 700; + margin: 0; + } + + & .meta { + opacity: 0.6; + } +} + +@keyframes dropin { + 0% { + display: none; + opacity: 0; + visibility: hidden; + } + 1% { + display: inline-block; + opacity: 0; + } + 100% { + opacity: 1; + visibility: visible; + } +} + +.popover { + z-index: 999; + position: absolute; + width: 20rem; + display: none; + background-color: var(--light); + padding: 1rem; + margin: 1rem; + border: 1px solid var(--outlinegray); + border-radius: 5px; + pointer-events: none; + transition: opacity 0.2s ease, transform 0.2s ease; + user-select: none; + overflow-wrap: anywhere; + box-shadow: 6px 6px 36px 0 rgba(0,0,0,0.25); + + @media all and (max-width: 600px) { + display: none !important; + } + + &.visible { + opacity: 1; + visibility: visible; + display: inline-block; + animation: dropin 0.2s ease; + } + + & > h3 { + font-size: 1rem; + margin: 0.25rem 0; + } + + & .meta { + margin-top: 0.25rem; + opacity: 0.5; + font-family: var(--font-mono); + font-size: 0.8rem; + } + + & > p { + margin: 0; + padding: 0.5rem 0; + } + + & > p, & > a { + font-size: 1rem; + font-weight: 400; + user-select: none; + } +} + +#contact_buttons ul { + list-style-type: none; + + li { + display: inline-block; + } + + li a { + padding: 0 1em; + } +} + +mark { + background-color: var(--highlighted); + color: var(--gray); +} diff --git a/assets/styles/clipboard.scss b/assets/styles/clipboard.scss new file mode 100644 index 00000000..7989e248 --- /dev/null +++ b/assets/styles/clipboard.scss @@ -0,0 +1,47 @@ +.clipboard-button { + position: absolute; + display: flex; + float: right; + right: 0; + padding: 0.69em; + margin: 0.5em; + color: var(--outlinegray); + border-color: var(--dark); + background-color: var(--lightgray); + filter: contrast(1.1); + border: 2px solid; + border-radius: 6px; + font-size: 0.8em; + z-index: 1; + opacity: 0; + transition: 0.12s; + + & > svg { + fill: var(--light); + filter: contrast(0.3); + } + + &:hover { + cursor: pointer; + border-color: var(--primary); + + & > svg { + fill: var(--primary); + } + } + + &:focus { + outline: 0; + } +} + +.highlight { + position: relative; + + &:hover > .clipboard-button { + opacity: 1; + transition: 0.2s; + } +} + + diff --git a/assets/styles/code-title.scss b/assets/styles/code-title.scss new file mode 100644 index 00000000..b384743b --- /dev/null +++ b/assets/styles/code-title.scss @@ -0,0 +1,20 @@ +.code-title { + color: var(--primary) ; + font-family: var(--font-mono); + width: max-content; + overflow-x: auto; + display: inline-block; + vertical-align: middle; + font-weight: normal; + line-height: 1em; + position: relative; + padding: 0.5em 0.6em 0.6em; // + 1.2 em + max-width: calc(100% - 1.2em); // (-1.2 em) fits article width exactly + margin-bottom: -0.2em; + z-index: -1; + border-top-left-radius: 0.3em; + border-top-right-radius: 0.3em; + font-size: 0.9em; + background-color: var(--lightgray); + filter: hue-rotate(-30deg) contrast(1.0) opacity(0.8); +} \ No newline at end of file diff --git a/assets/styles/custom.scss b/assets/styles/custom.scss new file mode 100644 index 00000000..fc0108a5 --- /dev/null +++ b/assets/styles/custom.scss @@ -0,0 +1,31 @@ +// Add your own CSS here! + +:root { + --light: #faf8f8; + --dark: #141021; + --secondary: #284b63; + --tertiary: #84a59d; + --visited: #afbfc9; + --primary: #f28482; + --gray: #4e4e4e; + --lightgray: #f0f0f0; + --outlinegray: #dadada; + --million-progress-bar-color: var(--secondary); + --highlighted: #f5dfaf88; +} + +[saved-theme="dark"] { + --light: #1e1e21 !important; + --dark: #fbfffe !important; + --secondary: #6b879a !important; + --visited: #4a575e !important; + --tertiary: #84a59d !important; + --primary: #f58382 !important; + --gray: #d4d4d4 !important; + --lightgray: #292633 !important; + --outlinegray: #343434 !important; + --highlighted: #574010; +} + + + diff --git a/assets/styles/darkmode.scss b/assets/styles/darkmode.scss new file mode 100644 index 00000000..61967d79 --- /dev/null +++ b/assets/styles/darkmode.scss @@ -0,0 +1,44 @@ +.darkmode { + float: right; + padding: 1em; + min-width: 30px; + position: relative; + + @media all and (max-width: 450px) { + padding: 1em; + } + + & > .toggle { + display: none; + box-sizing: border-box; + } + + & svg { + opacity: 0; + position: absolute; + width: 20px; + height: 20px; + top: calc(50% - 10px); + margin: 0 7px; + fill: var(--gray); + transition: opacity 0.1s ease; + } +} + +.toggle:checked ~ label { + & > #dayIcon { + opacity: 0; + } + & > #nightIcon { + opacity: 1; + } +} + +.toggle:not(:checked) ~ label { + & > #dayIcon { + opacity: 1; + } + & > #nightIcon { + opacity: 0; + } +} \ No newline at end of file diff --git a/assets/styles/syntax.scss b/assets/styles/syntax.scss new file mode 100644 index 00000000..6267f5cf --- /dev/null +++ b/assets/styles/syntax.scss @@ -0,0 +1,66 @@ +// Overrides +/* Background */ +.chroma { + overflow: hidden !important; + background-color: var(--lightgray) !important; +} + +/* LineTable */ +.chroma .lntable { + width: auto !important; + overflow: auto !important; + display: block !important; +} + +/* LineHighlight */ +.chroma .hl { + display: block !important; + width: 100% !important; +} + +/* LineNumbersTable */ +.chroma .lnt { + margin-right: 0.0em !important; + padding: 0 0.0em 0 0.0em !important; +} + +/* LineNumbers */ +.chroma .ln { + margin-right: 0.0em !important; + padding: 0 0.0em 0 0.0em !important; +} + +/* GenericDeleted */ +.chroma .gd { + color: #8b080b !important; +} + +/* GenericInserted */ +.chroma .gi { + font-weight: bold !important; +} + +.lntd:first-of-type > .chroma { + padding-right: 0 !important; +} + +.chroma code { + font-family: var(--font-mono) !important; + font-size: 0.85em !important; + line-height: 2em !important; + background: none !important; + padding: 0 !important; +} + +.chroma { + border-radius: 3px !important; + margin: 0 !important; +} + +pre.chroma { + -moz-tab-size:4;-o-tab-size:4;tab-size:4; +} + +.katex { + font-size: 1.1em !important; +} diff --git a/config.toml b/config.toml new file mode 100644 index 00000000..6e69a03a --- /dev/null +++ b/config.toml @@ -0,0 +1,33 @@ +baseURL = "https://dwebyvr.org/" +languageCode = "en-us" +relativeURLs = false +disablePathToLower = true +ignoreFiles = [ + "/content/templates/*", + "/content/private/*", +] +summaryLength = 20 +paginate = 10 +enableGitInfo = true + +[markup] + [markup.tableOfContents] + endLevel = 3 + ordered = true + startLevel = 2 + [markup.highlight] + noClasses = false + anchorLineNos = false + codeFences = true + guessSyntax = true + hl_Lines = "" + lineAnchors = "" + lineNoStart = 1 + lineNos = true + lineNumbersInTable = true + style = "dracula" + [frontmatter] + lastmod = ["lastmod", ":git", "date", "publishDate"] + publishDate = ["publishDate", "date"] + [markup.goldmark.renderer] + unsafe = true diff --git a/_notes/about.md b/content/About.md similarity index 100% rename from _notes/about.md rename to content/About.md diff --git a/_notes/bmann.md b/content/Boris Mann.md similarity index 91% rename from _notes/bmann.md rename to content/Boris Mann.md index d44c92f8..84b17d78 100644 --- a/_notes/bmann.md +++ b/content/Boris Mann.md @@ -1,14 +1,14 @@ --- title: Boris Mann -type: person +tags: +- Convener --- Boris Mann is the founder of [Fission](https://fission.codes), building an edge computing stack that includes identity, data, and compute on top of [[IPFS]] and other DWeb technologies. You can try out the open source [Webnative SDK](https://webnative.dev) to easily build apps with passwordless logins, encrypted user data, and more. - Contact * Twitter [@bmann](https://twitter.com/bmann) * Mastodon [@bmann@social.coop](https://social.coop/@bmann) * Linkedin [@boris](https://linkedin.com/in/boris) * [Digital Garden Notes](https://bmannconsulting.com) * [Personal blog](https://blog.bmannconsulting.com) -* [Foodwiki](https://foodwiki.bmann.ca) \ No newline at end of file +* [Foodwiki](https://foodwiki.bmann.ca) diff --git a/_notes/calendar.md b/content/Calendar.md similarity index 98% rename from _notes/calendar.md rename to content/Calendar.md index 1b7faf51..622c32fb 100644 --- a/_notes/calendar.md +++ b/content/Calendar.md @@ -41,4 +41,4 @@ What types of events and topics are a fit for sharing with the DWebYVR community Current calendar admins: * [[Emily McGill]] -* [[Boris Mann]] \ No newline at end of file +* [[Boris Mann]] diff --git a/_notes/code-of-conduct.md b/content/Code of Conduct.md similarity index 100% rename from _notes/code-of-conduct.md rename to content/Code of Conduct.md diff --git a/content/Colophon.md b/content/Colophon.md new file mode 100644 index 00000000..ee0721cd --- /dev/null +++ b/content/Colophon.md @@ -0,0 +1,10 @@ +--- +title: Colophon +--- + +This is a [Hugo](https://gohugo.io/) powered website, built using the [[Quartz]]. From the features of that template, [[wikilinks]] -- double square brackets around words -- can be used to easily link between notes, and show which notes link to each other in the sidebar. + + +This site is built and hosted using [[Github]]. For every commit, a Github Action runs and builds a Jekyll site, and then publishes to Github Pages. The `dwebyvr.org` domain is hosted on [[Google Domains]]. + +Issues related to the website can be [submitted on GitHub](https://github.com/DWebYVR/notes/issues). diff --git a/_notes/contributing.md b/content/Contributing.md similarity index 100% rename from _notes/contributing.md rename to content/Contributing.md diff --git a/_notes/dweb-principles.md b/content/DWeb Principles.md similarity index 100% rename from _notes/dweb-principles.md rename to content/DWeb Principles.md diff --git a/_drafts/dweb.md b/content/Decentralized Web.md similarity index 100% rename from _drafts/dweb.md rename to content/Decentralized Web.md diff --git a/_notes/digital-garden.md b/content/Digital Garden.md similarity index 100% rename from _notes/digital-garden.md rename to content/Digital Garden.md diff --git a/_notes/emcgill.md b/content/Emily McGill.md similarity index 97% rename from _notes/emcgill.md rename to content/Emily McGill.md index 20ea8cae..09c5bc4f 100644 --- a/_notes/emcgill.md +++ b/content/Emily McGill.md @@ -1,6 +1,7 @@ --- title: Emily McGill -type: person +tags: +- Convener --- Emily McGill is a co-founder and Director at [Living Systems Network](https://livingsystemsnetwork.ca), fostering principles and practices for a more regenerative culture. A [[multipotentialite]], Emily brings her convening superpower to catalyze community collaboration in the distributed web space (with a strong affinity towards [Holochain](https://www.holochain.org/).) diff --git a/content/Explore.md b/content/Explore.md new file mode 100644 index 00000000..9657d82a --- /dev/null +++ b/content/Explore.md @@ -0,0 +1,6 @@ +--- +title: Explore Notes +--- + +This website is organized as a [[Digital Garden]] -- an organic collection of notes that link to each other. + diff --git a/_notes/feb15th-2023-flash-talks-tea.md b/content/Feb 2023 Flash Talks & Tea.md similarity index 99% rename from _notes/feb15th-2023-flash-talks-tea.md rename to content/Feb 2023 Flash Talks & Tea.md index 713d17b9..3066c3c6 100644 --- a/_notes/feb15th-2023-flash-talks-tea.md +++ b/content/Feb 2023 Flash Talks & Tea.md @@ -2,7 +2,8 @@ title: Feb 2023 Flash Talks & Tea event-date: 2023-02-15 event-link: https://lu.ma/89c4ce58 -type: event +tags: +- Event --- " $href}} + {{$link := printf "%s
%s" $src_link $iframe_link}} + {{$content = replace $content . $link}} + + {{else}} + {{$link := printf "%s" $href $href}} + {{$content = replace $content . $link}} + {{end}} + {{else}} + {{$link := printf "%s" $href $display}} + {{$content = replace $content . $link}} + {{end}} + + {{else}} + {{$link := printf "%s" $display}} + {{$content = replace $content . $link}} + {{end}} + + {{end}} +{{end}} + +{{/* Add jumpable anchors */}} +{{ $content = $content | replaceRE "()(.+)()" `${1}# ${3}${4}` }} + +{{/* Callouts */}} +{{if $.Site.Data.config.enableCallouts}} + {{ $content = $content | replaceRE "
" "
" }} + {{ $blockquoteclasses := findRE `\[!.+\]` $content }} + {{ $blockquoteclasses1 := findRE "(.|\n)*?
" $content }} + {{ $blockquotetags := findRE `blockquote class=callout` $content }} + {{ $counter := 0 }} + {{ $counter1 := 0 }} + {{ $finder := index $blockquoteclasses1 $counter }} + {{range $blockquotetags}} + {{ $finder = index $blockquoteclasses1 $counter }} + {{ if (in $finder "[!") }} + {{ $inner := index $blockquoteclasses $counter1 }} + {{ if (in $finder "]-") }} + {{ $inner = $inner | replaceRE `\[!([a-zA-Z]+)\]` `callout-collapsible callout-collapsed ${1}`}} + {{ else if (in $finder "]+") }} + {{ $inner = $inner | replaceRE `\[!([a-zA-Z]+)\]` `callout-collapsible ${1}`}} + {{ else}} + {{ $inner = $inner | replaceRE `\[!([a-zA-Z]+)\]` `${1}` }} + {{ end }} + {{ $inner = printf "blockquote class=\"%s-callout\"" $inner | lower}} + {{ $content = replace $content . $inner 1}} + {{ $counter1 = add $counter1 1 }} + {{ else }} + {{ $inner := print "blockquote" }} + {{ $content = replace $content . $inner 1}} + {{ end }} + {{ $counter = add $counter 1 }} + {{end}} + {{ $content = $content | replaceRE `\[![a-zA-Z]+\][-\+]?` "" }} + {{ $content = $content | replaceRE "blockquote class=callout" "blockquote" }} + {{ $content = $content | replaceRE `(?s)(
.*?)
(.*?<\/blockquote)` `${1}

${2}` }} +{{end}} + +{{/* Make ==text== into text */}} +{{$mark := findRE "==([^=\n]+)==" $content}} +{{range $mark}} + {{$fixed := printf "%s" (replace . "==" "")}} + {{$content = replace $content . $fixed}} +{{end}} + +{{ $content | safeHTML }} diff --git a/layouts/partials/toc.html b/layouts/partials/toc.html new file mode 100644 index 00000000..bd0cb541 --- /dev/null +++ b/layouts/partials/toc.html @@ -0,0 +1,9 @@ +{{ $hasHeaders := gt (len (findRE "(.|\n)*?" .Content)) 0 }} +{{ if (or (and (not $.Site.Data.config.enableToc) .Params.enableToc) (and $.Site.Data.config.enableToc (ne .Params.enableToc false) $hasHeaders)) }} +

+{{end}} diff --git a/static/icon.png b/static/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b6656a7a819cf41ba6502b9eddf4e580617bbaba GIT binary patch literal 17368 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 P00000NkvXXu0mjf;?EWX literal 0 HcmV?d00001 diff --git a/styles.scss b/styles.scss deleted file mode 100644 index 6a98ad09..00000000 --- a/styles.scss +++ /dev/null @@ -1,6 +0,0 @@ ---- ---- - -@import "../_sass/normalize"; -@import "../_sass/code"; -@import "../_sass/style";