website: initial ooknet website commit

This commit is contained in:
ooks-io 2024-10-31 17:27:08 +11:00
parent 97be7a19c6
commit a9280b78cd
55 changed files with 2424 additions and 2 deletions

View file

@ -14,7 +14,7 @@ in {
description = "The server profile the host will use as a base";
};
services = mkOption {
type = listOf (enum []);
type = listOf (enum ["website"]);
default = [];
description = "List of services the server will host";
};

View file

@ -1,2 +1,5 @@
{
imports = [
./website
];
}

View file

@ -0,0 +1,73 @@
{
lib,
config,
self',
...
}: let
inherit (lib) mkIf elem;
inherit (config.ooknet.server) services;
inherit (self'.packages) website;
in {
config = mkIf (elem "website" services) {
users.groups.www = {};
systemd.tmpfiles.rules = [
"d /var/www 0775 caddy www"
"d /var/www/ooknet.org 0775 caddy www"
];
# cursed activation script
# need to find a better way
system.activationScripts.copyWebsite = {
text =
# sh
''
# clean-up
rm -rf /var/www/ooknet.org/*
# ensure dir exists
mkdir -p /var/www/ooknet.org
# copy files from pkg
cp -r ${website}/* /var/www/ooknet.org/
# set permissions
chown -R caddy:www /var/www/ooknet.org
chmod -R 775 /var/www/ooknet.org
'';
deps = ["users" "groups"];
};
# using caddy because it makes my life easy
services.caddy = {
enable = true;
group = "www";
virtualHosts = {
"ooknet.org".extraConfig =
# sh
''
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000;"
X-XSS-Protection "1; mode=block"
X-Frame-Options "DENY"
X-Content-Type-Options "nosniff"
-Server
Referrer-Policy: no-referrer
}
root * /var/www/ooknet.org/
file_server
'';
"www.ooknet.org".extraConfig = ''
redir https://ooknet.org{uri}
'';
};
};
};
}

View file

@ -12,7 +12,7 @@ in {
hostname = "ooknode";
type = "vm";
profile = "linode";
services = [];
services = ["website"];
};
};
}

View file

@ -8,6 +8,7 @@
repopack = callPackage ./repopack {};
live-buds-cli = callPackage ./live-buds-cli {};
instawow-tsm = callPackage ./instawow/plugins/tsm.nix {};
website = callPackage ./website {};
ook-vim = mkNeovim pkgs [ook-vim-config];
};

View file

@ -0,0 +1,13 @@
{
stdenvNoCC,
zola,
}:
stdenvNoCC.mkDerivation {
pname = "ooknet.org";
version = "0.1.0";
src = ./src;
nativeBuildInputs = [zola];
buildPhase = "zola build -o $out";
dontInstall = true;
}

View file

@ -0,0 +1,19 @@
# The URL the site will be built for
base_url = "/"
# Whether to automatically compile all Sass files in the sass directory
compile_sass = true
# Whether to build a search index to be used later on by a JavaScript library
build_search_index = true
# theme = "library"
[markdown]
# Whether to do syntax highlighting
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
highlight_code = true
highlight_theme = "css"
[extra]
# Put all your custom variables here

View file

@ -0,0 +1,7 @@
+++
title = "ooknet"
description = "ooknet is a personal website, a monorepo, a place to store my notes; all powered by nix."
template = "home.html"
+++
# Still very much under construction

View file

@ -0,0 +1,6 @@
+++
title = "notes library"
template = "notebook/notebook-home.html"
+++
## Notes collection

View file

@ -0,0 +1,7 @@
+++
title = "Nix"
insert_anchor_links= "right"
+++
## Welcome to my nix notebook

View file

@ -0,0 +1,240 @@
+++
title = "Syntax"
+++
## Resources
---
- [redhat documentation](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/security_guide/chap-system_auditing)
- [arch-wiki](https://wiki.archlinux.org/title/Audit_framework)
- [linux-audit 101](https://linux-audit.com/linux-audit-framework-101-basic-rules-for-configuration/)
- [linux-audit configuration](https://linux-audit.com/configuring-and-auditing-linux-systems-with-audit-daemon)
- [man page](https://linux.die.net/man/7/audit.rules)
## Overview
---
The linux audit framework is a collection of tools used to log events the administrator deems important; typically used to collect security-relevant information. It is not a form of protection against attacks, but simply a means of logging information to analyze after the fact.
Linux audit framework can be used in larger security pipelines, feeding information to scripts and dashboards to catch any potential weaknesses in a systems security.
It does this by listening to events reported by the kernel and logging them in a file.
> [!tip]
> The log file is typically found here: `/var/log/auditd.log`.
Linux audit framework is broken down into a few parts:
1. **Audit kernel module** - included in _most_ linux kernels (some custom kernels may require additional steps to include).
2. **Auditd** - A configurable daemon responsible for writing messages to the log file. Configuration is done in the `/etc/audit/auditd.conf` file.
3. **Command-line tools** - various command line tools to interface with the audit system. examples:
- `auditctl`: Interacting with the daemons configuration on the fly.
- `ausearch`: Searching for specific events.
- `aureport`: Generating reports.
- `autrace`: Tracing processes.
- There are many more tools that can be used to interact with the audit system.
4. **Audit rules** - A collection of `auditctl` command that are run at system boot time. Configured in the file: `/etc/audit/audit.rules`.
## Installation
---
Although the kernel module is likely included with your distribution; you may need to install the relevant packages to interface with it. For this example I will be showing how to enable the linux audit system on NixOS.
`nixpkgs` includes a module that be used to enable the linux audit system:
```nix
# configuration.nix
{
security.audit = {
enable = true;
};
}
```
You will also want to enable the audit daemon:
```nix
# configuration.nix
{
security = {
audit = {
enable = true;
};
auditd.enable = true;
};
}
```
Sources for these modules:
- [nixpkgs/audit.nix](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/audit.nix)
- [nixpkgs/auditd.nix](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/auditd.nix)
> [!info]
> Use the kernel parameter `audit=1` to allow the audit system to audit processes that are run before the audit daemon starts.
>
> This is set by default if you enable the NixOS module.
## Configuration
---
The `auditctl` command can be used to set and retrieve configuration settings, changes made this way are ephemeral and will removed when the system restarts.
For permanent changes, configuration is done in the `/etc/audit/auditd.conf` file. Configuration options are structured as such:
`{conf}keyword=value`
Example configuration option:
```conf
# /etc/audit/auditd.conf
# set the log file location
log_file=/var/log/auditd.log
```
In most cases you can leave the default configuration.
For a list of all available configuration options, refer to the [auditd.conf(5) man page](https://linux.die.net/man/5/auditd.conf).
## Rules
---
> [!warning]
> The output from the audit system can be _very_ verbose; filling up the log file very quickly. Make sure to test all rules before deployment.
The `auditctl` command can also be used for setting rules; these rules are definitions for what events we want to log & configuration for the kernel module itself. Configuring the audit system with the `auditctl` command is typically used for ad hoc changes, as these modifications are not automatically saved to a permanent configuration file. Changes made with `auditctl` are only active for the current session and will be lost upon system restart.
For persistent rules, we use the `/etc/audit/audit.rules` file or files in the `/etc/audit/rules.d/` directory.
Rules in auditd are broken up into 3 varieties:
- [Control](#control)
- [File System](#file-system)
- [System Calls](#system-calls)
### Control
---
These are commands that are used to configure the audit system (kernel module) directly.
For a full list of control rules see [auditctl(8) man page](https://linux.die.net/man/8/auditctl).
Some available _persistent_ options:
#### Failure mode
---
`-f`:
This is used for defining what _action_ to take when the a _critical error (failure mode)_ is detected. the available options are:
- `0` - silent.
- `1` - printk (print a failure message).
- `2` - panic (halt the system).
Example: `-f 1` print message when a critical error occurs.
#### Buffer Size
---
`-b`:
Set the maximum number of audit system buffers in the kernel.
Example: `-b 8192` Sets the maximum number of buffers to 8192, exceeding this number will trigger a _critical error_.
#### Enable flag
---
`-e`:
Set the enable flag. Available options:
- `0` - Disables auditing.
- `1` - Enables Auditing.
- `2` - Locks the configuration file preventing any further changes.
Example: `-e 2` Enables the auditing and locks the configuration file.
#### Rate
---
`-r`:
Set the message/sec limit, if set to `0`, disable rate limiting. If the rate is exceeded a _critical error_ will be triggered.
Example: `-r 60` sets the rate limit to 60 messages/sec.
#### Delete
---
`-D`:
Deletes all rules and watches.
### File System
---
Otherwise known as watches, the `-w` flag can be used to audit access to files and directories.
Example: `-w path/to/file -p permissions -k keyname`
#### Paths
---
Paths can either be a file or a directory. If a directory is defined, then the rule is used recursively down the directory tree excluding any directories that may be mount points. Keep this in mind as auditing a large tree may be resource intensive. Limiting the scope of your rules is key to optimizing performance.
#### Permissions
---
The `-p` option is for defining what permissions access type will trigger on. Available permissions:
- `r` - read of the file
- `w` - write to the file
- `x` - execute the file
- `a` - change in the file's attribute
These options can be combined e.g: `-p rw` or `-p rwa`.
#### Key
---
The `-k` option is used to set a string as an identifier (key) for the rule. This string is limited to 31 bytes long.
Typically used to group related rules to then be searched for with `ausearch`.
#### Example
---
```rules
# /etc/audit/auditd.rules
-w /etc/localtime -p wa -k system_changes
-w /etc/passwd -p x -k password_changes
-w /usr/bin/passwd -p x -k password_changes
```
In this example we set a few rules:
- `-w /etc/localtime -p wa -k system_changes` here we define a rule that tracks when the `localtime` file is either written to (`w`), or had an attribute changed (`a`). We then assign it the `system_changes` key as a unique identifier.
- `-w /etc/passwd -p x -k password_changes` & `-w /usr/bin/passwd -p x -k password_changes` here we are tracking when either of these files are executed (`x`), and assigning them both the `password_changes` key.
### System Calls
---
System call rules are for tracking kernel syscalls. It does this by loading rules into a matching engine that checks every syscall that all programs make on a system.
Example structure:
`-a action,list -S syscall -F field=value -k keyname`

View file

@ -0,0 +1,50 @@
+++
title = "Name-value Pairs"
+++
## References:
- https://nix.dev/tutorials/nix-language
## Overview
In [[Nix]], [[key-value-pair|key-value-pairs]] go by _name-value-pairs_.
## Structure
- **Key**: The key in [[Nix]] doesn't have to be a string.
- **Separator**: Values are assigned to a value with an equal sign (`=`).
- **Value**: Values can be any [[primitive-data-types|primitive data types]], [[functions]], or [[attribute-sets|attribute sets]], or [[lists]].
- **Delimiter**: name-value-pairs in a set are delimited by a semicolon (`;`)
_example structure_
```nix
{name}{separator}{value}{delimier}
name = "value";
```
```nix
{
a = "string";
b = 20;
c = true;
d = ./path/to;
e = ["list" 10 true];
f = {
name = "value";
attribute = true;
};
}
```
## Assigning names to values
Names can be assigned to values in a number of ways:
- [[attribute-sets|Attribute sets]] `{ ... }`
- [[let-bindings|Let bindings]] `let ... in`
- [[functions|Functions]] `:`
# [[primitive-data-types|Next: Primitive data types]]

View file

@ -0,0 +1,72 @@
+++
title = "Primitive Data Types"
+++
## References:
- https://nix.dev/manual/nix/2.18/language/values#list
- https://nix.dev/tutorials/nix-language
## Strings
[[strings|Single line strings]] are enclosed in quotes `" ... "`:
```nix
value = "string"
```
or multi-line with `'' ... ''`:
```nix
value = '' multi
line
string
''
```
## Numbers
**numbers|Integers**:
```nix
value = 1
```
**numbers|floating point numbers**:
```nix
value = 1.5
```
## Null
```nix
value = null
```
## Paths
**paths#Absolute paths|Absolute paths**:
```nix
value = /path/to
```
**paths#Relative Paths|Relative Paths**:
```nix
value = ./path
```
> [!warning] Paths in Nix cannot include trailing slashes `/`
```nix warn:1
value = ./path/
# result: error: path has a trailing slash
```
## Boolean
```nix
value = true # or false
```

View file

@ -0,0 +1,75 @@
$themes: (
dark: (
crust: hsl(0, 0%, 15.69%),
mantle: hsl(20, 3.09%, 19.02%),
base: hsl(24, 4.5%, 21.76%),
surface-0: hsl(22.5, 6.15%, 25.49%),
surface-1: hsl(21.82, 7.38%, 29.22%),
surface-2: hsl(25.71, 8.43%, 32.55%),
overlay-0: hsl(26.25, 8.25%, 38.04%),
overlay-1: hsl(30, 9.8%, 40%),
overlay-2: hsl(27.5, 10.71%, 43.92%),
subtext-0: hsl(30, 12.1%, 51.37%),
subtext-1: hsl(35, 17.14%, 58.82%),
text: hsl(38, 41.1%, 71.37%),
bright-text: hsl(48.46, 86.67%, 88.24%),
red: hsl(3.09, 76.4%, 65.1%),
dull-red: hsl(3, 56.18%, 65.1%),
bright-red: hsl(2.75, 85.62%, 70%),
orange: hsl(23.53, 76.12%, 60.59%),
dull-orange: hsl(24.11, 56%, 60.78%),
bright-orange: hsl(23.76, 86.13%, 66.08%),
gold: hsl(36.74, 62.32%, 59.41%),
dull-gold: hsl(37.24, 41.63%, 59.02%),
bright-gold: hsl(37.27, 71.74%, 63.92%),
green: hsl(69.63, 35.68%, 55.49%),
dull-green: hsl(71.35, 16.16%, 55.1%),
bright-green: hsl(70.21, 46.08%, 60%),
cyan: hsl(111.6, 25%, 60.78%),
dull-cyan: hsl(112.17, 11.56%, 60.98%),
bright-cyan: hsl(112.13, 35.26%, 66.08%),
blue: hsl(166.53, 23.22%, 58.63%),
dull-blue: hsl(162.86, 3.35%, 59.02%),
bright-blue: hsl(167, 32.61%, 63.92%),
purple: hsl(343.64, 46.67%, 67.65%),
dull-purple: hsl(343.64, 26.83%, 67.84%),
bright-purple: hsl(343.85, 56.52%, 72.94%),
),
light: (
//crust: hsl(46, 67%, 84%),
crust: hsl(40, 38%, 73%),
mantle: hsl(44, 60%, 82%),
base: hsl(43, 59%, 81%),
surface-0: hsl(42, 53%, 79%),
surface-1: hsl(41, 42%, 75%),
surface-2: hsl(40, 38%, 73%),
overlay-0: hsl(41, 29%, 66%),
overlay-1: hsl(43, 24%, 63%),
overlay-2: hsl(35, 17%, 59%),
subtext-0: hsl(30, 12%, 51%),
subtext-1: hsl(28, 11%, 44%),
text: hsl(22, 20%, 26%),
bright-text: hsl(22, 20%, 26%),
red: hsl(359, 65%, 42%),
dull-red: hsl(359, 54%, 40%),
bright-red: hsl(359, 68%, 47%),
orange: hsl(23, 93%, 38%),
dull-orange: hsl(23, 73%, 38%),
bright-orange: hsl(23, 88%, 43%),
gold: hsl(37, 86%, 38%),
dull-gold: hsl(37, 60%, 38%),
bright-gold: hsl(37, 91%, 45%),
green: hsl(63, 59%, 29%),
dull-green: hsl(63, 39%, 29%),
bright-green: hsl(63, 66%, 35%),
cyan: hsl(144, 26%, 38%),
dull-cyan: hsl(144, 10%, 38%),
bright-cyan: hsl(144, 36%, 45%),
blue: hsl(190, 52%, 31%),
dull-blue: hsl(190, 32%, 31%),
bright-blue: hsl(190, 62%, 36%),
purple: hsl(322, 30%, 44%),
dull-purple: hsl(322, 10%, 44%),
bright-purple: hsl(322, 35%, 54%),
),
);

View file

@ -0,0 +1,33 @@
$paragraph-margin-bottom: 1rem;
$border-solid: 1px solid var(--clr-text);
$border-light: 1px solid var(--clr-subtext-0);
$spacer: 1rem;
$horizontal-rule: 1px solid var(--clr-overlay-2);
$font-family-monospace: "Jetbrains Mono", system-ui, monospace;
$font-family-sans: "Geist Sans", "Geist", system-ui, sans-serif;
$font-family-title: "Geist Sans", "Geist", system-ui, sans-serif;
$font-family-header: "Geist Sans", "Geist", system-ui, sans-serif;
$font-family-base: $font-family-sans;
$font-family-code: $font-family-monospace;
$font-size-base: 1rem;
$font-size-small: $font-size-base * 0.875;
$font-size-medium: $font-size-base * 1.125;
$font-size-large: $font-size-base * 1.25;
$font-size-xl: $font-size-base * 2;
$font-weight-thin: 200;
$font-weight-regular: 400;
$font-weight-bold: 700;
$font-weight-bolder: 800;
$font-color-text: var(--clr-text);
$font-color-bright: var(--clr-bright-text);
$font-color-link: var(--clr-blue);
$font-color-link-hover: var(--clr-bright-blue);
$font-style-link-hover: underline;

View file

@ -0,0 +1,16 @@
@mixin min-screen($min-width: $body-width) {
@media screen and (min-width: $min-width) {
@content;
}
}
@mixin max-screen($max-width: $body-width) {
@media screen and (max-width: $max-width) {
@content;
}
}
$sidebar-width: 300px;
$navbar-height: 50px;
$solid-border: 1px solid var(--clr-text);

View file

@ -0,0 +1,3 @@
@forward "colors";
@forward "variables";
@forward "typography";

View file

@ -0,0 +1,78 @@
@use "../abstracts" as *;
body {
background-color: var(--clr-mantle);
color: $font-color-text;
font-family: $font-family-base;
font-size: $font-size-base;
font-weight: $font-weight-regular;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: $font-color-bright;
margin: $spacer * 2 0 0;
}
h1 {
font-size: $font-size-xl;
font-weight: $font-weight-bolder;
}
h2 {
font-size: $font-size-large;
}
h3 {
font-size: $font-size-medium;
}
h4 {
font-size: $font-size-small;
}
hr {
border: $horizontal-rule;
margin-bottom: $spacer;
}
p {
margin-bottom: $spacer;
}
ul {
margin: $spacer 0 0 $spacer;
list-style: square;
}
a {
color: $font-color-link;
&:hover {
color: $font-color-link-hover;
text-decoration: $font-style-link-hover;
}
}
table {
border-collapse: collapse;
border-color: $border-solid;
overflow-x: auto;
max-width: 100%;
display: block;
td {
padding: 3px 20px;
border: $border-solid;
}
thead {
th {
background-color: var(--clr-surface-1);
padding: 6px 13px;
font-weight: bold;
border: $border-solid;
}
}
}

View file

@ -0,0 +1,4 @@
@forward "root";
@forward "normalize";
@forward "general";
@forward "font-face";

View file

@ -0,0 +1,215 @@
*,
::before,
::after {
box-sizing: border-box;
}
:root {
line-height: 1.6;
text-size-adjust: 100%;
tab-size: 4;
font-feature-settings: normal;
font-variation-settings: normal;
}
body {
margin: 0;
line-height: inherit;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
text-decoration: underline dotted;
}
a {
color: inherit;
text-decoration: inherit;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp,
pre {
font-size: 1em;
font-family: "Courier New", Courier, monospace;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
font-size: 100%;
font-weight: inherit;
line-height: inherit;
color: inherit;
margin: 0;
padding: 0;
}
button,
select {
text-transform: none;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
appearance: button;
background-color: transparent;
background-image: none;
}
:-moz-focusring {
outline: auto;
}
:-moz-ui-invalid {
box-shadow: none;
}
progress {
vertical-align: baseline;
}
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
appearance: textfield;
outline-offset: -2px;
}
::-webkit-search-decoration {
appearance: none;
}
::-webkit-file-upload-button {
appearance: button;
font: inherit;
}
summary {
display: list-item;
}
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
dialog {
padding: 0;
}
textarea {
resize: vertical;
}
input::placeholder,
textarea::placeholder {
opacity: 1;
color: #9ca3af;
}
button,
[role="button"] {
cursor: pointer;
}
:disabled {
cursor: default;
}
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
vertical-align: middle;
}
img,
video {
max-width: 100%;
height: auto;
}
[hidden] {
display: none;
}

View file

@ -0,0 +1,15 @@
@use "../abstracts" as *;
:root {
// Generate light theme variables (default)
@each $color, $value in map-get($themes, "light") {
--clr-#{$color}: #{$value};
}
// Dark theme class
&.dark-theme {
@each $color, $value in map-get($themes, "dark") {
--clr-#{$color}: #{$value};
}
}
}

View file

@ -0,0 +1,41 @@
@font-face {
font-family: "JetBrains Mono";
font-display: swap;
src:
url("/fonts/JetBrainsMono-Regular.woff2") format("woff2"),
url("/fonts/JetBrainsMono-Regular.woff") format("woff");
}
@font-face {
font-family: "Geist Sans";
font-display: swap;
font-weight: 800;
src: url("/fonts/Geist-Black.woff2") format("woff2");
}
@font-face {
font-family: "Geist Sans";
font-display: swap;
font-weight: 700;
src: url("/fonts/Geist-Bold.woff2") format("woff2");
}
@font-face {
font-family: "Geist Sans";
font-display: swap;
font-weight: 500;
src: url("/fonts/Geist-Medium.woff2") format("woff2");
}
@font-face {
font-family: "Geist Sans";
font-display: swap;
font-weight: 400;
src: url("/fonts/Geist-Regular.woff2") format("woff2");
}
@font-face {
font-family: "Geist Sans";
font-display: swap;
font-weight: 300;
src: url("/fonts/Geist-Thin.woff2") format("woff2");
}

View file

@ -0,0 +1,33 @@
@use "../abstracts/" as *;
.callout {
padding: $spacer / 2 $spacer;
background: var(--clr-crust);
margin: $spacer 0;
border: 1px solid var(--clr-surface-0);
&__title {
display: flex;
align-items: center;
gap: $spacer / 2;
font-weight: $font-weight-bolder;
margin-bottom: $spacer;
}
&--tip {
border-left: 5px solid var(--clr-bright-green);
.callout__title {
color: var(--clr-green);
}
}
&--info {
border-left: 5px solid var(--clr-bright-blue);
.callout__title {
color: var(--clr-blue);
}
}
&--warning {
border-left: 5px solid var(--clr-bright-gold);
.callout__title {
color: var(--clr-bright-gold);
}
}
}

View file

@ -0,0 +1,512 @@
@use "../abstracts/" as *;
code {
font-family: $font-family-monospace;
font-weight: $font-weight-bold;
background: var(--clr-surface-0);
word-wrap: break-word;
padding: 0 0.2rem 0 0.2rem;
}
pre code {
background: var(--clr-crust);
}
.z-code {
color: var(--clr-text);
border: 1px solid var(--clr-subtext-0);
vertical-align: middle;
background: var(--clr-crust);
font-size: $font-size-small;
font-family: $font-family-monospace;
width: 100%;
padding: $spacer;
margin-bottom: $spacer;
overflow-x: auto;
}
/*pre code {
font-family: monospace;
font-size: 15px;
line-height: 1.5;
max-width: 80%;
overflow: auto;
padding: 1em 1em;
display: block;
justify-content: center;
margin: 25px 25px;
}*/
// syntax
.z-comment,
.z-punctuation.z-definition.z-comment {
color: var(--clr-subtext-0);
font-style: italic;
font-weight: $font-weight-regular;
}
.z-variable {
color: var(--clr-blue);
}
.z-string,
.z-constant.z-other.z-symbol {
color: var(--clr-green);
}
.z-constant.z-numeric {
color: var(--clr-cyan);
}
.z-string.z-regexp,
.z-constant.z-character.z-escape {
color: var(--clr-green);
}
.z-constant.z-language {
color: var(--clr-purple);
}
.z-constant.z-character,
.z-constant.z-other {
color: var(--clr-cyan);
}
.z-variable.z-member {
color: var(--clr-blue);
}
.z-keyword,
.z-keyword.z-operator.z-word {
color: var(--clr-red);
}
.z-keyword.z-operator {
color: var(--clr-orange);
}
.z-punctuation.z-separator,
.z-punctuation.z-terminator {
color: var(--clr-text);
}
.z-punctuation.z-section {
color: var(--clr-text);
}
.z-punctuation.z-accessor {
color: var(--clr-red);
}
.z-punctuation.z-definition.z-annotation {
color: var(--clr-text);
}
.z-variable.z-other.z-dollar.z-only.z-js,
.z-variable.z-other.z-object.z-dollar.z-only.z-js,
.z-variable.z-type.z-dollar.z-only.z-js,
.z-support.z-class.z-dollar.z-only.z-js {
color: var(--clr-blue);
}
.z-storage {
color: var(--clr-orange);
}
.z-storage.z-type {
color: var(--clr-orange);
}
.z-entity.z-name.z-function {
color: var(--clr-blue);
}
.z-entity.z-name,
.z-entity.z-name.z-tag,
.z-entity.z-name.z-label {
color: var(--clr-orange);
}
.z-entity.z-other.z-inherited-class {
color: #0070b3;
text-decoration: underline;
}
.z-variable.z-parameter {
color: var(--clr-blue);
}
.z-variable.z-language {
color: var(--clr-blue);
font-style: italic;
}
.z-entity.z-name.z-tag,
.z-meta.z-tag.z-sgml {
color: var(--clr-blue);
}
.z-punctuation.z-definition.z-tag.z-end,
.z-punctuation.z-definition.z-tag.z-begin,
.z-punctuation.z-definition.z-tag {
color: var(--clr-green);
}
.z-entity.z-other.z-attribute-name {
color: var(--clr-blue);
}
.z-variable.z-function,
.z-variable.z-annotation {
color: var(--clr-blue);
}
.z-support.z-function,
.z-support.z-macro {
color: var(--clr-cyan);
}
.z-support.z-constant {
color: var(--clr-cyan);
font-style: italic;
}
.z-support.z-type,
.z-support.z-class {
color: var(--clr-blue);
font-style: italic;
}
.z-invalid {
color: var(--clr-red);
}
.z-invalid.z-deprecated {
color: var(--clr-bright-text);
background-color: var(--clr-blue);
}
.z-source.z-ruby .z-variable.z-other.z-readwrite {
color: var(--clr-blue);
}
.z-source.z-css .z-entity.z-name.z-tag,
.z-source.z-sass .z-entity.z-name.z-tag,
.z-source.z-scss .z-entity.z-name.z-tag,
.z-source.z-less .z-entity.z-name.z-tag,
.z-source.z-stylus .z-entity.z-name.z-tag {
color: var(--clr-orange);
}
.z-source.z-css .z-support.z-type,
.z-source.z-sass .z-support.z-type,
.z-source.z-scss .z-support.z-type,
.z-source.z-less .z-support.z-type,
.z-source.z-stylus .z-support.z-type {
color: var(--clr-text);
}
.z-support.z-type.z-property-name {
color: var(--clr-green);
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: var(--clr-text);
}
.z-constant.z-numeric.z-line-number.z-match {
color: var(--clr-blue);
}
.z-entity.z-name.z-filename.z-find-in-files {
color: var(--clr-blue);
}
.z-message.z-error {
color: var(--clr-red);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-source.z-json
.z-meta.z-structure.z-dictionary.z-json
.z-string.z-quoted.z-double.z-json,
.z-source.z-json
.z-meta.z-structure.z-dictionary.z-json
.z-punctuation.z-definition.z-string {
color: var(--clr-green);
}
.z-markup.z-heading {
color: var(--clr-red);
font-weight: bold;
}
.z-string.z-other.z-link,
.z-markup.z-underline.z-link {
color: var(--clr-blue);
text-decoration: underline;
font-style: italic;
}
.z-punctuation.z-definition.z-image {
color: var(--clr-orange);
}
.z-markup.z-italic {
color: var(--clr-purple);
font-style: italic;
}
.z-markup.z-bold {
color: var(--clr-red);
font-weight: bold;
}
.z-markup.z-italic .z-markup.z-bold,
.z-markup.z-bold .z-markup.z-italic {
font-weight: bold;
font-style: italic;
}
.z-markup.z-raw {
background-color: var(--clr-text);
}
.z-markup.z-raw.z-inline {
background-color: var(--clr-text);
}
.z-meta.z-separator {
color: var(--clr-text);
background-color: var(--clr-text);
font-weight: bold;
}
.z-markup.z-quote {
color: var(--clr-subtext);
font-style: italic;
}
.z-markup.z-list.z-numbered.z-bullet,
.z-markup.z-list .z-punctuation.z-definition.z-list_item {
color: var(--clr-orange);
}
.z-markup.z-inserted {
color: var(--clr-green);
}
.z-markup.z-changed {
color: var(--clr-green);
}
.z-markup.z-deleted {
color: var(--clr-red);
}
.z-markup.z-strike {
color: var(--clr-orange);
}
.z-markup.z-table {
color: var(--clr-blue);
background-color: var(--clr-mantle);
}
.z-text.z-html.z-markdown .z-markup.z-raw.z-inline {
color: var(--clr-purple);
}
.z-text.z-html.z-markdown .z-meta.z-dummy.z-line-break {
color: var(--clr-text);
}
.z-markup.z-raw.z-block.z-fenced.z-markdown {
color: var(--clr-text);
background-color: var(--clr-mantle);
}
.z-punctuation.z-definition.z-fenced.z-markdown,
.z-variable.z-language.z-fenced.z-markdown {
color: var(--clr-text);
background-color: var(--clr-mantle);
}
.z-variable.z-language.z-fenced.z-markdown {
color: var(--clr-text);
}
.z-markup.z-inserted.z-git_gutter {
color: var(--clr-green);
}
.z-markup.z-changed.z-git_gutter {
color: var(--clr-blue);
}
.z-markup.z-deleted.z-git_gutter {
color: var(--clr-red);
}
.z-markup.z-ignored.z-git_gutter {
color: var(--clr-text);
}
.z-markup.z-untracked.z-git_gutter {
color: var(--clr-text);
}
.z-gutter_color {
color: var(--clr-bright-text);
}
.z-acejump.z-label.z-blue {
color: var(--clr-text);
background-color: var(--clr-blue);
}
.z-acejump.z-label.z-green {
color: var(--clr-text);
background-color: var(--clr-green);
}
.z-acejump.z-label.z-orange {
color: var(--clr-text);
background-color: var(--clr-blue);
}
.z-acejump.z-label.z-purple {
color: var(--clr-text);
background-color: var(--clr-purple);
}
.z-sublimelinter.z-mark.z-warning {
color: var(--clr-blue);
}
.z-sublimelinter.z-gutter-mark {
color: var(--clr-text);
}
.z-sublimelinter.z-mark.z-error {
color: var(--clr-red);
}

View file

@ -0,0 +1,38 @@
.info-box-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 10px;
padding: 20px;
}
.info-box-wrapper {
margin: 10px 10px;
padding: 10px 10px;
display: flex;
border: 1px solid var(--clr-text);
position: relative;
}
.info-box {
&__title {
z-index: 100;
position: absolute;
top: -0.8em;
background-color: var(--clr-mantle);
color: var(--clr-text);
padding: 0 5px;
display: flex;
align-content: center;
font-weight: bold;
}
&__title-text {
margin-left: 5px;
font-size: 16px;
}
&__content {
padding: 10px;
color: var(--clr-text);
}
&__list {
}
&__item {
}
}

View file

@ -0,0 +1,20 @@
@use "../abstracts" as *;
.content {
h1,
h2,
h3,
h4 {
display: flex;
align-items: center;
}
&__title {
justify-content: center;
}
li {
margin-bottom: $spacer;
}
.zola-anchor {
margin-left: $spacer / 2;
}
}

View file

@ -0,0 +1,6 @@
@forward "navbar";
@forward "code";
@forward "containers";
@forward "notebook-menu";
@forward "content";
@forward "callout";

View file

@ -0,0 +1,93 @@
// partials/navbar.scss
@use "../abstracts/" as *;
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100vw;
z-index: 1000;
font-family: "JetBrains Mono", monospace;
background-color: var(--clr-crust);
border-bottom: solid 1px var(--clr-text);
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
height: $navbar-height;
.switch {
cursor: pointer;
justify-content: center;
width: 24px;
height: 24px;
display: inline-block;
position: relative;
&__input {
display: none;
}
&__icon {
position: absolute;
transition: opacity;
&.icon__moon {
opacity: 0;
}
}
&:hover .switch__icon {
color: var(--clr-green);
}
&__input:checked ~ .switch__icon {
&.icon__sun {
opacity: 0;
}
&.icon__moon {
opacity: 1;
}
}
}
&__tab {
display: flex;
list-style-type: none;
padding: 0;
margin: 0;
justify-content: center;
}
&__tab-item {
margin-right: 10px;
&:last-child {
margin-right: 0; // Remove margin from the last item
}
}
&__link {
color: var(--clr-text);
text-decoration: none;
padding: 2px 5px;
background-color: var(--clr-base);
&:hover {
background-color: var(--clr-surface-1);
}
&--notes {
}
&--home {
}
&--contact {
}
}
&__info {
display: flex;
justify-content: flex-end;
align-items: center;
}
&__git {
color: var(--clr-purple);
margin-right: 15px;
display: flex;
align-items: center;
}
}

View file

@ -0,0 +1,151 @@
@use "../abstracts/" as *;
.s-menu__link-wrapper {
display: flex;
align-items: center;
}
.s-menu__link {
flex-grow: 1;
}
.s-menu__toggle,
.s-menu__toggle-placeholder {
width: 1.5rem;
height: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.s-menu__toggle {
background: none;
border: none;
cursor: pointer;
padding: 0;
}
.s-menu__toggle::after {
content: "";
font-size: 0.8rem;
}
.s-menu__toggle:not(.collapsed)::after {
transform: rotate(90deg);
}
.collapse {
display: none;
}
.collapse.show {
display: block;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.s-menu__sublist {
padding-left: 1.5rem;
}
.s-menu {
&__item {
}
&__list,
&__sublist {
margin: 0;
}
}
.tree-node {
margin-bottom: 0.25rem;
}
.sidebar {
background-color: var(--clr-crust);
border: $solid-border;
padding: $spacer;
}
.tree-view {
font-family: $font-family-monospace;
}
.tree-root {
list-style-type: none;
padding-left: 0;
}
.tree-node {
position: relative;
padding-left: 20px;
}
.tree-branch::before,
.tree-branch::after {
content: "";
position: absolute;
left: 0;
}
.tree-branch::before {
border-left: $border-light;
height: 100%;
top: 0;
}
.tree-branch::after {
border-top: $border-light;
width: 20px;
top: 12px;
}
.tree-node:last-child > .tree-branch::before {
height: 12px;
}
.tree-children {
list-style-type: none;
padding-left: 0;
}
.s-menu {
&__item {
margin-bottom: 0;
}
&__list,
&__sublist {
margin: 0;
}
}
.s-menu__link {
text-decoration: none;
color: $font-color-text;
}
.s-menu__link:hover,
.s-menu__link--active {
color: var(--clr-green);
}
.s-menu__link--book {
font-weight: bold;
}
.s-menu__link--chapter {
font-weight: $font-weight-bolder;
}
.s-menu__link--page {
font-weight: $font-weight-regular;
font-size: $font-size-small;
padding-left: 0.5rem;
}

View file

@ -0,0 +1,5 @@
@use "abstracts";
@use "base";
@use "utilities";
@use "components";
@use "pages";

View file

@ -0,0 +1 @@
@forward "notebook";

View file

@ -0,0 +1,64 @@
@use "../abstracts/" as *;
html {
scroll-padding-top: $navbar-height;
}
.notebook {
display: flex;
flex-direction: column;
width: 100vw;
margin-top: $navbar-height;
min-height: 100vh;
padding: 12px;
.sidebar {
width: 100%;
display: none;
flex-shrink: 0;
height: auto;
}
.content {
width: 100%;
flex-grow: 1;
overflow-y: auto;
}
&--menu-toggled .sidebar {
display: block;
}
}
@media (min-width: 800px) {
.notebook {
overflow: hidden;
.sidebar {
position: fixed;
display: flex;
top: calc($navbar-height + 10px);
left: 10px;
align-self: start;
height: calc(100vh - 70px);
width: $sidebar-width;
overflow-y: auto;
}
.content {
flex: 1;
margin-left: calc($sidebar-width + 10px);
padding: $spacer 10%;
max-width: calc(100% - $sidebar-width);
align-items: center;
}
&--menu-toggled {
.content {
margin-left: 0;
max-width: 100%;
padding: 10px 10%;
}
.sidebar {
display: none;
}
}
}
}

View file

@ -0,0 +1,19 @@
@use "../abstracts" as *;
@use "sass:map";
//@function colors($color-name) {
// @return map-get($colors, $color-name);
// }
//@mixin themify($themes) {
// @each $name, $values in $themes {
// .#{$name}-theme {
// $theme-map: $values !global;
// @content;
// }
// }
//}
//@function colors($key) {
// @return map-get($theme-map, $key);
// }

View file

@ -0,0 +1,101 @@
// _icons.scss
@use "sass:map";
$icon-sizes: (
"small": 16px,
"medium": 24px,
"large": 32px,
);
$icons: (
discord: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.1.1 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.1 16.1 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02M8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12m6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12'/%3E%3C/svg%3E",
color: purple,
),
contact: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M6 17c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6m9-9a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3a3 3 0 0 1 3 3M3 5v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2'/%3E%3C/svg%3E",
color: gold,
),
notes: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23000' d='M464 48c-67.61.29-117.87 9.6-154.24 25.69c-27.14 12-37.76 21.08-37.76 51.84V448c41.57-37.5 78.46-48 224-48V48ZM48 48c67.61.29 117.87 9.6 154.24 25.69c27.14 12 37.76 21.08 37.76 51.84V448c-41.57-37.5-78.46-48-224-48V48Z'/%3E%3C/svg%3E",
color: purple,
),
info: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M11 17h2v-6h-2zm1-8q.425 0 .713-.288T13 8t-.288-.712T12 7t-.712.288T11 8t.288.713T12 9m0 13q-2.075 0-3.9-.788t-3.175-2.137T2.788 15.9T2 12t.788-3.9t2.137-3.175T8.1 2.788T12 2t3.9.788t3.175 2.137T21.213 8.1T22 12t-.788 3.9t-2.137 3.175t-3.175 2.138T12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4T6.325 6.325T4 12t2.325 5.675T12 20m0-8'/%3E%3C/svg%3E",
color: blue,
),
git: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M17 7a2 2 0 1 0 0-4a2 2 0 0 0 0 4M7 7a2 2 0 1 0 0-4a2 2 0 0 0 0 4m0 14a2 2 0 1 0 0-4a2 2 0 0 0 0 4M7 7v10M17 7v1c0 2.5-2 3-2 3l-6 2s-2 .5-2 3v1'/%3E%3C/svg%3E",
color: purple,
),
moon: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 22c5.523 0 10-4.477 10-10c0-.463-.694-.54-.933-.143a6.5 6.5 0 1 1-8.924-8.924C12.54 2.693 12.463 2 12 2C6.477 2 2 6.477 2 12s4.477 10 10 10'/%3E%3C/svg%3E",
color: text,
),
sun: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M18 12a6 6 0 1 1-12 0a6 6 0 0 1 12 0'/%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M12 1.25a.75.75 0 0 1 .75.75v1a.75.75 0 0 1-1.5 0V2a.75.75 0 0 1 .75-.75M4.399 4.399a.75.75 0 0 1 1.06 0l.393.392a.75.75 0 0 1-1.06 1.061l-.393-.393a.75.75 0 0 1 0-1.06m15.202 0a.75.75 0 0 1 0 1.06l-.393.393a.75.75 0 0 1-1.06-1.06l.393-.393a.75.75 0 0 1 1.06 0M1.25 12a.75.75 0 0 1 .75-.75h1a.75.75 0 0 1 0 1.5H2a.75.75 0 0 1-.75-.75m19 0a.75.75 0 0 1 .75-.75h1a.75.75 0 0 1 0 1.5h-1a.75.75 0 0 1-.75-.75m-2.102 6.148a.75.75 0 0 1 1.06 0l.393.393a.75.75 0 1 1-1.06 1.06l-.393-.393a.75.75 0 0 1 0-1.06m-12.296 0a.75.75 0 0 1 0 1.06l-.393.393a.75.75 0 1 1-1.06-1.06l.392-.393a.75.75 0 0 1 1.061 0M12 20.25a.75.75 0 0 1 .75.75v1a.75.75 0 0 1-1.5 0v-1a.75.75 0 0 1 .75-.75' clip-rule='evenodd'/%3E%3C/svg%3E",
color: text,
),
arrow: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m12 6l-6 6l6 6m6-12l-6 6l6 6'/%3E%3C/svg%3E",
color: text,
),
menu: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M3 18v-2h18v2zm0-5v-2h18v2zm0-5V6h18v2z'/%3E%3C/svg%3E",
color: text,
),
tip: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 3.75c2.928 0 5.25 2.275 5.25 5.02c0 1.71-.44 2.581-.998 3.373q-.19.266-.417.56c-.524.685-1.154 1.51-1.601 2.699a3.5 3.5 0 0 1-.353.698l-.056.08a3 3 0 0 1-.42.482c-.406.372-.894.588-1.405.588c-.51 0-.999-.216-1.406-.588a3 3 0 0 1-.42-.483l-.055-.08a3.5 3.5 0 0 1-.353-.697c-.447-1.19-1.077-2.014-1.601-2.7a18 18 0 0 1-.417-.56c-.557-.79-.998-1.662-.998-3.373C6.75 6.025 9.073 3.75 12 3.75m3.167 13.119c.192-.3.35-.617.471-.94c.362-.963.818-1.562 1.318-2.217c.17-.223.345-.453.523-.706c.71-1.008 1.271-2.175 1.271-4.237c0-3.628-3.05-6.519-6.75-6.519S5.25 5.141 5.25 8.77c0 2.06.561 3.228 1.271 4.236c.178.253.353.483.523.706c.5.655.956 1.254 1.318 2.217c.121.323.28.64.471.94l.222 2.216a2.96 2.96 0 0 0 5.89 0zm-1.66 1.53l-.054.536a1.46 1.46 0 0 1-2.906 0l-.053-.536c.45.222.955.351 1.506.351c.55 0 1.056-.13 1.506-.351M2.423 3.019a.75.75 0 0 1 1.056-.095l1.5 1.25a.75.75 0 0 1-.96 1.152l-1.5-1.25a.75.75 0 0 1-.096-1.056m19.152 0a.75.75 0 0 1-.096 1.057l-1.5 1.25a.75.75 0 1 1-.96-1.152l1.5-1.25a.75.75 0 0 1 1.056.096M1.25 8.25A.75.75 0 0 1 2 7.5h2A.75.75 0 0 1 4 9H2a.75.75 0 0 1-.75-.75m18 0A.75.75 0 0 1 20 7.5h2A.75.75 0 0 1 22 9h-2a.75.75 0 0 1-.75-.75M5.17 11.915a.75.75 0 0 1-.335 1.006l-1.5.75a.75.75 0 1 1-.67-1.342l1.5-.75a.75.75 0 0 1 1.006.336m13.66 0a.75.75 0 0 1 1.005-.336l1.5.75a.75.75 0 1 1-.67 1.342l-1.5-.75a.75.75 0 0 1-.336-1.006'/%3E%3C/svg%3E",
color: green,
),
warning: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1 21L12 2l11 19zm3.45-2h15.1L12 6zM12 18q.425 0 .713-.288T13 17t-.288-.712T12 16t-.712.288T11 17t.288.713T12 18m-1-3h2v-5h-2zm1-2.5'/%3E%3C/svg%3E",
color: gold,
),
link: (
svg:
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M11 17H7q-2.075 0-3.537-1.463T2 12t1.463-3.537T7 7h4v2H7q-1.25 0-2.125.875T4 12t.875 2.125T7 15h4zm-3-4v-2h8v2zm5 4v-2h4q1.25 0 2.125-.875T20 12t-.875-2.125T17 9h-4V7h4q2.075 0 3.538 1.463T22 12t-1.463 3.538T17 17z'/%3E%3C/svg%3E",
color: text,
),
);
@mixin icon($name) {
$icon: map.get($icons, $name);
--svg: url("#{map.get($icon, 'svg')}");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
color: var(--clr-#{map.get($icon, "color")});
}
.icon {
display: inline-block;
background-color: currentColor;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
@each $name, $size in $icon-sizes {
&--#{$name} {
width: $size;
height: $size;
}
}
@each $name, $_ in $icons {
&__#{$name} {
@include icon($name);
}
}
}

View file

@ -0,0 +1,3 @@
@forward "icons";
@forward "color-utils";
@forward "screen-width";

View file

@ -0,0 +1,13 @@
@mixin min-screen($min-width: $body-width) {
@media screen and (min-width: $min-width) {
@content;
}
}
@mixin max-screen($max-width: $body-width) {
@media screen and (max-width: $max-width) {
@content;
}
}
$sidebar-width: 300px;

View file

@ -0,0 +1,53 @@
function processCallouts() {
console.log("Processing callouts");
const content = document.querySelector(".content");
if (content) {
const blockquotes = content.querySelectorAll("blockquote");
blockquotes.forEach((blockquote) => {
const firstParagraph = blockquote.querySelector("p");
if (firstParagraph && firstParagraph.textContent.startsWith("[!")) {
const match = firstParagraph.textContent.match(/\[!(\w+)\]/);
if (match) {
const type = match[1].toLowerCase();
console.log(`Matched callout: ${type}`);
// remove the [!type] from the first paragraph
firstParagraph.textContent = firstParagraph.textContent.replace(
/\[!\w+\]\s*/,
"",
);
// create the callout structure
const callout = document.createElement("div");
callout.className = `callout callout--${type}`;
const title = document.createElement("div");
title.className = "callout__title";
const icon = document.createElement("span");
icon.className = `icon icon--medium icon__${type}`;
const titleText = document.createElement("span");
titleText.textContent = type.charAt(0).toUpperCase() + type.slice(1);
title.appendChild(icon);
title.appendChild(titleText);
callout.appendChild(title);
// move blockquote contents to the callout
callout.appendChild(title);
while (blockquote.firstChild) {
callout.appendChild(blockquote.firstChild);
}
// replace the blockquote with the callout
blockquote.parentNode.replaceChild(callout, blockquote);
}
}
});
}
}
document.addEventListener("DOMContentLoaded", processCallouts);
window.addEventListener("load", processCallouts);

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,30 @@
function initToggleMenu() {
const menuToggle = document.querySelector(".menu-toggle");
const notebook = document.querySelector(".notebook");
menuToggle.addEventListener("click", function (e) {
e.preventDefault();
notebook.classList.toggle("notebook--menu-toggled");
});
}
document.addEventListener("DOMContentLoaded", initToggleMenu);
document.addEventListener("DOMContentLoaded", function () {
const toggles = document.querySelectorAll('[data-toggle="collapse"]');
toggles.forEach((toggle) => {
toggle.addEventListener("click", function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute("data-target"));
if (target) {
target.classList.toggle("show");
this.classList.toggle("collapsed");
this.setAttribute(
"aria-expanded",
this.classList.contains("collapsed") ? "false" : "true",
);
}
});
});
});

View file

@ -0,0 +1,41 @@
let checkbox = document.querySelector("input[name=theme-switch]");
function setTheme(isDark) {
if (isDark) {
document.documentElement.classList.add("dark-theme");
document.documentElement.classList.remove("light-theme");
checkbox.checked = true;
} else {
document.documentElement.classList.remove("dark-theme");
document.documentElement.classList.add("light-theme");
checkbox.checked = false;
}
// save the theme preference to local storage
localStorage.setItem("darkTheme", isDark);
}
// check for saved theme preference
let savedTheme = localStorage.getItem("darkTheme");
if (savedTheme !== null) {
// use the saved theme if it exists
setTheme(savedTheme === "true");
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
// if no saved preference, check system preference
setTheme(true);
} else {
setTheme(false);
}
// switch theme if checkbox is toggled
checkbox.addEventListener("change", (event) => {
console.log("button clicked");
setTheme(event.target.checked);
});
// listen for system color-scheme changes
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", (e) => {
setTheme(e.matches);
});

View file

@ -0,0 +1,5 @@
<a
class="zola-anchor icon icon--medium icon__link"
href="#{{ id }}"
aria-label="Anchor link for: {{ id }}"
></a>

View file

@ -0,0 +1,44 @@
<!doctype html>
<html lang="en">
<head>
{%- include "partials/head.html" %}
</head>
{% block body %} {% set page_class="home" %} {% endblock body %}
<body class="{{ page_class }}">
<header class="navbar-wrapper">
<nav class="navbar">
<div>{% block navbar_extras %} {% endblock navbar_extras %}</div>
<ul class="navbar__tab">
<li class="navbar__tab-item">
<a class="navbar__link navbar__link--home" href="{{ config.base_url }}"
>home</a
>
</li>
<li class="navbar__tab-item">
<a
class="navbar__link navbar__link--notes"
href="{{ get_url(path='notes') }}"
>notes</a
>
</li>
<li class="navbar__tab-item">
<a class="navbar__link navbar__link--contact" href="#">contact</a>
</li>
</ul>
<label class="switch">
<input class="switch__input" type="checkbox" name="theme-switch" />
<span class="icon icon--medium icon__moon switch__icon"></span>
<span class="icon icon--medium icon__sun switch__icon"></span>
</label>
</nav>
</header>
{% block home %} {% endblock home %}
{% block notebook %}{% endblock notebook %}
{% block js_body %}
<script type="text/javascript" src="{{ get_url(path="notebook_menu.js") | safe }}"></script>
<script type="text/javascript" src="{{ get_url(path="theme_switch.js") | safe }}"></script>
<script type="text/javascript" src="{{ get_url(path="callouts.js") | safe }}"></script>
{% endblock js_body %}
</body>
</html>

View file

@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block main_navbar %}
<header>
<div class="site-header">
<nav>
<ul class="nav-links">
<li><a href="{{ config.base_url }}"> ooknet</a></li>
<li><a href="{{ get_url(path='library') }}"> notes</a></li>
<li><a href="{{ get_url(path='resume') }}">󰇮 contact</a></li>
</ul>
</nav>
</div>
</header>
{% endblock main_navbar %}

View file

@ -0,0 +1,40 @@
{% extends "base.html" %}
<section class="info-box-container">
<article class="info-box-wrapper">
<div class="info-box">
<header class="info-box__title">
<span aria-hidden="true" class="icon icon--medium icon__info"></span>
<h2 class="info-box__title-text" "info-box__title-text--about">about</h2>
</header>
<div class="info-box__content">
<p>ooknet is a monorepo, a personal website and a collection of my notes</p>
</div>
</div>
</article>
<article class="info-box-wrapper">
<div class="info-box">
<header class="info-box__title">
<span aria-hidden="true" class="icon icon--medium icon__contact"></span>
<h2 class="info-box__title-text" "info-box__title-text--contact">contact</h2>
</header>
<div class="info-box__content">
<p>ooknet is a monorepo, a personal website and a collection of my notes</p>
</div>
</div>
</article>
<article class="info-box-wrapper">
<div class="info-box">
<header class="info-box__title">
<span aria-hidden="true" class="icon icon--medium icon__notes"></span>
<h2 class="info-box__title-text" "info-box__title-text--notes">notes</h2>
</header>
<div class="info-box__content">
<p>ooknet is a monorepo, a personal website and a collection of my notes</p>
</div>
</div>
</article>
</section>
{% block home %}
{{ section.content | safe }}
{% endblock home %}

View file

@ -0,0 +1,35 @@
{% extends "base.html" %}
{% block notebook %}
<h1 class="content__title">{{ section.title }}</h1>
{{ section.content | safe }}
<div class="notebook-grid">
{% set library = get_section(path="notes/_index.md") %}
{% for book in library.subsections %}
{% set book_section = get_section(path=book) %}
<div class="notebook-card">
<h2 class="notebook-card__title">
<a href="{{ book_section.permalink | safe }}" class="notebook-card__link">
{{ book_section.title }}
</a>
</h2>
{% if book_section.description %}
<p class="notebook-card__description">{{ book_section.description }}</p>
{% endif %}
{% if book_section.subsections %}
<ul class="notebook-card__chapters">
{% for chapter in book_section.subsections %}
{% set chapter_section = get_section(path=chapter) %}
<li class="notebook-card__chapter">
<a href="{{ chapter_section.permalink | safe }}" class="notebook-card__chapter-link">
{{ chapter_section.title }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</div>
{% endblock notebook %}

View file

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block navbar_extras %}
<button class="menu-toggle icon icon--large icon__menu"></button>
{% endblock navbar_extras %} {% block notebook %}
<div class="notebook">
{% block notebook_menu %} {% include "partials/notebook-menu.html" %} {%
endblock notebook_menu %}
<main class="content">
{% block content %}
<h1 class="content__title">{{ page.title | safe }}</h1>
{{ page.content | safe }} {% endblock content %}
</main>
</div>
{% endblock notebook %}

View file

@ -0,0 +1,27 @@
{% block head %}
<meta charset="utf-8" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta content="#ffffff" name="theme-color" />
<meta content="#da532c" name="msapplication-TileColor" />
<meta name="base" content={{ config.base_url | safe }} />
<meta name="HandheldFriendly" content="True" />
<meta name="mobule-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
{% if page %} {% if page.description %}
<meta name="description" content="{{ page.description }}" />
{% elif config.description %}
<meta name="description" content="{{ config.description }}" />
{% endif %} {% elif config.description %}
<meta name="description" content="{{ config.description }}" />
{% endif %}
<title>{% block title %}{{ config.title }}{% endblock title %}</title>
<!-- main css style sheet -->
{% block css %}
<link rel="stylesheet" href="{{ get_url(path="main.css") | safe }}">
{% endblock css %}
{% endblock head %}

View file

@ -0,0 +1,68 @@
<aside class="sidebar">
<nav role="navigation" class="s-menu tree-view">
<ul class="s-menu__list tree-root">
{% block menu -%}
{% set library = get_section(path="notes/_index.md") -%}
{% for book in library.subsections -%}
{% set book_section = get_section(path=book) -%}
{% set is_book_active = current_path is starting_with(book_section.path) %}
<li class="s-menu__item tree-node">
<div class="s-menu__link-wrapper">
<button class="s-menu__toggle{% if is_book_active %} s-menu__toggle--active{% else %} collapsed{% endif %}"
data-toggle="collapse"
data-target="#book-{{ loop.index }}"
aria-expanded="{% if is_book_active %}true{% else %}false{% endif %}">
<span class="sr-only">Toggle {{ book_section.title }}</span>
</button>
<a href="{{ book_section.permalink | safe }}"
class="s-menu__link s-menu__link--book{% if is_book_active %} s-menu__link--active{% endif %}">
{{ book_section.title }}
</a>
</div>
{%- if book_section.subsections %}
<ul id="book-{{ loop.index }}"
class="s-menu__sublist tree-children collapse{% if is_book_active %} show{% endif %}">
{%- for chapter in book_section.subsections %}
{% set chapter_section = get_section(path=chapter) -%}
{% set is_chapter_active = current_path is starting_with(chapter_section.path) %}
<li class="s-menu__item tree-node">
<span class="tree-branch"></span>
<div class="s-menu__link-wrapper">
{% if chapter_section.pages %}
<button class="s-menu__toggle{% if is_chapter_active %} s-menu__toggle--active{% else %} collapsed{% endif %}"
data-toggle="collapse"
data-target="#chapter-{{ book_section.path | slugify }}-{{ loop.index }}"
aria-expanded="{% if is_chapter_active %}true{% else %}false{% endif %}">
<span class="sr-only">Toggle {{ chapter_section.title }}</span>
</button>
{% endif %}
<a href="{{ chapter_section.permalink | safe }}"
class="s-menu__link s-menu__link--chapter{% if is_chapter_active %} s-menu__link--active{% endif %}">
{{ chapter_section.title }}
</a>
</div>
{%- if chapter_section.pages %}
<ul id="chapter-{{ book_section.path | slugify }}-{{ loop.index }}"
class="s-menu__sublist tree-children collapse{% if is_chapter_active %} show{% endif %}">
{%- for page in chapter_section.pages %}
<li class="s-menu__item tree-node">
<span class="tree-branch"></span>
<a href="{{ page.permalink | safe }}"
class="s-menu__link s-menu__link--page{% if current_path == page.path %} s-menu__link--active{% endif %}">
{{ page.title }}
</a>
</li>
{%- endfor %}
</ul>
{%- endif %}
</li>
{%- endfor %}
</ul>
{%- endif %}
</li>
{%- endfor %}
{%- endblock menu %}
</ul>
</nav>
</aside>

View file

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block body %} {% set page_class="notebook-layout" %} {% endblock body %}
{% block navbar_extras %}
<button class="menu-toggle icon icon--large icon__menu"></button>
{% endblock navbar_extras %}
{% block notebook %}
<div class="notebook">
{% block notebook_menu %}
{% include "partials/notebook-menu.html" %}
{% endblock notebook_menu %}
{% block content %}
<article class="content">
<h1 class=content__title>{{ section.title | safe }}</h1>
{{ section.content | safe }}
{% endblock content %}
</article>
</div>
{% endblock notebook %}