mirror of
https://github.com/RGBCube/Site
synced 2025-08-01 13:37:49 +00:00
Compare commits
9 commits
156ccda761
...
0acf135cc5
Author | SHA1 | Date | |
---|---|---|---|
0acf135cc5 | |||
8bbaad2e1c | |||
67d5fa028e | |||
5180fc70bd | |||
1a4c99f355 | |||
73115d08d2 | |||
a2f3fc2e5c | |||
350ecd5e97 | |||
5a30d40a3e |
5 changed files with 241 additions and 24 deletions
21
_config.ts
21
_config.ts
|
@ -23,12 +23,24 @@ site.process([".html"], (pages) => {
|
|||
document.querySelectorAll("table").forEach((table) => {
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("room", "rotated");
|
||||
table.classList.add("rotated");
|
||||
div.classList.add("overflow", "rotated");
|
||||
|
||||
table.parentNode!.insertBefore(div, table);
|
||||
div.appendChild(table);
|
||||
});
|
||||
|
||||
document.querySelectorAll(".hljs").forEach((code) => {
|
||||
const pre = code.parentElement!;
|
||||
const div = document.createElement("div");
|
||||
|
||||
code.classList.add("rotated");
|
||||
pre.classList.add("rotated");
|
||||
div.classList.add("overflow", "rotated");
|
||||
|
||||
pre.parentNode?.insertBefore(div, pre);
|
||||
div.appendChild(pre);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -36,21 +48,20 @@ site.use(feed({
|
|||
output: ["/blog.rss"],
|
||||
|
||||
query: "type=article",
|
||||
sort: "date=desc",
|
||||
sort: "date=asc",
|
||||
limit: Infinity,
|
||||
|
||||
info: {
|
||||
title: "RGBCube's Blog",
|
||||
description:
|
||||
"The blog where RGBCube dumps his schizophrenic ramblings about software and all the likes.",
|
||||
lang: "en",
|
||||
generator: false,
|
||||
},
|
||||
items: {
|
||||
title: "=title",
|
||||
description: "=description",
|
||||
published: "=date",
|
||||
content: "$ content",
|
||||
lang: "en",
|
||||
content: "$.content",
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
layout: text.vto
|
||||
---
|
||||
|
||||
{{ content }}
|
||||
<div class="content">{{ content }}</div>
|
||||
|
||||
{{ if tags.length !== 0 }}
|
||||
<p>Tags: {{ tags.join(", ") }}</p>
|
||||
|
|
|
@ -3,12 +3,21 @@ layout: base.vto
|
|||
---
|
||||
|
||||
<style>
|
||||
/* Centering */
|
||||
html,
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.centered {
|
||||
font-size: large;
|
||||
|
||||
display: initial;
|
||||
width: min(100vw - 2rem, 50rem);
|
||||
}
|
||||
|
||||
/* Make wrapping pretty */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
|
@ -20,21 +29,17 @@ layout: base.vto
|
|||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
.centered {
|
||||
font-size: large;
|
||||
|
||||
display: initial;
|
||||
width: min(100vw - 2rem, 50rem);
|
||||
}
|
||||
|
||||
/* Rotate nav, tables and codeblocks so the scrollbar is at the top */
|
||||
.rotated {
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow-wrap: break-word;
|
||||
/* Make tables and other elements scroll horizontally */
|
||||
.overflow {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* Style nav */
|
||||
nav {
|
||||
font-size: larger;
|
||||
word-break: normal;
|
||||
|
@ -63,6 +68,11 @@ layout: base.vto
|
|||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
/* Style content */
|
||||
.content {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link);
|
||||
}
|
||||
|
@ -71,10 +81,27 @@ layout: base.vto
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.room {
|
||||
overflow-x: auto;
|
||||
blockquote {
|
||||
border-left: 0.15rem solid var(--foreground);
|
||||
padding-top: 0.01rem;
|
||||
padding-bottom: 0.01rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
blockquote {
|
||||
background-color: #222;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
blockquote {
|
||||
background-color: #EEE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Style tables */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
white-space: nowrap;
|
||||
|
@ -87,8 +114,8 @@ layout: base.vto
|
|||
} */
|
||||
|
||||
th, td {
|
||||
border: 0.15em solid var(--foreground);
|
||||
padding: 0.3em;
|
||||
border: 0.15rem solid var(--foreground);
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
th {
|
||||
|
@ -96,9 +123,42 @@ layout: base.vto
|
|||
color: var(--background);
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 0.15rem solid var(--foreground);
|
||||
/* Codeblocks */
|
||||
.rotated:has(pre) {
|
||||
padding: 0.6rem;
|
||||
border: 0.15rem solid var(--foreground);
|
||||
}
|
||||
|
||||
pre:has(code) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.hljs-attr { color: lightblue; }
|
||||
.hljs-built_in { color: firebrick; }
|
||||
.hljs-keyword { color: firebrick; }
|
||||
.hljs-number { color: mediumslateblue; }
|
||||
.hljs-string { color: limegreen; }
|
||||
.hljs-title { color: lightcoral; }
|
||||
.hljs-type { color: aquamarine; }
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
.hljs-attr { color: darkblue; }
|
||||
.hljs-built_in { color: darkred; }
|
||||
.hljs-keyword { color: darkred; }
|
||||
.hljs-number { color: darkslateblue; }
|
||||
.hljs-string { color: darkgreen; }
|
||||
.hljs-title { color: darkgoldenrod; }
|
||||
.hljs-type { color: darkcyan; }
|
||||
}
|
||||
|
||||
/* The end */
|
||||
hr {
|
||||
border: 0.15rem solid var(--foreground);
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
|
@ -119,7 +179,8 @@ layout: base.vto
|
|||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="content">{{ content }}</div>
|
||||
{{ content }}
|
||||
|
||||
<footer>Copyright © RGBCube</footer>
|
||||
<hr>
|
||||
<footer>Copyright {{ new Date().getFullYear() }} © RGBCube</footer>
|
||||
</div>
|
||||
|
|
|
@ -10,7 +10,7 @@ Are you old? Then you might want to check out my super cool
|
|||
<a href="/blog.rss">RSS Feed</a> too!
|
||||
|
||||
<ul>
|
||||
{{ for article of search.pages("type=article", "date")}}
|
||||
{{ for article of search.pages("type=article", "order=asc title=date")}}
|
||||
<li>
|
||||
<p>
|
||||
<a href="{{ article.url }}">{{ article.date.toISOString().slice(0, 10) }}</a>:
|
||||
|
|
145
site/blog/htmnix.md
Normal file
145
site/blog/htmnix.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
title: HTMNIX
|
||||
description: How the absolutely cursed HTMNIX project works.
|
||||
|
||||
date: 2024-03-04
|
||||
|
||||
tags:
|
||||
- html
|
||||
- nix
|
||||
---
|
||||
|
||||
So, you may have seen the [HTMNIX](https://github.com/RGBCube/HTMNIX) project I've
|
||||
been working on the last few weeks. If not, no worries. Here is a Nix snippet
|
||||
that uses it:
|
||||
|
||||
```nix
|
||||
<html>
|
||||
<head>
|
||||
<title>"Hello, Internet!"<.title>
|
||||
<.head>
|
||||
<body>
|
||||
<p>"Yep, this is 100% Nix!"<.p>
|
||||
|
||||
<img.>{src="/foo.png"; alt="Attributes also work!";}
|
||||
<.body>
|
||||
<.html>
|
||||
```
|
||||
|
||||
> (hightlight.js shits the bed while highlighting this abomination - just ignore it)
|
||||
|
||||
You are probably thinking furiously right now, maybe you've noticed something:
|
||||
|
||||
> Aha! In Nix, `<foo>` is used to find stuff from the Nix path like so:
|
||||
>
|
||||
> ```nix
|
||||
> import <nixpkgs> {}
|
||||
> ```
|
||||
>
|
||||
> That means you have to add hundreds of elements to your Nix Path to make this work?
|
||||
|
||||
You are somewhat correct. But not quite.
|
||||
|
||||
Nix `<foo>` expressions actually boil down to a call of the builtin `__findFile`, like so:
|
||||
|
||||
```sh
|
||||
❯ nix-instantiate --parse --expr "<foo>"
|
||||
|
||||
(__findFile __nixPath "foo")
|
||||
```
|
||||
|
||||
> In case you didn't know, [`nix-instantiate`](https://nixos.org/manual/nix/stable/command-ref/nix-instantiate.html)
|
||||
> is a nice tool to see what your Nix code is desugared and un-precedence'd into.
|
||||
|
||||
Aha! So this means we can override the builtin `__findFile` and put whatever we would like in
|
||||
its place. So this will work:
|
||||
|
||||
```nix
|
||||
let
|
||||
__findFile = nixPath: name: {
|
||||
content = "<${name}>";
|
||||
};
|
||||
in
|
||||
<foo>
|
||||
```
|
||||
|
||||
Evaluating this (by running `nix eval -f test.nix`), we get `{ content = "<foo>"; }`
|
||||
|
||||
So, then. How do we make it work for multiple tags, all coming after one another
|
||||
(and attribute sets, strings, etc.)?
|
||||
|
||||
Another hack! We need to set the [magic `__functor` attribute](https://noogle.dev/md/tutorials/functors)
|
||||
of the attrset we return, so we can call our set and have it store the tags inside it (while also
|
||||
preserving its callability!).
|
||||
|
||||
We can do that like so:
|
||||
|
||||
```nix
|
||||
let
|
||||
__findFile = nixPath: name: {
|
||||
content = "<${name}>";
|
||||
__functor = self: next: self // {
|
||||
content = self.content + next;
|
||||
};
|
||||
};
|
||||
in
|
||||
<foo>
|
||||
"bar"
|
||||
"baz"
|
||||
```
|
||||
|
||||
Great news! When we evaluate this, we get `{ __functor = <LAMBDA>; content = "<foo>barbaz"; }`.
|
||||
|
||||
We can also add a case to check if the next element is a tag, and use its content if it is:
|
||||
|
||||
```nix
|
||||
let
|
||||
__findFile = nixPath: name: {
|
||||
content = "<${name}>";
|
||||
__functor = self: next: self // {
|
||||
content = self.content + (if next ? content then next.content else next);
|
||||
};
|
||||
};
|
||||
in
|
||||
<foo>
|
||||
"bar"
|
||||
"baz"
|
||||
<endfoo>
|
||||
```
|
||||
|
||||
Enter another hack! We can utilize the `outPath` property that exists on derivations
|
||||
and gets returned whenever you call `toString` with an attrset that has the property to make our code a little simpler:
|
||||
|
||||
```nix
|
||||
let
|
||||
__findFile = nixPath: name: {
|
||||
outPath = "<${name}>";
|
||||
__functor = self: next: self // {
|
||||
outPath = self.outPath + toString next;
|
||||
};
|
||||
};
|
||||
in
|
||||
<foo>
|
||||
"bar"
|
||||
"baz"
|
||||
123
|
||||
<endfoo>
|
||||
```
|
||||
|
||||
We also got support for other types for free, as well!
|
||||
|
||||
These are all the hidden builtins that [HTMNIX](https://github.com/RGBCube/HTMNIX) depends on
|
||||
and extends upon, making HTML in Nix an actually usable reality. It also
|
||||
has extra logic like turning attribute sets into HTML tags, which is fairly trivial
|
||||
compared to actaully discovering these hidden builtins in the first place.
|
||||
|
||||
You can read more about it in the project's README and
|
||||
see [an example site using it](https://github.com/RGBCube/NixSite).
|
||||
|
||||
I might even try to port this site to HTMNIX to ensure it is usable with more complex setups :-)
|
||||
|
||||
Soon, maybe...
|
||||
|
||||
---
|
||||
|
||||
Thanks for reading my first ever proper blog post! :-)
|
Loading…
Add table
Add a link
Reference in a new issue