diff options
Diffstat (limited to '_posts/hello.org')
| -rw-r--r-- | _posts/hello.org | 634 |
1 files changed, 0 insertions, 634 deletions
diff --git a/_posts/hello.org b/_posts/hello.org deleted file mode 100644 index 3a7a9c6..0000000 --- a/_posts/hello.org +++ /dev/null @@ -1,634 +0,0 @@ -:PROPERTIES: -:ID: 73d663b6-1aea-4d82-a0f6-b88b302e49cb -:END: -#+TITLE: Hello, Org -#+DATE: <2023-06-20 Tue 11:45> -#+filetags: :technology:home: - - - -* TLDR -:PROPERTIES: -:ID: b15846be-b33b-4233-86b1-b56a76622478 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -- Create a new folder -- Put [[https://raw.githubusercontent.com/mattkae/matthewkosarek-xyz/master/index.css][index.css]], [[https://raw.githubusercontent.com/mattkae/matthewkosarek-xyz/master/publish.el][publish.el]], and [[https://github.com/mattkae/matthewkosarek-xyz/blob/master/publish.sh][publish.sh]] in the folder -- Create a folder called ~_posts~ (this is where blog posts are written) -- Create an org file in ~_posts~, ideally with a ~#+DATE~ and ~#+TITLE~ attribute -- Create a folder called ~posts~ (this is where blog posts are published to) -- Put [[https://raw.githubusercontent.com/mattkae/matthewkosarek-xyz/master/posts/post.js][post.js]] and [[https://github.com/mattkae/matthewkosarek-xyz/blob/master/posts/post.css][post.css]] inside of the ~posts~ directory -- Run ~./publish.sh~ to generate the blog post files -- Run ~./python -m http.server 8080~ from the root folder -- Navigate to ~localhost:8080/posts/sitemap.html~ to see your posts - -* Introduction -:PROPERTIES: -:ID: 39f1ddfb-72e3-4894-9c4c-b160c6e224fe -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -I've recently fallen in love with ~org-mode~, specifically when I use it with [[https://www.orgroam.com/][org-roam]]. I find the whole workflow of creating, tagging, and - later on - searching for information on my computer to be very elegant. On top of that, now that I have the time, I want to begin writing blog posts to better work out my thoughts. With both of these things in mind, I am again turning to the universal tool for human prospering: ~org-mode~. This time, I want to see how it can help me turn a simple org file into a blog post on my website. My requirements are: - -1. Org files must get published to HTML files in a particular format with a preset stylesheet -2. Code blocks must include code highlighting -3. Images must be supported -4. Posts must be timestamped with the creation date next to the title -5. A high-level "directory" page should be generated containing a list of the posts ordered chronologically with the newest at the top -6. Posts should have tags that can be used for filtering and search. - -And that's pretty much it for now. Without further ado, let's jump into getting this up and running. - -(Note: I will be heavily inspired by [[https://systemcrafters.net/publishing-websites-with-org-mode/building-the-site/#creating-the-build-script][this post from System Crafters]]. I highly recommend that you read his post first before you follow my post, as he provides more details about the ~org-publish-project-alist~ command than I am willing to go into in this post.) - -* Basic HTML File -:PROPERTIES: -:ID: fbd6c42a-45cf-4c16-81fc-e99df88e2389 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -As a pilot, we are going to use this org file that I am currently writing (~hello.org~) as our guinea pig. The goal is to have this org file be our very first blog post. - -Emacs ships with org export goodies out of the box via the ~ox-publish.el~ package (which you can find [[https://github.com/emacs-mirror/emacs/blob/master/lisp/org/ox-publish.el][here]]). In our case, we will want to use this package to write a script that exports all the ~./_posts/*.org~ files and outputs them to a corresponding ~./posts/*.html~. Leaning heavily on the System Crafters information, we can create a file called ~publish.el~ and write the following inside of it: - -#+BEGIN_SRC emacs-lisp - (require 'ox-publish) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html))) - - (org-publish-all t) - (message "Build Complete") -#+END_SRC - - Next, in the same way that System Crafters made a shell script to execute this lisp, snippet, we can create a file called ~publish.sh~ and write the following inside of it: - - #+BEGIN_SRC sh -#!/bin/sh -emacs -Q --script publish.el - #+END_SRC - - We then do a ~chmod +x publish.sh~ to make it an executable and run it with ~./publish.sh~. If everything went according to plan, we should see a new file at ~posts/hello.html~. - -* Disabling features that we don't want -:PROPERTIES: -:ID: 393f268d-3200-4857-9c78-097468330437 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -The next thing will be to remove some of the generated items that I didn't ask for, namely the table of contents, author, section numbers, creation time stamp, and the validation link. - -#+BEGIN_SRC emacs-lisp - (require 'ox-publish) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html - :with-toc nil ; Disable table of contents - :with-author nil ; Disable author - :section-numbers nil ; Disable section numbers - :time-stamp-file nil ; Disable timestamp - :with-date nil))) ; Disable date - - (setq org-html-validation-link nil) ; Disable the validation link at the bottom - - (org-publish-all t) - (message "Build Complete") -#+END_SRC - -* Styling & Code Highlighting -:PROPERTIES: -:ID: 25bb1f38-ad48-4513-9238-229955db4328 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -Next thing on our list is custom styling. This can be achieved by first installing the ~htmlize~ package from ~melpa~ / ~elpa~. The EmacsWiki describes this as "a package for exporting the contents of an Emacs buffer to HTML while respecting display properties such as colors, fonts, underlining, invisibility, etc" ([[https://www.emacswiki.org/emacs/Htmlize][reference]]). If used "out-of-the-box", the buffer will be exported to HTML with all of the styles inlined (e.g. if you underline something in your org file, you will generate a ~<span style="text-decoration: underline">...</span>~). However, we are more interested in styling everything by ourselves: we don't want ~htmlize~ making assumptions about what underlining means to us! Luckily, ~htmlize~ gives us the option to export with class names instead of inline styles so that we can specify each style for ourselves. - -#+BEGIN_SRC emacs-lisp - (require 'ox-publish) - - ;; First, we need to setup our publish.el file to hook up to melpa/elpa so that we can ensure - ;; htmlize is installed before we begin publishing. - (require 'package) - (setq package-user-dir (expand-file-name "./.packages")) - (setq package-archives '(("melpa" . "https://melpa.org/packages/") - ("elpa" . "https://elpa.gnu.org/packages/"))) - - ;; Initialize the package system - (package-initialize) - (unless package-archive-contents - (package-refresh-contents)) - - ;; Install dependencies - (package-install 'htmlize) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html - :with-toc nil - :with-author nil - :section-numbers nil - :time-stamp-file nil))) - - (setq org-html-htmlize-output-type 'css) ;; Output classnames in the HTML instead of inline CSS - (setq org-html-htmlize-font-prefix "org-") ;; Prefix all class names with "org-" - - (setq org-html-validation-link nil - org-html-head-include-scripts nil ;; Removes any scripts that were included by default - org-html-head-include-default-style nil) ;; Removes any styles that were included by default - - (org-publish-all t) - - (message "Build Complete") - -#+END_SRC - -If you run ~publish.sh~ and open the HTML page now, you will see that _zero_ styling has been applied to the page. However, if you inspect an element in your browser that you /suspect/ should have styling (like our underlined element from before), you will see that it has a class name instead of inline styles. - -Now that our generated elements have class names, we can define the style for each relevant class name. In my case, I want to include both the ~index.css~ file that my entire website defines (you can find that [[https://matthewkosarek.xyz/index.css][here]]) so that there are some standard styles across the site. These standard styles include the font that should be used, the spacing around the ~body~ tag, the link styles, and other generic goodies. On top of that, we will want a custom stylesheet specifically for "post" files. In my case, I have defined the following in ~posts/post.css~: - -#+BEGIN_SRC css -pre { - background-color: #FEFEFE; - border: 1px solid #D5D5D5; - border-radius: 2px; - padding: 1rem; -} - -code { - font-family: "Consolas" sans-serif; - color: #D0372D; -} - -.underline { - text-decoration: underline; -} - -/* Taken from: https://emacs.stackexchange.com/questions/7629/the-syntax-highlight-and-indentation-of-source-code-block-in-exported-html-file */ -pre span.org-builtin {color:#006FE0;font-weight:bold;} -pre span.org-string {color:#008000;} -pre span.org-keyword {color:#0000FF;} -pre span.org-variable-name {color:#BA36A5;} -pre span.org-function-name {color:#006699;} -pre span.org-type {color:#6434A3;} -pre span.org-preprocessor {color:#808080;font-weight:bold;} -pre span.org-constant {color:#D0372D;} -pre span.org-comment-delimiter {color:#8D8D84;} -pre span.org-comment {color:#8D8D84;font-style:italic} -1pre span.org-outshine-level-1 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-2 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-3 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-4 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-5 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-6 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-7 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-8 {color:#8D8D84;font-style:italic} -pre span.org-outshine-level-9 {color:#8D8D84;font-style:italic} -pre span.org-rainbow-delimiters-depth-1 {color:#707183;} -pre span.org-rainbow-delimiters-depth-2 {color:#7388d6;} -pre span.org-rainbow-delimiters-depth-3 {color:#909183;} -pre span.org-rainbow-delimiters-depth-4 {color:#709870;} -pre span.org-rainbow-delimiters-depth-5 {color:#907373;} -pre span.org-rainbow-delimiters-depth-6 {color:#6276ba;} -pre span.org-rainbow-delimiters-depth-7 {color:#858580;} -pre span.org-rainbow-delimiters-depth-8 {color:#80a880;} -pre span.org-rainbow-delimiters-depth-9 {color:#887070;} -pre span.org-sh-quoted-exec {color:#FF1493;} -pre span.org-css-selector {color:#0000FF;} -pre span.org-css-property {color:#00AA00;} -#+END_SRC - -That CSS file should get you going with some decent code highlighting and styles, but I don't pretend that it is complete. - -Finally, we need to tell org mode to include our two CSS files when the page is loaded. To do this, we can use the HTML ~<link>~ entity. We will set the ~org-html-head~ variable to insert two link entities at the top of the page. - -#+BEGIN_SRC emacs-lisp - (require 'ox-publish) - - (require 'package) - (setq package-user-dir (expand-file-name "./.packages")) - (setq package-archives '(("melpa" . "https://melpa.org/packages/") - ("elpa" . "https://elpa.gnu.org/packages/"))) - - ;; Initialize the package system - (package-initialize) - (unless package-archive-contents - (package-refresh-contents)) - - ;; Install dependencies - (package-install 'htmlize) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html - :with-toc nil - :with-author nil - :section-numbers nil - :time-stamp-file nil))) - - (setq org-html-htmlize-output-type 'css) - (setq org-html-htmlize-font-prefix "org-") - - (setq org-html-validation-link nil - org-html-head-include-scripts nil - org-html-head-include-default-style nil - org-html-head " - <link rel=\"stylesheet\" href=\"/index.css\" /> - <link rel=\"stylesheet\" href=\"/posts/post.css\" /> - <link rel=\"shortcut icon\" href=\"/favicon/favicon.ico\" type=\"image/x-icon\"> - ") ;; Include index.css and posts/post.css when the page loads - ;; Note that I also set the "favicon" too, but this is optional - - (org-publish-all t) - - (message "Build Complete") - -#+END_SRC - -If we run the publish again, we can see that we have full styling on our code snippets and everything else on our website. - -* Images -:PROPERTIES: -:ID: 1ca21e46-c212-41ad-b9a7-34fa9909014a -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -Our first two criteria have been met! Next on the list is solving images. As an example, let's use this [[/_posts/assets/squirrel.jpg][squirrel image]] that I found online with an open source license. The ideal situation would be: - -1. The squirrel image lives closely to this org document (~hello.org~) -2. We can reference the image file in our org file, and see it in our HTML page as an image - -Unfortunately, it doesn't look to be that easy. Let's examine the ideal situation. Let's say we provide a relative path to an image in our org file like so: -#+BEGIN_SRC txt - [[./assets/squirrel.jpg]] -#+END_SRC - -If we click this link in our org buffer, the relative path will work right away. However, when we export the org file to HTML, the following tag will be generated: - -#+BEGIN_SRC html -<img src="./assets/squirrel.jpg" alt="squirrel.jpg"> - #+END_SRC - -The browser cannot resolve this absolute path, which results in the alternate "squirrel.jpg" text being shown next to a broken image. - -So what's the fix here? Well, we have two options, but I am going to go with the easiest. For more information, check out [[https://stackoverflow.com/questions/14684263/how-to-org-mode-image-absolute-path-of-export-html][this stackoverflow post]]. The route I chose puts the onus of making a proper link on the writer of the blog post. The fix simply modifies the ~src~ attribute of the generated HTML to have an absolute path to the image, while also allowing the org file to retain a link to the image that it understands. - -#+BEGIN_SRC TXT -#+ATTR_HTML: :src /_posts/assets/squirrel.jpg -[[./assets/squirrel.jpg]] -#+END_SRC - -That's all there is to it! There are simpler ways as well, but that should do it: -#+CAPTION: A Cute Squirrel -#+ATTR_HTML: :src /_posts/assets/squirrel.jpg :width 300 -[[./assets/squirrel.jpg]] - - -* Creation Date -:PROPERTIES: -:ID: f061a150-b8bc-41cf-8c50-77338ac47c80 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -Let's add the creation date below the title next. To start, we will modify the publish command to remove the title (~:with-title nil~) and, in its place, show a preamble bit of HTML that contains a formatted ~div~ with the title and the "last modified" span.z - -#+BEGIN_SRC emacs-lisp -(setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html - :with-toc nil - :with-author nil - :section-numbers nil - :time-stamp-file nil - :with-title nil - :html-preamble-format '(("en" " - <div class=\"org-article-title\"> - <h1>%t</h1> - <span>Last modified: %d</span> - </div> -")) -#+END_SRC - -The ~html-preamble-format~ variable takes an association list (alist) as a parameter. Each entry in the alist should have the export language (in this case english or "en") as the first value and the format for that language as the second value. - -The "%t" in the HTML string will be filled in with the title of your post. This is set by the ~#+TITLE: MY_TITLE~ attribute of your org file. In this case, that is "Hello, Org". The "%d" is used to insert the date of your post. This is set by the ~#+DATE: <ORG_TIMESTAMP>~ in your org file. You can insert a timestamp into the buffer by writing ~M-x org-time-stamp~, or by typing one out yourself. (Hint: You can do an ~M-x describe-variable~ and type "org-html-preamble-format" to get more info on what "%X" values you can include in this format). - -On top of this, we can modify our ~posts/post.css~ file to make the title a bit more pleasing to the eyes. - -#+BEGIN_SRC css -.org-article-title > h1 { - margin-bottom: 0; -} - -.org-article-title > span { - color: #707183; -} -#+END_SRC - -If you want to see the full list of which values can be included in the ~html-preamble-format~, you can do an ~M-x describe-variable~ on the ~org-html-preamble-format~ variable. - -Note that the downside of this is that the created date will change whenever you next save the buffer. This isn't a huge deal for my purposes, but you may need to come up with a more sophisticated mechanism for the exact "creation" date for your use case. - -* Generating the Directory -:PROPERTIES: -:ID: e2226b35-d9ed-4758-8471-71a5c82331f1 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -For every org file in my ~_posts~ folder, I would like to create a link to the generated HTML file at the ~/posts.html~ page of my website. You can think of this as the "directory" of all posts. My criteria is: -1. Posts should appear in order from newest to oldest -2. Posts should be searchable by tags (covered in the next section) -3. Posts should be searchable by title - -The "out-of-the-box" mechanism for accomplishing this is the *sitemap*. You can think of a sitemap as a directory of sorts. While sitemaps can grow to be infinitely deep (i.e. sitemaps referencing other sitemaps), we will keep our sitemap as a flat list containing the available posts in chronological order. - -To start, we can enable source maps for our publish like so: - -#+BEGIN_SRC emacs-lisp - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - :recursive t - :base-directory "./_posts" - :publishing-directory "./posts" - :publishing-function: 'org-html-publish-to-html - :with-toc nil - :with-author nil - :section-numbers nil - :time-stamp-file nil - :with-title nil - :html-preamble-format '(("en" " - <div class=\"org-article-title\"> - <h1>%t</h1> - <span>Last modified: %d</span> - </div> - ")) - :auto-sitemap t ; Enable the sitemap - :sitemap-sort-files "chronologically" ; Sort files chronologically - :sitemap-format-entry (lambda (entry style project) (get-org-file-title entry style project)) - ))) -#+END_SRC - -If we generate again, we will find two files generated: -1. ~_posts/sitemap.org~: The org file containing the generated sitemap -2. ~posts/sitemap.html~: The HTML file that was generated based on the previous ~sitemap.org~ file - -If you open the ~sitemap.html~ file in your browser, you will see a bulleted listed containing a link to "Hello, Org". Clicking on it will bring you to this blog post. - -From here, you may customize it however you like. The following are my customizations. - -** Sitemap Title -:PROPERTIES: -:ID: 47f964f9-15d7-4370-9483-a76dafd79f4c -:END: -I changed the title to "Matthew's Blog Posts". - -#+BEGIN_SRC emacs-lisp - (defun get-org-file-title(entry style project) - (setq timestamp (org-timestamp-format (car (org-publish-find-property entry :date project)) "%B %d, %Y")) - (format "%s created on %s" (org-publish-sitemap-default-entry entry style project) timestamp) - ) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - ... - :sitemap-title "Matthew's Blog Posts" ; Change the title - ))) - - #+END_SRC - - -** Format blog entries in the list -:PROPERTIES: -:ID: a1c2f9b9-085a-4540-a9f1-7f7388334191 -:END: -I like to include the creation date on the blog posts. To do this, we can use ~org-publish-find-property~ to find the date property of the org file. Afterward, we can format a string that includes our formatted timestamp and the ~org-publish-sitemap-default-entry~, which is just a link with the title of the post. -#+BEGIN_SRC emacs-lisp - (defun get-org-file-title(entry style project) - (setq timestamp (org-timestamp-format (car (org-publish-find-property entry :date project)) "%B %d, %Y")) - (format "%s created on %s" (org-publish-sitemap-default-entry entry style project) timestamp) - ) - - (setq org-publish-project-alist - (list - (list "matthewkosarek.xyz" - ... - :sitemap-format-entry (lambda (entry style project) (get-org-file-title entry style project)) - ))) -#+END_SRC - -* Tags & Filtering -:PROPERTIES: -:ID: bb278140-4b5c-4025-a267-693820251199 -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -I use [[https://www.orgroam.com/][Org-roam]] for all of my note-taking and, in the next blog post, I plan to demonstrate how I will hook up my Org-roam note-taking workflow to my blogging. In the meantime, just know that we can add tags to the top of our org files like this: - -#+BEGIN_SRC org -#+filetags: :tag_1:tag_2: -#+END_SRC - -This would tag this org buffer with "tag_1" and "tag_2". - -Our criteria for the tag filtering system is: -- A post can contain many tags -- Users can filter my one or many tags (i.e. "home" /and/ "technology" but /not/ "lifestyle") -- By default, users see all posts with all tags -- Searching happens on the client -- We don't have to manually maintain a list of valid tags. The list of valid tags should be dynamically loaded from the blog posts themselves. - -Let's modify the ~get-org-file-title~ function that we wrote in the previous section to parse and include these tags: - -#+BEGIN_SRC emacs-lisp -(defun get-org-file-title(entry style project) - (setq timestamp (org-timestamp-format (car (org-publish-find-property entry :date project)) "%B %d, %Y")) - (setq tag-list (org-publish-find-property entry :filetags project)) - (setq tag-list-str (mapconcat 'identity tag-list ",")) - (setq result (format "%s created on %s\n#+begin_sitemap_tag\n%s\n#+end_sitemap_tag\n" (org-publish-sitemap-default-entry entry style project) timestamp tag-list-str)) - ) -#+END_SRC - -We extract the "filetags" from the org file, concatenate them into a comma-delimited string, and format them into the title string. We place the contents inside of a ~begin_sitemap_tag~ and ~end_sitemap_tag~ block. In HTML, this creates an enclosing ~div~ element with the class name "sitemap_tag". That means we can target the ~.sitemap_tag~ element in CSS. In our case, we want to hide all of that data entirely so we can put the following in ~posts/post.css~: - -#+BEGIN_SRC css -.sitemap_tag { - display: none; -} -#+END_SRC - -If you rerun the ~publish.sh~ script now, you will see the tags only if you inspect the element, but they will not appear visually. - -Next thing is to write a small snippet of JavaScript that our page will load. This snippet is responsible for: -1. Creating a list of the used tags -2. Creating enable/disable buttons for each tag -3. Hiding/showing a post depending on the state of its tags - -We create a new file called ~posts/post.js~ and put the following inside: - -#+BEGIN_SRC js -function main() { - - // Gather the used set oof tags - const tagSet = new Set(); - const postList = []; - const tagContainers = document.getElementsByClassName('sitemap_tag'); - for (let index = 0; index < tagContainers.length; index++) { - const container = tagContainers[index]; - const pContainer = container.children[0]; - if (!pContainer) { - continue; - } - - const tagList = pContainer.textContent.split(','); - tagList.forEach(tag => tagSet.add(tag)); - postList.push({ - container: container.parentElement, - tagList: tagList, - enabled: tagList.length - }); - } - - // Create the tag container - const contentContainer = document.getElementById('content'); - const tagContainer = document.createElement('div'); - tagContainer.id = 'tag-filter-container'; - contentContainer.before(tagContainer); - - let numEnabled = tagSet.size; - for (const tag of tagSet) { - const tagElement = document.createElement('div'); - tagElement.className = "tag-filter-item"; - const tagElementLabel = document.createElement('span'); - tagElementLabel.innerHTML = tag; - const tagElementButton = document.createElement('button'); - tagElement.append(tagElementLabel, tagElementButton); - tagContainer.append(tagElement); - - - // Whenever a tag is clicked, execute the filtering behavior - tagElementButton.onclick = function() { - // Handle enable/disable - tagElement.remove(); - - if (tagElement.classList.contains('disabled')) { - tagElement.classList.remove('disabled'); - if (numEnabled === 0) { - tagContainer.prepend(tagElement); - } - else { - tagContainer.children[numEnabled - 1].after(tagElement); - } - numEnabled++; - - // Filter - postList.forEach(post => { - if (post.tagList.includes(tag)) { - post.enabled++; - - if (post.enabled) { - post.container.style.display = 'list-item'; - } - } - }); - } - else { - tagElement.classList.add('disabled'); - tagContainer.append(tagElement); - numEnabled--; - - // Filter - postList.forEach(post => { - if (post.tagList.includes(tag)) { - post.enabled--; - if (!post.enabled) { - post.container.style.display = 'none'; - } - } - }); - } - }; - } -} - -window.onload = main; -#+END_SRC - -Next, we modify the ~org-html-head~ to include ~<script src='/posts/post.js'></script>~ so that this script is loaded on every blog post page. - -Finally, let's append the following to ~posts/posts.css~ so that our tag list is pretty: - -#+BEGIN_SRC css -#tag-filter-container { - display: flex; - flex-direction: row; - column-gap: 8px; - margin-top: 1rem; -} - -.tag-filter-item { - display: flex; - flex-direction: row; - align-items: center; - padding: 0.25rem 0.5rem; - border: 1px solid black; - border-radius: 3px; - justify-content: center; - column-gap: 1rem; - background-color: #fffed8; -} - -.tag-filter-item button { - background: none; - border: none; - outline: none; - margin: 0; - padding: 0; - color: red; - font-size: 1.5rem; -} - -.tag-filter-item button:before { - content: '\00d7'; -} - -.tag-filter-item.disabled button:before { - content: '+'; -} - -.tag-filter-item.disabled { - background-color: #f2f2f2; - color: gray; - border-color: gray; -} - -.tag-filter-item.disabled button { - color: green; -} - -.tag-filter-item button:hover { - cursor: pointer; - opacity: 0.8; -} -#+END_SRC - -* Conclusion -:PROPERTIES: -:ID: 0612cef6-bdb4-4f43-8ba7-86e2c22120fd -:PUBDATE: 2025-05-06 Tue 14:32 -:END: -There are many more customizations that I plan to do on this system in the future, but I plan to leave this for now so that I can actually get to some blogging. I will proofread and fix my mistakes as time goes on, but this should be a good jumping off point for anyone interested in using org for their own blogging system. |
