diff --git a/content/posts/_index.md b/content/posts/_index.md new file mode 100644 index 0000000..895d95d --- /dev/null +++ b/content/posts/_index.md @@ -0,0 +1,7 @@ ++++ +paginate_by = 7 +title = "Posts" +sort_by = "date" + +insert_anchor_links = "heading" ++++ diff --git a/content/posts/configuration.md b/content/posts/configuration.md new file mode 100644 index 0000000..7e18fd0 --- /dev/null +++ b/content/posts/configuration.md @@ -0,0 +1,132 @@ ++++ +title = "Configuring Apollo" +date = "2024-07-09" + +[taxonomies] +tags=["documentation"] + +[extra] +repo_view = true ++++ + +## Theme Mode (`theme`) + +Sets the color theme for your blog. + +- Type: String +- Options: "light", "dark", "auto", "toggle" +- Default: "toggle" +- Usage: `theme = "toggle"` + +The "toggle" option allows users to switch between light and dark modes, while "auto" typically follows the user's system preferences. + +## Menu + +Defines the navigation menu items for your blog. + +- Type: Array of objects +- Default: [] +- Usage: + ```toml + menu = [ + { name = "/posts", url = "/posts", weight = 1 }, + { name = "/projects", url = "/projects", weight = 2 }, + { name = "/about", url = "/about", weight = 3 }, + { name = "/tags", url = "/tags", weight = 4 }, + ] + ``` + +## Socials + +Defines the social media links. + +- Type: Array of objects +- Default: [] +- Usage: + ```toml + socials = [ + { name = "twitter", url = "https://twitter.com/not_matthias", icon = "twitter" }, + { name = "github", url = "https://github.com/not-matthias/", icon = "github" }, + ] + ``` + +## Table of Contents (`toc`) + +Enables or disables the table of contents for posts. + +- Type: Boolean +- Default: true +- Usage: `toc = true` + +When enabled, a table of contents will be generated for posts, making it easier for readers to navigate through longer articles. + +## CDN Usage (`use_cdn`) + +Determines whether to use a Content Delivery Network (CDN) for assets. + +- Type: Boolean +- Default: false +- Usage: `use_cdn = false` + +When set to true, the theme will attempt to load assets from a CDN, which can improve loading times for visitors from different geographic locations. + +## Favicon (`favicon`) + +Specifies the path to the favicon image for your blog. + +- Type: String +- Default: "/icon/favicon.png" +- Usage: `favicon = "/icon/favicon.png"` + +This sets the small icon that appears in the browser tab for your website. + +## Comments (`comment`) + +Enables or disables the comment system for posts. + +- Type: Boolean +- Default: false +- Usage: `comment = false` + +After making `comment = true` save your script from [Giscus](https://giscus.app) to `templates/_giscus_script.html`. +When enabled, this allows readers to leave comments on your blog posts. + + +## Fancy Code Styling (`fancy_code`) + +Enables enhanced styling for code blocks. + +- Type: Boolean +- Default: true +- Usage: `fancy_code = true` + +This option adds the language label and a copy button. + +## Dynamic Notes (`dynamic_note`) + +Allows for the creation of togglable note sections in your content. + +- Type: Boolean +- Default: true +- Usage: `dynamic_note = true` + +When enabled, you can create expandable/collapsible note sections in your blog posts. + +## Source code (`repo_view`) + +Do you want to link to the source code of your blog post? You can turn on the `repo_view` inside the `[extra]` section of your blog post. + +```toml +[extra] +repo_view = true +repo_url = "https://github.com/not-matthias/apollo/tree/main/content" # Alternatively add the repo here +``` + +The `repo_url` can be set in the `[extra]` section or in your `config.toml`. + +## Anchor Links + +You can add anchor links by adding the following to your `_index.md`: +```toml +insert_anchor_links = "heading" +``` diff --git a/content/posts/markdown.md b/content/posts/markdown.md new file mode 100644 index 0000000..829d704 --- /dev/null +++ b/content/posts/markdown.md @@ -0,0 +1,84 @@ ++++ +title = "Markdown Test" +date = "2022-01-01" +updated = "2022-05-01" + +[taxonomies] +tags=["example"] ++++ + +# H1 +## H2 +### H3 + + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet sagittis id consectetur purus ut. In pellentesque massa placerat duis ultricies. Neque laoreet suspendisse interdum consectetur libero id. Justo nec ultrices dui sapien eget mi proin. Nunc consequat interdum varius sit amet mattis vulputate. Sollicitudin tempor id eu nisl nunc mi ipsum. Non odio euismod lacinia at quis. Sit amet nisl suscipit adipiscing. Amet mattis vulputate enim nulla aliquet porttitor lacus luctus accumsan. Sit amet consectetur adipiscing elit pellentesque habitant. Ac placerat vestibulum lectus mauris. Molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. [Google](https://www.google.com) + +![Markdown Logo](https://markdown-here.com/img/icon256.png) + +## Code Block + +```rust +fn main() { + println!("Hello World"); +} +``` + + +```rust,hl_lines=2,linenos +fn main() { + println!("Hello World"); +} +``` + +## Ordered List + +1. First item +2. Second item +3. Third item + +## Unordered List + +- List item +- Another item +- And another item + +## Nested list + +- Fruit + - Apple + - Orange + - Banana +- Dairy + - Milk + - Cheese + +## Quote + +> Two things are infinite: the universe and human stupidity; and I'm not sure about the +> universe.
+> — Albert Einstein + + +## Table Inline Markdown + +| Italics | Bold | Code | StrikeThrough | +| --------- | -------- | ------ | ----------------- | +| *italics* | **bold** | `code` | ~~strikethrough~~ | + +## Foldable Text + +
+ Title 1 +

IT'S A SECRET TO EVERYBODY.

+
+ +
+ Title 2 +

Stay awhile, and listen!

+
+ +## Code tags + +Lorem ipsum `dolor` sit amet, `consectetur adipiscing` elit. +`Lorem ipsum dolor sit amet, consectetur adipiscing elit.` diff --git a/content/posts/math-symbol.md b/content/posts/math-symbol.md new file mode 100644 index 0000000..adf1e08 --- /dev/null +++ b/content/posts/math-symbol.md @@ -0,0 +1,22 @@ ++++ +title = "Math Symbol Example" +date = "2023-01-06" + +[taxonomies] +tags=["example"] ++++ + +Note: This requires the `mathjax` and `mathjax_dollar_inline_enable` option set to `true`. + +# Inline Math + +- $(a+b)^2$ = $a^2 + 2ab + b^2$ +- A polynomial P of degree d over $\mathbb{F}_p$ is an expression of the form + $P(s) = a_0 + a_1 . s + a_2 . s^2 + ... + a_d . s^d$ for some + $a_0,..,a_d \in \mathbb{F}_p$ + +# Displayed Math + +$$ +p := (\sum_{k∈I}{c_k.v_k} + \delta_v.t(x))·(\sum_{k∈I}{c_k.w_k} + \delta_w.t(x)) − (\sum_{k∈I}{c_k.y_k} + \delta_y.t(x)) +$$ diff --git a/content/posts/shortcode.md b/content/posts/shortcode.md new file mode 100644 index 0000000..38c731b --- /dev/null +++ b/content/posts/shortcode.md @@ -0,0 +1,78 @@ ++++ +title = "Shortcode Example" +date = "2024-06-14" + +[taxonomies] +tags=["example"] ++++ + + +## Note + +Here is an example of the `note` shortcode: + +This one is static! +{{ note(header="Note!", body="This blog assumes basic terminal maturity") }} + +This one is clickable! +{{ note(clickable=true, hidden = true, header="Quiz!", body="The answer to the quiz!") }} + + +Syntax: +``` +{{/* note(header="Note!", body="This blog assumes basic terminal maturity") */}} +{{/* note(clickable=true, hidden = true, header="Quiz!", body="The answer to the quiz!") */}} +``` + +You can also use some HTML in the text: +{{ note(header="Note!", body="

This blog assumes basic terminal maturity

") }} + + +Literal shortcode: +``` +{{/* note(header="Note!", body="

This blog assumes basic terminal maturity

") */}} +``` + +Pretty cool, right? + +Finally, you can do something like this (hopefully): + +{% note(clickable=true, header="Quiz!") %} + +# Hello this is markdown inside a note shortcode + +```rust +fn main() { + println!("Hello World"); +} +``` + +We can't call another shortcode inside a shortcode, but this is good enough. + +{% end %} + +Here is the raw markdown: + +```markdown +{{/* note(clickable=true, header="Quiz!") */}} + +# Hello this is markdown inside a note shortcode + +\`\`\`rust +fn main() { + println!("Hello World"); +} +\`\`\` + +We can't call another shortcode inside a shortcode, but this is good enough. + +{{/* end */}} +``` + +Finally, we have center +{{ note(center=true, header="Centered Text", body="This is centered text") }} + +```markdown +{{/* note(center=true, header="Centered Text", body="This is centered text") */}} +``` +It works good enough for me! diff --git a/content/posts/snippet-test.md b/content/posts/snippet-test.md new file mode 100644 index 0000000..f4c7c8f --- /dev/null +++ b/content/posts/snippet-test.md @@ -0,0 +1,19 @@ ++++ +title = 'testing snippets' +author = 'Joost Agterhoek' +date = 2024-09-11 +updated = 2024-09-11 +[taxonomies] +tags = ['Neovim', 'LuaSnip', 'blogging'] ++++ + +This is my first test blog post (local only) where I setup the TOML front matter with a self-made LuaSnip snippet! 🤩 Of course the snippet was filled with errors, *but*, it did work! 🛠️ + +All in all, I am really getting into the flow of my current setup for note taking and blogging. I would like to further integrate this site, which should soon be my [note taking test site](https://notes.joostagterhoek.nl)'s theme, into Obsidian. + +So far, `zola` has had no problem updating the locally served site when I edit a blog post like this, so it would be great for testing. I would like a keymap for emojis though, I should remember to set that up. Which is exactly what I do in my personal Obsidian vault (see the connection here? 🔗). + + + + + diff --git a/content/posts/test.md b/content/posts/test.md new file mode 100644 index 0000000..008dae0 --- /dev/null +++ b/content/posts/test.md @@ -0,0 +1,11 @@ ++++ +title = "testing" +date = 2024-09-09 ++++ + +testing. + +![testing](/projects/project-1.jpg) + +[![testing remote image](https://images.pexels.com/photos/27774130/pexels-photo-27774130/free-photo-of-float.jpeg)](https://notes.joostagterhoek.nl) +_[Photo by Mateo Servia from Pexels](https://www.pexels.com/photo/float-27774130/)_ diff --git a/content/projects/project-1.jpg b/content/projects/project-1.jpg new file mode 100644 index 0000000..db5232e Binary files /dev/null and b/content/projects/project-1.jpg differ diff --git a/content/projects/project_1.md b/content/projects/project_1.md new file mode 100644 index 0000000..8c7582c --- /dev/null +++ b/content/projects/project_1.md @@ -0,0 +1,11 @@ ++++ +title = "Apollo" +description = "Modern and minimalistic blog theme." +weight = 1 + +[extra] +local_image = "/projects/project-1.jpg" +link_to = "https://github.com/not-matthias/apollo" ++++ + +Example project page \ No newline at end of file diff --git a/content/projects/project_2.md b/content/projects/project_2.md new file mode 100644 index 0000000..43704c7 --- /dev/null +++ b/content/projects/project_2.md @@ -0,0 +1,11 @@ ++++ +title = "Project 2" +description = "Example description" +weight = 1 + +[extra] +# You can also crop the image in the url by adjusting w=/h= +remote_image = "https://images.unsplash.com/photo-1523821741446-edb2b68bb7a0?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80" ++++ + +Example project page diff --git a/content/projects/project_3.md b/content/projects/project_3.md new file mode 100644 index 0000000..b19c2a1 --- /dev/null +++ b/content/projects/project_3.md @@ -0,0 +1,10 @@ ++++ +title = "Project 3" +description = "Example description" +weight = 1 + +[extra] +remote_image = "https://images.unsplash.com/photo-1462556791646-c201b8241a94?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1465&q=80" ++++ + +Example project page \ No newline at end of file diff --git a/content/projects/project_4.md b/content/projects/project_4.md new file mode 100644 index 0000000..e2f218d --- /dev/null +++ b/content/projects/project_4.md @@ -0,0 +1,10 @@ ++++ +title = "Project 4" +description = "Example description with a lot of words but without any meaning. Why use lorem ipsum when you can just write a lot of text that has no underlying meaning?" +weight = 1 + +[extra] +remote_image = "https://images.unsplash.com/photo-1620121692029-d088224ddc74?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1632&q=80" ++++ + +Example project page \ No newline at end of file diff --git a/content/projects/project_5.md b/content/projects/project_5.md new file mode 100644 index 0000000..6f01dd1 --- /dev/null +++ b/content/projects/project_5.md @@ -0,0 +1,7 @@ ++++ +title = "Project 4" +description = "Example description" +weight = 1 ++++ + +Example project page \ No newline at end of file diff --git a/sass/fonts.scss b/sass/fonts.scss new file mode 100644 index 0000000..06bacd2 --- /dev/null +++ b/sass/fonts.scss @@ -0,0 +1,31 @@ +@font-face { + font-family: 'Jetbrains Mono'; + font-style: normal; + font-weight: 400; + src: url('fonts/JetbrainsMono/JetBrainsMono-Regular.ttf'), local('ttf'); + font-display: swap; +} + +@font-face { + font-family: 'Jetbrains Mono'; + font-style: normal; + font-weight: 700; + src: url('fonts/JetbrainsMono/JetBrainsMono-Bold.ttf'), local('ttf'); + font-display: swap +} + +@font-face { + font-family: 'Space Grotesk'; + font-style: normal; + font-weight: 400; + src: url('fonts/SpaceGrotesk/SpaceGrotesk-Regular.ttf'), local('ttf'); + font-display: swap; +} + +@font-face { + font-family: 'Space Grotesk'; + font-style: normal; + font-weight: 700; + src: url('fonts/SpaceGrotesk/SpaceGrotesk-Bold.ttf'), local('ttf'); + font-display: swap; +} \ No newline at end of file diff --git a/sass/main.scss b/sass/main.scss new file mode 100644 index 0000000..2c18ba1 --- /dev/null +++ b/sass/main.scss @@ -0,0 +1,51 @@ +@import "parts/_cards.scss"; +@import "parts/_code.scss"; +@import "parts/_header.scss"; +@import "parts/_image.scss"; +@import "parts/_toc.scss"; +@import "parts/_note.scss"; +@import "parts/misc.scss"; +@import "parts/table.scss"; +@import "parts/tags.scss"; + +:root { + /* Used for: block comment, hr, ... */ + --border-color: var(--border-color); + + /* Fonts */ + --text-font: 'Jetbrains Mono'; + --header-font: 'Space Grotesk', 'Helvetica', sans-serif; + --code-font: 'Jetbrains Mono'; +} + +html { + background-color: var(--bg-0); + color: var(--text-0); + font-family: var(--text-font); + line-height: 1.6em; +} + +.content { + max-width: 1000px; + margin: 0 auto; + padding: 0 24px; + word-wrap: break-word; +} + +@media all and (min-width:640px) { + html { + font-size: 16.5px; + } +} + +@media all and (min-width:720px) { + html { + font-size: 17px; + } +} + +@media all and (min-width:960px) { + html { + font-size: 18px; + } +} \ No newline at end of file diff --git a/sass/parts/_cards.scss b/sass/parts/_cards.scss new file mode 100644 index 0000000..429f0a1 --- /dev/null +++ b/sass/parts/_cards.scss @@ -0,0 +1,55 @@ +.cards { + display: grid; + grid-template-rows: auto; + gap: 24px; + padding: 12px 0; +} + +@media all and (min-width: 640px) { + .cards { + grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); + } +} + +@media all and (max-width: 640px) { + .cards { + grid-template-columns: repeat(auto-fill, 1fr); + } +} + +.card { + min-height: 100px; + background: var(--bg-1); + border: 2px solid var(--border-color); + border-radius: 10px; + overflow: hidden; +} + +.card-info { + padding: 0 24px 24px 24px; +} + +.card-title { + margin-top: 0.7em; +} + +.card-image { + border: unset; + width: 100%; +} + +.card-image-placeholder { + height: 12px; + width: 100%; +} + +.card-description { + margin-top: 0.5em; + overflow: hidden; +} + +@media all and (max-width:720px) { + .cards { + gap: 18px; + } +} \ No newline at end of file diff --git a/sass/parts/_code.scss b/sass/parts/_code.scss new file mode 100644 index 0000000..889e864 --- /dev/null +++ b/sass/parts/_code.scss @@ -0,0 +1,159 @@ +// Define base colors and fonts for light and dark themes +:root { + --code-font: 'Courier New', monospace; + --bg-primary: var(--bg-1); + --text-color: var(--text-0); // Color of the code text + --label-color: #f0f0f0; // Text color of the label + + --hightlight-color: #f0f0f0; +} + +:root.dark { + --hightlight-color: #204e8a; +} + + +// Define language colors map +$language-colors: ( + "js": (#f7df1e, "JavaScript"), + "yaml": (#f71e6a, "YAML"), + "shell": (#4eaa25, "Shell"), + // Updated to a more specific green shade + "json": (dodgerblue, "JSON"), + "python": (#3572A5, "Python"), + // Using the specific Python blue + "css": (#264de4, "CSS"), + "go": (#00ADD8, "Go"), + // Official Go color + "markdown": (#0000ff, "Markdown"), + "rust": (#ff4647, "Rust"), + // Adjusted to match Rust's branding + "java": (#f89820, "Java"), + // Oracle Java color + "csharp": (#178600, "C#"), + "ruby": (#701516, "Ruby"), + "swift": (#f05138, "Swift"), + "php": (#777bb4, "PHP"), + "typescript": (#3178c6, "TypeScript"), + "scala": (#c22d40, "Scala"), + "kotlin": (#F18E33, "Kotlin"), + "lua": (#000080, "Lua"), + "perl": (#0298c3, "Perl"), + "haskell": (#5e5086, "Haskell"), + "r": (#198ce7, "R"), + "dart": (#00d2b8, "Dart"), + "elixir": (#6e4a7e, "Elixir"), + "clojure": (#5881d8, "Clojure"), + "bash": (#4eaa25, "Bash"), + "default": (#333, "Code"), +); + +@mixin base-label-style($bg-color, $text-color: var(--label-color)) { + background: $bg-color; + color: $text-color; + border-radius: 0 0 0.25rem 0.25rem; + font-size: 12px; + letter-spacing: 0.025rem; + padding: 0.1rem 0.5rem; + text-align: right; + text-transform: uppercase; + position: absolute; + right: 0; + top: 0; + margin-top: 0.1rem; +} + +// Example usage within a specific class for clarity +.code-label { + @include base-label-style(#333); // Default background color +} + +@each $lang, $color-info in $language-colors { + .label-#{$lang} { + @include base-label-style(nth($color-info, 1)); + } +} + +code { + background-color: var(--bg-primary); + padding: 0.1em 0.2em; + border-radius: 5px; + border: 1px solid var(--border-color); + font-family: var(--code-font); +} + +pre { + background-color: var(--bg-primary) !important; + border-radius: 5px; + border: 1px solid var(--border-color); + line-height: 1.4; + overflow-x: auto; + padding: 1em; + position: relative; + + mark { + background-color: var(--hightlight-color) !important; // Ensure mark uses the theme background + padding: 0; + border-radius: 0px; + } + + code { + background-color: transparent !important; + color: var(--text-color); + font-size: 100%; + padding: 0; + border: none; + font-family: var(--code-font); + + table { + margin: 0; + border-collapse: collapse; + font-family: var(--code-font); + + mark { + display: block; + color: unset; + padding: 0; + background-color: var(--hightlight-color) !important; + filter: brightness(1.2); // Example to slightly increase brightness + } + + } + + td, + th, + tr { + padding: 0; + border-bottom: none; + border: none; // Ensure no borders around rows + } + + tbody td:first-child { + text-align: center; + user-select: none; + min-width: 60px; + border-right: none, + } + + tbody tr:nth-child(even), + thead tr { + background-color: unset; + } + } +} + +.clipboard-button, +.clipboard-button svg { + all: unset; + cursor: pointer; + position: absolute; + bottom: 5px; + /* 5px from the bottom */ + right: 5px; + /* 5px from the right */ + z-index: 10; + background-color: transparent; + border: none; + fill: #ef5350; + /* Sets the color of the SVG, assuming it's an SVG icon */ +} \ No newline at end of file diff --git a/sass/parts/_header.scss b/sass/parts/_header.scss new file mode 100644 index 0000000..3e01c82 --- /dev/null +++ b/sass/parts/_header.scss @@ -0,0 +1,146 @@ +.page-header { + font-size: 2.5em; + line-height: 100%; + font-family: var(--header-font); + margin: 4rem 0px 1rem 0px; +} + +.centered-header { + font-family: var(--header-font); + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + font-size: 4em; +} + +header { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + padding: 1em 0; +} + +header .main { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-start; + gap: 12px; + font-size: 1.5rem; + + /* Otherwise header and menu is too close on small screens*/ + margin-bottom: 5px; +} + +header .social img, +header #dark-mode-toggle img { + width: 16px; + height: 16px; +} + +header .socials { + margin-bottom: 10px; + /* Space between social icons and menu items */ +} + +#dark-mode-toggle { + justify-content: center; +} + +.socials { + /* flex-child */ + flex-grow: 0; + /* flex-container */ + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-items: flex-end; + gap: 6px; +} + +.social { + border-bottom: unset; + background-image: unset; + padding: 2px; +} + +.social>img { + border: unset; + width: 24px; + height: 24px; +} + +/* Mobile-specific adjustments */ +@media (max-width: 600px) { + header { + flex-direction: column; + align-items: center; + padding: 1em 0; + } + + header .main a { + font-size: 20px; + } +} + +.meta { + color: #999; + display: flexbox; + /* This changes the meta class to use flexbox, which ensures inline display */ + align-items: center; + /* Aligns items vertically in the middle */ + flex-wrap: wrap; + /* Allows items to wrap as needed */ +} + +#dark-mode-toggle>img { + display: none; + width: 15px; + height: 15px; + border: unset; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 1.2rem; + margin-top: 2em; +} + +h1::before { + color: var(--primary-color); + content: "# "; +} + +h2::before { + color: var(--primary-color); + content: "## "; +} + +h3::before { + color: var(--primary-color); + content: "### "; +} + +h4::before { + color: var(--primary-color); + content: "#### "; +} + +h5::before { + color: var(--primary-color); + content: "##### "; +} + +h6::before { + color: var(--primary-color); + content: "###### "; +} diff --git a/sass/parts/_image.scss b/sass/parts/_image.scss new file mode 100644 index 0000000..447f930 --- /dev/null +++ b/sass/parts/_image.scss @@ -0,0 +1,35 @@ +img { + border: 3px solid #ececec; + max-width: 100%; +} + +figure { + box-sizing: border-box; + display: inline-block; + margin: 0; + max-width: 100%; +} + +figure img { + max-height: 500px; +} + +@media screen and (min-width: 600px) { + figure { + padding: 0 40px; + } +} + +figure h4 { + font-size: 1rem; + margin: 0; + margin-bottom: 1em; +} + +figure h4::before { + content: "↳ "; +} + +svg { + max-height: 15px; +} \ No newline at end of file diff --git a/sass/parts/_misc.scss b/sass/parts/_misc.scss new file mode 100644 index 0000000..c7739ab --- /dev/null +++ b/sass/parts/_misc.scss @@ -0,0 +1,132 @@ +.primary-color { + color: var(--primary-color); +} + +.draft-label { + color: var(--hover-color); + text-decoration: none; + padding: 2px 4px; + border-radius: 4px; + margin-left: 6px; + background-color: var(--primary-color); +} + +::-moz-selection { + background: var(--primary-color); + color: var(--hover-color); + text-shadow: none; +} + +::selection { + background: var(--primary-color); + color: var(--hover-color); +} + +p { + line-height: 1.5; +} + +hr { + border: 0; + border-top: 3px solid var(--border-color); + margin: 1em 0; +} + +blockquote { + border-left: 3px solid var(--primary-color); + color: #737373; + margin: 0; + padding-left: 1em; +} + +a { + border-bottom: 3px solid var(--primary-color); + color: inherit; + text-decoration: none; + + // Make sure the underline is at the top + position: relative; // needed for z-index + z-index: 1; +} + +a.zola-anchor { + border-bottom: none; +} + +a:hover { + background-color: var(--primary-color); + color: var(--hover-color); +} + +time { + color: grey; +} + +/* Remove post list padding */ +.list>ul { + margin: 0; + padding: 1rem 0 0 0; +} + +/* Post list */ +.list-item { + margin-bottom: 30px; + list-style-type: none; +} + +// change the line-through color +del { + text-decoration-color: var(--primary-color); + text-decoration-thickness: 3px; +} + +@media all and (max-width: 640px) { + .post-header { + display: grid; + grid-template-rows: auto 1fr; + + h1 { + margin-top: 0; + // font-size: 130%; + + a { + border-bottom: none; + } + } + } +} + +/* Post list */ +@media all and (min-width: 640px) { + .post-header { + display: grid; + gap: 1rem; + grid-row-gap: 1.5rem; + grid-template-columns: auto 1fr; + + h1 { + margin: 0; + font-size: 130%; + + a { + border-bottom: none; + } + } + } +} + +/* Remove styling from theme toggle button */ +#dark-mode-toggle { + border-bottom: none; + + &:hover { + background-color: transparent; + } +} + +.MathJax_Display, +.MJXc-display, +.MathJax_SVG_Display { + overflow-x: auto; + overflow-y: hidden; +} \ No newline at end of file diff --git a/sass/parts/_note.scss b/sass/parts/_note.scss new file mode 100644 index 0000000..8071ef2 --- /dev/null +++ b/sass/parts/_note.scss @@ -0,0 +1,88 @@ +:root { + --note-header-bg: var(--bg-2); + --note-header-color: var(--text-0); + --note-content-bg: var(--bg-1); +} + + +.note-container { + border-radius: 4px; + overflow: hidden; + margin: 1em 0; + position: relative; + border-left: 3px solid var(--primary-color); + font-family: var(--paragraph-font); +} + +.note-toggle, +.note-header { + color: var(--note-header-color); + background-color: var(--note-header-bg); + padding: 10px 25px; + text-align: left; + border: none; + width: 100%; + position: relative; + outline: none; + font-size: 1.2em; + transition: background-color 0.3s ease; + + p { + margin: 0; + } + + .note-center { + text-align: center; + padding-right: 50px; + } + + .note-icon, + .note-icon { + padding-left: 25px; + } +} + +.note-toggle { + cursor: pointer; + position: relative; +} + +.note-toggle::before { + content: '▼'; + position: absolute; + right: 20px; + /* Position the arrow to the right */ + top: 50%; + /* Center vertically */ + transform: translateY(-50%); + /* Center vertically */ +} + +.note-toggle:hover, +.note-toggle:focus { + color: var(--note-header-color); + background-color: var(--note-header-bg); + outline: none; +} + +.note-content { + padding: 10px 20px; + background-color: var(--note-content-bg); +} + +.note-icon::before { + content: '✎'; + color: var(--primary-color); + position: absolute; + left: 20px; + top: 50%; + transform: translateY(-50%); +} + +summary:hover, +summary:focus { + color: var(--primary-color); + background-color: var(--note-header-bg); + outline: none; + padding: 10px; +} \ No newline at end of file diff --git a/sass/parts/_table.scss b/sass/parts/_table.scss new file mode 100644 index 0000000..247db0f --- /dev/null +++ b/sass/parts/_table.scss @@ -0,0 +1,15 @@ +table { + border-spacing: 0; + border-collapse: collapse; +} + +table th { + padding: 6px 13px; + border: 1px solid #dfe2e5; + font-size: large; +} + +table td { + padding: 6px 13px; + border: 1px solid #dfe2e5; +} \ No newline at end of file diff --git a/sass/parts/_tags.scss b/sass/parts/_tags.scss new file mode 100644 index 0000000..c2c262c --- /dev/null +++ b/sass/parts/_tags.scss @@ -0,0 +1,26 @@ +.tags { + ul { + margin-left: 0; + padding-left: 0; + } + + li { + list-style-type: none; + } + + a { + border-bottom: 3px solid var(--primary-color); + font-family: var(--text-font); + } + + a:hover { + color: var(--hover_color); + background-color: var(--primary-color); + } + + a::before { + content: "🏷 "; /* Ensure there's a space after the emoji for spacing */ + display: inline; + white-space: nowrap !important; + } +} diff --git a/sass/parts/_toc.scss b/sass/parts/_toc.scss new file mode 100644 index 0000000..80442a3 --- /dev/null +++ b/sass/parts/_toc.scss @@ -0,0 +1,24 @@ +.toc-container { + .toc-title { + cursor: pointer; + position: relative; + padding-left: 20px; // Space for the arrow + + &:before { + content: '▼'; // Down arrow + position: absolute; + left: 0; + transition: transform 0.3s ease; // Smooth transformation + } + + &:hover:before, + &.expanded:before { + transform: rotate(180deg); // Arrow points up when expanded or on hover + } + } + + .toc-list { + display: none; // ToC is hidden by default + // Removed transition on display, not effective + } +} diff --git a/sass/theme/dark.scss b/sass/theme/dark.scss new file mode 100644 index 0000000..4b78793 --- /dev/null +++ b/sass/theme/dark.scss @@ -0,0 +1,26 @@ +$bg-0: #121212; + +// Dark theme needs a bigger contrast compared to the white theme. +$bg-1: lighten($bg-0, 5%); +$bg-2: lighten($bg-1, 10%); + +$text-0: lighten($bg-0, 87%); +$text-1: lighten($bg-0, 60%); + +:root.dark { + --text-0: #{$text-0}; + --text-1: #{$text-1}; + + --bg-0: #{$bg-0}; + --bg-1: #{$bg-1}; + --bg-2: #{$bg-2}; + + --border-color: var(--bg-2); + + --primary-color: #ef5350; + --hover-color: white; + + .social>img { + filter: invert(1); + } +} \ No newline at end of file diff --git a/sass/theme/light.scss b/sass/theme/light.scss new file mode 100644 index 0000000..eb6872a --- /dev/null +++ b/sass/theme/light.scss @@ -0,0 +1,25 @@ +$bg-0: #fff; +$bg-1: darken($bg-0, 2%); +$bg-2: darken($bg-1, 8%); + +$text-0: darken($bg-0, 87%); +$text-1: darken($bg-0, 60%); + +:root.light { + --text-0: #{$text-0}; + --text-1: #{$text-1}; + + --bg-0: #{$bg-0}; + --bg-1: #{$bg-1}; + --bg-2: #{$bg-2}; + + --border-color: var(--bg-2); + + --primary-color: #ef5350; + --hover-color: white; + + // invert colour on hover for consistency + .social :hover { + filter: invert(1) + } +} \ No newline at end of file diff --git a/static/feather/moon.svg b/static/feather/moon.svg new file mode 100644 index 0000000..dbf7c6c --- /dev/null +++ b/static/feather/moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/feather/sun.svg b/static/feather/sun.svg new file mode 100644 index 0000000..7f51b94 --- /dev/null +++ b/static/feather/sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/fonts/.gitkeep b/static/fonts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Bold.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Bold.ttf new file mode 100644 index 0000000..710c34b Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Bold.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-BoldItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-BoldItalic.ttf new file mode 100644 index 0000000..fdff00f Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-BoldItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBold.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBold.ttf new file mode 100644 index 0000000..eb94300 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBold.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBoldItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBoldItalic.ttf new file mode 100644 index 0000000..b70b4e7 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraBoldItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLight.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLight.ttf new file mode 100644 index 0000000..74efced Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLight.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLightItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLightItalic.ttf new file mode 100644 index 0000000..1a9d2d3 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-ExtraLightItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Italic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Italic.ttf new file mode 100644 index 0000000..ffd5d77 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Italic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Light.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Light.ttf new file mode 100644 index 0000000..c0682f9 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Light.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-LightItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-LightItalic.ttf new file mode 100644 index 0000000..f20bac9 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-LightItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Medium.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Medium.ttf new file mode 100644 index 0000000..17ff945 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Medium.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-MediumItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-MediumItalic.ttf new file mode 100644 index 0000000..9b699bb Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-MediumItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Regular.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Regular.ttf new file mode 100644 index 0000000..9a5202e Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Regular.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-SemiBold.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-SemiBold.ttf new file mode 100644 index 0000000..84b7795 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-SemiBold.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-SemiBoldItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-SemiBoldItalic.ttf new file mode 100644 index 0000000..ffa1f39 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-SemiBoldItalic.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-Thin.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-Thin.ttf new file mode 100644 index 0000000..1317bfe Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-Thin.ttf differ diff --git a/static/fonts/JetbrainsMono/JetBrainsMono-ThinItalic.ttf b/static/fonts/JetbrainsMono/JetBrainsMono-ThinItalic.ttf new file mode 100644 index 0000000..bc72439 Binary files /dev/null and b/static/fonts/JetbrainsMono/JetBrainsMono-ThinItalic.ttf differ diff --git a/static/fonts/SpaceGrotesk/SpaceGrotesk-Bold.ttf b/static/fonts/SpaceGrotesk/SpaceGrotesk-Bold.ttf new file mode 100644 index 0000000..869a60f Binary files /dev/null and b/static/fonts/SpaceGrotesk/SpaceGrotesk-Bold.ttf differ diff --git a/static/fonts/SpaceGrotesk/SpaceGrotesk-Light.ttf b/static/fonts/SpaceGrotesk/SpaceGrotesk-Light.ttf new file mode 100644 index 0000000..76a195f Binary files /dev/null and b/static/fonts/SpaceGrotesk/SpaceGrotesk-Light.ttf differ diff --git a/static/fonts/SpaceGrotesk/SpaceGrotesk-Medium.ttf b/static/fonts/SpaceGrotesk/SpaceGrotesk-Medium.ttf new file mode 100644 index 0000000..667905f Binary files /dev/null and b/static/fonts/SpaceGrotesk/SpaceGrotesk-Medium.ttf differ diff --git a/static/fonts/SpaceGrotesk/SpaceGrotesk-Regular.ttf b/static/fonts/SpaceGrotesk/SpaceGrotesk-Regular.ttf new file mode 100644 index 0000000..792fe1b Binary files /dev/null and b/static/fonts/SpaceGrotesk/SpaceGrotesk-Regular.ttf differ diff --git a/static/fonts/SpaceGrotesk/SpaceGrotesk-SemiBold.ttf b/static/fonts/SpaceGrotesk/SpaceGrotesk-SemiBold.ttf new file mode 100644 index 0000000..0219302 Binary files /dev/null and b/static/fonts/SpaceGrotesk/SpaceGrotesk-SemiBold.ttf differ diff --git a/static/js/codeblock.js b/static/js/codeblock.js new file mode 100644 index 0000000..def68bc --- /dev/null +++ b/static/js/codeblock.js @@ -0,0 +1,103 @@ +const successIcon = ` + + `; +const errorIcon = ` + + `; +const copyIcon = ` + + `; + +// Function to change icons after copying +const changeIcon = (button, isSuccess) => { + button.innerHTML = isSuccess ? successIcon : errorIcon; + setTimeout(() => { + button.innerHTML = copyIcon; // Reset to copy icon + }, 2000); +}; + +// Function to get code text from tables, skipping line numbers +const getCodeFromTable = (codeBlock) => { + return [...codeBlock.querySelectorAll('tr')] + .map(row => row.querySelector('td:last-child')?.innerText ?? '') + .join(''); +}; + +// Function to get code text from non-table blocks +const getNonTableCode = (codeBlock) => { + return codeBlock.textContent.trim(); +}; + +document.addEventListener('DOMContentLoaded', function () { + // Select all `pre` elements containing `code` + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + const pre = entry.target.parentNode; + const clipboardBtn = pre.querySelector('.clipboard-button'); + const label = pre.querySelector('.code-label'); + + if (clipboardBtn) { + // Adjust the position of the clipboard button when the `code` is not fully visible + clipboardBtn.style.right = entry.isIntersecting ? '5px' : `-${entry.boundingClientRect.right - pre.clientWidth + 5}px`; + } + + if (label) { + // Adjust the position of the label similarly + label.style.right = entry.isIntersecting ? '0px' : `-${entry.boundingClientRect.right - pre.clientWidth}px`; + } + }); + }, { + root: null, // observing relative to viewport + rootMargin: '0px', + threshold: 1.0 // Adjust this to control when the callback fires + }); + + document.querySelectorAll('pre code').forEach(codeBlock => { + const pre = codeBlock.parentNode; + pre.style.position = 'relative'; // Ensure parent `pre` can contain absolute elements + + // Create and append the copy button + const copyBtn = document.createElement('button'); + copyBtn.className = 'clipboard-button'; + copyBtn.innerHTML = copyIcon; + copyBtn.setAttribute('aria-label', 'Copy code to clipboard'); + pre.appendChild(copyBtn); + + // Attach event listener to copy button + copyBtn.addEventListener('click', async () => { + // Determine if the code is in a table or not + const isTable = codeBlock.querySelector('table'); + const codeToCopy = isTable ? getCodeFromTable(codeBlock) : getNonTableCode(codeBlock); + try { + await navigator.clipboard.writeText(codeToCopy); + changeIcon(copyBtn, true); // Show success icon + } catch (error) { + console.error('Failed to copy text: ', error); + changeIcon(copyBtn, false); // Show error icon + } + }); + + const langClass = codeBlock.className.match(/language-(\w+)/); + const lang = langClass ? langClass[1] : 'default'; + + // Create and append the label + const label = document.createElement('span'); + label.className = 'code-label label-' + lang; // Use the specific language class + label.textContent = lang.toUpperCase(); // Display the language as label + pre.appendChild(label); + + let ticking = false; + pre.addEventListener('scroll', () => { + if (!ticking) { + window.requestAnimationFrame(() => { + copyBtn.style.right = `-${pre.scrollLeft}px`; + label.style.right = `-${pre.scrollLeft}px`; + ticking = false; + }); + ticking = true; + } + }); + + }); +}); diff --git a/static/js/count.js b/static/js/count.js new file mode 100644 index 0000000..7c504bc --- /dev/null +++ b/static/js/count.js @@ -0,0 +1,270 @@ +// GoatCounter: https://www.goatcounter.com +// This file (and *only* this file) is released under the ISC license: +// https://opensource.org/licenses/ISC +;(function() { + 'use strict'; + + if (window.goatcounter && window.goatcounter.vars) // Compatibility with very old version; do not use. + window.goatcounter = window.goatcounter.vars + else + window.goatcounter = window.goatcounter || {} + + // Load settings from data-goatcounter-settings. + var s = document.querySelector('script[data-goatcounter]') + if (s && s.dataset.goatcounterSettings) { + try { var set = JSON.parse(s.dataset.goatcounterSettings) } + catch (err) { console.error('invalid JSON in data-goatcounter-settings: ' + err) } + for (var k in set) + if (['no_onload', 'no_events', 'allow_local', 'allow_frame', 'path', 'title', 'referrer', 'event'].indexOf(k) > -1) + window.goatcounter[k] = set[k] + } + + var enc = encodeURIComponent + + // Get all data we're going to send off to the counter endpoint. + var get_data = function(vars) { + var data = { + p: (vars.path === undefined ? goatcounter.path : vars.path), + r: (vars.referrer === undefined ? goatcounter.referrer : vars.referrer), + t: (vars.title === undefined ? goatcounter.title : vars.title), + e: !!(vars.event || goatcounter.event), + s: [window.screen.width, window.screen.height, (window.devicePixelRatio || 1)], + b: is_bot(), + q: location.search, + } + + var rcb, pcb, tcb // Save callbacks to apply later. + if (typeof(data.r) === 'function') rcb = data.r + if (typeof(data.t) === 'function') tcb = data.t + if (typeof(data.p) === 'function') pcb = data.p + + if (is_empty(data.r)) data.r = document.referrer + if (is_empty(data.t)) data.t = document.title + if (is_empty(data.p)) data.p = get_path() + + if (rcb) data.r = rcb(data.r) + if (tcb) data.t = tcb(data.t) + if (pcb) data.p = pcb(data.p) + return data + } + + // Check if a value is "empty" for the purpose of get_data(). + var is_empty = function(v) { return v === null || v === undefined || typeof(v) === 'function' } + + // See if this looks like a bot; there is some additional filtering on the + // backend, but these properties can't be fetched from there. + var is_bot = function() { + // Headless browsers are probably a bot. + var w = window, d = document + if (w.callPhantom || w._phantom || w.phantom) + return 150 + if (w.__nightmare) + return 151 + if (d.__selenium_unwrapped || d.__webdriver_evaluate || d.__driver_evaluate) + return 152 + if (navigator.webdriver) + return 153 + return 0 + } + + // Object to urlencoded string, starting with a ?. + var urlencode = function(obj) { + var p = [] + for (var k in obj) + if (obj[k] !== '' && obj[k] !== null && obj[k] !== undefined && obj[k] !== false) + p.push(enc(k) + '=' + enc(obj[k])) + return '?' + p.join('&') + } + + // Show a warning in the console. + var warn = function(msg) { + if (console && 'warn' in console) + console.warn('goatcounter: ' + msg) + } + + // Get the endpoint to send requests to. + var get_endpoint = function() { + var s = document.querySelector('script[data-goatcounter]') + if (s && s.dataset.goatcounter) + return s.dataset.goatcounter + return (goatcounter.endpoint || window.counter) // counter is for compat; don't use. + } + + // Get current path. + var get_path = function() { + var loc = location, + c = document.querySelector('link[rel="canonical"][href]') + if (c) { // May be relative or point to different domain. + var a = document.createElement('a') + a.href = c.href + if (a.hostname.replace(/^www\./, '') === location.hostname.replace(/^www\./, '')) + loc = a + } + return (loc.pathname + loc.search) || '/' + } + + // Run function after DOM is loaded. + var on_load = function(f) { + if (document.body === null) + document.addEventListener('DOMContentLoaded', function() { f() }, false) + else + f() + } + + // Filter some requests that we (probably) don't want to count. + goatcounter.filter = function() { + if ('visibilityState' in document && document.visibilityState === 'prerender') + return 'visibilityState' + if (!goatcounter.allow_frame && location !== parent.location) + return 'frame' + if (!goatcounter.allow_local && location.hostname.match(/(localhost$|^127\.|^10\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^192\.168\.|^0\.0\.0\.0$)/)) + return 'localhost' + if (!goatcounter.allow_local && location.protocol === 'file:') + return 'localfile' + if (localStorage && localStorage.getItem('skipgc') === 't') + return 'disabled with #toggle-goatcounter' + return false + } + + // Get URL to send to GoatCounter. + window.goatcounter.url = function(vars) { + var data = get_data(vars || {}) + if (data.p === null) // null from user callback. + return + data.rnd = Math.random().toString(36).substr(2, 5) // Browsers don't always listen to Cache-Control. + + var endpoint = get_endpoint() + if (!endpoint) + return warn('no endpoint found') + + return endpoint + urlencode(data) + } + + // Count a hit. + window.goatcounter.count = function(vars) { + var f = goatcounter.filter() + if (f) + return warn('not counting because of: ' + f) + + var url = goatcounter.url(vars) + if (!url) + return warn('not counting because path callback returned null') + + var img = document.createElement('img') + img.src = url + img.style.position = 'absolute' // Affect layout less. + img.style.bottom = '0px' + img.style.width = '1px' + img.style.height = '1px' + img.loading = 'eager' + img.setAttribute('alt', '') + img.setAttribute('aria-hidden', 'true') + + var rm = function() { if (img && img.parentNode) img.parentNode.removeChild(img) } + img.addEventListener('load', rm, false) + document.body.appendChild(img) + } + + // Get a query parameter. + window.goatcounter.get_query = function(name) { + var s = location.search.substr(1).split('&') + for (var i = 0; i < s.length; i++) + if (s[i].toLowerCase().indexOf(name.toLowerCase() + '=') === 0) + return s[i].substr(name.length + 1) + } + + // Track click events. + window.goatcounter.bind_events = function() { + if (!document.querySelectorAll) // Just in case someone uses an ancient browser. + return + + var send = function(elem) { + return function() { + goatcounter.count({ + event: true, + path: (elem.dataset.goatcounterClick || elem.name || elem.id || ''), + title: (elem.dataset.goatcounterTitle || elem.title || (elem.innerHTML || '').substr(0, 200) || ''), + referrer: (elem.dataset.goatcounterReferrer || elem.dataset.goatcounterReferral || ''), + }) + } + } + + Array.prototype.slice.call(document.querySelectorAll("*[data-goatcounter-click]")).forEach(function(elem) { + if (elem.dataset.goatcounterBound) + return + var f = send(elem) + elem.addEventListener('click', f, false) + elem.addEventListener('auxclick', f, false) // Middle click. + elem.dataset.goatcounterBound = 'true' + }) + } + + // Add a "visitor counter" frame or image. + window.goatcounter.visit_count = function(opt) { + on_load(function() { + opt = opt || {} + opt.type = opt.type || 'html' + opt.append = opt.append || 'body' + opt.path = opt.path || get_path() + opt.attr = opt.attr || {width: '200', height: (opt.no_branding ? '60' : '80')} + + opt.attr['src'] = get_endpoint() + 'er/' + enc(opt.path) + '.' + enc(opt.type) + '?' + if (opt.no_branding) opt.attr['src'] += '&no_branding=1' + if (opt.style) opt.attr['src'] += '&style=' + enc(opt.style) + if (opt.start) opt.attr['src'] += '&start=' + enc(opt.start) + if (opt.end) opt.attr['src'] += '&end=' + enc(opt.end) + + var tag = {png: 'img', svg: 'img', html: 'iframe'}[opt.type] + if (!tag) + return warn('visit_count: unknown type: ' + opt.type) + + if (opt.type === 'html') { + opt.attr['frameborder'] = '0' + opt.attr['scrolling'] = 'no' + } + + var d = document.createElement(tag) + for (var k in opt.attr) + d.setAttribute(k, opt.attr[k]) + + var p = document.querySelector(opt.append) + if (!p) + return warn('visit_count: append not found: ' + opt.append) + p.appendChild(d) + }) + } + + // Make it easy to skip your own views. + if (location.hash === '#toggle-goatcounter') { + if (localStorage.getItem('skipgc') === 't') { + localStorage.removeItem('skipgc', 't') + alert('GoatCounter tracking is now ENABLED in this browser.') + } + else { + localStorage.setItem('skipgc', 't') + alert('GoatCounter tracking is now DISABLED in this browser until ' + location + ' is loaded again.') + } + } + + if (!goatcounter.no_onload) + on_load(function() { + // 1. Page is visible, count request. + // 2. Page is not yet visible; wait until it switches to 'visible' and count. + // See #487 + if (!('visibilityState' in document) || document.visibilityState === 'visible') + goatcounter.count() + else { + var f = function(e) { + if (document.visibilityState !== 'visible') + return + document.removeEventListener('visibilitychange', f) + goatcounter.count() + } + document.addEventListener('visibilitychange', f) + } + + if (!goatcounter.no_events) + goatcounter.bind_events() + }) +})(); + diff --git a/static/js/imamu.js b/static/js/imamu.js new file mode 100644 index 0000000..c317f48 --- /dev/null +++ b/static/js/imamu.js @@ -0,0 +1 @@ +!function(){"use strict";!function(t){var e=t.screen,n=e.width,r=e.height,a=t.navigator.language,i=t.location,o=t.localStorage,u=t.document,c=t.history,f=i.hostname,s=i.pathname,l=i.search,d=u.currentScript;if(d){var m="data-",h=d.getAttribute.bind(d),v=h(m+"website-id"),p=h(m+"host-url"),g="false"!==h(m+"auto-track"),y=h(m+"do-not-track"),b=h(m+"domains")||"",S=b.split(",").map((function(t){return t.trim()})),k=(p?p.replace(/\/$/,""):d.src.split("/").slice(0,-1).join("/"))+"/api/send",w=n+"x"+r,N=/data-umami-event-([\w-_]+)/,T=m+"umami-event",j=300,A=function(t,e,n){var r=t[e];return function(){for(var e=[],a=arguments.length;a--;)e[a]=arguments[a];return n.apply(null,e),r.apply(t,e)}},x=function(){return{website:v,hostname:f,screen:w,language:a,title:M,url:I,referrer:J}},E=function(){return o&&o.getItem("umami.disabled")||y&&function(){var e=t.doNotTrack,n=t.navigator,r=t.external,a="msTrackingProtectionEnabled",i=e||n.doNotTrack||n.msDoNotTrack||r&&a in r&&r[a]();return"1"==i||"yes"===i}()||b&&!S.includes(f)},O=function(t,e,n){n&&(J=I,(I=function(t){try{return new URL(t).pathname}catch(e){return t}}(n.toString()))!==J&&setTimeout(D,j))},L=function(t,e){if(void 0===e&&(e="event"),!E()){var n={"Content-Type":"application/json"};return void 0!==K&&(n["x-umami-cache"]=K),fetch(k,{method:"POST",body:JSON.stringify({type:e,payload:t}),headers:n}).then((function(t){return t.text()})).then((function(t){return K=t})).catch((function(){}))}},D=function(t,e){return L("string"==typeof t?Object.assign({},x(),{name:t,data:"object"==typeof e?e:void 0}):"object"==typeof t?t:"function"==typeof t?t(x()):x())};t.umami||(t.umami={track:D,identify:function(t){return L(Object.assign({},x(),{data:t}),"identify")}});var K,P,_,q,C,I=""+s+l,J=u.referrer,M=u.title;if(g&&!E()){c.pushState=A(c,"pushState",O),c.replaceState=A(c,"replaceState",O),C=function(t){var e=t.getAttribute.bind(t),n=e(T);if(n){var r={};return t.getAttributeNames().forEach((function(t){var n=t.match(N);n&&(r[n[1]]=e(t))})),D(n,r)}return Promise.resolve()},u.addEventListener("click",(function(t){var e=t.target,n="A"===e.tagName?e:function(t,e){for(var n=t,r=0;r title"))&&_.observe(q,{subtree:!0,characterData:!0,childList:!0});var R=function(){"complete"!==u.readyState||P||(D(),P=!0)};u.addEventListener("readystatechange",R,!0),R()}}}(window)}(); \ No newline at end of file diff --git a/static/js/main.js b/static/js/main.js new file mode 100644 index 0000000..e69de29 diff --git a/static/js/note.js b/static/js/note.js new file mode 100644 index 0000000..ec7a141 --- /dev/null +++ b/static/js/note.js @@ -0,0 +1,14 @@ +document.addEventListener('DOMContentLoaded', function() { + document.querySelectorAll('.note-toggle').forEach(function(toggleButton) { + var content = toggleButton.nextElementSibling; + var isHidden = content.style.display === 'none'; + toggleButton.setAttribute('aria-expanded', !isHidden); + + toggleButton.addEventListener('click', function() { + var expanded = this.getAttribute('aria-expanded') === 'true'; + this.setAttribute('aria-expanded', !expanded); + content.style.display = expanded ? 'none' : 'block'; + }); + }); +}); + diff --git a/static/js/themetoggle.js b/static/js/themetoggle.js new file mode 100644 index 0000000..79764a8 --- /dev/null +++ b/static/js/themetoggle.js @@ -0,0 +1,57 @@ +function setTheme(mode) { + localStorage.setItem("theme-storage", mode); +} + +// Functions needed for the theme toggle +// + +function toggleTheme() { + if (localStorage.getItem("theme-storage") === "light") { + setTheme("dark"); + updateItemToggleTheme(); + } else if (localStorage.getItem("theme-storage") === "dark") { + setTheme("light"); + updateItemToggleTheme(); + } +} + +function updateItemToggleTheme() { + let mode = getSavedTheme(); + + const darkModeStyle = document.getElementById("darkModeStyle"); + if (darkModeStyle) { + darkModeStyle.disabled = (mode === "light"); + } + + const sunIcon = document.getElementById("sun-icon"); + const moonIcon = document.getElementById("moon-icon"); + if (sunIcon && moonIcon) { + sunIcon.style.display = (mode === "dark") ? "inline-block" : "none"; + moonIcon.style.display = (mode === "light") ? "inline-block" : "none"; + } + + let htmlElement = document.querySelector("html"); + if (mode === "dark") { + htmlElement.classList.remove("light") + htmlElement.classList.add("dark") + } else if (mode === "light") { + htmlElement.classList.remove("dark") + htmlElement.classList.add("light") + } +} + +function getSavedTheme() { + let currentTheme = localStorage.getItem("theme-storage"); + if(!currentTheme) { + if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { + currentTheme = "dark"; + } else { + currentTheme = "light"; + } + } + + return currentTheme; +} + +// Update the toggle theme on page load +updateItemToggleTheme(); diff --git a/static/js/toc.js b/static/js/toc.js new file mode 100644 index 0000000..5521c18 --- /dev/null +++ b/static/js/toc.js @@ -0,0 +1,15 @@ +document.addEventListener('DOMContentLoaded', () => { + const tocTitle = document.querySelector('.toc-title'); + const tocList = document.querySelector('.toc-list'); + + if (tocTitle && tocList) { + const toggleToC = () => { + const isExpanded = tocList.style.display === 'block' || window.getComputedStyle(tocList).display === 'block'; + tocList.style.display = isExpanded ? 'none' : 'block'; + tocTitle.classList.toggle('expanded', !isExpanded); + }; + + tocTitle.addEventListener('click', toggleToC); + } +}); + diff --git a/static/social_icons/LICENSE b/static/social_icons/LICENSE new file mode 100644 index 0000000..993facc --- /dev/null +++ b/static/social_icons/LICENSE @@ -0,0 +1 @@ +All icons in this directory are downloaded from [FontAwesome](https://fontawesome.com/). They are part of the [free offer](https://fontawesome.com/license/free) and are licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). \ No newline at end of file diff --git a/static/social_icons/apple.svg b/static/social_icons/apple.svg new file mode 100644 index 0000000..d0532d5 --- /dev/null +++ b/static/social_icons/apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/bitcoin.svg b/static/social_icons/bitcoin.svg new file mode 100644 index 0000000..941d9b0 --- /dev/null +++ b/static/social_icons/bitcoin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/deviantart.svg b/static/social_icons/deviantart.svg new file mode 100644 index 0000000..7dbd0b6 --- /dev/null +++ b/static/social_icons/deviantart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/diaspora.svg b/static/social_icons/diaspora.svg new file mode 100644 index 0000000..55527b5 --- /dev/null +++ b/static/social_icons/diaspora.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/discord.svg b/static/social_icons/discord.svg new file mode 100644 index 0000000..f0dfeab --- /dev/null +++ b/static/social_icons/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/discourse.svg b/static/social_icons/discourse.svg new file mode 100644 index 0000000..343bea6 --- /dev/null +++ b/static/social_icons/discourse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/email.svg b/static/social_icons/email.svg new file mode 100644 index 0000000..85245e2 --- /dev/null +++ b/static/social_icons/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/ethereum.svg b/static/social_icons/ethereum.svg new file mode 100644 index 0000000..af202de --- /dev/null +++ b/static/social_icons/ethereum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/etsy.svg b/static/social_icons/etsy.svg new file mode 100644 index 0000000..ebc040a --- /dev/null +++ b/static/social_icons/etsy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/facebook.svg b/static/social_icons/facebook.svg new file mode 100644 index 0000000..0afaf7a --- /dev/null +++ b/static/social_icons/facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/github.svg b/static/social_icons/github.svg new file mode 100644 index 0000000..e32807a --- /dev/null +++ b/static/social_icons/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/gitlab.svg b/static/social_icons/gitlab.svg new file mode 100644 index 0000000..b577d3f --- /dev/null +++ b/static/social_icons/gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/google.svg b/static/social_icons/google.svg new file mode 100644 index 0000000..b3776b0 --- /dev/null +++ b/static/social_icons/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/hacker-news.svg b/static/social_icons/hacker-news.svg new file mode 100644 index 0000000..23e3980 --- /dev/null +++ b/static/social_icons/hacker-news.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/instagram.svg b/static/social_icons/instagram.svg new file mode 100644 index 0000000..89f63c4 --- /dev/null +++ b/static/social_icons/instagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/linkedin.svg b/static/social_icons/linkedin.svg new file mode 100644 index 0000000..d54fcf5 --- /dev/null +++ b/static/social_icons/linkedin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/mastodon.svg b/static/social_icons/mastodon.svg new file mode 100644 index 0000000..5e12f81 --- /dev/null +++ b/static/social_icons/mastodon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/matrix.svg b/static/social_icons/matrix.svg new file mode 100644 index 0000000..bc41720 --- /dev/null +++ b/static/social_icons/matrix.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/static/social_icons/paypal.svg b/static/social_icons/paypal.svg new file mode 100644 index 0000000..efdc81a --- /dev/null +++ b/static/social_icons/paypal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/pinterest.svg b/static/social_icons/pinterest.svg new file mode 100644 index 0000000..eb977c2 --- /dev/null +++ b/static/social_icons/pinterest.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/quora.svg b/static/social_icons/quora.svg new file mode 100644 index 0000000..375d302 --- /dev/null +++ b/static/social_icons/quora.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/reddit.svg b/static/social_icons/reddit.svg new file mode 100644 index 0000000..a8a3a96 --- /dev/null +++ b/static/social_icons/reddit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/rss.svg b/static/social_icons/rss.svg new file mode 100644 index 0000000..b862886 --- /dev/null +++ b/static/social_icons/rss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/skype.svg b/static/social_icons/skype.svg new file mode 100644 index 0000000..3369aba --- /dev/null +++ b/static/social_icons/skype.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/slack.svg b/static/social_icons/slack.svg new file mode 100644 index 0000000..0dbc26d --- /dev/null +++ b/static/social_icons/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/snapchat.svg b/static/social_icons/snapchat.svg new file mode 100644 index 0000000..2cd79dd --- /dev/null +++ b/static/social_icons/snapchat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/soundcloud.svg b/static/social_icons/soundcloud.svg new file mode 100644 index 0000000..4724d74 --- /dev/null +++ b/static/social_icons/soundcloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/spotify.svg b/static/social_icons/spotify.svg new file mode 100644 index 0000000..1d393ba --- /dev/null +++ b/static/social_icons/spotify.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/stack-exchange.svg b/static/social_icons/stack-exchange.svg new file mode 100644 index 0000000..0a3177f --- /dev/null +++ b/static/social_icons/stack-exchange.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/stack-overflow.svg b/static/social_icons/stack-overflow.svg new file mode 100644 index 0000000..2ca50c7 --- /dev/null +++ b/static/social_icons/stack-overflow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/steam.svg b/static/social_icons/steam.svg new file mode 100644 index 0000000..b61f374 --- /dev/null +++ b/static/social_icons/steam.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/telegram.svg b/static/social_icons/telegram.svg new file mode 100644 index 0000000..02f48c0 --- /dev/null +++ b/static/social_icons/telegram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/twitter.svg b/static/social_icons/twitter.svg new file mode 100644 index 0000000..0778f72 --- /dev/null +++ b/static/social_icons/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/vimeo.svg b/static/social_icons/vimeo.svg new file mode 100644 index 0000000..d98368e --- /dev/null +++ b/static/social_icons/vimeo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/whatsapp.svg b/static/social_icons/whatsapp.svg new file mode 100644 index 0000000..d259142 --- /dev/null +++ b/static/social_icons/whatsapp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/x-twitter.svg b/static/social_icons/x-twitter.svg new file mode 100644 index 0000000..f5feed7 --- /dev/null +++ b/static/social_icons/x-twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/social_icons/youtube.svg b/static/social_icons/youtube.svg new file mode 100644 index 0000000..287dca2 --- /dev/null +++ b/static/social_icons/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..a0e1ee0 --- /dev/null +++ b/templates/404.html @@ -0,0 +1,8 @@ +{% extends "page.html" %} + +{% block main_content %} +
+ {{ post_macros::page_header(title="404")}} + Page not found :( +
+{% endblock main_content %} \ No newline at end of file diff --git a/templates/cards.html b/templates/cards.html new file mode 100644 index 0000000..2c67f32 --- /dev/null +++ b/templates/cards.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} + +{% block main_content %} + {% if section.extra.section_path -%} + {% set section = get_section(path=section.extra.section_path) %} + {% endif -%} + + {{ post_macros::page_header(title=section.title) }} + +
+ {%- if paginator %} + {%- set show_pages = paginator.pages -%} + {% else %} + {%- set show_pages = section.pages -%} + {% endif -%} + + {{ post_macros::cards_posts(pages=show_pages) }} +
+ + {% if paginator %} + + {% endif %} +{% endblock main_content %} \ No newline at end of file diff --git a/templates/homepage.html b/templates/homepage.html new file mode 100644 index 0000000..9bf49d5 --- /dev/null +++ b/templates/homepage.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} + +{% block main_content %} + {{ post_macros::home_page(section=section) }} +{% endblock main_content %} diff --git a/templates/macros/macros.html b/templates/macros/macros.html new file mode 100644 index 0000000..57aa534 --- /dev/null +++ b/templates/macros/macros.html @@ -0,0 +1,248 @@ +{% macro list_tag_posts(pages, tag_name=false) %} + {% if tag_name %} + + {% else %} + + {% endif %} + +
+ {{ post_macros::list_posts(pages=pages) }} +
+{% endmacro %} + +{% macro list_posts(pages) %} + +{% endmacro list_posts %} + +{% macro list_terms(terms) %} + +{% endmacro list_terms %} + +{% macro tags(page, short=false) %} + {%- if page.taxonomies and page.taxonomies.tags %} + + {%- if short %} + :: + {%- set sep = "," -%} + {% else %} + :: tags:  + {%- set sep = " " -%} + {% endif -%} + {%- for tag in page.taxonomies.tags %} + + {%- if not loop.last %}{{ sep | safe }}{% endif -%} + {% endfor -%} + + {% endif -%} +{% endmacro tags %} + +{% macro page_header(title) %} + +{% endmacro content %} + +{% macro home_page(section) %} +
+
+
+ {{post_macros::page_header(title=section.title)}} + {{ section.content | safe }} +
+
+
+{% endmacro home_page %} + +{% macro content(page) %} +
+
+
+ {#

{{ page.title }}

#} + {{ post_macros::page_header(title=page.title) }} + +
+ {% if page.date %} + Posted on + {% endif %} + + {% if page.updated %} + :: Updated on + {% endif %} + + {% if page.extra.read_time %} + :: Min Read + {% endif %} + + {# Inline display of tags directly after the date #} + {% if page.taxonomies and page.taxonomies.tags %} + :: Tags: + + {%- for tag in page.taxonomies.tags %} + {% if not loop.last %}, {% endif %} + {% endfor %} + + {% endif %} + + {# View the page on GitHub #} + {% if page.extra.repo_view | default(value=false) %} + {# Use the page's repo_url if defined, otherwise use the global edit_repo_url #} + {% if page.extra.repo_url is defined %} + {% set repo_url = page.extra.repo_url %} + {% elif config.extra.repo_url is defined %} + {% set repo_url = config.extra.repo_url %} + {% else %} + {% set repo_url = false %} + {% endif %} + + {% if repo_url %} + {% set final_url = repo_url ~ page.relative_path %} + :: Source Code + {% endif %} + {% endif %} + + {% if page.draft %} + DRAFT + {% endif %} + +
+
+ + {% if page.extra.tldr %} +
+ tl;dr: + {{ page.extra.tldr }} +
+ {% endif %} + + {# Optional table of contents #} + {% if config.extra.toc | default(value=false) %} + {% if page.toc %} +
+

Table of Contents

+
    + {% for h1 in page.toc %} +
  • + {{ h1.title }} + {% if h1.children %} +
      + {% for h2 in h1.children %} +
    • + {{ h2.title }} +
    • + + {% if h2.children %} + + {% endif %} + {% endfor %} +
    + {% endif %} +
  • + {% endfor %} +
+
+ {% endif %} + {% endif %} + +
+ {{ page.content | safe }} +
+
+
+{% endmacro content %} + +{% macro cards_posts(pages) %} +
+ {%- for page in pages %} +
+ {% if page.extra.local_image %} + {{ + {% elif page.extra.remote_image %} + {{ + {% else %} +
+ {% endif %} + +
+

+ {% if page.extra.link_to %} + {{page.title}} + {% else %} + {{page.title}} + {% endif %} +

+ +
+ {%- if page.date %} + + {% endif -%} + {% if page.draft %} + DRAFT + {% endif %} +
+ +
+ {% if page.description %} + {{ page.description }} + {% endif %} +
+
+
+ + {% endfor -%} +
+{% endmacro cards_posts %} diff --git a/templates/partials/header.html b/templates/partials/header.html new file mode 100644 index 0000000..f255743 --- /dev/null +++ b/templates/partials/header.html @@ -0,0 +1,182 @@ +{% import "macros/macros.html" as post_macros %} + + + + + + + {% if page.extra.meta %} + + {% for data in page.extra.meta %} + + {% endfor %} + {% endif %} + + {# Site title #} + {% set current_path = current_path | default(value="/") %} + {% if current_path == "/" %} + + {{ config.title | default(value="Home") }} + + {% if not page_has_og_title %} + + {% endif %} + + {% else %} + + {% if page.title %} {{ page.title }} + {% elif section.title %} {{ section.title }} + {% elif config.title %} {{ config.title }} + {% else %} Post {% endif %} + + + {% if not page_has_og_title %} + + {% endif %} + {% endif %} + + {% if not page_has_og_description %} + {% if page.description %} + + {% elif config.description %} + + {% endif %} + {% endif %} + + {% if not page_has_description %} + {% if page.description %} + + {% elif config.description %} + + {% endif %} + {% endif %} + + {# Favicon #} + {% if config.extra.favicon %} + + {% endif %} + + {# Font from cdn or disk #} + {% if config.extra.use_cdn | default(value=false) %} + + + {% else %} + + {% endif %} + + {# Analytics #} + {% if config.extra.analytics.enabled %} + {% if config.extra.analytics.umami.website_id %} + {% set website_id = config.extra.analytics.umami.website_id %} + {% set host_url = config.extra.analytics.umami.host_url | default(value="https://analytics.eu.umami.is") %} + + + + {% endif %} + + {% if config.extra.analytics.goatcounter.user %} + {% set user = config.extra.analytics.goatcounter.user %} + {% set host = config.extra.analytics.goatcounter.host | default(value="goatcounter.com") %} + + + + {% endif %} + {% endif %} + + {# Fancy Codeblock #} + {% if config.extra.fancy_code %} + + {% endif %} + + {# Table of contents #} + {% if config.extra.toc | default(value=false) %} + + {% endif %} + + {# Dynamic Note #} + {% if config.extra.dynamic_note | default(value=false) %} + + {% endif %} + + {% if config.extra.mathjax | default(value=false) %} + {% if config.extra.mathjax_dollar_inline_enable | default(value=false) %} + + {% endif %} + + {% endif %} + + {# RSS #} + + + + {% set theme = config.extra.theme | default(value="toggle") %} + {% if theme == "dark" %} + + {% elif theme == "light" %} + + {% elif theme == "auto" %} + + + {% elif theme == "toggle" %} + + + {% endif %} + + + + {% if theme == "dark" %} + + {% elif theme == "light" %} + + {% elif theme == "auto" %} + + {% else %} + + {% endif %} + + + + {% if config.extra.stylesheets %} + {% for stylesheet in config.extra.stylesheets %} + + {% endfor %} + {% endif %} + diff --git a/templates/partials/nav.html b/templates/partials/nav.html new file mode 100644 index 0000000..dd3d214 --- /dev/null +++ b/templates/partials/nav.html @@ -0,0 +1,29 @@ +
+
+ {{ config.title }} + +
+ {% for social in config.extra.socials | default(value=[]) %} + + {% endfor %} +
+
+ + +
diff --git a/templates/shortcodes/note.html b/templates/shortcodes/note.html new file mode 100644 index 0000000..adaabac --- /dev/null +++ b/templates/shortcodes/note.html @@ -0,0 +1,38 @@ +
+ {% if clickable | default(value=false) %} + + + {% if hidden | default(value=false) %} + diff --git a/templates/taxonomy_list.html b/templates/taxonomy_list.html new file mode 100644 index 0000000..17a4b74 --- /dev/null +++ b/templates/taxonomy_list.html @@ -0,0 +1,21 @@ +{%extends "base.html"%} + +{% block main_content %} +
+ {% block title %} + {{ post_macros::page_header(title="Tags") }} + {% endblock title %} + +
+ +
+
+{% endblock main_content %} \ No newline at end of file diff --git a/templates/taxonomy_single.html b/templates/taxonomy_single.html new file mode 100644 index 0000000..0549161 --- /dev/null +++ b/templates/taxonomy_single.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block main_content %} + +{{ post_macros::list_tag_posts(pages=term.pages, tag_name=term.name) }} + +{% endblock main_content %}