Commit 60c92907 authored by Pierre-Antoine Rouby's avatar Pierre-Antoine Rouby 🤘🏻

blog: Initial commit.

* css/main.css: New file.
* images/efetch.png: New file.
* images/librepoll.png: New file.
* posts/hello.md: New file.
* haunt.scm: New file.
* README.md: New file.
parents
# Blog
## Build
Build website on `/site`.
```shell
haunt build
```
## Test
Open web server on `http://localhost:8080`.
```shell
haunt serve
```
/* main.css -- Portfolio css main theme.
*
* Copyright (C) 2019 by Pierre-Antoine Rouby <contact@parouby.fr>
*/
html {
font-size: 1.30em;
color: #212121;
background-color: #fcfcff;
vertical-align: middle;
margin: 0px;
font-family: Arial, Helvetica, sans-serif;
}
body {
margin-left: 15%;
margin-right: 15%;
}
h1 {
color: #e12121;
text-align: center;
margin: 0px;
padding: 15px;
}
h2 {
padding-left: 5px;
padding-right: 5px;
}
h3 {
padding-left: 10px;
padding-right: 10px;
}
a {
color: #e12121;
}
a:hover {
color: #5c5c5c;
}
.navlink {
text-decoration: none;
}
p {
padding-left: 25px;
padding-right: 25px;
}
.color-star {
color: #e12121;
}
img {
margin-left: auto;
margin-right: auto;
box-shadow: 3px 3px 5px #444444;
}
.centred-img {
display: block;
max-width: 100%;
}
.badges {
margin-left: 15px;
}
/* Nav */
.nav {
padding-top: 1rem;
padding-bottom: 1rem;
margin-bottom: 3rem;
border-bottom: 1px solid #444444;
}
.nav ul {
list-style-type: none;
display: inline-block;
margin: 0;
padding: 0;
}
.nav li {
display: inline;
padding: 1rem;
}
/* Code */
code {
color: #fcfcff;
background-color: #212121;
display: inline-block;
margin-left: 50px;
margin-right: auto;
padding: 15px;
box-shadow: 3px 3px 5px #444444;
border-radius: 5px;
font-size: small;
font-family: "Lucida Console", monospace;
}
.syntax-symbol {
color: #f14141;
font-weight: bold;
}
.syntax-string {
color: #70a0f2;
}
.syntax-comment {
color: #acacac;
font-style: italic;
}
.syntax-special {
color: #70a0f2;
}
/* Footer */
footer {
padding-top: 8px;
font-size: 0.75em;
border-top: 1px solid #444444;
}
;;; Copyright (C) 2019 Pierre-Antoine Rouby <contact@parouby.fr>
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public 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 Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see
;;; <http://www.gnu.org/licenses/>.
;; Some piece of code come from David Thompson blog (GPLv3+).
;; https://git.dthompson.us/blog.git
(use-modules (haunt asset)
(haunt builder blog)
(haunt builder atom)
(haunt builder assets)
(haunt html)
(haunt page)
(haunt post)
(haunt reader)
(haunt reader commonmark)
(haunt reader skribe)
(haunt site)
(haunt utils)
(commonmark)
(syntax-highlight)
(syntax-highlight scheme)
(syntax-highlight xml)
(syntax-highlight c)
(sxml match)
(sxml transform)
(srfi srfi-1)
(srfi srfi-19)
(ice-9 rdelim)
(ice-9 regex)
(ice-9 match))
;;;
;;; Theme
;;;
(define (nav-link label url)
`((a (@ (class "navlink")
(href ,url)) ,label)))
(define %cc-by-sa-link
'(a (@ (href "https://creativecommons.org/licenses/by-sa/4.0/"))
"Creative Commons Attribution Share-Alike 4.0 International"))
(define %cc-by-sa-button
'(a (@ (class "cc-button")
(href "https://creativecommons.org/licenses/by-sa/4.0/"))
(img (@ (src "https://licensebuttons.net/l/by-sa/4.0/80x15.png")))))
(define main-theme
(theme
#:name "main"
#:layout
(λ (site title body)
`((doctype "html")
(head
(meta (@ (charset "utf-8")))
(title ,(string-append title " - " (site-title site)))
(link (@ (rel "stylesheet")
(href ,(string-append "/css/main.css"))))
(body
(div (@ (class "nav"))
(ul (li ,(nav-link "Pierre-Antoine Rouby" "/"))
;; (li ,(nav-link "About" "/about.html"))
(li ,(nav-link "Curriculum Vitae" "/cv.html"))
(li ,(nav-link "My projects" "/projects.html"))
(li ,(nav-link "Blog" "/index.html"))))
,body
(footer
(p "© 2019 Pierre-Antoine Rouby "
,%cc-by-sa-button)
(p "The text on this site are free culture works available
under the " ,%cc-by-sa-link " license.")
(p "Powered by "
(a (@ (href "https://dthompson.us/projects/haunt.html"))
"Haunt")
" and Scheme with "
(a (@ (href "https://gnu.org/s/guile"))
"GNU Guile")
"."))))))
#:post-template
(λ (post)
`((h2 (@ (class "title")),(post-ref post 'title))
(div (@ (class "date"))
(em ,(date->string (post-date post)
"~d ~B ~Y")))
(div (@ (class "post"))
,(post-sxml post))))))
;;;
;;; Static page
;;;
(define (static-page title file-name body)
(lambda (site posts)
(make-page file-name
(with-layout main-theme site title body)
sxml->html)))
;;;
;;; Highlight
;;;
;; Some of highlight function come from David Thompson blog.
;; https://git.dthompson.us/blog.git
(define (maybe-highlight-code lang source)
(let ((lexer (match lang
('scheme lex-scheme)
('xml lex-xml)
('c lex-c)
(_ #f))))
(if lexer
(highlights->sxml (highlight lexer source))
source)))
(define (sxml-identity . args) args)
(define (highlight-code . tree)
(sxml-match tree
((code (@ (class ,class) . ,attrs) ,source)
(let ((lang (string->symbol
(string-drop class (string-length "language-")))))
`(code (@ ,@attrs)
,(maybe-highlight-code lang source))))
(,other other)))
(define (highlight-scheme code)
`(pre (code ,(highlights->sxml (highlight lex-scheme code)))))
(define %commonmark-rules
`((code . ,highlight-code)
(*text* . ,(lambda (tag str) str))
(*default* . ,sxml-identity)))
(define (post-process-commonmark sxml)
(pre-post-order sxml %commonmark-rules))
(define commonmark-reader*
(make-reader (make-file-extension-matcher "md")
(lambda (file)
(call-with-input-file file
(lambda (port)
(values (read-metadata-headers port)
(post-process-commonmark
(commonmark->sxml port))))))))
;;;
;;; About
;;;
;; (define about-page
;; (static-page
;; "About"
;; "about.html"
;; `((h2 "About")
;; (p "This is main page!"))))
;;;
;;; CV
;;;
(define my-cv-fr
'((info . (("Age" "24 ans")
("Lieu" "Bordeaux")))
(contact . (("email" "contact [at] parouby [dot] fr")
("Framagit" ("https://framagit.org/prouby" "@prouby"))
("Mastodon" ("https://framapiaf.org/@parouby"
"@framapiaf.org@parouby"))
("Atom Feed" ("/feed.xml" "parouby.fr/feed.xml"))
("Github" ("https://github.com/RoubyPA" "RoubyPA"))
("Linkedin" "Pierre-Antoine Rouby")))
(association . ((("April" "https://april.org") "2017")))
(project . (("librepoll" "Service de sondage en ligne libre.")
("efetch" "Extension à l'éditeur de texte Emacs pour
la récupération d'informations du système.")))
(contribution . ("GNU Guix" "Guile-sdl2"))
(loisir . ("Développement" "Administration système"
"Sage MP3" "Cinéma"))
(etude . (("Licence" "Licence informatique 2ème année"
"2018-2019" "Université de Bordeaux")))
(diplome . (("Licence pro" "Bac+3" "ADSILLH"
"2018" "Université de Bordeaux" "Major de promotion")
("BTS" "Bac+2" "SNIR"
"2016" "Lycée du Grésivaudan (Meylan)" "")
("BAC" "Bac" "STDI2D SIN"
"2014" "Briffaut Valence" "Mention Bien")))
(exp . (("Inria Bordeaux Sud-Ouest" "Stage LPro"
"Avril-Août 2018" "Talence"
("Définition de paquets GNU Guix"
"Intégration continue avec Gitlab-runner"
"Développement logiciel en Scheme (Guile)"))
("Ponant Technologies" "Technicien Informatique"
"2016-2017" "Valence"
("Test de solutions eUICC (chez Ingenico)"
"Mise en place et administration de BDD PostgreSQL (chez Ingenico)"))
("Acorel" "Stage BTS"
"6 semaine 2015" "Saint-Péray"
("Développement d'outils d'administration en C# et VBA"
"Installation d'un serveur rack"))))
(competence . (("Programmation"
(("C" 4)
("GNU Guile" 4)
("Elisp" 3)
("Python" 2)
("OCAML" 2)
("R" 1)
("Assembler" 1)))
("Outils"
(("Git" 4)
("Autotools" 2)
("Cmake" 2)))
("Système d'expoitation"
(("GuixSD" 4)
("Debian" 3)
("Centos" 2)
("OpenBSD" 1)))
("Base de données"
(("SQLite" 4)
("MariaDB" 2)
("PostgreSQL" 2)
("MongoDB" 1)))
("Office"
(("LaTeX" 4)
("Org" 4)
("Markdown" 3)
("LibreOffice" 2)))
("Jeu video"
(("Guile-sdl2" 3)
("SDL2" 2)))
("Transversales"
(("Anglais" 3)
("Italien" 1)))))))
(define (info->sxml l)
(define (infos l sxml)
(match l
(() sxml)
(((label value) . r)
(infos r (cons `(li (@ (class "li-info"))
,label " - " ,value)
sxml)))))
`((h3 "Informations")
,(cons* 'ul '(@ (class "ul-info"))
(infos l '()))))
(define (contact->sxml l)
(define (contacts l sxml)
(match l
(() sxml)
(((label (url displ)) . r)
(contacts r (cons `(li (@ (class "li-contact"))
(em ,(string-append label ":// "))
(a (@ (href ,url))
,displ))
sxml)))
(((label value) . r)
(contacts r (cons `(li (@ (class "li-contact"))
(em ,(string-append label ":// "))
,value)
sxml)))))
`((h3 "Contact")
,(cons* 'ul '(@ (class "ul-contact"))
(reverse (contacts l '())))))
(define (project->sxml l)
(define (linked name)
`(a (@ (href ,(string-append "/projects/" name ".html")))
,name))
(define (projects l sxml)
(match l
(() sxml)
(((label value) . r)
(projects r (cons `(li (@ (class "li-project"))
,(linked label) " - "
,value)
sxml)))))
`((h3 "Projects")
,(cons* 'ul '(@ (class "ul-project"))
(reverse (projects l '())))))
(define (association->sxml l)
(define (associations l sxml)
(match l
(() sxml)
((((label url) value) . r)
(associations r (cons `(li (@ (class "li-association"))
(strong (a (@ (href ,url))
,label))
" depuis " ,value)
sxml)))))
`((h3 "Association")
,(cons* 'ul '(@ (class "ul-association"))
(reverse (associations l '())))))
(define (etude->sxml l)
(define (etudes l sxml)
(match l
(() sxml)
(((type name year place) . r)
(etudes r (cons `(li (@ (class "li-etude"))
(strong ,type) " - " ,name (br)
,year " | " ,place)
sxml)))))
`((h3 "Etude en cours")
,(cons* 'ul '(@ (class "ul-etude"))
(reverse (etudes l '())))))
(define (diplome->sxml l)
(define (diplomes l sxml)
(match l
(() sxml)
(((type lvl name year place mention) . r)
(diplomes r (cons `(li (@ (class "li-diplome"))
(strong ,type) " (" ,lvl ") ",name (br)
,year " | " ,place " | " (em ,mention))
sxml)))))
`((h3 "Diplomes")
,(cons* 'ul '(@ (class "ul-diplome"))
(reverse (diplomes l '())))))
(define (exp->sxml l)
(define (work->sxml str)
`(li (@ (class "li-exp-work"))
,str))
(define (exps l sxml)
(match l
(() sxml)
(((inc type years place works) . r)
(exps r (cons `(li (@ (class "li-exp"))
(strong ,inc) " | " (em ,type) (br)
,years " | " ,place (br)
,(cons* 'ul '(@ (class "ul-exp-work"))
(map work->sxml works)))
sxml)))))
`((h3 "Experiences")
,(cons* 'ul '(@ (class "ul-exp"))
(reverse (exps l '())))))
(define (hobbies->sxml l)
(define (hobbies-map s)
`(li (@ (class "li-hobbies"))
,s))
`((h3 "Loisirs")
,(cons* 'ul '(@ (class "ul-hobbies"))
(map hobbies-map l))))
(define (competence->sxml l)
(define (make-color-star n)
(if (> n 0)
(string-append "★" (make-color-star (- n 1)))
""))
(define (make-li l)
(match l
((x n)
`(li (@ (class "li-with-star"))
,x " "
(span (@ (class "color-star"))
,(make-color-star n))
,(make-color-star (- 5 n))))))
(define (competences l sxml)
(match l
(() sxml)
(((type l) . r)
(competences r (cons `(li (@ (class "li-sub-competence"))
(h4 ,type)
,(cons* 'ul '(@ (class "ul-sub-competence"))
(map make-li l)))
sxml)))))
`((h3 "Compétences")
,(cons* 'ul '(@ (class "ul-competence"))
(reverse (competences l '())))))
(define (cv-alist->sxml alist)
`(,(info->sxml (assoc-ref alist 'info))
,(contact->sxml (assoc-ref alist 'contact))
,(association->sxml (assoc-ref alist 'association))
,(project->sxml (assoc-ref alist 'project))
,(hobbies->sxml (assoc-ref alist 'loisir))
,(etude->sxml (assoc-ref alist 'etude))
,(diplome->sxml (assoc-ref alist 'diplome))
,(exp->sxml (assoc-ref alist 'exp))
,(competence->sxml (assoc-ref alist 'competence))))
(define cv-page
(static-page
"Curriculum vitae"
"cv.html"
`((h2 "Curriculum Vitae")
,(cv-alist->sxml my-cv-fr))))
;;;
;;; Projects
;;;
(define (link label url)
`((a (@ (href ,url)) ,label)))
(define projects-page
(static-page
"Projects"
"projects.html"
`((h2 "My projects")
(ul
(li ,(link "Librepoll" "/porjects/librepoll.html"))
(li ,(link "Efetch" "/porjects/efetch.html"))))))
(define %framagit `(a (@ (href "https://framagit.org/"))
"Framagit"))
(define* (project-page #:key name file description
badges repo license)
(define body
`((h1 ,name)
,@(if badges
(map (λ (i)
`(img (@ (class "badges")
(src ,i))))
badges)
'())
,description
(h2 "Source Code")
(p ,name " is hosted on Framasoft Gitlab ("
,%framagit "). See the repo " (a (@ (href ,repo))
"here") ".")
(code ,(string-append "git clone " repo))
(h2 "License")
(p ,name "is Free Software under " (strong ,license))))
(static-page name (string-append "projects/" file) body))
(define librepoll-page
(project-page
#:name "LibrePoll"
#:file "librepoll.html"
#:description
`((p "Librepoll is a free opinion poll service. It's designed to be
self hosted service.")
(img (@ (class "centred-img")
(src "/images/librepoll.png")
(alt "LibrePoll screenshot."))))
#:badges
'("https://img.shields.io/badge/License-agpl3+-blue.svg?logo=gnu&logoColor=white"
"https://img.shields.io/badge/Release-0.0.0-blue.svg?logo=gitlab")
#:repo "https://framagit.org/prouby/librepoll"
#:license "GNU AGPL3+"))
(define efetch-page
(project-page
#:name "Efetch"
#:file "efetch.html"
#:description
`((p "Emacs extenction to see your system configuration.")
(img (@ (class "centred-img")
(src "/images/efetch.png")
(alt "Efetch screenshot."))))
#:badges
'("https://img.shields.io/badge/Release-0.0.5-blue.svg?logo=gitlab"
"https://img.shields.io/badge/Guix-local_package-yellow.svg?logo=gnu&logoColor=white"
"https://img.shields.io/badge/License-gpl3+-blue.svg?logo=gnu&logoColor=white"
"https://framagit.org/prouby/emacs-fetch/badges/master/pipeline.svg")
#:repo "https://framagit.org/prouby/emacs-fetch"
#:license "GNU GPL3+"))
;;;
;;; Site
;;;
(site #:title "Pierre-Antoine Rouby"
#:domain "parouby.fr"
#:default-metadata
'((author . "Pierre-Antoine Rouby")
(email . "contact@parouby.fr"))
#:readers (list skribe-reader commonmark-reader*)
#:builders (list (blog #:theme main-theme)