Committing extra source files
This commit is contained in:
5418
.packages/archives/elpa/archive-contents
Normal file
5418
.packages/archives/elpa/archive-contents
Normal file
File diff suppressed because it is too large
Load Diff
1
.packages/archives/elpa/archive-contents.signed
Normal file
1
.packages/archives/elpa/archive-contents.signed
Normal 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
|
||||
5963
.packages/archives/melpa/archive-contents
Normal file
5963
.packages/archives/melpa/archive-contents
Normal file
File diff suppressed because it is too large
Load Diff
84
.packages/htmlize-20250724.1703/htmlize-autoloads.el
Normal file
84
.packages/htmlize-20250724.1703/htmlize-autoloads.el
Normal 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
|
||||
10
.packages/htmlize-20250724.1703/htmlize-pkg.el
Normal file
10
.packages/htmlize-20250724.1703/htmlize-pkg.el
Normal 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")))
|
||||
1817
.packages/htmlize-20250724.1703/htmlize.el
Normal file
1817
.packages/htmlize-20250724.1703/htmlize.el
Normal file
File diff suppressed because it is too large
Load Diff
BIN
.packages/htmlize-20250724.1703/htmlize.elc
Normal file
BIN
.packages/htmlize-20250724.1703/htmlize.elc
Normal file
Binary file not shown.
89
about.org
Normal file
89
about.org
Normal 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]]
|
||||
BIN
assets/org-roam-ui-graph.png
Normal file
BIN
assets/org-roam-ui-graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 296 KiB |
8
blogs/blogs-intro.org
Normal file
8
blogs/blogs-intro.org
Normal 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
6
blogs/blogs-list.org
Normal 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
20
blogs/zettelkasten.org
Normal 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
234
build-site.el
Normal 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 © 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
16
contact.org
Normal 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!
|
||||
89
index.org
89
index.org
@@ -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
15
posts.org
Normal 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
27
posts/posts-intro.org
Normal 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 can’t explain it simply you don’t 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, it’s 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
5
posts/posts-list.org
Normal 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
21
script.js
Normal 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
294
setup.org
Normal 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 © 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
0
setup.org~
Normal file
125
style.css
Normal file
125
style.css
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user