This commit is contained in:
parent
2fe8b81523
commit
1cd021d0a7
|
@ -4,7 +4,7 @@ A starter repository showing how to build a blog with the [Eleventy](https://www
|
|||
|
||||
## Getting Started
|
||||
|
||||
* [Want a more generic/detailed getting started guide?](https://www.11ty.dev/docs/getting-started/)
|
||||
- [Want a more generic/detailed getting started guide?](https://www.11ty.dev/docs/getting-started/)
|
||||
|
||||
1. Make a directory and navigate to it:
|
||||
|
||||
|
|
170
_data/colors.js
170
_data/colors.js
|
@ -1,92 +1,92 @@
|
|||
export default {
|
||||
dark: {
|
||||
"source": "rootloops.sh",
|
||||
"hex": {
|
||||
"background": "#0a0808",
|
||||
"foreground": "#e7e1e2",
|
||||
"cursor": "#c2b5b8",
|
||||
"black": "#272022",
|
||||
"red": "#cf5080",
|
||||
"green": "#7b8d39",
|
||||
"yellow": "#b57235",
|
||||
"blue": "#3c8cbf",
|
||||
"magenta": "#9468d8",
|
||||
"cyan": "#3b9586",
|
||||
"white": "#c2b5b8",
|
||||
"brightBlack": "#5a4e51",
|
||||
"brightRed": "#e26b95",
|
||||
"brightGreen": "#8fa445",
|
||||
"brightYellow": "#cf8544",
|
||||
"brightBlue": "#4fa1d7",
|
||||
"brightMagenta": "#a782e5",
|
||||
"brightCyan": "#47ac9b",
|
||||
"brightWhite": "#f3f0f1"
|
||||
source: "rootloops.sh",
|
||||
hex: {
|
||||
background: "#0a0808",
|
||||
foreground: "#e7e1e2",
|
||||
cursor: "#c2b5b8",
|
||||
black: "#272022",
|
||||
red: "#cf5080",
|
||||
green: "#7b8d39",
|
||||
yellow: "#b57235",
|
||||
blue: "#3c8cbf",
|
||||
magenta: "#9468d8",
|
||||
cyan: "#3b9586",
|
||||
white: "#c2b5b8",
|
||||
brightBlack: "#5a4e51",
|
||||
brightRed: "#e26b95",
|
||||
brightGreen: "#8fa445",
|
||||
brightYellow: "#cf8544",
|
||||
brightBlue: "#4fa1d7",
|
||||
brightMagenta: "#a782e5",
|
||||
brightCyan: "#47ac9b",
|
||||
brightWhite: "#f3f0f1",
|
||||
},
|
||||
hsl: {
|
||||
background: "hsl(345.13, 15.37%, 3.54%)",
|
||||
foreground: "hsl(344.94, 10.53%, 89.29%)",
|
||||
cursor: "hsl(344.63, 9.37%, 73.52%)",
|
||||
black: "hsl(344.1, 8.9%, 13.97%)",
|
||||
red: "hsl(337.55, 56.97%, 56.34%)",
|
||||
green: "hsl(72.88, 42.49%, 38.93%)",
|
||||
yellow: "hsl(28.49, 54.76%, 45.89%)",
|
||||
blue: "hsl(203.33, 52.42%, 49.09%)",
|
||||
magenta: "hsl(264.05, 58.81%, 62.59%)",
|
||||
cyan: "hsl(169.71, 43.35%, 40.84%)",
|
||||
white: "hsl(344.63, 9.37%, 73.52%)",
|
||||
brightBlack: "hsl(344.15, 7.1%, 32.99%)",
|
||||
brightRed: "hsl(339.06, 67.64%, 65.41%)",
|
||||
brightGreen: "hsl(72.99, 40.55%, 45.65%)",
|
||||
brightYellow: "hsl(28.18, 58.94%, 53.93%)",
|
||||
brightBlue: "hsl(203.73, 63.27%, 57.72%)",
|
||||
brightMagenta: "hsl(262.71, 65.56%, 70.29%)",
|
||||
brightCyan: "hsl(169.62, 41.51%, 47.79%)",
|
||||
brightWhite: "hsl(345.03, 10.68%, 94.62%)",
|
||||
},
|
||||
"hsl": {
|
||||
"background": "hsl(345.13, 15.37%, 3.54%)",
|
||||
"foreground": "hsl(344.94, 10.53%, 89.29%)",
|
||||
"cursor": "hsl(344.63, 9.37%, 73.52%)",
|
||||
"black": "hsl(344.1, 8.9%, 13.97%)",
|
||||
"red": "hsl(337.55, 56.97%, 56.34%)",
|
||||
"green": "hsl(72.88, 42.49%, 38.93%)",
|
||||
"yellow": "hsl(28.49, 54.76%, 45.89%)",
|
||||
"blue": "hsl(203.33, 52.42%, 49.09%)",
|
||||
"magenta": "hsl(264.05, 58.81%, 62.59%)",
|
||||
"cyan": "hsl(169.71, 43.35%, 40.84%)",
|
||||
"white": "hsl(344.63, 9.37%, 73.52%)",
|
||||
"brightBlack": "hsl(344.15, 7.1%, 32.99%)",
|
||||
"brightRed": "hsl(339.06, 67.64%, 65.41%)",
|
||||
"brightGreen": "hsl(72.99, 40.55%, 45.65%)",
|
||||
"brightYellow": "hsl(28.18, 58.94%, 53.93%)",
|
||||
"brightBlue": "hsl(203.73, 63.27%, 57.72%)",
|
||||
"brightMagenta": "hsl(262.71, 65.56%, 70.29%)",
|
||||
"brightCyan": "hsl(169.62, 41.51%, 47.79%)",
|
||||
"brightWhite": "hsl(345.03, 10.68%, 94.62%)"
|
||||
}
|
||||
},
|
||||
light: {
|
||||
"source": "rootloops.sh",
|
||||
"hex": {
|
||||
"background": "#f3f0f1",
|
||||
"foreground": "#40373a",
|
||||
"cursor": "#74666a",
|
||||
"black": "#e7e1e2",
|
||||
"red": "#cf5080",
|
||||
"green": "#7b8d39",
|
||||
"yellow": "#b57235",
|
||||
"blue": "#3c8cbf",
|
||||
"magenta": "#9468d8",
|
||||
"cyan": "#3b9586",
|
||||
"white": "#74666a",
|
||||
"brightBlack": "#b5a7ab",
|
||||
"brightRed": "#e26b95",
|
||||
"brightGreen": "#8fa445",
|
||||
"brightYellow": "#cf8544",
|
||||
"brightBlue": "#4fa1d7",
|
||||
"brightMagenta": "#a782e5",
|
||||
"brightCyan": "#47ac9b",
|
||||
"brightWhite": "#272022"
|
||||
source: "rootloops.sh",
|
||||
hex: {
|
||||
background: "#f3f0f1",
|
||||
foreground: "#40373a",
|
||||
cursor: "#74666a",
|
||||
black: "#e7e1e2",
|
||||
red: "#cf5080",
|
||||
green: "#7b8d39",
|
||||
yellow: "#b57235",
|
||||
blue: "#3c8cbf",
|
||||
magenta: "#9468d8",
|
||||
cyan: "#3b9586",
|
||||
white: "#74666a",
|
||||
brightBlack: "#b5a7ab",
|
||||
brightRed: "#e26b95",
|
||||
brightGreen: "#8fa445",
|
||||
brightYellow: "#cf8544",
|
||||
brightBlue: "#4fa1d7",
|
||||
brightMagenta: "#a782e5",
|
||||
brightCyan: "#47ac9b",
|
||||
brightWhite: "#272022",
|
||||
},
|
||||
"hsl": {
|
||||
"background": "hsl(345.03, 10.68%, 94.62%)",
|
||||
"foreground": "hsl(344.11, 7.75%, 23.41%)",
|
||||
"cursor": "hsl(344.2, 6.49%, 42.82%)",
|
||||
"black": "hsl(344.94, 10.53%, 89.29%)",
|
||||
"red": "hsl(337.55, 56.97%, 56.34%)",
|
||||
"green": "hsl(72.88, 42.49%, 38.93%)",
|
||||
"yellow": "hsl(28.49, 54.76%, 45.89%)",
|
||||
"blue": "hsl(203.33, 52.42%, 49.09%)",
|
||||
"magenta": "hsl(264.05, 58.81%, 62.59%)",
|
||||
"cyan": "hsl(169.71, 43.35%, 40.84%)",
|
||||
"white": "hsl(344.2, 6.49%, 42.82%)",
|
||||
"brightBlack": "hsl(344.53, 8.76%, 68.33%)",
|
||||
"brightRed": "hsl(339.06, 67.64%, 65.41%)",
|
||||
"brightGreen": "hsl(72.99, 40.55%, 45.65%)",
|
||||
"brightYellow": "hsl(28.18, 58.94%, 53.93%)",
|
||||
"brightBlue": "hsl(203.73, 63.27%, 57.72%)",
|
||||
"brightMagenta": "hsl(262.71, 65.56%, 70.29%)",
|
||||
"brightCyan": "hsl(169.62, 41.51%, 47.79%)",
|
||||
"brightWhite": "hsl(344.1, 8.9%, 13.97%)"
|
||||
}
|
||||
hsl: {
|
||||
background: "hsl(345.03, 10.68%, 94.62%)",
|
||||
foreground: "hsl(344.11, 7.75%, 23.41%)",
|
||||
cursor: "hsl(344.2, 6.49%, 42.82%)",
|
||||
black: "hsl(344.94, 10.53%, 89.29%)",
|
||||
red: "hsl(337.55, 56.97%, 56.34%)",
|
||||
green: "hsl(72.88, 42.49%, 38.93%)",
|
||||
yellow: "hsl(28.49, 54.76%, 45.89%)",
|
||||
blue: "hsl(203.33, 52.42%, 49.09%)",
|
||||
magenta: "hsl(264.05, 58.81%, 62.59%)",
|
||||
cyan: "hsl(169.71, 43.35%, 40.84%)",
|
||||
white: "hsl(344.2, 6.49%, 42.82%)",
|
||||
brightBlack: "hsl(344.53, 8.76%, 68.33%)",
|
||||
brightRed: "hsl(339.06, 67.64%, 65.41%)",
|
||||
brightGreen: "hsl(72.99, 40.55%, 45.65%)",
|
||||
brightYellow: "hsl(28.18, 58.94%, 53.93%)",
|
||||
brightBlue: "hsl(203.73, 63.27%, 57.72%)",
|
||||
brightMagenta: "hsl(262.71, 65.56%, 70.29%)",
|
||||
brightCyan: "hsl(169.62, 41.51%, 47.79%)",
|
||||
brightWhite: "hsl(344.1, 8.9%, 13.97%)",
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,6 +6,6 @@ export default {
|
|||
author: {
|
||||
name: "Saji",
|
||||
email: "saji@saji.dev",
|
||||
url: "https://saji.dev/about-me/"
|
||||
}
|
||||
}
|
||||
url: "https://saji.dev/about-me/",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ layout: layouts/home.njk
|
|||
permalink: 404.html
|
||||
eleventyExcludeFromCollections: true
|
||||
---
|
||||
|
||||
# Content not found.
|
||||
|
||||
Go <a href="/">home</a>.
|
||||
|
|
|
@ -4,6 +4,7 @@ eleventyNavigation:
|
|||
key: About Me
|
||||
order: 3
|
||||
---
|
||||
|
||||
# About Me
|
||||
|
||||
I am a person that writes stuff.
|
||||
|
|
|
@ -6,6 +6,4 @@ tags:
|
|||
- project
|
||||
---
|
||||
|
||||
|
||||
This is a test
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
export default {
|
||||
tags: [
|
||||
"posts"
|
||||
],
|
||||
"layout": "layouts/post.njk",
|
||||
tags: ["posts"],
|
||||
layout: "layouts/post.njk",
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ has been documented to death by skids, I haven't seen anyone reference this yet.
|
|||
I'm sure someone is using it, since it's powerful.
|
||||
|
||||
Case in point:
|
||||
|
||||
```
|
||||
/"[a-z]{4}(?: [a-z]{4}){3}"/ language:Python SMTP
|
||||
```
|
||||
|
|
|
@ -13,7 +13,7 @@ Part one focuses on the image format.
|
|||
|
||||
# Introduction
|
||||
|
||||
*[ITAR]: International Traffic in Arms Regulations
|
||||
\*[ITAR]: International Traffic in Arms Regulations
|
||||
In the past few years, Chinese manufacturers have brought cheap, performant microbolometer arrays to the consumer market.
|
||||
These arrays are higher resolution and faster framerates than what can reasonably be acquired in the West - mostly due
|
||||
to low competition and ITAR restrictions. Most popular are the low-cost modules by Infiray, which provides whitelabel solutions
|
||||
|
@ -35,10 +35,8 @@ odd phone app. However this choice seems less popular on forums and there is no
|
|||
reverse engineering project that exists already, so we'll have to start from
|
||||
scratch.
|
||||
|
||||
|
||||
# Getting the picture
|
||||
|
||||
|
||||
To start with something simple, lets figure out how their image format works. They call it "radiometric JPEG". This
|
||||
isn't to be confused with FLIR's RJPEG format, which is already well understood.. When using regular image viewers,
|
||||
we get a screenshot of the display. Where things get interesting is when we open the image with the Hikmicro Analyzer software, we can see the full
|
||||
|
@ -69,9 +67,3 @@ Well that's something. It's not perfect, but it means that our thermal data is r
|
|||
# I'm hexing here
|
||||
|
||||
Imhex is pretty great. You can perform a lot of analysis without needing other tools.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ complex Ansible playbooks. While I don't think NixOS is ready for
|
|||
personal computers, it absolutely makes sense on less dynamic devices
|
||||
like servers or embedded-ish machines.
|
||||
|
||||
|
||||
We can use NixOS and nixpkgs to derive a fully defined operating system and services.
|
||||
Then, we can:
|
||||
|
||||
|
@ -118,12 +117,10 @@ $ ls /nix/store | grep myblog
|
|||
mqhssdlmg9f03avpajwcqaah2apknl02-myblog
|
||||
```
|
||||
|
||||
|
||||
Before we go any further, let's set up the nginx server,
|
||||
as well as a well-known path for our website. I'll also
|
||||
add a user here that we can use to deploy.
|
||||
|
||||
|
||||
```nix
|
||||
{
|
||||
config,
|
||||
|
@ -194,17 +191,15 @@ in
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
Now we have a scoped user, with an ssh key authorized. It needs a shell so we can actually log
|
||||
in remotely.
|
||||
The last step is creating that symlink. This is where the concept of "activation" comes into play.
|
||||
|
||||
|
||||
For NixOS, `deploy-rs` activation just calls `switch-to-configuration` to make
|
||||
the system change the profile. We can effectively do whatever we want here.
|
||||
|
||||
|
||||
Reading the [custom activator](https://github.com/serokell/deploy-rs/blob/aa07eb05537d4cd025e2310397a6adcedfe72c76/flake.nix#L58C13-L96C17) source:
|
||||
|
||||
```nix
|
||||
custom = {
|
||||
__functor = customSelf: base: activate:
|
||||
|
@ -246,7 +241,6 @@ custom = {
|
|||
};
|
||||
```
|
||||
|
||||
|
||||
This is a bit difficult to parse because there's the whole `__functor` bit.
|
||||
Essentially, we use `buildEnv` to add some new scripts to the `base` package,
|
||||
which are then used to call `activate`, which can be a shell script or a binary.
|
||||
|
@ -314,7 +308,6 @@ The chain looks like this:
|
|||
A profile is just a symlink to a derivation in the nix store. One layer of indirection
|
||||
exists to make rollbacks easier.
|
||||
|
||||
|
||||
# End
|
||||
|
||||
I hope this was useful for you. I think non-root deployment is
|
||||
|
|
|
@ -140,4 +140,3 @@ to hack around that with a shim but that's a problem for later. It works
|
|||
fine at 9600 baud using software flow control.
|
||||
|
||||
To the folks who rave about the terminals of yore, I get it now.
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@ description: Bringing modern synthesis to 30-year old technology with Yosys and
|
|||
date: 2024-06-14
|
||||
---
|
||||
|
||||
|
||||
|
||||
GAL/PALs are ancient chips designed to implement custom logic as a precursor to CPLDs and FPGAs.
|
||||
They can implement any combinational logic using a Sum-of-Products architecture and a grid of wires
|
||||
with certain wires being connected at different coordinates:
|
||||
|
@ -41,11 +39,9 @@ DESCRIPTION
|
|||
Simple test of combinatorial logic.
|
||||
```
|
||||
|
||||
|
||||
I don't want to deal with this. It's annoying to think about. What if we could create our own Verilog flow for GAL chips?
|
||||
Then we could take advantage of the simulation and synthesis capabilities, which would make these chips a bit more useful.
|
||||
|
||||
|
||||
# The idea
|
||||
|
||||
We use Yosys to synthesize Verilog, and do technology-mapping onto a set of primitive blocks that are then mapped by a custom tool.
|
||||
|
@ -54,20 +50,15 @@ onto actual positions based on a pin constraints file.
|
|||
|
||||
There's two components - Yosys technology mapping, and writing a "place-and-route" tool. We'll start with Yosys.
|
||||
|
||||
|
||||
|
||||
## Yosys Technology Mapping
|
||||
|
||||
This process is cursed and low level, but it works a little like this:
|
||||
|
||||
- Yosys takes a generic synthesis pass at a netlist, which simplifies the design without looking at any physical implementation
|
||||
- The simplified design is then mapped into Verilog-based "blocks", which could be things like AND gates, or complex blocks like a LUT.
|
||||
This process turns generic blocks like an adder into a set of gates.
|
||||
This process turns generic blocks like an adder into a set of gates.
|
||||
- certain sequences of gates are then grouped and unified in the "extract" pass. Extraction would convert an operation like `mul -> add`
|
||||
into a single `mul_add` block.
|
||||
|
||||
|
||||
|
||||
into a single `mul_add` block.
|
||||
|
||||
## A history lesson
|
||||
|
||||
|
@ -127,7 +118,6 @@ logic chip, changing the function depending on what you need. Additionally,
|
|||
GALs operate at 5 volts is useful when interfacing with older systems and
|
||||
removes the need for a level shifter.
|
||||
|
||||
|
||||
In practice, this isn't all great. Programming GALs is an exercise in frustration.
|
||||
Take a look at a basic combinatorial assembly file:
|
||||
|
||||
|
@ -159,18 +149,16 @@ test this in a larger system (we'll get back to this). Compared to the Verilog
|
|||
flow, with simulation, testbenches, and synthesis, the raw assembly is stuck in
|
||||
the 80s and requires manual logic simplification.
|
||||
|
||||
Verilog compilers for GALs *did exist*, but they ran on old-as-dirt systems,
|
||||
Verilog compilers for GALs _did exist_, but they ran on old-as-dirt systems,
|
||||
didn't have any significant optimization capabilities, and were almost always
|
||||
proprietary. What if we could make our own open-source Verilog flow for GAL
|
||||
chips? Then we could write test benches in Verilog, map complex designs onto
|
||||
the chip, and even integrate our designs with FPGAs later down the line.
|
||||
|
||||
|
||||
# The idea
|
||||
|
||||
GAL assembly appears occasionally when working with older systems, especially in a retro emulation context.
|
||||
|
||||
|
||||
# Is this useful?
|
||||
|
||||
Not particularly.
|
||||
|
|
|
@ -15,8 +15,8 @@ C interop, interesting features, and fast. Some of the headlines:
|
|||
|
||||
- `comptime`: Lispers are in shambles. Run Zig code to generate Zig code.
|
||||
- Cross compilation. For real. Not Rust cross where you need to find a sysroot.
|
||||
Not Go cross locking you out of CGO. You can literally change a variable and make
|
||||
a Mac binary on Windows like it's nothing.
|
||||
Not Go cross locking you out of CGO. You can literally change a variable and make
|
||||
a Mac binary on Windows like it's nothing.
|
||||
- Web target, both WASI and freestanding.
|
||||
- SIMD Vectors? We take those I guess.
|
||||
- It's got a build/test system built in. More on that later.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export default {
|
||||
tags: [
|
||||
],
|
||||
"layout": "layouts/deck.njk",
|
||||
tags: [],
|
||||
layout: "layouts/deck.njk",
|
||||
};
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
<section>
|
||||
<h2>Object (dis)orientation</h2>
|
||||
<h6> How to survive a "post-OO" world</h6>
|
||||
<h6>How to survive a "post-OO" world</h6>
|
||||
</section>
|
||||
<section>
|
||||
<section>
|
||||
Class/Inheritance has challenges
|
||||
</section>
|
||||
<section>Class/Inheritance has challenges</section>
|
||||
<section>
|
||||
Combining Data + Code
|
||||
<pre><code data-trim data-noescape data-line-numbers="5|7-9">
|
||||
|
@ -20,21 +18,32 @@
|
|||
};
|
||||
};
|
||||
</code></pre>
|
||||
<p class="fragment">You have to know if this is an "interface", abstract class, or regular class.</p>
|
||||
<small class="fragment">(it's an abstract class, since <code>makeSound</code> is pure virtual)</small>
|
||||
<p class="fragment">
|
||||
You have to know if this is an "interface", abstract class, or regular
|
||||
class.
|
||||
</p>
|
||||
<small class="fragment"
|
||||
>(it's an abstract class, since <code>makeSound</code> is pure
|
||||
virtual)</small
|
||||
>
|
||||
</section>
|
||||
<section>
|
||||
<p> A class can be one of many things </p>
|
||||
<p>A class can be one of many things</p>
|
||||
<ul>
|
||||
<li>Interface - abstract class with no members, and purely virtual </li>
|
||||
<li>Abstract Class - class with <em>some</em> pure virtual methods </li>
|
||||
<li>"Regular" Class - class that is standalone and is fully implemented </li>
|
||||
<li>Interface - abstract class with no members, and purely virtual</li>
|
||||
<li>Abstract Class - class with <em>some</em> pure virtual methods</li>
|
||||
<li>
|
||||
"Regular" Class - class that is standalone and is fully implemented
|
||||
</li>
|
||||
</ul>
|
||||
<small class="fragment">These concepts all exist under the <code>class</code> keyword </small>
|
||||
<small class="fragment"
|
||||
>These concepts all exist under the <code>class</code> keyword
|
||||
</small>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
In Rust, you trade <em>Inheritance</em> for <em>Traits</em> and <em>Types</em>.
|
||||
In Rust, you trade <em>Inheritance</em> for <em>Traits</em> and
|
||||
<em>Types</em>.
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
@ -63,10 +72,9 @@
|
|||
}
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<p> And can be used statically <em>or</em> dynamically!</p>
|
||||
<p>And can be used statically <em>or</em> dynamically!</p>
|
||||
<pre><code data-trim>
|
||||
fn static_mammal<T: Mammal>(m: T) {
|
||||
// the type of T must be known at compile time.
|
||||
|
@ -77,4 +85,3 @@
|
|||
</code></pre>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ eleventyNavigation:
|
|||
key: Now
|
||||
order: 4
|
||||
---
|
||||
|
||||
## Save Slot 0
|
||||
|
||||
Rate-Monotonic scheduling my life.
|
||||
|
|
|
@ -3,43 +3,49 @@ export function eleventyComputedPermalink() {
|
|||
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
||||
return (data) => {
|
||||
// Always skip during non-watch/serve builds
|
||||
if(data.draft && !process.env.BUILD_DRAFTS) {
|
||||
if (data.draft && !process.env.BUILD_DRAFTS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return data.permalink;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function eleventyComputedExcludeFromCollections() {
|
||||
// When using `addGlobalData` and you *want* to return a function, you must nest functions like this.
|
||||
// `addGlobalData` acts like a global data file and runs the top level function it receives.
|
||||
return (data) => {
|
||||
// Always exclude from non-watch/serve builds
|
||||
if(data.draft && !process.env.BUILD_DRAFTS) {
|
||||
if (data.draft && !process.env.BUILD_DRAFTS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return data.eleventyExcludeFromCollections;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default function (eleventyConfig) {
|
||||
eleventyConfig.addGlobalData("eleventyComputed.permalink", eleventyComputedPermalink);
|
||||
eleventyConfig.addGlobalData("eleventyComputed.eleventyExcludeFromCollections", eleventyComputedExcludeFromCollections);
|
||||
eleventyConfig.addGlobalData(
|
||||
"eleventyComputed.permalink",
|
||||
eleventyComputedPermalink,
|
||||
);
|
||||
eleventyConfig.addGlobalData(
|
||||
"eleventyComputed.eleventyExcludeFromCollections",
|
||||
eleventyComputedExcludeFromCollections,
|
||||
);
|
||||
|
||||
let logged = false;
|
||||
eleventyConfig.on("eleventy.before", ({runMode}) => {
|
||||
eleventyConfig.on("eleventy.before", ({ runMode }) => {
|
||||
let text = "Excluding";
|
||||
// Only show drafts in serve/watch modes
|
||||
if(runMode === "serve" || runMode === "watch") {
|
||||
if (runMode === "serve" || runMode === "watch") {
|
||||
process.env.BUILD_DRAFTS = true;
|
||||
text = "Including";
|
||||
}
|
||||
|
||||
// Only log once.
|
||||
if(!logged) {
|
||||
console.log( `[11ty/eleventy-base-blog] ${text} drafts.` );
|
||||
if (!logged) {
|
||||
console.log(`[11ty/eleventy-base-blog] ${text} drafts.`);
|
||||
}
|
||||
|
||||
logged = true;
|
||||
|
|
|
@ -11,13 +11,12 @@ import pluginNavigation from "@11ty/eleventy-navigation";
|
|||
import { EleventyHtmlBasePlugin } from "@11ty/eleventy";
|
||||
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
|
||||
|
||||
|
||||
import pluginDrafts from "./eleventy.config.drafts.js";
|
||||
|
||||
import fs from 'fs/promises'
|
||||
import fs from "fs/promises";
|
||||
|
||||
/** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */
|
||||
export default async function(eleventyConfig) {
|
||||
export default async function (eleventyConfig) {
|
||||
// Copy the contents of the `public` folder to the output folder
|
||||
// For example, `./public/css/` ends up in `_site/css/`
|
||||
eleventyConfig.addPassthroughCopy({
|
||||
|
@ -32,30 +31,27 @@ export default async function(eleventyConfig) {
|
|||
eleventyConfig.addPlugin(pluginDrafts);
|
||||
// eleventyConfig.addPlugin(pluginFonts);
|
||||
// Official plugins
|
||||
let mkFeed = function(type, path) {
|
||||
let mkFeed = function (type, path) {
|
||||
eleventyConfig.addPlugin(feedPlugin, {
|
||||
type: type,
|
||||
outputPath: path,
|
||||
collection: {
|
||||
name: "posts",
|
||||
limit: 0
|
||||
limit: 0,
|
||||
},
|
||||
metadata: {
|
||||
title: "Musings",
|
||||
base: "https://saji.dev",
|
||||
language: "en",
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
mkFeed("rss", "/rss.feed.xml");
|
||||
mkFeed("atom", "/atom.feed.xml");
|
||||
mkFeed("json", "/feed.json");
|
||||
|
||||
eleventyConfig.addPlugin(pluginSyntaxHighlight, {
|
||||
preAttributes: { tabindex: 0 }
|
||||
preAttributes: { tabindex: 0 },
|
||||
});
|
||||
eleventyConfig.addPlugin(pluginNavigation);
|
||||
eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
|
||||
|
@ -68,20 +64,20 @@ export default async function(eleventyConfig) {
|
|||
loading: "lazy",
|
||||
decoding: "async",
|
||||
sizes: "auto",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Filters
|
||||
eleventyConfig.addFilter("readableDate", (dateObj, format, zone) => {
|
||||
// Formatting tokens for Luxon: https://moment.github.io/luxon/#/formatting?id=table-of-tokens
|
||||
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(format || "dd LLLL yyyy");
|
||||
return DateTime.fromJSDate(dateObj, { zone: zone || "utc" }).toFormat(
|
||||
format || "dd LLLL yyyy",
|
||||
);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter('htmlDateString', (dateObj) => {
|
||||
eleventyConfig.addFilter("htmlDateString", (dateObj) => {
|
||||
// dateObj input: https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-date-string
|
||||
return DateTime.fromJSDate(dateObj, { zone: 'utc' }).toFormat('yyyy-LL-dd');
|
||||
return DateTime.fromJSDate(dateObj, { zone: "utc" }).toFormat("yyyy-LL-dd");
|
||||
});
|
||||
|
||||
// Get the first `n` elements of a collection.
|
||||
|
@ -102,21 +98,23 @@ export default async function(eleventyConfig) {
|
|||
});
|
||||
|
||||
// Return all the tags used in a collection
|
||||
eleventyConfig.addFilter("getAllTags", collection => {
|
||||
eleventyConfig.addFilter("getAllTags", (collection) => {
|
||||
let tagSet = new Set();
|
||||
for (let item of collection) {
|
||||
(item.data.tags || []).forEach(tag => tagSet.add(tag));
|
||||
(item.data.tags || []).forEach((tag) => tagSet.add(tag));
|
||||
}
|
||||
return Array.from(tagSet);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("filterTagList", function filterTagList(tags) {
|
||||
return (tags || []).filter(tag => ["all", "nav", "post", "posts"].indexOf(tag) === -1);
|
||||
return (tags || []).filter(
|
||||
(tag) => ["all", "nav", "post", "posts"].indexOf(tag) === -1,
|
||||
);
|
||||
});
|
||||
|
||||
let mdIt;
|
||||
// Customize Markdown library settings:
|
||||
eleventyConfig.amendLibrary("md", mdLib => {
|
||||
eleventyConfig.amendLibrary("md", (mdLib) => {
|
||||
// hack to let us use the markdown renderer for later.
|
||||
mdIt = mdLib;
|
||||
mdLib.use(markdownItAnchor, {
|
||||
|
@ -127,23 +125,25 @@ export default async function(eleventyConfig) {
|
|||
ariaHidden: false,
|
||||
}),
|
||||
level: [1, 2, 3, 4],
|
||||
slugify: eleventyConfig.getFilter("slugify")
|
||||
slugify: eleventyConfig.getFilter("slugify"),
|
||||
});
|
||||
mdLib.use(markdownItAbbr);
|
||||
mdLib.use(markdownItKatex.default);
|
||||
});
|
||||
|
||||
eleventyConfig.addShortcode("currentBuildDate", () => {
|
||||
return (new Date()).toISOString();
|
||||
})
|
||||
return new Date().toISOString();
|
||||
});
|
||||
|
||||
eleventyConfig.addShortcode("includeRaw", async (file) => fs.readFile(file, "utf8"));
|
||||
eleventyConfig.addShortcode("includeRaw", async (file) =>
|
||||
fs.readFile(file, "utf8"),
|
||||
);
|
||||
|
||||
//eleventyConfig.addPairedShortcode("section", async (content, transition = "none") => {
|
||||
// return `<section data-transition=${transition}> ${mdIt.renderInline(content)} </section>`;
|
||||
//})
|
||||
//
|
||||
eleventyConfig.addPairedShortcode("callout", function(content) {
|
||||
eleventyConfig.addPairedShortcode("callout", function (content) {
|
||||
// The 'content' variable holds the text/HTML placed between
|
||||
// {% callout %} and {% endcallout %}
|
||||
// We wrap it with our div structure.
|
||||
|
@ -165,12 +165,7 @@ export default async function(eleventyConfig) {
|
|||
return {
|
||||
// Control which files Eleventy will process
|
||||
// e.g.: *.md, *.njk, *.html, *.liquid
|
||||
templateFormats: [
|
||||
"md",
|
||||
"njk",
|
||||
"html",
|
||||
"liquid",
|
||||
],
|
||||
templateFormats: ["md", "njk", "html", "liquid"],
|
||||
|
||||
// Pre-process *.md files with: (default: `liquid`)
|
||||
markdownTemplateEngine: "njk",
|
||||
|
@ -183,7 +178,7 @@ export default async function(eleventyConfig) {
|
|||
input: "content", // default: "."
|
||||
includes: "../_includes", // default: "_includes"
|
||||
data: "../_data", // default: "_data"
|
||||
output: "_site"
|
||||
output: "_site",
|
||||
},
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
@ -198,4 +193,4 @@ export default async function(eleventyConfig) {
|
|||
// folder name and does **not** affect where things go in the output folder.
|
||||
pathPrefix: "/",
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
31
flake.nix
31
flake.nix
|
@ -6,29 +6,42 @@
|
|||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, deploy-rs, systems, treefmt-nix }: let
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
deploy-rs,
|
||||
systems,
|
||||
treefmt-nix,
|
||||
}:
|
||||
let
|
||||
# systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
|
||||
forAllSystems = fn:
|
||||
nixpkgs.lib.genAttrs (import systems) (system: fn nixpkgs.legacyPackages.${system});
|
||||
forAllSystems =
|
||||
fn: nixpkgs.lib.genAttrs (import systems) (system: fn nixpkgs.legacyPackages.${system});
|
||||
|
||||
treefmtEval = forAllSystems (pkgs: treefmt-nix.lib.evalModule pkgs ./treefmt.nix);
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
apps = forAllSystems (pkgs: {
|
||||
"deploy" = {
|
||||
type = "app";
|
||||
program = let
|
||||
ci = (pkgs.writeShellApplication {
|
||||
program =
|
||||
let
|
||||
ci = (
|
||||
pkgs.writeShellApplication {
|
||||
name = "ci.sh";
|
||||
text = ''
|
||||
nix build
|
||||
'';
|
||||
});
|
||||
in "${ci}/ci.sh";
|
||||
}
|
||||
);
|
||||
in
|
||||
"${ci}/ci.sh";
|
||||
};
|
||||
});
|
||||
packages = forAllSystems (pkgs: {
|
||||
default = pkgs.callPackage ./package.nix {};
|
||||
default = pkgs.callPackage ./package.nix { };
|
||||
});
|
||||
deploy.nodes.myblog = {
|
||||
hostname = "saji.dev";
|
||||
|
|
|
@ -7,36 +7,40 @@ export default function figcaptionPlugin(md) {
|
|||
for (let i = 0; i < tokens.length; i++) {
|
||||
// Check for paragraph containing only an image
|
||||
if (
|
||||
tokens[i].type === 'paragraph_open' &&
|
||||
tokens[i].type === "paragraph_open" &&
|
||||
i + 2 < tokens.length &&
|
||||
tokens[i + 1].type === 'inline' &&
|
||||
tokens[i + 1].type === "inline" &&
|
||||
tokens[i + 1].children &&
|
||||
tokens[i + 1].children.length === 1 &&
|
||||
tokens[i + 1].children[0].type === 'image' &&
|
||||
tokens[i + 2].type === 'paragraph_close'
|
||||
tokens[i + 1].children[0].type === "image" &&
|
||||
tokens[i + 2].type === "paragraph_close"
|
||||
) {
|
||||
// Check if the next token is a paragraph starting with emphasis
|
||||
if (
|
||||
i + 5 < tokens.length &&
|
||||
tokens[i + 3].type === 'paragraph_open' &&
|
||||
tokens[i + 4].type === 'inline' &&
|
||||
tokens[i + 3].type === "paragraph_open" &&
|
||||
tokens[i + 4].type === "inline" &&
|
||||
tokens[i + 4].children &&
|
||||
tokens[i + 4].children.length > 0 &&
|
||||
tokens[i + 4].children[0].type === 'em_open' &&
|
||||
tokens[i + 5].type === 'paragraph_close'
|
||||
tokens[i + 4].children[0].type === "em_open" &&
|
||||
tokens[i + 5].type === "paragraph_close"
|
||||
) {
|
||||
figcaptionStartIndex = i + 3; // Start index of the caption paragraph
|
||||
|
||||
// --- Replace tokens ---
|
||||
|
||||
// 1. Change paragraph_open to figure_open
|
||||
const figureOpen = new state.Token('figure_open', 'figure', 1);
|
||||
const figureOpen = new state.Token("figure_open", "figure", 1);
|
||||
tokens[i] = figureOpen; // Replace paragraph_open
|
||||
|
||||
// 2. Keep the inline token with the image as is (tokens[i+1])
|
||||
|
||||
// 3. Change paragraph_close to figcaption_open
|
||||
const figcaptionOpen = new state.Token('figcaption_open', 'figcaption', 1);
|
||||
const figcaptionOpen = new state.Token(
|
||||
"figcaption_open",
|
||||
"figcaption",
|
||||
1,
|
||||
);
|
||||
tokens[i + 2] = figcaptionOpen; // Replace paragraph_close
|
||||
|
||||
// 4. Remove the caption's paragraph_open
|
||||
|
@ -45,23 +49,29 @@ export default function figcaptionPlugin(md) {
|
|||
// 5. Modify the caption's inline content: remove outer <em> tags
|
||||
const captionInlineToken = tokens[figcaptionStartIndex]; // Now at index i+3 after splice
|
||||
if (
|
||||
captionInlineToken.children[0].type === 'em_open' &&
|
||||
captionInlineToken.children[captionInlineToken.children.length - 1].type === 'em_close'
|
||||
captionInlineToken.children[0].type === "em_open" &&
|
||||
captionInlineToken.children[captionInlineToken.children.length - 1]
|
||||
.type === "em_close"
|
||||
) {
|
||||
captionInlineToken.children.shift(); // Remove em_open
|
||||
captionInlineToken.children.pop(); // Remove em_close
|
||||
}
|
||||
// Adjust level for caption content
|
||||
captionInlineToken.level += 1;
|
||||
captionInlineToken.children.forEach(child => { child.level += 1; });
|
||||
|
||||
captionInlineToken.children.forEach((child) => {
|
||||
child.level += 1;
|
||||
});
|
||||
|
||||
// 6. Change the caption's paragraph_close to figcaption_close
|
||||
const figcaptionClose = new state.Token('figcaption_close', 'figcaption', -1);
|
||||
const figcaptionClose = new state.Token(
|
||||
"figcaption_close",
|
||||
"figcaption",
|
||||
-1,
|
||||
);
|
||||
tokens[figcaptionStartIndex + 1] = figcaptionClose; // Replace paragraph_close (now at i+4)
|
||||
|
||||
// 7. Add figure_close after figcaption_close
|
||||
const figureClose = new state.Token('figure_close', 'figure', -1);
|
||||
const figureClose = new state.Token("figure_close", "figure", -1);
|
||||
tokens.splice(figcaptionStartIndex + 2, 0, figureClose); // Insert figure_close (at i+5)
|
||||
|
||||
// Adjust token index to skip the newly inserted/modified tokens
|
||||
|
@ -71,13 +81,27 @@ export default function figcaptionPlugin(md) {
|
|||
}
|
||||
}
|
||||
|
||||
md.core.ruler.after('inline', 'figcaption', figcaptionRule);
|
||||
md.core.ruler.after("inline", "figcaption", figcaptionRule);
|
||||
|
||||
// Add renderer rules if they don't exist
|
||||
md.renderer.rules.figure_open = md.renderer.rules.figure_open || function () { return '<figure>\n'; };
|
||||
md.renderer.rules.figure_close = md.renderer.rules.figure_close || function () { return '</figure>\n'; };
|
||||
md.renderer.rules.figcaption_open = md.renderer.rules.figcaption_open || function () { return '<figcaption>'; };
|
||||
md.renderer.rules.figcaption_close = md.renderer.rules.figcaption_close || function () { return '</figcaption>\n'; };
|
||||
md.renderer.rules.figure_open =
|
||||
md.renderer.rules.figure_open ||
|
||||
function () {
|
||||
return "<figure>\n";
|
||||
};
|
||||
md.renderer.rules.figure_close =
|
||||
md.renderer.rules.figure_close ||
|
||||
function () {
|
||||
return "</figure>\n";
|
||||
};
|
||||
md.renderer.rules.figcaption_open =
|
||||
md.renderer.rules.figcaption_open ||
|
||||
function () {
|
||||
return "<figcaption>";
|
||||
};
|
||||
md.renderer.rules.figcaption_close =
|
||||
md.renderer.rules.figcaption_close ||
|
||||
function () {
|
||||
return "</figcaption>\n";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
const HSEP = "---";
|
||||
const VSEP = "===";
|
||||
|
||||
|
||||
/**
|
||||
* MarkdownIt plugin to generate revealjs friendly markup.
|
||||
*
|
||||
|
@ -29,12 +28,12 @@ export default function revealjs_plugin(md, options) {
|
|||
function renderOpening(tokens, idx, options, env, slf) {
|
||||
var token = tokens[idx];
|
||||
return `<${tokens[idx].tag}${slf.renderAttrs(tokens[idx])}>`;
|
||||
};
|
||||
}
|
||||
|
||||
function renderClosing(tokens, idx, options, env, slf) {
|
||||
var token = tokens[idx];
|
||||
return `</${tokens[idx].tag}>`;
|
||||
};
|
||||
}
|
||||
|
||||
md.renderer.rules.pres_open = renderOpening;
|
||||
md.renderer.rules.pres_close = renderClosing;
|
||||
|
@ -64,9 +63,7 @@ export default function revealjs_plugin(md, options) {
|
|||
function presentationOpen(state) {
|
||||
var token = new state.Token("pres_open", "section", 1);
|
||||
token.block = true;
|
||||
token.attrs = [
|
||||
["class", "reveal"]
|
||||
];
|
||||
token.attrs = [["class", "reveal"]];
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -77,9 +74,7 @@ export default function revealjs_plugin(md, options) {
|
|||
function slidesOpen(state) {
|
||||
var token = new state.Token("slides_open", "div", 1);
|
||||
token.block = true;
|
||||
token.attrs = [
|
||||
["class", "slides"]
|
||||
];
|
||||
token.attrs = [["class", "slides"]];
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -97,7 +92,7 @@ export default function revealjs_plugin(md, options) {
|
|||
return new state.Token("slide_close", "section", -1);
|
||||
}
|
||||
|
||||
md.core.ruler.push("revealjs", function(state) {
|
||||
md.core.ruler.push("revealjs", function (state) {
|
||||
let divIdx = 0;
|
||||
while (true) {
|
||||
divIdx = nextDivider(state.tokens, divIdx);
|
||||
|
@ -123,9 +118,11 @@ export default function revealjs_plugin(md, options) {
|
|||
// in it's own section
|
||||
if (openSlides === 1) {
|
||||
let slideOpenIdx = previousSlideOpen(state.tokens, divIdx);
|
||||
state.tokens.splice(slideOpenIdx, 1,
|
||||
state.tokens.splice(
|
||||
slideOpenIdx,
|
||||
1,
|
||||
state.tokens[slideOpenIdx], // reuse it to avoid increasing openSlides
|
||||
slideOpen(state)
|
||||
slideOpen(state),
|
||||
);
|
||||
divIdx++; // we added a token before the divider, we need to update divIdx
|
||||
}
|
||||
|
@ -152,4 +149,4 @@ export default function revealjs_plugin(md, options) {
|
|||
state.tokens.push(slidesClose(state));
|
||||
state.tokens.push(presentationClose(state));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
importNpmLock,
|
||||
vips,
|
||||
lib,
|
||||
}: buildNpmPackage {
|
||||
}:
|
||||
buildNpmPackage {
|
||||
name = "myblog";
|
||||
version = "unstable";
|
||||
buildInputs = [
|
||||
|
|
|
@ -1,46 +1,51 @@
|
|||
@font-face {
|
||||
font-family: 'WO3';
|
||||
src: url('/fonts/WO3.woff2') format('woff2'),
|
||||
url('/fonts/WO3.ttf') format('ttf');
|
||||
font-family: "WO3";
|
||||
src:
|
||||
url("/fonts/WO3.woff2") format("woff2"),
|
||||
url("/fonts/WO3.ttf") format("ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "wip3out";
|
||||
src: url('/fonts/wip3out.woff2') format('woff2'),
|
||||
url('/fonts/wip3out.ttf') format('ttf');
|
||||
src:
|
||||
url("/fonts/wip3out.woff2") format("woff2"),
|
||||
url("/fonts/wip3out.ttf") format("ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-stretch: semi-expanded;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'SometypeMono';
|
||||
src: url('/fonts/SometypeMono-Regular.woff2') format('woff2'),
|
||||
url('/fonts/SometypeMono-Regular.ttf') format('ttf') ;
|
||||
font-family: "SometypeMono";
|
||||
src:
|
||||
url("/fonts/SometypeMono-Regular.woff2") format("woff2"),
|
||||
url("/fonts/SometypeMono-Regular.ttf") format("ttf");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'SometypeMono';
|
||||
src: url('/fonts/SometypeMono-Bold.woff2') format('woff2'),
|
||||
url('/fonts/SometypeMono-Bold.ttf') format('ttf') ;
|
||||
font-family: "SometypeMono";
|
||||
src:
|
||||
url("/fonts/SometypeMono-Bold.woff2") format("woff2"),
|
||||
url("/fonts/SometypeMono-Bold.ttf") format("ttf");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'SometypeMono';
|
||||
src: url('/fonts/SometypeMono-Medium.woff2') format('woff2'),
|
||||
url('/fonts/SometypeMono-Medium.ttf') format('ttf') ;
|
||||
font-family: "SometypeMono";
|
||||
src:
|
||||
url("/fonts/SometypeMono-Medium.woff2") format("woff2"),
|
||||
url("/fonts/SometypeMono-Medium.ttf") format("ttf");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Orbitron";
|
||||
src: url('/fonts/Orbitron-VariableFont_wght.woff2') format('woff2');
|
||||
src: url("/fonts/Orbitron-VariableFont_wght.woff2") format("woff2");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
/* Theme colors */
|
||||
:root {
|
||||
|
||||
|
||||
--text-color-link: var(--color-cyan);
|
||||
--text-color-link-active: var(--color-cyan-bright);
|
||||
--text-color-link-visited: var(--color-cyan);
|
||||
|
@ -18,7 +16,6 @@
|
|||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
|
||||
/* --text-color is assigned to --color-gray-_ above */
|
||||
/* --text-color-link: #1493fb; */
|
||||
/* --text-color-link-active: #6969f7; */
|
||||
|
@ -26,11 +23,9 @@
|
|||
--text-color-link: var(--color-cyan);
|
||||
--text-color-link-active: var(--color-cyan-bright);
|
||||
--text-color-link-visited: var(--color-cyan);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* list style custom */
|
||||
|
||||
ul {
|
||||
|
@ -130,7 +125,7 @@ code {
|
|||
font-family: var(--font-family-monospace);
|
||||
}
|
||||
pre:not([class*="language-"]) {
|
||||
margin: .5em 0;
|
||||
margin: 0.5em 0;
|
||||
line-height: 1.375; /* 22px /16 */
|
||||
-moz-tab-size: var(--syntax-tab-size);
|
||||
-o-tab-size: var(--syntax-tab-size);
|
||||
|
@ -154,7 +149,7 @@ code {
|
|||
/* Header */
|
||||
header {
|
||||
display: flex;
|
||||
gap: 1em .5em;
|
||||
gap: 1em 0.5em;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
padding: 1em;
|
||||
|
@ -219,8 +214,8 @@ header {
|
|||
font-size: 1.1875em; /* 19px /16 */
|
||||
font-weight: 700;
|
||||
flex-basis: calc(100% - 1.5rem);
|
||||
padding-left: .25em;
|
||||
padding-right: .5em;
|
||||
padding-left: 0.25em;
|
||||
padding-right: 0.5em;
|
||||
text-underline-position: from-font;
|
||||
text-underline-offset: 0;
|
||||
text-decoration-thickness: 1px;
|
||||
|
@ -245,7 +240,7 @@ header {
|
|||
.post-metadata {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5em;
|
||||
gap: 0.5em;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -259,7 +254,7 @@ header {
|
|||
text-decoration: none;
|
||||
font-style: normal;
|
||||
font-size: 1em;
|
||||
margin-left: .1em;
|
||||
margin-left: 0.1em;
|
||||
}
|
||||
a[href].header-anchor,
|
||||
a[href].header-anchor:visited {
|
||||
|
@ -277,12 +272,13 @@ a[href].header-anchor:focus,
|
|||
h2 + .header-anchor {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
font-family: WO3;
|
||||
letter-spacing: .1rem;
|
||||
letter-spacing: 0.1rem;
|
||||
}
|
||||
|
||||
|
||||
/* blockquote styling */
|
||||
|
||||
blockquote {
|
||||
|
@ -299,7 +295,7 @@ blockquote p {
|
|||
|
||||
/* Top-left corner bracket */
|
||||
blockquote::before {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0.5em; /* Adjust position */
|
||||
left: 0.5em; /* Adjust position */
|
||||
|
@ -312,7 +308,7 @@ blockquote::before {
|
|||
|
||||
/* Bottom-right corner bracket */
|
||||
blockquote::after {
|
||||
content: '';
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0.5em; /* Adjust position */
|
||||
right: 0.5em; /* Adjust position */
|
||||
|
@ -322,4 +318,3 @@ blockquote::after {
|
|||
border-right: 3px solid var(--color-white); /* White border, adjust thickness */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ pre[class*="language-diff-"] {
|
|||
.token.prefix.inserted,
|
||||
.token.prefix.deleted {
|
||||
width: var(--eleventy-code-padding);
|
||||
background-color: rgba(0,0,0,.2);
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Optional: full-width background color */
|
||||
|
|
Loading…
Reference in a new issue