diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..b6bbccc --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,5 @@ +;;; Directory Local Variables -*- no-byte-compile: t -*- +;;; For more information see (info "(emacs) Directory Variables") + +((nil . ((compile-command . "FORCE=true emacs -Q --batch -l ./publish.el --funcall dw/publish"))) + (org-mode . ((org-link-file-path-type . relative)))) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 736d427..722845f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,11 +12,23 @@ jobs: - name: Check out uses: actions/checkout@v1 + - name: Check out the style repo + run: git clone --depth 1 https://git.sr.ht/~daviwil/daviwil.com daviwil.com + - name: Install Emacs - run: sudo apt install emacs-nox --yes + uses: purcell/setup-emacs@master + with: + version: 27.2 - name: Build the site - run: ./build.sh + run: | + cp -R daviwil.com/public . + emacs --batch -l ./publish.el --funcall dw/publish + + - name: Link Checker + uses: lycheeverse/lychee-action@v1.0.8 + with: + args: --verbose --no-progress ./public/**/*.html - name: Publish generated content to GitHub Pages uses: JamesIves/github-pages-deploy-action@4.1.4 diff --git a/.gitignore b/.gitignore index 182368a..388ecd1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,11 @@ -/.packages/ +; Don't commit downloaded Emacs packages +.packages/ + +; Ignore the org-publish cache +.org-cache/ + +; Ignore shared content with daviwil.com +public/ + +; Ignore Gemini output +gemini/ diff --git a/assets/css/code.css b/assets/css/code.css new file mode 100644 index 0000000..ef5313c --- /dev/null +++ b/assets/css/code.css @@ -0,0 +1,1051 @@ +body { + color: #eeffff; + background-color: #292d3e; +} +.org-ansi-color-black { + /* ansi-color-black */ + color: #292d3e; + background-color: #292d3e; +} +.org-ansi-color-blue { + /* ansi-color-blue */ + color: #82aaff; + background-color: #82aaff; +} +.org-ansi-color-bright-black { + /* ansi-color-bright-black */ + color: #1c1f2b; + background-color: #232635; +} +.org-ansi-color-bright-blue { + /* ansi-color-bright-blue */ + color: #94b6ff; + background-color: #94b6ff; +} +.org-ansi-color-bright-cyan { + /* ansi-color-bright-cyan */ + color: #9ae2ff; + background-color: #9ae2ff; +} +.org-ansi-color-bright-green { + /* ansi-color-bright-green */ + color: #cbeb9e; + background-color: #cbeb9e; +} +.org-ansi-color-bright-magenta { + /* ansi-color-bright-magenta */ + color: #cfa2ed; + background-color: #cfa2ed; +} +.org-ansi-color-bright-red { + /* ansi-color-bright-red */ + color: #ff6c85; + background-color: #ff6c85; +} +.org-ansi-color-bright-white { + /* ansi-color-bright-white */ + color: #a6accd; + background-color: #a6accd; +} +.org-ansi-color-bright-yellow { + /* ansi-color-bright-yellow */ + color: #ffd281; + background-color: #ffd281; +} +.org-ansi-color-cyan { + /* ansi-color-cyan */ + color: #89ddff; + background-color: #89ddff; +} +.org-ansi-color-faint { +} +.org-ansi-color-fast-blink { +} +.org-ansi-color-green { + /* ansi-color-green */ + color: #c3e88d; + background-color: #c3e88d; +} +.org-ansi-color-inverse { +} +.org-ansi-color-magenta { + /* ansi-color-magenta */ + color: #c792ea; + background-color: #c792ea; +} +.org-ansi-color-red { + /* ansi-color-red */ + color: #ff5370; + background-color: #ff5370; +} +.org-ansi-color-slow-blink { +} +.org-ansi-color-white { + /* ansi-color-white */ + color: #eeffff; + background-color: #eeffff; +} +.org-ansi-color-yellow { + /* ansi-color-yellow */ + color: #ffcb6b; + background-color: #ffcb6b; +} +.org-bold { + /* bold */ + font-weight: bold; +} +.org-border { +} +.org-buffer-menu-buffer { + /* buffer-menu-buffer */ + font-weight: bold; +} +.org-builtin { + /* font-lock-builtin-face */ + color: #82aaff; +} +.org-button { + /* button */ + color: #c792ea; + font-weight: bold; + text-decoration: underline; +} +.org-calendar-month-header { + /* calendar-month-header */ + color: #82aaff; +} +.org-calendar-today { + /* calendar-today */ + text-decoration: underline; +} +.org-calendar-weekday-header { + /* calendar-weekday-header */ + color: #f78c6c; +} +.org-calendar-weekend-header { + /* calendar-weekend-header */ + color: #676e95; +} +.org-child-frame-border { +} +.org-comint-highlight-input { + /* comint-highlight-input */ + font-weight: bold; +} +.org-comint-highlight-prompt { + /* comint-highlight-prompt */ + color: #c792ea; +} +.org-comment { + /* font-lock-comment-face */ + color: #676e95; +} +.org-comment-delimiter { + /* font-lock-comment-delimiter-face */ + color: #676e95; +} +.org-completions-common-part { + /* completions-common-part */ + color: #add8e6; +} +.org-completions-first-difference { + /* completions-first-difference */ + font-weight: bold; +} +.org-completions-group-separator { + /* completions-group-separator */ + color: #676e95; + text-decoration: line-through; +} +.org-completions-group-title { + /* completions-group-title */ + color: #676e95; + font-style: italic; +} +.org-constant { + /* font-lock-constant-face */ + color: #f78c6c; +} +.org-cursor { + /* cursor */ + background-color: #c792ea; +} +.org-diary { + /* diary */ + color: #ffff00; +} +.org-doc { + /* font-lock-doc-face */ + color: #8d92af; +} +.org-doc-markup { + /* font-lock-doc-markup-face */ + color: #f78c6c; +} +.org-eldoc-highlight-function-argument { + /* eldoc-highlight-function-argument */ + font-weight: bold; +} +.org-elisp-shorthand-font-lock { + /* elisp-shorthand-font-lock-face */ + color: #00ffff; +} +.org-error { + /* error */ + color: #ff5370; +} +.org-escape-glyph { + /* escape-glyph */ + color: #89ddff; +} +.org-file-name-shadow { + /* file-name-shadow */ + color: #676e95; +} +.org-fill-column-indicator { + /* fill-column-indicator */ + color: #676e95; +} +.org-fixed-pitch { +} +.org-fixed-pitch-serif { +} +.org-fringe { + /* fringe */ + color: #4e5579; + background-color: #292d3e; +} +.org-function-name { + /* font-lock-function-name-face */ + color: #82aaff; +} +.org-glyphless-char { + /* glyphless-char */ + font-size: 60%; +} +.org-header-line { + /* header-line */ + color: #a6accd; + background-color: #232635; +} +.org-header-line-highlight { + /* header-line-highlight */ + color: #1c1f2b; + background-color: #c792ea; +} +.org-help-argument-name { + /* help-argument-name */ + font-style: italic; +} +.org-help-for-help-header { + /* help-for-help-header */ + font-size: 126%; +} +.org-help-key-binding { + /* help-key-binding */ + color: #add8e6; + background-color: #303030; +} +.org-highlight { + /* highlight */ + color: #1c1f2b; + background-color: #c792ea; +} +.org-holiday { + /* holiday */ + background-color: #8b4513; +} +.org-homoglyph { + /* homoglyph */ + color: #00ffff; +} +.org-internal-border { +} +.org-isearch { + /* isearch */ + color: #eeffff; + background-color: #4e5579; + font-weight: bold; +} +.org-isearch-fail { + /* isearch-fail */ + color: #1c1f2b; + background-color: #ff5370; + font-weight: bold; +} +.org-isearch-group-1 { + /* isearch-group-1 */ + color: #8b2323; + background-color: #ff82ab; +} +.org-isearch-group-2 { + /* isearch-group-2 */ + color: #8b2323; + background-color: #cd6889; +} +.org-italic { + /* italic */ + font-style: italic; +} +.org-keyword { + /* font-lock-keyword-face */ + color: #89ddff; +} +.org-lazy-highlight { + /* lazy-highlight */ + color: #eeffff; + background-color: #4e5579; + font-weight: bold; +} +.org-line-number { + /* line-number */ + color: #676e95; + background-color: #292d3e; +} +.org-line-number-major-tick { + /* line-number-major-tick */ + background-color: #bfbfbf; + font-weight: bold; +} +.org-line-number-minor-tick { + /* line-number-minor-tick */ + background-color: #8c8c8c; + font-weight: bold; +} +.org-link { + /* link */ + color: #c792ea; + font-weight: bold; + text-decoration: underline; +} +.org-link-visited { + /* link-visited */ + color: #ee82ee; + font-weight: bold; + text-decoration: underline; +} +.org-match { + /* match */ + color: #c3e88d; + background-color: #1c1f2b; + font-weight: bold; +} +.org-menu { +} +.org-minibuffer-prompt { + /* minibuffer-prompt */ + color: #c792ea; +} +.org-mode-line { + /* mode-line */ + color: #a6accd; + background-color: #232635; +} +.org-mode-line-buffer-id { + /* mode-line-buffer-id */ + font-weight: bold; +} +.org-mode-line-emphasis { + /* mode-line-emphasis */ + color: #c792ea; +} +.org-mode-line-highlight { + /* mode-line-highlight */ + color: #1c1f2b; + background-color: #c792ea; +} +.org-mode-line-inactive { + /* mode-line-inactive */ + color: #676e95; + background-color: #282c3d; +} +.org-mouse { +} +.org-mouse-drag-and-drop-region { + /* mouse-drag-and-drop-region */ + background-color: #3c435e; +} +.org-negation-char { + /* font-lock-negation-char-face */ + color: #89ddff; + font-weight: bold; +} +.org-next-error { + /* next-error */ + background-color: #3c435e; +} +.org-next-error-message { + /* next-error-message */ + color: #1c1f2b; + background-color: #c792ea; +} +.org-nobreak-hyphen { + /* nobreak-hyphen */ + color: #00ffff; +} +.org-nobreak-space { + /* nobreak-space */ + color: #89ddff; + text-decoration: underline; +} +.org-org-agenda-calendar-event { + /* org-agenda-calendar-event */ + color: #eeffff; + background-color: #292d3e; +} +.org-org-agenda-calendar-sexp { + /* org-agenda-calendar-sexp */ + color: #eeffff; + background-color: #292d3e; +} +.org-org-agenda-clocking { + /* org-agenda-clocking */ + background-color: #3a4664; +} +.org-org-agenda-column-dateline { + /* org-agenda-column-dateline */ + background-color: #4d4d4d; +} +.org-org-agenda-current-time { + /* org-agenda-current-time */ + color: #676e95; +} +.org-org-agenda-date { + /* org-agenda-date */ + color: #bb80b3; +} +.org-org-agenda-date-today { + /* org-agenda-date-today */ + color: #d6b2d1; +} +.org-org-agenda-date-weekend { + /* org-agenda-date-weekend */ + color: #704c6b; +} +.org-org-agenda-date-weekend-today { + /* org-agenda-date-weekend-today */ + color: #d6b2d1; +} +.org-org-agenda-diary { + /* org-agenda-diary */ + color: #eeffff; + background-color: #292d3e; +} +.org-org-agenda-dimmed-todo { + /* org-agenda-dimmed-todo-face */ + color: #676e95; +} +.org-org-agenda-done { + /* org-agenda-done */ + color: #676e95; + font-weight: bold; +} +.org-org-agenda-filter-category { + /* org-agenda-filter-category */ + color: #a6accd; + background-color: #232635; +} +.org-org-agenda-filter-effort { + /* org-agenda-filter-effort */ + color: #a6accd; + background-color: #232635; +} +.org-org-agenda-filter-regexp { + /* org-agenda-filter-regexp */ + color: #a6accd; + background-color: #232635; +} +.org-org-agenda-filter-tags { + /* org-agenda-filter-tags */ + color: #a6accd; + background-color: #232635; +} +.org-org-agenda-restriction-lock { + /* org-agenda-restriction-lock */ + background-color: #1c1c1c; +} +.org-org-agenda-structure { + /* org-agenda-structure */ + color: #eeffff; +} +.org-org-agenda-structure-secondary { + /* org-agenda-structure-secondary */ + color: #eeffff; +} +.org-org-archived { + /* org-archived */ + color: #8d92af; +} +.org-org-block { + /* org-block */ + background-color: #232635; +} +.org-org-block-begin-line { + /* org-block-begin-line */ + color: #676e95; + background-color: #232635; +} +.org-org-block-end-line { + /* org-block-end-line */ + color: #676e95; + background-color: #232635; +} +.org-org-checkbox { + /* org-checkbox */ + color: #c3e88d; + font-weight: bold; +} +.org-org-checkbox-statistics-done { + /* org-checkbox-statistics-done */ + color: #676e95; + font-weight: bold; +} +.org-org-checkbox-statistics-todo { + /* org-checkbox-statistics-todo */ + color: #c3e88d; + font-weight: bold; +} +.org-org-cite { + /* org-cite */ + color: #55c0b8; +} +.org-org-cite-key { + /* org-cite-key */ + color: #88d4d0; + text-decoration: underline; +} +.org-org-clock-overlay { + /* org-clock-overlay */ + color: #ffffff; + background-color: #4a708b; +} +.org-org-code { + /* org-code */ + color: #f78c6c; + background-color: #232635; +} +.org-org-column { + /* org-column */ + background-color: #4d4d4d; +} +.org-org-column-title { + /* org-column-title */ + background-color: #4d4d4d; + font-weight: bold; + text-decoration: underline; +} +.org-org-date { + /* org-date */ + color: #ffcb6b; +} +.org-org-date-selected { + /* org-date-selected */ + color: #ffc0cb; +} +.org-org-default { +} +.org-org-dispatcher-highlight { + /* org-dispatcher-highlight */ + color: #ffd700; + background-color: #333333; + font-weight: bold; +} +.org-org-document-info { + /* org-document-info */ + color: #82aaff; +} +.org-org-document-info-keyword { + /* org-document-info-keyword */ + color: #676e95; +} +.org-org-document-title { + /* org-document-title */ + color: #82aaff; + font-weight: bold; +} +.org-org-done { + /* org-done */ + color: #676e95; + font-weight: bold; +} +.org-org-drawer { + /* org-drawer */ + color: #676e95; +} +.org-org-ellipsis { + /* org-ellipsis */ + color: #676e95; +} +.org-org-footnote { + /* org-footnote */ + color: #f78c6c; +} +.org-org-formula { + /* org-formula */ + color: #89ddff; +} +.org-org-headline-done { + /* org-headline-done */ + color: #676e95; +} +.org-org-headline-todo { + /* org-headline-todo */ + color: #eea9b8; +} +.org-org-hide { + /* org-hide */ + color: #292d3e; +} +.org-org-imminent-deadline { + /* org-imminent-deadline */ + color: #ffcb6b; +} +.org-org-inline-src-block { + /* org-inline-src-block */ + background-color: #232635; +} +.org-org-latex-and-related { + /* org-latex-and-related */ + color: #a6accd; + font-weight: bold; +} +.org-org-level-1 { + /* org-level-1 */ + color: #82aaff; + font-weight: bold; +} +.org-org-level-2 { + /* org-level-2 */ + color: #c792ea; + font-weight: bold; +} +.org-org-level-3 { + /* org-level-3 */ + color: #bb80b3; + font-weight: bold; +} +.org-org-level-4 { + /* org-level-4 */ + color: #a1bfff; + font-weight: bold; +} +.org-org-level-5 { + /* org-level-5 */ + color: #d5adef; + font-weight: bold; +} +.org-org-level-6 { + /* org-level-6 */ + color: #c0d4ff; + font-weight: bold; +} +.org-org-level-7 { + /* org-level-7 */ + color: #e3c8f4; + font-weight: bold; +} +.org-org-level-8 { + /* org-level-8 */ + color: #e6eeff; + font-weight: bold; +} +.org-org-link { + /* org-link */ + color: #c792ea; + font-weight: bold; + text-decoration: underline; +} +.org-org-list-dt { + /* org-list-dt */ + color: #c792ea; +} +.org-org-macro { + /* org-macro */ + color: #a6accd; + font-weight: bold; +} +.org-org-meta-line { + /* org-meta-line */ + color: #8d92af; +} +.org-org-mode-line-clock { + /* org-mode-line-clock */ + color: #a6accd; + background-color: #232635; +} +.org-org-mode-line-clock-overrun { + /* org-mode-line-clock-overrun */ + color: #a6accd; + background-color: #ff0000; +} +.org-org-priority { + /* org-priority */ + color: #ff5370; +} +.org-org-property-value { + /* org-property-value */ + color: #8d92af; +} +.org-org-quote { + /* org-quote */ + background-color: #232635; + font-style: italic; +} +.org-org-scheduled { + /* org-scheduled */ + color: #eeffff; +} +.org-org-scheduled-previously { + /* org-scheduled-previously */ + color: #a6accd; +} +.org-org-scheduled-today { + /* org-scheduled-today */ + color: #717cb4; +} +.org-org-sexp-date { + /* org-sexp-date */ + color: #eeffff; +} +.org-org-special-keyword { + /* org-special-keyword */ + color: #8d92af; +} +.org-org-table { + /* org-table */ + color: #bb80b3; +} +.org-org-table-header { + /* org-table-header */ + color: #000000; + background-color: #d3d3d3; +} +.org-org-tag { + /* org-tag */ + color: #8d92af; +} +.org-org-tag-group { + /* org-tag-group */ + color: #8d92af; +} +.org-org-target { + /* org-target */ + text-decoration: underline; +} +.org-org-time-grid { + /* org-time-grid */ + color: #676e95; +} +.org-org-todo { + /* org-todo */ + color: #c3e88d; + font-weight: bold; +} +.org-org-upcoming-deadline { + /* org-upcoming-deadline */ + color: #c6d5d8; +} +.org-org-upcoming-distant-deadline { + /* org-upcoming-distant-deadline */ + color: #8b969e; +} +.org-org-verbatim { + /* org-verbatim */ + color: #c3e88d; +} +.org-org-verse { + /* org-verse */ + background-color: #232635; +} +.org-org-warning { + /* org-warning */ + color: #ffcb6b; +} +.org-outline-1 { + /* outline-1 */ + color: #82aaff; + font-weight: bold; +} +.org-outline-2 { + /* outline-2 */ + color: #c792ea; + font-weight: bold; +} +.org-outline-3 { + /* outline-3 */ + color: #bb80b3; + font-weight: bold; +} +.org-outline-4 { + /* outline-4 */ + color: #a1bfff; + font-weight: bold; +} +.org-outline-5 { + /* outline-5 */ + color: #d5adef; + font-weight: bold; +} +.org-outline-6 { + /* outline-6 */ + color: #c0d4ff; + font-weight: bold; +} +.org-outline-7 { + /* outline-7 */ + color: #e3c8f4; + font-weight: bold; +} +.org-outline-8 { + /* outline-8 */ + color: #e6eeff; + font-weight: bold; +} +.org-preprocessor { + /* font-lock-preprocessor-face */ + color: #89ddff; + font-weight: bold; +} +.org-query-replace { + /* query-replace */ + color: #eeffff; + background-color: #4e5579; + font-weight: bold; +} +.org-read-multiple-choice { + /* read-multiple-choice-face */ + font-weight: bold; + text-decoration: underline; +} +.org-regexp-grouping-backslash { + /* font-lock-regexp-grouping-backslash */ + color: #89ddff; + font-weight: bold; +} +.org-regexp-grouping-construct { + /* font-lock-regexp-grouping-construct */ + color: #89ddff; + font-weight: bold; +} +.org-region { + /* region */ + background-color: #3c435e; +} +.org-scroll-bar { + /* scroll-bar */ + color: #ffffff; +} +.org-secondary-selection { + /* secondary-selection */ + background-color: #676e95; +} +.org-separator-line { + /* separator-line */ + background-color: #505050; + font-size: 10%; +} +.org-shadow { + /* shadow */ + color: #676e95; +} +.org-show-paren-match { + /* show-paren-match */ + color: #ff5370; + background-color: #1c1f2b; +} +.org-show-paren-match-expression { + /* show-paren-match-expression */ + color: #ff5370; + background-color: #1c1f2b; +} +.org-show-paren-mismatch { + /* show-paren-mismatch */ + color: #1c1f2b; + background-color: #ff5370; +} +.org-string { + /* font-lock-string-face */ + color: #c3e88d; +} +.org-success { + /* success */ + color: #c3e88d; +} +.org-tab-bar { + /* tab-bar */ + color: #242837; + background-color: #242837; +} +.org-tab-bar-tab { + /* tab-bar-tab */ + color: #eeffff; + background-color: #292d3e; +} +.org-tab-bar-tab-group-current { + /* tab-bar-tab-group-current */ + color: #eeffff; + background-color: #292d3e; + font-weight: bold; +} +.org-tab-bar-tab-inactive { + /* tab-bar-tab-inactive */ + color: #bfc7d5; + background-color: #242837; +} +.org-tab-line { + /* tab-line */ + color: #242837; + background-color: #242837; +} +.org-tab-line-close-highlight { + /* tab-line-close-highlight */ + color: #c792ea; +} +.org-tab-line-highlight { + /* tab-line-highlight */ + color: #eeffff; + background-color: #292d3e; +} +.org-tab-line-tab { + /* tab-line-tab */ + color: #eeffff; + background-color: #292d3e; +} +.org-tab-line-tab-current { + /* tab-line-tab-current */ + color: #eeffff; + background-color: #292d3e; +} +.org-tab-line-tab-group { + /* tab-line-tab-group */ + color: #242837; + background-color: #242837; +} +.org-tab-line-tab-inactive { + /* tab-line-tab-inactive */ + color: #bfc7d5; + background-color: #242837; +} +.org-tab-line-tab-inactive-alternate { + /* tab-line-tab-inactive-alternate */ + color: #bfc7d5; + background-color: #242837; +} +.org-tab-line-tab-modified { + /* tab-line-tab-modified */ + color: #8d92af; +} +.org-tab-line-tab-special { + /* tab-line-tab-special */ + font-style: italic; +} +.org-table-cell { + /* table-cell */ + color: #e5e5e5; + background-color: #0000ff; +} +.org-tabulated-list-fake-header { + /* tabulated-list-fake-header */ + font-weight: bold; + text-decoration: underline; + text-decoration: overline; +} +.org-tool-bar { + /* tool-bar */ + color: #000000; + background-color: #bfbfbf; +} +.org-tooltip { + /* tooltip */ + color: #eeffff; + background-color: #1c202c; +} +.org-trailing-whitespace { + /* trailing-whitespace */ + background-color: #ff5370; +} +.org-tty-menu-disabled { + /* tty-menu-disabled-face */ + color: #d3d3d3; + background-color: #0000ff; +} +.org-tty-menu-enabled { + /* tty-menu-enabled-face */ + color: #ffff00; + background-color: #0000ff; + font-weight: bold; +} +.org-tty-menu-selected { + /* tty-menu-selected-face */ + background-color: #ff0000; +} +.org-type { + /* font-lock-type-face */ + color: #c792ea; +} +.org-underline { + /* underline */ + text-decoration: underline; +} +.org-variable-name { + /* font-lock-variable-name-face */ + color: #ffcb6b; +} +.org-variable-pitch { +} +.org-vc-conflict-state { +} +.org-vc-edited-state { +} +.org-vc-locally-added-state { +} +.org-vc-locked-state { +} +.org-vc-missing-state { +} +.org-vc-needs-update-state { +} +.org-vc-removed-state { +} +.org-vc-state-base { +} +.org-vc-up-to-date-state { +} +.org-vertical-border { + /* vertical-border */ + color: #232635; + background-color: #232635; +} +.org-warning { + /* warning */ + color: #ffcb6b; +} +.org-warning-1 { + /* font-lock-warning-face */ + color: #ffcb6b; +} +.org-window-divider { + /* window-divider */ + color: #232635; + background-color: #232635; +} +.org-window-divider-first-pixel { + /* window-divider-first-pixel */ + color: #232635; + background-color: #232635; +} +.org-window-divider-last-pixel { + /* window-divider-last-pixel */ + color: #232635; + background-color: #232635; +} + +a { + color: inherit; + background-color: inherit; + font: inherit; + text-decoration: inherit; +} +a:hover { + text-decoration: underline; +} diff --git a/assets/css/site.css b/assets/css/site.css new file mode 100644 index 0000000..e6c44e9 --- /dev/null +++ b/assets/css/site.css @@ -0,0 +1,463 @@ +/* + * Globals + */ + +::root { + box-sizing: border-box; +} + +html { + font-size: 12px; +} + +@media screen and (max-width: 767px) { + html { + font-size: 12px; + } + + .logo { + max-width: 200px; + } + + .row .column:not(:last-child) { + margin-bottom: 1rem; + } + + .video { + width: 100%; + } + + .list-form { + width: 90%; + } + + .newsletter-text { + font-size: 0.65rem; + } +} + +/* sm */ +@media screen and (min-width: 768px) { + html { + font-size: 13px; + } + + .logo { + max-width: 200px; + } + + .row { + display: flex; + flex-direction: row; + padding: 0; + width: 100%; + } + + .row .column { + display: block; + flex: 1 1 auto; + max-width: 100%; + width: 100%; + } + + .row .column:not(:last-child) { + margin-right: 10px; + } + + .align-right { + text-align: right; + } + + .video { + width: 70%; + } + + .list-form { + width: 60%; + } + + .newsletter-text { + font-size: 1.2rem; + } +} + +/* md */ +@media screen and (min-width: 992px) { + html { + font-size: 15px; + } + + .logo { + max-width: 300px; + } +} + +/* lg */ +@media screen and (min-width: 2560px) { + html { + font-size: 18px; + } +} + +body { + margin: 0; + font-family: "Iosevka Aile Web", sans-serif; + font-weight: 300; + font-size: 1.3rem; + line-height: 1.5; + color: #eeffff; + background-color: #292d3e; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +b { + font-weight: 800; +} + +blockquote { + font-style: italic; +} + +.container { + margin-right: auto; + margin-left: auto; + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.nav { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Iosevka Aile Web", sans-serif; + font-weight: 600; + line-height: 1.2; + margin-top: 1.3rem; + margin-bottom: 0.5rem; + color: #eeffff; +} + +h1 { + color: #89aaeb; +} + +h2 { + color: #c3e88d; +} + +h3 { + color: #c792ea; +} + +h4 { + color: #c3e88d; +} + +a { + /* color: #c3e88d; */ + color: #82aaff; +} + +a:hover, +a:focus { + color: #82aaff; +} + +.anchor { + color: #292d3e; + float: left; + padding-right: 4px; + margin-left: -23px; +} + +.anchor:hover { + text-decoration: none; +} + +h2:hover .anchor, +h3:hover .anchor, +h4:hover .anchor { + color: inherit; +} + +kbd { + font-family: "JetBrains Mono", monospace; + font-weight: 200; +} + +pre { + font-family: "JetBrains Mono", monospace; + background-color: #232635; + padding: 1em; + overflow-x: scroll; +} + +code { + color: #c3e88d; +} + +pre, +code { + font-family: "JetBrains Mono", monospace; + font-weight: 200; + font-size: 1rem; +} + +strong { + font-weight: 700; +} + +/* + * Override Bootstrap's default container. + */ + +.container { + max-width: 60rem; +} + +/* + * Masthead for nav + */ + +.site-masthead { + margin-bottom: 0.5rem; + background-color: rgba(28, 31, 38, 0.5); + border-bottom: 0.05rem solid #c3e88d; + -webkit-box-shadow: inset 0 -0.1rem 0.25rem rgba(0, 0, 0, 0.1); + box-shadow: inset 0 -0.1rem 0.25rem rgba(0, 0, 0, 0.1); +} + +.logo { + display: block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +/* Nav links */ +.nav-link { + position: relative; + padding: 0rem; + font-size: 1.3rem; + margin: 0.5rem 1.25rem 0.5rem 0rem; + font-weight: bold; + color: #cdddeb; +} +.nav-link:hover, +.nav-link:focus { + color: #fff; + background-color: transparent; +} + +/* Active state gets a caret at the bottom */ +.nav-link.active { + color: #fff; + font-weight: bolder; +} + +.nav-icon { + float: right; +} + +.nav-icons { + width: auto; +} + +/* + * Blog name and description + */ + +.site-header { + font-family: "Iosevka Aile Web", sans-serif; + font-weight: bold; + background-image: url("/img/header_bg.png"); + background-size: cover; +} + +.site-title { + margin-bottom: 0; + font-size: 3rem; + font-weight: bold; + color: #82aaff; +} +.site-description { + font-size: 1.5rem; + color: #999; +} + +@media (max-width: 40em) { + .site-description { + margin-bottom: 1rem; + } +} + +/* + * Site pages + */ + +.site-post { + margin-bottom: 2rem; +} + +.site-post-title { + margin-bottom: 0.75rem; + font-size: 2.5rem; +} + +.site-post-meta { + margin-bottom: 1.25rem; + color: #999; +} + +.site-post-tags { + margin-top: 3rem; + margin-bottom: 1.25rem; + font-size: 1.1rem; + color: #999; +} + +/* + * Footer + */ + +.site-footer { + padding: 1.3rem 0; + margin-top: 1rem; + color: #cdddeb; + font-size: 1rem; + background-color: #232635; + border-top: 0.05rem solid #c3e88d; +} + +.site-footer p:last-child { + margin-bottom: 0; +} + +.site-footer-right { + text-align: right; +} + +.video { + position: relative; + overflow: hidden; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.center { + display: block; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.video::after { + display: block; + content: ""; + padding-top: 56.25%; +} + +.video iframe { + position: absolute; + top: 0; + left: 0; + border: 0; + width: 100%; + height: 100%; +} + +.cta { + width: 80%; + padding: 1rem; + margin-top: 1rem; + margin-bottom: 1rem; + border: 1px solid #f78c6c; + border-radius: 4px; + background-color: #232635; +} + +.stream-time { + width: 80%; + padding: 1rem; + margin-top: 1rem; + margin-bottom: 1rem; + border: 1px solid #c792ea; + border-radius: 4px; + background-color: #232635; +} + +.list-form { + font-size: 0.9rem; + padding: 1rem; + margin-bottom: 1rem; + border: 1px solid #c3e88d; + border-radius: 4px; + background-color: #232635; +} + +.list-form-title { + font-family: "Iosevka Aile Web", sans-serif; + font-weight: 600; + font-size: 1.2rem; + margin-bottom: 0.5rem; + color: #c3e88d; +} + +.list-form-label { + margin-top: 0.8rem; + font-weight: bold; +} + +.list-form input[type="text"] { + width: 100%; + padding: 10px 10px; + margin: 8px 0; + box-sizing: border-box; + border: 1px solid #c3e88d; + border-radius: 4px; + background-color: #232635; + color: #eeffff; +} + +.list-form input[type="submit"] { + width: 50%; + padding: 10px 10px; + margin: 8px 0; + box-sizing: border-box; + border: 1px solid #89aaeb; + border-radius: 4px; + background-color: #89aaeb; + color: #232635; +} + +.newsletter-text { +} + +.register-button { + width: 60%; + padding: 10px 10px; + border: 1px solid #89aaeb; + border-radius: 4px; + background-color: #89aaeb; + color: #232635; +} + +a:hover.register-button, +a:focus.register-button { + color: #232635; +} diff --git a/assets/fonts/iosevka-aile/iosevka-aile.css b/assets/fonts/iosevka-aile/iosevka-aile.css new file mode 100644 index 0000000..cd5088d --- /dev/null +++ b/assets/fonts/iosevka-aile/iosevka-aile.css @@ -0,0 +1,382 @@ +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 100; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-thin.woff2") format("woff2"), + url("ttf/iosevka-aile-thin.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 100; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-thinoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-thinoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 100; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-thinoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-thinoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 100; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-thinitalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-thinitalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 200; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extralight.woff2") + format("woff2"), + url("ttf/iosevka-aile-extralight.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 200; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extralightoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-extralightoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 200; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extralightoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-extralightoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 200; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extralightitalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-extralightitalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 300; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-light.woff2") format("woff2"), + url("ttf/iosevka-aile-light.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 300; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-lightoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-lightoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 300; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-lightoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-lightoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 300; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-lightitalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-lightitalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 400; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-regular.woff2") + format("woff2"), + url("ttf/iosevka-aile-regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 400; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-oblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-oblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 400; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-oblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-oblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 400; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-italic.woff2") + format("woff2"), + url("ttf/iosevka-aile-italic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 500; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-medium.woff2") + format("woff2"), + url("ttf/iosevka-aile-medium.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 500; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-mediumoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-mediumoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 500; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-mediumoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-mediumoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 500; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-mediumitalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-mediumitalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 600; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-semibold.woff2") + format("woff2"), + url("ttf/iosevka-aile-semibold.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 600; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-semiboldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-semiboldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 600; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-semiboldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-semiboldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 600; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-semibolditalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-semibolditalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 700; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-bold.woff2") format("woff2"), + url("ttf/iosevka-aile-bold.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 700; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-boldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-boldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 700; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-boldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-boldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 700; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-bolditalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-bolditalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 800; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extrabold.woff2") + format("woff2"), + url("ttf/iosevka-aile-extrabold.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 800; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extraboldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-extraboldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 800; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extraboldoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-extraboldoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 800; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-extrabolditalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-extrabolditalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 900; + font-stretch: normal; + font-style: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-heavy.woff2") format("woff2"), + url("ttf/iosevka-aile-heavy.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 900; + font-stretch: normal; + font-style: oblique; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-heavyoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-heavyoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web Oblique"; + font-display: swap; + font-weight: 900; + font-stretch: normal; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-heavyoblique.woff2") + format("woff2"), + url("ttf/iosevka-aile-heavyoblique.ttf") format("truetype"); +} + +@font-face { + font-family: "Iosevka Aile Web"; + font-display: swap; + font-weight: 900; + font-stretch: normal; + font-style: italic; + src: url("/fonts/iosevka-aile/woff2/iosevka-aile-heavyitalic.woff2") + format("woff2"), + url("ttf/iosevka-aile-heavyitalic.ttf") format("truetype"); +} diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-bold.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-bold.ttf new file mode 100644 index 0000000..faa3d04 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-bold.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-bolditalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-bolditalic.ttf new file mode 100644 index 0000000..e58bf1c Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-bolditalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-boldoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-boldoblique.ttf new file mode 100644 index 0000000..8b8ab27 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-boldoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabold.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabold.ttf new file mode 100644 index 0000000..8480520 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabold.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabolditalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabolditalic.ttf new file mode 100644 index 0000000..da4653e Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extrabolditalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extraboldoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extraboldoblique.ttf new file mode 100644 index 0000000..91cd30c Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extraboldoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralight.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralight.ttf new file mode 100644 index 0000000..b923a59 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralight.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightitalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightitalic.ttf new file mode 100644 index 0000000..5d04b9a Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightitalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightoblique.ttf new file mode 100644 index 0000000..00aadc4 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-extralightoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavy.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavy.ttf new file mode 100644 index 0000000..95a98f6 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavy.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyitalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyitalic.ttf new file mode 100644 index 0000000..a15ca6f Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyitalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyoblique.ttf new file mode 100644 index 0000000..eee87b9 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-heavyoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-italic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-italic.ttf new file mode 100644 index 0000000..fcc3587 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-italic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-light.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-light.ttf new file mode 100644 index 0000000..7af9e3e Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-light.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightitalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightitalic.ttf new file mode 100644 index 0000000..4827385 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightitalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightoblique.ttf new file mode 100644 index 0000000..528b725 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-lightoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-medium.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-medium.ttf new file mode 100644 index 0000000..077a150 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-medium.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumitalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumitalic.ttf new file mode 100644 index 0000000..640110d Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumitalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumoblique.ttf new file mode 100644 index 0000000..4607131 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-mediumoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-oblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-oblique.ttf new file mode 100644 index 0000000..024a67f Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-oblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-regular.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-regular.ttf new file mode 100644 index 0000000..c7063db Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-regular.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibold.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibold.ttf new file mode 100644 index 0000000..3e262a3 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibold.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibolditalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibolditalic.ttf new file mode 100644 index 0000000..d2ea895 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semibolditalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-semiboldoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semiboldoblique.ttf new file mode 100644 index 0000000..ffecba9 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-semiboldoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-thin.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thin.ttf new file mode 100644 index 0000000..e291878 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thin.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinitalic.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinitalic.ttf new file mode 100644 index 0000000..05225d0 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinitalic.ttf differ diff --git a/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinoblique.ttf b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinoblique.ttf new file mode 100644 index 0000000..9dfd123 Binary files /dev/null and b/assets/fonts/iosevka-aile/ttf/iosevka-aile-thinoblique.ttf differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-bold.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-bold.woff2 new file mode 100644 index 0000000..ad25ad8 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-bold.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-bolditalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-bolditalic.woff2 new file mode 100644 index 0000000..0fdc57c Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-bolditalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-boldoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-boldoblique.woff2 new file mode 100644 index 0000000..ab4e3ec Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-boldoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabold.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabold.woff2 new file mode 100644 index 0000000..1fadc61 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabold.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabolditalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabolditalic.woff2 new file mode 100644 index 0000000..8851ec1 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extrabolditalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extraboldoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extraboldoblique.woff2 new file mode 100644 index 0000000..eadb8fc Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extraboldoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralight.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralight.woff2 new file mode 100644 index 0000000..1b0c549 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralight.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightitalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightitalic.woff2 new file mode 100644 index 0000000..8b10961 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightitalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightoblique.woff2 new file mode 100644 index 0000000..169ba05 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-extralightoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavy.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavy.woff2 new file mode 100644 index 0000000..6ea17a0 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavy.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyitalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyitalic.woff2 new file mode 100644 index 0000000..cbb6f2c Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyitalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyoblique.woff2 new file mode 100644 index 0000000..4f07643 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-heavyoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-italic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-italic.woff2 new file mode 100644 index 0000000..da82f61 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-italic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-light.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-light.woff2 new file mode 100644 index 0000000..5575584 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-light.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightitalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightitalic.woff2 new file mode 100644 index 0000000..64713be Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightitalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightoblique.woff2 new file mode 100644 index 0000000..1a70a8e Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-lightoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-medium.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-medium.woff2 new file mode 100644 index 0000000..3de00b6 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-medium.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumitalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumitalic.woff2 new file mode 100644 index 0000000..dfb4221 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumitalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumoblique.woff2 new file mode 100644 index 0000000..3314109 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-mediumoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-oblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-oblique.woff2 new file mode 100644 index 0000000..9c6ab02 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-oblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-regular.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-regular.woff2 new file mode 100644 index 0000000..ee3a8e3 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-regular.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibold.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibold.woff2 new file mode 100644 index 0000000..82ef99f Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibold.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibolditalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibolditalic.woff2 new file mode 100644 index 0000000..9f2377f Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semibolditalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-semiboldoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semiboldoblique.woff2 new file mode 100644 index 0000000..30b7bb3 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-semiboldoblique.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-thin.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thin.woff2 new file mode 100644 index 0000000..8d1c25a Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thin.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinitalic.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinitalic.woff2 new file mode 100644 index 0000000..33106c3 Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinitalic.woff2 differ diff --git a/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinoblique.woff2 b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinoblique.woff2 new file mode 100644 index 0000000..d3ac50b Binary files /dev/null and b/assets/fonts/iosevka-aile/woff2/iosevka-aile-thinoblique.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000..07fe5d7 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2 new file mode 100644 index 0000000..57263ef Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-BoldItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBold.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBold.woff2 new file mode 100644 index 0000000..9ba04e6 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBold.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.woff2 new file mode 100644 index 0000000..25b16c9 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraBoldItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLight.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLight.woff2 new file mode 100644 index 0000000..0fcf808 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLight.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLightItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLightItalic.woff2 new file mode 100644 index 0000000..2101028 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-ExtraLightItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2 new file mode 100644 index 0000000..cf9e8ef Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Light.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000..a456787 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Light.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-LightItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000..209ce0a Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-LightItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000..b4d9438 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-MediumItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-MediumItalic.woff2 new file mode 100644 index 0000000..3ac249b Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-MediumItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000..cc9a1ae Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-Thin.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-Thin.woff2 new file mode 100644 index 0000000..70e9c48 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-Thin.woff2 differ diff --git a/assets/fonts/jetbrains-mono/JetBrainsMono-ThinItalic.woff2 b/assets/fonts/jetbrains-mono/JetBrainsMono-ThinItalic.woff2 new file mode 100644 index 0000000..dc9f741 Binary files /dev/null and b/assets/fonts/jetbrains-mono/JetBrainsMono-ThinItalic.woff2 differ diff --git a/assets/fonts/jetbrains-mono/jetbrains-mono.css b/assets/fonts/jetbrains-mono/jetbrains-mono.css new file mode 100644 index 0000000..21b614e --- /dev/null +++ b/assets/fonts/jetbrains-mono/jetbrains-mono.css @@ -0,0 +1,76 @@ +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Bold-Italic.woff2") + format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Bold-Italic.woff") format("woff"); + font-weight: 700; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Bold.woff2") format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Bold.woff") format("woff"); + font-weight: 700; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-ExtraBold-Italic.woff2") + format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-ExtraBold-Italic.woff") + format("woff"); + font-weight: 800; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-ExtraBold.woff2") + format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-ExtraBold.woff") format("woff"); + font-weight: 800; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Italic.woff2") format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Italic.woff") format("woff"); + font-weight: 400; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Medium-Italic.woff2") + format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Medium-Italic.woff") format("woff"); + font-weight: 500; + font-style: italic; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2") format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Medium.woff") format("woff"); + font-weight: 500; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "JetBrains Mono"; + src: url("/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2") format("woff2"), + url("/fonts/jetbrains-mono/JetBrainsMono-Regular.woff") format("woff"); + font-weight: 400; + font-style: normal; + font-display: swap; +} diff --git a/assets/img/codeberg.png b/assets/img/codeberg.png new file mode 100644 index 0000000..c505e7b Binary files /dev/null and b/assets/img/codeberg.png differ diff --git a/assets/img/courses/HandsOnGuileSchemeBeginners.png b/assets/img/courses/HandsOnGuileSchemeBeginners.png new file mode 100644 index 0000000..50c7743 Binary files /dev/null and b/assets/img/courses/HandsOnGuileSchemeBeginners.png differ diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000..7802741 Binary files /dev/null and b/assets/img/favicon.png differ diff --git a/assets/img/header_bg.png b/assets/img/header_bg.png new file mode 100644 index 0000000..f43d2b9 Binary files /dev/null and b/assets/img/header_bg.png differ diff --git a/assets/img/sc_logo.png b/assets/img/sc_logo.png new file mode 100644 index 0000000..3b4a480 Binary files /dev/null and b/assets/img/sc_logo.png differ diff --git a/publish.el b/publish.el new file mode 100644 index 0000000..bfb3536 --- /dev/null +++ b/publish.el @@ -0,0 +1,556 @@ +;;; publish.el --- Build systemcrafters.net + +;; Copyright (C) 2021, 2023 David Wilson + +;; Author: David Wilson +;; Maintainer: David Wilson +;; URL: https://codeberg.org/SystemCrafters/systemcrafters.net +;; Version: 0.0.1 +;; Package-Requires: ((emacs "28.2")) +;; Keywords: hypermedia, blog, feed, rss + +;; This file is not part of GNU Emacs. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Docs License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Docs License for more details. +;; +;; You should have received a copy of the GNU General Docs License +;; along with this program. If not, see . + +;;; Usage: +;; emacs -Q --batch -l ./publish.el --funcall dw/publish + +;;; Code: + +;; Initialize package sources +(require 'package) + +;; Set the package installation directory so that packages aren't stored in the +;; ~/.emacs.d/elpa path. +(setq package-user-dir (expand-file-name "./.packages")) + +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) +(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/")) + +;; Initialize the package system +(package-initialize) +(unless package-archive-contents + (package-refresh-contents)) + +;; Install use-package +(unless (package-installed-p 'use-package) + (package-install 'use-package)) +(require 'use-package) + +;; Require built-in dependencies +(require 'vc-git) +(require 'ox-publish) +(require 'subr-x) +(require 'cl-lib) + +;; Install other dependencies +(use-package esxml + :pin "melpa-stable" + :ensure t) + +(use-package htmlize + :ensure t) + +(use-package webfeeder + :ensure t) + +(defvar yt-iframe-format + (concat "
" + " " + "
")) + +(defun dw/embed-video (video-id) + (format yt-iframe-format video-id)) + +(setq user-full-name "David Wilson") +(setq user-mail-address "david@systemcrafters.net") + +(defvar dw/site-url (if (string-equal (getenv "CI") "true") + "" ;; Don't hardcode the domain + "http://localhost:8080") + "The URL for the site being generated.") + +(defun dw/embed-list-form () + `(div (@ (class "list-form center")) + (div (@ (class "list-form-title")) "Subscribe to the System Crafters Newsletter!") + (form (@ (method "POST") + (action "https://www.simplelists.com/subscribe.php")) + (input (@ (type "hidden") (name "format") (value "text"))) + (input (@ (type "hidden") (name "action") (value "subscribe"))) + (input (@ (type "hidden") (name "list") (value "news@lists.systemcrafters.net"))) + (div (@ (class "list-form-message")) + "Stay up to date with the latest System Crafters news and updates! Read the " + (a (@ (href "/newsletter/")) "Newsletter") + " page for more information.") + (div (@ (class "row")) + (div (@ (class "column")) + (div (@ (class "row center list-form-label")) "Name (optional)") + (div (@ (class "row")) (input (@ (type "text") (name "name"))))) + (div (@ (class "column")) + (div (@ (class "row center list-form-label")) "Email Address") + (div (@ (class "row")) (input (@ (type "text") (name "email")))))) + (div nil + (input (@ (type "submit") (value "Subscribe!"))))))) + +(org-link-set-parameters + "yt" + :follow + (lambda (handle) + (browse-url + (concat "https://www.youtube.com/watch?v=" + handle))) + :export + (lambda (path desc backend channel) + (when (eq backend 'html) + (dw/embed-video path)))) + +(defun dw/site-header () + (list `(header (@ (class "site-header")) + (div (@ (class "container")) + (div (@ (class "site-title")) + (img (@ (class "logo") + (src ,(concat dw/site-url "/img/sc_logo.png")) + (alt "System Crafters"))))) + (div (@ (class "site-masthead")) + (div (@ (class "container")) + (nav (@ (class "nav")) + (a (@ (class "nav-link") (href "/")) "Home") " " + (a (@ (class "nav-link") (href "/guides/")) "Guides") " " + (a (@ (class "nav-link") (href "/news/")) "News") " " + (a (@ (class "nav-link") (href "/community/")) "Community") " " + (a (@ (class "nav-link") (href "https://store.systemcrafters.net?utm_source=sc-site-nav")) "Store") " " + (a (@ (class "nav-link") (href "/how-to-help/")) "How to Help"))))))) + +(defun dw/site-footer () + (list `(footer (@ (class "site-footer")) + (div (@ (class "container")) + (div (@ (class "row")) + (div (@ (class "column")) + (p (a (@ (href ,(concat dw/site-url "/privacy-policy/"))) "Privacy Policy") + " · " + (a (@ (href ,(concat dw/site-url "/credits/"))) "Credits") + " · " + (a (@ (href ,(concat dw/site-url "/rss/"))) "RSS Feeds") + " · " + (a (@ (rel "me") (href "https://fosstodon.org/@daviwil")) "Fediverse")) + (p "© 2021-2023 System Crafters LLC")) + (div (@ (class "column align-right")) + (p (a (@ (href "https://codeberg.org/SystemCrafters/systemcrafters.net")) + (img (@ (src ,(concat dw/site-url "/img/codeberg.png")) + (style "width: 120px") + (alt "Contribute on Codeberg"))))))))))) + +(defun get-article-output-path (org-file pub-dir) + (let ((article-dir (concat pub-dir + (downcase + (file-name-as-directory + (file-name-sans-extension + (file-name-nondirectory org-file))))))) + + (if (string-match "\\/index.org\\|\\/404.org$" org-file) + pub-dir + (progn + (unless (file-directory-p article-dir) + (make-directory article-dir t)) + article-dir)))) + +(defun dw/get-commit-hash () + "Get the short hash of the latest commit in the current repository." + (string-trim-right + (with-output-to-string + (with-current-buffer standard-output + (vc-git-command t nil nil "rev-parse" "--short" "HEAD"))))) + +(cl-defun dw/generate-page (title + content + info + &key + (publish-date) + (head-extra) + (pre-content) + (exclude-header) + (exclude-footer)) + (concat + "\n" + "" + (sxml-to-xml + `(html (@ (lang "en")) + (head + (meta (@ (charset "utf-8"))) + (meta (@ (author "System Crafters - David Wilson"))) + (meta (@ (name "viewport") + (content "width=device-width, initial-scale=1, shrink-to-fit=no"))) + (link (@ (rel "icon") (type "image/png") (href "/img/favicon.png"))) + (link (@ (rel "alternative") + (type "application/rss+xml") + (title "System Crafters News") + (href ,(concat dw/site-url "/rss/news.xml")))) + (link (@ (rel "stylesheet") (href ,(concat dw/site-url "/fonts/iosevka-aile/iosevka-aile.css")))) + (link (@ (rel "stylesheet") (href ,(concat dw/site-url "/fonts/jetbrains-mono/jetbrains-mono.css")))) + (link (@ (rel "stylesheet") (href ,(concat dw/site-url "/css/code.css")))) + (link (@ (rel "stylesheet") (href ,(concat dw/site-url "/css/site.css")))) + (script (@ (defer "defer") + (data-domain "systemcrafters.net") + (src "https://plausible.io/js/plausible.js")) + ;; Empty string to cause a closing tag + "") + ,(when head-extra head-extra) + (title ,(concat title " - System Crafters"))) + (body ,@(unless exclude-header + (dw/site-header)) + (div (@ (class "container")) + (div (@ (class "site-post")) + (h1 (@ (class "site-post-title")) + ,title) + ,(when publish-date + `(p (@ (class "site-post-meta")) ,publish-date)) + ,(if-let ((video-id (plist-get info :video))) + (dw/embed-video video-id)) + ,(when pre-content pre-content) + (div (@ (id "content")) + ,content)) + ,(dw/embed-list-form)) + ,@(unless exclude-footer + (dw/site-footer))))))) + +(defun dw/org-html-template (contents info) + (dw/generate-page (org-export-data (plist-get info :title) info) + contents + info + :publish-date (org-export-data (org-export-get-date info "%B %e, %Y") info))) + +(defun dw/org-html-link (link contents info) + "Removes file extension and changes the path into lowercase file:// links." + (when (and (string= 'file (org-element-property :type link)) + (string= "org" (file-name-extension (org-element-property :path link)))) + (org-element-put-property link :path + (downcase + (file-name-sans-extension + (org-element-property :path link))))) + + (let ((exported-link (org-export-custom-protocol-maybe link contents 'html info))) + (cond + (exported-link exported-link) + ((equal contents nil) + (format "%s" + (org-element-property :raw-link link) + (org-element-property :raw-link link))) + ((string-prefix-p "/" (org-element-property :raw-link link)) + (format "%s" + (org-element-property :raw-link link) + contents)) + (t (org-export-with-backend 'html link contents info))))) + +(defun dw/make-heading-anchor-name (headline-text) + (thread-last headline-text + (downcase) + (replace-regexp-in-string " " "-") + (replace-regexp-in-string "[^[:alnum:]_-]" ""))) + +(defun dw/org-html-headline (headline contents info) + (let* ((text (org-export-data (org-element-property :title headline) info)) + (level (org-export-get-relative-level headline info)) + (level (min 7 (when level (1+ level)))) + (anchor-name (dw/make-heading-anchor-name text)) + (attributes (org-element-property :ATTR_HTML headline)) + (container (org-element-property :HTML_CONTAINER headline)) + (container-class (and container (org-element-property :HTML_CONTAINER_CLASS headline)))) + (when attributes + (setq attributes + (format " %s" (org-html--make-attribute-string + (org-export-read-attribute 'attr_html `(nil + (attr_html ,(split-string attributes)))))))) + (concat + (when (and container (not (string= "" container))) + (format "<%s%s>" container (if container-class (format " class=\"%s\"" container-class) ""))) + (if (not (org-export-low-level-p headline info)) + (format "%s%s" + level + (or attributes "") + anchor-name + anchor-name + text + level + (or contents "")) + (concat + (when (org-export-first-sibling-p headline info) "
    ") + (format "
  • %s%s
  • " text (or contents "")) + (when (org-export-last-sibling-p headline info) "
"))) + (when (and container (not (string= "" container))) + (format "" (cl-subseq container 0 (cl-search " " container))))))) + +(defun dw/org-html-src-block (src-block _contents info) + (let* ((lang (org-element-property :language src-block)) + (code (org-html-format-code src-block info))) + (format "
%s
" (string-trim code)))) + +(defun dw/org-html-special-block (special-block contents info) + "Transcode a SPECIAL-BLOCK element from Org to HTML. +CONTENTS holds the contents of the block. INFO is a plist +holding contextual information." + (let* ((block-type (org-element-property :type special-block)) + (attributes (org-export-read-attribute :attr_html special-block))) + (format "
\n%s\n
" + block-type + (or contents + (if (string= block-type "cta") + "If you find this guide helpful, please consider supporting System Crafters via the links on the How to Help page!" + ""))))) + +(org-export-define-derived-backend 'site-html 'html + :translate-alist + '((template . dw/org-html-template) + (link . dw/org-html-link) + (src-block . dw/org-html-src-block) + (special-block . dw/org-html-special-block) + (headline . dw/org-html-headline)) + :options-alist + '((:video "VIDEO" nil nil))) + +(defun org-html-publish-to-html (plist filename pub-dir) + "Publish an org file to HTML, using the FILENAME as the output directory." + (let ((article-path (get-article-output-path filename pub-dir))) + (cl-letf (((symbol-function 'org-export-output-file-name) + (lambda (extension &optional subtreep pub-dir) + ;; The 404 page is a special case, it must be named "404.html" + (concat article-path + (if (string= (file-name-nondirectory filename) "404.org") "404" "index") + extension)))) + (org-publish-org-to 'site-html + filename + (concat "." (or (plist-get plist :html-extension) + "html")) + plist + article-path)))) + +(defun dw/publish-newsletter-page (plist filename pub-dir) + "Publish a newsletter .txt file to a simple HTML page." + (let* ((issue-name (file-name-sans-extension + (file-name-nondirectory filename))) + (output-file (expand-file-name + (concat issue-name ".html") + pub-dir)) + (contents (with-temp-buffer + (insert-file-contents filename) + (buffer-string)))) + (with-temp-file output-file + (insert + (dw/generate-page + (concat "Issue " + (nth 2 (split-string issue-name "-"))) + (format "
%s
" + (replace-regexp-in-string + "\\(http\\|https\\)://[^ \t\n\r<>\"']*[^ \t\n\r<>\".,;!?']" + (lambda (match) + (format "%s" match match)) + contents)) + '() + :exclude-header t + :exclude-footer t))))) + +(setq org-publish-use-timestamps-flag t + org-publish-timestamp-directory "./.org-cache/" + org-export-with-section-numbers nil + org-export-use-babel nil + org-export-with-smart-quotes t + org-export-with-sub-superscripts nil + org-export-with-tags 'not-in-toc + org-html-htmlize-output-type 'css + org-html-prefer-user-labels t + org-html-link-home dw/site-url + org-html-link-use-abs-url t + org-html-link-org-files-as-html t + org-html-html5-fancy t + org-html-self-link-headlines t + org-export-with-toc nil + make-backup-files nil) + +(defun dw/format-live-stream-entry (entry style project) + "Format posts with author and published data in the index page." + (cond ((not (directory-name-p entry)) + (format "[[file:%s][%s]] - %s" + entry + (org-publish-find-title entry project) + (format-time-string "%B %d, %Y" + (org-publish-find-date entry project)))) + ((eq style 'tree) (file-name-nondirectory (directory-file-name entry))) + (t entry))) + +(defun dw/format-news-entry (entry style project) + "Format posts with author and published data in the index page." + (cond ((not (directory-name-p entry)) + (format "[[file:%s][%s]] - %s · %s" + entry + (org-publish-find-title entry project) + (car (org-publish-find-property entry :author project)) + (format-time-string "%B %d, %Y" + (org-publish-find-date entry project)))) + ((eq style 'tree) (file-name-nondirectory (directory-file-name entry))) + (t entry))) + +(defun dw/news-sitemap (title files) + (format "#+title: %s\n\n%s" + title + (mapconcat (lambda (file) + (format "- %s\n" file)) + (cadr files) + "\n"))) + +(defun dw/rss-extract-title (html-file) + "Extract the title from an HTML file." + (with-temp-buffer + (insert-file-contents html-file) + (let ((dom (libxml-parse-html-region (point-min) (point-max)))) + (dom-text (car (dom-by-class dom "site-post-title")))))) + +(defun dw/rss-extract-date (html-file) + "Extract the post date from an HTML file." + (with-temp-buffer + (insert-file-contents html-file) + (let* ((dom (libxml-parse-html-region (point-min) (point-max))) + (date-string (dom-text (car (dom-by-class dom "site-post-meta")))) + (parsed-date (parse-time-string date-string)) + (day (nth 3 parsed-date)) + (month (nth 4 parsed-date)) + (year (nth 5 parsed-date))) + ;; NOTE: Hardcoding this at 8am for now + (encode-time 0 0 8 day month year)))) + +;(defun dw/rss-extract-summary (html-file) +; ) + +(setq webfeeder-title-function #'dw/rss-extract-title + webfeeder-date-function #'dw/rss-extract-date) + +(setq org-publish-project-alist + (list '("systemcrafters:main" + :base-directory "./content" + :base-extension "org" + :publishing-directory "./public" + :publishing-function org-html-publish-to-html + :with-title nil + :with-timestamps nil) + '("systemcrafters:faq" + :base-directory "./content/faq" + :base-extension "org" + :publishing-directory "./public/faq" + :publishing-function org-html-publish-to-html + :with-title nil + :with-timestamps nil) + '("systemcrafters:courses" + :base-directory "./content/courses" + :base-extension "org" + :recursive t + :publishing-directory "./public/courses" + :publishing-function org-html-publish-to-html + :with-title nil + :with-timestamps nil) + '("systemcrafters:assets" + :base-directory "./assets" + :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|woff2\\|ttf" + :publishing-directory "./public" + :recursive t + :publishing-function org-publish-attachment) + '("systemcrafters:live-streams" + :base-directory "./content/live-streams" + :base-extension "org" + :publishing-directory "./public/live-streams" + :publishing-function org-html-publish-to-html + :auto-sitemap t + :sitemap-filename "../live-streams.org" + :sitemap-title "Live Streams" + :sitemap-format-entry dw/format-live-stream-entry + :sitemap-style list + :sitemap-sort-files anti-chronologically + :with-title nil + :with-timestamps nil) + '("systemcrafters:news" + :base-directory "./content/news" + :base-extension "org" + :publishing-directory "./public/news" + :publishing-function org-html-publish-to-html + :auto-sitemap t + :sitemap-filename "../news.org" + :sitemap-title "System Crafters News" + :sitemap-format-entry dw/format-news-entry + :sitemap-style list + ;; :sitemap-function dw/news-sitemap + :sitemap-sort-files anti-chronologically + :with-title nil + :with-timestamps nil) + '("systemcrafters:newsletter" + :base-directory "./content/newsletter" + :base-extension "txt" + :publishing-directory "./public/newsletter" + :publishing-function dw/publish-newsletter-page) + '("systemcrafters:videos" + :base-directory "./content/videos" + :base-extension "org" + :recursive t + :publishing-directory "./public" + :publishing-function org-html-publish-to-html + :with-title nil + :with-timestamps nil))) + +;; TODO: Generate a _redirects file instead once Codeberg Pages releases a new version +(defun dw/generate-redirects (redirects) + (dolist (redirect redirects) + (let ((output-path (concat "./public/" (car redirect) "/index.html")) + (redirect-url (concat dw/site-url "/" (cdr redirect) "/"))) + (make-directory (file-name-directory output-path) t) + (with-temp-file output-path + (insert + (dw/generate-page "Redirecting..." + (concat "You are being redirected to " + "" redirect-url "") + '() + :head-extra + (concat ""))))))) + +(defun dw/publish () + "Publish the entire site." + (interactive) + + (make-directory "public/rss" t) + (make-directory "public/newsletter" t) + + (org-publish-all (string-equal (or (getenv "FORCE") + (getenv "CI")) + "true")) + + (webfeeder-build "rss/news.xml" + "./public" + dw/site-url + (let ((default-directory (expand-file-name "./public/"))) + (remove "news/index.html" + (directory-files-recursively "news" + ".*\\.html$"))) + :builder 'webfeeder-make-rss + :title "System Crafters News" + :description "News and Insights from System Crafters!" + :author "David Wilson") + + (dw/generate-redirects '(("support-the-channel" . "how-to-help") + ("videos" . "guides"))) + + ;; Copy the domains file to ensure the custom domain resolves + (copy-file ".domains" "public/.domains" t) + + ;; Copy the .well-known folder for Matrix + (unless (file-exists-p "public/.well-known") + (copy-directory ".well-known" "public/" t))) + +(provide 'publish) +;;; publish.el ends here