From cb24d0bac1b88de5f4862de73900fa311ed0c658 Mon Sep 17 00:00:00 2001 From: "Yann Esposito (Yogsototh)" Date: Wed, 14 Aug 2019 14:54:14 +0200 Subject: [PATCH] updated a bit --- .gitignore | 1 + .project.el.gpg | Bin 3667 -> 3737 bytes src/archive.org | 8 - src/css/minimalist.css | 69 ++- src/index.org | 26 +- src/posts/2019-07-04-static-org-publish.org | 607 +++++++++----------- 6 files changed, 336 insertions(+), 375 deletions(-) delete mode 100644 src/archive.org diff --git a/.gitignore b/.gitignore index ca35be0..dba907b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ _site +src/archive.org diff --git a/.project.el.gpg b/.project.el.gpg index 678cdc9049a7f0e23015ec327451c65d302fc5d8..9e709532da56aa0a5c16066dcec5c7ea728ea367 100644 GIT binary patch literal 3737 zcmV;K4rcL%0t^FvF6E%v-!tL?5C2yVTuD6ag(zUeJ}i8lbu>ch)K8jEwyvGW#k8uP zAI!Jqjwk>SUjv0LwM$lnD2zzep;nCRk`|oZ!@P3Xojh+BCu~%Ki$hx|^qX8)UNLev zHYQY|dWPLY9Bw$=07!YWnBhJR17#sIB#%?@0wDcj1E&^N`;aeX>-E*EU>%`z)MYe& zvE`&3!3geoeik*eW`pBe-l7+PWhr5?@wwa3vMCGueht)hI~k1FP0aJAH>a6~}?u{%uusLH!^=iy}sBI)P_`w(sCoY614+3pS@dnb_Btt0E?va{5-edaF36gB#hYT-cB4_T>(JnQ z3h6dRV+jwGX6?HKm%ygpd#M+Mskk|0>@GY`Uv{c^*G76xOgw60T$Cr`8)8-cUmen3 zQ9VlX^%0qXRLTiB$cBe8xj^W~H#HeixdBYgPR-jv_)yK?8wR5q4G&{s>I%?&CeBJ%M;6gYU%C@lSn_P-nmbf4rHojW7AYVcT6=P9R z>{8Iki@`mTHw|{f4|Prxuvxw+yim!T$`Ex`;eKm766nOy);$T3;{Dv88d-mgB~UJ9 zP_1Qv=-0>qmoy`UwlKzST4}sW!E2#v2{v!^B4`OyY~rfs;ve&WY3+v>=IT}#WHg~wq9RZlizusldH6)cwDwoZJbxpRySz)e zPJC+0EMX%@?@yi8{-Ps68Dp#%QP(Ho6fE5~58~OB60stZluScXX=Y;{A7qZ%;4c@1 zsI>xzZJQW`bh!R!4bIRcOcmag#*KJae=M&Cu+yWf|C&4TkZseJw7b|-ta~(qH2_7a zpqkOq&jFP2P5`&oxAV9*3u(pTpy-(OPHWhVsP8jnibeug_RcFz;TS>uNmV^!&HS#_>AWEaxs374T$g?eHDhnnX zY5|n}SOgk%SvcUKul8h@8QG+bqB?%dEDeYrD=z|#-%-b#OG6IUbgJq`2*8$E6oKZTe&*02%r(8RB00}!a3=$?i zOEHzr!JJ2the8iFC_KD)tiZBLVax@qSxQX&U;Q#6K71(6;?EUcxAzUF$Z}s7UZ3&M zqASS24V%~OYYfP+FW`H>%j^?o5=VaYJ-Ibo)&&kzBeQkay?Z;&2_$Y&+2&UsME8<= zGtSO-OgfuPWiW%Q44(|#$zp19_M44Z&`s@egd+dfBA6#lpJSArMoQ(unj>WeJ;vn}Hjl)wb@ z4iT)KWWri84%^62VH0fe!FZ;vtDTGF){&&u`?DWk3;kIVPt2cS`1s=brO@12a%{-Z z4>e4PFLXwIfJi=b=v_UL%JU5&T+==^WqHMTB%#%06P2)w4lY%Ha?Aq=TXL8Fz#9~6 zi7?z@4rL%Ry7O)1gNz&Y_Ez>K$vtpWUx^w%q>RhAwKyE1MV*G5u>li?%RoC&3@Fsp z-OQhJ#9XLWcEJp!owY8S*tQP|=S)j9Q#ELyV<|)A+Y+u+mOyZdAAvA{fk5|lbIl+{ zHVzmE8HCvY($nKepzUMBM&h#~lfA7PgiO@e;Nh_r%hwR<%|>O(R{@$&KtY`_2#D%1 zmk167(7NW)L zP<}eu&mBdKktKFa`if1&;;tMOs)In%UWQ46rGU)6Q}UzTeUBo#8Ti1d0T!#O`j7(&_F>Qq=oTPN?!|Ijsllc}$jrfqC_SZ~*4VQjAmzzf) z7ed3F=tSJ8*<$z7x@5iU(>jug^STmUdp!#MrC$j+Q_GL!7O1TkF5e&I&JIhP(_qdA zhHp@>j@ffcs!1L%4d7&skd789p+@|1I5)u1vt`J%cQUI#w*d7-Ewh*D{K`5+4+l}%gX;Fkh?G|dfiGi!o)ch(3~%_wlVy{*D8hr~ z%m-1>II!P5@sS)^JG6rlXu+C#El)d{vj@gqQy*7usos*BKmwO$WkjaH8;PSn0d^8W ze3Oi=9J}TbGfTX&uVxy=zOLG|6dtTy@cR*8_eU3wr3Y#y0dJ8glR={!$JLFog5NfO zVMtU7;E0)IiPtdhcb8W{w+kRHL)9leEK*0@NsW#~#Joqri_aLZ9WX4Fe+%Jy9Y6~l z1PNIC^BF_!mB!UJ7<$WhLPMQi#JZ34ja1^k1qrsDWr)}5V02rQgDmF`h0O1wN<2F1;$;cluy$R3& zn;g?Fj}(T!AY~C8J2gts81q>5gUm~NXm|A66d6lUDBny{E85Ebro{kY zQ1U1U*#&j0N?eBbKiR3Cxf48My`}VdJ7X6D1;7+r)iS^}8e(3h{c@S_oCMe6ZinRi zw4pE7ne!b%-Muv4kGQqP08D>6a`E&kItyM)^2!|r8+`R}$~++<9nvX0+W-sy|1}yU zy}Iz`#S*3`$i9Ir&!!@kicsZb!5gVo9WB~xgyfvZ@6 zG}i=<`;33$;XX_Yqt2`U&Y0Svtac?E zi)y-ZXqqyZTFHFOcoFf`w6yV?w?cwLcTqP(9wYI@3L3FNspqul<%ZOkvOeHeie}K& z0HqP0?at8`$5{({Eml1qO7`p<5{*96ZuNW|wNl2JWBAwhNk+nZY{iMrOhlZ6QW+|` zzDXo!LM-cyg&m}c-_>cXYBoZ(OI8RYJkScF=MQ1BUea_GXU=4ij0jG_nm5R7;EK*5 zlUu3GIeW-x_baTVcw8@>wwxO?w)R~oFb!h7X|oTm!kA;2(rc%8$jVr|@3x-@n-zi_7RMQmbhl{+Muf|KPBhbdR^dw^K~XI~Q-q^DgxV|2xiE+1Ay zm+5%Y!Y}Ym{-m1vodc80`UOdT>(Z+2fozRcC6z^k^s)ABuphZ0qgRsH9XgdXfKw>j zn62KUV_{I1>aIJ~2`RFC*PZjTiKT6);mW+y#lIyR97wUN4Q4`y@R;nV2e1W^N< zGmd5RAxU4O3L^cGAh-BQ-iz!ZNdzd!D%ZIZfiO5=L39u#CV@KH(IL*UK-CX6zzGPVEmlEX~i^*1+|G4+D&7IC4H6opP8){JAcrn9MH|gc^cW#^LJ8Myk3Ta zgClM_Ypl9%2T&)@z?!5R>x~%8T5VPAw3*33c3A-O`?r^}x_z>DG+6@zhbKW$*Lrki zF$0!`_V^pB-xBr6ei3#@w)aw#DP7xsuK!mRvkvQg(_gY&wfQG33pQE24Hqapk!8oW zMtbLP46c}1ty+3;N&(xE$v#+yn&9BJay@%vf!SDt`YV0ev7CVwR*PlVrRk zg9Bj~!3_Te80FGTSHe>tR}e+6YD_t~LNsil#mpW9w~p4`r|049a4*`vB&l#-rbB@) z_Gu-jZc5Em`23D)8HE$4e1*{<&1DI-0jTmSSg*&HUy$K;Nf$~k?34Ra(_NkvUcI`D zkOU)fKUQ59t(jtE+t)V^ozuD^hMl{#08qTvq%T;9@zEe=p^BBd=#I2=d`urG-n?HP zqGmK7aAixOz&UW0GFaclAC}-Q^!g>Lpy{2#eb;rs!n=XLb=Hm_kUosCH_E-(i#6Rr zpRBj3!f|Gsur#HBq+RzU;iTM6q@q!3FI&4}zYS`W#nP=PWxI+6aup4Z(aSSEs%arh zmiCpUk6N0=JD?(P$1(Pb`p5(SaEA5|3uhIe`hW6b5?q-{ua@$|F&bWcffpQ|n3l{h zwce=DN~iXgXEp*Jy4!+Uw`02P#sg>S1lt7nOmCX#Dx%p`RA%`MJJ_Oz*Fi+!7w0gv2aQytmg08{6|ExU~4b2418d DtI{;{ literal 3667 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 @@html:@@ 2019-08-13: @@html:@@ [[file:posts/project-el/index.org][Autoload Script by project]] @@html:@@ @@html:@@ -@@html:
  • @@ @@html:@@ 2019-07-15: @@html:@@ [[file:posts/2019-07-04-static-org-publish.org][Static blog with org-mode]] @@html:@@ @@html:
  • @@ -#+end_archive diff --git a/src/css/minimalist.css b/src/css/minimalist.css index 93dbecc..30a5e62 100644 --- a/src/css/minimalist.css +++ b/src/css/minimalist.css @@ -190,17 +190,22 @@ navigation > a { } #preamble { border-bottom: solid 1px; + margin-bottom: 1em; } #preamble h1, #preamble h2 { margin: 0; } +#preamble h2 { + font-weight: normal; + font-style: italic; +} #postamble { border-top: solid 1px; margin-top: 10px; } #content,.content { max-width: 50em; - margin: 0 auto; + margin: 0 1em; padding: 1px; } #content *:first-child { @@ -267,6 +272,13 @@ navigation > a { --soft-foreground: var(--base01); --border-color: var(--base02); --todo-txt: #000; + --color-h1: var(--magenta); + --color-h2: var(--violet); + --color-h3: var(--blue); + --color-h4: var(--cyan); + --color-h5: var(--green); + --color-h6: var(--yellow); + --color-link: var(--yellow); } /* org colors */ @@ -290,7 +302,9 @@ navigation > a { cursor: pointer; font-style: italic; } -input#light, input#dark { display:none; } + +body > input { display:none; } + input#light:checked ~ .main { --main-background: #fefaf0; /* 0.5 lighter than #fdf6e3 */ --main-foreground: var(--base01); @@ -300,6 +314,11 @@ input#light:checked ~ .main { --border-color: var(--base2); --todo-txt: #FFF; } +input#light:checked ~ #labels { + background: #fefaf0; + color: var(--base00); +} + input#dark:checked ~ .main { --main-background: var(--base03); /* 0.5 darker than #002b36; */ --main-foreground: var(--base1); @@ -309,14 +328,33 @@ input#dark:checked ~ .main { --border-color: var(--base02); --todo-txt: #000; } -input#light:checked ~ #labels { - background: #fefaf0; - color: var(--base00); -} input#dark:checked ~ #labels { background: var(--base03); color: var(--base0); } + +input#raw:checked ~ .main { + --main-background: #fff; + --main-foreground: #000; + --second-foreground: #000; + --reveal-background: #fff; + --soft-foreground: #000; + --border-color: #000; + --todo-txt: #000; + --color-h1: #000; + --color-h2: #000; + --color-h3: #000; + --color-h4: #000; + --color-h5: #000; + --color-h6: #000; + --color-link: #33d; +} +input#raw:checked ~ #labels { + background: #fff; + color: #000; +} + + body,.main { background: var(--main-background); color: var(--main-foreground); @@ -337,7 +375,7 @@ pre::after,pre::before,hr:after, } a:hover, a:active, a:focus, .main a:hover,.main a:active,.main a:focus { - color: var(--yellow); + color: var(--color-link); } navigation a, navigation a:visited, .main navigation a,.main navigation a:visited { @@ -345,7 +383,7 @@ navigation a, navigation a:visited, } navigation a:focus, navigation a:hover, .main navigation a:focus,.main navigation a:hover { - color: var(--yellow); + color: var(--color-link); } thead, .main thead { @@ -357,22 +395,25 @@ tr:hover, background-color: var(--reveal-background); } h1, .main h1 { - color: var(--magenta); + color: var(--color-h1); +} +#preamble h2, .main #preamble h2 { + color: var(--color-h4); } h2, .main h2 { - color: var(--violet); + color: var(--color-h2); } h3, .main h3 { - color: var(--blue); + color: var(--color-h3); } h4, .main h4 { - color: var(--cyan); + color: var(--color-h4); } h5, .main h5 { - color: var(--green); + color: var(--color-h5); } h6, .main h6 { - color: var(--green); + color: var(--color-h6); } table, td, th, .main table,.main td,.main th { diff --git a/src/index.org b/src/index.org index 04e962a..8118936 100644 --- a/src/index.org +++ b/src/index.org @@ -8,12 +8,24 @@ #+OPTIONS: H:5 #+STARTUP: showeverything -Welcome! +Welcome to my personal website. -#+begin_notes -This website is dark by default, but it support user preferred theme. -For example on Mac OS X > 10.14, if you have selected a light theme, the website -will be light. -#+end_notes +Here I will talk mostly about the life of a software developer. +So programming, functional programming in particular. -- [[./archive.html][articles]] +That website was created with the following constraints in mind by order of +priority: + +1. /Respect Privacy/; no tracker of any sort (no google ads, no referrer for all external links, + etc...) +2. /javascript free/; no js at all, yes even the theme changer +3. /disability friendly/; should be easy to read on a text browser so people + with disabilities could easily consume it +4. /nerdy/; should feel mostly like markdown text in a terminal and source code + should be syntax higlighted. +5. /org-mode friendly/; I should write my post in [[https://orgmode.org][org mode]] +6. /user friendly/; support your preferred light/dark theme by default but you + can change it if you want. +7. /frugal/; try to minize the resources needed to visit my website; no + javascript, no webfont, not too much CSS magic, not much images or really + compressed one. diff --git a/src/posts/2019-07-04-static-org-publish.org b/src/posts/2019-07-04-static-org-publish.org index 7f01f0c..7d44857 100644 --- a/src/posts/2019-07-04-static-org-publish.org +++ b/src/posts/2019-07-04-static-org-publish.org @@ -1,406 +1,321 @@ -#+TITLE: Static blog with org-mode +#+TITLE: Blogging with org-mode +#+SUBTITLE: Meta post about this blog #+AUTHOR: Yann Esposito #+EMAIL: yann@esposito.host #+DATE: 2019-07-27 -#+KEYWORDS: programming, blog, org-mode +#+KEYWORDS: programming, blog, org-mode, meta #+OPTIONS: auto-id:t #+begin_quote -/tl;dr/: [[#current-solution][Full code for the impatient↓]]. -Read the full blog post to have all the details. +/tl;dr/: [[#full-solution][Go to the full solution]] for the impatients. #+end_quote -This is the first article using my new blog system. +As the first article of my new blogging system, let's have a meta blog post. + +Once in a while, I like to change how I blog. +A long time ago, I used PHP for my first website using my personal space at my +university. +And as of today, a clond of my university website still exists: +http://yann.esposito.free.fr It contains all details about my old research +activities and teaching resources for my students. -Once in a while, I create a new personal website. -A long time ago, I used PHP for my first website. -I used include and took care of XHTML pages validation. Then I used [[http://nanoc.ws][nanoc]], a ruby static website generator. Then I switched to [[https://jaspervdj.be/hakyll/][hakyll]] because I wanted to switch to a Haskell's written tool. -Now I'll try to use [[http://orgmode.org][org-mode]] directly with [[https://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html][org-publish]]. -I am became a quite extensive emacs user now. So using org-mode and org-publish -is a bit like not having to install any 3rd party software. -* Why? - :PROPERTIES: - :CUSTOM_ID: why--8eb9 - :END: +This time I'll try to use [[http://orgmode.org][org-mode]] directly with [[https://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html][org-publish]]. +I used vim a lot, but recently I switched to emacs. +The main reason were: -Everything started when I was hired in a place where I was given a terrible -keyboard. -After a few weeks I started to feel a lot of pain in both my wrists. -So I started to go from classical IDE to being able to use vim -correctly[fn:vim]. +1. You use LISP as plugin language while for Vim it is vimscript which is a + quite terrible language. +2. Many comment on the Internet about people telling that [[https://github.com/emacs-evil/evil][evil]] (vim keybdings in + emacs) was really really good. And I can confirm it is. +3. The [[http://spacemacs.org][spacemacs]] project made it easier to handle the emacs configuratin + complexity for a newbie. -Then I started to work in Clojure and I heard that emacs might certainly be a -better fit for LISP dialiects. -But, I couldn't switch to an editor without vim keybindings support because they -are so great once you're used to them. -By chance it was about the same time that [[http://spacemacs.org][spacemacs]] appeared and I switched. -Is is really impressive how well the vim keybindings are supported. -Even most of the advanced vim features I used to use worked like a charm. - -The first benefit of emacs is you can configure emacs with elisp. -Which unlike vimscript looks like a correct language to work with. - -One unexpected benefit of emacs was [[http://orgmode.org][org-mode]]. -I always heard good things about it but it took me a while to really get it and -to understand why it is so great. - -If you don't know anything about org-mode, it is many things. -First imagine a Markdown but more TODO list oriented. -But along with this, emacs has a lot of helper functions to work with those -org-mode files. - -One real game changer is ~org-capture~. -You can add a task quite easily while doing other work in emacs. - -[fn:vim] I wrote this article to help people use vim: [[http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/][learn vim progressively]] +And by doing the switch, I discovered a lot of great emacs packages. +Now I really do not regret the switch. +In particular, [[http://orgmode.org][org-mode]] has been a game changer. +I used to write markdown before. +But now I use the org format. +It is superior for my usage(s). * How? :PROPERTIES: - :CUSTOM_ID: how--831e + :CUSTOM_ID: how :END: You can easily follow the org-mode doc to make your own website. -But I have added a few "goodies". +But I have added a few niceties. +First, the code to export is provided in a local file. +I've got a system to auto-load elisp file when entering in a new project. +It is quite safe as it uses PGP and check if I trust the person who encrypted +the file. +See [[file:project-el/index.org][my other post about it]]. -- attempt to obfuscate contact email, -** Basic Blog +** Configuration variables :PROPERTIES: - :CUSTOM_ID: basic-blog-a1fc + :CUSTOM_ID: configuration-variables :END: -I put the need minimal code in a =.project.el.gpg= file of my blog repository. -Inspired by this [[https://francismurillo.github.io/2017-02-15-Project-Script-Loader/][blog post]] I enhanced this version to be both more user friendly -and secure (see [[./autoload-emacs-script-by-project.org][Autoload Emacs Script by Project]]). - -But even before that, I simply put the code in has an elisp code block of my -=index.org= that I exectued with =C-c C-c=. - -I have a code block in my =index.org= page that I do not export containing the -elisp code I use to load all the information needed by =org-publish=. -Do not export an org-mode subtree you can simply tag it with =:noexport:=. - -=org-publish= suppose that you'll export one html page per org file. -You need to provide a minimum set of information: - -- base directory that should contain your org files -- publish directory, where you will export the html from the org files - -A very basic publish rule would be: - -#+begin_src org -,* Magic Script :noexport: -,#+begin_src elisp :results none - (setq org-publish-project-alist - '(("orgfiles" - :base-directory "/users/me/blog/src" - :publishing-directory "/users/me/blog/_site" - :recursive t))) -,#+end_src -#+end_src - -So now, if you put org files in the base directory it will copy -recursively the tree in that base directory and will copy it to -the publishing directory exporting all org files to html files. - -Nice. - -If you are not familiar with emacs or orgmode, orgpublish. -This block of code set the variable named ~org-publish-project-alist~. -The ~alist~ in the end is for "associative list". - -#+begin_quote -/☞/ So when you'll execute the command =org-publish= in emacs. -You will get prompted to enter the name of what to publish. -You should see a single proposition named =orgfiles=. -Once selected the export and publish will occurs. -Notice, org-publish does what you expect and do not re-export all files -each time but only the one that have changed. -#+end_quote - -** Relative Paths - :PROPERTIES: - :CUSTOM_ID: relative-paths-d145 - :END: - -A first issue with this is that I don't want to put that in my emacs -preferences. -I would like to be able to publish my website for anyone that could clone my git -repository. -So I will use emacs projectile to find the root directory of the current -project. - #+begin_src elisp - (setq base-dir (concat (projectile-project-root) "src")) - (setq publish-dir (concat (projectile-project-root) "_site")) - (setq org-publish-project-alist - `(("orgfiles" - :base-directory ,base-dir - :publishing-directory ,publish-dir - :recursive t - :base-extension "org"))) +;; CONFIGURATION VARIABLES +(setq domainname "https://her.esy.fun") +(setq base-dir (concat (projectile-project-root) "src")) +(setq publish-dir (concat (projectile-project-root) "_site")) +(setq assets-dir (concat base-dir "/")) +(setq publish-assets-dir (concat publish-dir "/")) +(setq rss-dir base-dir) +(setq rss-title "Subscribe to articles") +(setq publish-rss-dir publish-dir) +(setq css-path "/css/minimalist.css") +(setq author-name "Yann Esposito") +(setq author-email "yann@esposito.host") #+end_src -That's better. -Now anyone can clone the repository. -Open my =index.org= file, and execute the code in it by =C-e C-e= and then will -be able to publish the website locally in the =_site= directory. - -** Assets - :PROPERTIES: - :CUSTOM_ID: assets-cf7d - :END: - -Generally you want a bit more features than that for publishing a blog. -Typically you would like to have a common template, an header, some CSS. - -For that you need to work a bit more. -First, important thing, add an org publish section to publish your assets (CSS, -images, etc...) - -#+begin_src elisp - (setq base-dir (concat (projectile-project-root) "src")) - (setq publish-dir (concat (projectile-project-root) "_site")) - (setq assets-dir (concat base-dir "/assets")) - (setq publish-assets-dir (concat publish-dir "/assets")) - (setq org-publish-project-alist - `(("orgfiles" - :base-directory ,base-dir - :publishing-directory ,publish-dir - :recursive t - :base-extension "org" - :exclude ".*drafts/.*") - - ("assets" - :base-directory ,assets-dir - :base-extension ".*" - :publishing-directory ,publish-assets-dir - :publishing-function org-publish-attachment - :recursive t) - - ("blog" :components ("orgfiles" "assets")))) -#+end_src - -With that you will copy the assets and export org file to html. -You can do both by selecting `blog` when doing an `org-publish`. - -That's better. But for a blog you also generally want to have your own CSS. - -* Current Solution +* Full Solution :PROPERTIES: - :CUSTOM_ID: current-solution + :CUSTOM_ID: full-solution :END: #+begin_src elisp - ;; Global variables - (setq domainname "https://her.esy.fun") - (setq base-dir (concat (projectile-project-root) "src")) - (setq publish-dir (concat (projectile-project-root) "_site")) - (setq assets-dir (concat base-dir "/assets")) - (setq publish-assets-dir (concat publish-dir "/assets")) - (setq rss-dir base-dir) - (setq publish-rss-dir publish-dir) - (setq css-name "minimalist.css") - (setq author-name "Yann Esposito") - (setq author-email "yann@esposito.host") - (require 'org) - (require 'ox-publish) - (require 'ox-html) - (require 'org-element) - (require 'ox-rss) +(require 'org) +(require 'ox-publish) +(require 'ox-html) +(require 'org-element) +(require 'ox-rss) - (defun org-blog-prepare (project-plist) - "With help from `https://github.com/howardabrams/dot-files'. - Touch `index.org' to rebuilt it. - Argument `PROJECT-PLIST' contains information about the current project." - (let* ((base-directory (plist-get project-plist :base-directory)) - (buffer (find-file-noselect (expand-file-name "index.org" base-directory) t))) - (with-current-buffer buffer - (set-buffer-modified-p t) - (save-buffer 0)))) +(setq org-link-file-path-type 'relative) - (defvar org-blog-head - (concat - "" - "" - "" - "")) +(defun org-blog-prepare (project-plist) + "With help from `https://github.com/howardabrams/dot-files'. +Touch `index.org' to rebuilt it. +Argument `PROJECT-PLIST' contains information about the current project." + (let* ((base-directory (plist-get project-plist :base-directory)) + (buffer (find-file-noselect (expand-file-name "index.org" base-directory) t))) + (with-current-buffer buffer + (set-buffer-modified-p t) + (save-buffer 0)))) - (defun menu (lst) - "Blog menu" - (concat - "" - (mapconcat 'identity - (append - '("Home" - "Posts") - lst) - " | ") - "")) +(defvar org-blog-head + (concat + "" + "" + "" + "")) - (defun str-time-to-year-float (date-str) - (/ (float-time - (apply 'encode-time - (mapcar (lambda (x) (if (null x) 0 x)) - (parse-time-string date-str)))) - (* 365.25 24 60 60))) +(defun menu (lst) + "Blog menu" + (concat + "" + (mapconcat 'identity + (append + '("Home" + "Posts" + "About") + lst) + " | ") + "")) - (defvar blog-creation-date "2019-07-01") - (defun delta-date (date-str) - "Number of year since the begining of this blog" - (let ((y (- (str-time-to-year-float date-str) - (str-time-to-year-float blog-creation-date)))) - (format "∆t=%.2f" y))) +(defun str-time-to-year-float (date-str) + (/ (float-time + (apply 'encode-time + (mapcar (lambda (x) (if (null x) 0 x)) + (parse-time-string date-str)))) + (* 365.25 24 60 60))) - (defun org-blog-preamble (info) - "Pre-amble for whole blog." - (concat - "
    " - (menu '("↓ bottom ↓")) - "

    " - (format "%s" (plist-get info :title)) - (when-let ((date (get-from-info info :date))) - (format " - %s" date)) - "

    " - "
    ")) +(defvar blog-creation-date "2019-07-01") - (defun get-from-info (info k) - (let ((i (car (plist-get info k)))) - (when (and i (stringp i)) - i))) +(defun y-date (date-str) + "Number of year since the begining of this blog" + (let ((y (- (str-time-to-year-float date-str) + (str-time-to-year-float blog-creation-date)))) + (format "∆t=%.2f" y))) - (defun rand-obfs (c) - (let ((r (% (random) 20))) - (cond ((eq 0 r) (format "%c" c)) - ((< 0 r 10) (format "&#%d;" c)) - (t (format "&#x%X;" c))))) +(defun org-blog-preamble (info) + "Pre-amble for whole blog." + (concat + "
    " + (menu '("↓ bottom ↓")) + "

    " + (format "%s" (car (plist-get info :title))) + "

    " + (when-let ((date (get-from-info info :date))) + (format "%s" date)) + (when-let ((subtitle (car (plist-get info :subtitle)))) + (format "

    %s

    " subtitle)) + "
    ")) - (defun obfuscate-html (txt) - (apply 'concat - (mapcar 'rand-obfs txt))) +(defun get-from-info (info k) + (let ((i (car (plist-get info k)))) + (when (and i (stringp i)) + i))) - (defun org-blog-postamble (info) - "Post-amble for whole blog." - (concat - "
    " - "
    " - (when-let ((author (get-from-info info :author))) - (if-let ((email (plist-get info :email))) - (format "
    Author: %s
    " +(defun rand-obfs (c) + (let ((r (% (random) 20))) + (cond ;; ((eq 0 r) (format "%c" c)) + ((<= 0 r 10) (format "&#%d;" c)) + (t (format "&#x%X;" c))))) + +(defun obfuscate-html (txt) + (apply 'concat + (mapcar 'rand-obfs txt))) + +(defun org-blog-postamble (info) + "Post-amble for whole blog." + (concat + "
    " + ;; TODO install a comment system + ;; (let ((url (format "%s%s" domainname (replace-regexp-in-string base-dir "" (plist-get info :input-file))))) + ;; (format "comment" + ;; (url-hexify-string url))) + "
    " + (when-let ((author (get-from-info info :author))) + (if-let ((email (plist-get info :email))) + (let* ((obfs-email (obfuscate-html email)) + (obfs-author (obfuscate-html author)) + (obfs-title (obfuscate-html (get-from-info info :title))) + (full-email (format "%s <%s>" obfs-author obfs-email))) + (format "
    Author: %s
    " (obfuscate-html "mailto:") - (obfuscate-html email) - (obfuscate-html author)) - (format "
    Author: %s
    " author))) - (when-let ((date (get-from-info info :date))) - (format "
    Created: %s (%s)
    " date (delta-date date))) - (when-let ((keywords (plist-get info :keywords))) - (format "
    Keywords: %s
    " keywords)) - (format "
    Generated: %s
    " - (format-time-string "%Y-%m-%d %H:%M:%S")) - (format (concat "
    Generated with " - "Emacs %s, " - "Spacemacs %s, " - "Org Mode %s" - "
    ") - emacs-version spacemacs-version org-version) - "
    " - (menu '("↑ Top ↑")) - "
    ")) + full-email + (obfuscate-html "?subject=yblog: ") + obfs-title + full-email)) + (format "
    Author: %s
    " author))) + (when-let ((date (get-from-info info :date))) + (format "
    Created: %s (%s)
    " date (y-date date))) + (when-let ((keywords (plist-get info :keywords))) + (format "
    Keywords: %s
    " keywords)) + (format "
    Generated: %s
    " + (format-time-string "%Y-%m-%d %H:%M:%S")) + (format (concat "
    Generated with " + "Emacs %s, " + "Spacemacs %s, " + "Org Mode %s" + "
    ") + emacs-version spacemacs-version org-version) + "
    " + (menu '("↑ Top ↑")) + "
    ")) - (defun org-blog-sitemap-format-entry (entry _style project) - "Return string for each ENTRY in PROJECT." - (when (s-starts-with-p "posts/" entry) - (format "@@html:@@ %s: @@html:@@ [[file:%s][%s]] @@html:@@" - (format-time-string "%Y-%m-%d" - (org-publish-find-date entry project)) - entry - (org-publish-find-title entry project)))) +(defun org-blog-sitemap-format-entry (entry _style project) + "Return string for each ENTRY in PROJECT." + (when (s-starts-with-p "posts/" entry) + (format "@@html:@@ %s: @@html:@@ [[file:%s][%s]] @@html:@@" + (format-time-string "%Y-%m-%d" + (org-publish-find-date entry project)) + entry + (org-publish-find-title entry project)))) - (defun org-blog-sitemap-function (title list) - "Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry'." - (concat "#+TITLE: " title "\n" - "#+AUTHOR: " author-name "\n" - "#+EMAIL: " author-email "\n" - "\n#+begin_archive\n" - (mapconcat (lambda (li) - (format "@@html:
  • @@ %s @@html:
  • @@" (car li))) - (seq-filter #'car (cdr list)) - "\n") - "\n#+end_archive\n")) +(defun org-blog-sitemap-function (title list) + "Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry'." + (concat "#+TITLE: " title "\n" + "#+AUTHOR: " author-name "\n" + "#+EMAIL: " author-email "\n" + "\n#+begin_archive\n" + (mapconcat (lambda (li) + (format "@@html:
  • @@ %s @@html:
  • @@" (car li))) + (seq-filter #'car (cdr list)) + "\n") + "\n#+end_archive\n")) - (setq org-publish-project-alist - `(("orgfiles" - :base-directory ,base-dir - :exclude ".*drafts/.*" - :base-extension "org" +(defun org-blog-publish-to-html (plist filename pub-dir) + "Same as `org-html-publish-to-html' but modifies html before finishing." + (let ((file-path (org-html-publish-to-html plist filename pub-dir))) + (with-current-buffer (find-file-noselect file-path) + (goto-char (point-min)) + (search-forward "") + (insert (mapconcat 'identity + '("" + "" + "
    " + "
    " + "" + " / " + "" + "
    " + "
    " + "
    ") + "\n")) + (goto-char (point-max)) + (search-backward "") + (insert "\n
    \n") + (save-buffer) + (kill-buffer)) + file-path)) - :publishing-directory ,publish-dir +(setq org-publish-project-alist + `(("orgfiles" + :base-directory ,base-dir + :exclude ".*drafts/.*" + :base-extension "org" + :publishing-directory ,publish-dir - :recursive t - :preparation-function org-blog-prepare - :publishing-function org-html-publish-to-html + :recursive t + :preparation-function org-blog-prepare + :publishing-function org-blog-publish-to-html - :with-toc nil - :with-title nil - :with-date t - :section-numbers nil - :html-doctype "html5" - :html-html5-fancy t - :html-head-include-default-style nil - :html-head-include-scripts nil - :htmlized-source t - :html-head-extra ,org-blog-head - :html-preamble org-blog-preamble - :html-postamble org-blog-postamble + :with-toc nil + :with-title nil + :with-date t + :section-numbers nil + :html-doctype "html5" + :html-html5-fancy t + :html-head-include-default-style nil + :html-head-include-scripts nil + :htmlized-source t + :html-head-extra ,org-blog-head + :html-preamble org-blog-preamble + :html-postamble org-blog-postamble - :auto-sitemap t - :sitemap-filename "archive.org" - :sitemap-title "Blog Posts" - :sitemap-style list - :sitemap-sort-files anti-chronologically - :sitemap-format-entry org-blog-sitemap-format-entry - :sitemap-function org-blog-sitemap-function) + :auto-sitemap t + :sitemap-filename "archive.org" + :sitemap-title "Blog Posts" + :sitemap-style list + :sitemap-sort-files anti-chronologically + :sitemap-format-entry org-blog-sitemap-format-entry + :sitemap-function org-blog-sitemap-function) - ("assets" - :base-directory ,assets-dir - :base-extension ".*" - :publishing-directory ,publish-assets-dir - :publishing-function org-publish-attachment - :recursive t) + ("assets" + :base-directory ,assets-dir + :base-extension ".*" + :exclude ".*\.org$" + :publishing-directory ,publish-assets-dir + :publishing-function org-publish-attachment + :recursive t) - ("rss" - :base-directory ,rss-dir - :base-extension "org" - :html-link-home ,domainname - :html-link-use-abs-url t - :rss-extension "xml" - :publishing-directory ,publish-rss-dir - :publishing-function (org-rss-publish-to-rss) - :exclude ".*" - :include ("archive.org") - :section-numbers nil - :table-of-contents nil) + ("rss" + :base-directory ,rss-dir + :base-extension "org" + :html-link-home ,domainname + :html-link-use-abs-url t + :rss-extension "xml" + :publishing-directory ,publish-rss-dir + :publishing-function (org-rss-publish-to-rss) + :exclude ".*" + :include ("archive.org") + :section-numbers nil + :table-of-contents nil) - ("blog" :components ("orgfiles" "assets" "rss")))) + ("blog" :components ("orgfiles" "assets" "rss")))) - ;; add target=_blank and rel="noopener noreferrer" to all links by default - (defun my-org-export-add-target-blank-to-http-links (text backend info) - "Add target=\"_blank\" to external links." - (when (and - (org-export-derived-backend-p backend 'html) - (string-match "href=\"http[^\"]+" text) - (not (string-match "target=\"" text)) - (not (string-match (concat "href=\"" domainname "[^\"]*") text))) - (string-match "