Compare commits

..

36 Commits

Author SHA1 Message Date
3ebb70a524 cande laptop
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-20 12:32:55 +01:00
c4c5cd40af test2
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2024-11-13 15:59:42 +01:00
d0120c4144 test
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2024-11-13 15:05:39 +01:00
32a75322e5 sum pc 2024-11-13 10:41:50 +01:00
7eb0356860 git restore mtime
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 19:32:15 +02:00
c50c3ca37a debug
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 19:01:28 +02:00
444a937d0b no css
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 18:51:24 +02:00
81b8deb4cf build dst
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 18:45:02 +02:00
4d13fc9604 :)
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 18:29:55 +02:00
000e49afd7 laptops 2024-06-20 20:52:54 +02:00
3bec601f31 yes
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-14 11:49:29 +02:00
9e0f049a52 ubuntu
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-14 11:45:36 +02:00
dbcdea640a standalone
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-14 00:43:47 +02:00
015e7b6ed2 rm
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-14 00:34:39 +02:00
c0debe8c47 _site
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-14 00:32:14 +02:00
c902b1e87f alpine has a differente date command
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-14 00:25:02 +02:00
dacdd27a73 bash
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-14 00:04:28 +02:00
836e85c086 idk
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-14 00:02:12 +02:00
d37c580263 no perms?
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-13 23:02:28 +02:00
e15d9075e7 aaa
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-13 22:29:49 +02:00
9641c44657 code location
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-13 22:27:09 +02:00
7ccd4a8dc6 build location
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-13 22:11:03 +02:00
44c32bf138 new build system and structure using pandoc
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-13 22:06:56 +02:00
9d6ceb3121 _site dir
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-14 15:01:56 +02:00
cdfb6edc04 direct deploy
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-14 14:57:37 +02:00
4eff6d90da back to drone
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-14 14:20:47 +02:00
e89718fc2a label
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 25s
2023-08-14 12:23:18 +02:00
8b218d1497 testing actions
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1m4s
2023-08-14 12:17:57 +02:00
105ac552b0 no m.2
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-06-08 18:40:38 +02:00
7318e2c550 Add 'alba.txt'
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-06-08 16:23:38 +00:00
2e3b4c02f7 Update 'nas.txt' 2023-06-08 16:17:39 +00:00
980b2329ae Update 'tara.txt' 2023-06-08 16:14:25 +00:00
d0633a734d pc 2
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-31 18:32:06 +01:00
5dc359995f vpn 2023-01-31 18:19:20 +01:00
4726f07ea7 unraid 2023-01-31 18:19:20 +01:00
660b758927 10gb lan 2023-01-31 18:19:20 +01:00
85 changed files with 827 additions and 2883 deletions

View File

@ -1,39 +1,20 @@
---
kind: pipeline
type: docker
name: deploy-jekyll-sergio.am
name: deploy-sergio.am
steps:
- name: build
image: ruby:latest
volumes:
- name: bundle-cache
path: /cache
image: ubuntu:latest
commands:
- bundle config set --local path /cache/.bundle
- bundle install
- bundle exec jekyll build
- name: deploy
image: busybox
volumes:
- name: www
path: /tmp/www
commands:
- rm -rf /tmp/www/_site
- cp -r _site /tmp/www/_site
- apt -y update && apt -y install bash git git-restore-mtime jq pandoc
- git restore-mtime
- bash ./build.sh
- rm -rf /var/www/_site && mv _site /var/www/
when:
branch:
- main
node:
location: marley
volumes:
- name: bundle-cache
host:
path: /var/lib/drone/temp/ruby-bundle-cache-sergio.am
- name: www
host:
path: /var/www
location: nexus

8
404.md
View File

@ -1,5 +1,7 @@
---
title: 404
layout: 404
permalink: "/404.html"
title: 404 Not found!
---
Lo que sea que buscabas ya no está aquí.
The content you are looking for it's no longer here.

35
Gemfile
View File

@ -1,35 +0,0 @@
source "https://rubygems.org"
gem "webrick"
# Hello! This is where you manage which Jekyll version is used to run.
# When you want to use a different version, change it below, save the
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
#
# bundle exec jekyll serve
#
# This will help ensure the proper Jekyll version is running.
# Happy Jekylling!
gem "jekyll", "~> 4.1.0"
# This is the default theme for new Jekyll sites. You may change this to anything you like.
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
# gem "github-pages", group: :jekyll_plugins
# If you have any plugins, put them here!
group :jekyll_plugins do
gem 'jekyll-feed', '~> 0.13'
gem 'jekyll-sitemap', '~> 1.4'
gem 'jekyll-compose', '~> 0.12.0'
gem 'jekyll-postfiles', '~> 3.1'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
# gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# Performance-booster for watching directories on Windows
# gem "wdm", "~> 0.1.0" if Gem.win_platform?
#

View File

@ -1,12 +1,10 @@
---
title: Licencia
permalink: /LICENSE/
layout: page
---
MIT License
Copyright (c) 2021 Sergio Álvarez
Copyright (c) 2024 Sergio Álvarez
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,24 +1,12 @@
# sergio.am
Notas y apuntes, futuro contenido de static pages en sergio.am
Static content.
## Dev
```shell
docker run -it --rm --volume="$PWD:/srv/jekyll:Z" jekyll/jekyll jekyll build
docker run -it --rm --volume="$PWD:/srv/jekyll:Z" -p 4000:4000 jekyll/jekyll jekyll serve
python3 -m http.server -b "::" -d dist/ 4000
```
```shell
cd _site
python3 -m http.server 4000
```
http://localhost:4000
# Drafts
Usar directorio `_drafts` y para ver el doc usar:
```shell
docker run -it --rm --volume="$PWD:/srv/jekyll:Z" -p 4000:4000 jekyll/jekyll jekyll serve --drafts
```
http://[::]:4000 (ipv6 to bypass WSL2 networking issues)

View File

@ -1,84 +0,0 @@
# Site settings
title: sergio.am
description: >- # site description
Notas y apuntes de cosas con las que suelo perder el tiempo, para mi yo del futuro.
lang: es-ES
timezone: Europe/Madrid
image: assets/img/sergio.png # This image used for Open Graph more info https://ogp.me/
mode: dark # default theme "dark" | "light"
# Profile settings
author:
name: Sergio Álvarez
bio: >- # tell to the world
Notas y apuntes para mi yo del futuro.
username: sergioam # general username
github: xergio # github username
twitter: xergio # twitter username
email: correo@sergio.am # email adress
avatar: /assets/img/sergio100w.jpg # change with your own avatar
# URL settings
url: "https://sergio.am" #
baseurl:
permalink: /read/:title/
google_analytics: # leave it blank if not wish
fb_appid:
# Collection setting
collections:
posts:
output: true
# Markdown settings
markdown: kramdown
highlighter: rouge
kramdown:
syntax_highlighter: rouge
# Default front matter
defaults:
- scope:
path: ""
values:
layout: post
comments: false
# Jekyll Compose default front matter
jekyll_compose:
post_default_front_matter:
modified:
tags: []
description:
draft_default_front_matter:
modified:
tags: []
description:
# Homepage limit posts
number_of_posts: 5000
# Build settings
# theme: klise
sass:
style: compressed
exclude:
- CNAME
- Gemfile
- Gemfile.lock
- CHANGELOG.md
- README.md
- node_modules
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- lighthouse.png
- klise-*.gem
- klise.gemspec
- vendor
# Plugins
plugins:
- jekyll-feed
- jekyll-sitemap
- jekyll-postfiles

View File

@ -1,14 +0,0 @@
- title: Inicio
url: /
- title: Código fuente
url: https://sergio.am/code/sergio.am
- title: Regexp
url: https://xrg.es/
- title: Dencode
url: https://dencode.xrg.es/
- title: Contacto
url: /contact/

View File

@ -1,105 +0,0 @@
{% capture headingsWorkspace %}
{% comment %}
Version 1.0.4
https://github.com/allejo/jekyll-anchor-headings
"Be the pull request you wish to see in the world." ~Ben Balter
Usage:
{% include anchor_headings.html html=content %}
Parameters:
* html (string) - the HTML of compiled markdown generated by kramdown in Jekyll
Optional Parameters:
* beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content
* anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `<a>` tag; you may NOT use `href`, `class` or `title`
* anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is available
* anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a space
* anchorTitle (string) : '' - The `title` attribute that will be used for anchors
* h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be ignored
* h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be ignored
* bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and content
* bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and content
Output:
The original HTML with the addition of anchors inside of all of the h1-h6 headings.
{% endcomment %}
{% assign minHeader = include.h_min | default: 1 %}
{% assign maxHeader = include.h_max | default: 6 %}
{% assign beforeHeading = include.beforeHeading %}
{% assign nodes = include.html | split: '<h' %}
{% capture edited_headings %}{% endcapture %}
{% for _node in nodes %}
{% capture node %}{{ _node | strip }}{% endcapture %}
{% if node == "" %}
{% continue %}
{% endif %}
{% assign nextChar = node | replace: '"', '' | strip | slice: 0, 1 %}
{% assign headerLevel = nextChar | times: 1 %}
<!-- If the level is cast to 0, it means it's not a h1-h6 tag, so let's try to fix it -->
{% if headerLevel == 0 %}
{% if nextChar != '<' and nextChar != '' %}
{% capture node %}<h{{ node }}{% endcapture %}
{% endif %}
{% capture edited_headings %}{{ edited_headings }}{{ node }}{% endcapture %}
{% continue %}
{% endif %}
{% assign _workspace = node | split: '</h' %}
{% assign _idWorkspace = _workspace[0] | split: 'id="' %}
{% assign _idWorkspace = _idWorkspace[1] | split: '"' %}
{% assign html_id = _idWorkspace[0] %}
{% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %}
{% assign header = _workspace[0] | replace: _hAttrToStrip, '' %}
<!-- Build the anchor to inject for our heading -->
{% capture anchor %}{% endcapture %}
{% if html_id and headerLevel >= minHeader and headerLevel <= maxHeader %}
{% capture anchor %}href="#{{ html_id }}"{% endcapture %}
{% if include.anchorClass %}
{% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %}
{% endif %}
{% if include.anchorTitle %}
{% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', header }}"{% endcapture %}
{% endif %}
{% if include.anchorAttrs %}
{% capture anchor %}{{ anchor }} {{ include.anchorAttrs }}{% endcapture %}
{% endif %}
{% capture anchor %}<a {{ anchor }}>{{ include.anchorBody | replace: '%heading%', header | default: '' }}</a>{% endcapture %}
<!-- In order to prevent adding extra space after a heading, we'll let the 'anchor' value contain it -->
{% if beforeHeading %}
{% capture anchor %}{{ anchor }} {% endcapture %}
{% else %}
{% capture anchor %} {{ anchor }}{% endcapture %}
{% endif %}
{% endif %}
{% capture new_heading %}
<h{{ _hAttrToStrip }}
{{ include.bodyPrefix }}
{% if beforeHeading %}
{{ anchor }}{{ header }}
{% else %}
{{ header }}{{ anchor }}
{% endif %}
{{ include.bodySuffix }}
</h{{ _workspace | last }}
{% endcapture %}
{% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %}
{% endfor %}
{% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }}

View File

@ -1,9 +0,0 @@
<div class="author">
<img
class="author-avatar"
src="{{ site.author.avatar }}"
alt="{{ site.author.username }}"
/>
<h2 class="author-name">{{ site.author.name }}</h2>
<p class="author-bio">{{ site.author.bio }}</p>
</div>

View File

@ -1,10 +0,0 @@
<!-- unnecessary file, however you can still use for comment section, e.g disqus -->
<script
src="https://utteranc.es/client.js"
repo="username/reponame"
issue-term="pathname"
label="✨ comment ✨"
theme="github-light"
crossorigin="anonymous"
async
></script>

View File

@ -1,22 +0,0 @@
<footer class="footer">
<span class="footer_item"><a href="/LICENSE">&copy; Sergio Álvarez</a> <span title="Last build: {{ site.time | date_to_xmlschema }}">🔨 {{ site.time | date: "%d %b %Y" }}</span> <img src="https://ci.sergio.am/api/badges/code/sergio.am/status.svg" alt="Status" /></span>
</footer>
<script src="/assets/js/main.js" defer="defer"></script>
{%- if page.google_analytics -%}
<script src="/assets/js/galite.js"></script>
<script>
var galite = galite || {};
galite.UA = "{{ site.google_analytics }}";
</script>
{%- endif -%}
{%- if page.url == '/archive/' -%}
<script src="/assets/js/search.min.js"></script>
<script>
var sjs = SimpleJekyllSearch({
searchInput: document.getElementById('search-input'),
resultsContainer: document.getElementById('search-results'),
json: '/assets/search.json',
});
</script>
{%- endif -%}

View File

@ -1,142 +0,0 @@
<head prefix="og: http://ogp.me/ns#">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="application-name" content="{{ site.title }}" />
<meta name="apple-mobile-web-app-status-bar-style" content="#fff" />
<meta name="apple-mobile-web-app-title" content="{{ site.title }}" />
<title>
{% if page.title %}{{ page.title | escape }} - {{ site.title }}{% else %}{{
site.title | escape }}{% endif %}
</title>
<link
rel="alternate"
href="{{
page.url | remove: 'index.html' | remove: '.html' | absolute_url
}}"
hreflang="{{ site.lang }}"
/>
<link
rel="canonical"
href="{{
page.url | remove: 'index.html' | remove: '.html' | absolute_url
}}"
/>
{% if paginator.previous_page %}
<link
rel="prev"
href="{{
paginator.previous_page_path
| remove: 'index.html'
| remove: '.html'
}}"
/>
{% endif %} {% if paginator.next_page %}
<link
rel="next"
href="{{
paginator.next_page_path
| remove: 'index.html'
| remove: '.html'
}}"
/>
{% endif %}
<meta
name="description"
content="{{
page.description
| default: site.description
| strip_html
| normalize_whitespace
| truncate: 200
| escape
}}"
/>
<meta name="referrer" content="no-referrer-when-downgrade" />
<meta property="fb:app_id" content="{{ site.fb_appid }}" />
<meta
property="og:site_name"
content="{% if page.title %}{{ page.title | escape }} | {{
site.author.name
}}{% else %}{{ site.title | escape }}{% endif %}"
/>
<meta
property="og:title"
content="{% if page.title %}{{ page.title | escape }} | {{
site.author.name
}}{% else %}{{ site.title | escape }}{% endif %}"
/>
{% if page.location %}
<meta property="og:type" content="article" />
<meta
property="article:publisher"
content="https://web.facebook.com/{{ site.author.facebook }}"
/>
{% else %}
<meta property="og:type" content="website" />
{% endif %}
<meta
property="og:url"
content="{{
page.url | remove: 'index.html' | remove: '.html' | absolute_url
}}"
/>
<meta
property="og:description"
content="{{
page.description
| default: site.description
| strip_html
| normalize_whitespace
| truncate: 200
| escape
}}"
/>
{% if page.image %}
<meta property="og:image" content="{{ page.image | absolute_url }}" />
{% else %}
<meta property="og:image" content="{{ site.image | absolute_url }}" />
{% endif %}
<meta property="og:image:width" content="640" />
<meta property="og:image:height" content="640" />
<meta name="twitter:card" content="summary" />
<meta
name="twitter:title"
content="{% if page.title %}{{ page.title | escape }} | {{
site.author.twitter
}}{% else %}{{ site.title | escape }}{% endif %}"
/>
<meta
name="twitter:url"
content="{{
page.url | remove: 'index.html' | remove: '.html' | absolute_url
}}"
/>
<meta name="twitter:site" content="@{{ site.author.twitter }}" />
<meta name="twitter:creator" content="@{{ site.author.twitter }}" />
<meta
name="twitter:description"
content="{{
page.description
| default: site.description
| strip_html
| normalize_whitespace
| truncate: 200
| escape
}}"
/>
{% if page.image %}
<meta name="twitter:image" content="{{ page.image | absolute_url }}" />
{% else %}
<meta name="twitter:image" content="{{ site.image | absolute_url }}" />
{% endif %} {% feed_meta %}
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
<link rel="manifest" href="/assets/favicons/site.webmanifest">
<link rel="stylesheet" href="/assets/css/style.css" />
</head>

View File

@ -1,9 +0,0 @@
{% capture imagePath %}{{ page.date | date: "%Y-%m-%d" }}-{{ page.title | slugify }}/{{ include.name }}{% endcapture %}
{% if include.caption %}
<figure>
<img src="/assets/posts/{{ imagePath }}" {% if include.alt %} alt="{{ include.alt }}" {% endif %} {% if include.width %} width="{{ include.width }}" {% endif %}/>
<figcaption>{{ include.caption }}</figcaption>
</figure>
{% else %}
<img src="/assets/posts/{{ imagePath }}" {% if include.alt %} alt="{{ include.alt }}" {% endif %} {% if include.width %} width="{{ include.width }}" {% endif %}/>
{% endif %}

View File

@ -1,201 +0,0 @@
<div class="navbar" role="navigation">
<nav class="menu">
<input type="checkbox" id="menu-trigger" class="menu-trigger" />
<label for="menu-trigger">
<span class="menu-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512"
>
<path
d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z"
/>
</svg>
</span>
</label>
<div class="trigger">
<div class="trigger-container">
{%- assign url = page.url -%}
{%- assign menus = site.data.menus -%}
{%- if menus %}
{%- for menu in menus -%}
{%- if url == menu.url -%}
<a class="menu-link active" href="{{ menu.url }}">{{ menu.title }}</a>
{%- else -%}
<a class="menu-link" href="{{ menu.url }}">{{ menu.title }}</a>
{%- endif -%}
{%- endfor -%}
{%- else -%}
<a class="menu-link {% if url == '/' %}active{% endif %}" href="/">home</a>
<a class="menu-link {% if url == '/about/' %}active{% endif %}" href="/about">about</a>
{%- endif -%}
<a class="menu-link rss" href="/feed.xml">
<svg
xmlns="http://www.w3.org/2000/svg"
width="17"
height="17"
viewBox="0 0 512 512"
fill="#ED812E"
>
<title>RSS</title>
<path
d="M108.56,342.78a60.34,60.34,0,1,0,60.56,60.44A60.63,60.63,0,0,0,108.56,342.78Z"
/>
<path
d="M48,186.67v86.55c52,0,101.94,15.39,138.67,52.11s52,86.56,52,138.67h86.66C325.33,312.44,199.67,186.67,48,186.67Z"
/>
<path
d="M48,48v86.56c185.25,0,329.22,144.08,329.22,329.44H464C464,234.66,277.67,48,48,48Z"
/>
</svg>
</a>
</div>
</div>
<a id="mode">
<svg
class="mode-sunny"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512"
>
<title>LIGHT</title>
<line
x1="256"
y1="48"
x2="256"
y2="96"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="256"
y1="416"
x2="256"
y2="464"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="403.08"
y1="108.92"
x2="369.14"
y2="142.86"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="142.86"
y1="369.14"
x2="108.92"
y2="403.08"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="464"
y1="256"
x2="416"
y2="256"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="96"
y1="256"
x2="48"
y2="256"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="403.08"
y1="403.08"
x2="369.14"
y2="369.14"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="142.86"
y1="142.86"
x2="108.92"
y2="108.92"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<circle
cx="256"
cy="256"
r="80"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
</svg>
<svg
class="mode-moon"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 512 512"
>
<title>DARK</title>
<line
x1="256"
y1="48"
x2="256"
y2="96"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="256"
y1="416"
x2="256"
y2="464"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="403.08"
y1="108.92"
x2="369.14"
y2="142.86"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="142.86"
y1="369.14"
x2="108.92"
y2="403.08"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="464"
y1="256"
x2="416"
y2="256"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="96"
y1="256"
x2="48"
y2="256"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="403.08"
y1="403.08"
x2="369.14"
y2="369.14"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<line
x1="142.86"
y1="142.86"
x2="108.92"
y2="108.92"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
<circle
cx="256"
cy="256"
r="80"
style="stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"
/>
</svg>
</a>
</nav>
</div>

View File

@ -1,16 +0,0 @@
<nav class="post-nav">
{% if page.previous %}
<a
class="post-nav-item post-nav-prev"
href="{{ page.previous | relative_url }}"
>
<div class="nav-arrow">↶ Anterior</div>
<span class="post-title">{{ page.previous.title }}</span>
</a>
{% endif %} {% if page.next %}
<a class="post-nav-item post-nav-next" href="{{ page.next | relative_url }}">
<div class="nav-arrow">Siguiente ↷</div>
<span class="post-title">{{ page.next.title }}</span>
</a>
{% endif %}
</nav>

View File

@ -1,21 +0,0 @@
<!-- NOTE: unused file, but u can use if necessary -->
<!-- <div class="pagination">
{% if paginator.previous_page %}
<a
class="page-previous"
href="{{ paginator.previous_page_path }}"
class="previous"
>
<span aria-hidden="true">←</span> NEWER POSTS
</a>
{% endif %}
<span class="page_number"
>PAGE {{ paginator.page }} OF {{ paginator.total_pages }}</span
>
{% if paginator.next_page %}
<a class="page-next" href="{{ paginator.next_page_path }}" class="next"
>OLDER POSTS
<span aria-hidden="true">→</span>
</a>
{% endif %}
</div> -->

View File

@ -1,46 +0,0 @@
---
layout: compress
---
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: ' en ' }}">
{% include header.html %}
<body data-theme="{{ site.mode }}" class="notransition">
<script>
const body = document.body;
const data = body.getAttribute("data-theme");
const initTheme = (state) => {
if (state === "dark") {
body.setAttribute("data-theme", "dark");
} else if (state === "light") {
body.removeAttribute("data-theme");
} else {
localStorage.setItem("theme", data);
}
};
initTheme(localStorage.getItem("theme"));
setTimeout(() => body.classList.remove("notransition"), 75);
</script>
{% include navbar.html %}
<div class="wrapper">
<main aria-label="Content">
<div class="not-found">
<div class="container">
<div class="title">404</div>
<p class="phrase">😕 Hmm... Parece que aquí no hay nada...</p>
<a class="solution" href="{{ site.url }}">volver al inicio</a>
</div>
</div>
</main>
{% include footer.html %}
</div>
</body>
</html>

View File

@ -1,4 +0,0 @@
---
---
{% if site.compress_html.ignore.envs contains jekyll.environment %}{{ content }}{% else %}{% capture _content %}{{ content }}{% endcapture %}{% if site.compress_html.endings == "all" %}{% assign _endings = "html head body li dt dd p rt rp optgroup option colgroup caption thead tbody tfoot tr td th" | split: " " %}{% else %}{% assign _endings = site.compress_html.endings %}{% endif %}{% for _element in _endings %}{% capture _end %}</{{ _element }}>{% endcapture %}{% assign _content = _content | remove: _end %}{% endfor %}{% if site.compress_html.comments.size == 2 %}{% assign _comment_befores = _content | split: site.compress_html.comments.first %}{% for _comment_before in _comment_befores %}{% assign _comment_content = _comment_before | split: site.compress_html.comments.last | first %}{% if _comment_content %}{% capture _comment %}{{ site.compress_html.comments.first }}{{ _comment_content }}{{ site.compress_html.comments.last }}{% endcapture %}{% assign _content = _content | remove: _comment %}{% endif %}{% endfor %}{% endif %}{% assign _pre_befores = _content | split: "<pre" %}{% assign _content = "" %}{% for _pre_before in _pre_befores %}{% assign _pres = _pre_before | split: "</pre>" %}{% case _pres.size %}{% when 2 %}{% capture _content %}{{ _content }}<pre{{ _pres.first }}</pre>{{ _pres.last | split: " " | join: " " }}{% endcapture %}{% when 1 %}{% capture _content %}{{ _content }}{{ _pres.last | split: " " | join: " " }}{% endcapture %}{% endcase %}{% endfor %}{% if site.compress_html.clippings == "all" %}{% assign _clippings = "html head title base link meta style body article section nav aside h1 h2 h3 h4 h5 h6 hgroup header footer address p hr blockquote ol ul li dl dt dd figure figcaption main div table caption colgroup col tbody thead tfoot tr td th" | split: " " %}{% else %}{% assign _clippings = site.compress_html.clippings %}{% endif %}{% for _element in _clippings %}{% assign _edges = " <e;<e; </e>;</e>;</e> ;</e>" | replace: "e", _element | split: ";" %}{% assign _content = _content | replace: _edges[0], _edges[1] | replace: _edges[2], _edges[3] | replace: _edges[4], _edges[5] %}{% endfor %}{{ _content }}{% endif %}

View File

@ -1,38 +0,0 @@
---
layout: compress
---
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: " en " }}">
{% include header.html %}
<body data-theme="{{ site.mode }}" class="notransition">
<script>
const body = document.body;
const data = body.getAttribute("data-theme");
const initTheme = (state) => {
if (state === "dark") {
body.setAttribute("data-theme", "dark");
} else if (state === "light") {
body.removeAttribute("data-theme");
} else {
localStorage.setItem("theme", data);
}
};
initTheme(localStorage.getItem("theme"));
setTimeout(() => body.classList.remove("notransition"), 75);
</script>
{% include navbar.html %}
<div class="wrapper">
{% include author.html %}
<main aria-label="Content">
{{ content }}
</main>
</div>
{% include footer.html %}
</body>
</html>

View File

@ -1,14 +0,0 @@
---
layout: default
home: true
---
<h3 class="posts-item-note" aria-label="Recent Posts">Recent Posts ↓</h3>
{%- for post in site.posts limit: site.number_of_posts -%}
<article class="post-item">
<span class="post-item-date">{{ post.date | date: "%d %b %Y" }}</span>
<h4 class="post-item-title">
<a href="{{ post.url }}">{{ post.title | escape }}</a>
</h4>
</article>
{%- endfor -%}

View File

@ -1,43 +0,0 @@
---
layout: compress
---
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: " en " }}">
{% include header.html %}
<body data-theme="{{ site.mode }}" class="notransition">
<script>
const body = document.body;
const data = body.getAttribute("data-theme");
const initTheme = (state) => {
if (state === "dark") {
body.setAttribute("data-theme", "dark");
} else if (state === "light") {
body.removeAttribute("data-theme");
} else {
localStorage.setItem("theme", data);
}
};
initTheme(localStorage.getItem("theme"));
setTimeout(() => body.classList.remove("notransition"), 75);
</script>
{% include navbar.html %}
<div class="wrapper">
<header class="header">
<h1 class="header-title center" itemprop="headline">{{ page.title | escape }}.</h1>
</header>
<main class="page-content" aria-label="Content">
{% include anchor_headings.html html=content anchorClass="anchor-head" beforeHeading=true h_min=4 h_max=4 %}
</main>
</div>
{% include footer.html %}
</body>
</html>

View File

@ -1,101 +0,0 @@
---
layout: compress
---
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: "en" }}">
{% include header.html %}
<body data-theme="{{ site.mode }}" class="notransition">
<script>
const body = document.body;
const data = body.getAttribute("data-theme");
const initTheme = (state) => {
if (state === "dark") {
body.setAttribute("data-theme", "dark");
} else if (state === "light") {
body.removeAttribute("data-theme");
} else {
localStorage.setItem("theme", data);
}
};
initTheme(localStorage.getItem("theme"));
setTimeout(() => body.classList.remove("notransition"), 75);
</script>
{% include navbar.html %}
<div class="wrapper post">
<main class="page-content" aria-label="Content">
<article itemscope itemtype="https://schema.org/BlogPosting">
<header class="header">
<h1 class="header-title" itemprop="headline">{{ page.title | escape }}</h1>
{% if page.date %}
<div class="post-meta">
<time datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
{{ page.date | date: "%d %b %Y" }}
</time>
<span hidden itemprop="author" itemscope itemtype="https://schema.org/Person">
<span itemprop="name">{{ site.author.name }}</span>
</span>
{% if page.tags and page.tags != empty %}
<!--
<small class="tags">
{% assign tags = page.tags %}
<span itemprop="keywords">
&lt;
{% for tag in tags %}
<a class="tag"
href="/tags/#{{tag | downcase | slugify}}">{{tag | upcase }}</a>{% unless forloop.last %},{% endunless %}
{% endfor %}
/&gt;
</span>
</small>
-->
{% endif %}
<time hidden datetime="{{ page.modified | date_to_xmlschema }}" itemprop="dateModified">
{{ page.date | date: "%b %d, %Y" }}
</time>
<span hidden itemprop="publisher" itemtype="Person">{{ site.author.name }}</span>
<span hidden itemprop="image">{{ page.image }}</span>
<span hidden itemprop="mainEntityOfPage">{{ page.excerpt }}</span>
</div>
{% endif %}
</header>
<div class="page-content" itemprop="articleBody">
{% include anchor_headings.html html=content anchorClass="anchor-head" beforeHeading=true h_min=1 h_max=4 %}
{% if page.tweet %}
<p>Comments this article on
<a href="https://twitter.com/{{site.twitter}}/status/{{page.tweet}}">Twitter</a>.
</p>
{% endif %}
</div>
</article>
{% if page.comments %}
{% include comments.html %}
{% endif %}
</main>
{% if page.modified %}
<small class="post-updated-at">updated_at {{page.modified | date: "%d-%m-%Y"}}</small>
{% endif %}
{% if page.next or page.previous %}
{% include navigation.html %}
{% endif %}
</div>
{% include footer.html %}
</body>
</html>

View File

@ -7,14 +7,14 @@ Primer post, sin mucho que contar para variar. Al menos habrá un bonito _commit
La chuleta para hacer andar esto es la siguiente:
```shell
```bash
docker run -it --rm --volume="$PWD:/srv/jekyll:Z" jekyll/jekyll jekyll build
docker run -it --rm --volume="$PWD:/srv/jekyll:Z" -p 4000:4000 jekyll/jekyll jekyll serve
```
O bien, si ya está _buildeado_:
```shell
```bash
cd _site
python3 -m http.server 4000
```

View File

@ -0,0 +1,97 @@
---
layout: post
title: "MagicMirror con sensor de movimiento"
---
Un MagicMirror no es más que un "espejo" con una pantalla detrás que muestra información "impresa" en el espejo. Y digo "espejo" porque esto no se hace con un espejo normal, sino con un vinilo unidireccional, como el de los cristales de las salas de interrogatorios de las pelis.
Para que este vinilo funcione se necesita un requisito imprescindible: que la parte de detrás del reflejo sea oscuro, o más escruto que lo de en frente. Si este vinilo lo pones en una ventana normal, de día verás tu reflejo al haber más luz fuera que dentro, pero si iluminas el interior, o fuera es de noche, se ve todo el interior. O gran parte.
He aprovechado una RaspberryPi 3b+ que no le daba uso ya para hacer este tinglado. Lo que se necesita, a grandes rasgos:
### Una raspi
Recomiendo usar Raspbian de 64bits. El resto de la instalación es standart. Le instalamos [MagicMirror](https://magicmirror.builders/) como dicen la documentación. No entraré en detalles de eso, no he hecho nada fuera de lo común.
### Un monitor/pantalla
Voy a usar un monitor viejo, solo tiene DVI así que le he puesto un adaptador HDMI-DVI. Lo he desmontado/destripado y me quedaré solo con la pantalla en si y la circuitería.
### Sensor de movimiento
Para encender/apagar la pantalla. No tiene sentido tenerla encendida el 100% del tiempo, solo cuando vea que me acerco. [He pillado este](https://www.amazon.es/gp/product/B07CNBYRQ7/ref=ppx_yo_dt_b_asin_title_o05_s00?ie=UTF8&th=1). Cableado:
![wiring](/assets/magicmirror/pir_wiring.png)
Yo he usado [los pines 4, 6 y 8](https://gpiozero.readthedocs.io/en/stable/recipes.html#pin-numbering), por quedar juntos. El pin 8 es el GPIO14.
[Mucha info sobre cómo usar el PIR con la Raspi](https://projects.raspberrypi.org/en/projects/physical-computing/11).
### Cables
Jumper cables, un alargo, un ladrón. Hay que conectar el sensor a la raspi, la raspi y el monitor a la luz, la raspi a la pantalla, etc. Cables por todos lados.
# Configuración de la Raspi
A parte [meter en el arranque el MM²](https://docs.magicmirror.builders/configuration/autostart.html) y de [desactivar el protector de pantalla](https://github.com/MichMich/MagicMirror/wiki/Configuring-the-Raspberry-Pi#disabling-the-screensaver), he tenido que usar `vcgencmd` en vez de `tvservice`:
```
tvservice is not supported when using the vc4-kms-v3d driver.
Similar features are available with standard linux tools
such as modetest from libdrm-tests.
```
Se podríá usar otro driver, pero entonces Electron se come la raspi.
Pero es lo mismo, `vcgencmd display_power 0` para apagar la pantalla, `1` para encender. [Montones de info aquí](https://forum.magicmirror.builders/topic/6291/howto-turn-on-off-your-monitor-time-based-pir-button-app).
# `pir.py`
Esto leerá el sensor y controlará la pantalla en consecuencia:
```python
#! /usr/bin/python
import os
import time
from gpiozero import MotionSensor
from datetime import datetime
pir = MotionSensor(14)
print('up!')
while True:
pir.wait_for_motion()
os.system('vcgencmd display_power 1')
pir.wait_for_no_motion()
os.system('vcgencmd display_power 0')
```
A parte, para que estoy quede fino, he configurado el sensor en modo H (re-trigger), que viene a ser que si el sensor está UP, y vuelve a haber movimiento, se resetea el tiempo de espera. [En la docu del sensor lo explican](/assets/magicmirror/Bewegungsmelder_Modul_Datenblatt.pdf) (o algo así).
Si en tu red local usas cosas como [Pi-hole](https://pi-hole.net/) para filtrar los DNS y bloquear publicidad/malware/etc, y por casualidad tienes algún dispositivo iOS (Apple), vas a tener una notificación permanente de que "La red no es segura". Algo tiene que ver el [DoH](https://en.wikipedia.org/wiki/DNS_over_HTTPS), que se ve que viene activado por defecto, y al "falsear los DNS" se entera.
Mi solución ha sido drástica: los iPhone no usan Pi-hole en mi red. Para ello hay que crear un _tag_ con las opciones pertinentes, y un Static Lease tageando ese dispositivo. Lo explican en la documentación de OpenWRT: [Client classifying and individual options](https://openwrt.org/docs/guide-user/base-system/dhcp_configuration#client_classifying_and_individual_options) (no se puede hacer via admin, no tienen implementados los _tags_):
```shell
uci set dhcp.nopi="tag"
uci set dhcp.nopi.dhcp_option="6,8.8.8.8,1.1.1.1"
uci add dhcp host
uci set dhcp.@host[-1].name="pepito-iphone"
uci set dhcp.@host[-1].mac="AA:BB:CC:DD:FF:11"
uci set dhcp.@host[-1].ip="192.168.1.20"
uci set dhcp.@host[-1].tag="nopi"
uci commit dhcp
/etc/init.d/dnsmasq restart
```
No he probado a no darle in IP concreta, seguramente no haga ni falta.
Se reconecta a la WiFi y pista, nuevas opciones DHCP para él solito, y aquí no ha pasado nada.

View File

@ -1,7 +1,7 @@
---
layout: post
title: "LVM"
tags: [lvm, disk, discos, partición, volumen, lógico, raspberry pi, create, crear]
tags: [lvm, disk, discos, partición, volumen, lógico, raspberry pi]
---
[LVM](https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)) es una de esas cosas que siempre he visto pero nunca me paré siquiera a ver para qué podía ser útil. Casualmente ahora le he encontrado utilidad de rebote.
@ -86,3 +86,6 @@ $ transmission-remote -c /mnt/lvm_ssd/torrents
```
La única pega que le estoy viendo, por ahora, es lo que una vez descargado algo tarda en pasar al HDD (obviamente), pero me gusta la flexibilidad que ofrece LVM.
*NOTA: Actualización 2024:* Dejé de usar esto hace 1 año, funcionó bien pero terminé dejando de usarlo en favor de [mergerfs](https://github.com/trapexit/mergerfs) + [SnapRAID](https://www.snapraid.it/), en un intento de emular lo que hace [unraid](https://unraid.net/) como tengo en el NAS y va PERFECTO.

View File

@ -0,0 +1,65 @@
---
layout: post
title: "Unraid: servidor NAS en casa"
tags: [unraid, nas, server, home, linux, raid]
---
[Unraid](https://unraid.net) es una distribución de Linux para montar una NAS. Además podrás poner en marcha VMs y contenedores de Docker, instalar apps, o usarlo como una distribución más (con sus matices).
La característica principal de este SO es la forma que tiene de gestionar los discos. Tiene algo muy similar a un [MergerFS](https://github.com/trapexit/mergerfs) + [SnapRAID](https://www.snapraid.it/), que no es más que la unión de varios discos con uno para [paridad](https://en.wikipedia.org/wiki/Parity_drive). Y no solo eso, sino que al NO SER UN RAID puedes ver el contenido de los discos desde cualquier otro equipo. Quiero decir, que quitas un disco del equipo, lo pinchas en otro, y ves el contenido qeu ha caido en ese disco concreto. Podrás si quieres copiarlo, o borrar lo que tiene, reemplazarlo por otro igual o mayor (sin superar el disco de paridad), etc. Casi casi es un [JBOD](https://en.wikipedia.org/wiki/Non-RAID_drive_architectures#JBOD) "seguro".
La diferencia con [SHR de Synology](https://kb.synology.com/en-eu/DSM/tutorial/What_is_Synology_Hybrid_RAID_SHR) es que en Unraid se usa [FUSE](https://github.com/libfuse/libfuse) por encima de los discos, y SHR usa [LVM](https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)). Eso da un poco más de performance, pero se pierde la "ventaja" de no usar RAID (si es que queremos verlo como ventaja).
Ok, basta de introducciones y a ver qué cacharro he montado. Este cacharro es la evolución durante años de tener discos por USB con Raspis, NUCs, y ahora ya un sistema hecho y derecho con los discos conectados por SATA. Más seguro, más versátil, y más rápido (y caro, si, pero lo compensa). Podría haber usado LSI/SAS pero para uso doméstico no me he atrevido.
# Hardware
Unraid lo tengo instalado en un *Kingston DataTraveler SE9* de 32GB. Es USB2, como recomiendan. Unraid se carga en memoria, no se instala en disco.
Para la caja uso una *Fractal Design Node 804*. Es cuadrada y con dos "cámaras", una para los componentes y otra para los discos. De lo mejorcito que he probado en mucho tiempo.
La placa base es una *MSI B560M PRO*. Si, una placa de escritorio, lo he preferido sobre la típica Supermicro por un tema de precio + disponibilidad + futura reutilización. Además tiene red de 2.5Gbit y buenas VRMs de alimentación. Chipset B560 para socket LGA1200.
Procesador *Intel Core i3-10105* de 10th generación. Buen precio, potente, "bajo" voltaje y soporte para Quick Sync, necesario para hacer Transcode con Plex, por ejemplo.
Memoria RAM *Kingston FURY Beast DDR4 2666MHz 8GB CL16*. Nada del otro mundo, no es ECC.
Fuente de alimentación *EVGA 500 GD v2 500W 80+ Gold*. Una 80+ Gold "barata", aquí seguramente haya mejores opciones.
Ventilación de CPU *NOX HUMMER H-212*. Silencioso y enfría muy muy bien, muchísimo mejor que el ventilador de stock. Y barato.
Tarjeta de expansión *PCIe SATA3 x1 6ports*. Puesto que tengo 10 discos SATA, necesito más tomas que las que trae la placa.
Tema discos, actualmente esta es la configuración de inicio para aprovechar los discos que ya tengo:
- Disco de paridad: Toshiba N300 4TB 7200RPM
- Discos de datos:
- 5x 4TB Seagate IronWolf 5900RPM
- 2x 3TB Seagate IronWolf 5200RPM
- 2x 1TB WD Red 5200RPM
- Discos de cache:
- appdata y system: Crucial MX500 250GB
- descargas: Crucial MX500 1TB
Por último, un *HDMI Dummy Plug* para que no se desactive la iGPU del procesador.
# Software
Como ya he dicho, he empezado con *Unraid*, versión 6.11.0.
Plugins esenciales:
- Auto Turbo Write Mode: permite duplicar la escritura de paridad cuando todos los discos están encendidos. Sobre todo apra mover los datos inicialmente, esto es esencial.
- Fix Common Problems: el nombre lo dice. Te avisa de cosas que no van bien.
- My Servers: Cloud de unraid, sincroniza la key.
- Unassigned Devices: aumenta las opciones de la pantalla _Main_.
- User Scripts: yo lo uso para crear crones.
Contenedores principales:
- nginx
- iperf3
- qBittorrent
- Plex
VM de momento no tengo ninguna, ni creo que vaya a usar.

View File

@ -0,0 +1,107 @@
---
layout: post
title: "Abrir la LAN con WireGuard"
tags: [unraid, nas, server, home, linux, lan, wireguard, vpn]
---
Hasta ahora lo típico para acceder a la LAN de casa era abrir el puerto 22 por ejemplo, y de ahí ya acceder a los equipos de la red. Pero he ido cambiando eso por WireGuard.
Dejando a un lado las ventajas de WireGuard frente a otras VPN, las dos mayores ventajas que me han hecho cambiar a este setup son:
- Velocidad de reconexión: cuando cambias de red (por ejemplo el móvil entre antenas), o el portátil entre trabajo/casa, el propio túnel se actualiza él solo al vuelo.
- Menos consumo de red: WireGuard usa menos red, lo que se traduce en menos ping y más tasa de red.
Mi configuración inicial consistía en todos los clientes/_peers_ conectados al servidor VPN que monté en el router. Funcionaba, pero eso me hacía depender de un router con kernel moderno. Por diversas razones ya no puedo tener esa dependencia, además no quiero depende tampoco de tener que abrir puertos. Y para finalizar, me he dado cuenta ahora que el router me limitaba levemente la conexión de la VPN por la velocidad del procesador.
Por eso he pasado a tener la VPN en un VPS externo, y para acceder a la LAN de casa (u otra) lo hago _colándome_ por el túnel, concretamente por el _peer_ del NAS.
Para este setup he recurrido a diferentes artículos de referencia sobre WireGuard. Lo que más me ha ayudado, de lejos, es la [página oficial](https://www.wireguard.com/) y este comentario:
> In other words, when sending packets, the list of allowed IPs behaves as a sort of routing table, and when receiving packets, the list of allowed IPs behaves as a sort of access control list.
Otra página que me ha servido de infinita ayuda es [pirate/wireguard-docs](https://github.com/pirate/wireguard-docs). No solo explica cada caso de uso y parámetro, sino que detalla las tripas de WireGuard.
Entre algunos de los problemas que me salieron fue que uno de los _peers_ tenía baja velocidad de transferencia. Resultó ser por el MTU cuando el _endpoint_ iba por IPv6, explicado [aquí](https://keremerkan.net/posts/wireguard-mtu-fixes/).
Y para acabar, los [tutoriales en el foro de Unraid sobre WireGuard](https://forums.unraid.net/topic/84226-wireguard-quickstart/), sobre todo el de [LAN-to-LAN](https://forums.unraid.net/topic/88906-lan-to-lan-wireguard/), donde vi la idea de crear una ruta estática en casa, algo que soportan todos los routers hoy en día.
El resto es cosa de los comandos `ip` e `iptables` de linux .
# Configuración modelo
Servidor:
```
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
MTU = 1412
PrivateKey = ...
PostUp = iptables -A FORWARD -i %i -j ACCEPT
PostUp = iptables -A FORWARD -o %i -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o %i -j MASQUERADE
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PreDown = iptables -D FORWARD -i %i -j ACCEPT
PreDown = iptables -D FORWARD -o %i -j ACCEPT
PreDown = iptables -t nat -D POSTROUTING -o %i -j MASQUERADE
PreDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
# Name = nas
PublicKey = ...
AllowedIPs = 10.0.0.2/32, 192.168.1.0/24
```
Con esto hacemos que cualquier conexión que nos venga para la LAN de casa (192.168.1.0/24) se mande por el _peer_ 10.0.0.2 (el nas).
Ahora la config del nas:
```
[Interface]
PrivateKey = ...
Address = 10.0.0.2/24
ListenPort = 51820
MTU = 1412
PostUp = iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o br0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o br0 -j MASQUERADE
PostUp = ip -4 route flush table 200
PostUp = ip -4 route add default via 10.0.0.2 table 200
PostUp = ip -4 route add 192.168.1.0/24 via 192.168.1.1 table 200
PostDown = ip -4 route flush table 200
PostDown = ip -4 route add unreachable default table 200
PostDown = ip -4 route add 192.168.1.0/24 via 192.168.1.1 table 200
[Peer]
# Name = vps
PublicKey = ...
Endpoint = 1.2.3.4:51820
AllowedIPs = 10.0.0.0/24, 172.20.0.0/24
PersistentKeepalive = 25
```
Con este `AllowedIPs` hacemos que se vaya por el túnel todo lo de la VPN y lo de la red de los Dockers que hay en el VPS. Para que cualquier equipo conectado al router de casa se le aplica la ruta estática configurada en el mismo, que precisamente manda estos dos rangos a la IP local del nas, dicho de otra forma, 172.20.0.0/24 redireccionado al "gateway" 192.168.1.2 . Y las rutas y reglas de `iptables` sirven precisamente para que cualquiera que venga por el túnel a otro equipo de la LAN, pueda acceder.
El resto de _peers_ de la VPN no necesitan una config especial, por ejemplo al móvil o al portátil les vale con algo así para acceder tanto a la LAN como a los Dockers:
```
[Interface]
PrivateKey = ...
Address = 10.0.0.x/24
ListenPort = 51820
[Peer]
# Name = movil
PublicKey = ...
Endpoint = 1.2.3.4:51820
AllowedIPs = 192.168.1.0/24, 172.20.0.0/24
```
Resumiendo:
- Todos los _peers_ de la VPN pueden hablar entre si, con los contenedores de Docker del VPS, y con los equipos de la LAN de casa (incluido el NAS y el router).
- El VPS y sus contenedores pueden acceder a la LAN y a los _peers_.
- Cualquier equipo de casa, NAS y router incluidos, pueden acceder a los contendores del VPS y al resto de _peers_.
Total, que todos pueden conectar a todos solo por estar a rango de la VPN.
Y lo mejor de este setup es que me puedo llevar el NAS a otra conexión/casa, o cambiar de proveedor/equipos/router, y con un mínimo ajuste (rutas estáticas) todo funcionaría igual.

View File

@ -0,0 +1,15 @@
---
title: "Simplificando el blog, aun más"
---
El otro día fui a escribir un post y resulta que [Jekyll](https://jekyllrb.com/) no montaba el sitio por no séquépaquete desactualizado por la versión de ruby nosequé. Excusa perfecta para deshacerme de ello y simplificar más aun esto.
Como prácticamente esto son 4 `.md` mal contados, por poco pensé "mira, los publico tal cual", pero con una búsqueda rápida descubrí [pandoc](https://pandoc.org/), un simple conversor, entre ellos de `.md` a `.html`. PERFECTO.
Así que he creado [un script básico](https://sergio.am/code/sergio.am/src/branch/main/build.sh) para pasar todos los Markdown a HTML, y he cambiado el [CI/CD](https://sergio.am/code/sergio.am/src/branch/main/.drone.yml).
Además, para no cambiar nada más, he seguido el formato de Jekyll en la medida de lo posible.
Igual a futuro añado más cosas, pero algo me dice que de hecho quitaré algo. Tags? _pa qué_, RSS? Tal vez... (alguien lo usa???), comentario? nah... que me manden [un mail](/about.html). Y ojo que igual hasta quito el CSS, es lo que más tiempo me ha llevado y casi casi me lo cepillo.
En fin, por eso, que más sencillo aun.

View File

@ -1,377 +0,0 @@
// Reset some basic elements
* {
-webkit-transition: background-color 75ms ease-in, border-color 75ms ease-in;
-moz-transition: background-color 75ms ease-in, border-color 75ms ease-in;
-ms-transition: background-color 75ms ease-in, border-color 75ms ease-in;
-o-transition: background-color 75ms ease-in, border-color 75ms ease-in;
transition: background-color 75ms ease-in, border-color 75ms ease-in;
}
.notransition {
-webkit-transition: none;
-moz-transition: none;
-ms-transition: none;
-o-transition: none;
transition: none;
}
html {
overflow-x: hidden;
width: 100%;
}
body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
hr,
dl,
dd,
ol,
ul,
figure {
margin: 0;
padding: 0;
}
// Basic styling
body {
min-height: 100vh;
overflow-x: hidden;
position: relative;
color: $text-base-color;
font: $normal-weight #{$base-font-size}/#{$base-line-height} $sans-family;
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
-webkit-font-feature-settings: "kern" 1;
-moz-font-feature-settings: "kern" 1;
-o-font-feature-settings: "kern" 1;
font-feature-settings: "kern" 1;
font-kerning: normal;
box-sizing: border-box;
background: url(/assets/img/simple_dashed_l.png);
background-color: $white;
background-repeat: repeat;
background-attachment: fixed;
}
// Set `margin-bottom` to maintain vertical rhythm
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
ul,
ol,
dl,
figure,
%vertical-rhythm {
margin-top: $spacing-full - 20;
margin-bottom: $spacing-full - 20;
}
// strong | bold
strong,
b {
font-weight: $bold-weight;
color: $black;
}
// horizontal rule
hr {
border-bottom: 0;
border-style: solid;
border-color: $light;
}
// kbd tag
kbd {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border: 1px solid $light;
border-radius: 2px;
color: $black;
display: inline-block;
font-size: $small-font-size;
line-height: 1.4;
font-family: $mono-family;
margin: 0 0.1em;
font-weight: $bold-weight;
padding: 0.01em 0.4em;
text-shadow: 0 1px 0 $white;
}
// Image
img {
max-width: 100%;
vertical-align: middle;
-webkit-user-drag: none;
margin: 0 auto;
text-align: center;
}
// Figure
figure {
position: relative;
}
// Image inside Figure tag
figure > img {
display: block;
position: relative;
}
// Image caption
figcaption {
font-size: 13px;
text-align: center;
}
// List
ul {
list-style: none;
li {
display: list-item;
text-align: -webkit-match-parent;
}
li::before {
content: "\FE63";
display: inline-block;
top: -1px;
width: 1.2em;
position: relative;
margin-left: -1.3em;
font-weight: 700;
}
}
ol {
list-style: none;
counter-reset: li;
li {
position: relative;
counter-increment: li;
&::before {
content: counter(li);
display: inline-block;
width: 1em;
margin-right: 0.5em;
margin-left: -1.6em;
text-align: right;
direction: rtl;
font-weight: $bold-weight;
font-size: $small-font-size;
}
}
}
ul,
ol {
margin-top: 0;
margin-left: $spacing-full;
}
li {
padding-bottom: 1px;
padding-top: 1px;
&:before {
color: $black;
}
> ul,
> ol {
margin-bottom: 2px;
margin-top: 0;
}
}
// Headings
h1,
h2,
h3,
h4,
h5,
h6 {
color: $black;
font-weight: $bold-weight;
& + ul,
& + ol {
margin-top: 10px;
}
@include media-query($on-mobile) {
scroll-margin-top: 65px;
}
}
// Headings with link
h1 > a,
h2 > a,
h3 > a,
h4 > a,
h5 > a,
h6 > a {
text-decoration: none;
border: none;
&:hover {
text-decoration: none;
border: none;
}
}
// Link
a {
color: inherit;
text-decoration: none;
&:hover {
color: $text-link-blue;
}
&:focus {
outline: 3px solid rgba(0, 54, 199, 0.6);
outline-offset: 2px;
}
}
// Del
del {
color: inherit;
}
// Em
em {
color: inherit;
}
// Blockquotes
blockquote {
color: $gray;
font-style: italic;
text-align: center;
opacity: 0.9;
border-top: 1px solid $light;
border-bottom: 1px solid $light;
padding: 10px;
margin-left: 10px;
margin-right: 10px;
font-size: 1em;
> :last-child {
margin-bottom: 0;
margin-top: 0;
}
}
// Wrapper
.wrapper {
max-width: -webkit-calc(#{$narrow-size} - (#{$spacing-full} * 2));
max-width: calc(#{$narrow-size} - (#{$spacing-full} * 2));
position: relative;
margin-right: auto;
margin-left: auto;
padding-right: $spacing-full;
padding-left: $spacing-full;
padding-top: 1px;
background-color: #dddddd70;
@extend %clearfix;
@include media-query($on-mobile) {
max-width: -webkit-calc(#{$narrow-size} - (#{$spacing-full}));
max-width: calc(#{$narrow-size} - (#{$spacing-full}));
padding-right: $spacing-full - 10;
padding-left: $spacing-full - 10;
&.blurry {
animation: 0.2s ease-in forwards blur;
-webkit-animation: 0.2s ease-in forwards blur;
}
}
.header-title {
font-weight: 700;
}
}
// Underline
u {
text-decoration-color: #d2c7c7;
}
// Small
small {
font-size: $small-font-size;
}
// Superscript
sup {
border-radius: 10%;
top: -3px;
left: 2px;
font-size: small;
position: relative;
margin-right: 2px;
}
// Table
.overflow-table {
overflow-x: auto;
}
table {
width: 100%;
margin-top: $spacing-half;
border-collapse: collapse;
font-size: $small-font-size;
thead {
font-weight: $bold-weight;
color: $black;
border-bottom: 1px solid $light;
}
th,
td,
tr {
border: 1px solid $light;
padding: 2px 7px;
}
}
// Clearfix
%clearfix:after {
content: "";
display: table;
clear: both;
}
// When mouse block a text set this color
mark,
::selection {
background: #fffba0;
color: $black;
}
// Github Gist clear border
.gist {
table {
border: 0;
tr,
td {
border: 0;
}
}
}

View File

@ -1,254 +0,0 @@
body[data-theme="dark"] {
color: $dark-text-base-color;
background-color: $dark-black;
background-image: url(/assets/img/simple_dashed.png);
// Heading
h1,
h2,
h3,
h4,
h5,
h6 {
color: $dark-white;
}
// Table
table {
thead {
color: $dark-white;
border-color: $dark-light;
}
th,
td,
tr {
border-color: $dark-light;
}
}
.wrapper {
background-color: #1c1c1c70;
}
// Post
.page-content {
a {
color: $dark-text-link-blue;
&:hover,
&:active,
&:focus {
color: $dark-text-link-blue-active;
}
}
h3 {
border-color: $dark-light;
}
h1,
h2,
h3,
h4,
h5,
h6 {
.anchor-head {
color: $dark-text-link-blue;
}
}
}
// Syntax
code {
&.highlighter-rouge {
background-color: $dark-light;
}
}
// kbd tag
kbd {
border-color: $dark-light;
color: $dark-white;
text-shadow: 0 1px 0 $dark-black;
}
// horizontal rule
hr {
border-color: $dark-light;
}
// Post Meta
.post-meta {
color: $dark-gray;
time {
&::after {
background-color: $dark-light;
}
}
span[itemprop="author"] {
border-color: $dark-light;
}
}
// Link
a {
color: inherit;
text-decoration-color: $dark-smoke;
&:hover {
color: $dark-text-link-blue;
}
&:focus {
outline-color: rgba(255, 82, 119, 0.6);
}
}
// List
li {
&:before {
color: $dark-white;
}
}
// Blockquote
blockquote {
color: $dark-gray;
border-color: $dark-light;
}
// Strong, Bold
strong,
b {
color: $dark-white;
}
// Navbar
.navbar {
border-color: $dark-light;
.menu {
a#mode {
.mode-sunny {
display: block;
}
.mode-moon {
display: none;
}
}
.menu-link {
color: $dark-white;
}
@include media-query($on-mobile) {
background-color: $dark-black;
border-color: $dark-light;
.menu-icon {
> svg {
fill: $dark-white;
}
}
input[type="checkbox"]:checked ~ .trigger {
background: $dark-black;
}
}
}
}
// Post Item
.post-item {
&:not(:first-child) {
border-color: $dark-light;
}
.post-item-date {
color: $dark-white;
}
.post-item-title {
a {
color: $dark-text-link-blue;
&:hover,
&focus {
color: $dark-white;
}
}
}
}
// Post Navigation
.post-nav {
border-color: $dark-light;
background: $dark-light;
background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(27,29,37,1) 50%, rgba(0,0,0,0) 100%);
.post-nav-item {
font-weight: $bold-weight;
.post-title {
color: $dark-white;
opacity: 0.9;
}
&:hover,
&:focus {
.post-title {
color: $dark-text-link-blue-active;
}
}
.nav-arrow {
color: $dark-gray;
}
}
@include media-query($on-mobile) {
.post-nav-item:nth-child(even) {
border-color: $dark-light;
}
}
}
// Footer
.footer {
span.footer_item {
color: $dark-white;
}
a.footer_item:not(:last-child) {
color: $dark-white;
}
.footer_copyright {
color: $dark-gray;
opacity: 1;
}
}
// 404 Page
.not-found {
.title {
color: $dark-white;
text-shadow: 1px 0px 0px $dark-text-link-blue;
}
.phrase {
color: $dark-text-base-color;
}
.solution {
color: $dark-text-link-blue;
}
.solution:hover {
color: $dark-text-link-blue-active;
}
}
.search-article {
input[type="search"] {
color: $dark-text-base-color;
&::-webkit-input-placeholder {
color: rgba(128,128,128,0.8);
}
}
}
}

View File

@ -1,188 +0,0 @@
@charset "utf-8";
/*
* https://fonts.googleapis.com/css2?family=JetBrains+Mono&family=Roboto:wght@400;700&display=swap
* https://fonts.google.com/specimen/Roboto
* https://fonts.google.com/specimen/jetBrains+Mono
*/
/* cyrillic-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTN1OVgaY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTPlOVgaY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTOVOVgaY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTNVOVgaY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTNFOVgaY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'JetBrains Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/jetbrainsmono/v12/tDbY2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKxTOlOV.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu72xKOzY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu5mxKOzY.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7mxKOzY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4WxKOzY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7WxKOzY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu7GxKOzY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOmCnqEu92Fr1Mu4mxK.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmWUlfBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -1,379 +0,0 @@
// Navbar
.navbar {
height: auto;
max-width: calc(#{$wide-size} - (#{$spacing-full} * 2));
max-width: -webkit-calc(#{$wide-size} - (#{$spacing-full} * 2));
position: relative;
margin-right: auto;
margin-left: auto;
border-bottom: 1px solid $light;
padding: $spacing-full - 15px $spacing-full;
@extend %clearfix;
}
// Navigation
.menu {
user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
a#mode {
float: right;
right: 8px;
top: 6px;
position: relative;
-webkit-transform: scale(1, 1);
transform: scale(1, 1);
opacity: 0.7;
z-index: 1;
&:hover {
cursor: pointer;
opacity: 1;
}
&:active {
-webkit-transform: scale(0.9, 0.9);
transform: scale(0.9, 0.9);
}
.mode-moon {
display: block;
line {
stroke: $black;
fill: none;
}
circle {
fill: $black;
stroke: $black;
}
}
.mode-sunny {
display: none;
line {
stroke: $dark-white;
fill: none;
}
circle {
fill: none;
stroke: $dark-white;
}
}
}
.trigger {
float: left;
}
.menu-trigger {
display: none;
}
.menu-icon {
display: none;
}
.menu-link {
color: $black;
line-height: $base-line-height + 0.4;
text-decoration: none;
padding: 5px 8px;
opacity: 0.7;
letter-spacing: 0.3px;
&:hover {
opacity: 1;
}
&:not(:last-child) {
margin-right: 5px;
}
&.rss {
position: relative;
bottom: -3px;
outline: none;
}
@include media-query($on-mobile) {
opacity: 0.8;
}
}
.menu-link.active {
opacity: 1;
font-weight: 600;
}
@include media-query($on-mobile) {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 2;
text-align: center;
height: 50px;
background-color: $white;
border-bottom: 1px solid $light;
a#mode {
right: 20px;
top: 12px;
}
.menu-icon {
display: block;
position: absolute;
left: 10px;
width: 50px;
height: 23px;
line-height: 0;
padding-top: 13px;
padding-bottom: 15px;
cursor: pointer;
text-align: center;
z-index: 1;
> svg {
fill: $black;
opacity: 0.7;
}
&:hover {
> svg {
opacity: 1;
}
}
&:active {
-webkit-transform: scale(0.9, 0.9);
transform: scale(0.9, 0.9);
}
}
input[type="checkbox"]:not(:checked) ~ .trigger {
clear: both;
visibility: hidden;
}
input[type="checkbox"]:checked ~ .trigger {
position: fixed;
animation: 0.2s ease-in forwards fadein;
-webkit-animation: 0.2s ease-in forwards fadein;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: $white;
height: 100vh;
width: 100%;
top: 0;
}
.menu-link {
display: block;
box-sizing: border-box;
font-size: 1.1em;
&:not(:last-child) {
margin: 0;
padding: 2px 0;
}
}
}
}
// Author
.author {
margin-top: 4rem;
margin-bottom: 4rem;
text-align: center;
@include media-query($on-mobile) {
margin-bottom: 3em;
}
.author-avatar {
width: 70px;
height: 70px;
border-radius: 100%;
user-select: none;
background-color: $black;
-ms-user-select: none;
-webkit-user-select: none;
-webkit-animation: 0.5s ease-in forwards fadein;
animation: 0.5s ease-in forwards fadein;
opacity: 1;
}
.author-name {
font-size: 1.7em;
margin-bottom: 2px;
}
.author-bio {
margin: 0 auto;
opacity: 0.9;
max-width: 393px;
line-height: 1.688;
}
}
// Content
.posts-item-note {
font-size: $base-font-size;
font-weight: 700;
margin-bottom: 5px;
color: $black;
}
// List of posts
.post-item {
display: flex;
padding-top: 5px;
padding-bottom: 6px;
@extend %clearfix;
&:not(:first-child) {
border-top: 1px solid $light;
}
.post-item-date {
min-width: 96px;
color: $black;
font-weight: 700;
padding-right: 10px;
@include media-query($on-mobile) {
font-size: 16px;
}
}
.post-item-title {
margin: 0;
border: 0;
padding: 0;
font-size: $base-font-size;
font-weight: normal;
letter-spacing: 0.1px;
a {
color: $text-link-blue;
&:hover,
&focus {
color: $black;
}
}
}
}
// Footer
.footer {
margin-top: 2em;
margin-bottom: 2em;
text-align: center;
@include media-query($on-mobile) {
margin-top: 3em;
}
span.footer_item {
color: $black;
opacity: 0.8;
font-weight: $bold-weight;
font-size: $small-font-size;
}
a.footer_item {
color: $black;
opacity: 0.8;
text-decoration: none;
&:not(:last-child) {
margin-right: 10px;
&:hover {
opacity: 1;
}
}
}
.footer_copyright {
font-size: $small-font-size - 1;
margin-top: 3px;
display: block;
color: $gray;
opacity: 0.8;
}
}
.not-found {
text-align: center;
display: flex;
justify-content: center;
flex-direction: column;
height: 75vh;
.title {
font-size: 5em;
font-weight: $bold-weight;
line-height: 1.1;
color: $black;
text-shadow: 1px 0px 0px $text-link-blue;
}
.phrase {
color: $text-base-color;
}
.solution {
color: $text-link-blue;
letter-spacing: 0.5px;
}
.solution:hover {
color: $text-link-blue-active;
}
}
.search-article {
position: relative;
margin-bottom: 50px;
label[for="search-input"] {
position: relative;
top: 10px;
left: 11px;
}
input[type="search"] {
top: 0;
left: 0;
border: 0;
width: 100%;
height: 40px;
outline: none;
position: absolute;
border-radius: 5px;
padding: 10px 10px 10px 35px;
color: $text-base-color;
-webkit-appearance: none;
font-size: $base-font-size;
background-color: rgba(128, 128, 128, 0.1);
border: 1px solid rgba(128, 128, 128, 0.1);
&::-webkit-input-placeholder {
color: #808080;
}
&::-webkit-search-decoration,
&::-webkit-search-results-decoration {
display: none;
}
}
}
#search-results {
text-align: center;
li {
text-align: left;
}
}
.archive-tags {
height: auto;
.tag-item {
padding: 1px 3px;
border-radius: 2px;
border: 1px solid rgba(128, 128, 128, 0.1);
background-color: rgba(128, 128, 128, 0.1);
}
}

View File

@ -1,41 +0,0 @@
// Animation fade-in
@keyframes fadein {
0% {
opacity: 0.2;
}
100% {
opacity: 0.8;
}
}
// Animation blur
@keyframes blur {
0% {
filter: blur(0px);
}
100% {
filter: blur(4px);
}
}
// Responsive embed video
.embed-responsive {
height: 0;
max-width: 100%;
overflow: hidden;
position: relative;
padding-bottom: 56.25%;
margin-top: 20px;
iframe,
object,
embed {
top: 0;
left: 0;
width: 100%;
height: 100%;
position: absolute;
}
}

View File

@ -1,262 +0,0 @@
// Post wrapper
.wrapper.post {
@include media-query($on-mobile) {
padding-left: $spacing-half;
padding-right: $spacing-half;
}
}
// Post title
.header {
margin-top: 3em;
margin-bottom: 3em;
.tags {
margin-left: 3px;
letter-spacing: 0.5px;
.tag {
font-weight: $bold-weight;
font-size: $small-font-size - 2;
&:hover {
text-decoration: none;
}
}
}
.header-title {
font-size: 2em;
line-height: 1.2;
margin-top: 10px;
margin-bottom: 20px;
&.center {
text-align: center;
}
@include media-query($on-mobile) {
font-size: 1.9em;
}
}
}
// Post meta
.post-meta {
padding-top: 3px;
line-height: 1.3;
color: $gray;
time {
position: relative;
margin-right: 1.5em;
&::after {
background: $light;
bottom: 1px;
content: " ";
height: 2px;
position: absolute;
right: -20px;
width: 12px;
}
}
span[itemprop="author"] {
border-bottom: 1px dotted $light;
}
}
// Post content
.page-content {
iframe {
text-align: center;
}
figure {
img {
border-radius: 2px;
}
figcaption {
margin-top: 5px;
font-style: italic;
font-size: $small-font-size;
}
}
a {
color: $text-link-blue;
text-decoration: none;
&[target="_blank"]::after {
content: " \2197";
font-size: $small-font-size;
line-height: 0;
position: relative;
bottom: 5px;
vertical-align: baseline;
}
&:hover {
color: $text-link-blue-active;
}
&:focus {
color: $text-link-blue;
}
}
> p {
margin: 0;
padding-top: $spacing-full - 15;
padding-bottom: $spacing-full - 15;
}
ul.task-list {
list-style: none;
margin: 0;
li::before {
content: "";
}
li input[type="checkbox"] {
margin-right: 10px;
}
}
dl dt {
font-weight: $bold-weight;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: $black;
font-weight: $bold-weight;
margin-top: $spacing-full;
margin-bottom: 0;
&:hover {
.anchor-head {
color: $text-link-blue;
opacity: 1;
}
}
.anchor-head {
position: relative;
opacity: 0;
outline: none;
&::before {
content: "#";
position: absolute;
right: -3px;
width: 1em;
font-weight: $bold-weight;
}
}
}
h1 {
@include relative-font-size(1.5);
}
h2 {
@include relative-font-size(1.375);
}
h3 {
@include relative-font-size(1.25);
border-bottom: 1px solid $light;
padding-bottom: 4px;
}
h4 {
@include relative-font-size(1.25);
}
h5 {
@include relative-font-size(1);
}
h6 {
@include relative-font-size(0.875);
}
}
.post-nav {
display: flex;
position: relative;
margin-top: 3em;
border-top: 1px solid $light;
background: $light;
background: linear-gradient(90deg, rgba(0,0,0,0) 0%, rgba(236,236,236,1) 50%, rgba(0,0,0,0) 100%);
line-height: 1.4;
.post-nav-item {
border-bottom: 0;
font-weight: $bold-weight;
padding-bottom: 10px;
.post-title {
color: $black;
}
&:hover,
&:focus {
.post-title {
color: $text-link-blue-active;
opacity: 0.9;
}
}
.nav-arrow {
font-weight: $normal-weight;
font-size: $small-font-size;
color: $gray;
margin-bottom: 3px;
}
width: 50%;
padding-top: 10px;
text-decoration: none;
box-sizing: border-box;
&:nth-child(odd) {
padding-left: 0;
padding-right: 20px;
}
&:nth-child(even) {
text-align: right;
padding-right: 0;
padding-left: 20px;
}
}
@include media-query($on-mobile) {
display: block;
font-size: $small-font-size;
.post-nav-item {
display: block;
width: 100%;
}
.post-nav-item:nth-child(even) {
border-left: 0;
padding-left: 0;
border-top: 1px solid $light;
}
}
}
.post-updated-at {
font-family: "JetBrains Mono", "monospace";
}

View File

@ -1,182 +0,0 @@
// Code
code {
font-family: $mono-family;
text-rendering: optimizeLegibility;
font-feature-settings: "calt" 1;
font-variant-ligatures: normal;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
font-size: inherit;
&.highlighter-rouge {
padding: 1px 3px;
position: relative;
top: -1px;
background-color: #f6f6f6;
border-radius: 2px;
border: 1px solid rgba(128,128,128,0.1);
}
}
// Codeblock Theme
pre.highlight, pre {
margin: 30px -30px;
@include media-query($on-mobile) {
margin: 0 calc(51% - 51vw);
padding-left: 20px;
}
background-color: #1a1b21;
padding: 10px;
display: block;
overflow-x: auto;
> code {
width: 100%;
margin-left: auto;
margin-right: auto;
line-height: 1.5;
display: block;
border: 0;
}
}
.highlight table td {
padding: 5px;
}
.highlight table pre {
margin: 0;
}
.highlight,
.highlight .w {
color: #fbf1c7;
// background-color: #1a1b21;
}
.highlight .err {
color: #fb4934;
// background-color: #1a1b21;
font-weight: bold;
}
.highlight .c,
.highlight .cd,
.highlight .cm,
.highlight .c1,
.highlight .cs {
color: #928374;
font-style: italic;
}
.highlight .cp {
color: #8ec07c;
}
.highlight .nt {
color: #fb4934;
}
.highlight .o,
.highlight .ow {
color: #fbf1c7;
}
.highlight .p,
.highlight .pi {
color: #fbf1c7;
}
.highlight .gi {
color: #b8bb26;
background-color: #282828;
}
.highlight .gd {
color: #fb4934;
background-color: #282828;
}
.highlight .gh {
color: #b8bb26;
font-weight: bold;
}
.highlight .k,
.highlight .kn,
.highlight .kp,
.highlight .kr,
.highlight .kv {
color: #fb4934;
}
.highlight .kc {
color: #d3869b;
}
.highlight .kt {
color: #fabd2f;
}
.highlight .kd {
color: #fe8019;
}
.highlight .s,
.highlight .sb,
.highlight .sc,
.highlight .sd,
.highlight .s2,
.highlight .sh,
.highlight .sx,
.highlight .s1 {
color: #b8bb26;
font-style: italic;
}
.highlight .si {
color: #b8bb26;
font-style: italic;
}
.highlight .sr {
color: #b8bb26;
font-style: italic;
}
.highlight .se {
color: #fe8019;
}
.highlight .nn {
color: #8ec07c;
}
.highlight .nc {
color: #8ec07c;
}
.highlight .no {
color: #d3869b;
}
.highlight .na {
color: #b8bb26;
}
.highlight .m,
.highlight .mf,
.highlight .mh,
.highlight .mi,
.highlight .il,
.highlight .mo,
.highlight .mb,
.highlight .mx {
color: #d3869b;
}
.highlight .ss {
color: #83a598;
}

View File

@ -1,63 +0,0 @@
// Fonts preferences
$sans-family: Roboto, sans-serif;
$mono-family: JetBrains Mono, Consolas, monospace;
$base-font-size: 16px;
$medium-font-size: $base-font-size * 0.938;
$small-font-size: $base-font-size * 0.875;
$base-line-height: 1.85;
// Font weight
// $light-weight: 300; // uncomment if necessary
$normal-weight: 400;
$bold-weight: 700;
// $black-weight: 900; // uncomment if necessary
//Light Colors
$text-base-color: #434648;
$text-link-blue: #003fff;
$text-link-blue-active: #0036c7;
$black: #0d122b;
$light: #ececec;
$smoke: #d2c7c7;
$gray: #6b7886;
$white: #fff;
// Dark Colors
$dark-text-base-color: #d0d0d0;
$dark-text-link-blue: #ff5277;
$dark-text-link-blue-active: #ff2957;
$dark-black: #131418;
$dark-white: #eaeaea;
$dark-light: #1b1d25;
$dark-smoke: #4a4d56;
$dark-gray: #767f87;
// Width of the content area
$wide-size: 890px;
$narrow-size: 890px;
// Padding unit
$spacing-full: 30px;
$spacing-half: $spacing-full / 2;
// State of devices
$on-mobile: 768px;
$on-tablet: 769px;
$on-desktop: 1024px;
$on-widescreen: 1152px;
@mixin media-query($device) {
@media screen and (max-width: $device) {
@content;
}
}
@mixin relative-font-size($ratio) {
font-size: $base-font-size * $ratio;
}
// Import sass files
@import "klise/fonts", "klise/base", "klise/layout", "klise/post",
"klise/miscellaneous", "klise/syntax", "klise/dark";

View File

@ -1,19 +1,24 @@
---
title: Qué es esto
title: Qué es esto?
permalink: /about/
layout: page
comments: false
---
## Yo
Esto podría resumirse en un cementerio de textos que de vez en cuando (de año en año) actualizo, abandono, actualizo, abandono, etc.
Técnicamente soy un simple programador, desde los 16 años que me compraron mi primer ordenador y empecé a aprender todo por mi cuenta. Tengo la mente demasiado dispersa y lo que aquí se publica es un ejemplo de ello.
No es la primera vez que monto algo así, ni será la última. Por eso, para mi yo del futuro, voy a dejar unas premisas, unos _por qués_, y unos _cómos_ para no reinventar la rueda ni recorrer caminos ya andados (y fallidos).
## Este sitio
## Contacto
No es la primera vez que monto algo así, ni será la última. Por eso, para mi yo del futuro, voy a dejar unas premisas, unos por qués, y unos cómos para no reinventar la rueda ni recorrer caminos ya andados.
Lo primero, cómo puedes encontrarme:
### Premisas
- [correo@sergio.am](mailto:correo@sergio.am?subject=sergio.am), es lo más cómodo, el tradicional email.
- [Telegram](https://t.me/sxergio), ahí seguro que también lo veo.
Así de simple, cualquier otro método seguramente pierda el mensaje.
## Premisas
Este sitio tiene como objetivo:
@ -25,25 +30,23 @@ Este sitio tiene como objetivo:
Y todo ello tiene que ser:
- sencillo. [KISS](https://en.wikipedia.org/wiki/KISS_principle)
- mantenible. Obvio...
- portable. Alguna vez se os ha petado un disco/servidor? Pues eso.
- autosuficiente. Mi sueño es que, si me muero, esto quede para siempre disponible aunque no haya nadie al mando.
- sencillo
- mantenible
- portable
- autosuficiente
### Por qué
## Por qué
Eso, por qué otra vez esto, o por qué otro sitio como los miles que ya habrá por internet. Ok, sencillo... porque me da pereza tener que buscar en google una y otra vez lo mismo pasado X tiempo. Porque a veces me baso en otras ideas, tutoriales, documentos, etc. y lo que termino haciendo yo no tiene una explicación exacta, o una línea recta que seguir, y necesito apuntarme mis cambios o cómo lo he hecho.
He tenido muchos por qué, pero a día de hoy es simplemente por recordar a futuro cómo he hecho alguna cosa. Todo lo que hago suele ser un mix de cosas que busco, aprendo y experimento, y cuando pasa el tiempo se me olvida el camino recorrido.
Y porque mi memoria es muy corta y limitada, me quedo con chorradas pero no con lo importante. Y esto, para mi, es importante.
Así que a veces necesito un rinconcito donde anotarme cosas, y si encima sirven para que otra persona, mejor. Al igual que me han servidor a mi los textos de otros, es una pqueña forma de devolver el favor.
### Cómo
## Cómo
Habrá otros documentos para explicar toda la plataforma que tengo montada. Pero este sitio en concreto no.
Ya tengo una edad donde no me apetece recordar cómo he montado las cosas básicas, por lo cada vez lo simplifico y recorto más.
Genero el sitio de forma estática con [Jekyll](https://jekyllrb.com/) por conveniencia y lo extendido que está. Además no es la primera vez que lo uso y minimizaba mi apredizaje. Uso el theme [Klisé](http://github.com/piharpi/jekyll-klise) modificado.
Actualmente es tan sencillo como escribir unos `.md` y con un script muy sencillo los convierto a `.html` con [pandoc](https://pandoc.org/). YA ESTÁ.
Edito los `.md` via terminal, [Sublime](https://www.sublimetext.com/) o el editor de [Gitea](https://gitea.io/). Según me de.
Lo textos los edito via terminal, o con el editor de turno, o directamente desde [Gitea](https://github.com/go-gitea/gitea). Según me de o dónde me pille. En el fondo es un repo de Git con un puñado de archivos. Con un simple `post-hook` reconstruyo el sitio y ya.
Actualmente uso la conexión de casa para servir el sitio pero la idea es que no haga falta, por ello estoy pensando entre usar el [Free Tier de AWS](https://aws.amazon.com/free/) o sitios gratuitos como [Netlify](https://netlify.com)+[Cloudflare](https://cloudflare.com), [Github Pages](https://pages.github.com/), o similares.
Para los DNS y dominios uso [OVH](https://ovh.com). No todos tienen `.io` y `.am`...
Y poco más, todo esto puedo luego publicarlo desde un simple nginx, sitios como GitHub Pages o Cloudflare, una RasPi, da igual. Son archivos estáticos que se sirven hasta por señales de humo :)

View File

@ -1,29 +0,0 @@
---
title: Archive
permalink: /archive/
layout: page
excerpt: All post.
comments: false
---
<div class="search-article">
<label for="search-input" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="rgba(128,128,128,0.8)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
</label>
<input type="search" id="search-input" placeholder="Find some articles here" aria-label="Search">
</div>
<ul id="search-results"></ul>
{%- for post in site.posts -%}
{%- capture current_year -%}{{ post.date | date: "%Y" }}{%- endcapture -%}
{%- unless current_year == previous_year -%}
<h2>{{ current_year }}</h2>
{%- assign previous_year = current_year -%}
{%- endunless -%}
<article class="post-item">
<h3 class="post-item-title">
<a href="{{ post.url }}">{{ post.title | escape }}</a>
</h3>
</article>
{%- endfor -%}

View File

@ -1,4 +0,0 @@
---
---
@import "main";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1 +0,0 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

View File

@ -1 +0,0 @@
!function(t,e,n){"use strict";var o=function(t,e){var n,o;return function(){var i=this,r=arguments,d=+new Date;n&&d<n+t?(clearTimeout(o),o=setTimeout(function(){n=d,e.apply(i,r)},t)):(n=d,e.apply(i,r))}},i=!1,r=!1,d=!1,s=!1,a="unloaded",u=!1,l=function(){if(!u||!e.body.contains(u)||"loaded"==u.disqusLoaderStatus)return!0;var n,o,i=t.pageYOffset,l=(n=u,o=n.getBoundingClientRect(),{top:o.top+e.body.scrollTop,left:o.left+e.body.scrollLeft}).top;if(l-i>t.innerHeight*r||i-l-u.offsetHeight-t.innerHeight*r>0)return!0;var c,f,p,y=e.getElementById("disqus_thread");y&&y.removeAttribute("id"),u.setAttribute("id","disqus_thread"),u.disqusLoaderStatus="loaded","loaded"==a?DISQUS.reset({reload:!0,config:d}):(t.disqus_config=d,"unloaded"==a&&(a="loading",c=s,f=function(){a="loaded"},(p=e.createElement("script")).src=c,p.async=!0,p.setAttribute("data-timestamp",+new Date),p.addEventListener("load",function(){"function"==typeof f&&f()}),(e.head||e.body).appendChild(p)))};t.addEventListener("scroll",o(i,l)),t.addEventListener("resize",o(i,l)),t.disqusLoader=function(t,n){n=function(t,e){var n,o={};for(n in t)Object.prototype.hasOwnProperty.call(t,n)&&(o[n]=t[n]);for(n in e)Object.prototype.hasOwnProperty.call(e,n)&&(o[n]=e[n]);return o}({laziness:1,throttle:250,scriptUrl:!1,disqusConfig:!1},n),r=n.laziness+1,i=n.throttle,d=n.disqusConfig,s=!1===s?n.scriptUrl:s,(u="string"==typeof t?e.querySelector(t):"number"==typeof t.length?t[0]:t)&&(u.disqusLoaderStatus="unloaded"),l()}}(window,document);

View File

@ -1 +0,0 @@
(function(b,l,e,g,h,f){1!==parseInt(e.msDoNotTrack||b.doNotTrack||e.doNotTrack,10)&&b.addEventListener("load",function(){var r=(new Date).getTime();b.galite=b.galite||{};var m=new XMLHttpRequest,n="https://www.google-analytics.com/collect?cid="+(l.uid=l.uid||Math.random()+"."+Math.random())+"&v=1&tid="+galite.UA+"&dl="+f(h.location.href)+"&ul=en-us&de=UTF-8",a=function(b){var d="",c;for(c in b){if(void 0===b[c])return!1;d+=f(b[c])}return d},p={dt:[h.title],sd:[g.colorDepth,"-bit"],sr:[g.availHeight,"x",g.availWidth],vp:[innerWidth,"x",innerHeight],dr:[h.referrer]},k;for(k in p){var q=k+"="+a(p[k]);q&&(n+="&"+q)}a=function(b,d){var c="",a;for(a in d)c+="&"+a+"="+f(d[a]);return function(){var a=n+c+(galite.anonymizeIp?"&aip=1":"")+"&t="+f(b)+"&z="+(new Date).getTime();if(e.sendBeacon)e.sendBeacon(a);else try{m.open("GET",a,!1),m.send()}catch(t){(new Image).src=a}}};setTimeout(a("pageview",null),100);b.addEventListener("unload",a("timing",{utc:"JS Dependencies",utv:"unload",utt:(new Date).getTime()-r}))})})(window,localStorage,navigator,screen,document,encodeURIComponent)

View File

@ -1,31 +0,0 @@
(() => {
// Theme switch
const body = document.body;
const lamp = document.getElementById("mode");
const toggleTheme = (state) => {
if (state === "dark") {
localStorage.setItem("theme", "light");
body.removeAttribute("data-theme");
} else if (state === "light") {
localStorage.setItem("theme", "dark");
body.setAttribute("data-theme", "dark");
} else {
initTheme(state);
}
};
lamp.addEventListener("click", () =>
toggleTheme(localStorage.getItem("theme"))
);
// Blur the content when the menu is open
const cbox = document.getElementById("menu-trigger");
cbox.addEventListener("change", function () {
const area = document.querySelector(".wrapper");
this.checked
? area.classList.add("blurry")
: area.classList.remove("blurry");
});
})();

View File

@ -1,6 +0,0 @@
/*!
* Simple-Jekyll-Search
* Copyright 2015-2020, Christian Fei
* Licensed under the MIT License.
*/
!function(){"use strict";var i={compile:function(r){return o.template.replace(o.pattern,function(t,e){var n=o.middleware(e,r[e],o.template);return void 0!==n?n:r[e]||t})},setOptions:function(t){o.pattern=t.pattern||o.pattern,o.template=t.template||o.template,"function"==typeof t.middleware&&(o.middleware=t.middleware)}},o={};o.pattern=/\{(.*?)\}/g,o.template="",o.middleware=function(){};var n=function(t,e){var n=e.length,r=t.length;if(n<r)return!1;if(r===n)return t===e;t:for(var i=0,o=0;i<r;i++){for(var u=t.charCodeAt(i);o<n;)if(e.charCodeAt(o++)===u)continue t;return!1}return!0},e=new function(){this.matches=function(t,e){return n(e.toLowerCase(),t.toLowerCase())}};var r=new function(){this.matches=function(e,t){return!!e&&(e=e.trim().toLowerCase(),(t=t.trim().toLowerCase()).split(" ").filter(function(t){return 0<=e.indexOf(t)}).length===t.split(" ").length)}};var u={put:function(t){if(f(t))return p(t);if(function(t){return Boolean(t)&&"[object Array]"===Object.prototype.toString.call(t)}(t))return function(t){var e=[];l();for(var n=0,r=t.length;n<r;n++)f(t[n])&&e.push(p(t[n]));return e}(t);return undefined},clear:l,search:function(t){return t?function(t,e,n,r){for(var i=[],o=0;o<t.length&&i.length<r.limit;o++){var u=function(t,e,n,r){for(var i in t)if(!function(t,e){for(var n=!1,r=0,i=(e=e||[]).length;r<i;r++){var o=e[r];!n&&new RegExp(t).test(o)&&(n=!0)}return n}(t[i],r.exclude)&&n.matches(t[i],e))return t}(t[o],e,n,r);u&&i.push(u)}return i}(s,t,c.searchStrategy,c).sort(c.sort):[]},setOptions:function(t){(c=t||{}).fuzzy=t.fuzzy||!1,c.limit=t.limit||10,c.searchStrategy=t.fuzzy?e:r,c.sort=t.sort||a}};function a(){return 0}var s=[],c={};function l(){return s.length=0,s}function f(t){return Boolean(t)&&"[object Object]"===Object.prototype.toString.call(t)}function p(t){return s.push(t),s}c.fuzzy=!1,c.limit=10,c.searchStrategy=c.fuzzy?e:r,c.sort=a;var d={load:function(t,e){var n=window.XMLHttpRequest?new window.XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP");n.open("GET",t,!0),n.onreadystatechange=function(e,n){return function(){if(4===e.readyState&&200===e.status)try{n(null,JSON.parse(e.responseText))}catch(t){n(t,null)}}}(n,e),n.send()}};var h={merge:function(t,e){var n={};for(var r in t)n[r]=t[r],"undefined"!=typeof e[r]&&(n[r]=e[r]);return n},isJSON:function(t){try{return t instanceof Object&&JSON.parse(JSON.stringify(t))?!0:!1}catch(e){return!1}}};var t,m,v,w;function y(t){u.put(t),m.searchInput.addEventListener("input",function(t){-1===[13,16,20,37,38,39,40,91].indexOf(t.which)&&(g(),z(t.target.value))})}function g(){m.resultsContainer.innerHTML=""}function O(t){m.resultsContainer.innerHTML+=t}function z(t){var e;(e=t)&&0<e.length&&(g(),function(t,e){var n=t.length;if(0===n)return O(m.noResultsText);for(var r=0;r<n;r++)t[r].query=e,O(i.compile(t[r]))}(u.search(t),t))}function S(t){throw new Error("SimpleJekyllSearch --- "+t)}t=window,m={searchInput:null,resultsContainer:null,json:[],success:Function.prototype,searchResultTemplate:'<li><a href="{url}" title="{desc}">{title}</a></li>',templateMiddleware:Function.prototype,sortMiddleware:function(){return 0},noResultsText:"No results found",limit:10,fuzzy:!1,exclude:[]},w=function j(t){if(!((e=t)&&"undefined"!=typeof e.required&&e.required instanceof Array))throw new Error("-- OptionsValidator: required options missing");var e;if(!(this instanceof j))return new j(t);var r=t.required;this.getRequiredOptions=function(){return r},this.validate=function(e){var n=[];return r.forEach(function(t){"undefined"==typeof e[t]&&n.push(t)}),n}}({required:v=["searchInput","resultsContainer","json"]}),t.SimpleJekyllSearch=function(t){var n;0<w.validate(t).length&&S("You must specify the following required options: "+v),m=h.merge(m,t),i.setOptions({template:m.searchResultTemplate,middleware:m.templateMiddleware}),u.setOptions({fuzzy:m.fuzzy,limit:m.limit,sort:m.sortMiddleware}),h.isJSON(m.json)?y(m.json):(n=m.json,d.load(n,function(t,e){t&&S("failed to get JSON ("+n+")"),y(e)}));var e={search:z};return"function"==typeof m.success&&m.success.call(e),e}}();

View File

@ -0,0 +1,3 @@
[ZoneTransfer]
ZoneId=3
HostUrl=about:internet

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,4 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://projects.raspberrypi.org/
HostUrl=https://projects-static.raspberrypi.org/projects/physical-computing/248971027a596f3437da45bafd2bd8a8cc35cb95/en/images/pir_wiring.png

View File

@ -1,14 +0,0 @@
---
layout: none
---
[
{% for post in site.posts %}
{
"title" : "{{ post.title | escape }}",
"tags" : "{{ post.tags | join: ', ' }}",
"url" : "{{ site.baseurl }}{{ post.url }}",
"date" : "{{ post.date }}"
} {% unless forloop.last %},{% endunless %}
{% endfor %}
]

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/favicons/mstile-150x150.png"/>
<TileColor>#2c2c2c</TileColor>
</tile>
</msapplication>
</browserconfig>

55
build.sh Executable file
View File

@ -0,0 +1,55 @@
#! /bin/bash
set -x
rm -rf _site-tmp
mkdir -p _site-tmp
touch _site-tmp/index.md
buildDate="$(date '+%d %b %Y')"
# $1=file $2=add to index
convert_md_to_html() {
ls -la "$1"
fileName=$(basename "${1%.*}")
postDate=$(date '+%d %b %Y' -d "$(stat -c %y "$1" | awk '{print $1}')")
bodyClass="page"
if [ $2 -eq 1 ]; then
bodyClass="post"
echo "- [$(pandoc --template=pandoc-metadata.json "$1" | jq -r .title)](/$fileName.html) _${postDate}_" >> _site-tmp/index.md
fi
pandoc --template=tpl-layout.html --highlight-style=zenburn --metadata buildDate="$buildDate" --metadata postDate="$postDate" --metadata bodyClass="$bodyClass" -f markdown -t html5 "$1" > _site-tmp/"$fileName".html
}
# posts
for post in _posts/*.md; do
convert_md_to_html "$post" 1
done
# drafts
if [ $# -eq 1 ]; then
for post in _drafts/*.md; do
convert_md_to_html "$post" 1
done
fi
# pages
for post in ./*.md; do
convert_md_to_html "$post" 0
done
# index
# is there a better way to invert the file?
echo "$(tac _site-tmp/index.md)" > _site-tmp/index.md
pandoc --template=tpl-layout.html --metadata isIndex=1 --metadata buildDate="$buildDate" --metadata bodyClass="index" -f markdown -t html5 _site-tmp/index.md > _site-tmp/index.html
# static files
cp -r static _site-tmp/static
cp -r assets _site-tmp/assets
cp -r root/* _site-tmp/
# concat css
cat static/reset.css static/styles.css > _site-tmp/static/css.css
rm -rf _site
mv _site-tmp _site

View File

@ -1,12 +0,0 @@
---
title: Dónde encontrarme
permalink: /contact/
layout: page
comments: false
---
## Contacto / Contact
Puedes mandar mail a <correo@sergio.am>, o [@xergio](https://twitter.com/xergio) en twitter.
You can send an email to <correo@sergio.am>, or tweet me at [@xergio](https://twitter.com/xergio).

View File

@ -1,3 +1,4 @@
---
layout: home
---
title: Notas y apuntes para mi yo del futuro.
---
<ul><li><a href="2021-10-02-hi.html">2021-10-02-hi</a></li><li><a href="2022-05-08-drone-gitea-ci-cd.html">2022-05-08-drone-gitea-ci-cd</a></li><li><a href="2022-05-10-openwrt-ipv6-home-lan.html">2022-05-10-openwrt-ipv6-home-lan</a></li><li><a href="2022-05-18-digi-reemplazo-openwrt-ont.html">2022-05-18-digi-reemplazo-openwrt-ont</a></li><li><a href="2022-05-20-openwrt-exclude-clients-dhcp-options.html">2022-05-20-openwrt-exclude-clients-dhcp-options</a></li><li><a href="2022-06-23-backups.html">2022-06-23-backups</a></li><li><a href="2022-06-26-openwrt-ipv6-port-forwarding.html">2022-06-26-openwrt-ipv6-port-forwarding</a></li><li><a href="2022-07-29-lvm.html">2022-07-29-lvm</a></li><li><a href="2022-10-18-docker-alpine-intel-quicksync.html">2022-10-18-docker-alpine-intel-quicksync</a></li><li><a href="2022-10-21-unraid-nas-server-home.html">2022-10-21-unraid-nas-server-home</a></li><li><a href="2022-10-23-windows-wsl-migrate.html">2022-10-23-windows-wsl-migrate</a></li><li><a href="2023-01-23-wireguard-lan-hub.html">2023-01-23-wireguard-lan-hub</a></li><li><a href="2024-03-29-blog-simplification.html">2024-03-29-blog-simplification</a></li></ul>

11
lan.txt
View File

@ -1,11 +0,0 @@
Digi Fibra Smart 1Gbps (symetric)
Linksys WRT3600ACM
Linksys LGS116P-EU
Netgear WAX620
Raspberry Pi 3b+ (MagicMirror²)
Raspberry Pi 4b (PyKVM)
PC Ryzen 9 3900X (pc.txt)
Unraid NAS (nas.txt)
Synology DS118 (offsite backup)

1
pandoc-metadata.json Normal file
View File

@ -0,0 +1 @@
$meta-json$

12
root/alba.txt Normal file
View File

@ -0,0 +1,12 @@
junio 2023
Intel Core i5-13400 2.5 GHz/4.6 GHz
Gigabyte B760M Gaming X AX DDR4
Kingston FURY Beast DDR4 2666 MHz 8GB CL16
Kioxia Exceria G2 Unidad SSD 1TB NVMe M.2 2280
Mars Gaming MC300 FRGB USB 3.0 Rosa
Tempest PSU Fuente de Alimentación 750W
Tempest Cooler 4Pipes Black RGB
Logitech Brio 300

28
root/andrea.txt Normal file
View File

@ -0,0 +1,28 @@
Medion Akoya E16401 MD62264 Intel Core i5-1135G7/8GB/512GB SSD/16.1"
https://www.pccomponentes.com/medion-akoya-e16401-md62264-intel-core-i5-1135g7-8gb-512gb-ssd-161
Procesador Intel® Core™ i5-1135G7 (4 núcleos, hasta 4.2 GHz con tecnología Intel® Turbo Boost, 8 MB L3 caché)
Memoria RAM 8 GB DDR4
Almacenamiento 512 GB SSD
Unidad óptica No
Display 16.1" (40,7 cm) con tecnología IPS y resolución Full HD (1920 x 1080 píxeles)
Controlador gráfico Intel® Iris Xe Graphics
Conectividad Intel® Wi-Fi AX201 con función Bluetooth 5.1 integrada
Webcam Sí, HD
Micrófono Sí
Audio Sonido de alta resolución Dolby Audio™ con 2 altavoces
Teclado Retroiluminado
Batería 3 celdas, Polímero de litio, 45Wh
Conexiones
1 x USB 3.2 Gen 2 Tipo-C con función DisplayPort
1 x USB 2.0
1 x HDMI
1 x Lector tarjeta Micro SD
1 x Audio Combo
1 x Dc-in
Sistema operativo FreeDOS (SIN SISTEMA OPERATIVO)
Dimensiones (Ancho x Profundidad x Altura) 370 x 23 x 245 mm
Peso 1,95 kg
Color Gris

25
root/cande.txt Normal file
View File

@ -0,0 +1,25 @@
https://www.pccomponentes.com/hp-250-g9-intel-core-i5-1235u-16gb-512gbssd-156
HP 250 G9 Intel Core i5-1235U/16GB/512GBSSD/15.6"
Procesador Intel® Core™ i5-1235U (10 núcleos, frecuencia turbo máxima de 4.40GHz, 12 MB Intel® Smart Cache)
Memoria RAM 16GB DDR4-SDRAM 3200MHz (2x8GB)
Almacenamiento 512GB SSD
Unidad óptica No
Display 15.6" (39,6 cm) Full HD (1920 x 1080), Micro-Edge, IPS, Antirreflectante, 250 nits, 45% NTSC
Controlador gráfico Intel Iris Xe Graphics
Conectividad Wi-Fi 6 (802.11ax) Realtek RTL8852BE 2x2 + Bluetooth 5.2
Cámara de portátil HD 720p con micrófonos integrados (2)
Audio Altavoces dobles
Batería 3 celdas, Ion-Litio, 41 Wh
Conexiones
2 x USB 3.2 Gen 1 Tipo A
1 x USB 3.2 Gen 1 Tipo C
1 x Combo de auriculares/micrófono jack 3.5 mm
1 x HDMI 1.4b
1 x Ethernet LAN (RJ-45)
Sistema operativo
Sin Sistema Operativo
Dimensiones (Ancho x Profundidad x Altura) 358 x 242 x 19,9 mm
Peso 1,74 kg
Color Plata

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

12
root/lan.txt Normal file
View File

@ -0,0 +1,12 @@
Digi Fibra Smart PRO 10Gbps (symetric)
Router Zyxel AX7501-B0
Switch Mikrotik CSS610-8G-2S+IN
Transceptor 10Gtek® SFP+ RJ45 10GBASE-T
DAC 10Gtek® SFP+ 10GBASE-CU
Raspberry Pi 3b+ (MagicMirror²)
Raspberry Pi 4b (PyKVM)
PC Ryzen 9 3900X (pc.txt)
Unraid NAS (nas.txt)
Synology DS118 (offsite backup)

26
root/md.txt Normal file
View File

@ -0,0 +1,26 @@
Medion Akoya E15415 Intel Core i5-10210U/8GB/256GB SSD/15.6"
https://www.pccomponentes.com/medion-akoya-e15415-intel-core-i5-10210u-8gb-256gb-ssd-156
Procesador Intel® Core™ i5-10210U
Memoria RAM 8 GB DDR4
Almacenamiento 256 GB SSD
Unidad óptica No
Pantalla 15.6" (39.6 cm) Full HD (1920 x 1080 píxeles) con tecnología IPS
Controlador gráfico Intel UHD
Conectividad Intel® Wi-Fi AC-9462 con función Bluetooth® 5.1 integrada
Webcam Webcam de 1MP y micrófono dual - array integrados
Batería 3 celdas, polímeros de litio
Conexiones
1 x Lector tarjeta SD
1 x USB 3.2 Gen 1 Tipo C soporte salida DisplayPort™ y función de carga
2 x USB 3.2 Gen 1 Tipo A
1 x USB 2.0 Tipo A
1 x HDMI - Out
1 x Audio Combo
1 x DC-in
Sistema operativo SIN SISTEMA OPERATIVO
Dimensiones (Ancho x Profundidad x Altura) 35.9 x 2.26 x 24 cm
Peso 1,78 kg
Color Plata

View File

@ -1,3 +1,4 @@
Unraid OS Plus
Fractal Design Node 804
@ -7,12 +8,13 @@ Kingston FURY Beast DDR4 2666MHz 8GB CL16
EVGA 500 GD v2 500W 80+ Gold
NOX HUMMER H-212
PCIe SATA3 x1 6ports
PCIe SATA3 x1 4ports
Toshiba N300 4TB 7200RPM [Parity]
5x 4TB Seagate IronWolf 5900RPM
2x 3TB Seagate IronWolf 5200RPM
2x 1TB WD Red 5200RPM
3x 18TB Toshiba MG09 7200RPM
Crucial MX500 250GB [Cache]
HDMI Dummy Plug
Kingston DataTraveler SE9 32GB
PCIe 10Gtek® X520-DA2
Plex Pass Lifetime

View File

@ -5,7 +5,6 @@ Corsair Vengeance LPX CMK32GX4M2B3200C16 [3200MHz C16] (4x16GB)
Asus GeForce ROG Strix Gaming GTX 1080Ti [11GB GDDR5]
Corsair 5000D Airflow
Crucial MX500 [250GB]
Crucial MX500 [1TB M.2]
Samsung 970 EVO Plus [250GB M.2]
Samsung 860 EVO [2TB]
Seagate Barracuda 7200.14 [1TB]

BIN
root/sergio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

4
root/sum.txt Normal file
View File

@ -0,0 +1,4 @@
ASUS STRIX Z270H GAMING
Intel Core i5-7600K
NVIDIA GTX 1080

14
root/tara.txt Normal file
View File

@ -0,0 +1,14 @@
junio 2022
Intel Core i5-11400 2.6 GHz
MSI B560M PRO WIFI
Corsair Vengeance LPX DDR4 3200MHz PC4-25600 8GB CL16
Crucial P2 SSD M.2 2280 250GB PCIe Gen3 x4 NVMe
Tempest Start Torre ATX
Mars Gaming MPII650
EVGA GTX 1060 6GB
Logitech MK295 Combo
Creative Live Cam Sync 1080p V2
Logitech G335

Binary file not shown.

Binary file not shown.

74
static/reset.css Normal file
View File

@ -0,0 +1,74 @@
/* https://piccalil.li/blog/a-more-modern-css-reset/ */
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Prevent font size inflation */
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
/* Remove default margin in favour of better control in authored CSS */
body, h1, h2, h3, h4, p,
figure, blockquote, dl, dd {
margin-block-end: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
list-style: none;
}
/* Set core body defaults */
body {
min-height: 100vh;
line-height: 1.5;
}
/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4,
button, input, label {
line-height: 1.1;
}
/* Balance text wrapping on headings */
h1, h2,
h3, h4 {
text-wrap: balance;
}
/* A elements that don't have a class get default styles */
a:not([class]) {
text-decoration-skip-ink: auto;
/*color: currentColor;*/
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input, button,
textarea, select {
font: inherit;
}
/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
min-height: 10em;
}
/* Anything that has been anchored to should have extra scroll margin */
:target {
scroll-margin-block: 5ex;
}

BIN
static/sergio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/sergio100w.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

183
static/styles.css Normal file
View File

@ -0,0 +1,183 @@
/* https: //gist.github.com/Albert221/753d7f8955eeb6f5e50486fce048e39f */
@font-face {
font-family: 'JetBrains Mono';
src: url('/static/JetBrainsMono-Regular.woff2') format('woff2'),
url('/static/JetBrainsMono-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 1.2rem;
font-weight: 500;
line-height: 1.8;
max-width: 900px;
margin: 0 auto;
background-color: #1E1F22; /* Dark background */
color: #CED2D7; /* Main text color */
}
header, footer {
color: #fff;
padding: 10px;
font-size: .9em;
font-weight: bold;
}
header {
/* border-bottom: 3px solid #333; */
border-bottom: 3px solid transparent;
border-image: linear-gradient(0.25turn, #1E1F22, #333, #1E1F22);
border-image-slice: 1;
}
footer {
/* border-top: 3px solid #333; */
border-top: 3px solid transparent;
border-image: linear-gradient(0.25turn, #1E1F22, #333, #1E1F22);
border-image-slice: 1;
text-align: center;
padding-bottom: 20px;
}
nav ul {
list-style-type: none;
text-align: center;
}
nav ul li {
display: inline;
margin-right: 20px;
}
nav ul li a, footer a {
color: #fff;
text-decoration: none;
}
main {
padding: 20px;
}
body.index main {
padding-top: 0;
}
main p {
margin-left: 1rem;
}
main a {
color: #ff5277;
text-decoration: none;
position: relative;
}
/* https: //tobiasahlin.com/blog/css-trick-animating-link-underlines/ */
main a::before {
content: "";
position: absolute;
display: block;
width: 100%;
height: 1px;
bottom: 0;
left: 0;
background-color: #ff5277;
transform: scaleX(0);
transform-origin: top left;
transition: transform 0.2s ease;
}
main a:hover::before {
transform: scaleX(1);
}
main a:visited {
color: #BF6C6C;
}
body.index main ul {
list-style: none;
padding-left: 0;
}
body.index main ul li em {
font-style: normal;
font-size: 0.7rem;
color: #888;
background-color: #2d2d2d;
border-radius: 0.2rem;
padding: 2px 5px;
}
body.index .header {
background: rgb(30, 31, 34);
background: linear-gradient(0.25turn, rgba(30, 31, 34, 1) 0%, rgba(51, 51, 51, 1) 35%, rgba(30, 31, 34, 1) 100%);
text-align: center;
padding: 3rem;
}
body.index .header img {
margin: 0 auto;
border-radius: 100%;
}
a:hover {
color: #ff5277;
}
div.sourceCode, pre {
background-color: #333;
}
pre {
padding: 1rem;
}
pre, code, tt {
font-family: 'JetBrains Mono';
}
p code {
background-color: #2d2d2d;
color: #c4c399;
border-radius: 0.2rem;
padding-left: 5px;
padding-right: 5px;
}
h1, h2, h3, h4, h5, h6 {
background: #ffffff;
background: linear-gradient(to bottom, #ffffff 0%, #00dda6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0px 0px 2px rgba(0,0,0,0.2);
}
main div.subtitle {
margin-top: 0px;
color: #555;
font-size: .8em;
}
figure * {
margin: 0 auto;
font-size: 0.9rem;
text-align: center;
}
/* Responsive Styles */
@media only screen and (max-width: 900px) {
header, footer {
width: 100%; /* Full width on mobile */
}
main {
width: 100%; /* Full width on mobile */
max-width: none; /* Remove max-width on mobile */
}
}

View File

@ -1,27 +0,0 @@
---
title: Tags
permalink: /tags/
layout: page
excerpt: Sorted article by tags.
---
<div class="archive-tags">
<a class="tag-item" href="#">all</a>
{%- for tag in site.tags -%}
{% capture name %}{{ tag | first }}{% endcapture %}
<a class="tag-item" href="#{{name}}">{{ name }}</a>
{%- endfor -%}
</div>
{%- for tag in site.tags -%}
{%- capture name -%}{{ tag | first }}{%- endcapture -%}
<h2 id="{{ name }}">{{ name | upcase }}</h2>
{%- for post in site.tags[name] -%}
<article class="post-item" id="results-container">
<span class="post-item-date">{{ post.date | date: "%b %d, %Y" }}</span>
<h3 class="post-item-title">
<a href="{{ post.url }}">{{ post.title | escape }}</a>
</h3>
</article>
{%- endfor -%}
{%- endfor -%}

48
tpl-layout.html Normal file
View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>$if(title)$$title$$else$Sergio Álvarez$endif$ | sergio.am</title>
<style>
/*
$styles.html()$
*/
$highlighting-css$
</style>
<link rel="preload" as="font" href="/static/JetBrainsMono-Regular.woff2">
<link rel="preload" as="font" href="/static/JetBrainsMono-Regular.woff">
<link rel="stylesheet" href="/static/css.css">
</head>
<body class="$bodyClass$">
<header>
<nav>
<ul>
<li><a href="/">Índice</a></li>
<li><a href="https://sergio.am/explore/repos">Código fuente</a></li>
<li><a href="https://xrg.es/">RegExp</a></li>
<li><a href="https://dencode.xrg.es/">Dencode</a></li>
<li><a href="/about.html">Contacto</a></li>
<!--<li><a href="/rss.xml">RSS/Feed</a></li>-->
</ul>
</nav>
</header>
<main>
$if(isIndex)$<div class="header">
<img class="avatar" src="/static/sergio100w.jpg" alt="sergio.am">
<h2>Sergio Álvarez</h2>
<p>Notas y apuntes para mi yo del futuro.</p>
</div>$endif$
$if(title)$<h1>$title$</h1>$endif$
$if(postDate)$<div class="subtitle">~ $postDate$</div>$endif$
$body$
</main>
<footer>
<p><a href="/LICENSE.html">© Sergio Álvarez Muñoz</a> <span title="Site build date">🔨 $buildDate$</span></p>
</footer>
</body>
</html>