Compare commits
36 Commits
5f6a5c00a1
...
main
Author | SHA1 | Date | |
---|---|---|---|
3ebb70a524
|
|||
c4c5cd40af
|
|||
d0120c4144
|
|||
32a75322e5
|
|||
7eb0356860
|
|||
c50c3ca37a
|
|||
444a937d0b
|
|||
81b8deb4cf
|
|||
4d13fc9604
|
|||
000e49afd7
|
|||
3bec601f31
|
|||
9e0f049a52
|
|||
dbcdea640a
|
|||
015e7b6ed2
|
|||
c0debe8c47
|
|||
c902b1e87f
|
|||
dacdd27a73
|
|||
836e85c086
|
|||
d37c580263
|
|||
e15d9075e7
|
|||
9641c44657
|
|||
7ccd4a8dc6
|
|||
44c32bf138
|
|||
9d6ceb3121 | |||
cdfb6edc04 | |||
4eff6d90da | |||
e89718fc2a | |||
8b218d1497 | |||
105ac552b0 | |||
7318e2c550 | |||
2e3b4c02f7 | |||
980b2329ae | |||
d0633a734d | |||
5dc359995f | |||
4726f07ea7 | |||
660b758927 |
33
.drone.yml
@ -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
@ -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
@ -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?
|
||||
#
|
@ -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
|
||||
|
22
README.md
@ -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)
|
||||
|
84
_config.yml
@ -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
|
@ -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/
|
@ -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 }}
|
@ -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>
|
@ -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>
|
@ -1,22 +0,0 @@
|
||||
<footer class="footer">
|
||||
<span class="footer_item"><a href="/LICENSE">© 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 -%}
|
@ -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>
|
@ -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 %}
|
@ -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>
|
@ -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>
|
@ -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> -->
|
@ -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>
|
@ -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 %}
|
@ -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>
|
@ -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 -%}
|
@ -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>
|
@ -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">
|
||||
<
|
||||
{% for tag in tags %}
|
||||
<a class="tag"
|
||||
href="/tags/#{{tag | downcase | slugify}}">{{tag | upcase }}</a>{% unless forloop.last %},{% endunless %}
|
||||
{% endfor %}
|
||||
/>
|
||||
</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>
|
@ -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
|
||||
```
|
||||
|
97
_posts/2022-06-19-magicmirror-raspberry-pir-sensor.md
Normal 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:
|
||||
|
||||

|
||||
|
||||
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.
|
@ -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.
|
65
_posts/2022-10-21-unraid-nas-server-home.md
Normal 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.
|
107
_posts/2023-01-23-wireguard-lan-hub.md
Normal 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.
|
15
_posts/2024-03-29-blog-simplification.md
Normal 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.
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
43
about.md
@ -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 :)
|
||||
|
29
archive.html
@ -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 -%}
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
---
|
||||
|
||||
@import "main";
|
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 245 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 914 B |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -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"}
|
Before Width: | Height: | Size: 112 B |
Before Width: | Height: | Size: 537 B |
@ -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);
|
@ -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)
|
@ -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");
|
||||
});
|
||||
})();
|
6
assets/js/search.min.js
vendored
@ -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}}();
|
BIN
assets/magicmirror/Bewegungsmelder_Modul_Datenblatt.pdf
Normal file
@ -0,0 +1,3 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
HostUrl=about:internet
|
BIN
assets/magicmirror/pir_wiring.png
Normal file
After Width: | Height: | Size: 52 KiB |
4
assets/magicmirror/pir_wiring.png:Zone.Identifier
Normal 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
|
@ -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 %}
|
||||
]
|
@ -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
@ -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
|
12
contact.md
@ -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).
|
5
index.md
@ -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
@ -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
@ -0,0 +1 @@
|
||||
$meta-json$
|
12
root/alba.txt
Normal 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
@ -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
@ -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
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
12
root/lan.txt
Normal 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
@ -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
|
@ -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
|
@ -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
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
4
root/sum.txt
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
ASUS STRIX Z270H GAMING
|
||||
Intel Core i5-7600K
|
||||
NVIDIA GTX 1080
|
14
root/tara.txt
Normal 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
|
BIN
static/JetBrainsMono-Regular.woff
Normal file
BIN
static/JetBrainsMono-Regular.woff2
Normal file
74
static/reset.css
Normal 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
After Width: | Height: | Size: 15 KiB |
BIN
static/sergio100w.jpg
Normal file
After Width: | Height: | Size: 11 KiB |
183
static/styles.css
Normal 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 */
|
||||
}
|
||||
}
|
27
tags.html
@ -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
@ -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>
|