added theme directory

This commit is contained in:
dadox395
2025-03-15 19:02:24 +01:00
parent 929d76e383
commit 5ece94dfd5
78 changed files with 9432 additions and 0 deletions

112
novemila/themes/typo/.gitignore vendored Normal file
View File

@@ -0,0 +1,112 @@
### Go ###
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
### Hugo ###
# Generated files by hugo
/public/
/resources/_gen/
/assets/jsconfig.json
hugo_stats.json
# Executable may be added to repository
hugo.exe
hugo.darwin
hugo.linux
# Temporary lock file while building
/.hugo_build.lock
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk

View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -0,0 +1,19 @@
# How to contribute to Typo
The goal of this theme is to be as simple as possible, hence adding or changing existing
features need some thought.
Any change that is too niche or heavily tailored to a specific developer's need will be rejected, as
that would make some features cumbersome to set up.
To avoid unnecessary work, please start a discussion or open an issue with a proposal.
Any other reasonable changes are more than welcome, keep in mind the guidelines:
- keep the code as minimal as possible, and avoid comments in the code unless needed;
- keep the parameters (e.g. in hugo.toml) as concise and clear as possible;
- update the [wiki](https://github.com/tomfran/typo/tree/main/wiki) if needed, trying to maintain the current style of writing;
- refrain from breaking existing behavior, for example, make a new feature disabled by default;
- squash your change in a single commit.
<br>
Thank you, <br>
Francesco

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Francesco Tomaselli
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.

View File

@@ -0,0 +1,45 @@
![banner](https://raw.githubusercontent.com/tomfran/typo/main/images/banner-light.webp)
# Typo, a Hugo theme.
Typo is a theme backed by simplicity, as you can see in the screenshots below. The goal was to have a website centered around content and nothing more.
[![wiki](https://img.shields.io/badge/doc-wiki-orange)](https://tomfran.github.io/typo-wiki/)
[![hugo-typo](https://img.shields.io/badge/hugo_themes-@typo-red)](https://themes.gohugo.io/themes/typo/)
[![GitHub Release](https://img.shields.io/github/v/release/tomfran/typo)](https://github.com/tomfran/typo/releases/latest)
[![last-commit](https://img.shields.io/github/last-commit/tomfran/typo)](https://github.com/tomfran/typo/commits/)
**Homepage**
![1](https://raw.githubusercontent.com/tomfran/typo/main/images/1.webp)
**Article**
![2](https://raw.githubusercontent.com/tomfran/typo/main/images/2.webp)
![3](https://raw.githubusercontent.com/tomfran/typo/main/images/3.webp)
## 1 Wiki
Typo's [Wiki](https://tomfran.github.io/typo-wiki/) is the place to find instructions on how to [setup](https://tomfran.github.io/typo-wiki/setup) the theme and an overview of the available [features](https://tomfran.github.io/typo-wiki/features).
Some of the most relevant are: heading auto-numbering, dark mode, color palettes, dark and light images, comments, etc.
## 2 Support
If you use the theme or found it useful you can support me by leaving a star ⭐ to Typo's Github repository.
[Contributions](https://github.com/tomfran/typo/blob/main/CONTRIBUTING.md) are always welcome, feel free to open issues and PRs with fixes or new features.
## 3 Typo Users
If you're using Typo for your website, feel free to add your website to [the list](https://github.com/tomfran/typo/blob/main/USERS.md) alongside what you do! 😊
## 4 Questions or ideas?
Use the [discussion tab](https://github.com/tomfran/typo/discussions) to share ideas/tips/questions about Typo or Hugo in general!
## 5 References
The SVGs for social icons are taken from [Simple Icons](https://github.com/simple-icons/simple-icons).
Every SVG present on the website is usable on the theme.

View File

@@ -0,0 +1,10 @@
# Typo Users
- https://tomfran.github.io, **tomfran**, Software Engineer
- https://arunmathaisk.in/, **Arun Mathai S K**, Software Engineer
- https://zohaibkhalid.com, **Muhammad Zohaib Khalid**, Data Engineer
- https://as215887.net, **Serhiy Bobrov**, Personal Autonomous System
- https://smdp26.github.io/, **Soumyadeep Paul**, PhD
- https://aadityathapa.github.io/, **Aaditya Thapa**, Data Analyst
- https://automagic.blog, **Sangeeth Sudheer**, UX Engineer
- https://kmiziz.xyz, **Vasily Negrebetskiy**, Software Engineer

View File

@@ -0,0 +1,5 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(88, 80, 98); /*base07*/
--content-secondary: rgb(165, 157, 175); /*base04*/
--background: rgb(251, 241, 242); /*base00*/
--code-background: rgb(242, 241, 244); /*base01*/
--code-border: rgb(216, 213, 221); /*base02*/
}
.dark {
--content-primary: rgb(251, 241, 242); /*base00*/
--content-secondary: rgb(191, 185, 198); /*base03*/
--background: rgb(88, 80, 98); /*base07*/
--code-background: rgb(114, 103, 126); /*base06*/
--code-border: rgb(139, 129, 152); /*base05*/
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(24, 24, 24); /*base07*/
--content-secondary: rgb(88, 88, 88); /*base04*/
--background: rgb(248, 248, 248); /*base00*/
--code-background: rgb(232, 232, 232); /*base01*/
--code-border: rgb(216, 216, 216); /*base02*/
}
.dark {
--content-primary: rgb(248, 248, 248); /*base00*/
--content-secondary: rgb(184, 184, 184); /*base03*/
--background: rgb(24, 24, 24); /*base07*/
--code-background: rgb(40, 40, 40); /*base06*/
--code-border: rgb(56, 56, 56); /*base05*/
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(45, 45, 45); /*base00*/
--content-secondary: rgb(116, 115, 105); /*base03*/
--background: rgb(242, 240, 236); /*base07*/
--code-background: rgb(232, 230, 223); /*base06*/
--code-border: rgb(211, 208, 200); /*base05*/
}
.dark {
--content-primary: rgb(242, 240, 236); /*base07*/
--content-secondary: rgb(160, 159, 147); /*base04*/
--background: rgb(45, 45, 45); /*base00*/
--code-background: rgb(57, 57, 57); /*base01*/
--code-border: rgb(81, 81, 81); /*base02*/
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(59, 50, 40); /*base00*/
--content-secondary: rgb(126, 112, 90); /*base03*/
--background: rgb(245, 238, 235); /*base07*/
--code-background: rgb(233, 225, 221); /*base06*/
--code-border: rgb(208, 200, 198); /*base05*/
}
.dark {
--content-primary: rgb(245, 238, 235); /*base07*/
--content-secondary: rgb(184, 175, 173); /*base04*/
--background: rgb(59, 50, 40); /*base00*/
--code-background: rgb(83, 70, 54); /*base01*/
--code-border: rgb(100, 82, 64); /*base02*/
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(43, 48, 59); /*base00*/
--content-secondary: rgb(101, 115, 126); /*base03*/
--background: rgb(239, 241, 245); /*base07*/
--code-background: rgb(223, 225, 232); /*base06*/
--code-border: rgb(192, 197, 206); /*base05*/
}
.dark {
--content-primary: rgb(239, 241, 245); /*base07*/
--content-secondary: rgb(167, 173, 186); /*base04*/
--background: rgb(43, 48, 59); /*base00*/
--code-background: rgb(52, 61, 70); /*base01*/
--code-border: rgb(79, 91, 102); /*base02*/
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(76, 79, 105);
--content-secondary: rgb(108, 111, 133);
--background: rgb(239, 241, 245);
--code-background: rgb(230, 233, 239);
--code-border: rgb(188, 192, 204);
}
.dark {
--content-primary: rgb(198, 208, 245);
--content-secondary: rgb(165, 173, 206);
--background: rgb(48, 52, 70);
--code-background: rgb(41, 44, 60);
--code-border: rgb(81, 87, 109);
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(36, 36, 36);
--content-secondary: rgb(117, 117, 117);
--background: rgb(255, 255, 255);
--code-background: rgb(249, 249, 249);
--code-border: rgb(229, 229, 229);
}
.dark {
--content-primary: rgb(218, 218, 218);
--content-secondary: rgb(140, 140, 140);
--background: rgb(20, 20, 20);
--code-background: rgb(30, 30, 30);
--code-border: rgb(50, 50, 50);
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(0, 0, 0);
--content-secondary: rgb(0, 0, 0);
--background: rgb(255, 255, 255);
--code-background: rgb(255, 255, 255);
--code-border: rgb(0, 0, 0);
}
.dark {
--content-primary: rgb(255, 255, 255);
--content-secondary: rgb(255, 255, 255);
--background: rgb(0, 0, 0);
--code-background: rgb(0, 0, 0);
--code-border: rgb(255, 255, 255);
}

View File

@@ -0,0 +1,15 @@
:root {
--content-primary: rgb(60, 56, 54);
--content-secondary: rgb(148, 133, 112);
--background: rgb(251, 241, 199);
--code-background: rgb(241, 231, 189);
--code-border: rgb(178, 163, 142);
}
.dark {
--content-primary: rgb(235, 219, 178);
--content-secondary: rgb(132, 122, 114);
--background: rgb(40, 40, 40);
--code-background: rgb(50, 50, 50);
--code-border: rgb(112, 102, 94);
}

View File

@@ -0,0 +1 @@
/* Place custom css here */

View File

@@ -0,0 +1,47 @@
@font-face {
font-family: 'Literata';
src: url('/fonts/Literata/Literata-Light.woff2') format('woff2');
font-weight: light;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Literata';
src: url('/fonts/Literata/Literata-LightItalic.woff2') format('woff2');
font-weight: light;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Literata';
src: url('/fonts/Literata/Literata-SemiBold.woff2') format('woff2');
font-weight: bold;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Literata';
src: url('/fonts/Literata/Literata-SemiBoldItalic.woff2') format('woff2');
font-weight: bold;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Monaspace';
src: url('/fonts/Monaspace/MonaspaceArgon-Regular.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Monaspace';
src: url('/fonts/Monaspace/MonaspaceArgon-SemiBold.woff') format('woff');
font-weight: bold;
font-style: normal;
font-display: swap;
}

View File

@@ -0,0 +1,601 @@
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-body);
margin: auto;
max-width: var(--main-width);
padding-left: var(--main-padding);
padding-right: var(--main-padding);
color: var(--content-primary);
background: var(--background);
}
.content {
min-height: var(--content-height) !important;
}
h1 {
margin-top: var(--h1-margin-top);
margin-bottom: var(--h1-margin-bottom);
font-size: var(--h1-font-size);
}
h2 {
margin-top: var(--h2-margin-top);
margin-bottom: var(--h2-margin-bottom);
font-size: var(--h2-font-size);
}
h3,
h4,
h5,
h6 {
font-size: var(--hx-font-size);
margin-top: var(--hx-margin-top);
margin-bottom: var(--hx-margin-bottom);
}
.heading {
.anchor {
text-decoration: none;
font-weight: normal;
color: var(--content-secondary);
visibility: hidden;
font-size: 0.9em;
font-family: var(--font-mono);
}
&:hover .anchor {
visibility: visible;
}
}
p {
margin-top: var(--p-margin-top);
margin-bottom: var(--p-margin-bottom);
font-size: var(--p-font-size);
line-height: var(--p-line-height);
}
li {
margin-left: var(--li-indent);
&:has(> input[type="checkbox"]) {
list-style-type: none;
}
& > input[type="checkbox"] {
width: var(--li-checkbox-size);
height: var(--li-checkbox-size);
margin: 0 0.2em 0.15em -1.25em;
vertical-align: middle;
}
}
a {
text-decoration: underline;
}
input {
.dark & {
color-scheme: dark;
}
}
/* Code blocks */
.copy-code-button {
background-color: var(--background);
font-family: var(--font-mono);
padding: 3px 6px;
font-size: 0.8em;
border-radius: var(--copy-code-button-border-radius);
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
display: none;
border: 1px solid var(--code-border);
}
pre:hover .copy-code-button {
display: block;
}
pre {
position: relative;
padding: var(--code-padding);
border: 1px solid var(--code-border);
overflow: scroll;
border-radius: var(--code-border-radius);
margin-top: var(--code-margin-top);
margin-bottom: var(--code-margin-bottom);
background-color: var(--code-background) !important;
overflow-x: auto;
-ms-overflow-style: none;
scrollbar-width: none;
line-height: 1.3em;
}
pre::-webkit-scrollbar {
display: none;
}
code span {
display: inline !important;
}
code {
-webkit-font-smoothing: antialiased;
-moz-font-feature-settings: "liga=1, dlig=1";
-ms-font-feature-settings: "liga", "dlig";
-webkit-font-feature-settings: "liga", "dlig";
-o-font-feature-settings: "liga", "dlig";
font-feature-settings: "liga", "dlig";
font-variant-ligatures: contextual;
font-family: var(--font-mono);
font-size: .9em;
line-height: 0;
}
.katex-display {
overflow-x: auto;
overflow-y: hidden;
-ms-overflow-style: none;
scrollbar-width: none;
}
.katex-display::-webkit-scrollbar {
display: none;
}
/* Footnotes */
.footnotes {
margin-top: 3rem;
border-style: none;
}
hr {
border: none;
height: 1px;
background: var(--content-secondary);
margin-top: 2rem;
margin-bottom: 2rem;
}
/* Header */
.header {
padding-top: var(--header-top-gap);
margin-bottom: var(--header-bottom-gap);
}
.header p {
font-size: small;
font-family: var(--font-mono);
margin-top: var(--header-menu-top-gap);
margin-right: var(--header-menu-side-gap);
}
.header-title {
font-size: 2.6em;
font-weight: bold;
margin-bottom: 0;
margin-top: 0;
}
.header-title a {
text-decoration: none;
}
/* Footer */
footer {
font-size: small;
display: flex;
justify-content: center;
align-items: center;
max-height: var(--footer-height);
}
footer a {
font-family: var(--font-mono);
margin-left: .2rem;
margin-right: .2rem;
}
/* Posts list */
.post-line {
margin-bottom: .5rem;
display: flex;
align-items: baseline;
}
.tag-line {
margin-bottom: .5rem;
display: flex;
align-items: baseline;
}
.post-line p {
margin-top: 0rem;
margin-bottom: 0rem;
}
.line-date {
font-size: small;
font-family: var(--font-mono);
min-width: 120px;
max-width: 120px;
text-align: right;
padding-right: 1rem;
margin-top: 0rem;
margin-bottom: 0rem;
}
.line-title {
margin: 0;
}
.tag-title {
margin: 0;
}
.line-summary {
font-size: small;
margin-top: .2rem !important;
/* font-style: italic; */
color: var(--content-secondary);
}
.list-container {
padding-bottom: 3rem;
}
.pagination {
display: flex;
align-items: center;
margin-top: 1rem;
margin-bottom: 0rem;
justify-content: center;
}
.pagination-control {
min-width: 3rem;
margin-left: .5rem;
margin-right: .5rem;
text-align: center;
align-items: center;
}
.page-number {
min-width: 3rem;
margin-left: .5rem;
margin-right: .5rem;
display: flex;
align-items: center;
justify-content: center;
align-items: center;
font-weight: bold;
}
/* Social Icons */
.social-icons {
padding: 12px 0;
margin-bottom: var(--social-icons-bottom-margin)
}
.social-icons a {
text-decoration: none;
}
.social-icons a:not(:last-of-type) {
margin-inline-end: 12px;
}
.social-icons a svg {
height: 20px;
width: 20px;
}
/* Single post page */
.single-intro-container {
margin-top: 1rem;
margin-bottom: 2rem;
}
.single-title {
margin-bottom: .5rem;
}
.single-readtime {
margin-top: .5rem;
color: var(--content-secondary);
}
.single-summary {
margin-bottom: 0;
color: var(--content-secondary);
}
.single-content {
margin-bottom: 5rem;
}
.single-tags {
margin-top: -1rem;
}
.single-tags span {
margin-right: .3rem;
}
/* Single pagination */
.single-pagination {
margin-top: 3rem;
margin-bottom: 3rem;
}
.single-pagination a {
margin-left: .4rem;
margin-right: .4rem;
}
.single-pagination hr {
margin: 0;
}
.single-pagination-text {
display: flex;
justify-content: center;
align-items: center;
min-height: 100%;
}
.single-pagination-prev {
min-width: 50%;
margin-top: 1rem;
margin-bottom: 1rem;
text-align: right;
}
.single-pagination-next {
min-width: 50%;
margin-top: 1rem;
margin-bottom: 1rem;
text-align: left;
}
.single-pagination-container-next {
display: flex;
min-height: 100%;
padding: .5rem;
}
.single-pagination-container-prev {
display: flex;
min-height: 100%;
padding: .5rem;
float: right;
}
/* Table of contents */
.toc {
font-size: var(--p-font-size);
line-height: calc(.9 * var(--p-line-height));
margin-top: var(--toc-margin-top);
margin-bottom: var(--toc-margin-bottom);
}
.toc ul {
margin-top: .1rem;
margin-bottom: .1rem;
}
.toc li {
margin-top: .1rem;
margin-bottom: .1rem;
}
/* Autonumbering */
.autonumber {
counter-reset: h2-counter 0;
}
.autonumber h2 {
counter-increment: h2-counter 1;
counter-reset: h3-counter 0;
}
.autonumber h3 {
counter-increment: h3-counter 1;
counter-reset: h4-counter 0;
}
.autonumber h4 {
counter-increment: h4-counter 1;
}
.autonumber h2:before {
content: counter(h2-counter) "\00a0\00a0";
}
.autonumber h3:before {
content: counter(h2-counter) "." counter(h3-counter) "\00a0\00a0";
}
.autonumber h4:before {
content: counter(h2-counter) "." counter(h3-counter) "." counter(h4-counter) "\00a0\00a0";
}
/* images */
figure>div {
width: 100%;
display: flex;
justify-content: center;
}
figure img {
max-width: 100%;
max-height: var(--figure-img-max-height);
width: auto;
height: auto;
margin-inline: auto;
}
.dark .img-light {
display: none !important;
}
.light .img-dark {
display: none !important;
}
.img-small div {
display: flex;
align-items: center;
justify-content: center;
}
.img-small img {
max-height: calc(var(--figure-img-max-height) * 0.8);
}
.img-small div:first-child {
height: 80%;
width: 80%;
margin: auto;
}
.img-full div {
display: flex;
align-items: center;
justify-content: center;
}
.img-full img {
height: auto;
width: 100vw !important;
max-width: 100vw !important;
}
.caption-container {
display: flex;
justify-content: center;
}
figcaption {
color: var(--content-secondary);
padding-left: var(--caption-padding);
padding-right: var(--caption-padding);
font-size: var(--caption-font-size);
margin-top: 1rem;
margin-bottom: 1rem;
}
/* 404 */
.not-found {
display: flex;
align-items: center;
justify-content: center;
}
.not-found div {
text-align: center;
}
.not-found div h1 {
font-size: 6rem;
margin-bottom: 3rem;
}
/* breadcrumbs */
.breadcrumbs {
display: flex;
flex-wrap: wrap;
gap: 2px;
font-size: small;
margin-bottom: calc(-0.5 * var(--h1-margin-top));
font-family: var(--font-mono);
}
/* Comments */
.giscus {
margin-top: 3rem;
}
/* Back to top */
.back-to-top {
text-align: center;
font-family: var(--font-mono);
font-size: small;
margin-bottom: 2rem;
/* margin-top: -3rem; */
}
/* Code in paragraphs */
p code {
background-color: var(--code-background);
border-radius: 3px;
padding: 2px;
}
/* Tables */
table {
border-collapse: collapse;
margin-top: var(--table-margin-top);
margin-bottom: var(--table-margin-bottom);
font-size: var(--p-font-size);
line-height: var(--p-line-height);
color: var(--content-primary);
}
th,
td {
padding: var(--table-cell-padding);
border: 1px solid var(--code-border);
text-align: left;
}
th {
background-color: var(--code-background);
font-weight: bold;
}
table code {
background-color: var(--code-background);
border-radius: 3px;
padding: 2px;
}
/* Quotes */
blockquote {
margin: 1.5rem;
margin-left: 0;
margin-right: 0;
border-left: solid 2px;
color: var(--content-secondary);
}
blockquote p {
margin-left: 1rem;
margin-right: 1rem;
}

View File

@@ -0,0 +1,117 @@
*,
::after,
::before {
box-sizing: border-box;
}
html {
-webkit-tap-highlight-color: transparent;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
a,
button,
body,
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--primary);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 18px;
line-height: 1.6;
word-break: break-word;
background: var(--theme);
}
article,
aside,
figcaption,
figure,
header,
hgroup,
main,
nav,
section,
table {
display: block;
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.2;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
margin-top: 0;
margin-bottom: 0;
}
ul, ol {
padding: 0;
}
a {
text-decoration: none;
}
body,
figure,
ul {
margin: 0;
}
table {
width: 100%;
border-collapse: collapse;
border-spacing: 0;
overflow-x: auto;
word-break: keep-all;
}
button,
input,
textarea {
padding: 0;
font: inherit;
background: 0 0;
border: 0;
}
input,
textarea {
outline: 0;
}
button,
input[type=button],
input[type=submit] {
cursor: pointer;
}
input:-webkit-autofill,
textarea:-webkit-autofill {
box-shadow: 0 0 0 50px var(--theme) inset;
}
img {
display: block;
max-width: 100%;
}

View File

@@ -0,0 +1,20 @@
.flex {
display: flex;
flex-wrap: wrap;
}
.bold {
font-weight: bold;
}
.italic {
font-style: italic;
}
.small {
font-size: medium;
}
.monospace {
font-family: var(--font-mono);
}

View File

@@ -0,0 +1,82 @@
:root {
--main-width: 780px;
--main-padding: 1.4em;
--main-padding-bottom: 3rem;
--caption-padding: calc(.25 * var(--main-padding));
/* header settings */
--header-top-gap: 2rem;
--header-bottom-gap: 2rem;
--header-menu-side-gap: .5rem;
--header-menu-top-gap: 1rem;
/* Typography */
--font-body: 'Literata', Georgia, Cambria, 'Noto Serif', 'Droif Serif', ui-serif, serif;
--font-mono: "Monaspace", ui-monospace, monospace;
--h1-margin-top: 2rem;
--h1-margin-bottom: 1.5rem;
--h2-margin-top: 2rem;
--h2-margin-bottom: 1.5rem;
--hx-margin-top: 1.5rem;
--hx-margin-bottom: 1rem;
--p-margin-top: 1rem;
--p-margin-bottom: 1rem;
--code-margin-top: 2rem;
--code-margin-bottom: 2rem;
--h1-font-size: 2em;
--h2-font-size: 1.8em;
--hx-font-size: 1.3em;
--p-font-size: 1em;
--p-line-height: 1.5em;
--caption-font-size: .8em;
/* Lists */
--li-indent: 2rem;
--ul-margin-top: 1rem;
--ul-margin-bottom: 1rem;
--li-checkbox-size: 0.8em;
/* TOC */
--toc-margin-top: 2rem;
--toc-margin-bottom: 3rem;
/* Code */
--code-padding: 1.5rem;
--code-border-radius: 10px;
--copy-code-button-border-radius: 7px;
/* Social section */
--social-icons-bottom-margin: 3rem;
/* Footer */
--footer-height: 3rem;
/* Content */
--content-height: calc(100vh - var(--footer-height));
--figure-img-max-height: 800px;
/* Tables */
--table-cell-padding: .5rem;
--table-margin-top: 1.5rem;
--table-margin-bottom: 1.5rem;
}
@media screen and (max-width: 1024px) {
:root {
--main-width: 750px;
--header-top-gap: 1rem;
--caption-padding: calc(.25 * var(--main-padding));
}
}
@media screen and (max-width: 640px) {
:root {
--header-top-gap: 1rem;
--social-icons-bottom-margin: 0rem;
--caption-padding: calc(2 * var(--main-padding));
}
}

View File

@@ -0,0 +1,4 @@
+++
title = 'Home'
draft = false
+++

View File

@@ -0,0 +1,3 @@
module github.com/tomfran/typo
go 1.20

View File

@@ -0,0 +1,15 @@
baseURL = 'https://example.org/'
languageCode = 'en-us'
defaultContentLanguage = 'en-us'
title = 'typo'
[module]
[module.hugoVersion]
extended = false
min = "0.116.0"
# Default config
[params.breadcrumbs]
enabled = true
showCurrentPage = true
home = "Home"

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

View File

@@ -0,0 +1,12 @@
{{ define "main" }}
<div class="not-found">
<div>
<h1> typo? </h1>
<p> Click <a href="/">here</a> to return home </p>
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,4 @@
<pre class="mermaid">
{{- .Inner | htmlEscape | safeHTML }}
</pre>
{{ .Page.Store.Set "hasMermaid" true }}

View File

@@ -0,0 +1,4 @@
<h{{ .Level }} class="heading" id="{{ .Anchor }}">
{{ .Text }}
<a class="anchor" href="#{{ .Anchor }}">#</a>
</h{{ .Level }}>

View File

@@ -0,0 +1,58 @@
{{/*
To get page resources and relative paths to work. Copied as is from default
hook:
https://github.com/gohugoio/hugo/blob/89bd02/tpl/tplimpl/embedded/templates/_default/_markup/render-image.html
*/}}
{{- $u := urls.Parse .Destination -}}
{{- $url := $u.String -}}
{{- $imgResource := .Page.Scratch.Get "typoNilVariable" -}}
{{- if not $u.IsAbs -}}
{{- $path := strings.TrimPrefix "./" $u.Path -}}
{{/* Check if this is a page bundle or standalone page */}}
{{- if .PageInner.Resources -}}
{{- $imgResource = .PageInner.Resources.Get $path -}}
{{- else if (or .PageInner.Parent .PageInner.Parent.Resources) -}}
{{- $imgResource = .PageInner.Parent.Resources.Get $path -}}
{{- end -}}
{{- $imgResource := or $imgResource (resources.Get $path) -}}
{{- with $imgResource -}}
{{- $url = .RelPermalink -}}
{{- with $u.RawQuery -}}
{{- $url = printf "%s?%s" $url . -}}
{{- end -}}
{{- with $u.Fragment -}}
{{- $url = printf "%s#%s" $url . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/* Split URL at # */}}
{{ $url = $url | safeURL }}
{{ $file_name_array := split $url "#" }}
{{/*
Iterate over all tags, which are in pos 1 to len array - 1,
and build the img class string as "img-tag1 img-tag2 ..."
*/}}
{{ $classes := "" }}
{{ range $idx := seq (sub (len $file_name_array) 1) }}
{{ $tag := index $file_name_array $idx }}
{{ $classes = printf "%s img-%s" $classes $tag}}
{{ end }}
{{/* Use the computed classes on the rendered figure */}}
<figure class="{{ $classes }}">
<div>
<img loading="lazy" alt="{{ .Text }}" src="{{ $url }}" {{ with $imgResource }}width="{{ .Width }}px" height="{{ .Height }}px"{{ end }}>
</div>
{{ with .Title }}
<div class="caption-container">
<figcaption> {{ . | markdownify}} </figcaption>
</div>
{{ end }}
</figure>

View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="{{ or site.Language.LanguageCode site.Language.Lang }}"
dir="{{ or site.Language.LanguageDirection `ltr` }}">
<head>
{{ partial "head.html" . }}
</head>
{{ $theme := "auto"}}
{{ with .Param "theme" }}
{{ $theme = .}}
{{ end }}
<body class="{{ $theme }}">
<div class="content">
<header>
{{ partial "header.html" . }}
</header>
<main class="main">
{{ block "main" . }}{{ end }}
</main>
</div>
<footer>
{{ partial "footer.html" . }}
</footer>
{{ if .Param "math" }}
{{ partialCached "math.html" . }}
{{ end }}
</body>
<script src="{{ "js/theme-switch.js" | relURL }}"></script>
<script defer src="{{ "js/copy-code.js" | relURL }}"></script>
</html>

View File

@@ -0,0 +1,61 @@
{{ define "main" }}
{{ .Content }}
{{/* Intro summary section */}}
{{ if or .Site.Params.homeIntroTitle .Site.Params.homeIntroContent }}
<div class="intro">
{{ with .Site.Params.homeIntroTitle }}
<h1>{{ . }}</h1>
{{ end }}
{{ with .Site.Params.homeIntroContent }}
<p>{{ . | markdownify }}</p>
{{ end }}
</div>
{{ end }}
{{/* Social Icons */}}
{{ with site.Params.social }}
<div class="social-icons">
{{- range . }}
<a href="{{ trim .url " " | safeURL }}" target="_blank"
rel="noopener noreferrer me"
title="{{ (.title | default .name) | title }}">
{{ partial "svg.html" . }}
</a>
{{- end }}
</div>
{{ end }}
{{/* Collection Section */}}
{{ if .Site.Params.homeCollection }}
<div class="list-container">
{{ with .Site.Params.homeCollectionTitle}}
<h1> {{ . }} </h1>
{{ end }}
{{ $pages := where .Site.RegularPages "Section" .Site.Params.homeCollection
}}
{{ $paginationSize := 1}}
{{ if (gt .Site.Params.paginationSize 0) }}
{{ $paginationSize = .Site.Params.paginationSize }}
{{ end }}
{{ $paginator := .Paginate $pages $paginationSize }}
{{ range $index, $page := $paginator.Pages }}
{{ partial "post-entry.html" $page}}
{{ end }}
{{ partial "pagination-controls.html" $paginator}}
{{ end }}
</div>
{{ end }}

View File

@@ -0,0 +1,32 @@
{{ define "main" }}
<div class="list-container">
{{ partial "breadcrumbs.html" . }}
<h1>{{ .Title }}</h1>
{{ .Content }}
{{ $tagsPage := eq .Title "Tags"}}
{{ $paginationSize := 1}}
{{ if (gt .Site.Params.paginationSize 0) }}
{{ $paginationSize = .Site.Params.paginationSize }}
{{ end }}
{{ $paginator := .Paginate (.Pages) $paginationSize }}
{{ range $index, $page := $paginator.Pages }}
{{ if $tagsPage }}
{{ partial "tag-entry.html" $page}}
{{ else }}
{{ partial "post-entry.html" $page}}
{{ end }}
{{ end }}
{{ partial "pagination-controls.html" $paginator}}
</div>
{{ end }}

View File

@@ -0,0 +1,105 @@
{{ define "main" }}
{{/* Breadcrumbs */}}
{{ if not .IsHome }}
{{ partial "breadcrumbs.html" . }}
{{ end }}
<div {{ if .Param "autonumber" }} class="autonumber" {{ end }}>
<div class="single-intro-container">
{{/* Title and Summary */}}
<h1 class="single-title">{{ .Title }}</h1>
{{ with .Param "summary" }}
<p class="single-summary">{{ . | markdownify }}</p>
{{ end }}
{{/* Reading Time */}}
<p class="single-readtime">
{{ with .Date }}
{{ $dateMachine := . | time.Format "2006-01-02T15:04:05-07:00" }}
{{ $dateHuman := . | time.Format (default ":date_long" $.Site.Params.singleDateFormat) }}
<time datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>
{{end}}
{{ if .Param "readTime" }}
&nbsp; · &nbsp;
{{ .ReadingTime }} min read
{{end }}
</p>
</div>
{{ if .Param "showTags" }}
{{ $taxonomy := "tags" }}
{{ with .Param $taxonomy }}
<div class="single-tags">
{{ range $index, $tag := . }}
{{ with $.Site.GetPage (printf "/%s/%s" $taxonomy $tag) -}}
<span>
<a href="{{ .Permalink }}">#{{ .LinkTitle }}</a>
</span>
{{ end }}
{{ end }}
</div>
{{ end }}
{{ end }}
{{/* Table of Content */}}
{{ if .Param "toc" }}
<aside class="toc">
<p><strong>Table of contents</strong></p>
{{ .TableOfContents }}
</aside>
{{ end }}
{{/* Page content */}}
<div class="single-content">
{{ .Content }}
{{ if .Site.Params.giscus.enable }}
{{ if not .Params.disableComment }}
{{ partial "comments.html" . }}
{{ end }}
{{ end }}
</div>
{{ if .Store.Get "hasMermaid" }}
{{ $mermaidDarkTheme := default "dark" (or .Params.mermaidDarkTheme .Site.Params.mermaidDarkTheme) }}
{{ $mermaidTheme := default "default" (or .Params.mermaidTheme .Site.Params.mermaidTheme) }}
<script defer
type="module"
id="mermaid_script"
data-light-theme="{{ $mermaidTheme }}"
data-dark-theme="{{ $mermaidDarkTheme }}"
src='{{ "js/mermaid.js" | relURL }}'>
</script>
{{ end }}
{{/* Next prev controls */}}
{{ if not (.Param "hidePagination") }}
{{ partial "pagination-single.html" . }}
{{ end }}
{{/* Back to top */}}
{{ if not (.Param "hideBackToTop") }}
<div class="back-to-top">
<a href="#top">
back to top
</a>
</div>
{{ end }}
</div>
{{ end }}

View File

@@ -0,0 +1,23 @@
{{- if .Site.Params.breadcrumbs.enabled -}}
{{- $breadcrumbs := .Site.Params.breadcrumbs -}}
<div class="breadcrumbs">
{{- range $i, $v := .Ancestors.Reverse -}}
<a href="{{ .RelPermalink }}">
{{- if (and (eq $i 0) (ne $breadcrumbs.home "")) -}}
{{- $breadcrumbs.home -}}
{{- else -}}
{{- .Title -}}
{{- end -}}
</a>
{{- if (lt $i (sub $.Ancestors.Len 1)) -}}
<span class="breadcrumbs-separator">/</span>
{{- end -}}
{{- end -}}
{{- if $breadcrumbs.showCurrentPage -}}
<span class="breadcrumbs-separator">/</span>
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
{{- end -}}
</div>
{{- end -}}

View File

@@ -0,0 +1,16 @@
<script src="https://giscus.app/client.js"
data-repo="{{ .Site.Params.giscus.repo }}"
data-repo-id="{{ .Site.Params.giscus.repoid }}"
data-category="{{ .Site.Params.utteranc.category }}"
data-category-id="{{ .Site.Params.giscus.categoryid }}"
data-mapping="{{ .Site.Params.giscus.mapping }}"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="top"
data-theme="{{ .Site.Params.giscus.theme }}"
data-lang="en"
data-loading="lazy"
crossorigin="anonymous"
async>
</script>

View File

@@ -0,0 +1,14 @@
{{ $showFooter := default true .Site.Params.showFooter }}
{{ if $showFooter }}
{{ if not .Site.Params.footerContent }}
<p>Powered by
<a href="https://gohugo.io/">Hugo</a>
and
<a href="https://github.com/tomfran/typo">tomfran/typo</a>
</p>
{{ end }}
{{ with .Site.Params.footerContent }}
<p>{{ . | markdownify }}</p>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,48 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
{{ $faviconPath := (.Site.Params.faviconPath | default "" | absURL) }}
<link rel="icon" type="image/ico" href="{{ $faviconPath }}/favicon.ico">
<link rel="icon" type="image/png" sizes="16x16" href="{{ $faviconPath }}/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="{{ $faviconPath }}/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="192x192" href="{{ $faviconPath }}/android-chrome-192x192.png">
<link rel="apple-touch-icon" sizes="180x180" href="{{ $faviconPath }}/apple-touch-icon.png">
{{ with .OutputFormats.Get "rss" -}}
{{ printf `<link rel=%q type=%q href=%q title=%q>` .Rel .MediaType.Type .Permalink site.Title | safeHTML }}
{{ end }}
{{- if .IsHome -}}
<meta name="description" content="{{ site.Params.Description }}"/>
{{- else -}}
<meta name="description" content="{{ .Params.Description }}"/>
{{- end }}
{{ if .Param "fediverse" }}
<meta name="fediverse:creator" content="{{ .Params.Fediverse }}">
{{ end }}
<title>
{{ if .IsHome }}
{{ site.Title }}
{{ else }}
{{ printf "%s | %s" .Title site.Title }}
{{ end }}
</title>
<link rel="canonical" href="{{ .Permalink }}"/>
{{ template "_internal/opengraph.html" . }}
{{ partialCached "head/css.html" . }}
{{ partialCached "head/js.html" . }}
{{ if hugo.IsProduction }}
{{ template "_internal/google_analytics.html" . }}
{{ if .Site.Params.umami.enable }}
{{ partial "umami.html" . }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,26 @@
{{
$CSS := slice
(resources.Get "css/reset.css")
(resources.Get "css/vars.css")
(resources.Get "css/utils.css")
(resources.Get "css/fonts.css")
(resources.Get "css/main.css")
(resources.Get "css/custom.css")
(resources.Get "css/colors/default.css")
}}
{{ with .Site.Params.colorPalette }}
{{ $path := printf "css/colors/%s.css" . }}
{{ $CSS = $CSS | append (resources.Get $path)}}
{{ end }}
{{
$combined := $CSS
| resources.Concat "assets/combined.css"
| minify
| fingerprint
}}
<link rel="stylesheet" href="{{ $combined.RelPermalink }}" media="all">

View File

@@ -0,0 +1,7 @@
{{- with resources.Get "js/main.js" }}
{{- $opts := dict "minify" true }}
{{- with . | js.Build $opts | fingerprint }}
<script src="{{ .RelPermalink }}" integrity="{{- .Data.Integrity }}"
crossorigin="anonymous"></script>
{{- end }}
{{- end }}

View File

@@ -0,0 +1,28 @@
{{/* Header */}}
<div class="header">
{{ if or (not (.Param "hideHeader")) .IsHome }}
<h1 class="header-title">
<a href="{{ site.BaseURL }}">{{ site.Title }}</a>
</h1>
<div class="flex">
{{ $currentPage := . }}
{{ with site.Params.menu }}
{{ range . }}
<p class="small {{ if eq .name (lower $currentPage.Name) }} bold {{end}}">
<a href="{{ .url }}" {{ if and (isset . "newTab") .newTab }}target="_blank" rel="noopener noreferrer"{{ end }}>
/{{.name }}
</a>
</p>
{{ end }}
{{ end }}
</div>
{{ end }}
</div>

View File

@@ -0,0 +1,19 @@
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css">
<script defer
src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"></script>
<script defer
src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body);"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false }
]
});
});
</script>

View File

@@ -0,0 +1,23 @@
{{ if gt .TotalPages 1 }}
<div class="pagination">
<div class="pagination-control">
{{ if .HasPrev }}
<a href="{{ .Prev.URL | absURL }}">
prev
</a>
{{ end }}
</div>
<div class="page-number">
<p>
{{ .PageNumber }}/{{ .TotalPages }}
</p>
</div>
<div class="pagination-control">
{{ if .HasNext }}
<a href="{{ .Next.URL | absURL }}">
next
</a>
{{ end }}
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,39 @@
{{ if or .NextInSection .PrevInSection }}
<div class="single-pagination">
<hr />
<div class="flex">
<div class="single-pagination-prev">
{{ with .PrevInSection }}
<div class="single-pagination-container-prev">
<div class="single-pagination-text"></div>
<div class="single-pagination-text">
<a href="{{ .RelPermalink }}">
{{ .Title }}
</a>
</div>
</div>
{{ end }}
</div>
<div class="single-pagination-next">
{{ with .NextInSection }}
<div class="single-pagination-container-next">
<div class="single-pagination-text">
<a href="{{ .RelPermalink }}">
{{ .Title }}
</a>
</div>
<div class="single-pagination-text"></div>
</div>
{{ end }}
</div>
</div>
<hr />
</div>
{{ end }}

View File

@@ -0,0 +1,21 @@
<div class="post-line">
{{ $dateFormat := "2 Jan 2006"}}
{{ with .Site.Params.listDateFormat }}
{{ $dateFormat = .}}
{{ end }}
<p class="line-date">{{ .Date | time.Format $dateFormat }} </p>
<div>
<p class="line-title">
<a href="{{ .RelPermalink }}">
{{ .Title }}
</a>
</p>
{{ if .Site.Params.listSummaries }}
<p class="line-summary"> {{ .Summary }} </p>
{{ end }}
</div>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
<div class="tag-line">
<div>
<p class="tag-title">
<a href="{{ .RelPermalink }}">#{{ .Title }}</a>
</p>
</div>
</div>

View File

@@ -0,0 +1,6 @@
<script
async
defer
data-website-id="{{ .Site.Params.umami.websiteId }}"
src="{{ .Site.Params.umami.jsLocation }}"
></script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -0,0 +1,34 @@
document.addEventListener("DOMContentLoaded", function () {
const codeBlocks = document.querySelectorAll("pre");
codeBlocks.forEach((codeBlock) => {
if (codeBlock.className == "mermaid") return;
const copyButton = document.createElement("button");
copyButton.className = "copy-code-button";
copyButton.textContent = "copy";
// Insert the button inside the <pre> block
codeBlock.appendChild(copyButton);
copyButton.addEventListener("click", function () {
const code = codeBlock.querySelector("code");
// Get the code content
const textToCopy = code.textContent || code.innerText;
// Use the Clipboard API to copy the text
navigator.clipboard
.writeText(textToCopy)
.then(() => {
// Change button text to "Copied"
copyButton.textContent = "copied";
setTimeout(() => {
copyButton.textContent = "copy";
}, 2000); // Reset the button text after 2 seconds
})
.catch((err) => {
console.error("Unable to copy text:", err);
});
});
});
});

View File

@@ -0,0 +1,28 @@
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
const this_js_script = document.getElementById('mermaid_script');
const light_theme = this_js_script.getAttribute('data-light-theme');
const dark_theme = this_js_script.getAttribute('data-dark-theme');
function runmermaid() {
const theme = (document.body.classList.contains('dark') ? dark_theme : light_theme)
mermaid.initialize({ startOnLoad: false, theme: theme});
const items = document.querySelectorAll('.mermaid');
let counter = 0;
for (const item of items) {
const id = counter++;
if(item.originalCode === undefined) {
item.originalCode = item.textContent.trim();
}
mermaid.render("mermaid"+id, item.originalCode).then((val) => {
item.innerHTML = val.svg
}, (err) => {
console.log(err);
// Workaround: move incorrectly placed error messages into their diagram
item.innerHTML = "";
item.appendChild(document.getElementById("mermaid" + id));
});
}
}
document.addEventListener('DOMContentLoaded', runmermaid);
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', runmermaid);

View File

@@ -0,0 +1,28 @@
function isAuto() {
return document.body.classList.contains("auto");
}
function setTheme() {
if (!isAuto()) {
return
}
document.body.classList.remove("auto");
let cls = "light";
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
cls = "dark";
}
document.body.classList.add(cls);
}
function invertBody() {
document.body.classList.toggle("dark");
document.body.classList.toggle("light");
}
if (isAuto()) {
window.matchMedia('(prefers-color-scheme: dark)').addListener(invertBody);
}
setTheme();

View File

@@ -0,0 +1,36 @@
name = 'Typo'
license = 'MIT'
licenselink = 'https://github.com/tomfran/typo/blob/main/LICENSE'
description = 'A simple Hugo theme'
homepage = 'https://github.com/tomfran/typo'
demosite = 'https://tomfran.github.io/'
tags = [
"responsive",
"simple",
"clean",
"light",
"dark",
"blog",
"minimal",
"personal",
"portfolio",
]
features = [
"responsive",
"blog",
"table-of-contents",
"highlight.js",
"favicon",
"social-icons",
"minified-assets",
"dark-light-images",
"color-palettes",
]
[author]
name = 'Francesco Tomaselli'
homepage = 'https://tomfran.github.io/'

View File

@@ -0,0 +1,88 @@
---
title: "Contributors"
date: "2025-01-01"
summary: "List of Typo's contributors"
description: "List of Typo's contributors"
toc: false
readTime: false
autonumber: false
math: false
showTags: false
hidePagination: true
hideBackToTop: false
---
<div id="loading-message">Fetching GitHub data, hang tight!</div>
<div id="content" style="display: none;">
The theme has accumulated <span id="star-count">over 300</span> stars on Github, and
currently counts <span id="contributors-count">over 20</span> contributors:
<ul id="contributors-list" style="list-style-type: none; padding: 0; margin-top: 2rem"></ul>
</div>
<script>
async function fetchGitHubData() {
const cacheKey = "githubData";
const cacheExpiryKey = "githubDataExpiry";
const cacheExpiryTime = 3600 * 1000; // 1 hour in milliseconds
// Check if cached data exists and is still valid
const cachedData = localStorage.getItem(cacheKey);
const cachedExpiry = localStorage.getItem(cacheExpiryKey);
const now = new Date().getTime();
if (cachedData && cachedExpiry && now < cachedExpiry) {
const { starCount, contributors } = JSON.parse(cachedData);
updateUI(starCount, contributors);
return;
}
try {
// Fetch star count
const repoResponse = await fetch("https://api.github.com/repos/tomfran/typo");
const repoData = await repoResponse.json();
const starCount = repoData.stargazers_count;
// Fetch contributors
const contributorsResponse = await fetch("https://api.github.com/repos/tomfran/typo/contributors");
const contributors = await contributorsResponse.json();
// Cache data
localStorage.setItem(cacheKey, JSON.stringify({ starCount, contributors }));
localStorage.setItem(cacheExpiryKey, now + cacheExpiryTime);
updateUI(starCount, contributors);
} catch (error) {
console.error("Error fetching GitHub data:", error);
document.getElementById("star-count").textContent = "Failed to fetch star count.";
document.getElementById("contributors-count").textContent = "Failed to fetch contributors count.";
}
}
function updateUI(starCount, contributors) {
document.getElementById("loading-message").style.display = "none";
document.getElementById("content").style.display = "block";
document.getElementById("star-count").textContent = `${starCount}`;
document.getElementById("contributors-count").textContent = `${contributors.length}`;
const contributorsList = document.getElementById("contributors-list");
contributorsList.innerHTML = "";
contributors.forEach(contributor => {
const listItem = document.createElement("li");
listItem.style.marginBottom = ".5rem";
listItem.innerHTML = `
<span style="display: flex; align-items: bottom;">
<img src="${contributor.avatar_url}" alt="${contributor.login}" width="30" height="30" style="margin-right: 10px; border-radius: 50%;">
<a href="${contributor.html_url}">${contributor.login}</a>&nbsp;- ${contributor.contributions}
</span>
`;
contributorsList.appendChild(listItem);
});
}
fetchGitHubData();
</script>

View File

@@ -0,0 +1,97 @@
---
title: "Appearance"
date: "2024-10-12"
summary: "Appearance parameters"
description: "Appearance parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
Typo has a built-in dark and light mode, you can decide the default one and control images on both modes.
## Choosing a Theme
By default the mode in use is auto, if you want, you can hard-code a color scheme.
```toml
[params]
theme = 'auto | light | dark'
```
## Choosing a Color Palette
Typo has the possibility to specify the color palette to use in the theme. The default one is black and white,
but they can easily be added.
The color palettes are stored under `assets/css/colors/*` and the one in use can be specified with the following
parameter:
```toml
[params]
colorPalette = 'default'
```
Note that omitting the parameter implies using the default palette.
This is the complete list of palettes available:
- default;
- catpuccin;
- gruvebox;
- eink;
- base16-default;
- base16-eighties;
- base16-ocean;
- base16-mocha;
- base16-cupcake.
More are to come.
## Adding a Custom Color Palette
You can add a custom color palette by creating a new file under `assets/css/colors/*` named after your wanted palette name.
Use another one as base and define the required parameters.
You can then use your new palette, by using its file name in the `colorPalette` site param.
## Hide Header Mode
You can choose to hide the header on every page apart from the homepage with this parameter.
```toml
[params]
hideHeader = true
```
I strongly recommend enabling breadcrumbs if you do so.
## Note on Syntax Highlighting
The theme supports syntax highlighting, and you can specify the theme as follows:
```toml
[markup]
[markup.highlight]
style = 'algol'
```
`algol` is the recommended theme, and for it to work, the background-color of the code
elements is enforced.
This has the side effect of breaking other color schemes, e.g. Monokai.
You can make them work by removing `!important` from the background color of the code pre elements.
I suggest trying [color schemes](https://xyproto.github.io/splash/docs/all.html) and see what can work for you.
## Footer Customization
One can decide to hide the footer completely or to change it's content by specifying the following parameters.
Note that if you don't include the following parameters (or leave footerContent empty) the default footer is shown.
```toml
[params]
showFooter = true
footerContent = "Your **custom** md `footer`"
```

View File

@@ -0,0 +1,40 @@
---
title: "Collections"
date: "2024-10-10"
summary: "Collections parameters"
description: "Collections parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
Here are some parameters regarding collections, those apply to both the home displayed one and to the dedicated folder pages.
## Pagination
Specify the maximum number of posts per page.
```toml
[params]
paginationSize = 100
```
## Date Format
The date format can be tweaked with a format string.
```toml
[params]
listDateFormat = '2 Jan 2006'
```
## Summary Toggle
Summaries can be turned on and off with this setting.
```toml
[params]
listSummaries = true
```

View File

@@ -0,0 +1,54 @@
---
title: "Controlling Images"
date: "2024-10-11"
summary: "Controlling Images parameters"
description: "Controlling Images parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
## Dark and Light Mode Images
Sometimes images don't look good in both light and dark mode. You can annotate the import path with a special tag to ensure an image is only shown on a specific color scheme.
```md
![sstable](sstable-l.webp#light)
![sstable](sstable-d.webp#dark)
```
In the above example, the light image is a transparent background with dark lines, while the dark one has light ones.
If you omit the `#dark` or `#light` tags an image is always shown.
## Images Sizing
There exist two tags to control sizing:
- `#small`: the image takes 80% of the original scale.
- `#full`: the image takes up all the available screen width.
You can also specify a caption using the following form:
```
![alt text](path.png#dark#small "Caption text")
```
I understand everyone could want a different scale for small images, you can override the default small class in your custom CSS:
```css
.img-small img {
scale: 80%;
}
```
[Here](https://tomfran.github.io/posts/hugo-images/) you can find a blog post showing different tags combinations.
## Adding new Image Tags
All tags are assumed to be related to an image class, which applies styling for the figure environment.
You can add a new one, provided you add a class named `img-<tag_name>`.
Feel free to have a look at existing ones to have a grasp on how they work.

View File

@@ -0,0 +1,27 @@
---
title: "Custom CSS"
date: "2024-10-07"
summary: "Custom CSS parameters"
description: "Custom CSS parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
hideBackToTop: true
---
The theme supports custom css, you can override anything you want by redefining classes in the `assets/css/custom.css` file.
For instance, changing the main width can be done as follows:
```css
:root {
--main-width: 1024px; /* overrides default of 780px */
}
```
Note that backward incompatible changes in the CSS will likely not happen, but there might be cases in the future where
backward compatibility is not possible. If you are overriding a huge amount of CSS I suggest you forking the project instead of
defining it here.

View File

@@ -0,0 +1,32 @@
---
title: "Header"
date: "2024-10-13"
summary: "Header parameters"
description: "Header parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
To pick pages to include in the header you must add the following elements:
```toml
[[params.menu]]
name = "home"
url = "/"
[[params.menu]]
name = "posts"
url = "/posts"
```
There exists an optional new tab parameter, to choose whether menu items are opened in a new tab or not.
```toml
[[params.menu]]
name = "posts"
url = "/posts"
newTab = true
```

View File

@@ -0,0 +1,56 @@
---
title: "Homepage"
date: "2024-10-14"
summary: "Homepage parameters"
description: "Homepage parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
The homepage offers minimal customization options, you can specify an intro, a collection to display, and social icons.
## Intro Section
By setting those two parameters in your `hugo.toml` config you can control the text to display after the header on the homepage. Note that the body is interpreted as markdown.
```toml
[params]
homeIntroTitle = 'Hi!'
homeIntroContent = """
I am an Italian Software Engineer with a strong foundation in computer science and a passion for solving complex problems.
I am interested in a range of topics, including algorithms, distributed systems, databases, and information retrieval.
"""
```
Note that you can omit one of the two if you want.
## Social Icons
You can include social icons after the intro like follows.
```toml
[[params.social]]
name = "linkedin"
url = "https://www.linkedin.com/in/user/"
[[params.social]]
name = "medium"
url = "https://medium.com/@user"
```
If some icons are missing, feel free to open a request or a PR.
## Display a Collection
You can decide to include a collection in your homepage:
```toml
[params]
homeCollectionTitle = 'Posts'
homeCollection = 'posts'
```
The above example includes the `/posts` collection. Note that you can omit the title if you prefer.

View File

@@ -0,0 +1,108 @@
---
title: "Other Parameters"
date: "2024-10-08"
summary: "Other Parameters parameters"
description: "Other Parameters parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
Miscellaneous settings.
## Home Meta Description
You can specify the homepage meta description with the following parameter:
```toml
[params]
description = "Your description"
```
## Breadcrumbs
Show breadcrumbs on pages.
Example:
```toml
[params.breadcrumbs]
enabled = true
showCurrentPage = true
home = "~"
```
Set `enabled` to `false` if you want to hide breadcrumbs. By default, breadcrumbs are shown.
Set `showCurrentPage` to `false` to hide the last crumb, i.e, the current page.
`home` when set with a non-empty string, uses the latter as the first crumb instead of the string "Home".
## Comments
Enable comments on your posts using [Giscus](https://giscus.app/).
```toml
[params.giscus]
enable = false
repo = "your/repo"
repoid = "id"
category = "category"
categoryid = "categoryId"
mapping = "pathname"
theme = "preferred_color_scheme"
```
Tip: use `preferred_color_scheme` theme to have a consistent dark and light appearance.
You can decide to hide the comments section on certain pages, using the following parameter on the page itself:
```md
disableComment: true
```
## Umami
You can include [Umami](https://umami.is/) in your website as follows:
```toml
[params.umami]
enable = true
websiteId = "unique-website-id"
jsLocation = "http://example.org/umami.js"
```
## Favicons
The following favicons are included in the head of the website:
- `favicon.ico`
- `favicon-16x16.png`
- `favicon-32x32.png`
- `android-chrome-192x192.png`
- `apple-touch-icon.png`
You must override the existing one in your static folder.
You can also specify a subdirectory of /static if you prefer
using the following param:
```toml
[params]
faviconPath = 'your-path'
```
You can easily generate favicons using [this website](https://realfavicongenerator.net/) starting from your image.
[Here](https://github.com/tomfran/tomfran.github.io/tree/main/static) you can see an example of icons overriding default ones.
## Mermaid Diagrams
Mermaid diagrams are supported, just follow [this reference](https://gohugo.io/content-management/diagrams/#mermaid-diagrams) to use them. You can set Mermaid's light- and dark themes in your config; they switch with your blog's light/dark state. These are the defaults:
```toml
[params]
mermaidTheme = "default"
mermaidDarkTheme = "dark"
```

View File

@@ -0,0 +1,97 @@
---
title: "Single Page Parameters"
date: "2024-10-09"
summary: "Single Page Parameters parameters"
description: "Single Page Parameters parameters"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
---
The following parameters apply to single pages, they are meant to be inserted in the `.md` files introductions, apart from the date format.
## Table of Contents
Show a table of contents at the beginning of the post.
```md
toc: true
```
## Sections Auto-numbering
Auto-number headings.
```md
autonumber: true
```
Note that headings should start from level two.
## Math Rendering
Enable math rendering.
```md
math: true
```
## Tags
Create tags associated with the post and decide to show them.
```md
tags: ["database", "java"]
showTags: false
```
## Display Read Time
Choose to display reading time.
```md
readTime: true
```
## Hide Back to Top
Choose to display back to top at the end of the page.
```md
hideBackToTop: true
```
## Hide Pagination Controls
Choose to display pagination controls at the end of the page.
```md
hidePagination: true
```
## Meta Description
You can specify the post meta description as follows:
```md
description: "Your Description"
```
## Fediverse
You can include a [fediverse handle](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) in your posts.
```md
fediverse: "@username@instance.url"
```
## Date Format
You can decide the date format to apply to single posts by setting the following param in the toml file:
```toml
[params]
singleDateFormat = '2 January 2006'
```

View File

@@ -0,0 +1,188 @@
---
title: "Setup"
date: "2024-10-12"
summary: "How to setup a Hugo's website using Typo as a theme."
description: "Getting started with Typo theme"
toc: false
readTime: false
autonumber: true
math: false
showTags: false
hidePagination: true
---
## Installation
Below are the ways to get started with the Typo theme.
### Getting Started
First of all, create a new Hugo project as follows:
```bash
hugo new site <your site name> --config toml
```
### Downloading the Theme
Themes are contained in the `/themes` directory, there are different ways to get Typo there
**Submodule - Recommended**
```bash
git submodule add --depth=1 https://github.com/tomfran/typo.git themes/typo
git submodule update --init --recursive
```
**Hugo module**
Installing Typo as a Hugo module requires Go to be installed in your development environment.
```bash
# Initialize your project as a Hugo module
hugo mod init <module_name>
# Install the theme
hugo mod get github.com/tomfran/typo
```
Then add the following to `hugo.toml`:
```toml
[module]
[[module.imports]]
path = "github.com/tomfran/typo"
```
Finally, remove the `theme = 'typo'` parameter from `hugo.toml`.
**Cloning**
```bash
git clone https://github.com/tomfran/typo themes/typo --depth=1
```
You need to keep it updated manually by pulling.
**Manual download a release**
Finally, you can manually download a [release](https://github.com/tomfran/typo/releases) and unzip it into the appropriate folder.
## Sample Config
Use those to get started with the theme. You can find a complete overview of the available features [here](https://tomfran.github.io/typo-wiki/features/).
[Here](https://github.com/tomfran/tomfran.github.io) you can find a repo using this theme.
### Site Config
Here is a sample `hugo.toml` config to get started with the theme.
```toml
baseURL = 'https://example.org/'
languageCode = 'en-us'
title = 'My website'
theme = 'typo'
# Google analytics code
googleAnalytics = "G-xxxxxxxxx"
[taxonomies]
tag = 'tags'
[params]
# Meta description
description = "A Tech Blog"
# Appearance settings
theme = 'auto'
colorPalette = 'default'
hideHeader = false
# Intro on main page, content is markdown
homeIntroTitle = 'Hi!'
homeIntroContent = """
I am an Italian Software Engineer with a strong foundation in computer science and a passion for solving complex problems.
I am interested in a range of topics, including algorithms, distributed systems, databases, and information retrieval.
"""
# Collection to display on home
homeCollectionTitle = 'Posts'
homeCollection = 'posts'
# Lists parameters
paginationSize = 100
listSummaries = true
listDateFormat = '2 Jan 2006'
# Breadcrumbs
[params.breadcrumbs]
enabled = true
showCurrentPage = true
home = "Home"
# Social icons
[[params.social]]
name = "linkedin"
url = "https://www.linkedin.com/in/user/"
[[params.social]]
name = "medium"
url = "https://medium.com/@user"
[[params.social]]
name = "github"
url = "https://github.com/user"
# Main menu pages
[[params.menu]]
name = "home"
url = "/"
[[params.menu]]
name = "posts"
url = "/posts"
[[params.menu]]
name = "about"
url = "/about"
# Syntax highlight on code blocks
[markup]
[markup.highlight]
style = 'algol'
# Giscus comments
[params.giscus]
enable = false
repo = "user/repo"
repoid = "repoId"
category = "General"
categoryid = "categoryId"
mapping = "pathname"
theme = "preferred_color_scheme"
```
### Post Config
Sample post config.
```markdown
---
title: "Log-Structured Merge Tree"
date: "2023-11-12"
summary: "An LSM Tree overview and Java implementation."
description: "An LSM Tree overview and Java implementation."
toc: true
readTime: true
autonumber: true
math: true
tags: ["database", "java"]
showTags: false
hideBackToTop: false
fediverse: "@username@instance.url"
---
```
## Support
If you use the theme or found it useful you can support me by leaving a star :star: to Typo's Github repository or opening issues and PRs with fixes or new features.