Committing extra source files

This commit is contained in:
2025-08-08 12:26:01 +01:00
parent 3443e98d1f
commit 0309c458ba
22 changed files with 14241 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2025-08-06T22:05:04+0100 using EDDSA

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
;;; htmlize-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
;; Generated by the `loaddefs-generate' function.
;; This file is part of GNU Emacs.
;;; Code:
(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
;;; Generated autoloads from htmlize.el
(autoload 'htmlize-buffer "htmlize" "\
Convert BUFFER to HTML, preserving colors and decorations.
The generated HTML is available in a new buffer, which is returned.
When invoked interactively (or if optional INTERACTIVE is non-nil),
the new buffer is selected in the current window. The title of the
generated document will be set to the buffer's file name or, if that
is not available, to the buffer's name.
Note that htmlize doesn't fontify your buffers, it only uses the
decorations that are already present. If you don't set up font-lock or
something else to fontify your buffers, the resulting HTML will be
plain. Likewise, if you don't like the choice of colors, fix the mode
that created them, or simply alter the faces it uses.
(fn &optional BUFFER INTERACTIVE)" t)
(autoload 'htmlize-region "htmlize" "\
Convert the region to HTML, preserving colors and decorations.
See `htmlize-buffer' for details.
(fn BEG END &optional INTERACTIVE)" t)
(autoload 'htmlize-file "htmlize" "\
Load FILE, fontify it, convert it to HTML, and save the result.
Contents of FILE are inserted into a temporary buffer, whose major mode
is set with `normal-mode' as appropriate for the file type. The buffer
is subsequently fontified with `font-lock' and converted to HTML. Note
that, unlike `htmlize-buffer', this function explicitly turns on
font-lock. If a form of highlighting other than font-lock is desired,
please use `htmlize-buffer' directly on buffers so highlighted.
Buffers currently visiting FILE are unaffected by this function. The
function does not change current buffer or move the point.
If TARGET is specified and names a directory, the resulting file will be
saved there instead of to FILE's directory. If TARGET is specified and
does not name a directory, it will be used as output file name.
(fn FILE &optional TARGET)" t)
(autoload 'htmlize-many-files "htmlize" "\
Convert FILES to HTML and save the corresponding HTML versions.
FILES should be a list of file names to convert. This function calls
`htmlize-file' on each file; see that function for details. When
invoked interactively, you are prompted for a list of files to convert,
terminated with RET.
If TARGET-DIRECTORY is specified, the HTML files will be saved to that
directory. Normally, each HTML file is saved to the directory of the
corresponding source file.
(fn FILES &optional TARGET-DIRECTORY)" t)
(autoload 'htmlize-many-files-dired "htmlize" "\
HTMLize dired-marked files.
(fn ARG &optional TARGET-DIRECTORY)" t)
(register-definition-prefixes "htmlize" '("htmlize-"))
;;; End of scraped data
(provide 'htmlize-autoloads)
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; no-native-compile: t
;; coding: utf-8-emacs-unix
;; End:
;;; htmlize-autoloads.el ends here

View File

@@ -0,0 +1,10 @@
;; -*- no-byte-compile: t; lexical-binding: nil -*-
(define-package "htmlize" "20250724.1703"
"Convert buffer text and decorations to HTML."
'((emacs "26.1"))
:url "https://github.com/emacsorphanage/htmlize"
:commit "c9a8196a59973fabb3763b28069af9a4822a5260"
:revdesc "c9a8196a5997"
:keywords '("hypermedia" "extensions")
:authors '(("Hrvoje Niksic" . "hniksic@gmail.com"))
:maintainers '(("Hrvoje Niksic" . "hniksic@gmail.com")))

File diff suppressed because it is too large Load Diff

Binary file not shown.

89
about.org Normal file
View File

@@ -0,0 +1,89 @@
#+TITLE: About Me
* About Me 👋
I'm building a personal site using *Emacs*, *Org-mode*, and *Cloudflare Pages*.
**This page is linked** from the [[file:index.org][homepage]]!
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Interests
- Linux
- Open source
- Org mode
- Static sites
* Back to [[file:index.org][Home]]

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

8
blogs/blogs-intro.org Normal file
View File

@@ -0,0 +1,8 @@
#+TITLE: Blogs Introduction
#+OPTIONS: toc:nil num:nil
#+DATE: <2025-08-08 Fri>
#+FILETAGS: :introduction:
* Introduction
In this section you will find posts that are not as /structured/ as the ones found in [[../posts/posts-list.org][here]]. Mainly these will deal with findings, research, assorted writings and random bits and blobs.

6
blogs/blogs-list.org Normal file
View File

@@ -0,0 +1,6 @@
#+TITLE: Blogs List
#+OPTIONS: toc:nil num:nil
* Posts:
- [[file:blogs-intro.org][Blogs Introduction]] @@html:<span class="post-date">2025-08-08</span>@@ @@html:<span class="post-tag">introduction</span>@@
- [[file:zettelkasten.org][Zettelkasten Method]] @@html:<span class="post-date">2025-08-05</span>@@ @@html:<span class="post-tag">education</span>@@

20
blogs/zettelkasten.org Normal file
View File

@@ -0,0 +1,20 @@
#+TITLE: Zettelkasten Method
#+DATE: <2025-08-05 Tue>
#+OPTIONS: toc:nil num:nil
#+FILETAGS: :education:
* The Zettelkasten Method
This Zettelkasten method is growing in popularity for taking notes. Ever felt as though there's too much pieces of information but you don't know how to deal with it? This method solves exactly that problem and more. Think of it as forming a /second brain/, where you can jot down ideas and information whilst simultaneously being able to connect them together.
The [[https://zettelkasten.de/introduction/][official website]] describes in detail exactly what the Zettelkasten method is, providing use cases and benefits to this method. The part I wanted to highlighted in this is the following paragraph, where the author depicts how this concept would be explained to someone unfamiliar with it:
#+BEGIN_QUOTE
A Zettelkasten is a personal tool for thinking and writing. It has hypertextual features to make a web of thoughts possible. The difference to other systems is that you create a web of thoughts instead of notes of arbitrary size and form, and emphasize connection, not a collection.
#+END_QUOTE
This web of thoughts is exactly what makes it useful, it takes on the seemingly cluttered /mess of information/ and is able to link the nodes together to create something meaningful and useful.
There are many personal knowledge management systems' (PKMS) out there that allow you to practice this method; the most common ones being [[https://obsidian.md/][Obsidian]] and [[https://www.orgroam.com/][Org Roam]]. After using Org Roam with Emacs for about a year or so, I realised how useful this method really is. A random idea can be jotted down and later connected to a bigger project or note system. The following picture below is a screenshot of a graph generated UI for all the nodes created in my Org Roam folder:
[[../assets/org-roam-ui-graph.png]]

234
build-site.el Normal file
View File

@@ -0,0 +1,234 @@
;; Commented out things:
;; (defvar z-head
;; "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
;; <link rel=\"stylesheet\" href=\"/style.css\" />")
;; (setq org-html-validation-link nil
;; org-html-head-include-scripts nil
;; org-html-head-include-default-style nil
;; org-html-head z-head)
;; (type-of (car '(rose violet daisy buttercup)))
;; (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))
;; (let ((list '(("post1.org") ("post2.org"))))
;; (mapconcat (lambda (entry)
;; (format "- [[file:%s]]" (car entry)))
;; list
;; "\n"))
;;BEGIN:
;; Set the package installation directory so that packages aren't stored in the
;; ~/.emacs.d/elpa path.
(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)
;; Load the publishing system
(require 'ox-publish)
(setq org-html-htmlize-output-type 'css)
(defvar z-preamble
"<nav>
<a href=\"/\">Home | </a>
<a href=\"/posts/posts-list.html\">Posts | </a>
<a href=\"/blogs/blogs-list.html\">Blogs | </a>
<a href=\"/contact.html\">Contact</a>
</nav>
<div id=\"updated\">Updated: %C</div>"
)
(defvar z-postamble
"<footer>
<div class=\"copyright-container\">
<div class=\"copyright\">
Copyright &copy; 2022-2025 Zaine Qayyum. All rights reserved unless otherwise noted.</div></div>
<div class=\"generated\">
Created with %c on <a href=\"https://www.archlinux.org/\">Arch</a> <a href=\"https://www.gnu.org\">GNU</a>/<a href=\"https://www.kernel.org/\">Linux</a>
</div>
</footer>")
(defun z/posts-sitemap (title list)
"sitemap that lists post links as bullet points with dates and tags."
(concat
"#+TITLE: " title "\n"
"#+OPTIONS: toc:nil num:nil \n\n"
"* Posts:\n"
(mapconcat
(lambda (entry)
(let* ((link (car entry))
;; extract relative file name from the link
(filename (if (string-match "\\[\\[file:\\([^]]+\\)\\]" link)
(match-string 1 link)
link))
(full-path (expand-file-name filename "~/master-folder/org_files/org_web/posts/"))
(date-str "no date")
(tags-str ""))
;; Get publish date
(let ((date (org-publish-find-date full-path org-publish-project-alist)))
(when date
(setq date-str (format-time-string "%Y-%m-%d" date))))
;; Get FILETAGS from file buffer
(when (file-exists-p full-path)
(with-temp-buffer
(insert-file-contents full-path)
(org-mode)
(let* ((tags (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))))
(when tags
(setq tags-str (mapconcat (lambda (tag)
(format "@@html:<span class=\"post-tag\">%s</span>@@" tag))
(split-string tags ":" t) ;; <- Splits by ":" and removes empty strings
" "))))))
;; Final line output
(format "- %s @@html:<span class=\"post-date\">%s</span>@@ %s" link date-str tags-str)))
(cdr list)
"\n")))
(defun z/blogs-sitemap (title list)
"sitemap that lists blog links as bullet points with dates and tags."
(concat
"#+TITLE: " title "\n"
"#+OPTIONS: toc:nil num:nil \n\n"
"* Posts:\n"
(mapconcat
(lambda (entry)
(let* ((link (car entry))
;; extract relative file name from the link
(filename (if (string-match "\\[\\[file:\\([^]]+\\)\\]" link)
(match-string 1 link)
link))
(full-path (expand-file-name filename "~/master-folder/org_files/org_web/blogs/"))
(date-str "no date")
(tags-str ""))
;; Get publish date
(let ((date (org-publish-find-date full-path org-publish-project-alist)))
(when date
(setq date-str (format-time-string "%Y-%m-%d" date))))
;; Get FILETAGS from file buffer
(when (file-exists-p full-path)
(with-temp-buffer
(insert-file-contents full-path)
(org-mode)
(let* ((tags (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))))
(when tags
(setq tags-str (mapconcat (lambda (tag)
(format "@@html:<span class=\"post-tag\">%s</span>@@" tag))
(split-string tags ":" t) ;; <- Splits by ":" and removes empty strings
" "))))))
;; Final line output
(format "- %s @@html:<span class=\"post-date\">%s</span>@@ %s" link date-str tags-str)))
(cdr list)
"\n")))
;; Define the publishing project
(setq org-publish-project-alist
`(("org-notes"
:recursive t
:base-directory "~/master-folder/org_files/org_web/"
:publishing-function org-html-publish-to-html
:publishing-directory "~/master-folder/org_files/org_web/output"
:with-author nil
:with-creator t
:with-toc t
:base-extension "org"
:section-numbers nil
:time-stamp-file nil
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"style.css\" />
<script src=\"script.js\" defer></script>
"
)
("org-posts"
:base-directory "~/master-folder/org_files/org_web/posts"
:base-extension "org"
:publishing-directory "~/master-folder/org_files/org_web/output/posts/"
:recursive t
:base-extension "org"
:publishing-function org-html-publish-to-html
:with-author nil
:with-creator nil
:html-validation-link nil
:with-toc t
:section-numbers t
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:auto-sitemap t
:sitemap-filename "posts-list.org"
:sitemap-title "Posts List"
:sitemap-style list
:sitemap-function z/posts-sitemap
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"../style.css\" />
<script src=\"../script.js\" defer></script>
"
)
("org-blogs"
:base-directory "~/master-folder/org_files/org_web/blogs"
:base-extension "org"
:publishing-directory "~/master-folder/org_files/org_web/output/blogs/"
:recursive t
:base-extension "org"
:publishing-function org-html-publish-to-html
:with-author nil
:with-creator nil
:html-validation-link nil
:with-toc t
:section-numbers t
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:auto-sitemap t
:sitemap-filename "blogs-list.org"
:sitemap-title "Blogs List"
:sitemap-style list
:sitemap-function z/blogs-sitemap
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"../style.css\" />
<script src=\"../script.js\" defer></script>
"
)
("org-assets"
:base-directory "~/master-folder/org_files/org_web/assets/"
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|svg\\|pdf\\|woff\\|woff2\\|ttf"
:publishing-directory "~/master-folder/org_files/org_web/output/assets/"
:recursive t
:publishing-function org-publish-attachment)
("org-static"
:base-directory "~/master-folder/org_files/org_web/"
:base-extension "css\\|js"
:publishing-directory "~/master-folder/org_files/org_web/output"
:recursive t
:publishing-function org-publish-attachment)
("website"
:components ("org-notes" "org-assets" "org-posts" "org-blogs" "org-static"))))
(delete-directory "~/master-folder/org_files/org_web/output/" t)
(message "Directory deleted")
;; Generate the site output
(org-publish-all t)
(message "Build complete!")

16
contact.org Normal file
View File

@@ -0,0 +1,16 @@
#+TITLE: Contact
#+OPTIONS: toc:nil num:nil
* Contact Using the Following:
> LinkedIn: *[[https://www.linkedin.com/in/zaine-ul-abideen-qayyum-801a53247/][LinkedIn]]*
> GitHub: *[[https://github.com/zainezq][Github]]*
> Email:
- *zaineulabideen (at) outlook (dot) com*
- [[mailto:zaineulabideen@outlook.com][zaineulabideen@outlook.com]]
Thanks for visiting!

View File

@@ -1 +1,88 @@
* Testing #+TITLE: Zaine Qayyum
#+OPTIONS: toc:nil num:nil
* Welcome! 🌱
This is a website built using Emacs Org-mode and published using ~org-publish~.
Feel free to explore:
- [[file:about.org][About Page]]
- [[file:posts/posts-list.org][Posts Page]]
- [[file:blogs/blogs-list.org][Blogs Page]]
- [[file:setup.org][Setup Page]]
* How to publish web pages using ~org-publish~
This website is heavily inspired by some people who have decided to use ~org-publish~ as a way to convert ~org~ files into ~html~. I came across a few that took the plunge and decided to migrate from platforms like Wordpress and instead opted for a more transparent, text-based workflow.
There is a [[https://en.wikipedia.org/wiki/Unix_philosophy][Unix philosophy]] that emphasises building simple and compact code that can be easily maintainable, and following this approach (do one thing well) aligns with this philosophy.
So how does one go about publishing web pages through Emacs's ~org-publish~? The answer is quite simple. You probably will need to have some familiarity with ~elisp~ although it's not a must.
The first thing we will want to do is edit our ~init.el~ file, which is the *initialization* file. In this file we want to add the following:
#+begin_src emacs-lisp
(setq org-publish-project-alist
'(("org-notes"
:base-directory "~/web"
:base-extension "org"
:publishing-directory "~/web"
:recursive t
:publishing-function org-html-publish-to-html
:with-author nil
:with-creator nil
:html-validation-link nil
:with-toc t
:section-numbers t
:html-head "<link rel=\"stylesheet\" href=\"style.css\" />"
)
("org-static"
:base-directory "~/web"
:base-extension "css\\|js\\|png\\|jpg\\|gif"
:publishing-directory "~/web/output"
:recursive t
:publishing-function org-publish-attachment)
("website" :components ("org-notes" "org-static"))))
#+end_src
What this snippet of code is doing is it is telling ~org-publish~ what **configurations** we want to use when we end up running the publish command. Under ~~/web~ is where we want to include our files. Let us take a simple example and create an ~index.org~ file:
#+begin_src emacs-lisp
,#+TITLE: Website Name
,#+OPTIONS: toc:nil num:nil
,#+HTML_HEAD: <link rel="stylesheet" href="style.css">
,* Welcome!
This is a simple website
#+end_src
There are some metadata at the very top as we can see, these help us customise each page the way we want to. Here I disabled the Table of Contents and section numbers just for this file. We can also create a simple ~styles.css~ file in the same directory.
After doing this, we can run the command:
#+begin_src emacs-lisp
M-x org-publish RET website
#+end_src
This will generate a html file inside the ~~/web/output/~ directory, and we can serve this file using any static site generation tools; I recommend python due to it's simplicity:
#+begin_src bash
cd ~/web/output
python3 -m http.server 8000
#+end_src
And there we go! The files are now being hosted on ~http://localhost:8000/~ and we have a fully functioning workflow for converting org files into a static website.
* Contact
Feel free to reach out on GitHub: https://github.com/zainezq

15
posts.org Normal file
View File

@@ -0,0 +1,15 @@
#+TITLE: Posts
#+OPTIONS: toc:nil num:nil
#+HTML_HEAD: <script src="script.js" defer></script>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://gongzhitaao.org/orgcss/org.css"/>
#+HTML_HEAD: <link rel="stylesheet" href="style.css">
#+SELECT_TAGS: export
* Links
*** [[file:posts/posts-intro.org][Posts Introduction]] :intro:
*** [[file:posts/zettelkasten.org][Zettelkasten Method]] :education:
<2025-08-06 Wed>

27
posts/posts-intro.org Normal file
View File

@@ -0,0 +1,27 @@
#+TITLE: Posts Introduction
#+OPTIONS: toc:nil num:nil
#+DATE: <2025-08-06 Wed>
#+FILETAGS: :introduction:
* Introduction
In this section you will find posts related to both technical and non-technical topics. As Einstein said: “If you cant explain it simply you dont understand it well enough”, thus the goal with these ~posts~ is to develop the skill of being able to deliver habitual high quality explanations as well as reinforcing the topic(s) learnt.
Generally, for teachers, this is done by taking the time to develop their own capacity to explain key concepts simply. In some institutions, departmental CPD is well spent rehearsing ways to improve the ability to explain the more difficult material in a more simpler way.
When we study a topic, we get a grasp of the thing we are trying to learn, and then later on one may realise that they didn't /actually/ learn it. The context of this differs for every person, for some it may be in the field of medicine, others in the field of software development; we may find ourselves with a solution without knowing the /why/.
Explaining topics is a fantastic method of learning, an [[https://hamatti.org/posts/explaining-it-helps-you-learn-it/][article]] written by Juha-Matti Santala titled *Explaining it helps you learn it* says:
#+BEGIN_QUOTE
The act of teaching (and more accurately, the act of preparing to teach) forces us to discover the knowledge gaps, fill them and improve our communication skills to a level where we know enough to confidently, comfortably and successfully transfer that knowledge from our mind to another mind.
#+END_QUOTE
The article further quotes Henrik Jernevad in whose [[https://henko.net/blog/if-you-cant-explain-it-you-dont-understand-it/][blog post]] writes:
#+BEGIN_QUOTE
I think the magic comes when you need to put words to things. It is quite easy to have a vague picture of something in your mind without realizing how vague it actually is. Putting things in words exposes that vagueness.
#+END_QUOTE
The final line /Putting things in words exposes that vagueness/ is profound in the context of learning. In the pursuit of any academic discipline, we're often confronted with vagueness. Yet, its often through explaining a concept to someone else, using your own words, analogies, and diagrams, that one ends up /actually/ understanding it.

5
posts/posts-list.org Normal file
View File

@@ -0,0 +1,5 @@
#+TITLE: Posts List
#+OPTIONS: toc:nil num:nil
* Posts:
- [[file:posts-intro.org][Posts Introduction]] @@html:<span class="post-date">2025-08-06</span>@@ @@html:<span class="post-tag">introduction</span>@@

21
script.js Normal file
View File

@@ -0,0 +1,21 @@
// COPY BUTTON:
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("pre.src").forEach(function (block) {
const button = document.createElement("button");
button.innerText = "Copy";
button.className = "copy-btn";
// Append button inside <pre>
block.appendChild(button);
button.addEventListener("click", function () {
const text = block.innerText.replace(button.innerText, ""); // exclude button text
navigator.clipboard.writeText(text.trim()).then(() => {
button.innerText = "Copied!";
setTimeout(() => (button.innerText = "Copy"), 1500);
});
});
});
});

294
setup.org Normal file
View File

@@ -0,0 +1,294 @@
#+TITLE: Setup
#+OPTIONS: toc:nil num:nil
* Introduction
This page will highlight the ~build-script.el~ used to generate this website. This entire website is generated through org files using the command:
#+BEGIN_SRC bash
emacs -Q --script build-site.el
#+END_SRC
* The script
The script is as follows, at the start I have commented out pieces of code (somewhat relevant to the script but never really used), followed by package management. Then there's the declaration of variables and functions and finally the ~org-publish-project-alist~ which handles nearly all of the project generation instructions.
#+BEGIN_SRC emacs-lisp
;; Commented out things:
;; (defvar z-head
;; "<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
;; <link rel=\"stylesheet\" href=\"/style.css\" />")
;; (setq org-html-validation-link nil
;; org-html-head-include-scripts nil
;; org-html-head-include-default-style nil
;; org-html-head z-head)
;; (type-of (car '(rose violet daisy buttercup)))
;; (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))
;; (let ((list '(("post1.org") ("post2.org"))))
;; (mapconcat (lambda (entry)
;; (format "- [[file:%s]]" (car entry)))
;; list
;; "\n"))
;;BEGIN:
;; Set the package installation directory so that packages aren't stored in the
;; ~/.emacs.d/elpa path.
(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)
;; Load the publishing system
(require 'ox-publish)
(setq org-html-htmlize-output-type 'css)
(defvar z-preamble
"<nav>
<a href=\"/\">Home | </a>
<a href=\"/posts/posts-list.html\">Posts | </a>
<a href=\"/blogs/blogs-list.html\">Blogs | </a>
<a href=\"/contact.html\">Contact</a>
</nav>
<div id=\"updated\">Updated: %C</div>"
)
(defvar z-postamble
"<footer>
<div class=\"copyright-container\">
<div class=\"copyright\">
Copyright &copy; 2022-2025 Zaine Qayyum. All rights reserved unless otherwise noted.</div></div>
<div class=\"generated\">
Created with %c on <a href=\"https://www.archlinux.org/\">Arch</a> <a href=\"https://www.gnu.org\">GNU</a>/<a href=\"https://www.kernel.org/\">Linux</a>
</div>
</footer>")
(defun z/posts-sitemap (title list)
"sitemap that lists post links as bullet points with dates and tags."
(concat
"#+TITLE: " title "\n"
"#+OPTIONS: toc:nil num:nil \n\n"
"* Posts:\n"
(mapconcat
(lambda (entry)
(let* ((link (car entry))
;; extract relative file name from the link
(filename (if (string-match "\\[\\[file:\\([^]]+\\)\\]" link)
(match-string 1 link)
link))
(full-path (expand-file-name filename "~/master-folder/org_files/org_web/posts/"))
(date-str "no date")
(tags-str ""))
;; Get publish date
(let ((date (org-publish-find-date full-path org-publish-project-alist)))
(when date
(setq date-str (format-time-string "%Y-%m-%d" date))))
;; Get FILETAGS from file buffer
(when (file-exists-p full-path)
(with-temp-buffer
(insert-file-contents full-path)
(org-mode)
(let* ((tags (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))))
(when tags
(setq tags-str (mapconcat (lambda (tag)
(format "@@html:<span class=\"post-tag\">%s</span>@@" tag))
(split-string tags ":" t) ;; <- Splits by ":" and removes empty strings
" "))))))
;; Final line output
(format "- %s @@html:<span class=\"post-date\">%s</span>@@ %s" link date-str tags-str)))
(cdr list)
"\n")))
(defun z/blogs-sitemap (title list)
"sitemap that lists blog links as bullet points with dates and tags."
(concat
"#+TITLE: " title "\n"
"#+OPTIONS: toc:nil num:nil \n\n"
"* Posts:\n"
(mapconcat
(lambda (entry)
(let* ((link (car entry))
;; extract relative file name from the link
(filename (if (string-match "\\[\\[file:\\([^]]+\\)\\]" link)
(match-string 1 link)
link))
(full-path (expand-file-name filename "~/master-folder/org_files/org_web/blogs/"))
(date-str "no date")
(tags-str ""))
;; Get publish date
(let ((date (org-publish-find-date full-path org-publish-project-alist)))
(when date
(setq date-str (format-time-string "%Y-%m-%d" date))))
;; Get FILETAGS from file buffer
(when (file-exists-p full-path)
(with-temp-buffer
(insert-file-contents full-path)
(org-mode)
(let* ((tags (cadr (assoc "FILETAGS" (org-collect-keywords '("FILETAGS"))))))
(when tags
(setq tags-str (mapconcat (lambda (tag)
(format "@@html:<span class=\"post-tag\">%s</span>@@" tag))
(split-string tags ":" t) ;; <- Splits by ":" and removes empty strings
" "))))))
;; Final line output
(format "- %s @@html:<span class=\"post-date\">%s</span>@@ %s" link date-str tags-str)))
(cdr list)
"\n")))
;; Define the publishing project
(setq org-publish-project-alist
`(("org-notes"
:recursive t
:base-directory "~/master-folder/org_files/org_web/"
:publishing-function org-html-publish-to-html
:publishing-directory "~/master-folder/org_files/org_web/output"
:with-author nil
:with-creator t
:with-toc t
:base-extension "org"
:section-numbers nil
:time-stamp-file nil
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"style.css\" />
<script src=\"script.js\" defer></script>
"
)
("org-posts"
:base-directory "~/master-folder/org_files/org_web/posts"
:base-extension "org"
:publishing-directory "~/master-folder/org_files/org_web/output/posts/"
:recursive t
:base-extension "org"
:publishing-function org-html-publish-to-html
:with-author nil
:with-creator nil
:html-validation-link nil
:with-toc t
:section-numbers t
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:auto-sitemap t
:sitemap-filename "posts-list.org"
:sitemap-title "Posts List"
:sitemap-style list
:sitemap-function z/posts-sitemap
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"../style.css\" />
<script src=\"../script.js\" defer></script>
"
)
("org-blogs"
:base-directory "~/master-folder/org_files/org_web/blogs"
:base-extension "org"
:publishing-directory "~/master-folder/org_files/org_web/output/blogs/"
:recursive t
:base-extension "org"
:publishing-function org-html-publish-to-html
:with-author nil
:with-creator nil
:html-validation-link nil
:with-toc t
:section-numbers t
:html-preamble ,z-preamble
:html-postamble ,z-postamble
:auto-sitemap t
:sitemap-filename "blogs-list.org"
:sitemap-title "Blogs List"
:sitemap-style list
:sitemap-function z/blogs-sitemap
:html-head "
<link rel=\"stylesheet\" type=\"text/css\" href=\"https://gongzhitaao.org/orgcss/org.css\" />
<link rel=\"stylesheet\" href=\"../style.css\" />
<script src=\"../script.js\" defer></script>
"
)
("org-assets"
:base-directory "~/master-folder/org_files/org_web/assets/"
:base-extension "css\\|js\\|png\\|jpg\\|gif\\|svg\\|pdf\\|woff\\|woff2\\|ttf"
:publishing-directory "~/master-folder/org_files/org_web/output/assets/"
:recursive t
:publishing-function org-publish-attachment)
("org-static"
:base-directory "~/master-folder/org_files/org_web/"
:base-extension "css\\|js"
:publishing-directory "~/master-folder/org_files/org_web/output"
:recursive t
:publishing-function org-publish-attachment)
("website"
:components ("org-notes" "org-assets" "org-posts" "org-blogs" "org-static"))))
;; Delete the output before generating the new one
(delete-directory "~/master-folder/org_files/org_web/output/" t)
(message "Directory deleted")
;; Generate the site output
(org-publish-all t)
(message "Build complete!")
#+END_SRC
* Publish Script
As the project is hosted on Github, I have created a small script that is able to push changes to the remote repository, which Cloudflare will automatically detect and rebuild the website:
#+BEGIN_SRC bash
#!/bin/bash
# Exit immediately if any command fails
set -e
# Define paths
ORG_PROJECT_NAME="website"
ORG_OUTPUT_DIR="$HOME/master-folder/org_files/org_web/output"
# commands used prior to having the `build-script.el`
# echo "Running org-publish..."
# emacs --batch \
# --eval "(require 'org)" \
# --eval "(require 'ox-publish)" \
# --eval "(org-publish \"$ORG_PROJECT_NAME\" t)"
cd "$ORG_OUTPUT_DIR"
echo "HTML published to: $ORG_OUTPUT_DIR"
# Git commands
echo "Adding changes to Git..."
git add .
echo "Committing..."
git commit -m "Auto-publish on $(date)" || echo "Nothing to commit."
echo "Pushing to GitHub..."
git push origin main
echo "Done! Changes pushed and Cloudflare should rebuild the site."
#+END_SRC

0
setup.org~ Normal file
View File

125
style.css Normal file
View File

@@ -0,0 +1,125 @@
:root {
--bg: #ffffff;
--fg: #000000;
--link: #1a0dab;
--heading: #004c99;
--code-bg: #f0f0f0;
}
body {
background-color: var(--bg);
color: var(--fg);
transition: background-color 0.3s, color 0.3s;
}
/* Headings (override org.css if needed) */
h1, h2, h3 {
color: var(--heading);
}
/* Links */
a {
color: var(--link);
}
a:hover {
text-decoration: underline;
}
/* Copy button inside code blocks */
.copy-btn {
position: absolute;
top: 0.4em;
right: 0.4em;
background-color: var(--code-bg);
color: var(--heading);
border: 1px solid var(--heading);
border-radius: 4px;
padding: 0.2em 0.6em;
font-size: 0.8rem;
cursor: pointer;
z-index: 10;
transition: background-color 0.3s;
}
.copy-btn:hover {
background-color: var(--heading);
color: var(--code-bg);
}
/* Nav styling */
nav {
border-radius: 6px;
margin-bottom: 1rem;
font-weight: 600;
font-size: 1.1rem;
}
nav a {
color: var(--link);
text-decoration: none;
font-weight: 600;
}
nav a:hover {
text-decoration: underline;
}
/* Footer styling */
footer {
color: var(--fg);
padding: 1rem;
margin-top: 2rem;
border-radius: 6px;
text-align: center;
font-size: 0.9rem;
font-style: italic;
}
#updated {
font-size: 0.8rem;
color: var(--fg);
margin-bottom: 1rem;
font-style: italic;
}
pre.src::before {
content: none !important;
}
/* Container: <pre> */
pre.src {
padding: 1.5em 1em 1em 1em; /* top padding leaves space for button */
font-family: "Fira Mono", "Courier New", monospace;
font-size: 0.9rem;
line-height: 1.4;
overflow-x: auto;
white-space: pre-wrap; /* wrap long lines */
}
.post-date {
color: pink;
font-size: 0.9em;
margin-left: 8px;
}
.post-tag {
display: inline-block;
background-color: #f0f0f0;
color: #444;
border-radius: 5px;
padding: 2px 6px;
margin-left: 6px;
font-size: 0.8em;
float: right;
}
li::after {
content: "";
display: block;
clear: both;
}
li {
margin-bottom: 8px;
}