Merge remote-tracking branch 'origin/master'

This commit is contained in:
Daniel Flanagan 2024-06-06 17:05:27 -05:00
commit 4b67ef3b9d
22 changed files with 180 additions and 139 deletions

View file

@ -19,7 +19,7 @@ markup:
# post: /blog/:title # post: /blog/:title
params: params:
Description: "Hi! I'm Daniel. I live in Kansas City where I help run a small Christian church, raise two kids with my awesome wife, and write software for Divvy." Description: "Hi! I'm Daniel. I live in Kansas City where I help run a small Christian church, raise three boys with my awesome wife, and write software."
outputs: outputs:
home: [html] home: [html]
@ -35,10 +35,10 @@ menu:
name: blog name: blog
url: /blog/ url: /blog/
weight: 20 weight: 20
- identifier: tips # - identifier: tips
name: tips # name: tips
url: /tips/ # url: /tips/
weight: 30 # weight: 30
- identifier: contact - identifier: contact
name: contact name: contact
url: /contact/ url: /contact/

View file

@ -7,19 +7,22 @@
<!-- updates here must be mirrored in site config for meta description--> <!-- updates here must be mirrored in site config for meta description-->
I live in Kansas City where I help run <a target="_blank" I live in Kansas City where I help run <a target="_blank"
href="https://kcrising.church">a small Christian church</a>, raise two kids href="https://kcrising.church">a small Christian church</a>, raise three boys
with my <a target="_blank" with my <a target="_blank"
href="https://www.instagram.com/valerielauren93">awesome wife</a>, and write href="https://www.instagram.com/valerielauren93">awesome wife</a>, and write
software for <a target="_blank" href="https://getdivvy.com">Divvy</a>. software for <a target="_blank" href="https://getdivvy.com">Divvy (bought by
Bill.com)</a>.
I run a ton of self-hosted software here at home on some machines that sit on I run a lot of self-hosted software here at home on some machines that sit on
[an unnecessarily large server rack in my basement][rack]. I love building [an unnecessarily large server rack in my basement][rack]. I love building
[keyboards][kb], too. [I heavily customize my workflow][wf] and you can [keyboards][kb], too. [I heavily customize my workflow][wf] and you can
sift through my [dotfiles][df] if you like. see how I set everything up with [Nix][nix] if you like (or even my old
[dotfiles](df)).
Occasionally, I post technical articles here. Occasionally, I post technical articles (of varying length and complexity) here.
[rack]: //files.lyte.dev/images/server-rack.jpg [rack]: //files.lyte.dev/images/server-rack-angle-2023-07.jpg
[kb]: //files.lyte.dev/keyboards [kb]: //files.lyte.dev/keyboards
[wf]: //files.lyte.dev/images/desktop-screenshot.png [wf]: //files.lyte.dev/images/desktop-screenshot-busy-2023-07.png
[nix]: //git.lyte.dev/lytedev/nix
[df]: //git.lyte.dev/lytedev/dotfiles [df]: //git.lyte.dev/lytedev/dotfiles

View file

@ -35,7 +35,7 @@ can either use [`Ecto.Changeset.change/2`][Ecto.Changeset.change/2] to handle
the results of an admin user submitting those forms or implement some sort of the results of an admin user submitting those forms or implement some sort of
protocol that lets you specify an admin-specific changeset. protocol that lets you specify an admin-specific changeset.
## Getting That Sweet, Sweet Metadata # Getting That Sweet, Sweet Metadata
My first issue was figuring out how to get the metadata that I knew Ecto already My first issue was figuring out how to get the metadata that I knew Ecto already
had about my schemas. Y'know, which fields are which types, so that I could use had about my schemas. Y'know, which fields are which types, so that I could use
@ -301,7 +301,7 @@ single schema you have, too! Ahh, simplicity.
Here's all the code jumbled together (and perhaps slightly different): Here's all the code jumbled together (and perhaps slightly different):
## All Together Now! # All Together Now!
```elixir ```elixir
# router.ex # router.ex

View file

@ -22,7 +22,7 @@ Check it out in context on
<a href="https://ellie-app.com/53ypTnnFykXa1" target="_blank">Ellie</a>, <a href="https://ellie-app.com/53ypTnnFykXa1" target="_blank">Ellie</a>,
the Elm playground! the Elm playground!
## How Did I Get Here? # How Did I Get Here?
To preface this, I'm going to be writing a *lot* of forms with a *lot* of To preface this, I'm going to be writing a *lot* of forms with a *lot* of
fields, all of which will pretty much work exactly the same, so creating a layer fields, all of which will pretty much work exactly the same, so creating a layer
@ -42,7 +42,7 @@ of copying code from it, I'm just going to roll my own, which is generally
a really good way to learn something anyways. So, while frustrated, I was also a really good way to learn something anyways. So, while frustrated, I was also
eager to tackle the problem. eager to tackle the problem.
## Code Already! # Code Already!
Since the Elm compiler is so awesome, I've taken to what I'm calling Since the Elm compiler is so awesome, I've taken to what I'm calling
"compiler-driven development", which is where I write out what I expect to work "compiler-driven development", which is where I write out what I expect to work
@ -248,7 +248,7 @@ do (computers, amirite?) before I made it to this point.
Now, I'm confident Elm is a tool that can do everything I need it to do. I look Now, I'm confident Elm is a tool that can do everything I need it to do. I look
forward to using it more in the future! forward to using it more in the future!
## Full Source # Full Source
Check it out in context on Check it out in context on
<a href="https://ellie-app.com/53ypTnnFykXa1" target="_blank">Ellie</a>, <a href="https://ellie-app.com/53ypTnnFykXa1" target="_blank">Ellie</a>,

View file

@ -1,12 +1,15 @@
--- ---
title: "Fetching Go Modules via `goproxy` Inside VPN" title: "Fetching Go Modules via `goproxy` Inside VPN"
date: "2023-06-22" date: "2024-02-29"
toc: false
--- ---
I think I finally setup the holy grail of universally being able to I think I finally setup the holy grail of universally being able to
fetch-by-proxy go modules through a firewall using fetch-by-proxy go modules through a firewall using
https://github.com/goproxy/goproxy https://github.com/goproxy/goproxy
<!--more-->
On your internal host (such as your work machine), run the following: On your internal host (such as your work machine), run the following:
```shell_session ```shell_session

View file

@ -1,11 +1,14 @@
--- ---
title: "iex and dbg/1 without pry prompts" title: "iex and dbg/1 without pry prompts"
date: "2023-06-22" date: "2023-06-22"
toc: false
--- ---
I love `iex -S mix ...` but I usually don't like when `dbg` asks me to `pry`. I love `iex -S mix ...` but I usually don't like when `dbg` asks me to `pry`.
Just show me my data! Well, today I learned about `iex --no-pry`: Just show me my data! Well, today I learned about `iex --no-pry`:
<!--more-->
```console ```console
$ iex --help $ iex --help
Usage: iex [options] [.exs file] [data] Usage: iex [options] [.exs file] [data]

View file

@ -5,6 +5,14 @@ draft: true
toc: false toc: false
--- ---
For the longest time, my backup setup has been [a script I run manually that
was quite dumb][backupify] that had no features other than encryption. After
getting my feet wet with `btrfs` somewhat recently and seeing the magic of
deduplication, compression, and snapshots, I was all-in on these features and
also wanted them for my backups.
<!--more-->
# TL;DR # TL;DR
- Install `restic` on both machines (may only be needed on the backupper?) - Install `restic` on both machines (may only be needed on the backupper?)
@ -14,18 +22,6 @@ toc: false
password in a secret place accessible only to the backupper user password in a secret place accessible only to the backupper user
- `for d in $DIRS; do RESTIC_PASSWORD_COMMAND="load secret restic-key" restic -r sftp:restic@backuppee:/backups "$d"; done` - `for d in $DIRS; do RESTIC_PASSWORD_COMMAND="load secret restic-key" restic -r sftp:restic@backuppee:/backups "$d"; done`
<!--more-->
# Intro
For the longest time, my backup setup has been [a script I run manually that
was quite dumb][backupify] that had no features other than encryption. After
getting my feet wet with `btrfs` somewhat recently and seeing the magic of
deduplication, compression, and snapshots, I was all-in on these features and
also wanted them for my backups.
I also had a friend that had been using `btrfs` snapshots for sometime and I was super impressed with the simplicity of his setup. It made me want to improve mine!
# Planning # Planning
The most important thing to think about when it comes to backups is to think The most important thing to think about when it comes to backups is to think

View file

@ -23,13 +23,13 @@ https://git.faceless.lyte.dev/lytedev/weechat-matrix-encryption-guide.git
/tmp/wmeg && $EDITOR /tmp/wmeg/easy-script.bash && /tmp/wmeg/easy-script.bash` /tmp/wmeg && $EDITOR /tmp/wmeg/easy-script.bash && /tmp/wmeg/easy-script.bash`
+ [Configure](#configuration) as needed + [Configure](#configuration) as needed
## Python Versions # Python Versions
We need to establish which version of Python your WeeChat is using. You can find We need to establish which version of Python your WeeChat is using. You can find
this out in WeeChat with `/python version`. In my case, my `python` binary is this out in WeeChat with `/python version`. In my case, my `python` binary is
3.7.2 (`python -V`) while my WeeChat Python version is 2.7.15. 3.7.2 (`python -V`) while my WeeChat Python version is 2.7.15.
## Dependencies # Dependencies
There are a number of dependencies we can go ahead and start grabbing. The main There are a number of dependencies we can go ahead and start grabbing. The main
repository lists a number of them in the `README`, so we will grab those. We repository lists a number of them in the `README`, so we will grab those. We
@ -44,7 +44,7 @@ Notice that we left out the [`matrix-nio`][matrix-nio] dependency. It's not in
PyPi, so we can't just `pip2 install matrix-nio` (yet!) and PyPi's `nio` package PyPi, so we can't just `pip2 install matrix-nio` (yet!) and PyPi's `nio` package
is something probably unrelated, so we'll need to install it manually. is something probably unrelated, so we'll need to install it manually.
## Installing `matrix-nio` # Installing `matrix-nio`
Let's go ahead and clone down the repository and get ready to do some stuff: Let's go ahead and clone down the repository and get ready to do some stuff:
@ -98,7 +98,7 @@ package:
sudo python2 ./setup.py install sudo python2 ./setup.py install
``` ```
## Weechat Plugin Installation # Weechat Plugin Installation
Once we've done that, we should have all the dependencies for `weechat-matrix`, Once we've done that, we should have all the dependencies for `weechat-matrix`,
so let's go ahead and clone that and install it! so let's go ahead and clone that and install it!
@ -111,7 +111,7 @@ make install
Done! Done!
## Configuration # Configuration
The rest is up to you! You'll need to [configure your Matrix servers within The rest is up to you! You'll need to [configure your Matrix servers within
WeeChat][weechat-matrix-config] and then verify keys. Verifying keys isn't WeeChat][weechat-matrix-config] and then verify keys. Verifying keys isn't

View file

@ -29,7 +29,7 @@ function checkMinecraftServerStatus() {
loading.style.display = "inherit"; loading.style.display = "inherit";
servers.style.display = "none"; servers.style.display = "none";
try { try {
fetch("https://api.lyte.dev/minecraft-server-status").then(res => { fetch("https://deno-deploy-private.deno.dev/minecraft-server-status").then(res => {
res.json().then(statuses => { res.json().then(statuses => {
console.log(statuses) console.log(statuses)
loading.style.display = "none"; loading.style.display = "none";

View file

@ -1,5 +0,0 @@
---
title: Blog
---
## Latest Tips ([RSS](/tips/index.xml))

View file

@ -11,6 +11,12 @@ description: "About my tools, workflow, and other things I use as a software dev
This page lists the tools (both physical and otherwise) that I use to do my job This page lists the tools (both physical and otherwise) that I use to do my job
as a software developer along with some thoughts on them. as a software developer along with some thoughts on them.
While this page is likely to be out of date when you're reading it, since I am
usually trying a few small changes here and there at any given point to try and
improve things, I try to update it regularly. You can follow those updates by
looking at [the history of the source code for this page
specifically][uses-history].
For other pages like this from other folks, check out this repository: For other pages like this from other folks, check out this repository:
https://github.com/wesbos/awesome-uses https://github.com/wesbos/awesome-uses
@ -22,7 +28,8 @@ for simplicity, but everything listed here should be searchable. If not, let
me know! I'll try to link to anything free, though, such as software. me know! I'll try to link to anything free, though, such as software.
I'll break stuff up by topic as things come up so you can skip things that are I'll break stuff up by topic as things come up so you can skip things that are
not interesting to you. not interesting to you. There is also a Table of Contents at the top to help
you navigate.
I also think that in general sharing this much information about yourself isn't I also think that in general sharing this much information about yourself isn't
the _best_ idea. However, since I'm confident the bots can't know much more the _best_ idea. However, since I'm confident the bots can't know much more
@ -32,14 +39,15 @@ new stuff! Better yet, I hope you recommend me better stuff! I'm always wanting
to try new tools and discover something new that's good at something. to try new tools and discover something new that's good at something.
Regarding the configuration of my machines and the software referenced below, Regarding the configuration of my machines and the software referenced below,
[please refer to my dotfiles repo](https://git.lyte.dev/lytedev/dotfiles)! [please refer to my Nix repo](https://git.lyte.dev/lytedev/nix)! It may also
be useful to look through my old [dotfiles
repo](https://git.lyte.dev/lytedev/dotfiles).
# Good morning! # Good morning!
I wake up when my kids do out of a Purple mattress. I wake up when my kids do out of a Purple mattress. I slip on my PineTime wrist
watch, grab my flashlight, Android smartphone and backpack, put on my prescription glasses,
I slip on my PineTime wrist watch, grab my Android smartphone and backpack, put and usually make some tea.
on my prescription glasses, and usually make some tea.
## Mattress: Purple King Size ## Mattress: Purple King Size
@ -58,15 +66,31 @@ keeps improving! I get about two weeks of battery with light use and bluetooth
off. I get about 5 days if I've got notifications on full blast, but they off. I get about 5 days if I've got notifications on full blast, but they
recently improved the firmware and claim this may now be more than double! recently improved the firmware and claim this may now be more than double!
## Smart Phone: ASUS ROG Phone 5S ## Flashlight: Emisar DW4
I bought the phone that I can get root access to with the biggest battery, I have a phone with a flashlight. And even my watch can be enough of a
nicest display, and a headphone jack. That's pretty much all I want in a phone. flashlight to navigate in pitch black, but I've taken to carrying an actual
The speakers are a great bonus. The two USB-C ports is actually a super nice flashlight. Specifically, an Emisar DW4. It has a magnetic tailcap so it can
feature since I can connect peripherals while charging without a dock or crazy attach near or directly to many work surfaces. It can get hilariously bright or
dongle. I've also used the video mirroring on the side port to good effect a few dim enough to be suitable for use around sleeping family members in the dark.
times in a pinch. I love this device so much I've bought it twice. I'm not sure
I've done that for anything else... And it has fun RGB LEDs that can flash, show you the battery level, and just
look cool. It's not a game-changer, but at times it is incredibly convenient to
have on hand.
## Smart Phone: ASUS Zenfone 10
I've enjoyed ASUS's phones and have previously used the ROG Phone 5S. I bought
this since it maintained most of the important features of the ROG Phone while
being cheaper and my old ROG Phone started having bluetooth and phone call
issues. To be fair, I bought the international Chinese version off ebay to try
and save a buck.
The Zenfone 10 does everything I need. Lots of battery life, nice display for
reading on, good speakers, blah blah blah. Phone's get less interesting all the
time and most of them are good enough these days.
I hope a real Linux phone comes around!
### Android-Specific Software & Applications ### Android-Specific Software & Applications
@ -75,12 +99,14 @@ with my laptops/desktops) now in no particular order. I have no idea if any of
these have iOS equivalents, but here ya go. these have iOS equivalents, but here ya go.
- [Firefox](https://github.com/mozilla-mobile/fenix) as my web browser - [Firefox](https://github.com/mozilla-mobile/fenix) as my web browser
- Firefox supports extensions even on Android! I use the following: - Firefox supports (some) extensions even on Android! I use the following:
- [Dark Reader](https://addons.mozilla.org/en-US/firefox/addon/darkreader/) for keeping things easy on my eyes - [Dark Reader](https://addons.mozilla.org/en-US/firefox/addon/darkreader/) for keeping things easy on my eyes
- [uBlock Origin](https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/) for blocking ads - [uBlock Origin](https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/) for blocking ads
- [F-Droid](https://f-droid.org) as an awesome resource for applications - [F-Droid](https://f-droid.org) as an awesome resource for applications
- [Termux](https://github.com/termux/termux-app) for doing Linux-y and - [Termux](https://github.com/termux/termux-app) for doing Linux-y and
terminal-y things on my phone terminal-y things on my phone
- There's also [Nix-on-Droid](https://github.com/nix-community/nix-on-droid)
which I've started using more and more
- [OpenKeychain](https://github.com/open-keychain/open-keychain) for mobile GPG - [OpenKeychain](https://github.com/open-keychain/open-keychain) for mobile GPG
key management key management
- [Password Store](https://github.com/android-password-store/Android-Password-Store) - [Password Store](https://github.com/android-password-store/Android-Password-Store)
@ -97,10 +123,8 @@ these have iOS equivalents, but here ya go.
- [Obsidian](https://play.google.com/store/apps/details?id=md.obsidian) for - [Obsidian](https://play.google.com/store/apps/details?id=md.obsidian) for
reading and writing my notes (sync'd via `git`) reading and writing my notes (sync'd via `git`)
- [Fedilab](https://codeberg.org/tom79/Fedilab) as my mobile fediverse client - [Fedilab](https://codeberg.org/tom79/Fedilab) as my mobile fediverse client
- [Weechat-Android](https://github.com/ubergeek42/weechat-android) as my mobile - [Goguma](https://git.sr.ht/~emersion/goguma) as my mobile IRC client (connected to my IRC bouncer, (Soju)[https://git.sr.ht/~emersion/soju])
IRC relay interface - [Tailscale](https://github.com/tailscale/tailscale-android) for my VPN
- [Tailscale](https://github.com/tailscale/tailscale-android) for accessing
my VPN
- Google Wallet for NFC payments (tap-to-pay or contactless) because getting - Google Wallet for NFC payments (tap-to-pay or contactless) because getting
cards out of a wallet is _so_ pre-COVID cards out of a wallet is _so_ pre-COVID
- Google Messages for SMS, MMS, and RCS - Google Messages for SMS, MMS, and RCS
@ -146,6 +170,9 @@ problems immensely and makes port forwarding stuff a breeze. I'm roughly
familiar with its workings, which makes troubleshooting network problems that familiar with its workings, which makes troubleshooting network problems that
much easier for me. much easier for me.
This is the last bastion for Arch Linux in my network and I'm excited to move.
Not because I hate Arch, but I'm _really_ loving NixOS.
## WiFi Access Point: Unifi AP-Pro ## WiFi Access Point: Unifi AP-Pro
Fantastic access point that plays nicely with my very DIY home router. Not Fantastic access point that plays nicely with my very DIY home router. Not
@ -164,47 +191,45 @@ _Share the load_.
## Server(s) ## Server(s)
I have a lot of servers, but the main server is just an ASUS Chromebox 3 that I I was given a Dell R720xd with dual Xeon E5-2580 CPUs (10c/20t),
flashed Arch Linux to. It pretty much just runs a big ol' Docker Compose setup 256GB RAM, and 12x4TB (48TB) of raw disk space. It runs my own, my servers, and
with a sprinkling of other non-Docker'd services. It can do the hardware hosts onsite backups for all my stuff and serves as an offsite encrypted backup
transcoding for Jellyfin, my home media server, and just generally does not for some friends.
break a sweat.
I recently was given a Dell R720xd with 20 hyperthreaded CPU cores (40 threads),
256GB RAM, and 44TB of raw disk space, which I am _very_ excited about, so I'll
probably be moving most stuff to that bad boy, though I expect the power bill to
go up _just a tad_.
I have a few other cheap machines with larger disks at friends and family's I have a few other cheap machines with larger disks at friends and family's
houses for off-site, encrypted backups of important data. I should houses for off-site, encrypted backups of important data. They all run NixOS and
_really_ take the time to validate and automate my backup setup, because right use [its built-in restic backup setup][backups-nix].
now, I do a completely garbage job of it.
Any paid client workloads are served via redundant mechanisms via cloud Any paid client workloads are served via redundant mechanisms via cloud
services, generally Digital Ocean, and backed up with whatever the relevant services, generally Digital Ocean, and backed up with whatever the relevant
cloud offering is. cloud offering is.
I run the following applications for my home: I run the following main applications:
- [Traefik](https://traefik.io/traefik/) to reverse proxy all the things - [Caddy](https://traefik.io/traefik/) to reverse proxy, TLS-terminate all
- Though I use Caddy for most things, Traefik does work nicely with my the things, and serve static, public files
convoluted Docker Compose setup
- A homemade chat bot for various things - A homemade chat bot for various things
- Various game servers (Minecraft, Factorio, Valheim, etc.) - Various game servers (Minecraft, Factorio, Valheim, etc.)
- [A small service that multiplexes audio and video feeds](https://git.lyte.dev/lytedev/tcplexer) mainly for combining a couple audio feeds from DIY IP baby monitors into a single stream for listening
- [Gitea](https://about.gitea.com/) for https://git.lyte.dev 💜💛💙 - [Gitea](https://about.gitea.com/) for https://git.lyte.dev 💜💛💙
- [NGINX](https://www.nginx.com/) to serve static files for https://files.lyte.dev - [Jellyfin](https://jellyfin.org/) for streaming my video media to approved
- [Jellyfin](https://jellyfin.org/) for streaming my video media to approved users (family, friends, etc.) users (family, friends, etc.)
- [Plausible](https://plausible.io/) for web analytics - [PostgreSQL](https://www.postgresql.org/) as the great database for anything
- [PostgreSQL](https://www.postgresql.org/) as the great database for anything that needs one that needs one
- [MariaDB](https://mariadb.org/) for anything too lame to use Postgres - [Vaultwarden](https://github.com/dani-garcia/vaultwarden) for sharing and
managing passwords
- [Atuin](https://atuin.sh) for sync'ing shell histories across my machines
- Samba file shares
Other details can be found in [the Nix config for the `beefcake` host][beefnix].
I run a few services from the cloud as well: I run a few services from the cloud as well:
- [A small DDNS application](https://github.com/lytedev/deno-netlify-ddns) that machines report to so I have relatively up-to-date public IP information on most of my devices (this can't run from home for - [A small DDNS application](https://github.com/lytedev/deno-netlify-ddns) that
fairly obvious reasons 😉) machines report to so I have relatively up-to-date public IP information on
most of my devices (this can't run from home for fairly obvious reasons 😉)
- Each machine runs [the accompanying client](https://github.com/lytedev/deno-netlify-ddns-client) with unique credentials - Each machine runs [the accompanying client](https://github.com/lytedev/deno-netlify-ddns-client) with unique credentials
- Various monitoring scripts for specific things (also can't run from home - who would monitor the monitors?) - Various monitoring scripts for specific things (also can't run from home - who
would monitor the monitors?)
# Starting Work # Starting Work
@ -234,7 +259,7 @@ around with Pipewire.
Like a mattress, very subjective. Get your chairs secondhand for way cheap and Like a mattress, very subjective. Get your chairs secondhand for way cheap and
you can get some heckin' nice chairs. I spend about 8 hours a day in my chair, you can get some heckin' nice chairs. I spend about 8 hours a day in my chair,
so having a good chair is well worth it, even if the price tag is 1,500USD. 😬 so having a good chair is well worth it, even if the price tag is $1,500 USD. 😬
## Desk: Custom ## Desk: Custom
@ -624,3 +649,7 @@ Ah, we have a couple tablets for Khan Academy Kids, white noise (and other
sleep-inducing ambience), and podcasts (like Base Camp Adventures!) and a sleep-inducing ambience), and podcasts (like Base Camp Adventures!) and a
Google Home Mini or two, mostly for playing loud and obnoxious music or setting Google Home Mini or two, mostly for playing loud and obnoxious music or setting
timers. timers.
[uses-history]: https://git.lyte.dev/lytedev/site.lyte.dev/commits/branch/master/content/uses.md
[backups-nix]: https://git.lyte.dev/lytedev/nix/src/commit/fafd242e461620aaa48a669b3623614cc6829700/nixos/beefcake.nix#L528-L573
[beefnix]: https://git.lyte.dev/lytedev/nix/src/branch/main/nixos/beefcake.nix

View file

@ -12,7 +12,7 @@
<link rel="shortcut icon" href="/icon.png" /> <link rel="shortcut icon" href="/icon.png" />
<link defer rel="stylesheet" href="/styles.css" /> <link defer rel="stylesheet" href="/styles.css" />
<script defer type="module" src="/global.mjs"></script> <script defer type="module" src="/global.mjs"></script>
<script async defer data-domain="lyte.dev" src="https://a.lyte.dev/js/plausible.js"></script> <script async defer data-domain="lyte.dev" src="https://a.lyte.dev/js/script.js"></script>
</head> </head>
<body class="system-theme nojs"> <body class="system-theme nojs">
<noscript> <noscript>

View file

@ -10,7 +10,7 @@
</p> </p>
{{ end }} {{ end }}
{{ if not (isset .Params "toc") }} {{ if not (isset .Params "toc") }}
<details style="margin-bottom: 2.5em;"> <details class="left-border" style="margin-bottom: 2.5em;">
<summary> <summary>
<h3>Table of Contents</h3> <h3>Table of Contents</h3>
</summary> </summary>

View file

@ -1,8 +1,10 @@
<h3> <div class="left-border">
<h3>
<a style="flex-shrink: 1; margin-right: auto;" href="{{ .Permalink }}"> <a style="flex-shrink: 1; margin-right: auto;" href="{{ .Permalink }}">
{{ .Title }} {{ .Title }}
</a> </a>
<br /> <br />
<small>Posted on {{ dateFormat "Jan 2 2006" (cond .Date.IsZero .Lastmod .Date) }}</small> <small>Posted on {{ dateFormat "Jan 2 2006" (cond .Date.IsZero .Lastmod .Date) }}</small>
</h3> </h3>
{{ .Summary }} {{ .Summary }}
</div>

View file

@ -16,18 +16,4 @@
{{ end }} {{ end }}
</details> </details>
<details open>
<summary>
<h2 id="latest-tips">
Latest <a href="/tips">Tips</a> (<a target="_blank" href="/tips/index.xml">RSS</a>)
</h2>
</summary>
{{ range (where .Site.RegularPages "Section" "tips") }}
{{ .Render "li" }}
{{ else }}
<p>Looks like there's nothing here!... yet!</p>
{{ end }}
</details>
{{ end }} {{ end }}

View file

@ -1,6 +1,6 @@
<svg class="hide-in-align-center" width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg class="hide-in-align-center" width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12" /> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12H12m-8.25 5.25h16.5" />
</svg> </svg>
<svg class="hide-in-align-left" width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg class="hide-in-align-left" width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /> <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M7.75 12 h8.5 m-12.25 5.25 h16.5" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 559 B

View file

@ -5,5 +5,5 @@
<path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z" />
</svg> </svg>
<svg class="only-in-system-theme" height="24" width="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg class="only-in-system-theme" height="24" width="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /> <path stroke-linecap="round" stroke-linejoin="round" d="M9.53 16.122a3 3 0 0 0-5.78 1.128 2.25 2.25 0 0 1-2.4 2.245 4.5 4.5 0 0 0 8.4-2.245c0-.399-.078-.78-.22-1.128Zm0 0a15.998 15.998 0 0 0 3.388-1.62m-5.043-.025a15.994 15.994 0 0 1 1.622-3.395m3.42 3.42a15.995 15.995 0 0 0 4.764-4.648l3.876-5.814a1.151 1.151 0 0 0-1.597-1.597L14.146 6.32a15.996 15.996 0 0 0-4.649 4.763m3.42 3.42a6.776 6.776 0 0 0-3.42-3.42" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -37,9 +37,14 @@ button.copy-code-button
img, embed, frame, iframe { max-width: 100vw } img, embed, frame, iframe { max-width: 100vw }
details
position relative
details > summary details > summary
cursor pointer cursor pointer
list-style none list-style none
text-decoration underline
color var(--link-fg)
details > summary::-webkit-details-marker details > summary::-webkit-details-marker
display none display none
@ -47,17 +52,20 @@ details > summary::-webkit-details-marker
details > summary::after details > summary::after
position absolute position absolute
top 0 top 0
right 0 right -1em
align-self center background-image url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='currentColor' style='width: 1em; height: 1em;'><path stroke-linecap='round' stroke-linejoin='round' d='M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z' /></svg>")
content "+"
details[open] > summary::after details[open] > summary::after
content "-" content "-"
details .left-border
position relative position relative
padding-left 0.5em padding-left 0.5em
border-left solid var(--syntax-bpx) var(--syntax-ledg) border-left solid var(--syntax-bpx) var(--syntax-ledg)
transition 0.2s border-color
&:hover
border-color var(--syntax-ledgh)
html,body html,body
min-height 100vh min-height 100vh
@ -76,15 +84,21 @@ html,body
padding 0.5em padding 0.5em
line-height 1.6em line-height 1.6em
main:first-child, footer:first-child { margin-top: 0 } main:first-child, footer:first-child
margin-top 0
&> main, > footer > main, > footer
.highlight .highlight
pre.chroma
position relative position relative
background-color var(--syntax-bg) background-color var(--syntax-bg)
max-width 100vw max-width 100vw
border-left solid var(--syntax-bpx) var(--syntax-ledg) border-left solid var(--syntax-bpx) var(--syntax-ledg)
display flex display flex
transition 0.2s border-color
&:hover
border-color var(--syntax-ledgh)
li li
margin-top 0.5em margin-top 0.5em
@ -260,7 +274,7 @@ form
.hide-in-align-left { display: none } .hide-in-align-left { display: none }
.with-align { text-align: left } .with-align { text-align: left }
body.align-center body:not(.align-left)
.hide-in-align-center { display: none } .hide-in-align-center { display: none }
.with-align { text-align: center } .with-align { text-align: center }
&> main, > footer &> main, > footer
@ -280,24 +294,25 @@ form
margin-right auto margin-right auto
.highlight .highlight
border-left 0
pre.chroma pre.chroma
padding 0 padding 0
display flex display flex
flex-direction column flex-direction column
width auto width auto
flex 1 flex 1
justify-content center // justify-content center
align-content center // align-content center
align-items center // align-items center
margin-left auto margin-left auto
margin-right auto margin-right auto
> code width 600px
width: 600px;
padding 0.25em 0.5em padding 0.25em 0.5em
border-left solid var(--syntax-bpx) var(--syntax-ledg) border-left solid var(--syntax-bpx) var(--syntax-ledg)
transition border-color 0.2s
&:hover
border-color var(--syntax-ledgh)
img, img,
embed, embed,

View file

@ -10,7 +10,7 @@ main .highlight pre.chroma
color var(--fg) color var(--fg)
main > .highlight > pre.chroma > code > .line main > .highlight > pre.chroma > code > .line
margin-right 5em // margin-right 5em
.chroma .chroma
.err .err

View file

@ -22,6 +22,7 @@ light-theme = {
--syntax-brd: rgba(255, 255, 255, 0.2), --syntax-brd: rgba(255, 255, 255, 0.2),
--syntax-bg: #e6e9ef, --syntax-bg: #e6e9ef,
--syntax-ledg: rgba(0, 0, 0, 0.1), --syntax-ledg: rgba(0, 0, 0, 0.1),
--syntax-ledg: rgba(0, 0, 0, 0.3),
--syntax-sh: #6c6f85, --syntax-sh: #6c6f85,
--syntax-name: latte['green'], --syntax-name: latte['green'],
--syntax-mag: latte['red'], --syntax-mag: latte['red'],
@ -50,7 +51,8 @@ light-theme = {
dark-theme = { dark-theme = {
--syntax-brd: rgba(255, 255, 255, 0.2), --syntax-brd: rgba(255, 255, 255, 0.2),
--syntax-bg: #181825, --syntax-bg: #181825,
--syntax-ledg: #313244, --syntax-ledg: alpha(mocha['sapphire'], 0.5),
--syntax-ledgh: mocha['sapphire'],
--syntax-sh: #6c7086, --syntax-sh: #6c7086,
--icon-shadow: #000, --icon-shadow: #000,
--syntax-name: mocha['green'], --syntax-name: mocha['green'],

View file

@ -14,8 +14,8 @@ document.querySelectorAll(".theme-toggler").forEach((a) =>
const initAlign = () => { const initAlign = () => {
const cur = localStorage.getItem("align"); const cur = localStorage.getItem("align");
const prev = cur == "center" ? "left" : "center"; const prev = cur == "center" ? "left" : "center";
document.body.classList.add("align-" + cur);
document.body.classList.remove("align-" + prev); document.body.classList.remove("align-" + prev);
document.body.classList.add("align-" + cur);
}; };
if (localStorage.getItem("align") === null) { if (localStorage.getItem("align") === null) {

View file

@ -54,6 +54,13 @@ export class Theme {
document.body.classList.remove(`dark-theme`) document.body.classList.remove(`dark-theme`)
document.body.classList.remove(`system-theme`) document.body.classList.remove(`system-theme`)
document.body.classList.add(`${this.#theme}-theme`) document.body.classList.add(`${this.#theme}-theme`)
const toggler = document.getElementById("theme-toggler")
toggler.setAttribute("title", this.toggleTitle)
toggler.setAttribute("aria-label", "toggle theme")
}
get toggleTitle() {
return `toggle theme (current theme: ${this.theme})`
} }
get theme() { get theme() {