From: Christian Shtarkov Date: Sun, 20 Oct 2024 16:53:20 +0000 (+0100) Subject: Site skeleton X-Git-Url: https://shtarkov.net/gitweb/?a=commitdiff_plain;h=9310aee089de702ff839a4f1c68374b00d1e8441;p=shtarkov.net.git Site skeleton --- diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..67aa147 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +Except where otherwise noted, site content is licensed under the Creative Commons Attribution 4.0 International license: +https://creativecommons.org/licenses/by/4.0/ + +All else is licensed under the GNU General Public License, either version 3 of the License, or (at your option) any later version: +https://www.gnu.org/licenses/gpl-3.0.en.html#license-text diff --git a/assets/cat/cat1.jpg b/assets/cat/cat1.jpg new file mode 100644 index 0000000..502c7f8 Binary files /dev/null and b/assets/cat/cat1.jpg differ diff --git a/assets/cat/cat2.jpg b/assets/cat/cat2.jpg new file mode 100644 index 0000000..af77c25 Binary files /dev/null and b/assets/cat/cat2.jpg differ diff --git a/assets/cat/cat3.jpg b/assets/cat/cat3.jpg new file mode 100644 index 0000000..78e5395 Binary files /dev/null and b/assets/cat/cat3.jpg differ diff --git a/assets/cat/cat4.jpg b/assets/cat/cat4.jpg new file mode 100644 index 0000000..5c22c66 Binary files /dev/null and b/assets/cat/cat4.jpg differ diff --git a/assets/cat/cat5.jpg b/assets/cat/cat5.jpg new file mode 100644 index 0000000..1c8d267 Binary files /dev/null and b/assets/cat/cat5.jpg differ diff --git a/assets/emacs/transpose-regions.webm b/assets/emacs/transpose-regions.webm new file mode 100644 index 0000000..6004fd3 Binary files /dev/null and b/assets/emacs/transpose-regions.webm differ diff --git a/assets/one.css b/assets/main.css similarity index 56% rename from assets/one.css rename to assets/main.css index b99d34f..1d2264f 100644 --- a/assets/one.css +++ b/assets/main.css @@ -1,4 +1,5 @@ -@import url('https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400&family=Noto+Sans:wght@400;700&display=swap'); +@import url('https://fonts.googleapis.com/css?family=Cantarell'); +@import url('https://fonts.googleapis.com/css?family=Fira Mono'); html, body, p, ol, ul, li, dl, dt, dd, blockquote, figure, fieldset, legend, textarea, @@ -52,7 +53,7 @@ body { background: #151515; color: #dedede; font-family: "Noto Sans",sans-serif; - font-size: 106%; + font-size: 106%; line-height: 1.5; word-wrap: break-word; } @@ -95,33 +96,43 @@ a:visited { img { display: block; + width: 80%; margin-left: auto; margin-right: auto; border: 1px solid; } +img[src="/cat.png"] { + width: auto; +} + +video { + width: 100%; + border: 1px solid; +} + /* ------- '.one' classes used by 'one-ox' org backend ------- */ .one-hl { - font-family: 'Fira Mono', monospace; - font-size: 80%; - border-radius: 6px; + font-family: "Fira Mono", monospace; + font-size: 90%; } .one-hl-inline { - background: #31424a; + background: #31424a; padding: 0.2em 0.4em; margin: 0; white-space: break-spaces; } .one-hl-block { - background: #161f22; + background: #000000; color: #c5c5c5; display: block; overflow: auto; padding: 16px; line-height: 1.45; + border: 1px solid; } .one-blockquote { @@ -133,6 +144,7 @@ img { } .one-blockquote > p:last-child { + text-align: right; margin-bottom: 0; } @@ -187,17 +199,17 @@ img { background: #31424a; } -/* -------- specific to the default render functions -------- */ +/* -------- render functions -------- */ .header { color: #ffffff; + font-family: "Cantarell", sans-serif; font-size: 2em; font-weight: bold; padding: 0 16px 0 16px; background: #151515; width: 100%; height: 3.5rem; - position: fixed; top: 0; left: 0; border-bottom: 1px solid #1d272b; @@ -217,9 +229,8 @@ img { } .content { - margin: 3.5rem auto; - padding-top: 1.8rem; - max-width: 740px; + margin: 0 auto; + max-width: 852px; padding: 0 16px; } @@ -228,20 +239,8 @@ img { padding: 1.8rem 0; } -.title-empty { - padding-top: 1rem; -} - -/* -------- one-default-home -------- */ - -#home { - margin: 5rem 0 1.5rem 0; -} - -/* -------- one-default-home-list-pages -------- */ - #home-list-pages { - margin: 5rem 0 1.5rem 0; + margin: 0 0 1.5rem 0; } #pages ul { @@ -264,217 +263,28 @@ img { color: #ffffff; } -/* -------- one-default, one-default-with-toc, one-default-with-sidebar, one-default-doc -------- */ - -.nav { - border-top: 1px solid #c5c5c5; - margin-top: 3em; - padding: 2em 0; +.article-header { display: flex; - justify-content: center; - gap: 0.5em; - font-weight: bold; + justify-content: space-between; } -.nav a { - display: block; - background: #dedede; - border-radius: 6px; - padding: 0.2em 0.8em; - color: #151515; - width: 20%; - text-align: center; +.article-header #category { } -@media (max-width:600px) { - .nav a { - width: auto; - } +.article-header #date { } -/* -------- one-default-with-toc, one-default-doc -------- */ - -.toc { - display: flex; - justify-content: center; - margin-bottom: 1.8rem; - color: #d1d1d1; -} - -.toc > div { - padding: 0 1em; +.category { } -.toc a { - color: #d1d1d1; -} - -.toc > div > div:first-child { - text-decoration: underline 1px; +#footer { + margin: 3rem 0; text-align: center; - font-size: 1.2em; - margin-bottom: 16px; -} - -/* --------- one-default-with-sidebar, one-default-doc --------- */ - -#sidebar-header { - color: #ffffff; - font-size: 2em; - font-weight: bold; - padding: 0 16px 0 16px; - background: #151515; - width: 100%; - height: 3.5rem; - position: fixed; - top: 0; - left: 0; - border-bottom: 1px solid #1d272b; - display: flex; - justify-content: center; - align-items: center; -} - -#sidebar-header > a { - color: inherit; - cursor: pointer; - text-decoration: none; -} - -#sidebar-header > a:visited { - color: inherit; -} - -#hamburger { - cursor: pointer; - height: 1em; - fill: #dedede; - display: none; - font-weight: normal; - margin-right: 0.3em; -} - -#sidebar-content { - margin: 3.5rem auto; - display: flex; - margin-left: auto; - margin-right: auto; - max-width: 1140px; - width: 100%; - padding: 1em 16px; -} - -#sidebar { - border-right: 2px solid #31424a; - top: 4.5rem; - position: sticky; - padding-top: 2.2em; - padding-bottom: 6em; - width: 250px; - max-height: 100vh; - overflow-y: auto; -} - -#sidebar a { - display: block; - color: #dedede; -} - -#sidebar a:hover { - text-decoration: none; -} - -#sidebar ul { - list-style: none; - padding:0; -} - -#sidebar li { - padding: 0.5em 0.6em; -} - -#sidebar li:hover { - background: #31424a; -} - -article { - padding: 0 1.5em; - max-width: 640px; - width: 100%; -} - -#sidebar-left { - width: 0; - height: 100%; - position: fixed; - z-index: 3; - top: 0; - left: 0; - transition: 0.25s; - background: #2c444f; - overflow: hidden; /* to make the children disappear when width is 0 */ - overflow-y: auto; -} - -#sidebar-left > div:first-child { - height: 3.5rem; - font-size: 2em; - font-weight: bold; - border-bottom: 1px solid #b8b8b8; - padding-left: 16px; - margin-bottom: 16px; - display: flex; - align-items: center; + font-size: 70%; } -#sidebar-left > ul { - padding: 0 16px 0 16px; -} - -#sidebar-left > ul ul { - padding-left: 0.8em; - margin-left: 3px; - border-left: 1px solid #b8b8b8; -} - -#sidebar-left a { - color: #dedede; - text-decoration: none; -} - -#sidebar-left li { - padding: 0.5em 0; - list-style-type: none; -} - -#sidebar-main { - display: none; - top: 0; - right: 0; - width: 100%; - height: 100%; - position: fixed; - background: #080808; - opacity: 0.80; - z-index: 2; -} - -@media (max-width: 840px) { - #hamburger { - display: block; - } - #sidebar { - display: none; - } - #sidebar-content { - justify-content: center; - } - #sidebar-header { - justify-content: left; - } - article { - padding: 0; - } +#footer p { + margin-bottom: 0; } /* Local Variables: */ diff --git a/one.org b/one.org deleted file mode 100644 index 9b8c4c2..0000000 --- a/one.org +++ /dev/null @@ -1,219 +0,0 @@ -* shtarkov.net -:PROPERTIES: -:ONE: one-default-home-list-pages -:CUSTOM_ID: / -:END: - -[[./assets/cat.png][Cat]] - -* List all website's pages on the home page -:PROPERTIES: -:ONE: one-default-home-list-pages -:CUSTOM_ID: /blog/default-home-list-pages/ -:END: - -This page is rendered with the default render function -~one-default-home-list-pages~ specified in ~ONE~ org property which lists -below all the pages on the website. You can use it instead of -~one-default-home~ for your home page. - -* The default page -:PROPERTIES: -:ONE: one-default -:CUSTOM_ID: /blog/default/ -:END: - -This page is rendered with the default render function ~one-default~ -specified in ~ONE~ org property. - -** Do you want a table of content? - -As you can see, ~one-default~ doesn't add a table of content (TOC). If -you want a default render function that adds the TOC to the page you can -use the render function ~one-default-with-toc~ presented in [[#/blog/one-default-with-toc/][The default -page with a TOC]]. - -** Headline foo -*** Headline bar - -Some content. - -*** Headline baz - -#+BEGIN_SRC bash :results verbatim -tree -#+END_SRC - -#+RESULTS: -#+begin_example -. -├── assets -│ └── one.css -├── one.org -└── public - ├── blog - │ ├── default - │ │ └── index.html - │ ├── default-home-list-pages - │ │ └── index.html - │ ├── one-default-doc - │ │ └── index.html - │ ├── one-default-with-sidebar - │ │ └── index.html - │ └── one-default-with-toc - │ └── index.html - ├── index.html - └── one.css - -8 directories, 9 files -#+end_example - -* The default page with a TOC -:PROPERTIES: -:ONE: one-default-with-toc -:CUSTOM_ID: /blog/one-default-with-toc/ -:END: - -This page is rendered with the render function ~one-default-with-toc~ -specified in the org property ~ONE~. - -** Do you want a sidebar? - -Perhaps you want a sidebar listing all the pages on your website, as -many modern documentation sites do. If so, you can use the default -render function ~one-default-with-sidebar~ presented in [[#/blog/one-default-with-sidebar/][The default page -with a sidebar]]. - -** Headline foo -*** Headline bar - -Some content. - -*** Headline baz - -#+BEGIN_SRC bash :results verbatim -tree -#+END_SRC - -#+RESULTS: -#+begin_example -. -├── assets -│ └── one.css -├── one.org -└── public - ├── blog - │ ├── default - │ │ └── index.html - │ ├── default-home-list-pages - │ │ └── index.html - │ ├── one-default-doc - │ │ └── index.html - │ ├── one-default-with-sidebar - │ │ └── index.html - │ └── one-default-with-toc - │ └── index.html - ├── index.html - └── one.css - -8 directories, 9 files -#+end_example - -* The default page with a sidebar -:PROPERTIES: -:ONE: one-default-with-sidebar -:CUSTOM_ID: /blog/one-default-with-sidebar/ -:END: - -This page is rendered with the render function ~one-default-with-sidebar~ -specified in the org property ~ONE~. - -** Do you want a sidebar and a TOC? - -Perhaps you want a sidebar listing all the pages on your website and a -table of content, as many modern documentation sites do. If so, you -can use the default render function ~one-default-doc~ presented in [[#/blog/one-default-doc/][The -default page with TOC and sidebar]]. - -** Headline foo -*** Headline bar - -Some content. - -*** Headline baz - -#+BEGIN_SRC bash :results verbatim -tree -#+END_SRC - -#+RESULTS: -#+begin_example -. -├── assets -│ └── one.css -├── one.org -└── public - ├── blog - │ ├── default - │ │ └── index.html - │ ├── default-home-list-pages - │ │ └── index.html - │ ├── one-default-doc - │ │ └── index.html - │ ├── one-default-with-sidebar - │ │ └── index.html - │ └── one-default-with-toc - │ └── index.html - ├── index.html - └── one.css - -8 directories, 9 files -#+end_example - -* The default page with TOC and sidebar -:PROPERTIES: -:ONE: one-default-doc -:CUSTOM_ID: /blog/one-default-doc/ -:END: - -This page is rendered with the function ~one-default-doc~ specified -in the org property ~ONE~. - -** Do you want to know more about one.el? - -Check the documentation at https://one.tonyaldon.com. - -** Headline foo -*** Headline bar - -Some content. - -*** Headline baz - -#+BEGIN_SRC bash :results verbatim -tree -#+END_SRC - -#+RESULTS: -#+begin_example -. -├── assets -│ └── one.css -├── one.org -└── public - ├── blog - │ ├── default - │ │ └── index.html - │ ├── default-home-list-pages - │ │ └── index.html - │ ├── one-default-doc - │ │ └── index.html - │ ├── one-default-with-sidebar - │ │ └── index.html - │ └── one-default-with-toc - │ └── index.html - ├── index.html - └── one.css - -8 directories, 9 files -#+end_example diff --git a/onerc.el b/onerc.el new file mode 100644 index 0000000..20f13cd --- /dev/null +++ b/onerc.el @@ -0,0 +1,171 @@ +;; -*- lexical-binding: t; -*- +(org-export-define-backend 'shtarkov.net-ox + '((headline . one-ox-headline) + (section . one-ox-section) + (paragraph . one-ox-paragraph) + + (plain-text . one-ox-plain-text) + + (bold . one-ox-bold) + (italic . one-ox-italic) + (strike-through . one-ox-strike-through) + (underline . one-ox-underline) + (code . one-ox-code) + (verbatim . one-ox-verbatim) + + (subscript . one-ox-no-subscript) + (superscript . one-ox-no-superscript) + + (plain-list . one-ox-plain-list) + (item . one-ox-item) + + (src-block . one-ox-src-block) + (example-block . one-ox-example-block) + (fixed-width . one-ox-fixed-width) + (quote-block . one-ox-quote-block) + + (link . shtarkov.net-link))) + +(defun shtarkov.net-head (website-name) + `(:head + (:meta (@ :charset "UTF-8")) + (:meta (@ :name "viewport" :content "width=device-width,initial-scale=1")) + (:link (@ :rel "stylesheet" :type "text/css" :href "/main.css")) + (:title ,website-name))) + +(setq shtarkov.net-footer + '(:div/footer + (:p + "© 2024 Christian Shtarkov. Except where otherwise noted, content on this site is licensed under the " + (:a (@ :href "https://creativecommons.org/licenses/by/4.0/") "Creative Commons Attribution 4.0 International license") + ".") + (:p + "Built with " (:a (@ :href "https://one.tonyaldon.com") "one.el") + " (" (:a (@ :href "/source/") "source") ")"))) + +(defun shtarkov.net-category (custom-id) + (cadr (string-split custom-id "/"))) + +(defun shtarkov.net-home (page-tree pages _global) + (let* ((website-name (one-default-website-name pages)) + (content (org-export-data-with-backend + (org-element-contents page-tree) + 'shtarkov.net-ox nil)) + (pages-list (one-default-pages pages "^/[^/]+/$"))) + (jack-html + "" + `(:html + (@ :lang "en") + ,(shtarkov.net-head website-name) + (:body + (:div.header (:a (@ :href "/") ,website-name)) + (:div.content + (:div/home-list-pages ,content) + (:div/pages (:ul ,(reverse pages-list)))) + ,shtarkov.net-footer))))) + +(defun shtarkov.net-articles (page-tree pages _global) + (let* ((website-name (one-default-website-name pages)) + (title (org-element-property :raw-value page-tree)) + (content (org-export-data-with-backend + (org-element-contents page-tree) + 'shtarkov.net-ox nil)) + (pages-list + (one-default-pages + pages + (format "^%s[^$]" (org-element-property :CUSTOM_ID page-tree))))) + (jack-html + "" + `(:html + (@ :lang "en") + ,(shtarkov.net-head website-name) + (:body + (:div.header (:a (@ :href "/") ,website-name)) + (:div.content + (:div.title (:h1 ,title)) + (:div/home-list-pages ,content) + (:div/pages (:ul ,(reverse pages-list))))) + ,shtarkov.net-footer)))) + +(defun shtarkov.net-default (page-tree pages _global) + (let* ((website-name (one-default-website-name pages)) + (title (org-element-property :raw-value page-tree)) + (content (org-export-data-with-backend + (org-element-contents page-tree) + 'shtarkov.net-ox nil))) + (jack-html + "" + `(:html + (@ :lang "en") + ,(shtarkov.net-head website-name) + (:body + (:div.header (:a (@ :href "/") ,website-name)) + (:div.content + (:div.title (:h1 ,title)) + ,content)) + ,shtarkov.net-footer)))) + +(defun shtarkov.net-article (page-tree pages _global) + (let* ((website-name (one-default-website-name pages)) + (title (org-element-property :raw-value page-tree)) + (category + (shtarkov.net-category (org-element-property :CUSTOM_ID page-tree))) + (date (org-element-property :DATE page-tree)) + (content (org-export-data-with-backend + (org-element-contents page-tree) + 'shtarkov.net-ox nil))) + (jack-html + "" + `(:html + (@ :lang "en") + ,(shtarkov.net-head website-name) + (:body + (:div.header (:a (@ :href "/") ,website-name)) + (:div.content + (:div.title (:h1 ,title)) + (:div.article-header + (:a/category (@ :href ,(format "/%s/" category)) "#" ,category) + (:p/date ,date)) + ,content)) + ,shtarkov.net-footer)))) + +(defun shtarkov.net-link (link desc info) + "Transcode a LINK object from Org to HTML. +DESC is the description part of the link, or the empty string. +INFO is a plist holding contextual information." + (let* ((type (org-element-property :type link)) + (path (org-element-property :path link)) + (raw-link (org-element-property :raw-link link)) + (custom-type-link + (let ((export-func (org-link-get-parameter type :export))) + (and (functionp export-func) + (funcall export-func path desc 'shtarkov.net-ox info)))) + (href (cond + ((string= type "custom-id") path) + ((string= type "fuzzy") + (let ((beg (org-element-property :begin link))) + (signal 'one-link-broken + `(,raw-link + "fuzzy links not supported" + ,(format "goto-char: %s" beg))))) + ((string= type "file") + (or + ;; ./assets/images/image-1.png --> /images/image-1.png + ;; ./public/blog/page-1.md --> /blog/page-1.md + (and (string-match "\\`\\./\\(assets\\|public\\)" path) + (replace-match "" nil nil path)) + (let ((beg (org-element-property :begin link))) + (signal 'one-link-broken + `(,raw-link ,(format "goto-char: %s" beg)))))) + (t raw-link)))) + (or custom-type-link + (and + (string-match one-ox-link-image-extensions path) + (format "

\"%s\"

" + href (or (org-string-nw-p desc) href)) ) + (and + (string-match "\\.webm$" path) + (format "" + href (or (org-string-nw-p desc) href))) + (format "%s" + href (or (org-string-nw-p desc) href))))) diff --git a/shtarkov.net.org b/shtarkov.net.org new file mode 100644 index 0000000..ddc018b --- /dev/null +++ b/shtarkov.net.org @@ -0,0 +1,87 @@ +* (shtarkov) +:properties: +:one: shtarkov.net-home +:custom_id: / +:end: + +[[file+emacs:./assets/cat.png][Cat]] + +* Emacs +:properties: +:one: shtarkov.net-articles +:custom_id: /emacs/ +:end: + +* Cat +:properties: +:one: shtarkov.net-default +:custom_id: /cat/ +:end: + +#+begin_quote +A good movie is precisely the one in which the camera disappears, when +we are no longer aware of watching a movie, while an avant-garde film +tries to turn the camera to itself and show the hidden device. A +jocular way of understanding this would be to compare the reaction of +a human and that of a cat when we point to an object with the finger; +while the human looks beyond the finger trying to discover the object +to which the finger points, the cat stares at the finger; in this +sense, the cat is avant-garde, it is more interested in the medium +(the finger, the camera) than the object pointed. + +Julio Cabrera +#+end_quote + +[[file+emacs:./assets/cat/cat1.jpg]] +[[file+emacs:./assets/cat/cat2.jpg]] +[[file+emacs:./assets/cat/cat3.jpg]] +[[file+emacs:./assets/cat/cat4.jpg]] +[[file+emacs:./assets/cat/cat5.jpg]] + +* Transpose Regions +:properties: +:one: shtarkov.net-article +:custom_id: /emacs/transpose-regions/ +:date: <2024-10-20 Sun> +:end: + +Often times I find myself indecisive about how to lay out function +arguments. + +#+begin_src c++ +dump(repository, file); +#+end_src + +Which one should go first? It's easy enough to reorder them with +=C-M-t (transpose-sexps)= by placing point between the two. + +But, until now, I never had a good solution for the function +declaration: + +#+begin_src c++ +void dump(repository::Repository &repository, const std::filesystem::path &file); +#+end_src + +~transpose-sexps~ does not produce the desired result: + +#+begin_src c++ +void dump(repository::Repository &const, repository std::filesystem::path &file); +#+end_src + +A Web search reveals that the usual approaches are defining Elisp +commands in advance, installing packages or mucking about with the +kill ring. Same goes for Vim! + +Well, there's also ~transpose-regions~, unbound by default. Let's see +how that can work: + +[[./assets/emacs/transpose-regions.webm][Transpose Regions Demo]] + +Did you see it? The trick is to save the mark 3 times — at the +beginning and end of the first region, and at the beginning of the +second region. Then leave point at the end of the second region and do +~transpose-regions~, which I've bound to =C-c t=. Isearch comes in +handy here, because it saves the mark where the search starts. I've +modified it to [[https://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html][leave point at the start of the match]], which makes it +even more convenient. If you find Isearch too cumbersome you can use +something like [[https://www.emacswiki.org/emacs/iy-go-to-char.el][iy-go-to-char.el]] or [[#/emacs/do-not-zap-up-to-char][do-not-zap-up-to-char]].