Browse Source

import the itix theme with its history

Imported from https://github.com/nmasse-itix/hugo-theme-itix (main, 7d4207e).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNHsWYTXPThURz6TbVS1j3
master
Nicolas Massé 1 month ago
parent
commit
0c667e53e8
  1. 21
      themes/itix/LICENSE
  2. 1
      themes/itix/README.md
  3. 1
      themes/itix/assets/css/.gitignore
  4. 859
      themes/itix/assets/css/itix.css
  5. 42
      themes/itix/i18n/en.yaml
  6. 42
      themes/itix/i18n/fr.yaml
  7. 9
      themes/itix/layouts/404.html
  8. 14
      themes/itix/layouts/_default/baseof.html
  9. 214
      themes/itix/layouts/_default/search.html
  10. 14
      themes/itix/layouts/_default/section.html
  11. 18
      themes/itix/layouts/_default/single.html
  12. 14
      themes/itix/layouts/_default/taxonomy.html
  13. 14
      themes/itix/layouts/_default/terms.html
  14. 14
      themes/itix/layouts/blog/list.html
  15. 24
      themes/itix/layouts/index.html
  16. 11
      themes/itix/layouts/partials/article-headline.html
  17. 146
      themes/itix/layouts/partials/head.html
  18. 16
      themes/itix/layouts/partials/icons/en.svg
  19. 6
      themes/itix/layouts/partials/icons/fr.svg
  20. 5
      themes/itix/layouts/partials/icons/label.svg
  21. 5
      themes/itix/layouts/partials/icons/link.svg
  22. 6
      themes/itix/layouts/partials/icons/rss_feed.svg
  23. 6
      themes/itix/layouts/partials/icons/schedule.svg
  24. 5
      themes/itix/layouts/partials/icons/search.svg
  25. 5
      themes/itix/layouts/partials/icons/vertical_align_top.svg
  26. 15
      themes/itix/layouts/partials/lang-detection.html
  27. 36
      themes/itix/layouts/partials/mathjax.html
  28. 65
      themes/itix/layouts/partials/menu.html
  29. 43
      themes/itix/layouts/partials/post-metadata.html
  30. 23
      themes/itix/layouts/partials/toolbar.html
  31. 7
      themes/itix/layouts/shortcodes/highlightFile.html
  32. 7
      themes/itix/layouts/shortcodes/highlightWithTitle.html
  33. 31
      themes/itix/layouts/shortcodes/internalLink.html
  34. 14
      themes/itix/layouts/speaking/list.html
  35. 14
      themes/itix/layouts/writing/list.html
  36. BIN
      themes/itix/static/fonts/JetBrainsMono-Regular.ttf
  37. BIN
      themes/itix/static/fonts/JetBrainsMono-Regular.woff
  38. BIN
      themes/itix/static/fonts/JetBrainsMono-Regular.woff2
  39. BIN
      themes/itix/static/fonts/SourceSansPro-Regular.ttf
  40. BIN
      themes/itix/static/fonts/SourceSerifPro-Regular.ttf
  41. BIN
      themes/itix/static/fonts/material-icons.ttf
  42. BIN
      themes/itix/static/fonts/material-icons.woff2
  43. 9
      themes/itix/static/js/fuse.js
  44. 19
      themes/itix/theme.toml

21
themes/itix/LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Nicolas Massé
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1
themes/itix/README.md

@ -0,0 +1 @@
# Theme for www.itix.fr

1
themes/itix/assets/css/.gitignore

@ -0,0 +1 @@
chroma.css

859
themes/itix/assets/css/itix.css

@ -0,0 +1,859 @@
:root {
/*
* Theme colors
*/
--main-color: #1870c9; /* Adjusted to ensure a 4.5:1 contrast ratio for accessibility */
--main-background-color: #fcfcfc;
--alternate-text-color: #145ca4;
--main-text-color: #092949; /* 50% darker than main-color */
--active-menu-background-color: #f4f8fb;
--active-menu-color: #0e4377;
--active-menu-border-color: #74abe3;
--hover-menu-background-color: #f4f8fb;
--hover-menu-color: #0e4377;
--hover-menu-border-color: #74abe3;
--post-metadata-color: #555;
--text-selection-background-color: #a2c7ec;
--quote-background-color: #f0f5fa;
--quote-border-color: #589bdd;
--codeblock-background-color: #ebf2f9;
--toc-background-color: #f0f5fa;
--pagination-disabled-color: #555;
--table-border-color: #092949;
/*
* Layout
*/
--menu-container-width: 25%;
--toolbar-container-width: 25%;
/*
* Fonts
*/
--default-font-list: "Source Serif Pro", serif;
--mono-font-list: "JetBrains Mono", monospace;
--sans-preferred-font-list: "Source Sans Pro", sans-serif;
}
/*
* Fonts
*/
@font-face{
font-family: 'JetBrains Mono';
src: url('/fonts/JetBrainsMono-Regular.woff2') format('woff2'),
url('/fonts/JetBrainsMono-Regular.woff') format('woff'),
url('/fonts/JetBrainsMono-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
/*
* Core Web Vitals / Cumulative Layout Shift.
*
* Avoid showing invisible text while custom fonts load.
*/
font-display: swap;
}
@font-face{
font-family: 'Source Serif Pro';
src: url('/fonts/SourceSerifPro-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
/*
* Core Web Vitals / Cumulative Layout Shift.
*
* Avoid showing invisible text while custom fonts load.
*/
font-display: swap;
}
@font-face{
font-family: 'Source Sans Pro';
src: url('/fonts/SourceSansPro-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
/*
* Core Web Vitals / Cumulative Layout Shift.
*
* Avoid showing invisible text while custom fonts load.
*/
font-display: swap;
}
/*
* General settings
*/
::selection {
/* Text selection uses the theme main color with some transparency */
background: var(--text-selection-background-color);
}
body {
background: var(--main-background-color);
padding: 0;
margin: 0;
font-family: var(--default-font-list);
color: var(--main-text-color);
}
* {
/* By default in the CSS box model, the width and height you assign to an
* element is applied only to the element's content box. If the element has
* any border or padding, this is then added to the width and height to arrive
* at the size of the box that's rendered on the screen. This means that when
* you set width and height, you have to adjust the value you give to allow
* for any border or padding that may be added.
*
* border-box tells the browser to account for any border and padding in the
* values you specify for an element's width and height. If you set an element's
* width to 100 pixels, that 100 pixels will include any border or padding you
* added, and the content box will shrink to absorb that extra width.
* This typically makes it much easier to size elements.
*/
box-sizing: border-box;
}
/*
* Heading and figure numbering
*/
main, #TableOfContents {
/*
* all counters need to be specified on one single line
* and they have to be reset on an enclosing element
*/
counter-reset: h2 figcaption;
}
h2::before, #TableOfContents > ul > li::before {
content: counter(h2) ".\0000a0\0000a0"; /* \0000a0 => Non-breakable space */
counter-increment: h2;
}
h2, #TableOfContents > ul > li {
counter-reset: h3;
}
h3::before, #TableOfContents > ul > li > ul > li::before {
content: counter(h2) "." counter(h3) ".\0000a0\0000a0";
counter-increment: h3;
}
figcaption::before {
/*
* When the numbering is done in CSS, we cannot honor typographical
* conventions of the user language. So, here I chose the english convention
* with no space before the colon and a space after.
*/
content: "Figure " counter(figcaption) ": ";
counter-increment: figcaption;
}
/*
* Main content formatting
*/
h1, h2, h3 {
font-weight: bold;
line-height: 1.5em;
}
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 20px 0;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 21px;
}
h4 {
font-size: 21px;
}
h5 {
font-size: 20px;
}
h6 {
font-size: 19px;
}
figure {
margin: 0;
}
figure figcaption {
font-style: italic;
}
ul {
list-style-type: "\2013\0000a0";
list-style-position: outside;
}
textarea,
select,
input,
button {
outline: none !important;
}
main table {
table-layout: fixed;
overflow-x: scroll;
border-collapse: collapse;
width: 100%;
table-layout: auto;
}
main table td, main table th {
border: 1px solid var(--table-border-color);
padding: 0.2rem 0.5rem;
}
button {
cursor: pointer;
}
blockquote {
padding: 10px 20px;
border-left: 3px solid var(--quote-border-color);
color: var(--alternate-text-color);
background: var(--quote-background-color);
}
blockquote p {
margin-bottom: 0;
}
blockquote * {
color: var(--alternate-text-color);
}
a {
color: var(--main-color);
}
a:hover {
color: var(--alternate-text-color);
}
/*
* Code block
*/
pre.chroma {
/* Overide the default chroma background color with ours */
background: var(--codeblock-background-color);
}
/* Code block (three backticks in markdown) */
pre {
background: var(--codeblock-background-color);
padding: 12px 15px;
border-radius: 5px;
font-family: var(--mono-font-list);
/* Do not wrap lines of code */
overflow-x: hidden;
/* Hide scrollbar for IE, Edge and Firefox */
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* Hide scrollbar for Chrome, Safari and Opera */
pre::-webkit-scrollbar {
display: none;
}
/* Inline code (single backticks in markdown) */
code {
color: var(--alternate-text-color);
background: var(--codeblock-background-color) !important;
padding: 2px 5px;
border-radius: 3px;
font-family: var(--mono-font-list);
}
/*
* And because there is a code tag inside a pre tag for Markdown code blocks,
* we need to overide some properties
*/
pre code {
background: none !important;
font-family: var(--mono-font-list) !important;
padding: 0;
}
/*
* Highlighted file has a wrapping div. Some properties are redefined for it
* and reset to their default value for its children.
*/
.highlightedFile {
background: var(--codeblock-background-color);
border-radius: 5px;
}
.highlightedFile .filename {
border-bottom: 2px solid var(--hover-menu-border-color);
font-family: var(--sans-preferred-font-list) !important;
font-size: larger;
padding: 12px 15px;
}
.highlightedFile pre {
background: inherit;
border-radius: inherit;
padding: 12px 15px;
margin: 0;
}
pre:hover {
/* Show the horizontal scroll bar when hovering code (if needed) */
overflow-x: auto;
}
/*
* i18n
*/
.tiny-flag {
vertical-align: middle;
margin-left: 5px;
margin-right: 5px;
}
/*
* Pagination
*/
.pagination {
list-style: none;
padding: 0;
text-align: center;
font-size: larger;
}
.pagination .page-item {
display: inline;
margin: 5px;
}
.pagination .disabled {
color: var(--pagination-disabled-color);
}
.pagination .active {
font-weight: bold;
}
/*
* Article list
*/
.article-list p {
/* Move the excerpt closer to the metadata */
margin-top: 0.5em;
/* Add spacing around each item of the list */
margin-bottom: 2.5em;
}
.article-list h4 {
/* Move the title closer to the metadata */
margin-bottom: 0.5em;
}
.article-list .post-metadata {
/* Fade the metadata */
color: var(--post-metadata-color);
}
.article-list .continue-reading {
/* Leave some space between the excerpt and the "continue reading" link */
margin-left: 0.5em;
}
/*
* Post Metadata (valid for the "list" and "single" views)
*/
.post-metadata .material-icons {
vertical-align: sub;
margin-right: 3px;
margin-left: 5px;
max-height: 1rem;
}
.post-metadata time {
/* Leave some space between publication date and taxonomies */
margin-right: 20px;
}
article .post-metadata {
/* Leave some space between the metadata and the title */
margin-top: 20px;
}
/*
* Single post layout
*/
article {
padding: 50px 35px 20px 35px;
font-size: 16px;
line-height: 1.5em;
}
article img, article video {
max-width: 100%;
height: auto;
border-radius: 5px;
overflow: hidden;
}
article p {
text-align: justify;
text-justify: inter-word;
}
article header {
padding-bottom: 30px;
font-style: normal;
line-height: 1.5em;
/* Align the site title with the article title */
padding-top: 11px;
}
/* Article title */
article header h1 {
font-size: 30px;
margin: 0;
}
/* Article subtitle */
article header h4 {
font-size: 18px;
opacity: 0.6;
padding: 0px 0 8px 0;
}
/*
* Menu (left side)
*/
.menu-lang {
padding-right: 28px;
}
.menu-head, .menu-link-list a, .menu-head:hover, .menu-link-list a:hover {
display: block;
text-decoration: none !important;
cursor: pointer;
border-right: 2px solid transparent;
}
.menu-head.active, .menu-link-list a.active {
border-right: 2px solid var(--active-menu-border-color);
background: var(--active-menu-background-color);
color: var(--active-menu-color);
}
.menu-head:hover, .menu-link-list a:hover {
border-right: 2px solid var(--hover-menu-border-color);
background: var(--hover-menu-background-color);
color: var(--hover-menu-color);
}
.menu-footer {
padding: 20px 30px 0 20px;
font-size: 12px;
}
.menu-head {
padding: 30px 28px 30px 20px;
margin-bottom: 10px;
color: var(--main-text-color);
}
.menu-title {
--menu-title-size: 30px;
font-size: var(--menu-title-size);
line-height: calc(var(--menu-title-size) * 1.4);
}
.menu-subtitle {
margin-top: 8px;
font-size: 18px;
}
.menu-link-list {
flex-grow: 1;
}
.menu-link-list a {
font-size: 20px;
margin-bottom: 10px;
padding: 8px 28px 8px 30px;
color: var(--main-text-color);
}
.menu-content {
position: fixed;
top: 0;
height: 100vh;
width: var(--menu-container-width);
text-align: right;
font-family: var(--sans-preferred-font-list);
padding: 20px 0 50px 0;
display: flex;
flex-direction: column;
justify-content: space-between;
/* Below the hamburger menu but on top of the overlay */
z-index: 253;
}
/*
* Hamburger menu
*/
.menu input.hamburger-menu {
display: block;
width: 80px;
height: 72px;
position: fixed;
top: 0px;
left: 0px;
margin: 0;
cursor: pointer;
opacity: 0; /* hide this */
z-index: 255; /* and place it over the hamburger */
-webkit-touch-callout: none;
}
/*
* Draw the hamburger
*/
.menu div.hamburger-menu {
width: 32px;
height: 4px;
position: fixed;
left: 24px;
background: var(--main-text-color);
border-radius: 3px;
z-index: 254;
transform-origin: center;
transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
opacity 0.55s ease;
}
.menu div.hamburger-menu:nth-child(2) {
top: 25px;
}
.menu div.hamburger-menu:nth-child(3) {
top: 34px;
}
.menu div.hamburger-menu:nth-child(4) {
top: 43px;
}
/* Transform all the slices of hamburger into a crossmark. */
.menu input.hamburger-menu:checked ~ div.hamburger-menu:nth-child(2) {
opacity: 1;
transform: translate(0, 9px) rotate(45deg);
}
/* But let's hide the middle one. */
.menu input.hamburger-menu:checked ~ div.hamburger-menu:nth-child(3) {
opacity: 0;
transform: rotate(0deg) scale(0.2, 0.2);
}
/* And the last one should go the other direction */
.menu input.hamburger-menu:checked ~ div.hamburger-menu:nth-child(4) {
transform: translate(0, -9px) rotate(-45deg);
}
/* On mobile browsers, keep a title displayed on top */
.menu .mobile-title {
padding: 20px 80px 20px 80px;
margin: 0;
width: 100%;
height: 80px;
line-height: 40px; /* line-height = height - padding-top - padding-bottom */
text-align: center;
font-size: calc(var(--heading1-size) - 3 * var(--heading-diff));
font-weight: bold;
position: fixed;
box-shadow: 0 0 16px rgba(0, 0, 0, 0.12);
background-color: var(--main-background-color);
}
/* But hide them by default. They will be uncovered when needed by media queries */
.menu .hamburger-menu, .menu .mobile-title {
display: none;
}
/*
* Toolbar (right side)
*/
.toolbar {
position: fixed;
top: 0;
right: 0;
width: var(--toolbar-container-width);
font-family: var(--sans-preferred-font-list);
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.actions {
position: fixed;
bottom: 0;
display: flex;
flex-direction: row;
margin-bottom: 50px;
margin-left: 30px;
}
.actions .action {
display: flex;
flex-direction: column;
cursor: pointer;
margin-right: 10px;
}
.actions a {
text-decoration: none;
color: var(--main-text-color);
}
.actions a:visited {
color: var(--main-text-color);
}
.actions .material-icons {
height: 2rem;
width: auto;
}
/*
* Search page
*/
.search input {
width: 100%;
}
@media screen {
/*
* Main part of the page (center)
*
* Enclosed in @media screen block because this style is not desired for
* printing.
*/
main {
padding-left: var(--menu-container-width);
padding-right: var(--toolbar-container-width);
width: 100%;
min-height: 100vh;
}
/* Immediate children of main gets a left/right shadow */
main > * {
box-shadow: 0 0 16px rgba(0, 0, 0, 0.12);
min-height: 100vh;
}
}
/*
* Table of content (within the toolbar on the right)
*/
.toc {
float: right;
border-radius: 5px;
margin-left: 30px;
margin-right: 60px;
margin-top: 30px;
max-width: 260px;
max-height: 80vh;
overflow: auto;
background: var(--toc-background-color);
padding: 20px;
font-size: 16px;
}
.toc ul {
list-style: none;
padding: 0;
margin: 0;
line-height: 1.7em;
}
.toc h4 {
text-align: center;
margin: 0 0 10px 0;
}
/* Mathjax container */
mjx-container {
overflow-y: hidden !important;
}
/*
* Reactive tweaks
*/
@media screen and (max-width: 1440px) {
:root {
--menu-container-width: 20%;
}
}
@media screen and (max-width: 1280px) {
.toc {
display: none;
}
:root {
--toolbar-container-width: 5%;
}
}
@media screen and (max-width: 1140px) {
article {
padding: 30px 20px 20px 20px;
}
main {
padding: 0;
min-height: unset;
}
.toolbar {
display: none;
}
.toc {
line-height: 2em;
float: none;
margin-top: 30px;
margin-left: 0;
margin-right: 0;
}
/*
* On mobile devices, there are no :hover events. So we must always
* propose horizontal scrollbars when needed.
*/
pre {
overflow-x: auto;
}
.menu .hamburger-menu, .menu .mobile-title {
display: block;
}
/*
* On mobile, leave some room above the article so that the title + hamburger
* menu do not hide the article title.
*/
main > *:first-child {
padding-top: 110px;
}
.menu .menu-content {
width: 300px;
left: -300px;
height: 100vh;
background-color: var(--main-background-color);
position: fixed;
transform: none;
transition: transform 0.2s linear;
}
.menu .menu-overlay {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
transition: background-color 0.2s linear;
/*
* Put the overlay on the bottom of the stack so that it does not catch
* click events.
*/
z-index: -1;
}
/*
* When the hamburger menu is clicked, show the menu content and enable
* the overlay that hides the article content.
*/
.menu input.hamburger-menu:checked ~ .menu-content {
transform: translate(300px, 0);
}
.menu input.hamburger-menu:checked ~ .menu-overlay {
/* Semi transparent background */
background-color: rgba(0, 0, 0, 0.5);
/* Below the hamburger menu, the menu content but over the article content */
z-index: 250;
}
/*
* Leave some room between the list items in the term pages so that it is
* easier to click on mobile. Also makes Google happy.
*/
.terms ul li {
line-height: 2em;
}
}
@media screen and (max-width: 512px) {
/*
* On mobile, hide some post metadata
*/
.post-metadata .opensource, .post-metadata .topic, .post-metadata .reading-time {
display: none;
}
}
/*
* Tweaks for printing
*/
@media print {
.menu, .menu-content, .hamburger-menu, .toolbar {
display: none !important;
}
/* Since you cannot scroll horizontally on a paper, wrap the code blocks */
pre {
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
}
}

42
themes/itix/i18n/en.yaml

@ -0,0 +1,42 @@
- id: last_modify_on
translation: Last modified on
- id: published_on
translation: Published on
- id: date_format
translation: "January 2, 2006"
- id: toc
translation: Table of contents
- id: back_to_top
translation: Top of the page
- id: minutes
translation:
one: '{{ .Count }} minute'
other: '{{ .Count }} minutes'
- id: continue_reading
translation: Continue reading
- id: articles_related_to
translation: Articles related to
- id: recent_articles
translation: Recent articles
- id: not_found
translation: This page does not exist!
- id: go_home
translation: Go Home
- id: search
translation: Search
- id: search_here
translation: Search something...
- id: type_blog
translation: Article
- id: type_writing
translation: Writing
- id: type_speaking
translation: Speaking
- id: type_page
translation: Misc.
- id: show_menu
translation: Show the menu
- id: file
translation: 'File "%s"'
- id: rss_feed
translation: 'RSS Feed'

42
themes/itix/i18n/fr.yaml

@ -0,0 +1,42 @@
- id: last_modify_on
translation: Dernière modification le
- id: published_on
translation: Publié le
- id: date_format
translation: "02/01/2006"
- id: toc
translation: Sommaire
- id: back_to_top
translation: Retour en haut de la page
- id: minutes
translation:
one: '{{ .Count }} minute'
other: '{{ .Count }} minutes'
- id: continue_reading
translation: Continuer la lecture
- id: articles_related_to
translation: Articles concernant
- id: recent_articles
translation: Articles récents
- id: not_found
translation: Cette page n'existe pas !
- id: go_home
translation: Retour à la page d'accueil
- id: search
translation: Recherche
- id: search_here
translation: Rechercher quelque chose...
- id: type_blog
translation: Article
- id: type_writing
translation: Publication
- id: type_speaking
translation: Conférence
- id: type_page
translation: Divers
- id: show_menu
translation: Afficher le menu
- id: file
translation: 'Fichier "%s"'
- id: rss_feed
translation: 'Flux RSS'

9
themes/itix/layouts/404.html

@ -0,0 +1,9 @@
{{ define "main" }}
<!-- The "404" layout prints the classical 404 error -->
<article class="post">
<header>
<h1>{{ i18n "not_found" }}</h1>
</header>
<p><a href="{{ .Site.Home.RelPermalink }}">{{ i18n "go_home" }}</a></p>
</article>
{{ end }}

14
themes/itix/layouts/_default/baseof.html

@ -0,0 +1,14 @@
<!-- the baseof.html layout is the entrypoint for every page -->
<!DOCTYPE html>
<html lang="{{ .Lang }}">
{{ partial "head.html" . }}
<body>
<!-- HTML Anchor used by the button "back to top" -->
<a name="top"></a>
{{ partial "menu.html" . }}
{{ partial "toolbar.html" . }}
<main>
{{ block "main" . }}{{- end }}
</main>
</body>
</html>

214
themes/itix/layouts/_default/search.html

@ -0,0 +1,214 @@
{{ define "main" }}
<!-- The "search/index.html" layout renders the search engine -->
<article class="search article-list">
<header>
<h1>{{ .Title }}</h1>
{{- with .Description }}
<h4>{{ . }}</h4>
{{- end }}
</header>
{{ .Content }}
<input id="searchInput" tabindex="0" placeholder="{{ i18n "search_here" }}" autofocus>
<div id="searchResults">
</div>
<div style="display: none;" id="image-store">
{{- range $_, $file := (slice "en" "fr" "label" "link" "schedule") -}}
<div id="embedded-svg-{{ $file }}">
{{- partial (printf "icons/%s.svg" $file) . -}}
</div>
{{- end }}
</div>
<script type="text/javascript">
var searchResults = document.getElementById('searchResults'); // targets the <div> above
var searchInput = document.getElementById('searchInput'); // input box for search
var lastSearch = "";
// Helper function to create an element with attributes
function tag(name, attrs) {
var el = document.createElement(name.toString());
!!attrs && Object.keys(attrs).forEach(function(key) {
el.setAttribute(key, attrs[key]);
});
return el;
}
function printSearchResult(result) {
var section = tag("section");
//
// Article headline
//
var a = tag("a", { href: result.item.permalink });
a.textContent = result.item.title;
if (result.item.hasEnFlag) {
var uk_flag_svg = document.getElementById("embedded-svg-en");
if (uk_flag_svg != null) {
var img = uk_flag_svg.firstChild.cloneNode(true);
a.appendChild(img);
}
}
var h4 = tag("h4");
h4.textContent = result.item.type_label + " >> ";
h4.appendChild(a);
section.appendChild(h4);
//
// Metadata
//
if (result.item.type != "page") {
var div = tag("div", { 'class': 'post-metadata'});
var span_date = tag("span", { 'class': 'publication-date' });
span_date.textContent = {{ i18n "published_on" }} + " " + result.item.date;
div.appendChild(span_date);
if (result.item.topics != null) {
result.item.topics.forEach(function (v) {
var topic_detail = taxonomies.topics[v];
if (topic_detail == null) {
return;
}
var span = tag("span", { 'class': 'topic' });
var link_svg = document.getElementById("embedded-svg-link");
if (link_svg != null) {
var img = link_svg.firstChild.cloneNode(true);
span.appendChild(img);
}
var a = tag("a", { href: topic_detail.href });
a.textContent = topic_detail.title;
span.appendChild(a);
div.appendChild(span);
});
}
if (result.item.opensource != null) {
result.item.opensource.forEach(function (v) {
var opensource_detail = taxonomies.opensource[v];
if (opensource_detail == null) {
return;
}
var span = tag("span", { 'class': 'opensource' });
var label_svg = document.getElementById("embedded-svg-label");
if (label_svg != null) {
var img = label_svg.firstChild.cloneNode(true);
span.appendChild(img);
}
var a = tag("a", { href: opensource_detail.href });
a.textContent = opensource_detail.title;
span.appendChild(a);
div.appendChild(span);
});
}
if (result.item.reading_time != null) {
var span = tag("span", { 'class': 'reading-time' });
var schedule_svg = document.getElementById("embedded-svg-schedule");
if (schedule_svg != null) {
var img = schedule_svg.firstChild.cloneNode(true);
span.appendChild(img);
}
var readingTime = document.createTextNode(result.item.reading_time);
span.appendChild(readingTime);
div.appendChild(span);
}
section.appendChild(div);
}
var p = tag("p", {});
p.textContent = result.item.summary;
var a = tag("a", { href: result.item.permalink, 'class': 'continue-reading' });
a.textContent = {{ i18n "continue_reading" }};
p.appendChild(a);
section.appendChild(p);
searchResults.appendChild(section);
}
function clearSearchResults() {
var child = searchResults.lastElementChild;
while (child) {
searchResults.removeChild(child);
child = searchResults.lastElementChild;
}
}
//
// load the search index
//
function fuseInit(searchDb) {
var options = { // fuse.js options; check fuse.js website for details
shouldSort: true,
ignoreLocation: true,
threshold: 0.4,
minMatchCharLength: 3,
keys: [
'title',
'permalink',
'summary',
'topics',
'opensource'
]
};
fuse = new Fuse(searchDb, options); // build the index from the json file
}
//
// using the index loaded previously, run a search query (for "term")
// every time a letter is typed in the search box
//
function executeSearch(term) {
if (lastSearch == term) {
// Don't query Fuse if the search terms have not changed
return;
}
clearSearchResults();
let results = fuse.search(term);
results.slice(0, 20).forEach(printSearchResult);
lastSearch = term;
}
// Fill-in details about taxonomies
{{- $.Scratch.Set "taxonomies" dict -}}
{{- range $name, $taxonomy := .Site.Taxonomies -}}
{{- $.Scratch.Set "taxonomy" dict -}}
{{- range (index $.Site.Taxonomies $name) -}}
{{- $.Scratch.SetInMap "taxonomy" .Page.Title (dict "href" .Page.RelPermalink "title" .Page.Title) -}}
{{- end -}}
{{- $.Scratch.SetInMap "taxonomies" $name ($.Scratch.Get "taxonomy") -}}
{{- end }}
var taxonomies = {{- $.Scratch.Get "taxonomies" | jsonify | safeJS -}};
// Fill-in the Search DB with site's content
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}
{{- $.Scratch.Set "reading_time" nil -}}
{{- if eq .Type "blog" -}}
{{- $minutes := .ReadingTime -}}
{{- if gt $minutes 0 -}}
{{- $.Scratch.Set "reading_time" (i18n "minutes" $minutes) -}}
{{- end -}}
{{- end -}}
{{- $.Scratch.Set "date" nil -}}
{{- if ne .Type "page" -}}
{{- $.Scratch.Set "date" (.Date.Format (i18n "date_format")) -}}
{{- end -}}
{{ .Scratch.Set "en_article_in_fr_site" false }}
{{- partial "lang-detection.html" . -}}
{{- $.Scratch.Add "index" (dict "title" .Title "opensource" .Params.opensource "topics" .Params.topics "permalink" .Permalink "hasEnFlag" (.Scratch.Get "en_article_in_fr_site") "type" .Type "type_label" (i18n (print "type_" .Type)) "date" ($.Scratch.Get "date") "reading_time" ($.Scratch.Get "reading_time") "summary" (.Summary | plainify | htmlUnescape)) -}}
{{- end }}
var searchDb = {{- $.Scratch.Get "index" | jsonify | safeJS -}};
// Initialize the Fuse.io framework with the Search DB
fuseInit(searchDb);
//
// execute search as each character is typed
//
searchInput.onkeyup = function(e) {
executeSearch(this.value);
}
</script>
</article>
{{ end }}

14
themes/itix/layouts/_default/section.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the section.html layout is used to render a list of articles under writing, speaking, etc. -->
<article class="section">
<header>
<h1>{{ .Title }}</h1>
</header>
{{ .Content }}
<ul>
{{ range (sort .Pages "Date").Reverse }}
<li><a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>
</article>
{{ end }}

18
themes/itix/layouts/_default/single.html

@ -0,0 +1,18 @@
{{ define "main" }}
<!-- The "single" layout prints a single post -->
{{- partial "lang-detection.html" . -}}
<article class="post" {{ if .Scratch.Get "en_article_in_fr_site" }}lang="en"{{ end }}>
<header>
<h1>{{ .Title }}</h1>
{{- with .Description }}
<h4>{{ . }}</h4>
{{- end }}
{{ partial "post-metadata.html" (dict "current" . "parent" .) -}}
</header>
{{ .Content }}
{{- if and (not .Lastmod.IsZero) (ne .Lastmod .PublishDate) }}
<hr width="100%" id="EOF">
<p>{{ i18n "last_modify_on" }} {{ .Lastmod.Format (i18n "date_format") }}</p>
{{- end }}
</article>
{{ end }}

14
themes/itix/layouts/_default/taxonomy.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the taxonomy.html layout is used to render the list of posts having a certain tag, topic, etc. -->
<article class="article-list">
<header>
<h1>{{ .Title }}</h1>
</header>
{{ i18n "articles_related_to" }} <a href="{{.Parent.RelPermalink}}">{{.Parent.Title}}</a> / <a href="{{.RelPermalink}}">{{ .Title }}</a>:
{{ .Content }}
{{ range (.Paginate (sort .Pages "Date").Reverse).Pages }}
{{- partial "article-headline.html" (dict "current" . "parent" $.Page) -}}
{{ end }}
{{ template "_internal/pagination.html" . }}
</article>
{{ end }}

14
themes/itix/layouts/_default/terms.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the terms.html layout is used to render the list of values of a certain tag, topic, etc. -->
<article class="terms">
<header>
<h1>{{ .Title }}</h1>
</header>
{{ .Content }}
<ul>
{{ range sort .Pages "Title" }}
<li><a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>
</article>
{{ end }}

14
themes/itix/layouts/blog/list.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the blog/list.html layout is used to render the list of posts under "blog" -->
<article class="article-list">
<header>
<h1>Articles</h1>
</header>
{{ .Content }}
{{ range (.Paginate (sort .Pages "Date").Reverse).Pages }}
{{- partial "article-headline.html" (dict "current" . "parent" $.Page) -}}
{{ end }}
{{ template "_internal/pagination.html" . }}
</article>
{{ end }}

24
themes/itix/layouts/index.html

@ -0,0 +1,24 @@
{{ define "main" }}
<!-- the index.html layout is used only to render the home page -->
<div>
<article class="bio">
<!--
<header>
<h1>{{ .Title }}</h1>
{{ if .Params.description }}
<h2>{{ .Params.description }}</h2>
{{ end }}
</header>
-->
{{ .Content }}
</article>
<article class="article-list">
<header>
<h1>{{ i18n "recent_articles" }}</h1>
</header>
{{ range first 5 (sort ((.Site.GetPage "/blog").Pages) "Date").Reverse }}
{{- partial "article-headline.html" (dict "current" . "parent" $.Page) -}}
{{ end }}
</article>
</div>
{{ end }}

11
themes/itix/layouts/partials/article-headline.html

@ -0,0 +1,11 @@
<section>
<h4><a href="{{ .current.RelPermalink }}">{{ .current.Title }}
{{- partial "lang-detection.html" .current -}}
{{ if .current.Scratch.Get "en_article_in_fr_site" }}
{{- partial "icons/en.svg" . -}}
{{ end }}
</a></h4>
{{- partial "post-metadata.html" . -}}
<p>{{ .current.Summary | plainify | htmlUnescape }} <a href="{{ .current.RelPermalink }}" class="continue-reading">{{ i18n "continue_reading" }}</a></p>
</section>

146
themes/itix/layouts/partials/head.html

@ -0,0 +1,146 @@
<head>
<title>{{.Title}}</title>
<meta charset="utf-8">
<!--
-- Package all CSS files together and minify them.
-- The page loading time should improve.
-->
{{ $chroma := resources.Get "css/chroma.css" }}
{{ $itix := resources.Get "css/itix.css" }}
{{ $css := slice $chroma $itix | resources.Concat "css/itix.css" | resources.Minify | resources.Fingerprint "sha512" }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}">
<!--
-- Core Web Vitals / Cumulative Layout Shift.
--
-- Preload all fonts and images to reduce layout shifts.
-->
<link rel="preload" href="/fonts/JetBrainsMono-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/fonts/JetBrainsMono-Regular.woff" as="font" type="font/woff" crossorigin="anonymous">
<link rel="preload" href="/fonts/JetBrainsMono-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preload" href="/fonts/SourceSerifPro-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<link rel="preload" href="/fonts/SourceSansPro-Regular.ttf" as="font" type="font/ttf" crossorigin="anonymous">
<!--
-- Add a reference to the favicon.ico.
-- The file needs to be added in the "static" directory.
-->
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<!--
-- Ensure the <meta name=description> tag is never empty since it is used
-- in the SEO score.
-->
{{- if .IsHome }}
{{- with .Site.Params.description }}
<meta name="description" content="{{ . }}">
{{- else }}
<meta name="description" content="{{ .Title }}">
{{- end }}
{{- else }}
{{- with .Params.description }}
<meta name="description" content="{{ . }}">
{{- else }}
<meta name="description" content="{{ .Title }}">
{{- end }}
{{- end }}
<!-- Add all the relevant RSS Feed URLs -->
{{ with .OutputFormats.Get "rss" -}}
{{ printf `<link rel=%q type=%q href=%q title=%q>` .Rel .MediaType.Type .Permalink site.Title | safeHTML }}
{{ end }}
<!-- Tell IE to use the Edge engine -->
<meta name="X-UA-Compatible" content="IE=edge">
<!--
-- The viewport is the user's visible area of a web page.
-- The viewport varies with the device, and will be smaller on a mobile phone
-- than on a computer screen.
--
-- This meta tag let web designers take control over the viewport.
--
-- The width property controls the size of the viewport. It can be set to
-- the special value device-width, which is the width of the screen in CSS
-- pixels at a scale of 100%.
--
-- The initial-scale=1.0 part sets the initial zoom level when the page
-- is first loaded by the browser.
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{ template "_internal/opengraph.html" . }}
{{ template "_internal/twitter_cards.html" . }}
<!-- The search page is the only one to require Javascript -->
{{ if eq .Type "search" }}
<!--
-- Download and copy over fuse.js file from fusejs.io.
-- I used the UMD build, minified, version 6.4.3
-->
<script src="/js/fuse.js"></script>
{{ end }}
{{- if .Site.Params.enablePlausible -}}
<script defer data-domain="itix.fr" src="https://plausible.io/js/plausible.js"></script>
{{- end -}}
{{- if .Params.enableMathJax -}}
{{- partial "mathjax.html" . -}}
{{- end -}}
<!-- Deal with the case of english articles published in the french site -->
{{- partial "lang-detection.html" . -}}
{{- if .IsTranslated -}}
{{- range .Translations -}}
{{- if .Scratch.Get "en_article_in_fr_site" -}}
<!--
-- It's an english article published in the french site
-- Tell Google not to index it and link to the original article.
--
-- See https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls
-->
<link rel="canonical" href="{{ .Permalink }}">
<meta name="robots" content="noindex">
{{ else }}
<!-- Otherwise, just link to the available translations, if any. -->
<link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}" title="{{ .Language.LanguageName }}">
{{ end -}}
{{- end -}}
{{- end -}}
<!--
-- Structured Data can be tested using the Google Search Console.
-- https://search.google.com/test/rich-results
-->
{{- if .IsHome -}}
{{- $.Scratch.Set "structured_data" (dict "@context" "http://schema.org" "@type" "WebSite" "name" .Site.Title "url" .Site.BaseURL) -}}
{{- with .Site.Params.subtitle -}}
{{- $.Scratch.SetInMap "structured_data" "description" . -}}
{{- end -}}
{{- else if and .IsPage (eq .Section "blog") -}}
{{- $.Scratch.Set "structured_data" (dict "@context" "http://schema.org" "@type" "BlogPosting" "headline" .Title "image" (slice) "articleSection" .Section) -}}
{{- if and (eq .Lang "fr") (.Scratch.Get "en_article_in_fr_site") -}}
{{- $.Scratch.SetInMap "structured_data" "inLanguage" "en" -}}
{{- range first 1 .Translations -}}
{{- $.Scratch.SetInMap "structured_data" "mainEntityOfPage" (dict "@type" "WebPage" "@id" .Permalink) -}}
{{- end -}}
{{- else -}}
{{- $.Scratch.SetInMap "structured_data" "inLanguage" .Language.Lang -}}
{{- $.Scratch.SetInMap "structured_data" "mainEntityOfPage" (dict "@type" "WebPage" "@id" .Permalink) -}}
{{- end -}}
{{- if not .PublishDate.IsZero -}}
{{- $.Scratch.SetInMap "structured_data" "datePublished" .PublishDate -}}
{{- end -}}
{{- if and (not .Lastmod.IsZero) (ne .Lastmod .PublishDate) -}}
{{- $.Scratch.SetInMap "structured_data" "dateModified" .Lastmod -}}
{{- end -}}
{{- end -}}
{{- with $.Scratch.Get "structured_data" }}
<script type="application/ld+json">
{{- . | jsonify | safeJS -}}
</script>
{{- end }}
</head>

16
themes/itix/layouts/partials/icons/en.svg

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 30" width="28" height="14" class="tiny-flag">
<title>British flag</title>
<clipPath id="s">
<path d="M0,0 v30 h60 v-30 z"/>
</clipPath>
<clipPath id="t">
<path d="M30,15 h30 v15 z v15 h-30 z h-30 v-15 z v-15 h30 z"/>
</clipPath>
<g clip-path="url(#s)">
<path d="M0,0 v30 h60 v-30 z" fill="#012169"/>
<path d="M0,0 L60,30 M60,0 L0,30" stroke="#fff" stroke-width="6"/>
<path d="M0,0 L60,30 M60,0 L0,30" clip-path="url(#t)" stroke="#C8102E" stroke-width="4"/>
<path d="M30,0 v30 M0,15 h60" stroke="#fff" stroke-width="10"/>
<path d="M30,0 v30 M0,15 h60" stroke="#C8102E" stroke-width="6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 676 B

6
themes/itix/layouts/partials/icons/fr.svg

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="14" class="tiny-flag">
<title>French flag</title>
<rect width="21" height="14" fill="#ED2939"/>
<rect width="14" height="14" fill="#fff"/>
<rect width="7" height="14" fill="#002395"/>
</svg>

After

Width:  |  Height:  |  Size: 249 B

5
themes/itix/layouts/partials/icons/label.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" class="material-icons">
<title>label</title>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/>
</svg>

After

Width:  |  Height:  |  Size: 317 B

5
themes/itix/layouts/partials/icons/link.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" class="material-icons">
<title>link</title>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/>
</svg>

After

Width:  |  Height:  |  Size: 395 B

6
themes/itix/layouts/partials/icons/rss_feed.svg

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32">
<title>rss_feed</title>
<path d="M0 0h24v24H0z" fill="none"/>
<circle cx="6.18" cy="17.82" r="2.18"/>
<path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/>
</svg>

After

Width:  |  Height:  |  Size: 350 B

6
themes/itix/layouts/partials/icons/schedule.svg

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" class="material-icons">
<title>schedule</title>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/>
<path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z"/>
</svg>

After

Width:  |  Height:  |  Size: 384 B

5
themes/itix/layouts/partials/icons/search.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" class="material-icons">
<title>search</title>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
</svg>

After

Width:  |  Height:  |  Size: 420 B

5
themes/itix/layouts/partials/icons/vertical_align_top.svg

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" class="material-icons">
<title>back to top</title>
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M8 11h3v10h2V11h3l-4-4-4 4zM4 3v2h16V3H4z"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

15
themes/itix/layouts/partials/lang-detection.html

@ -0,0 +1,15 @@
{{ if and .IsTranslated (eq .Lang "fr") }}
<!-- Try to compare files by SH256 fingerprint. -->
{{ if and (index .AllTranslations 0).File (index .AllTranslations 1).File }}
{{ $file0 := readFile (index .AllTranslations 0).File.Filename }}
{{ $file1 := readFile (index .AllTranslations 1).File.Filename }}
{{ if eq (sha256 $file0) (sha256 $file1) }}
{{ .Scratch.Set "en_article_in_fr_site" true }}
{{ end }}
{{ else }}
<!-- Sometimes there is no file though. In that case, compare the content. -->
{{ if eq (index .AllTranslations 0).Plain (index .AllTranslations 1).Plain }}
{{ .Scratch.Set "en_article_in_fr_site" true }}
{{ end }}
{{ end }}
{{ end }}

36
themes/itix/layouts/partials/mathjax.html

@ -0,0 +1,36 @@
<!-- From https://note.qidong.name/2018/03/hugo-mathjax/ -->
<script src="https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js"></script>
<script>
MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']]
},
svg: {
fontCache: 'global'
}
};
</script>
<script type="text/javascript" id="MathJax-script"
async
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
MathJax.Hub.Queue(function() {
// Fix <code> tags after MathJax finishes running. This is a
// hack to overcome a shortcoming of Markdown. Discussion at
// https://github.com/mojombo/jekyll/issues/199
var all = MathJax.Hub.getAllJax(), i;
for(i = 0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>
<style>
code.has-jax {
font: inherit;
font-size: 100%;
background: inherit;
border: inherit;
color: #515151;
}
</style>

65
themes/itix/layouts/partials/menu.html

@ -0,0 +1,65 @@
<nav class="menu">
<!--
-- A fake / hidden checkbox is used as click reciever,
-- so you can use the :checked selector on it.
-->
<input type="checkbox" class="hamburger-menu" id="show-menu" />
<!-- Some spans to draw a hamburger. -->
<div class="hamburger-menu"></div>
<div class="hamburger-menu"></div>
<div class="hamburger-menu"></div>
<!-- Add a label for accessibility -->
<label class="hamburger-menu" for="show-menu" style="display: none;" >{{ i18n "show_menu" }}</label>
<!-- And the site title for the mobile browsers -->
<div class="mobile-title">{{- .Site.Title -}}</div>
<div class="menu-content">
{{- if .IsHome }}
<a class="menu-head active" href="{{ .Site.Home.RelPermalink }}">
{{ else }}
<a class="menu-head" href="{{ .Site.Home.RelPermalink }}">
{{ end -}}
<div class="menu-title">
{{- .Site.Title -}}
</div>
{{- with .Site.Params.subtitle -}}
<div class="menu-subtitle">
{{- . -}}
</div>
{{- end -}}
</a>
<div class="menu-link-list">
{{- $currentPage := . -}}
{{- range .Site.Menus.main }}
<a class="{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}" href="{{ .URL| relLangURL }}">
{{- .Name -}}
</a>
{{- end }}
</div>
<div class="menu-lang">
{{- if .IsTranslated -}}
<!-- Try to redirect the user to the translated page if possible -->
{{- range .AllTranslations }}
<a href="{{ .RelPermalink }}">{{- partial (printf "icons/%s.svg" .Lang) . -}}</a>
{{- end -}}
{{- else -}}
<!-- Otherwise, redirect it to the homepage -->
{{- range site.Sites }}
<a href="{{ .Home.RelPermalink }}">{{- partial (printf "icons/%s.svg" .Language.Lang) . -}}</a>
{{- end -}}
{{- end }}
</div>
<div class="menu-footer">
&copy; {{ .Site.Home.Date.Year }} {{.Site.Title}}
</div>
</div>
<div class="menu-overlay">
</div>
</nav>

43
themes/itix/layouts/partials/post-metadata.html

@ -0,0 +1,43 @@
<div class="post-metadata">
<!-- Article publication date -->
{{- with .current.PublishDate }}
<span class="publication-date">
{{ i18n "published_on" }}
<time itemprop="published-on" date-time="{{ .Format "2006-01-02" }}">{{ .Format (i18n "date_format") }}</time>
</span>
{{- end }}
<!-- Expertise / Topics -->
{{ range .current.Params.topics -}}
<!-- Skip the item if we are on the term page presenting this item -->
{{- if or (not $.parent.Data.topic) (ne . $.parent.Data.Term) }}
<span class="topic">
{{- partial "icons/link.svg" . -}}<a href="{{ "/topics/" | relLangURL }}{{ . | urlize }}/">{{ . }}</a>
</span>
{{- end -}}
{{- end }}
<!-- Open Source communities -->
{{ range .current.Params.opensource -}}
<!-- Skip the item if we are on the term page presenting this item -->
{{- if or (not $.parent.Data.opensource) (ne . $.parent.Data.Term) }}
<span class="opensource">
{{- partial "icons/label.svg" . -}}<a href="{{ "/opensource/" | relLangURL }}{{ . | urlize }}/">{{ . }}</a>
</span>
{{- end -}}
{{- end }}
<!--
-- The reading time is only displayed on blog posts. Other kind of
-- articles are too short to be relevant.
-->
{{- if eq .current.Type "blog" }}
<span class="reading-time">
{{- partial "icons/schedule.svg" . -}}
{{- $minutes := .current.ReadingTime -}}
{{- if gt $minutes 0 -}}
{{- i18n "minutes" $minutes -}}
{{- end -}}
</span>
{{- end }}
</div>

23
themes/itix/layouts/partials/toolbar.html

@ -0,0 +1,23 @@
<aside class="toolbar">
<!-- Sometimes Hugo will generate an empty TOC enclosed within a nav element. -->
<!-- 32 is the length of this empty output. -->
{{- if gt (len .TableOfContents) 32 }}
<div class="toc">
<h4>{{ i18n "toc" }}</h4>
{{ .TableOfContents }}
</div>
{{- end }}
<div class="actions">
<a href="#top" class="action" title="{{ i18n "back_to_top" }}">
{{- partial "icons/vertical_align_top.svg" . -}}
</a>
<a href="{{ relref . "/search/index.md" }}" class="action" title="{{ i18n "search" }}">
{{- partial "icons/search.svg" . -}}
</a>
{{ with .OutputFormats.Get "rss" -}}
<a href="{{ .Permalink }}" class="action" title="{{ i18n "rss_feed" }}">
{{- partial "icons/rss_feed.svg" . -}}
</a>
{{ end }}
</div>
</aside>

7
themes/itix/layouts/shortcodes/highlightFile.html

@ -0,0 +1,7 @@
<!-- This shortcode renders an code block prefixed by a filename -->
<div class="highlightedFile">
{{- with .Get 0 -}}
<div class="filename">{{ printf (i18n "file") . | safeHTML }}</div>
{{- end -}}
{{- highlight (trim .Inner "\n") (.Get 1) (.Get 2) -}}
</div>

7
themes/itix/layouts/shortcodes/highlightWithTitle.html

@ -0,0 +1,7 @@
<!-- This shortcode renders an code block prefixed by a filename -->
<div class="highlightedFile">
{{- with .Get 0 -}}
<div class="filename">{{ . | safeHTML }}</div>
{{- end -}}
{{- highlight (trim .Inner "\n") (.Get 1) (.Get 2) -}}
</div>

31
themes/itix/layouts/shortcodes/internalLink.html

@ -0,0 +1,31 @@
<!-- This shortcode generates the HTML link to an internal resource, which can be translated or not.
-- It displays a country flag when the target page is in a different language than the current page.
-- Currently, this shortcode can only handle Hugo sites with two languages. -->
{{ $path := .Get "path" }}
{{ $currentLang := .Page.Lang }}
{{ $title := .Get "title" }}
{{ $sites := .Page.Sites }}
{{ if ne $currentLang (index .Page.Sites 0).Language.Lang }}
{{ $sites = collections.Reverse .Page.Sites }}
{{ end }}
{{ range $sites }}
{{ with .GetPage $path }}
<a href="{{ .RelPermalink }}">
{{ if ne $title "" }}
{{ $title }}
{{ else }}
{{ .Title }}
{{ end }}
</a>
{{ if and (eq $currentLang "en") (eq .Lang "fr") }}
{{- partial "icons/fr.svg" . -}}
{{ end }}
{{ if (eq $currentLang "fr") }}
{{- partial "lang-detection.html" . -}}
{{ if .Scratch.Get "en_article_in_fr_site" }}
{{- partial "icons/en.svg" . -}}
{{ end }}
{{ end }}
{{ break }}
{{ end }}
{{ end }}

14
themes/itix/layouts/speaking/list.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the speaking/list.html layout is used to render the list of posts under "speaking" -->
<article class="article-list">
<header>
<h1>{{ .Title }}</h1>
</header>
{{ .Content }}
<ul>
{{ range (sort .Pages "Date").Reverse }}
<li>{{ .Date.Format "January 2006" }} - <a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>
</article>
{{ end }}

14
themes/itix/layouts/writing/list.html

@ -0,0 +1,14 @@
{{ define "main" }}
<!-- the writing/list.html layout is used to render the list of posts under "writing" -->
<article class="article-list">
<header>
<h1>{{ .Title }}</h1>
</header>
{{ .Content }}
<ul>
{{ range (sort .Pages "Date").Reverse }}
<li>{{ .Date.Format "January 2006" }} - <a href="{{.RelPermalink}}">{{ .Title }}</a></li>
{{ end }}
</ul>
</article>
{{ end }}

BIN
themes/itix/static/fonts/JetBrainsMono-Regular.ttf

Binary file not shown.

BIN
themes/itix/static/fonts/JetBrainsMono-Regular.woff

Binary file not shown.

BIN
themes/itix/static/fonts/JetBrainsMono-Regular.woff2

Binary file not shown.

BIN
themes/itix/static/fonts/SourceSansPro-Regular.ttf

Binary file not shown.

BIN
themes/itix/static/fonts/SourceSerifPro-Regular.ttf

Binary file not shown.

BIN
themes/itix/static/fonts/material-icons.ttf

Binary file not shown.

BIN
themes/itix/static/fonts/material-icons.woff2

Binary file not shown.

9
themes/itix/static/js/fuse.js

File diff suppressed because one or more lines are too long

19
themes/itix/theme.toml

@ -0,0 +1,19 @@
name = "ITIX"
license = "MIT"
licenselink = "https://github.com/nmasse-itix/hugo-theme-itix/blob/master/LICENSE"
description = "Theme of my personal site: www.itix.fr"
homepage = "https://www.itix.fr/"
tags = ["blog"]
features = ["mobile","elegant"]
min_version = "0.59.0"
[author]
name = "Nicolas Massé"
homepage = "https://www.itix.fr/"
# If porting an existing theme
[original]
name = "amazingrise"
homepage = "https://amazingrise.net/"
repo = "https://github.com/amazingrise/hugo-theme-diary"
Loading…
Cancel
Save