Merge pull request 'Rewrite v2' (#1) from rewrite into main

Reviewed-on: #1
This commit is contained in:
Sofía Aritz 2025-04-26 14:53:08 +00:00
commit 56323c9ea0
63 changed files with 4112 additions and 2118 deletions

10
.editorconfig Normal file
View file

@ -0,0 +1,10 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2

View file

@ -1,39 +1,213 @@
const { DateTime } = require("luxon")
const markdownIt = require("markdown-it");
const markdownItAnchor = require("markdown-it-anchor");
const timeToRead = require("eleventy-plugin-time-to-read")
import { createRequire } from "module"
const require = createRequire(import.meta.url)
module.exports = function(eleventyConfig) {
eleventyConfig.addPassthroughCopy({ "static": "/" })
import { basename, dirname, extname, join, relative } from "path";
import { access, constants, copyFile, mkdir, readdir, readFile, stat, unlink } from "fs/promises";
import { createHash } from "crypto";
eleventyConfig.addPlugin(timeToRead, {
import { DateTime } from "luxon";
import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
import { feedPlugin } from "@11ty/eleventy-plugin-rss";
import markdownIt from "markdown-it";
import markdownItAnchor from "markdown-it-anchor";
const markdownItEmoji = require("markdown-it-emoji");
import markdownItFootnote from "markdown-it-footnote";
const HASHED_ASSETS = [".css", ".js"]
const assetsManifest = {}
async function hashFile(filePath) {
const content = await readFile(filePath)
return createHash("sha1").update(content).digest("hex").slice(0, 12)
}
async function walk(dir) {
let files = [];
for (const item of await readdir(dir, { withFileTypes: true })) {
const fullPath = join(dir, item.name);
if (item.isDirectory()) {
files = files.concat(await walk(fullPath));
} else if (item.isFile()) {
files.push(fullPath);
}
}
return files;
}
async function prepareManifest(assetsPath, log = console.log) {
const files = await walk(assetsPath);
if (process.env.ELEVENTY_RUN_MODE === "serve") {
log("[sofi-assets] In watch mode, skipping hashing")
}
for (const absPath of files) {
if (!(await stat(absPath)).isFile()) continue;
const ext = extname(absPath)
if (!HASHED_ASSETS.includes(ext) || process.env.ELEVENTY_RUN_MODE === "serve") {
const rel = relative(assetsPath, absPath)
assetsManifest[rel] = rel
continue;
}
const base = basename(absPath, ext)
if (base.endsWith("__h")) continue;
const hash = await hashFile(absPath)
const newBase = `${base}-${hash}__h${ext}`
const relDir = dirname(relative(assetsPath, absPath))
const newRelPath = relDir === "."
? newBase
: join(relDir, newBase)
assetsManifest[relative(assetsPath, absPath)] = newRelPath
}
}
async function fileExists(path) {
return await access(path, constants.F_OK).then(() => true, () => false);
}
async function processAssets(assetsPath, outputPath, log = console.log) {
for (const [origRel, newRel] of Object.entries(assetsManifest)) {
const src = join(assetsPath, origRel);
const dest = join(outputPath, newRel);
if (basename(dest, extname(dest)).endsWith("__h") && await fileExists(dest)) {
log(`[sofi-assets] Skipped copying '${src}' because it already exists as '${dest}'`)
continue
}
await mkdir(dirname(dest), { recursive: true })
await copyFile(src, dest);
log(`[sofi-assets] Copied: '${src}' to '${dest}'`);
}
}
const markdownItOptions = {
html: true,
linkify: true,
}
const feedOptions = {
type: "atom",
outputPath: "/feed.xml",
collection: {
name: "weblogActive",
limit: 50,
},
metadata: {
language: "en",
style: "long",
hours: "auto",
minutes: true,
title: "Sofía Aritz's weblog",
subtitle: "Updates and thoughts from Sofía and her projects.",
base: "https://sofiaritz.com",
author: {
name: "Sofía Aritz",
email: "sofi@sofiaritz.com",
},
},
}
const dirOptions = {
input: "src",
output: "www",
}
function dateDesc(a, b) {
return DateTime.fromJSDate(b.data.date) - DateTime.fromJSDate(a.data.date);
}
export default async function (eleventyConfig) {
const log = eleventyConfig.logger.log.bind(eleventyConfig.logger)
eleventyConfig.addPassthroughCopy({ "assets/robots.txt": "robots.txt" })
eleventyConfig.addWatchTarget("./assets/")
eleventyConfig.on("eleventy.before", async () => {
await prepareManifest("assets", log)
})
eleventyConfig.setLibrary("md", markdownIt({
html: true
}).use(markdownItAnchor, {
level: 2
}))
eleventyConfig.addFilter("relevantTags", tags => tags.filter(v => !["archived", "post"].includes(v)))
eleventyConfig.addFilter("readableDate", dateObj => {
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).setLocale("es-ES").toFormat("dd LLL yyyy");
eleventyConfig.on("eleventy.after", async () => {
log("[sofi-assets] Build done, performing asset processing")
await processAssets("assets", join(dirOptions.output, "/assets/"), log)
})
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
eleventyConfig.addFilter('htmlDateString', dateObj => {
return DateTime.fromJSDate(dateObj, {zone: 'utc'}).toFormat('yyyy-LL-dd');
eleventyConfig.addShortcode("assetPath", (asset) => {
if (assetsManifest[asset] != null) {
return `/assets/${assetsManifest[asset]}`
} else {
throw `Asset '${asset}' is not in asset manifest`
}
})
eleventyConfig.addCollection("weblog", (collection) => {
return collection.getFilteredByGlob(join(dirOptions.input, "/weblog/*"))
.filter(item => !item.page.filePathStem?.endsWith("index"))
.sort(dateDesc);
})
eleventyConfig.addCollection("weblogActive", (collection) => {
return collection.getFilteredByGlob(join(dirOptions.input, "/weblog/*"))
.filter(item => !item.page.filePathStem?.endsWith("index"))
.filter(item => !item.data.archived)
.sort(dateDesc);
})
eleventyConfig.addCollection("projects", (collection) => {
return collection.getFilteredByGlob(join(dirOptions.input, "/projects/*"))
.filter(item => !item.page.filePathStem?.endsWith("index"))
.sort(dateDesc);
})
const markdown = markdownIt(markdownItOptions)
.use(markdownItAnchor)
.use(markdownItEmoji.full, { shortcuts: {} })
.use(markdownItFootnote);
eleventyConfig.setLibrary("md", markdown)
eleventyConfig.addPlugin(syntaxHighlight)
eleventyConfig.addPlugin(eleventyImageTransformPlugin)
eleventyConfig.addPlugin(feedPlugin, feedOptions)
eleventyConfig.addGlobalData("permalink", () => {
return (data) => eleventyConfig.getFilter("slugify")(data.page.fileSlug).concat("/")
})
eleventyConfig.addFilter("markdown", content => {
return markdown.render(content)
})
eleventyConfig.addFilter("readTime", content => {
const minutes = content.trim().split(" ").length / 130 // 130 wpm
return Math.ceil(minutes)
})
eleventyConfig.addFilter("datetime", date => {
return DateTime.fromJSDate(date).toFormat("LLLL dd, yyyy")
})
eleventyConfig.addFilter("HTMLdatetime", date => {
return DateTime.fromJSDate(date).toFormat("yyyy-MM-dd")
})
eleventyConfig.addFilter("removeTitle", content => {
const match = content.match(/<h1[^>]*>(.*?)<\/h1>/);
if (match) {
return content.replace(match[0], "").trim()
}
return content
})
return {
passthroughFileCopy: true,
dir: {
input: "src"
}
dir: dirOptions,
}
}

4
.gitattributes vendored Normal file
View file

@ -0,0 +1,4 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated

24
.gitignore vendored
View file

@ -1,4 +1,20 @@
.scripts/
.idea/
_site/
node_modules/
www
# Compat with old site
_site
.scripts
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
#!.yarn/cache
.pnp.*

View file

@ -1,5 +1 @@
# sofi web
My personal website :)
[sofiaritz.com](https://sofiaritz.com)
# sofi-web

View file

@ -14,4 +14,4 @@ a/xLBCS5BgMBCAfCfgQYFgoAJhYhBKEVU9yTYwhnuD7hKloUhbTMzdtKBQJneV6n
AhsMBQkDwmcAAAoJEFoUhbTMzdtK72kA/0JKzhX51gN4YPrsCL3Qc3+kDlR0xG4z
kpeXX7gk1Y7ZAQDagUM1PCkb7vT6stQsPuuhdyvXsYcvWtV15uxPbITUAg==
=b5x3
-----END PGP PUBLIC KEY BLOCK-----
-----END PGP PUBLIC KEY BLOCK-----

57
assets/robots.txt Normal file
View file

@ -0,0 +1,57 @@
# AI scrapers
User-agent: AI2Bot
User-agent: Ai2Bot-Dolma
User-agent: aiHitBot
User-agent: Amazonbot
User-agent: anthropic-ai
User-agent: Applebot
User-agent: Applebot-Extended
User-agent: Brightbot 1.0
User-agent: Bytespider
User-agent: CCBot
User-agent: ChatGPT-User
User-agent: Claude-Web
User-agent: ClaudeBot
User-agent: cohere-ai
User-agent: cohere-training-data-crawler
User-agent: Cotoyogi
User-agent: Crawlspace
User-agent: Diffbot
User-agent: DuckAssistBot
User-agent: FacebookBot
User-agent: Factset_spyderbot
User-agent: FirecrawlAgent
User-agent: FriendlyCrawler
User-agent: Google-Extended
User-agent: GoogleOther
User-agent: GoogleOther-Image
User-agent: GoogleOther-Video
User-agent: GPTBot
User-agent: iaskspider/2.0
User-agent: ICC-Crawler
User-agent: ImagesiftBot
User-agent: img2dataset
User-agent: imgproxy
User-agent: ISSCyberRiskCrawler
User-agent: Kangaroo Bot
User-agent: meta-externalagent
User-agent: meta-externalfetcher
User-agent: NovaAct
User-agent: OAI-SearchBot
User-agent: omgili
User-agent: omgilibot
User-agent: Operator
User-agent: PanguBot
User-agent: Perplexity-User
User-agent: PerplexityBot
User-agent: PetalBot
User-agent: Scrapy
User-agent: SemrushBot-OCOB
User-agent: SemrushBot-SWA
User-agent: Sidetrade indexer bot
User-agent: TikTokSpider
User-agent: Timpibot
User-agent: VelenPublicWebCrawler
User-agent: Webzio-Extended
User-agent: YouBot
Disallow: /

View file

@ -0,0 +1,15 @@
/* Warning */
.warning {
padding: 1rem;
background-color: color-mix(in srgb, var(--color-secondary),#fff 80%);
border: 1px solid var(--color-accent);
border-radius: 0.5rem;
margin-bottom: 1.5rem;
color: var(--color-text);
}
.warning h3 {
margin-top: 0;
font-size: 1.25rem;
color: var(--color-accent);
}

View file

@ -1,17 +1,3 @@
@font-face {
font-family: "JetBrains Mono";
src: url("https://cdn.sofiaritz.com/fonts/ofl/jetbrainsmono/JetBrainsMono-Italic[wght].ttf");
font-style: italic;
font-weight: 300;
}
@font-face {
font-family: "JetBrains Mono";
src: url("https://cdn.sofiaritz.com/fonts/ofl/jetbrainsmono/JetBrainsMono[wght].ttf");
font-style: normal;
font-weight: 300;
}
@font-face {
font-family: "Rubik";
src: url("https://cdn.sofiaritz.com/fonts/ofl/rubik/Rubik[wght].ttf");
@ -31,4 +17,18 @@
src: url("https://cdn.sofiaritz.com/fonts/ofl/nunito/Nunito[wght].ttf");
font-style: normal;
font-weight: 700;
}
@font-face {
font-family: "Lora";
src: url("https://cdn.sofiaritz.com/fonts/ofl/lora/Lora[wght].ttf");
font-style: normal;
font-weight: 400 500 600 700 800;
}
@font-face {
font-family: "Lora";
src: url("https://cdn.sofiaritz.com/fonts/ofl/lora/Lora[wght].ttf");
font-style: italic;
font-weight: 400 500 600 700 800;
}

187
assets/styles/layout.css Normal file
View file

@ -0,0 +1,187 @@
.site-body {
margin: 0;
padding: 0;
box-sizing: border-box;
background: var(--color-bg);
color: var(--color-text);
font-family: "Lora", serif;
display: flex;
min-height: 100vh;
}
.nav-toggle {
background: var(--color-footer-bg);
color: var(--color-bg);
font-size: 1.25rem;
border: none;
padding: 1rem;
width: 100%;
text-align: left;
display: none;
}
.nav-toggle:hover {
cursor: pointer;
}
.site-nav {
background: var(--color-footer-bg);
font-family: "Rubik", sans-serif;
width: 15rem;
padding: 1rem 1.5rem;
position: sticky;
top: 0;
min-height: 100vh;
}
.site-logo, .site-logo h1 {
font-family: "Nunito", sans-serif;
text-decoration: none;
color: var(--color-bg);
}
.nav-section-title {
color: var(--color-bg);
font-weight: bold;
display: block;
padding-bottom: 0.35rem;
}
.nav-section-list {
list-style: none;
margin-bottom: 2rem;
padding: 0;
}
.nav-link {
text-decoration: none;
color: var(--color-bg);
display: block;
padding: 0.25rem 0.5rem;
border-left: 3px solid transparent;
}
.nav-link:hover,
.nav-link:focus {
background: var(--color-bg);
border-left-color: var(--color-bg);
color: var(--color-footer-bg);
}
.layout-main {
flex-grow: 1;
}
.content-area {
display: flex;
flex-direction: column;
height: 100%;
}
.main-content {
padding: 2rem;
max-width: 75rem;
width: 100%;
margin: 0 auto;
}
.site-footer {
background: var(--color-footer-bg);
color: var(--color-footer-text);
padding: 1rem 1.7rem;
margin-top: auto;
display: flex;
flex-wrap: wrap;
}
.footer-meta,
.footer-source {
flex: 1 1 200px;
}
.site-footer a {
color: var(--color-footer-text);
}
/* Responsive */
@media (max-width: 992px) {
.nav-toggle {
display: flex;
justify-content: space-between;
align-items: last baseline;
padding: 0 1rem;
font-size: 1.5rem;
}
.site-logo {
font-size: 0.8rem;
}
.desktop-site-logo {
display: none;
}
.nav-section-title {
font-size: 1.3rem;
padding: 0;
}
.nav-section-list {
margin-top: 0.5rem;
}
.nav-link {
font-size: 1.5rem;
padding: 0.7rem 0.5rem;
}
.site-nav {
position: relative;
width: 100%;
height: 100%;
}
.site-nav.collapsed {
display: none;
}
.site-nav.expanded {
display: block;
position: relative;
width: 100%;
background: var(--color-footer-bg);
padding: 1rem 1.5rem;
}
.site-body {
flex-direction: column;
}
.main-content {
padding: 1.5rem;
}
}
@media (max-width: 600px) {
.site-body {
font-size: 16px;
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.75rem;
}
.site-footer {
flex-direction: column;
text-align: center;
}
.footer-meta,
.footer-source {
flex: 1 1 auto;
}
}

View file

@ -0,0 +1,339 @@
/*
Copyright (c) 2015 PrismJS
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.
*/
/**
* Coldark Theme for Prism.js
* Theme variation: Cold
* Tested with HTML, CSS, JS, JSON, PHP, YAML, Bash script
* @author Armand Philippot <contact@armandphilippot.com>
* @homepage https://github.com/ArmandPhilippot/coldark-prism
* @license MIT
*/
code[class*="language-"],
pre[class*="language-"] {
color: #111b27;
background: none;
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
background: #8da1b9;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
background: #8da1b9;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #e3eaf2;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em 0.3em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #3c526d;
}
.token.punctuation {
color: #111b27;
}
.token.delimiter.important,
.token.selector .parent,
.token.tag,
.token.tag .token.punctuation {
color: #006d6d;
}
.token.attr-name,
.token.boolean,
.token.boolean.important,
.token.number,
.token.constant,
.token.selector .token.attribute {
color: #755f00;
}
.token.class-name,
.token.key,
.token.parameter,
.token.property,
.token.property-access,
.token.variable {
color: #005a8e;
}
.token.attr-value,
.token.inserted,
.token.color,
.token.selector .token.value,
.token.string,
.token.string .token.url-link {
color: #116b00;
}
.token.builtin,
.token.keyword-array,
.token.package,
.token.regex {
color: #af00af;
}
.token.function,
.token.selector .token.class,
.token.selector .token.id {
color: #7c00aa;
}
.token.atrule .token.rule,
.token.combinator,
.token.keyword,
.token.operator,
.token.pseudo-class,
.token.pseudo-element,
.token.selector,
.token.unit {
color: #a04900;
}
.token.deleted,
.token.important {
color: #c22f2e;
}
.token.keyword-this,
.token.this {
color: #005a8e;
}
.token.important,
.token.keyword-this,
.token.this,
.token.bold {
font-weight: bold;
}
.token.delimiter.important {
font-weight: inherit;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.language-markdown .token.title,
.language-markdown .token.title .token.punctuation {
color: #005a8e;
font-weight: bold;
}
.language-markdown .token.blockquote.punctuation {
color: #af00af;
}
.language-markdown .token.code {
color: #006d6d;
}
.language-markdown .token.hr.punctuation {
color: #005a8e;
}
.language-markdown .token.url > .token.content {
color: #116b00;
}
.language-markdown .token.url-link {
color: #755f00;
}
.language-markdown .token.list.punctuation {
color: #af00af;
}
.language-markdown .token.table-header {
color: #111b27;
}
.language-json .token.operator {
color: #111b27;
}
.language-scss .token.variable {
color: #006d6d;
}
/* overrides color-values for the Show Invisibles plugin
* https://prismjs.com/plugins/show-invisibles/
*/
.token.token.tab:not(:empty):before,
.token.token.cr:before,
.token.token.lf:before,
.token.token.space:before {
color: #3c526d;
}
/* overrides color-values for the Toolbar plugin
* https://prismjs.com/plugins/toolbar/
*/
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button {
color: #e3eaf2;
background: #005a8e;
}
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus {
color: #e3eaf2;
background: #005a8eda;
text-decoration: none;
}
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover,
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus {
color: #e3eaf2;
background: #3c526d;
}
/* overrides color-values for the Line Highlight plugin
* http://prismjs.com/plugins/line-highlight/
*/
.line-highlight.line-highlight {
background: #8da1b92f;
background: linear-gradient(to right, #8da1b92f 70%, #8da1b925);
}
.line-highlight.line-highlight:before,
.line-highlight.line-highlight[data-end]:after {
background-color: #3c526d;
color: #e3eaf2;
box-shadow: 0 1px #8da1b9;
}
pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before {
background-color: #3c526d1f;
}
/* overrides color-values for the Line Numbers plugin
* http://prismjs.com/plugins/line-numbers/
*/
.line-numbers.line-numbers .line-numbers-rows {
border-right: 1px solid #8da1b97a;
background: #d0dae77a;
}
.line-numbers .line-numbers-rows > span:before {
color: #3c526dda;
}
/* overrides color-values for the Match Braces plugin
* https://prismjs.com/plugins/match-braces/
*/
.rainbow-braces .token.token.punctuation.brace-level-1,
.rainbow-braces .token.token.punctuation.brace-level-5,
.rainbow-braces .token.token.punctuation.brace-level-9 {
color: #755f00;
}
.rainbow-braces .token.token.punctuation.brace-level-2,
.rainbow-braces .token.token.punctuation.brace-level-6,
.rainbow-braces .token.token.punctuation.brace-level-10 {
color: #af00af;
}
.rainbow-braces .token.token.punctuation.brace-level-3,
.rainbow-braces .token.token.punctuation.brace-level-7,
.rainbow-braces .token.token.punctuation.brace-level-11 {
color: #005a8e;
}
.rainbow-braces .token.token.punctuation.brace-level-4,
.rainbow-braces .token.token.punctuation.brace-level-8,
.rainbow-braces .token.token.punctuation.brace-level-12 {
color: #7c00aa;
}
/* overrides color-values for the Diff Highlight plugin
* https://prismjs.com/plugins/diff-highlight/
*/
pre.diff-highlight > code .token.token.deleted:not(.prefix),
pre > code.diff-highlight .token.token.deleted:not(.prefix) {
background-color: #c22f2e1f;
}
pre.diff-highlight > code .token.token.inserted:not(.prefix),
pre > code.diff-highlight .token.token.inserted:not(.prefix) {
background-color: #116b001f;
}
/* overrides color-values for the Command Line plugin
* https://prismjs.com/plugins/command-line/
*/
.command-line .command-line-prompt {
border-right: 1px solid #8da1b97a;
}
.command-line .command-line-prompt > span:before {
color: #3c526dda;
}

18
assets/styles/root.css Normal file
View file

@ -0,0 +1,18 @@
:root {
--color-bg: #fefcfb;
--color-text: #2d1740;
--color-secondary: #f38cc2;
--color-accent: #dc158d;
--color-footer-bg: rgba(45, 23, 64, 0.9);
--color-footer-text: #ffffff;
}
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}

56
assets/styles/text.css Normal file
View file

@ -0,0 +1,56 @@
h1,
h2,
h3,
h4,
h5 {
color: var(--color-text);
margin: 1.5rem 0 0.75rem;
}
h1 {
font-size: 2.5rem;
border-bottom: 2px solid var(--color-secondary);
padding-bottom: 0.1rem;
}
h2 {
font-size: 2rem;
border-bottom: 1px dashed var(--color-accent);
padding-bottom: 0.2rem;
}
p {
margin: 1rem 0;
}
a {
color: var(--color-accent);
text-decoration: underline;
}
a:hover,
a:focus {
color: var(--color-secondary);
}
blockquote {
margin: 2rem 0;
padding: 1rem 1.5rem;
border-left: 4px solid var(--color-accent);
background-color: color-mix(in srgb, var(--color-text),#fff 95%);
color: var(--color-text);
font-style: italic;
font-size: 1.1rem;
}
blockquote p {
margin: 0;
}
blockquote cite {
display: block;
margin-top: 0.75rem;
font-size: 0.9rem;
color: var(--color-accent);
font-style: normal;
}

View file

@ -1,24 +1,24 @@
{
"name": "eleventy-base",
"version": "1.0.0",
"description": "A template for creating 11ty websites.",
"main": "index.js",
"author": "Sofía Aritz",
"license": "UNLICENSED",
"private": true,
"devDependencies": {
"@11ty/eleventy": "^2.0.1",
"eleventy-plugin-time-to-read": "^1.3.0",
"luxon": "^3.4.4",
"markdown-it": "^13.0.2",
"markdown-it-anchor": "^8.6.7"
},
"name": "sofi-web",
"type": "module",
"packageManager": "yarn@4.4.1",
"scripts": {
"build": "npx @11ty/eleventy",
"serve": "npx @11ty/eleventy --serve",
"tree": "tree --gitignore",
"fresh-build": "rm -rf _site/ && yarn build",
"deploy": "cd .scripts/ && ./deploy.sh"
"start": "yarn run clean && yarn exec eleventy --serve",
"build": "yarn run clean && yarn exec eleventy",
"clean": "rm -rf www/"
},
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
"dependencies": {
"@11ty/eleventy": "^3.0.0"
},
"devDependencies": {
"@11ty/eleventy-img": "^6.0.2",
"@11ty/eleventy-plugin-rss": "^2.0.3",
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
"@sindresorhus/slugify": "^2.2.1",
"luxon": "^3.6.1",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0",
"markdown-it-emoji": "^3.0.0",
"markdown-it-footnote": "^4.0.0"
}
}

View file

@ -1,14 +0,0 @@
---
layout: base_page.njk
---
# not found
The requested content was not found.
If you have found a broken link, **please [contact me](/en/contact)**. The following information could be useful:
* Where did you find the broken link
* What is the broken link
Thank you :)

14
src/_data/events.json Normal file
View file

@ -0,0 +1,14 @@
{
"featured": [
{
"title": "SalmorejoTech 2025",
"description": "I will be presenting at SalmorejoTech 2025 on FSFE's upcoming project, MP Scrape.",
"link": "https://salmorejo.tech/2025"
},
{
"title": "Devconf.CZ 2025",
"description": "I will be hosting at Devconf.CZ:\n- An [Upcycling Android Workshop](https://pretalx.devconf.info/devconf-cz-2025/talk/FRXKNL/)\n- A talk about [Munin](/projects/munin): [&ldquo;Identity: Supporting dementia care with Free Software&rdquo;](https://pretalx.devconf.info/devconf-cz-2025/talk/P8ZEE8/).",
"link": "https://www.devconf.info/cz/"
}
]
}

28
src/_data/site.json Normal file
View file

@ -0,0 +1,28 @@
{
"title": "sofi web",
"description": "Updates and thoughts from Sofía and her projects.",
"author": "Sofía Aritz",
"url": "https://sofiaritz.com",
"repo": "https://git.sofiaritz.com/sofia/sofi-web",
"repoSourceBase": "https://git.sofiaritz.com/sofia/sofi-web/src/branch/main/",
"nav": [
{
"title": "pages",
"links": [
{ "label": "about me", "href": "/" },
{ "label": "contact", "href": "/contact" },
{ "label": "weblog", "href": "/weblog" },
{ "label": "projects", "href": "/projects" }
]
},
{
"title": "links",
"links": [
{ "label": "fediverse", "href": "https://hachyderm.io/@sofiaritz", "rel": "me" },
{ "label": "codeberg", "href": "https://codeberg.org/sofiaritz" },
{ "label": "git", "href": "https://git.sofiaritz.com" },
{ "label": "status", "href": "https://status.sofiaritz.com" }
]
}
]
}

View file

@ -1,86 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=yes, initial-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="fediverse:creator" content="@sofiaritz@hachyderm.io">
<link href="https://cdn.sofiaritz.com" rel="preconnect" crossorigin>
<link href="/assets/css/fonts.css" rel="stylesheet">
<link href="/assets/css/base.css" rel="stylesheet">
{% if styles %}
{% for style in styles %}
<link href="{{ style }}" rel="stylesheet">
{% endfor %}
{% endif %}
<title>{% if title %} {{ title }} - {% endif %}sofi web</title>
</head>
<body>
<div style="display: none !important">
<a rel="me" href="https://hachyderm.io/@sofiaritz">Fediverse</a>
<a rel="me" href="https://git.sofiaritz.com/sofia">Forgejo</a>
</div>
<h1><a href="/">sofi web</a></h1>
<div class="page-container">
<main>
{{ content | safe }}
</main>
<nav>
{% if lang != "en" %}
<div>
<i>yo</i>
<ul>
<li><a href="/">inicio y sobre mí</a></li>
<li><a href="/contacto">contacto</a></li>
</ul>
</div>
<div>
<i>creaciones</i>
<ul>
<li><a href="/weblog">weblog</a></li>
<li><a href="/proyectos">proyectos</a></li>
</ul>
</div>
{% else %}
<div>
<i>me</i>
<ul>
<li><a href="/en">home and about me</a></li>
<li><a href="/en/contact">contact</a></li>
</ul>
</div>
<div>
<i>creations</i>
<ul>
<li><a href="/en/weblog">weblog</a></li>
</ul>
</div>
{% endif %}
<div>
<i>links</i>
<ul>
<li><a href="https://status.sofiaritz.com">status</a></li>
<li><a href="https://git.sofiaritz.com/explore/repos">forgejo</a></li>
</ul>
</div>
<div>
<i>global</i>
<ul>
<li><a href="/en">english</a></li>
<li><a href="/">spanish</a></li>
</ul>
</div>
</nav>
</div>
{% if scripts %}
{% for script in scripts %}
<script src="{{ script }}"></script>
{% endfor %}
{% endif %}
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="{{ lang | default: 'en' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description | default: site.description }}">
<meta name="fediverse:creator" content="@sofiaritz@hachyderm.io">
<link href="https://cdn.sofiaritz.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="{% assetPath 'styles/root.css' %}">
<link rel="stylesheet" href="{% assetPath 'styles/fonts.css' %}">
<link rel="stylesheet" href="{% assetPath 'styles/layout.css' %}">
<link rel="stylesheet" href="{% assetPath 'styles/text.css' %}">
<link rel="stylesheet" href="{% assetPath 'styles/components.css' %}">
<link rel="stylesheet" href="{% assetPath 'styles/prism-coldark-cold.css' %}">
<title>{% if title %}{{ title }} - {% endif %}{{ site.title }}</title>
<link rel="alternate" href="{{ site.url }}/feed.xml" type="application/atom+xml" title="{{ site.title }} Feed">
</head>
<body class="site-body">
<header class="site-header">
<button class="nav-toggle" id="nav-toggle" aria-label="Toggle navigation" aria-expanded="false">
<a href="/" class="site-logo"><h1>sofi web</h1></a>
<span>&#9776; Menu</span>
</button>
<nav class="site-nav" id="site-nav">
<a href="/" class="desktop-site-logo site-logo"><h1>sofi web</h1></a>
{% for section in site.nav %}
<span class="nav-section-title">{{ section.title }}</span>
<ul class="nav-section-list">
{% for link in section.links %}
<li><a class="nav-link" href="{{ link.href }}" {% if link.rel %}rel="{{ link.rel }}" {% endif %}>{{
link.label }}</a></li>
{% endfor %}
</ul>
{% endfor %}
</nav>
</header>
<div class="layout-main">
<div class="content-area">
<main class="main-content">
{% if archived %}
<div class="warning">
<h3>Archived Page</h3>
<p>This page is archived and preserved for historical purposes. It may contain outdated information,
and some links or features might not work. The content may not reflect my current views.</p>
</div>
{% endif %}
<article>
{{ content }}
</article>
</main>
<footer class="site-footer">
<div class="footer-meta">
<p>&copy; {{ "now" | date: "%Y" }} {{ site.author }}</p>
{% if license == false %}
<p>All rights reserved for this article.</p>
{% elsif license %}
<p>This article is licensed under {{ license }}, unless otherwise stated.</p>
{% else %}
<p>This article is licensed under
<a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">CC BY-NC-ND 4.0</a>, unless
otherwise stated.
</p>
{% endif %}
</div>
<div class="footer-source">
{% assign cleanPath = page.inputPath | remove: "./" %}
<p>
<a href="https://git.sofiaritz.com/sofia/sofi-web/src/branch/main/{{ cleanPath }}">source
code</a>
</p>
</div>
</footer>
</div>
</div>
<script>
const toggle = document.getElementById("nav-toggle");
const nav = document.getElementById("site-nav");
toggle.hidden = false;
nav.classList.add("collapsed");
toggle.addEventListener("click", () => {
const isCollapsed = nav.classList.contains("collapsed");
nav.classList.toggle("collapsed", !isCollapsed);
nav.classList.toggle("expanded", isCollapsed);
toggle.setAttribute("aria-expanded", isCollapsed);
});
</script>
</body>
</html>

18
src/_includes/post.liquid Normal file
View file

@ -0,0 +1,18 @@
---
layout: "layout"
---
<div id="title-header">
<a href="/weblog" style="text-decoration: none; font-family: 'Nunito', sans-serif">&larr; Weblog</a>
<h1 style="margin-top: 0.7rem;">{{ title }}</h1>
</div>
<div style="padding-bottom: 1rem;">
<time datetime="{{ date | HTMLdatetime }}">{{ date | datetime }}</time> by {{ author | default:site.author }} in
{%for tag in tags %}<span><a href="/weblog/tags/{{ tag }}">#{{ tag }}</a>&nbsp;</span>{% endfor %}
| Estimated read time: {{ content | readTime }} minute(s)
</div>
{{ content | removeTitle }}
<a href="#title-header" style="text-decoration: none; font-family: 'Nunito', sans-serif;">&uarr; Go back to top</a>

View file

@ -1,47 +0,0 @@
---
layout: base_page.njk
scripts: ["/assets/weblog/comments.js", "/assets/libraries/dompurify.js"]
styles: ["/assets/css/comments.css"]
---
<h1>{{ title }}</h1>
<div style="display: inline">
{% if date %}
<time datetime="{{ date | htmlDateString }}">{{ date | readableDate }}</time> |
{% endif %}
{% if tags.includes("archived") %}
<span><a href="/meta/archived">Archived post</a></span> |
{% endif %}
{% if tags %}
{% if tags.length > 1 %}
<span>Tags:</span>
{% else %}
<span>Tag:</span>
{% endif %}
{% set relTags = tags | relevantTags %}
{% for tag in relTags %}
<span><a href="/weblog/tags/{{ tag }}">{{ tag }}</a> {% if loop.last == false %}·{% endif %}</span>
{% endfor %}
|
{% endif %}
{{ content | timeToRead }}
{% if comment_status %}
| <a href="#comments">Comments</a>
{% endif %}
</div>
{{ content | safe }}
{% if comment_status %}
<hr>
<div id="comments">
<div>
<h2 style="display: inline">comments · <a href="https://hachyderm.io/@sofiaritz/{{ comment_status }}">post</a></h2>
</div>
<section data-status="{{ comment_status }}" id="comment-section"></section>
</div>
{% endif %}

View file

@ -0,0 +1,19 @@
---
layout: "layout"
---
<div id="title-header">
<a href="/projects" style="text-decoration: none; font-family: 'Nunito', sans-serif">&larr; Projects</a>
<h1 style="margin-top: 0.7rem;">{{ title }}</h1>
</div>
{% if inactive == true %}
<div class="warning">
<h3>Inactive project</h3>
<p>This project is now inactive, development has been stalled.</p>
</div>
{% endif %}
{{ content | removeTitle }}
<a href="#title-header" style="text-decoration: none; font-family: 'Nunito', sans-serif;">&uarr; Go back to top</a>

View file

@ -1,11 +0,0 @@
---
layout: base_page.njk
---
{% if lang == "en" %}
<h1>redirect</h1>
<p>This page has been moved: {{ content | safe }}</p>
{% else %}
<h1>redirección</h1>
<p>Esta página ha sido movida: {{ content | safe }}</p>
{% endif %}

View file

@ -1,5 +1,17 @@
---
layout: redirect
layout: "layout"
---
[/contacto](/contacto)
# contact
You might use any of the following to contact me:
- E-mail: [sofi@sofiaritz.com](mailto:sofi@sofiaritz.com) ([public key](/assets/keys/sofi@sofiaritz.com.pub))
- Signal: @sofiaritz.01
- Matrix: [@sofiaritz:matrix.org](https://matrix.to/#/@sofiaritz:matrix.org)
## social media
- Fediverse: [@me@sofiaritz.com](https://hachyderm.io/@sofiaritz) (@sofiaritz@hachyderm.io)
- Forgejo: [sofia@git.sofiaritz.com](https://git.sofiaritz.com/sofia)
- Codeberg [sofiaritz@codeberg.org](https://codeberg.org/sofiaritz)

View file

@ -1,16 +0,0 @@
---
layout: base_page.njk
title: contacto
---
# contacto
## contacto directo
* Correo electrónico: [sofi@sofiaritz.com](mailto:sofi@sofiaritz.com)
* Matrix: [@sofiaritz:matrix.org](https://matrix.to/#/@sofiaritz:matrix.org)
## redes sociales
* Forgejo: [sofia@git.sofiaritz.com](https://git.sofiaritz.com/sofia)
* Fediverse: [@me@sofiaritz.com](https://hachyderm.io/@sofiaritz) (@sofiaritz@hachyderm.io)

View file

@ -1,17 +0,0 @@
---
layout: base_page.njk
title: contact
lang: "en"
---
# contact
### direct
* E-mail: [sofi@sofiaritz.com](mailto:sofi@sofiaritz.com)
* Matrix: [@sofiaritz:matrix.org](https://matrix.to/#/@sofiaritz:matrix.org)
### social media
* Forgejo: [sofia@git.sofiaritz.com](https://git.sofiaritz.com/sofia)
* Fediverse: [@me@sofiaritz.com](https://hachyderm.io/@sofiaritz) (@sofiaritz@hachyderm.io)

View file

@ -1,20 +0,0 @@
---
layout: base_page.njk
lang: "en"
---
# home
I'm Sofía Aritz, a young programmer passionate about technology as a tool for social transformation.
I work on projects with social impact &mdash;such as [Identity](https://git.sofiaritz.com/sofia/identity), an initiative designed to contribute to palliative care and the treatment of conditions like dementia&mdash;
seeking solutions that empower individuals and promote digital autonomy.
I have always been deeply interested in the intersection of the technical, political, and social aspects of Free Software.
My approach to Software development is deeply shaped by my interest in decentralized and federated systems,
which I believe are essential for building a fairer and more sustainable technological ecosystem.
## affiliations
- Collaborator at the [Free Software Club of the University of Córdoba](https://uco.es/aulasoftwarelibre/)
- Leader and lead developer of [Identity](https://git.sofiaritz.com/sofia/identity)

8
src/errors/404.md Normal file
View file

@ -0,0 +1,8 @@
---
layout: "layout"
permalink: /errors/404/
---
# 404: Not found
The requested resource was not found on this server.

60
src/index.liquid Normal file
View file

@ -0,0 +1,60 @@
---
layout: "layout"
---
<h1>home</h1>
<p>
I'm Sofía Aritz, a young programmer passionate about technology as a tool for social transformation.
I work on projects with social impact &mdash;such as <a href="https://codeberg.org/Identity/munin">Munin</a>, an
initiative designed to contribute to palliative care and the treatment of conditions like dementia&mdash;
seeking solutions that empower individuals and promote digital autonomy.
</p>
<p>
I have always been deeply interested in the intersection of the technical, political, and social aspects of Free
Software.
</p>
<p>
My approach to Software development is deeply shaped by my interest in decentralized and federated systems,
which I believe are essential for building a fairer and more sustainable technological ecosystem.
</p>
<h2>affiliations</h2>
<ul>
<li>Collaborator at the <a href="https://uco.es/aulasoftwarelibre/">Free Software Club of the University of Córdoba</a></li>
<li>Leader and lead developer of <a href="https://codeberg.org/Identity/munin">Munin</a></li>
</ul>
<h2>latest articles</h2>
{% assign limitedPosts = collections.weblogActive | slice: 0, 2 %}
{% for post in limitedPosts %}
<div>
<h3 style="margin-bottom: 0.2rem;"><a style="text-decoration: none;" href="{{ post.data.permalink }}">{{ post.data.title }}</a></h3>
<time datetime="{{ post.data.page.date | HTMLdatetime }}">{{ post.data.page.date | datetime }}</time>
{% if post.data.introduction %}
<p style="font-size: 0.9rem;">
{% if post.data.archived %}
<span><strong><span style="font-family: 'Nunito', sans-serif">&#9888;</span> Archived</strong> | </span>
{% endif %}
{{ post.data.introduction }}
</p>
{% endif %}
<hr style="color: var(--color-secondary); border: 3px dotted; border-style: none none dotted;">
</div>
{% endfor %}
{% if events.featured %}
<h2>featured events</h2>
{% for event in events.featured %}
<div style="margin-bottom: 0.5rem;">
<h3 style="margin-bottom: 0;"><a style="text-decoration: none;" href="{{ event.link }}">{{ event.title }}</a></h3>
<p style="font-size: 0.9rem; margin-top: 0.4rem;">{{ event.description | markdown }}</p>
</div>
{% endfor %}
{% endif %}

View file

@ -1,19 +0,0 @@
---
layout: base_page.njk
---
# inicio
Soy Sofía Aritz, una joven programadora apasionada por la tecnología como herramienta de transformación social.
Trabajo en proyectos con un trasfondo social &mdash;como [Identity](https://git.sofiaritz.com/sofia/identity),
una iniciativa diseñada para contribuir a los cuidados paliativos y el tratamiento de condiciones como demencia&mdash; buscando soluciones que empoderen a las personas y fomenten la autonomía digital.
Siempre he tenido un fuerte interés en la relación entre el aspecto técnico, político y social del Software Libre.
Mi enfoque a la hora de desarrollar Software está profundamente influido por mi interés en los sistemas descentralizados y federados,
que considero fundamentales para construir un ecosistema tecnológico más justo y sostenible.
## afiliaciones
- Colaboradora del [Aula de Software Libre de la UCO](https://www.uco.es/aulasoftwarelibre/)
- Líder y desarrolladora principal de [Identity](https://git.sofiaritz.com/sofia/identity)

View file

@ -1,6 +1,7 @@
---
layout: base_page.njk
title: archived
layout: "layout"
permalink: /meta/archived/
archived: true
---
# archived pages

View file

@ -1,6 +1,5 @@
---
layout: base_page.njk
title: meta
layout: "layout"
---
# meta

View file

@ -1,8 +1,9 @@
---
layout: base_page.njk
title: maintenance tiers
layout: "layout"
permalink: /meta/maintenance-tiers/
---
# maintenance tiers
Not all projects are treated equal. Some are in active development, others are finished, others are deprecated, etc.

13
src/projects/gfonts.md Normal file
View file

@ -0,0 +1,13 @@
---
layout: "project"
description: "GFonts is a project aimed at providing a set of tools that together offer an open-source, self-hosted alternative to Google Fonts."
inactive: true
---
# GFonts
[Repositories](https://git.sofiaritz.com/GFonts) · [Website](https://gfonts.sofiaritz.com)
GFonts is a project aimed at providing a set of tools that together offer an open-source, self-hosted alternative to Google Fonts.
The project is still under development, and there isn't a post yet that systematically summarizes the project's objectives, motivations, and ideas. In the meantime, you can visit [my mirror of Google Fonts page for more information](https://cdn.sofiaritz.com/fonts/).

16
src/projects/index.liquid Normal file
View file

@ -0,0 +1,16 @@
---
layout: "layout"
title: projects
permalink: /projects/index.html
---
<h1>projects</h1>
Brief introduction to a few projects I've been leading or have created.
{% for project in collections.projects %}
<div>
<h2>{{ project.data.title }}</h2>
<p>{{ project.data.description }} <a href="{{ project.data.permalink }}">Learn more...</a></p>
</div>
{% endfor %}

36
src/projects/munin.md Normal file
View file

@ -0,0 +1,36 @@
---
layout: "project"
description: "Munin (prev. Identity) is a platform for securely preserving your personal heritage in an interoperable and federated system."
---
# Munin
[Repository](https://codeberg.org/Identity/munin) · [Website](https://munin.id) · [Posts](/weblog/tags/munin)
Munin (prev. Identity) is a platform for securely preserving your [personal heritage](#personal-heritage) in an interoperable and federated system.
- You can store your personal heritage, keeping your memories and experiences safe in a structured and meaningful way.
- You choose trusted custodians who may request access to your heritage (or a subset) under conditions you define, such as dementia or after your passing.
- Identity is built for interoperability, allowing seamless integration with other systems, ensuring broad accessibility and usability.
## Background
You can read more about the history and background of Munin in [an interview](https://fsfe.org/news/2025/news-20250107-01.en.html) by the [FSFE](https://fsfe.org) and in the [original repository](https://git.sofiaritz.com/sofia/identity).
## Contributing
You can contribute to Munin in many ways!
- If you'd like to contribute to its **technical development**, check [the contribution guidelines](https://codeberg.org/Identity/munin/src/branch/main/CONTRIBUTING.md)
- If you'd like to **report an issue**, go to our [Issue Tracker](https://codeberg.org/Identity/identity/issues)
- If you'd like to share your **thoughts and ideas**, fill the [_Identity: Ideas!_ form](https://cryptpad.fr/form/#/2/form/view/5jagE-jwyIueIHA0EHHXzEEIdSxyCJk4CT20kp8itVQ/)
- If you'd like to contribute with your knowledge, fill the [_Group of Experts: Expression of Interest_ form](https://cryptpad.fr/form/#/2/form/view/TBBGrmNwIH4VB95l+ok4P2o9p3Neh+OlRETl8+r4q8I/) and join our Group of Experts
You can always send an e-mail to [sofia@munin.id](mailto:sofia@munin.id) and it will be forwarded to the right people.
## Personal heritage
Personal heritage is the collection of memories, experiences, and key moments that shape an individual.
Personal heritage represents the unique narrative of someone's life, encompassing their thoughts, emotions, and personal history.
Personal heritage is deeply individual and can be shared, passed down, or integrated into various contexts, such as healthcare. In medical applications, personal heritage can provide valuable insight into a person's identity, contributing to more compassionate and personalized approaches to care, particularly in dementia and palliative treatment.

View file

@ -0,0 +1,21 @@
import slugify from '@sindresorhus/slugify';
export default function() {
return {
eleventyComputed: {
title: data => {
const content = data.page?.rawInput
const match = content?.match(/^#\s+(.+)$/m)
return match ? match[1].trim() : data.page.fileSlug
},
permalink: data => {
// Manually set
if (typeof data.permalink === "string") {
return data.permalink
}
return `/projects/${slugify(data.title)}/`
},
}
}
}

View file

@ -1,28 +0,0 @@
---
layout: base_page.njk
title: proyectos
---
# proyectos
## Identity
[Identity](https://git.sofiaritz.com/sofia/identity) es un proyecto con el objetivo de mejorar el tratamiento de condiciones como demencia y de los cuidados paliativos.
Ahora mismo el proyecto está bajo construcción.
## GFonts
[GFonts](https://git.sofiaritz.com/GFonts) es un proyecto cuyo objetivo es proveer una serie de herramientas que en
su conjunto ofrezcan una alternativa de código abierto y
[_autohospedada_](https://en.wikipedia.org/wiki/Self-hosting_(web_services)) de
[Google Fonts](https://fonts.google.com/).
El proyecto sigue en desarrollo, y aún no existe un post que resuma los objetivos, motivaciones e ideas del proyecto
de una manera sistemática. Mientras tanto, puedes visitar la página en mi
[mirror de Google Fonts](https://cdn.sofiaritz.com/fonts/) para obtener más información.
## otros
Puedes visitar mi [instancia de Forgejo](https://git.sofiaritz.com/explore/repos) para ver más proyectos míos y también
mi [cuenta de GitHub](https://github.com/sofiaritz) para ver mis contribuciones a otros proyectos.

View file

@ -1,19 +1,20 @@
---
layout: post.njk
title: Primer post
intro: El nacimiento de mi weblog! :)
layout: "post"
introduction: El nacimiento de mi weblog! :)
tags:
- meta
- archived
- es
date: 2023-03-12
permalink: /weblog/firstpost/
archived: true
---
# Primer post
Este es el primer post del weblog! Aquí iré compartiendo ideas, ocurrencias y experiencias a medida que me mueva por
los mundos de Internet y la programación.
Ahora mismo este weblog está parcialmente incompleto, pero dentro de poco añadiré las cosas que faltan para que esté
completamente a punto ([RSS](https://es.wikipedia.org/wiki/RSS), etiquetas, comentarios, etc).
Cualquier sugerencia o idea para este weblog podéis [enviármela](/contact) sin problema!
Cualquier sugerencia o idea para este weblog podéis [enviármela](/contact) sin problema!

View file

@ -1,17 +1,16 @@
---
layout: post.njk
title: Note Taking. Notas encriptadas
intro: Un programa experimental para encriptar notas.
layout: "post"
introduction: Un programa experimental para encriptar notas.
tags:
- rust
- experimentos
- note taking
- archived
- es
- note taking
- es
date: 2023-03-12
permalink: /weblog/note-taking-experiment/
archived: true
---
# Note Taking. Notas encriptadas
## motivación
Un día me di cuenta de que mi _setup_ para tomar notas era bastante engorroso: abría el bloc de notas, escribía, guardaba
@ -109,9 +108,7 @@ Cualquier idea es bienvenida! [Ponte en contacto conmigo](/contact) o abre una
[issue](https://git.sofiaritz.com/sofia/note-taking/issues) en el repositorio. :)
## imágenes
<img alt="Captura de pantalla donde se muestra una entrada de texto con los valores de entropía y longitud a la derecha en color verde, indicando así valores aceptables." src="/assets/weblog/note-taking-experimental/password-prompt.png" width="85%"/>
<img alt="Captura de pantalla donde se muestran los botones 'want to add one note?' y 'settings'" src="/assets/weblog/note-taking-experimental/top-buttons.png" width="85%"/>
<img alt="Captura de pantalla donde se muestra la lista de notas. En cada nota se muestra el título y su derecha la fecha. Bajo el título hay un botón que indica 'decrypt note'" src="/assets/weblog/note-taking-experimental/note-list.png" width="85%"/>
<img alt="Captura de pantalla donde se muestra el formulario de creación de notas, con diversas entradas de texto para el título, texto y metadatos. Al final hay un botón con el texto 'add note'" src="/assets/weblog/note-taking-experimental/note-creation.png" width="85%"/>
<img alt="Captura de pantalla donde se muestra una entrada de texto con los valores de entropía y longitud a la derecha en color verde, indicando así valores aceptables." src="./images/archived/password-prompt.png" width="85%"/>
<img alt="Captura de pantalla donde se muestran los botones 'want to add one note?' y 'settings'" src="./images/archived/top-buttons.png" width="85%"/>
<img alt="Captura de pantalla donde se muestra la lista de notas. En cada nota se muestra el título y su derecha la fecha. Bajo el título hay un botón que indica 'decrypt note'" src="./images/archived/note-list.png" width="85%"/>
<img alt="Captura de pantalla donde se muestra el formulario de creación de notas, con diversas entradas de texto para el título, texto y metadatos. Al final hay un botón con el texto 'add note'" src="./images/archived/note-creation.png" width="85%"/>

View file

@ -1,17 +1,16 @@
---
layout: post.njk
title: Note Taking (II). Retos
intro: Retos encontrados por el camino.
layout: "post"
introduction: Retos encontrados por el camino.
tags:
- rust
- experimentos
- note taking
- archived
- es
date: 2023-05-06
permalink: /weblog/note-taking-2/
archived: true
---
# Note Taking (II). Retos
Hace unos meses comencé a crear [Note Taking](https://git.sofiaritz.com/sofia/note-taking), una aplicación cuyo
propósito era la creación de un software que permitiera crear notas encriptadas de una manera sencilla y segura.
@ -26,7 +25,7 @@ los retos que me he encontrado en este camino.
La seguridad es sin duda uno de los apartados más importantes y complejos de este software. A día de hoy el sistema
utilizado es el siguiente:
<img src="/assets/weblog/archived/note-taking-2/diagram1.svg" width="100%">
<img alt="Diagrama mostrando el sistema utilizado: nota desencriptada, se hace SHA256 de la contraseña y ambos pasan por Argon2, usando eso como clave, se utiliza pwbox para producir la nota encriptada" src="./images/archived/diagram1.svg" width="100%">
Este sistema actualmente funciona bien:
* Todas las contraseñas tienen una alta entropía gracias al uso de Argon2 (un [KDF](https://es.wikipedia.org/wiki/Funci%C3%B3n_de_derivaci%C3%B3n_de_clave)).
@ -98,4 +97,4 @@ Sin duda crear este software está siendo una experiencia bastante interesante q
seguridad computacional y muchas otras cosas.
A lo largo de los meses venideros trataré de implementar estas y más cosas, subiré una actualización cuando ello ocurra
:)
:)

View file

@ -1,15 +1,16 @@
---
layout: post.njk
title: Major update
intro: The first major update to this website and the start of a new era.
layout: "post"
introduction: The first major update to this website and the start of a new era.
tags:
- meta
- website
- post
- en
date: 2023-11-28
permalink: /weblog/2023/11/major-update/
archived: true
---
# Major update
This website has received its first major update since
[Jan 2, 2023](https://git.sofiaritz.com/sofia/website/commit/cce91e6649575cb2ac5a19cbe4a058115df10a5a)! The design may
look familiar, but some things have changed:

View file

@ -1,14 +1,15 @@
---
layout: post.njk
title: "Identity: What's new? What's next?"
intro: It's been 9 months since the last Identity update, what's up?
layout: "post"
introduction: It's been 9 months since the last Identity update, what's up?
tags:
- identity
- post
- munin
- en
date: 2025-03-03
permalink: /weblog/2025/03/whats-new-whats-next-identity/
---
# Identity: What's new? What's next?
**TLDR;**
- The rewrite of Identity has resumed!
- The original Identity repository has been archived. Further development will continue in a new repository: <https://codeberg.org/Identity/identity>.

View file

@ -1,30 +0,0 @@
---
layout: base_page.njk
title: weblog
permalink: /en/weblog.html
lang: "en"
---
<h1>weblog</h1>
<div>
<span><a href="/weblog/tags/en">English posts</a></span> ·
<span><a href="/weblog/tags/es">Spanish posts</a></span>
</div>
<ul>
{% set taglist = collections["post"] %}
{% for post in taglist | reverse %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a>{% if post.data.intro %} · <span>{{ post.data.intro }}</span>{% endif %}</li>
{% endfor %}
</ul>
<details style="margin: 0; padding: 0" open>
<summary><h3 id="archived" style="display: inline">Archived</h3></summary>
<ul>
{% set taglist = collections["archived"] %}
{% for post in taglist | reverse %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
{% endfor %}
</ul>
</details>

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

31
src/weblog/index.liquid Normal file
View file

@ -0,0 +1,31 @@
---
layout: "layout"
eleventyExcludeFromCollections: true
permalink: /weblog/index.html
---
<h1>weblog</h1>
<p>Welcome to Sofía's weblog! A place for all kinds of updates, news, and miscellaneous thoughts.</p>
<h2>latest articles</h2>
<ul style="list-style-type: none; padding: 0;">
{% for post in collections.weblog %}
<li>
<div>
<h3 style="margin-bottom: 0.2rem;"><a style="text-decoration: none;" href="{{ post.data.permalink }}">{{ post.data.title }}</a></h3>
<time datetime="{{ post.data.page.date | HTMLdatetime }}">{{ post.data.page.date | datetime }}</time>
{% if post.data.introduction %}
<p style="font-size: 0.9rem;">
{% if post.data.archived %}
<span><strong><span style="font-family: 'Nunito', sans-serif">&#9888;</span> Archived</strong> | </span>
{% endif %}
{{ post.data.introduction }}
</p>
{% endif %}
<hr style="color: var(--color-secondary); border: 3px dotted; border-style: none none dotted;">
</div>
</li>
{% endfor %}
</ul>

View file

@ -1,28 +0,0 @@
---
layout: base_page.njk
title: weblog
---
<h1>weblog</h1>
<div>
<span><a href="/weblog/tags/es">Entradas en español</a></span> ·
<span><a href="/weblog/tags/en">Entradas en inglés</a></span>
</div>
<ul>
{% set taglist = collections["post"] %}
{% for post in taglist | reverse %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a>{% if post.data.intro %} · <span>{{ post.data.intro }}</span>{% endif %}</li>
{% endfor %}
</ul>
<details style="margin: 0; padding: 0" open>
<summary><h3 id="archived" style="display: inline">Archivado</h3></summary>
<ul>
{% set taglist = collections["archived"] %}
{% for post in taglist | reverse %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
{% endfor %}
</ul>
</details>

35
src/weblog/tags.liquid Normal file
View file

@ -0,0 +1,35 @@
---
layout: "layout"
pagination:
data: collections
size: 1
alias: tag
permalink: /weblog/tags/{{ tag }}/
---
<div id="title-header">
<a href="/weblog" style="text-decoration: none; font-family: 'Nunito', sans-serif">&larr; Weblog</a>
<h1 style="margin-top: 0.7rem;">Tagged “{{ tag }}”</h1>
</div>
{% assign taglist = collections[ tag ] %}
{% assign taglist = taglist | reverse %}
<ul style="list-style-type: none; padding: 0;">
{% for post in taglist %}
<li>
<div>
<h3 style="margin-bottom: 0.2rem;"><a style="text-decoration: none;" href="{{ post.permalink }}">{{ post.data.title }}</a></h3>
<time datetime="{{ post.page.date | HTMLdatetime }}">{{ post.page.date | datetime }}</time>
{% if post.data.introduction %}
<p style="font-size: 0.9rem;">
{% if post.archived %}
<span><strong><span style="font-family: 'Nunito', sans-serif">&#9888;</span> Archived</strong> | </span>
{% endif %}
{{ post.data.introduction }}
</p>
{% endif %}
<hr style="color: var(--color-secondary); border: 3px dotted; border-style: none none dotted;">
</div>
</li>
{% endfor %}
</ul>

View file

@ -1,22 +0,0 @@
---
layout: base_page.njk
pagination:
data: collections
size: 1
alias: tag
filter:
- archived
permalink: /weblog/tags/{{ tag }}/
---
<h1>Tagged “{{ tag }}”</h1>
<p>
Note: <a href="/meta/archived">Archived</a> posts may not be listed.
</p>
<ol>
{% set taglist = collections[ tag ] %}
{% for post in taglist | reverse %}
<li><a href="{{ post.url }}">{{ post.data.title }}</a> {% if post.data.intro %}<span>{{ post.data.intro }}</span>{% endif %}</li>
{% endfor %}
</ol>

View file

@ -1,7 +0,0 @@
---
layout: base_page.njk
---
# Tagged “archived”
[Archived](/meta/archived) posts are not listed here.

View file

@ -0,0 +1,21 @@
import slugify from '@sindresorhus/slugify';
export default function() {
return {
eleventyComputed: {
title: data => {
const content = data.page?.rawInput
const match = content?.match(/^#\s+(.+)$/m)
return match ? match[1].trim() : data.page.fileSlug
},
permalink: data => {
// Manually set
if (typeof data.permalink === "string") {
return data.permalink
}
return `/weblog/${slugify(data.title)}/`
},
}
}
}

View file

@ -1,102 +0,0 @@
:root {
font-family: "Rubik", Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 23px;
font-weight: 400;
min-height: 150vh;
color: rgba(255, 255, 255, 0.9);
background-color: #2d1740;
background-image: radial-gradient(hsl(324, 80%, 55%) 0.75px, hsl(273, 48%, 20%) 0.75px), radial-gradient(hsl(324, 80%, 55%) 0.75px, hsl(273, 48%, 20%) 0.75px);
background-size: 25px 25px;
background-position: 10px 10px;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
color: #e74cac;
}
body {
margin: 0;
}
body > h1 {
font-size: 50px;
text-align: center;
font-family: "Nunito", "Rubik", Inter, Avenir, Helvetica, Arial, sans-serif;
}
body > h1 > a {
color: #fafafa;
text-decoration: underline;
text-decoration-color: #d52c9c;
}
main {
width: 40vw;
padding: 1rem;
padding-bottom: 2rem;
background-color: rgba(10, 10, 10, 0.35);
border-radius: 5px;
margin-bottom: 10rem;
}
main > h1 {
line-height: 36px;
}
.page-container {
display: flex;
margin: 0 10px;
gap: 15px;
flex-direction: row-reverse;
justify-content: center;
}
@media only screen and (max-width: 900px) {
.page-container {
display: flex;
flex-direction: column-reverse;
width: 100%;
}
main {
width: 90%;
}
}
nav ul {
padding: 0;
list-style: none;
}
nav div ul a {
display: block;
width: 175px;
padding: 3px;
margin: 10px 0;
transition: all 150ms;
background-color: #dc3f99;
border: solid 3px;
border-color: #f38cc2 #dc158d #dc158d #f38cc2;
color: white;
}
@media only screen and (max-width: 900px) {
nav {
display: flex;
gap: 10px;
overflow: scroll;
}
}

View file

@ -1,39 +0,0 @@
.no-comments {
padding: 1rem 0;
}
.comment {
border: #382e60 solid 1px;
border-radius: 7px;
margin: 10px 0;
}
.comment-author {
display: flex;
gap: 5px;
padding: 5px;
background-color: hsl(273, 48%, 18%);
}
.comment-author-image {
border-radius: 4px;
height: 50px;
}
.comment-author-data {
display: flex;
flex-direction: column;
}
.comment-author-data > a, .comment-author-link {
text-decoration: none;
color: #fafafa;
}
.comment-author-data > a:hover, .comment-author-link:hover {
color: #e74cac;
}
.comment-content {
padding: 3px 10px;
}

File diff suppressed because one or more lines are too long

View file

@ -1,43 +0,0 @@
(async () => {
let el = document.getElementById("comment-section")
if (el == null) {
return
}
let status_url = `https://hachyderm.io/api/v1/statuses/${el.getAttribute("data-status")}/context`
let comments = await (await fetch(status_url)).json()
if (comments["descendants"] == null || comments["descendants"].length === 0) {
el.innerHTML = `<div class="no-comments">No comments yet</div>`
return
}
for (let comment of comments["descendants"]) {
let date = new Date(comment.created_at).toLocaleDateString(navigator.language || "en-GB", {
day: "2-digit",
year: "numeric",
month: "long",
hour: "2-digit",
minute: "2-digit",
})
let sanitize = DOMPurify.sanitize
let comment_html =
`
<div class="comment">
<div class="comment-author">
<img class="comment-author-image" src="${sanitize(comment.account.avatar)}" alt="Profile picture of ${sanitize(comment.account.display_name)}">
<div class="comment-author-data">
<div>
<span class="comment-author-name"><a class="comment-author-link" href="${comment.account.url}">${sanitize(comment.account.display_name)}</a></span>
</div>
<a href="${sanitize(comment.uri)}"><time datetime="${sanitize(comment.created_at)}">${date}</time></a>
</div>
</div>
<div class="comment-content">
${sanitize(comment.content)}
</div>
</div>
`
el.innerHTML += comment_html
}
})()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

View file

@ -1,2 +0,0 @@
User-agent: GPTBot
Disallow: /

4162
yarn.lock

File diff suppressed because it is too large Load diff