Oh I'm just adding the entire website

This commit is contained in:
root 2025-02-06 18:05:35 +01:00
commit 459862595a
67 changed files with 4073 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
zola

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "themes/duckquill"]
path = themes/duckquill
url = https://codeberg.org/daudix/duckquill.git

32
config.toml Normal file
View file

@ -0,0 +1,32 @@
title = "RSCC"
description = "Well, get on this site and find out."
theme = "duckquill"
# The URL the site will be built for
base_url = "https://rootsource.cc"
# 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
[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
[extra]
# Put all your custom variables here
[extra.footer]
show_copyright = true
show_powered_by = true
show_source = false
copyright = "raíz1.noho.st owns this website"
[extra.nav]
links = [
{ url = "Articles/", name = "Articles" },
]

View file

@ -0,0 +1,294 @@
+++
title = "TylkoLinux is done, here's how to install it."
description = "This article will go over the installation guide for the distro"
date = 2025-01-30
trigger = "TylkoLinux is still in experimental stage, and you should only install it if you know what you're doing. We do not take responsibility for any bricked machine as a result of not following the guide."
disclaimer = """
Do not follow this article. This page is NOT done yet.
"""
+++
`TylkoLinux 25.1/.2 Snyx x86_64`
As you may have read in the description, this article serves as a guide to install (build) TylkoLinux on your machine.
{% alert(important=true) %}
Prerequisites:
- x86_64 machine
- At least 32GB of storage
- CPU with at least four cores
- 8GB RAM
- A linux system running on the host system
{% end %}
## S1: Cloning the repository
The repository is available on GitHub. You can clone into it by running the following (if you have Git installed):
```bash
git clone https://github.com/kevadesu/TylkoLinux
```
Proceed to change directory into it.
```bash
cd ./TylkoLinux/
```
## S2: Run the compatibility checker
Run the compatibility check by running the script that is inside of the repository:
```bash
chmod +x ./version-check.sh && ./version-check.sh
```
Make sure everything is successful. If not, update your packages.
## S3: Partitioning the target device
Now that we have the installer ready, let's not run it just yet!
First, we need to __partition the drive we want to install it to.__
Now, of course, there are a lot of guides on how to do that online and depending on what setup you might want to achieve.
What IS clear though, is that you need a boot partition and a root partition, those are the bare minimum.
Obviously, I won't be able to write an ENTIRE guide on how to partiton your drive. If you don't know how to do that in the first place, then you shouldn't use TylkoLinux.
## S4: Setting the $LFS variable
Set the $LFS variable to point to /mnt/lfs. Of course, if you desire, you may also make it point to a different destination.
```bash
export LFS=/mnt/lfs
```
{% alert(caution=true) %}
Make sure that the $LFS variable always points to the correct destination.
It is recommended to always mount the target root partition under /mnt/lfs and set your variable to that.
Failure to do so may lead you to absolutely fuck up your system.
{% end %}
{% alert(tip=true) %}
From the LFS handbook:
One way to ensure that the LFS variable is always set is to edit the .bash_profile file in both your personal home directory and in /root/.bash_profile and enter the export command above. In addition, the shell specified in the /etc/passwd file for all users that need the LFS variable must be bash to ensure that the /root/.bash_profile file is incorporated as a part of the login process.
Another consideration is the method that is used to log into the host system. If logging in through a graphical display manager, the user's .bash_profile is not normally used when a virtual terminal is started. In this case, add the export command to the .bashrc file for the user and root. In addition, some distributions use an "if" test, and do not run the remaining .bashrc instructions for a non-interactive bash invocation. Be sure to place the export command ahead of the test for non-interactive use.
{% end %}
## S5: Mounting the partitions
Create the mount point and mount the filesystem using the following commands:
```bash
mkdir -pv $LFS
mount -v -t ext4 /dev/<foo> $LFS
# Replace <foo> with the partition name.
```
If using multiple partitions for TylkoLinux (for example, one for the root and one for the home partition), mount them as followed:
```bash
mkdir -pv $LFS
mount -v -t ext4 /dev/<xxx> $LFS
mkdir -v $LFS/home
mount -v -t ext4 /dev/<yyy> $LFS/home
# Replace <foo> and <bar> with the appropriate partition names.
```
{% alert(caution=true) %}
The instructions above assume that you are not rebooting your computer during the build. (imagine)
To automatically remount the partition on boot, modify /etc/fstab by adding this line:
```bash
/dev/<foo> /mnt/lfs ext4 defaults 1 1
```
If you use additional (optional) partitions, add them as well.
{% end %}
If also using swap, mount with the swapon command:
```bash
/sbin/swapon -v /dev/<owo>
# Replace <owo> with the name of the swap partition.
```
### S5.1: Move bash.bashrc out of the way
Several commercial distributions add an undocumented instantiation of /etc/bash.bashrc to the initialization of bash. This file has the potential to modify the lfs user's environment in ways that can affect the building of critical TylkoLinux (LFS) packages. To make sure the lfs user's environment is clean, check for the presence of /etc/bash.bashrc and, if present, move it out of the way. As the root user, run:
```bash
[ ! -e /etc/bash.bashrc ] || mv -v /etc/bash.bashrc /etc/bash.bashrc.NOUSE
```
## S6: Start the core installation tool
To start the installer, make sure you're in the same directory as the git repo we cloned, running as the `root` user, then type the following:
```bash
./Einrichter-CLI.sh
```
If this command fails, make sure it has the permissions to be executed by running the following:
```bash
chmod +x ./*.sh
```
### S6.1: Download packages
When in the script, you should see the following:
```bash
[i] The colour variables have been set.
Einrichter - TylkoLinux Installer Shell $EINRICHTER_VER
The script is located at $SCRIPT_DIR
Run einrichter.help for commands
einrichter>
```
To download packages and patches to the directory, type in the following function:
```bash
einrichter> einrichter.installer.pkgs
```
This action will proceed to download the packages and patches to $LFS/sources, and also the checksums.
### S6.2: Creating a limited directory layout
Run the following command:
```bash
einrichter> einrichter.installer.DirLayout
```
## S7: Enter lfs user
Enter the LFS environment to build the cross toolchain and temporary tools by entering the following:
```bash
einrichter> einrichter.installer.SafeUser
```
### S7.1: Going through pending steps
You are about to build a cross toolchain and temporary tools. You're going to see the following:
```bash
Einrichter is designed to work as an install script where you can resume where you left off. Do NOT skip anything if you have not ran the step yet.
Pending step: Setting up environment. Run, skip or quit?
```
Either type R to run, S to skip or Q to quit.
Do the same for the other remaining quesitons:
```bash
Pending step: Setting up toolchain. Run, skip or quit? R
Pending step: Installing cross toolchain and packages. Run, skip or quit? R
```
And eventually...
```bash
Done!
[i] Completed!
[i] Finished section installer.SafeUser
einrichter>
```
Before you know it, you're done!
Now HERE begins the real work (insert lqtroll emoji)
## S8: Actually building the system itself
{% alert(tip=true) %}
Before proceeding with the build,
One way to ensure that the LFS variable is always set is to edit the .bash_profile file in both your personal home directory and in /root/.bash_profile and enter the export command above. In addition, the shell specified in the /etc/passwd file for all users that need the LFS variable must be bash to ensure that the /root/.bash_profile file is incorporated as a part of the login process.
Another consideration is the method that is used to log into the host system. If logging in through a graphical display manager, the user's .bash_profile is not normally used when a virtual terminal is started. In this case, add the export command to the .bashrc file for the user and root. In addition, some distributions use an "if" test, and do not run the remaining .bashrc instructions for a non-interactive bash invocation. Be sure to place the export command ahead of the test for non-interactive use.
{% end %}
Now that you finished that section, enter the chroot environment like this:
```bash
einrichter> einrichter.installer.chroot
```
This command changes ownership of the commands under $LFS from the user `lfs` to `root`
It also mounts the virtual kernel file systems.
Then, it chroots you into the bash shell. Continue the installer by running the following command inside of the chroot:
```bash
$ /Einrichter-in-chroot.sh
```
This boots you into the eic shell.
Run the following commands:
```bash
einrichter/eic> eic.dirs.create # Creates necessary directories
einrichter/eic> eic.essentials.create # Creates necessary tools
einrichter/eic> eic.essentials.install # Installs the tools
einrichter/eic> eic.clean # Clean up the environment
```
Build the system by running the following:
```bash
einrichter/eic> eic.system.build
```
GCC, due to its nature of taking so long to build, gets its own function:
```bash
einrichter/eic> eic.system.build.gcc
```
Continue building as if nothing happened
```bash
einrichter/eic> eic.system.build.continue
```
### S8.1: Strip system (optional)
Done after so long? If you don't plan on doing any debugging on the system software/aren't that much of a programmer, you can remove debugging symbols and unnecessary symbol table entries from binaries and libraries.
This frees up about 2GB(?) on the system.
To do so, run the following:
```bash
einrichter/eic> eic.strip
```
### S8.2: Cleaning up
Finally, after all of that, clean up extra leftovers and the tester account by running this command:
```bash
einrichter/eic> eic.system.build.clean
```
## S9: Setting up the system
You are now in the stage where you set up your system and actually make an attempt at making your system bootable!
### S9.1: Networking
(This section only applies if a network card is to be configured.)
#### S9.1.1: Network Device Naming
{% alert(tip=true) %}
Modified from the LFS handbook: The interface names depend on the implementation and configuration of the udev daemon running on the system. The udev daemon for TylkoLinux (well, LFS) (systemd-udevd) will not run unless the TylkoLinux/LFS system is booted. So it's unreliable to determine the interface names being used in the TylkoLinux system by running those commands on the host distro, even though you are in the chroot environment.
{% end %}
Udev normally assigns network card interface names based on physical system characteristics such as enp2s1. If you are not sure what your interface name is, you can always run `ip link` after you have booted your system.
For most systems, there is only one network interface for each type of connection. For example, the classic interface name for a wired connection is eth0. A wireless connection will usually have the name wifi0 or wlan0.
If you'd like to use classic/customised network names, run the following function and enter the demanded information:
```bash
einrichter/eic> eic.config.network.devicenaming
[i] Enter MAC address of desired device: SN:UG:N0:0K:FR
[i] Enter the desired name of your interface: nasaethernet1
# Those are examples, not things you should actually enter!! Replace those with the actual info
```
#### S9.1.2: Static IP configuration
This makes a basic config file for a Static IP setup
```bash
einrichter/eic> eic.config.network.staticip
[i] Enter the name of the configured interface: nasaethernet1 # example
[?] Add DNS? If no, type N. If yes, type DNS address.
> Y # example
[?] Add domain? If no, type N. If yes, type domain name.
> N # example
[i] Skipped domain addition. # example
```
#### S9.1.3: DHCP configuration
```bash
einrichter/eic> eic.config.network.dhcp
[i] Enter the name of the configured interface: itsthesamethingagain0 # example
```
#### S9.1.4: /etc/resolv.conf
{% alert(tip=true) %}
From the LFS handbook: If using methods incompatible with systemd-resolved to configure your network interfaces (ex: ppp, etc.), or if using any type of local resolver (ex: bind, dnsmasq, unbound, etc.), or any other software that generates an /etc/resolv.conf (ex: a resolvconf program other than the one provided by systemd), the systemd-resolved service should not be used.
To switch settings about whether this should be allowed or not, run the command below ↓
{% end %}
```bash
einrichter/eic> eic.config.network.systemd.resolve <on/off>
[i] Disabling/Enabling systemd-resolved...
```
##### S9.1.4.1: Static resolv.conf
Want to create a static file? Here:
```bash
einrichter/eic> eic.config.network.staticresolver
[?] Add domain? If no, type N. If yes, type domain name.
> N # example
[?] Add primary nameserver? If no, type N. If yes, type nameserver name.
> N
[i] Skipped primary nameserver addition.
[?] Add secondary nameserver? If no, type N. If yes, type nameserver name.
> 1.2.3.4 # example
```
#### S9.1.5: Hostname
To configure the hostname, enter the following command:
```bash
einrichter/eic> eic.config.network.hostname <hostname>
# Replace <hostname> with the desired hostname
```
#### S9.1.6: Customising the /etc/hosts file
Remind me to work on this section.
# under construction!!!

View file

@ -0,0 +1,7 @@
+++
title = "Articles"
sort_by = "date"
template = "article_list.html"
page_template = "article.html"
paginate_by = 2
+++

18
content/_NOTindex.md.old Normal file
View file

@ -0,0 +1,18 @@
+++
template = "index.html"
title = "Hello World!"
+++
Hi!
There is your great future static site build with Zola ^w^
Check [the docs](https://www.getzola.org/documentation/getting-started/overview/) to get started!
## Tips
- Your Zola is installed in `/var/www/zola`
- Your content should be in `/var/www/zola/content`
- Your config file is `/var/www/zola/config.toml` (see [config docs](https://www.getzola.org/documentation/getting-started/configuration/))
- [Choose a theme](https://www.getzola.org/themes/), install it in `/var/www/zola/themes`, then configure it in your `config.toml` file
- This website will be automatically updated each time you modify something inside the `content`, `static`, `templates` or `themes` folders or the `config.toml` file!

14
content/_index.md Normal file
View file

@ -0,0 +1,14 @@
+++
title = "Home - RootSourceCC"
+++
# RootSourceCC
Welcome to RootSourceCC! You could technically call this: "The child of Raíz1, Icycoide and Costmiku"
With the ownership by Raíz1, hosted on and also being in charge of Costmiku, and hosting Icycoide's stuff!
Links:
- [Alpsource (Git forge)](https://git.rootsource.cc)
-[Raíz1](https://raiz1.noho.st) - [Icycoide](https://icycoide.github.io) 2025.

BIN
public/404.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

90
public/404.html Normal file
View file

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" >
<head>
<!-- 2025-02-01 Sat 04:04 -->
<meta charset="UTF-8" />
<meta name="description" content="Well, get on this site and find out." />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#9a9996" />
<title>404 - RSCC</title>
<link rel="canonical" href="&#x2F;" /><link rel="icon" type="image/png" href="https://rootsource.cc/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="https://rootsource.cc/apple-touch-icon.png" />
<style type="text/css">
:root {--accent-color: #6f8396;--contrast-color: #fff;}</style>
<link type="text/css" rel="stylesheet" href="https://rootsource.cc/style.css" />
<script type="text/javascript" defer src="https://rootsource.cc/closable.js"></script>
<meta property="og:site_name" content="RSCC" />
<meta property="og:title" content="404 - RSCC" />
<meta property="og:url" content="&#x2F;" />
<meta property="og:description" content="Well, get on this site and find out." />
<meta property="og:image" content="https://rootsource.cc/card.png" />
<meta property="og:locale" content="en_US" />
</head>
<body>
<header id="site-nav">
<nav>
<a href="#main-content" tabindex="0">
Skip to Main Content
</a>
<ul>
<li id="home">
<a href="https://rootsource.cc">
<i class="icon"></i>RSCC</a>
</li>
<li class="divider"></li>
<li>
<a href="https://rootsource.cc/Articles">Articles</a>
</li>
<li id="search">
<button id="search-toggle" class="circle" title="Search">
<i class="icon"></i>
</button>
</li>
</ul>
</nav>
<div id="search-container">
<label for="search-bar" class="visually-hidden">Search</label>
<input id="search-bar" placeholder="Search for…" autocomplete="off" type="search" disabled>
<div id="search-results-container">
<div id="search-results"></div>
</div>
</div>
</header>
<main id="main-content">
<picture>
<source srcset="https://rootsource.cc/404.png" media="(prefers-reduced-motion: reduce)"></source>
<img id="not-found" class="pixels transparent no-hover" alt="404"src="https://rootsource.cc/404.gif">
</picture>
<h1>Page Not Found</h1>
<p>The requested page could not be found.</p>
<div class="buttons">
<a href="https://rootsource.cc">Go Home</a>
</div>
<span id="search-index" class="hidden">https://rootsource.cc/search_index.en.json</span>
<span id="more-matches-text" class="hidden">$MATCHES more matches</span>
</main>
<footer id="site-footer">
<p>raíz1.noho.st owns this website</p>
<p>
<small>Powered by <a class="link external" href="https://www.getzola.org" rel="">Zola</a> and <a class="link external" href="https://duckquill.daudix.one" rel="">Duckquill</a>
</small>
</p>
</footer>
</body>
</html>

BIN
public/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

111
public/Articles/index.html Normal file
View file

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" >
<head>
<!-- 2025-02-01 Sat 04:04 -->
<meta charset="UTF-8" />
<meta name="description" content="Well, get on this site and find out." />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#9a9996" />
<title>Articles - RSCC</title>
<link rel="canonical" href="https://rootsource.cc/Articles/" /><link rel="icon" type="image/png" href="https://rootsource.cc/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="https://rootsource.cc/apple-touch-icon.png" />
<style type="text/css">
:root {--accent-color: #6f8396;--contrast-color: #fff;}</style>
<link type="text/css" rel="stylesheet" href="https://rootsource.cc/style.css" />
<script type="text/javascript" defer src="https://rootsource.cc/closable.js"></script>
<meta property="og:site_name" content="RSCC" />
<meta property="og:title" content="Articles - RSCC" />
<meta property="og:url" content="https://rootsource.cc/Articles/" />
<meta property="og:description" content="Well, get on this site and find out." />
<meta property="og:image" content="https://rootsource.cc/card.png" />
<meta property="og:locale" content="en_US" />
</head>
<body>
<header id="site-nav">
<nav>
<a href="#main-content" tabindex="0">
Skip to Main Content
</a>
<ul>
<li id="home">
<a href="https://rootsource.cc">
<i class="icon"></i>RSCC</a>
</li>
<li class="divider"></li>
<li>
<a href="https://rootsource.cc/Articles"class="active">Articles</a>
</li>
<li id="search">
<button id="search-toggle" class="circle" title="Search">
<i class="icon"></i>
</button>
</li>
</ul>
</nav>
<div id="search-container">
<label for="search-bar" class="visually-hidden">Search</label>
<input id="search-bar" placeholder="Search for…" autocomplete="off" type="search" disabled>
<div id="search-results-container">
<div id="search-results"></div>
</div>
</div>
</header>
<main id="main-content">
<h1>Articles</h1>
<p>
<small>
1 post in total
</small>
</p>
<div id="article-list"><article >
<a href="https://rootsource.cc/Articles/tylkolinux-installation/"></a>
<h3>TylkoLinux is done, here&#x27;s how to install it.</h3>
<p>This article will go over the installation guide for the distro</p>
<div class="details">
<small>
<time datetime="2025-01-30T00:00:00+00:00" pubdate>January 30, 2025</time></small>
</div></article>
</div>
<nav id="paginator">
<span id="paginator-first" title="First">
<i class="icon"></i>
</span>
<span id="paginator-previous" title="Previous">
<i class="icon"></i>
</span><span id="paginator-counter">1/1</span><span id="paginator-next" title="Next">
<i class="icon"></i>
</span>
<span id="paginator-last" title="Last">
<i class="icon"></i>
</span></nav>
<span id="search-index" class="hidden">https://rootsource.cc/search_index.en.json</span>
<span id="more-matches-text" class="hidden">$MATCHES more matches</span>
</main>
<footer id="site-footer">
<p>raíz1.noho.st owns this website</p>
<p>
<small>Powered by <a class="link external" href="https://www.getzola.org" rel="">Zola</a> and <a class="link external" href="https://duckquill.daudix.one" rel="">Duckquill</a>
</small>
</p>
</footer>
</body>
</html>

View file

@ -0,0 +1,6 @@
<!doctype html>
<meta charset="utf-8">
<link rel="canonical" href="https://rootsource.cc/Articles/">
<meta http-equiv="refresh" content="0; url=https://rootsource.cc/Articles/">
<title>Redirect</title>
<p><a href="https://rootsource.cc/Articles/">Click here</a> to be redirected.</p>

View file

@ -0,0 +1,323 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" >
<head>
<!-- 2025-02-01 Sat 04:04 -->
<meta charset="UTF-8" />
<meta name="description" content="Well, get on this site and find out." />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#9a9996" />
<title>TylkoLinux is done, here's how to install it. - RSCC</title>
<link rel="canonical" href="https://rootsource.cc/Articles/tylkolinux-installation/" /><link rel="icon" type="image/png" href="https://rootsource.cc/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="https://rootsource.cc/apple-touch-icon.png" />
<style type="text/css">
:root {--accent-color: #6f8396;--contrast-color: #fff;}</style>
<link type="text/css" rel="stylesheet" href="https://rootsource.cc/style.css" />
<script type="text/javascript" defer src="https://rootsource.cc/closable.js"></script>
<meta property="og:site_name" content="RSCC" />
<meta property="og:title" content="TylkoLinux is done, here's how to install it. - RSCC" />
<meta property="og:url" content="https://rootsource.cc/Articles/tylkolinux-installation/" />
<meta property="og:description" content="This article will go over the installation guide for the distro" />
<meta property="og:image" content="https://rootsource.cc/card.png" />
<meta property="og:locale" content="en_US" />
</head>
<body>
<header id="site-nav">
<nav>
<a href="#main-content" tabindex="0">
Skip to Main Content
</a>
<ul>
<li id="home">
<a href="https://rootsource.cc">
<i class="icon"></i>RSCC</a>
</li>
<li class="divider"></li>
<li>
<a href="https://rootsource.cc/Articles">Articles</a>
</li>
<li id="search">
<button id="search-toggle" class="circle" title="Search">
<i class="icon"></i>
</button>
</li>
</ul>
</nav>
<div id="search-container">
<label for="search-bar" class="visually-hidden">Search</label>
<input id="search-bar" placeholder="Search for…" autocomplete="off" type="search" disabled>
<div id="search-results-container">
<div id="search-results"></div>
</div>
</div>
</header>
<main id="main-content">
<article><div id="heading"><p>
<small>
<time datetime=" 2025-01-30T00:00:00+00:00">Published on
January 30, 2025</time></small>
</p><h1>TylkoLinux is done, here&#x27;s how to install it.</h1>
</div>
<div id="buttons-container"><a id="go-to-top" href="#top" title="Go to Top"><i class="icon"></i></a></div><p><code>TylkoLinux 25.1/.2 Snyx x86_64</code></p>
<p>As you may have read in the description, this article serves as a guide to install (build) TylkoLinux on your machine.
<blockquote class="important">
<p class="alert-title">
<i class="icon"></i>Important</p>
<p>Prerequisites:</p>
<ul>
<li>x86_64 machine</li>
<li>At least 32GB of storage</li>
<li>CPU with at least four cores</li>
<li>8GB RAM</li>
<li>A linux system running on the host system</li>
</ul>
</blockquote>
</p>
<h2 id="s1-cloning-the-repository">S1: Cloning the repository</h2>
<p>The repository is available on GitHub. You can clone into it by running the following (if you have Git installed):</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> clone https://github.com/kevadesu/TylkoLinux
</span></code></pre>
<p>Proceed to change directory into it.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#96b5b4;">cd</span><span> ./TylkoLinux/
</span></code></pre>
<h2 id="s2-run-the-compatibility-checker">S2: Run the compatibility checker</h2>
<p>Run the compatibility check by running the script that is inside of the repository:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">chmod</span><span> +x ./version-check.sh &amp;&amp; </span><span style="color:#bf616a;">./version-check.sh
</span></code></pre>
<p>Make sure everything is successful. If not, update your packages.</p>
<h2 id="s3-partitioning-the-target-device">S3: Partitioning the target device</h2>
<p>Now that we have the installer ready, let's not run it just yet!
First, we need to <strong>partition the drive we want to install it to.</strong>
Now, of course, there are a lot of guides on how to do that online and depending on what setup you might want to achieve.</p>
<p>What IS clear though, is that you need a boot partition and a root partition, those are the bare minimum.</p>
<p>Obviously, I won't be able to write an ENTIRE guide on how to partiton your drive. If you don't know how to do that in the first place, then you shouldn't use TylkoLinux.</p>
<h2 id="s4-setting-the-lfs-variable">S4: Setting the $LFS variable</h2>
<p>Set the $LFS variable to point to /mnt/lfs. Of course, if you desire, you may also make it point to a different destination.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#b48ead;">export </span><span style="color:#bf616a;">LFS</span><span>=</span><span style="color:#a3be8c;">/mnt/lfs
</span></code></pre>
<blockquote class="caution">
<p class="alert-title">
<i class="icon"></i>Caution</p>
<p>Make sure that the $LFS variable always points to the correct destination.
It is recommended to always mount the target root partition under /mnt/lfs and set your variable to that.
Failure to do so may lead you to absolutely fuck up your system.</p>
</blockquote>
<blockquote class="tip">
<p class="alert-title">
<i class="icon"></i>Tip</p>
<p>From the LFS handbook:
One way to ensure that the LFS variable is always set is to edit the .bash_profile file in both your personal home directory and in /root/.bash_profile and enter the export command above. In addition, the shell specified in the /etc/passwd file for all users that need the LFS variable must be bash to ensure that the /root/.bash_profile file is incorporated as a part of the login process.</p>
<p>Another consideration is the method that is used to log into the host system. If logging in through a graphical display manager, the user's .bash_profile is not normally used when a virtual terminal is started. In this case, add the export command to the .bashrc file for the user and root. In addition, some distributions use an "if" test, and do not run the remaining .bashrc instructions for a non-interactive bash invocation. Be sure to place the export command ahead of the test for non-interactive use.</p>
</blockquote>
<h2 id="s5-mounting-the-partitions">S5: Mounting the partitions</h2>
<p>Create the mount point and mount the filesystem using the following commands:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">mkdir -pv </span><span>$</span><span style="color:#bf616a;">LFS
</span><span style="color:#bf616a;">mount -v -t</span><span> ext4 /dev/&lt;foo&gt; $</span><span style="color:#bf616a;">LFS
</span><span style="color:#65737e;"># Replace &lt;foo&gt; with the partition name.
</span></code></pre>
<p>If using multiple partitions for TylkoLinux (for example, one for the root and one for the home partition), mount them as followed:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">mkdir -pv </span><span>$</span><span style="color:#bf616a;">LFS
</span><span style="color:#bf616a;">mount -v -t</span><span> ext4 /dev/&lt;xxx&gt; $</span><span style="color:#bf616a;">LFS
</span><span style="color:#bf616a;">mkdir -v </span><span>$</span><span style="color:#bf616a;">LFS</span><span>/home
</span><span style="color:#bf616a;">mount -v -t</span><span> ext4 /dev/&lt;yyy&gt; $</span><span style="color:#bf616a;">LFS</span><span>/home
</span><span style="color:#65737e;"># Replace &lt;foo&gt; and &lt;bar&gt; with the appropriate partition names.
</span></code></pre>
<blockquote class="caution">
<p class="alert-title">
<i class="icon"></i>Caution</p>
<p>The instructions above assume that you are not rebooting your computer during the build. (imagine)
To automatically remount the partition on boot, modify /etc/fstab by adding this line:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">/dev/</span><span>&lt;foo&gt; /mnt/lfs ext4 defaults 1 1
</span></code></pre>
<p>If you use additional (optional) partitions, add them as well.</p>
</blockquote>
<p>If also using swap, mount with the swapon command:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">/sbin/swapon -v</span><span> /dev/&lt;owo&gt;
</span><span style="color:#65737e;"># Replace &lt;owo&gt; with the name of the swap partition.
</span></code></pre>
<h3 id="s5-1-move-bash-bashrc-out-of-the-way">S5.1: Move bash.bashrc out of the way</h3>
<p>Several commercial distributions add an undocumented instantiation of /etc/bash.bashrc to the initialization of bash. This file has the potential to modify the lfs user's environment in ways that can affect the building of critical TylkoLinux (LFS) packages. To make sure the lfs user's environment is clean, check for the presence of /etc/bash.bashrc and, if present, move it out of the way. As the root user, run:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#96b5b4;">[ </span><span>! </span><span style="color:#bf616a;">-e</span><span> /etc/bash.bashrc </span><span style="color:#96b5b4;">] </span><span>|| </span><span style="color:#bf616a;">mv -v</span><span> /etc/bash.bashrc /etc/bash.bashrc.NOUSE
</span></code></pre>
<h2 id="s6-start-the-core-installation-tool">S6: Start the core installation tool</h2>
<p>To start the installer, make sure you're in the same directory as the git repo we cloned, running as the <code>root</code> user, then type the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">./Einrichter-CLI.sh
</span></code></pre>
<p>If this command fails, make sure it has the permissions to be executed by running the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">chmod</span><span> +x ./*.sh
</span></code></pre>
<h3 id="s6-1-download-packages">S6.1: Download packages</h3>
<p>When in the script, you should see the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">[i]</span><span> The colour variables have been set.
</span><span style="color:#bf616a;">Einrichter</span><span> - TylkoLinux Installer Shell $</span><span style="color:#bf616a;">EINRICHTER_VER
</span><span style="color:#bf616a;">The</span><span> script is located at $</span><span style="color:#bf616a;">SCRIPT_DIR
</span><span style="color:#bf616a;">Run</span><span> einrichter.help for commands
</span><span style="color:#bf616a;">einrichter</span><span>&gt;
</span></code></pre>
<p>To download packages and patches to the directory, type in the following function:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter</span><span>&gt; einrichter.installer.pkgs
</span></code></pre>
<p>This action will proceed to download the packages and patches to $LFS/sources, and also the checksums.</p>
<h3 id="s6-2-creating-a-limited-directory-layout">S6.2: Creating a limited directory layout</h3>
<p>Run the following command:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter</span><span>&gt; einrichter.installer.DirLayout
</span></code></pre>
<h2 id="s7-enter-lfs-user">S7: Enter lfs user</h2>
<p>Enter the LFS environment to build the cross toolchain and temporary tools by entering the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter</span><span>&gt; einrichter.installer.SafeUser
</span></code></pre>
<h3 id="s7-1-going-through-pending-steps">S7.1: Going through pending steps</h3>
<p>You are about to build a cross toolchain and temporary tools. You're going to see the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">Einrichter</span><span> is designed to work as an install script where you can resume where you left off. Do NOT skip anything if you have not ran the step yet.
</span><span style="color:#bf616a;">Pending</span><span> step: Setting up environment. Run, skip or quit?
</span></code></pre>
<p>Either type R to run, S to skip or Q to quit.
Do the same for the other remaining quesitons:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">Pending</span><span> step: Setting up toolchain. Run, skip or quit? R
</span><span style="color:#bf616a;">Pending</span><span> step: Installing cross toolchain and packages. Run, skip or quit? R
</span></code></pre>
<p>And eventually...</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">Done!
</span><span style="color:#bf616a;">[i]</span><span> Completed!
</span><span style="color:#bf616a;">[i]</span><span> Finished section installer.SafeUser
</span><span style="color:#bf616a;">einrichter</span><span>&gt;
</span></code></pre>
<p>Before you know it, you're done!
Now HERE begins the real work (insert lqtroll emoji)</p>
<h2 id="s8-actually-building-the-system-itself">S8: Actually building the system itself</h2>
<blockquote class="tip">
<p class="alert-title">
<i class="icon"></i>Tip</p>
<p>Before proceeding with the build,
One way to ensure that the LFS variable is always set is to edit the .bash_profile file in both your personal home directory and in /root/.bash_profile and enter the export command above. In addition, the shell specified in the /etc/passwd file for all users that need the LFS variable must be bash to ensure that the /root/.bash_profile file is incorporated as a part of the login process.</p>
<p>Another consideration is the method that is used to log into the host system. If logging in through a graphical display manager, the user's .bash_profile is not normally used when a virtual terminal is started. In this case, add the export command to the .bashrc file for the user and root. In addition, some distributions use an "if" test, and do not run the remaining .bashrc instructions for a non-interactive bash invocation. Be sure to place the export command ahead of the test for non-interactive use.</p>
</blockquote>
<p>Now that you finished that section, enter the chroot environment like this:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter</span><span>&gt; einrichter.installer.chroot
</span></code></pre>
<p>This command changes ownership of the commands under $LFS from the user <code>lfs</code> to <code>root</code>
It also mounts the virtual kernel file systems.
Then, it chroots you into the bash shell. Continue the installer by running the following command inside of the chroot:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> /Einrichter-in-chroot.sh
</span></code></pre>
<p>This boots you into the eic shell.
Run the following commands:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.dirs.create </span><span style="color:#65737e;"># Creates necessary directories
</span><span>einrichter/eic&gt; eic.essentials.create </span><span style="color:#65737e;"># Creates necessary tools
</span><span>einrichter/eic&gt; eic.essentials.install </span><span style="color:#65737e;"># Installs the tools
</span><span>einrichter/eic&gt; eic.clean </span><span style="color:#65737e;"># Clean up the environment
</span></code></pre>
<p>Build the system by running the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.system.build
</span></code></pre>
<p>GCC, due to its nature of taking so long to build, gets its own function:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.system.build.gcc
</span></code></pre>
<p>Continue building as if nothing happened</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.system.build.continue
</span></code></pre>
<h3 id="s8-1-strip-system-optional">S8.1: Strip system (optional)</h3>
<p>Done after so long? If you don't plan on doing any debugging on the system software/aren't that much of a programmer, you can remove debugging symbols and unnecessary symbol table entries from binaries and libraries.
This frees up about 2GB(?) on the system.
To do so, run the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.strip
</span></code></pre>
<h3 id="s8-2-cleaning-up">S8.2: Cleaning up</h3>
<p>Finally, after all of that, clean up extra leftovers and the tester account by running this command:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.system.build.clean
</span></code></pre>
<h2 id="s9-setting-up-the-system">S9: Setting up the system</h2>
<p>You are now in the stage where you set up your system and actually make an attempt at making your system bootable!</p>
<h3 id="s9-1-networking">S9.1: Networking</h3>
<p>(This section only applies if a network card is to be configured.)</p>
<h4 id="s9-1-1-network-device-naming">S9.1.1: Network Device Naming</h4>
<p><blockquote class="tip">
<p class="alert-title">
<i class="icon"></i>Tip</p>
<p>Modified from the LFS handbook: The interface names depend on the implementation and configuration of the udev daemon running on the system. The udev daemon for TylkoLinux (well, LFS) (systemd-udevd) will not run unless the TylkoLinux/LFS system is booted. So it's unreliable to determine the interface names being used in the TylkoLinux system by running those commands on the host distro, even though you are in the chroot environment.</p>
</blockquote>
Udev normally assigns network card interface names based on physical system characteristics such as enp2s1. If you are not sure what your interface name is, you can always run <code>ip link</code> after you have booted your system.
For most systems, there is only one network interface for each type of connection. For example, the classic interface name for a wired connection is eth0. A wireless connection will usually have the name wifi0 or wlan0.</p>
<p>If you'd like to use classic/customised network names, run the following function and enter the demanded information:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.devicenaming
</span><span style="color:#bf616a;">[i]</span><span> Enter MAC address of desired device: SN:UG:N0:0K:FR
</span><span style="color:#bf616a;">[i]</span><span> Enter the desired name of your interface: nasaethernet1
</span><span style="color:#65737e;"># Those are examples, not things you should actually enter!! Replace those with the actual info
</span></code></pre>
<h4 id="s9-1-2-static-ip-configuration">S9.1.2: Static IP configuration</h4>
<p>This makes a basic config file for a Static IP setup</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.staticip
</span><span style="color:#bf616a;">[i]</span><span> Enter the name of the configured interface: nasaethernet1 </span><span style="color:#65737e;"># example
</span><span style="color:#bf616a;">[?]</span><span> Add DNS? If no, type N. If yes, type DNS address.
</span><span>&gt; Y </span><span style="color:#65737e;"># example
</span><span style="color:#b48ead;">[</span><span>?</span><span style="color:#b48ead;">] </span><span style="color:#bf616a;">Add</span><span> domain? If no, type N. If yes, type domain name.
</span><span>&gt; N </span><span style="color:#65737e;"># example
</span><span style="color:#b48ead;">[</span><span>i</span><span style="color:#b48ead;">] </span><span style="color:#bf616a;">Skipped</span><span> domain addition. </span><span style="color:#65737e;"># example
</span></code></pre>
<h4 id="s9-1-3-dhcp-configuration">S9.1.3: DHCP configuration</h4>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.dhcp
</span><span style="color:#bf616a;">[i]</span><span> Enter the name of the configured interface: itsthesamethingagain0 </span><span style="color:#65737e;"># example
</span></code></pre>
<h4 id="s9-1-4-etc-resolv-conf">S9.1.4: /etc/resolv.conf</h4>
<blockquote class="tip">
<p class="alert-title">
<i class="icon"></i>Tip</p>
<p>From the LFS handbook: If using methods incompatible with systemd-resolved to configure your network interfaces (ex: ppp, etc.), or if using any type of local resolver (ex: bind, dnsmasq, unbound, etc.), or any other software that generates an /etc/resolv.conf (ex: a resolvconf program other than the one provided by systemd), the systemd-resolved service should not be used.</p>
<p>To switch settings about whether this should be allowed or not, run the command below ↓</p>
</blockquote>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.systemd.resolve &lt;on/off&gt;
</span><span style="color:#bf616a;">[i]</span><span> Disabling/Enabling systemd-resolved...
</span></code></pre>
<h5 id="s9-1-4-1-static-resolv-conf">S9.1.4.1: Static resolv.conf</h5>
<p>Want to create a static file? Here:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.staticresolver
</span><span style="color:#bf616a;">[?]</span><span> Add domain? If no, type N. If yes, type domain name.
</span><span>&gt; N </span><span style="color:#65737e;"># example
</span><span style="color:#b48ead;">[</span><span>?</span><span style="color:#b48ead;">] </span><span style="color:#bf616a;">Add</span><span> primary nameserver? If no, type N. If yes, type nameserver name.
</span><span>&gt; N
</span><span style="color:#bf616a;">[i]</span><span> Skipped primary nameserver addition.
</span><span style="color:#bf616a;">[?]</span><span> Add secondary nameserver? If no, type N. If yes, type nameserver name.
</span><span>&gt; </span><span style="color:#d08770;">1</span><span style="color:#bf616a;">.2.3.4 </span><span style="color:#65737e;"># example
</span></code></pre>
<h4 id="s9-1-5-hostname">S9.1.5: Hostname</h4>
<p>To configure the hostname, enter the following command:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">einrichter/eic</span><span>&gt; eic.config.network.hostname &lt;hostname&gt;
</span><span style="color:#65737e;"># Replace &lt;hostname&gt; with the desired hostname
</span></code></pre>
<h4 id="s9-1-6-customising-the-etc-hosts-file">S9.1.6: Customising the /etc/hosts file</h4>
<p>Remind me to work on this section.</p>
<h1 id="under-construction">under construction!!!</h1>
</article>
<span id="search-index" class="hidden">https://rootsource.cc/search_index.en.json</span>
<span id="more-matches-text" class="hidden">$MATCHES more matches</span>
</main>
<footer id="site-footer">
<p>raíz1.noho.st owns this website</p>
<p>
<small>Powered by <a class="link external" href="https://www.getzola.org" rel="">Zola</a> and <a class="link external" href="https://duckquill.daudix.one" rel="">Duckquill</a>
</small>
</p>
</footer>
</body>
</html>

18
public/_NOTindex.md.old Normal file
View file

@ -0,0 +1,18 @@
+++
template = "index.html"
title = "Hello World!"
+++
Hi!
There is your great future static site build with Zola ^w^
Check [the docs](https://www.getzola.org/documentation/getting-started/overview/) to get started!
## Tips
- Your Zola is installed in `/var/www/zola`
- Your content should be in `/var/www/zola/content`
- Your config file is `/var/www/zola/config.toml` (see [config docs](https://www.getzola.org/documentation/getting-started/configuration/))
- [Choose a theme](https://www.getzola.org/themes/), install it in `/var/www/zola/themes`, then configure it in your `config.toml` file
- This website will be automatically updated each time you modify something inside the `content`, `static`, `templates` or `themes` folders or the `config.toml` file!

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

1
public/auto-render.min.js vendored Normal file
View file

@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={771:function(t){t.exports=e}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={exports:{}};return t[e](i,i.exports,r),i.exports}r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var o={};return function(){r.d(o,{default:function(){return d}});var e=r(771),t=r.n(e);const n=function(e,t,n){let r=n,o=0;const i=e.length;for(;r<t.length;){const n=t[r];if(o<=0&&t.slice(r,r+i)===e)return r;"\\"===n?r++:"{"===n?o++:"}"===n&&o--,r++}return-1},i=/^\\begin{/;var a=function(e,t){let r;const o=[],a=new RegExp("("+t.map((e=>e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))).join("|")+")");for(;r=e.search(a),-1!==r;){r>0&&(o.push({type:"text",data:e.slice(0,r)}),e=e.slice(r));const a=t.findIndex((t=>e.startsWith(t.left)));if(r=n(t[a].right,e,t[a].left.length),-1===r)break;const l=e.slice(0,r+t[a].right.length),s=i.test(l)?l:e.slice(t[a].left.length,r);o.push({type:"math",data:s,rawData:l,display:t[a].display}),e=e.slice(r+t[a].right.length)}return""!==e&&o.push({type:"text",data:e}),o};const l=function(e,n){const r=a(e,n.delimiters);if(1===r.length&&"text"===r[0].type)return null;const o=document.createDocumentFragment();for(let e=0;e<r.length;e++)if("text"===r[e].type)o.appendChild(document.createTextNode(r[e].data));else{const i=document.createElement("span");let a=r[e].data;n.displayMode=r[e].display;try{n.preProcess&&(a=n.preProcess(a)),t().render(a,i,n)}catch(i){if(!(i instanceof t().ParseError))throw i;n.errorCallback("KaTeX auto-render: Failed to parse `"+r[e].data+"` with ",i),o.appendChild(document.createTextNode(r[e].rawData));continue}o.appendChild(i)}return o},s=function(e,t){for(let n=0;n<e.childNodes.length;n++){const r=e.childNodes[n];if(3===r.nodeType){let o=r.textContent,i=r.nextSibling,a=0;for(;i&&i.nodeType===Node.TEXT_NODE;)o+=i.textContent,i=i.nextSibling,a++;const s=l(o,t);if(s){for(let e=0;e<a;e++)r.nextSibling.remove();n+=s.childNodes.length-1,e.replaceChild(s,r)}else n+=a}else if(1===r.nodeType){const e=" "+r.className+" ";-1===t.ignoredTags.indexOf(r.nodeName.toLowerCase())&&t.ignoredClasses.every((t=>-1===e.indexOf(" "+t+" ")))&&s(r,t)}}};var d=function(e,t){if(!e)throw new Error("No element provided to render");const n={};for(const e in t)t.hasOwnProperty(e)&&(n[e]=t[e]);n.delimiters=n.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],n.ignoredTags=n.ignoredTags||["script","noscript","style","textarea","pre","code","option"],n.ignoredClasses=n.ignoredClasses||[],n.errorCallback=n.errorCallback||console.error,n.macros=n.macros||{},s(e,n)}}(),o=o.default}()}));

BIN
public/card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

27
public/closable.js Normal file
View file

@ -0,0 +1,27 @@
const closable = document.querySelectorAll("details.closable");
closable.forEach((detail) => {
detail.addEventListener("toggle", () => {
if (detail.open) setTargetDetail(detail);
});
});
function setTargetDetail(targetDetail) {
closable.forEach((detail) => {
if (detail !== targetDetail) {
detail.open = false;
}
});
}
document.addEventListener("click", function (event) {
const isClickInsideDetail = [...closable].some((detail) =>
detail.contains(event.target)
);
if (!isClickInsideDetail) {
closable.forEach((detail) => {
detail.open = false;
});
}
});

406
public/comments.js Normal file
View file

@ -0,0 +1,406 @@
// Taken from https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/
// Attachment, card, and spoiler code taken from https://github.com/cassidyjames/cassidyjames.github.io/blob/99782788a7e3ba3cc52d6803010873abd1b02b9e/_includes/comments.html#L251-L296
let blogPostAuthorText = document.getElementById("blog-post-author-text").textContent;
let boostsFromText = document.getElementById("boosts-from-text").textContent;
let dateLocale = document.getElementById("date-locale").textContent;
let favesFromText = document.getElementById("faves-from-text").textContent;
let host = document.getElementById("host").textContent;
let id = document.getElementById("id").textContent;
let lazyAsyncImage = document.getElementById("lazy-async-image").textContent;
let loadingText = document.getElementById("loading-text").textContent;
let noCommentsText = document.getElementById("no-comments-text").textContent;
let relAttributes = document.getElementById("rel-attributes").textContent;
let reloadText = document.getElementById("reload-text").textContent;
let sensitiveText = document.getElementById("sensitive-text").textContent;
let user = document.getElementById("user").textContent;
let viewCommentText = document.getElementById("view-comment-text").textContent;
let viewProfileText = document.getElementById("view-profile-text").textContent;
document.getElementById("load-comments").addEventListener("click", loadComments);
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function emojify(input, emojis) {
let output = input;
emojis.forEach((emoji) => {
let picture = document.createElement("picture");
let source = document.createElement("source");
source.setAttribute("srcset", escapeHtml(emoji.url));
source.setAttribute("media", "(prefers-reduced-motion: no-preference)");
let img = document.createElement("img");
img.className = "emoji";
img.setAttribute("src", escapeHtml(emoji.static_url));
img.setAttribute("alt", `:${emoji.shortcode}:`);
img.setAttribute("title", `:${emoji.shortcode}:`);
if (lazyAsyncImage == "true") {
img.setAttribute("decoding", "async");
img.setAttribute("loading", "lazy");
}
picture.appendChild(source);
picture.appendChild(img);
output = output.replace(`:${emoji.shortcode}:`, picture.outerHTML);
});
return output;
}
function loadComments() {
let commentsWrapper = document.getElementById("comments-wrapper");
commentsWrapper.innerHTML = "";
let loadCommentsButton = document.getElementById("load-comments");
loadCommentsButton.innerHTML = loadingText;
loadCommentsButton.disabled = true;
fetch(`https://${host}/api/v1/statuses/${id}/context`)
.then(function (response) {
return response.json();
})
.then(function (data) {
let descendants = data["descendants"];
if (
descendants &&
Array.isArray(descendants) &&
descendants.length > 0
) {
commentsWrapper.innerHTML = "";
descendants.forEach(function (status) {
console.log(descendants);
if (status.account.display_name.length > 0) {
status.account.display_name = escapeHtml(
status.account.display_name
);
status.account.display_name = emojify(
status.account.display_name,
status.account.emojis
);
} else {
status.account.display_name = status.account.username;
}
let instance = "";
if (status.account.acct.includes("@")) {
instance = status.account.acct.split("@")[1];
} else {
instance = host;
}
const isReply = status.in_reply_to_id !== id;
let op = false;
if (status.account.acct == user) {
op = true;
}
status.content = emojify(status.content, status.emojis);
let comment = document.createElement("article");
comment.id = `comment-${status.id}`;
comment.className = isReply ? "comment comment-reply" : "comment";
comment.setAttribute("itemprop", "comment");
comment.setAttribute("itemtype", "http://schema.org/Comment");
let avatarSource = document.createElement("source");
avatarSource.setAttribute(
"srcset",
escapeHtml(status.account.avatar)
);
avatarSource.setAttribute(
"media",
"(prefers-reduced-motion: no-preference)"
);
let avatarImg = document.createElement("img");
avatarImg.className = "avatar";
avatarImg.setAttribute(
"src",
escapeHtml(status.account.avatar_static)
);
avatarImg.setAttribute(
"alt",
`@${status.account.username}@${instance} avatar`
);
if (lazyAsyncImage == "true") {
avatarImg.setAttribute("decoding", "async");
avatarImg.setAttribute("loading", "lazy");
}
let avatarPicture = document.createElement("picture");
avatarPicture.appendChild(avatarSource);
avatarPicture.appendChild(avatarImg);
let avatar = document.createElement("a");
avatar.className = "avatar-link";
avatar.setAttribute("href", status.account.url);
avatar.setAttribute("rel", relAttributes);
avatar.setAttribute(
"title",
`${viewProfileText} @${status.account.username}@${instance}`
);
avatar.appendChild(avatarPicture);
comment.appendChild(avatar);
let instanceBadge = document.createElement("a");
instanceBadge.className = "instance";
instanceBadge.setAttribute("href", status.account.url);
instanceBadge.setAttribute(
"title",
`@${status.account.username}@${instance}`
);
instanceBadge.setAttribute("rel", relAttributes);
instanceBadge.textContent = instance;
let display = document.createElement("span");
display.className = "display";
display.setAttribute("itemprop", "author");
display.setAttribute("itemtype", "http://schema.org/Person");
display.innerHTML = status.account.display_name;
let header = document.createElement("header");
header.className = "author";
header.appendChild(display);
header.appendChild(instanceBadge);
comment.appendChild(header);
let permalink = document.createElement("a");
permalink.setAttribute("href", status.url);
permalink.setAttribute("itemprop", "url");
permalink.setAttribute("title", `${viewCommentText} ${instance}`);
permalink.setAttribute("rel", relAttributes);
permalink.textContent = new Date(
status.created_at
).toLocaleString(dateLocale, {
dateStyle: "long",
timeStyle: "short",
});
let timestamp = document.createElement("time");
timestamp.setAttribute("datetime", status.created_at);
timestamp.appendChild(permalink);
permalink.classList.add("external");
comment.appendChild(timestamp);
let main = document.createElement("main");
main.setAttribute("itemprop", "text");
if (status.sensitive == true || status.spoiler_text != "") {
let summary = document.createElement("summary");
if (status.spoiler_text == "") {
status.spoiler_text == sensitiveText;
}
summary.innerHTML = status.spoiler_text;
let spoiler = document.createElement("details");
spoiler.appendChild(summary);
spoiler.innerHTML += status.content;
main.appendChild(spoiler);
} else {
main.innerHTML = status.content;
}
comment.appendChild(main);
let attachments = status.media_attachments;
let SUPPORTED_MEDIA = ["image", "video", "gifv", "audio"];
let media = document.createElement("div");
media.className = "attachments";
if (
attachments &&
Array.isArray(attachments) &&
attachments.length > 0
) {
attachments.forEach((attachment) => {
if (SUPPORTED_MEDIA.includes(attachment.type)) {
let mediaElement;
switch (attachment.type) {
case "image":
mediaElement = document.createElement("img");
mediaElement.setAttribute("src", attachment.preview_url);
if (attachment.description != null) {
mediaElement.setAttribute("alt", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
if (lazyAsyncImage == "true") {
mediaElement.setAttribute("decoding", "async");
mediaElement.setAttribute("loading", "lazy");
}
if (status.sensitive == true) {
mediaElement.classList.add("spoiler");
}
media.appendChild(mediaElement);
break;
case "video":
mediaElement = document.createElement("video");
mediaElement.setAttribute("src", attachment.url);
mediaElement.setAttribute("controls", "");
if (attachment.description != null) {
mediaElement.setAttribute("aria-title", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
if (status.sensitive == true) {
mediaElement.classList.add("spoiler");
}
media.appendChild(mediaElement);
break;
case "gifv":
mediaElement = document.createElement("video");
mediaElement.setAttribute("src", attachment.url);
mediaElement.setAttribute("autoplay", "");
mediaElement.setAttribute("playsinline", "");
mediaElement.setAttribute("loop", "");
if (attachment.description != null) {
mediaElement.setAttribute("aria-title", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
if (status.sensitive == true) {
mediaElement.classList.add("spoiler");
}
media.appendChild(mediaElement);
break;
case "audio":
mediaElement = document.createElement("audio");
mediaElement.setAttribute("src", attachment.url);
mediaElement.setAttribute("controls", "");
if (attachment.description != null) {
mediaElement.setAttribute("aria-title", attachment.description);
mediaElement.setAttribute("title", attachment.description);
}
media.appendChild(mediaElement);
break;
}
let mediaLink = document.createElement("a");
mediaLink.setAttribute("href", attachment.url);
mediaLink.setAttribute("rel", relAttributes);
mediaLink.appendChild(mediaElement);
media.appendChild(mediaLink);
}
});
comment.appendChild(media);
}
let interactions = document.createElement("footer");
let boosts = document.createElement("a");
boosts.className = "boosts";
boosts.setAttribute("href", `${status.url}/reblogs`);
boosts.setAttribute("title", `${boostsFromText}`.replace("$INSTANCE", instance));
let boostsIcon = document.createElement("i");
boostsIcon.className = "icon";
boosts.appendChild(boostsIcon);
boosts.insertAdjacentHTML('beforeend', ` ${status.reblogs_count}`);
interactions.appendChild(boosts);
let faves = document.createElement("a");
faves.className = "faves";
faves.setAttribute("href", `${status.url}/favourites`);
faves.setAttribute("title", `${favesFromText}`.replace("$INSTANCE", instance));
let favesIcon = document.createElement("i");
favesIcon.className = "icon";
faves.appendChild(favesIcon);
faves.insertAdjacentHTML('beforeend', ` ${status.favourites_count}`);
interactions.appendChild(faves);
comment.appendChild(interactions);
if (status.card != null) {
let cardFigure = document.createElement("figure");
if (status.card.image != null) {
let cardImg = document.createElement("img");
cardImg.setAttribute("src", status.card.image);
cardImg.classList.add("no-hover");
cardFigure.appendChild(cardImg);
}
let cardCaption = document.createElement("figcaption");
let cardTitle = document.createElement("strong");
cardTitle.innerHTML = status.card.title;
cardCaption.appendChild(cardTitle);
if (status.card.description != null && status.card.description.length > 0) {
let cardDescription = document.createElement("p");
cardDescription.innerHTML = status.card.description;
cardCaption.appendChild(cardDescription);
}
cardFigure.appendChild(cardCaption);
let card = document.createElement("a");
card.className = "card";
card.setAttribute("href", status.card.url);
card.setAttribute("rel", relAttributes);
card.appendChild(cardFigure);
comment.appendChild(card);
}
if (op === true) {
comment.classList.add("op");
avatar.classList.add("op");
avatar.setAttribute(
"title",
`${blogPostAuthorText}: ` + avatar.getAttribute("title")
);
instanceBadge.classList.add("op");
instanceBadge.setAttribute(
"title",
`${blogPostAuthorText}: ` + instanceBadge.getAttribute("title")
);
}
commentsWrapper.innerHTML += comment.outerHTML;
});
}
else {
var statusText = document.createElement("p");
statusText.innerHTML = noCommentsText;
statusText.setAttribute("id", "comments-status");
commentsWrapper.appendChild(statusText);
}
loadCommentsButton.innerHTML = reloadText;
})
.catch(function (error) {
console.error('Error loading comments:', error);
})
.finally(function () {
loadCommentsButton.disabled = false;
});
}

57
public/copy-button.js Normal file
View file

@ -0,0 +1,57 @@
// Based on https://www.roboleary.net/2022/01/13/copy-code-to-clipboard-blog.html
document.addEventListener("DOMContentLoaded", function () {
let blocks = document.querySelectorAll("pre[class^='language-']");
blocks.forEach((block) => {
if (navigator.clipboard) {
// Code block header title
let title = document.createElement("span");
let lang = block.getAttribute("data-lang");
title.innerHTML = lang;
// Copy button icon
let icon = document.createElement("i");
icon.classList.add("icon");
// Copy button
let button = document.createElement("button");
let copyCodeText = document.getElementById("copy-code-text").textContent;
button.setAttribute("title", copyCodeText)
button.appendChild(icon);
// Code block header
let header = document.createElement("div");
header.classList.add("header");
header.appendChild(title);
header.appendChild(button);
// Container that holds header and the code block itself
let container = document.createElement("div");
container.classList.add("pre-container");
container.appendChild(header);
// Move code block into the container
block.parentNode.insertBefore(container, block);
container.appendChild(block);
button.addEventListener("click", async () => {
await copyCode(block, header, button); // Pass the button here
});
}
});
async function copyCode(block, header, button) {
let code = block.querySelector("code");
let text = code.innerText;
await navigator.clipboard.writeText(text);
header.classList.add("active");
button.setAttribute("disabled", true);
header.addEventListener("animationend", () => {
header.classList.remove("active");
button.removeAttribute("disabled");
}, { once: true });
}
});

271
public/count.js Normal file
View file

@ -0,0 +1,271 @@
// GoatCounter: https://www.goatcounter.com
// This file is released under the ISC license: https://opensource.org/licenses/ISC
;(function() {
'use strict';
if (window.goatcounter && window.goatcounter.vars) // Compatibility with very old version; do not use.
window.goatcounter = window.goatcounter.vars
else
window.goatcounter = window.goatcounter || {}
// Load settings from data-goatcounter-settings.
var s = document.querySelector('script[data-goatcounter]')
if (s && s.dataset.goatcounterSettings) {
try { var set = JSON.parse(s.dataset.goatcounterSettings) }
catch (err) { console.error('invalid JSON in data-goatcounter-settings: ' + err) }
for (var k in set)
if (['no_onload', 'no_events', 'allow_local', 'allow_frame', 'path', 'title', 'referrer', 'event'].indexOf(k) > -1)
window.goatcounter[k] = set[k]
}
var enc = encodeURIComponent
// Get all data we're going to send off to the counter endpoint.
var get_data = function(vars) {
var data = {
p: (vars.path === undefined ? goatcounter.path : vars.path),
r: (vars.referrer === undefined ? goatcounter.referrer : vars.referrer),
t: (vars.title === undefined ? goatcounter.title : vars.title),
e: !!(vars.event || goatcounter.event),
s: [window.screen.width, window.screen.height, (window.devicePixelRatio || 1)],
b: is_bot(),
q: location.search,
}
var rcb, pcb, tcb // Save callbacks to apply later.
if (typeof(data.r) === 'function') rcb = data.r
if (typeof(data.t) === 'function') tcb = data.t
if (typeof(data.p) === 'function') pcb = data.p
if (is_empty(data.r)) data.r = document.referrer
if (is_empty(data.t)) data.t = document.title
if (is_empty(data.p)) data.p = get_path()
if (rcb) data.r = rcb(data.r)
if (tcb) data.t = tcb(data.t)
if (pcb) data.p = pcb(data.p)
return data
}
// Check if a value is "empty" for the purpose of get_data().
var is_empty = function(v) { return v === null || v === undefined || typeof(v) === 'function' }
// See if this looks like a bot; there is some additional filtering on the
// backend, but these properties can't be fetched from there.
var is_bot = function() {
// Headless browsers are probably a bot.
var w = window, d = document
if (w.callPhantom || w._phantom || w.phantom)
return 150
if (w.__nightmare)
return 151
if (d.__selenium_unwrapped || d.__webdriver_evaluate || d.__driver_evaluate)
return 152
if (navigator.webdriver)
return 153
return 0
}
// Object to urlencoded string, starting with a ?.
var urlencode = function(obj) {
var p = []
for (var k in obj)
if (obj[k] !== '' && obj[k] !== null && obj[k] !== undefined && obj[k] !== false)
p.push(enc(k) + '=' + enc(obj[k]))
return '?' + p.join('&')
}
// Show a warning in the console.
var warn = function(msg) {
if (console && 'warn' in console)
console.warn('goatcounter: ' + msg)
}
// Get the endpoint to send requests to.
var get_endpoint = function() {
var s = document.querySelector('script[data-goatcounter]')
if (s && s.dataset.goatcounter)
return s.dataset.goatcounter
return (goatcounter.endpoint || window.counter) // counter is for compat; don't use.
}
// Get current path.
var get_path = function() {
var loc = location,
c = document.querySelector('link[rel="canonical"][href]')
if (c) { // May be relative or point to different domain.
var a = document.createElement('a')
a.href = c.href
if (a.hostname.replace(/^www\./, '') === location.hostname.replace(/^www\./, ''))
loc = a
}
return (loc.pathname + loc.search) || '/'
}
// Run function after DOM is loaded.
var on_load = function(f) {
if (document.body === null)
document.addEventListener('DOMContentLoaded', function() { f() }, false)
else
f()
}
// Filter some requests that we (probably) don't want to count.
goatcounter.filter = function() {
if ('visibilityState' in document && document.visibilityState === 'prerender')
return 'visibilityState'
if (!goatcounter.allow_frame && location !== parent.location)
return 'frame'
if (!goatcounter.allow_local && location.hostname.match(/(localhost$|^127\.|^10\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^192\.168\.|^0\.0\.0\.0$)/))
return 'localhost'
if (!goatcounter.allow_local && location.protocol === 'file:')
return 'localfile'
if (localStorage && localStorage.getItem('skipgc') === 't')
return 'disabled with #toggle-goatcounter'
return false
}
// Get URL to send to GoatCounter.
window.goatcounter.url = function(vars) {
var data = get_data(vars || {})
if (data.p === null) // null from user callback.
return
data.rnd = Math.random().toString(36).substr(2, 5) // Browsers don't always listen to Cache-Control.
var endpoint = get_endpoint()
if (!endpoint)
return warn('no endpoint found')
return endpoint + urlencode(data)
}
// Count a hit.
window.goatcounter.count = function(vars) {
var f = goatcounter.filter()
if (f)
return warn('not counting because of: ' + f)
var url = goatcounter.url(vars)
if (!url)
return warn('not counting because path callback returned null')
if (!navigator.sendBeacon(url)) {
// This mostly fails due to being blocked by CSP; try again with an
// image-based fallback.
var img = document.createElement('img')
img.src = url
img.style.position = 'absolute' // Affect layout less.
img.style.bottom = '0px'
img.style.width = '1px'
img.style.height = '1px'
img.loading = 'eager'
img.setAttribute('alt', '')
img.setAttribute('aria-hidden', 'true')
var rm = function() { if (img && img.parentNode) img.parentNode.removeChild(img) }
img.addEventListener('load', rm, false)
document.body.appendChild(img)
}
}
// Get a query parameter.
window.goatcounter.get_query = function(name) {
var s = location.search.substr(1).split('&')
for (var i = 0; i < s.length; i++)
if (s[i].toLowerCase().indexOf(name.toLowerCase() + '=') === 0)
return s[i].substr(name.length + 1)
}
// Track click events.
window.goatcounter.bind_events = function() {
if (!document.querySelectorAll) // Just in case someone uses an ancient browser.
return
var send = function(elem) {
return function() {
goatcounter.count({
event: true,
path: (elem.dataset.goatcounterClick || elem.name || elem.id || ''),
title: (elem.dataset.goatcounterTitle || elem.title || (elem.innerHTML || '').substr(0, 200) || ''),
referrer: (elem.dataset.goatcounterReferrer || elem.dataset.goatcounterReferral || ''),
})
}
}
Array.prototype.slice.call(document.querySelectorAll("*[data-goatcounter-click]")).forEach(function(elem) {
if (elem.dataset.goatcounterBound)
return
var f = send(elem)
elem.addEventListener('click', f, false)
elem.addEventListener('auxclick', f, false) // Middle click.
elem.dataset.goatcounterBound = 'true'
})
}
// Add a "visitor counter" frame or image.
window.goatcounter.visit_count = function(opt) {
on_load(function() {
opt = opt || {}
opt.type = opt.type || 'html'
opt.append = opt.append || 'body'
opt.path = opt.path || get_path()
opt.attr = opt.attr || {width: '200', height: (opt.no_branding ? '60' : '80')}
opt.attr['src'] = get_endpoint() + 'er/' + enc(opt.path) + '.' + enc(opt.type) + '?'
if (opt.no_branding) opt.attr['src'] += '&no_branding=1'
if (opt.style) opt.attr['src'] += '&style=' + enc(opt.style)
if (opt.start) opt.attr['src'] += '&start=' + enc(opt.start)
if (opt.end) opt.attr['src'] += '&end=' + enc(opt.end)
var tag = {png: 'img', svg: 'img', html: 'iframe'}[opt.type]
if (!tag)
return warn('visit_count: unknown type: ' + opt.type)
if (opt.type === 'html') {
opt.attr['frameborder'] = '0'
opt.attr['scrolling'] = 'no'
}
var d = document.createElement(tag)
for (var k in opt.attr)
d.setAttribute(k, opt.attr[k])
var p = document.querySelector(opt.append)
if (!p)
return warn('visit_count: append not found: ' + opt.append)
p.appendChild(d)
})
}
// Make it easy to skip your own views.
if (location.hash === '#toggle-goatcounter') {
if (localStorage.getItem('skipgc') === 't') {
localStorage.removeItem('skipgc', 't')
alert('GoatCounter tracking is now ENABLED in this browser.')
}
else {
localStorage.setItem('skipgc', 't')
alert('GoatCounter tracking is now DISABLED in this browser until ' + location + ' is loaded again.')
}
}
if (!goatcounter.no_onload)
on_load(function() {
// 1. Page is visible, count request.
// 2. Page is not yet visible; wait until it switches to 'visible' and count.
// See #487
if (!('visibilityState' in document) || document.visibilityState === 'visible')
goatcounter.count()
else {
var f = function(e) {
if (document.visibilityState !== 'visible')
return
document.removeEventListener('visibilitychange', f)
goatcounter.count()
}
document.addEventListener('visibilitychange', f)
}
if (!goatcounter.no_events)
goatcounter.bind_events()
})
})();

10
public/elasticlunr.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

1
public/fonts.css Normal file
View file

@ -0,0 +1 @@
@font-face{font-style:normal;font-weight:100 900;src:url("fonts/InterVariable.woff2") format("woff2");font-family:"Inter Variable";font-display:swap}@font-face{font-style:italic;font-weight:100 900;src:url("fonts/InterVariable-Italic.woff2") format("woff2");font-family:"Inter Variable";font-display:swap}@font-face{font-style:normal;font-weight:100 900;src:url("fonts/JetBrainsMono.woff2") format("woff2");font-family:"JetBrains Mono";font-display:swap}@font-face{font-style:italic;font-weight:100 900;src:url("fonts/JetBrainsMono-Italic.woff2") format("woff2");font-family:"JetBrains Mono";font-display:swap}body{font-family:"Inter Variable",var(--font-system-ui),var(--font-emoji)}h1,h2,h3,h4,h5,h6{font-weight:bold;font-family:"Inter Variable",var(--font-system-ui),var(--font-emoji)}h1{font-weight:900}pre,code,kbd,samp{font-family:"JetBrains Mono",var(--font-monospace-code)}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

9
public/fuse.js Normal file

File diff suppressed because one or more lines are too long

88
public/index.html Normal file
View file

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" >
<head>
<!-- 2025-02-01 Sat 04:04 -->
<meta charset="UTF-8" />
<meta name="description" content="Well, get on this site and find out." />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#9a9996" />
<title>RSCC</title>
<link rel="canonical" href="https://rootsource.cc/" /><link rel="icon" type="image/png" href="https://rootsource.cc/favicon.png" />
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="https://rootsource.cc/apple-touch-icon.png" />
<style type="text/css">
:root {--accent-color: #6f8396;--contrast-color: #fff;}</style>
<link type="text/css" rel="stylesheet" href="https://rootsource.cc/style.css" />
<script type="text/javascript" defer src="https://rootsource.cc/closable.js"></script>
<meta property="og:site_name" content="RSCC" />
<meta property="og:title" content="RSCC" />
<meta property="og:url" content="https://rootsource.cc/" />
<meta property="og:description" content="Well, get on this site and find out." />
<meta property="og:image" content="https://rootsource.cc/card.png" />
<meta property="og:locale" content="en_US" />
</head>
<body>
<header id="site-nav">
<nav>
<a href="#main-content" tabindex="0">
Skip to Main Content
</a>
<ul>
<li id="home">
<a href="https://rootsource.cc"class="active">
<i class="icon"></i>RSCC</a>
</li>
<li class="divider"></li>
<li>
<a href="https://rootsource.cc/Articles">Articles</a>
</li>
<li id="search">
<button id="search-toggle" class="circle" title="Search">
<i class="icon"></i>
</button>
</li>
</ul>
</nav>
<div id="search-container">
<label for="search-bar" class="visually-hidden">Search</label>
<input id="search-bar" placeholder="Search for…" autocomplete="off" type="search" disabled>
<div id="search-results-container">
<div id="search-results"></div>
</div>
</div>
</header>
<main id="main-content">
<h1 id="rootsourcecc">RootSourceCC</h1>
<p>Welcome to RootSourceCC! You could technically call this: "The child of Raíz1, Icycoide and Costmiku"</p>
<p>With the ownership by Raíz1, hosted on and also being in charge of Costmiku, and hosting Icycoide's stuff!</p>
<p>Links:</p>
<ul>
<li><a href="https://git.rootsource.cc">Alpsource (Git forge)</a></li>
</ul>
<p>-<a href="https://raiz1.noho.st">Raíz1</a> - <a href="https://icycoide.github.io">Icycoide</a> 2025.</p>
<span id="search-index" class="hidden">https://rootsource.cc/search_index.en.json</span>
<span id="more-matches-text" class="hidden">$MATCHES more matches</span>
</main>
<footer id="site-footer">
<p>raíz1.noho.st owns this website</p>
<p>
<small>Powered by <a class="link external" href="https://www.getzola.org" rel="">Zola</a> and <a class="link external" href="https://duckquill.daudix.one" rel="">Duckquill</a>
</small>
</p>
</footer>
</body>
</html>

8
public/katex-init.js Normal file
View file

@ -0,0 +1,8 @@
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
],
});
});

1209
public/katex.css Normal file

File diff suppressed because it is too large Load diff

1
public/katex.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

4
public/robots.txt Normal file
View file

@ -0,0 +1,4 @@
User-agent: *
Disallow:
Allow: /
Sitemap: https://rootsource.cc/sitemap.xml

View file

@ -0,0 +1,209 @@
// Based on https://github.com/getzola/zola/blob/1ac1231de1e342bbaf4d7a51a8a9a40ea152e246/docs/static/search.js
function debounce(func, wait) {
var timeout;
return function () {
var context = this;
var args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function () {
timeout = null;
func.apply(context, args);
}, wait);
};
}
// Taken from mdbook
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <b>.
function makeTeaser(body, terms) {
var TERM_WEIGHT = 40;
var NORMAL_WORD_WEIGHT = 2;
var FIRST_WORD_WEIGHT = 8;
var TEASER_MAX_WORDS = 30;
var stemmedTerms = terms.map(function (w) {
return elasticlunr.stemmer(w.toLowerCase());
});
var termFound = false;
var index = 0;
var weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
var sentences = body.toLowerCase().split(". ");
for (var i in sentences) {
var words = sentences[i].split(" ");
var value = FIRST_WORD_WEIGHT;
for (var j in words) {
var word = words[j];
if (word.length > 0) {
for (var k in stemmedTerms) {
if (elasticlunr.stemmer(word).startsWith(stemmedTerms[k])) {
value = TERM_WEIGHT;
termFound = true;
}
}
weighted.push([word, value, index]);
value = NORMAL_WORD_WEIGHT;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
var windowWeights = [];
var windowSize = Math.min(weighted.length, TEASER_MAX_WORDS);
// We add a window with all the weights first
var curSum = 0;
for (var i = 0; i < windowSize; i++) {
curSum += weighted[i][1];
}
windowWeights.push(curSum);
for (var i = 0; i < weighted.length - windowSize; i++) {
curSum -= weighted[i][1];
curSum += weighted[i + windowSize][1];
windowWeights.push(curSum);
}
// If we didn't find the term, just pick the first window
var maxSumIndex = 0;
if (termFound) {
var maxFound = 0;
// backwards
for (var i = windowWeights.length - 1; i >= 0; i--) {
if (windowWeights[i] > maxFound) {
maxFound = windowWeights[i];
maxSumIndex = i;
}
}
}
var teaser = [];
var startIndex = weighted[maxSumIndex][2];
for (var i = maxSumIndex; i < maxSumIndex + windowSize; i++) {
var word = weighted[i];
if (startIndex < word[2]) {
// missing text from index to start of `word`
teaser.push(body.substring(startIndex, word[2]));
startIndex = word[2];
}
// add <strong> around search terms
if (word[1] === TERM_WEIGHT) {
teaser.push("<strong>");
}
startIndex = word[2] + word[0].length;
teaser.push(body.substring(word[2], startIndex));
if (word[1] === TERM_WEIGHT) {
teaser.push("</strong>");
}
}
teaser.push("…");
return teaser.join("");
}
function formatSearchResultItem(item, terms) {
return '<div class="item">'
+ `<a href="${item.ref}">${item.doc.title}</a>`
+ `<span>${makeTeaser(item.doc.body, terms)}</span>`
+ '</div>';
}
function initSearch() {
var searchBar = document.getElementById("search-bar");
var searchContainer = document.getElementById("search-container");
var searchResults = document.getElementById("search-results");
var MAX_ITEMS = 10;
var options = {
bool: "AND",
fields: {
title: { boost: 2 },
body: { boost: 1 },
}
};
var currentTerm = "";
var index;
var initIndex = async function () {
if (index === undefined) {
let searchIndex = document.getElementById("search-index").textContent;
index = fetch(searchIndex)
.then(
async function (response) {
return await elasticlunr.Index.load(await response.json());
}
);
}
let res = await index;
return res;
}
searchBar.addEventListener("keyup", debounce(async function () {
var term = searchBar.value.trim();
if (term === currentTerm) {
return;
}
searchResults.style.display = term === "" ? "none" : "flex";
searchResults.innerHTML = "";
currentTerm = term;
if (term === "") {
return;
}
var results = (await initIndex()).search(term, options);
if (results.length === 0) {
searchResults.style.display = "none";
return;
}
for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
searchResults.innerHTML += formatSearchResultItem(results[i], term.split(" "));
}
}, 150));
document.addEventListener("keydown", function (event) {
if (event.key === "/") {
event.preventDefault();
toggleSearch();
}
});
document.getElementById("search-toggle").addEventListener("click", toggleSearch);
}
function toggleSearch() {
var searchContainer = document.getElementById("search-container");
var searchBar = document.getElementById("search-bar");
searchContainer.classList.toggle("active");
searchBar.toggleAttribute("disabled");
searchBar.focus();
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll)
) {
initSearch();
} else {
document.addEventListener("DOMContentLoaded", initSearch);
}

127
public/search-fuse.js Normal file
View file

@ -0,0 +1,127 @@
// Based on https://codeberg.org/daudix/duckquill/issues/101#issuecomment-2377169
let searchSetup = false;
let fuse;
async function initIndex() {
if (searchSetup) return;
const url = document.getElementById("search-index").textContent;
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const options = {
includeScore: false,
includeMatches: true,
ignoreLocation: true,
threshold: 0.15,
keys: [
{ name: "title", weight: 3 },
{ name: "description", weight: 2 },
{ name: "body", weight: 1 }
]
};
fuse = new Fuse(await response.json(), options);
searchSetup = true;
console.log("Search index initialized successfully");
}
function toggleSearch() {
initIndex();
const searchBar = document.getElementById("search-bar");
const searchContainer = document.getElementById("search-container");
const searchResults = document.getElementById("search-results");
searchContainer.classList.toggle("active");
searchBar.toggleAttribute("disabled");
searchBar.focus();
}
function debounce(actual_fn, wait) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
actual_fn(...args);
}, wait);
};
};
function initSearch() {
const searchBar = document.getElementById("search-bar");
const searchResults = document.getElementById("search-results");
const searchContainer = document.getElementById("search-container");
const MAX_ITEMS = 10;
const MAX_RESULTS = 4;
let currentTerm = "";
searchBar.addEventListener("keyup", (e) => {
const searchVal = searchBar.value.trim();
const results = fuse.search(searchVal, { limit: MAX_ITEMS });
let html = "";
for (const result of results) {
html += makeTeaser(result, searchVal);
}
searchResults.innerHTML = html;
if (html) {
searchResults.style.display = "flex";
} else {
searchResults.style.display = "none";
}
});
function makeTeaser(result, searchVal) {
const TEASER_SIZE = 20;
let output = `<div class="search-result item"><a class="result-title" href=${result.item.url}>${result.item.title}</a>`;
for (const match of result.matches) {
if (match.key === "title") continue;
const indices = match.indices.sort((a, b) => Math.abs(a[1] - a[0] - searchVal.length) - Math.abs(b[1] - b[0] - searchVal.length)).slice(0, MAX_RESULTS);
const value = match.value;
for (const ind of indices) {
const start = Math.max(0, ind[0] - TEASER_SIZE);
const end = Math.min(value.length - 1, ind[1] + TEASER_SIZE);
output += "<span>"
+ value.substring(start, ind[0])
+ `<strong>${value.substring(ind[0], ind[1] + 1)}</strong>`
+ value.substring(ind[1] + 1, end)
+ "</span>";
}
if (match.indices.length > 4) {
const moreMatchesText = document.getElementById("more-matches-text").textContent;
output += `<span class="more-matches">${moreMatchesText}</span>`.replace("$MATCHES", `+${match.indices.length - MAX_RESULTS}`);
}
}
return output + "</div>";
}
/*window.addEventListener("click", function (event) {
if (searchSetup && searchBar.getAttribute("disabled") === null && !searchContainer.contains(event.target)) {
toggleSearch();
}
}, { passive: true });*/
document.addEventListener("keydown", function(event) {
if (event.key === "/") {
event.preventDefault();
toggleSearch();
}
});
document.getElementById("search-toggle").addEventListener("click", toggleSearch);
}
if (document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll))
initSearch();
else
document.addEventListener("DOMContentLoaded", initSearch);

File diff suppressed because one or more lines are too long

16
public/sitemap.xml Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://rootsource.cc/</loc>
</url>
<url>
<loc>https://rootsource.cc/Articles/</loc>
</url>
<url>
<loc>https://rootsource.cc/Articles/page/1/</loc>
</url>
<url>
<loc>https://rootsource.cc/Articles/tylkolinux-installation/</loc>
<lastmod>2025-01-30</lastmod>
</url>
</urlset>

5
public/style.css Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,283 @@
/*
* theme "Solarized (dark)" generated by syntect
*/
.z-code {
color: #839496;
background-color: #002b36;
}
.z-comment, .z-meta.z-documentation {
color: #586e75;
}
.z-string {
color: #2aa198;
}
.z-string.z-regexp {
color: #2aa198;
}
.z-constant.z-character.z-escape {
color: #dc322f;
}
.z-constant.z-numeric {
color: #6c71c4;
}
.z-variable {
color: #268bd2;
}
.z-variable.z-function {
color: #b58900;
}
.z-variable.z-language {
color: #d33682;
}
.z-keyword {
color: #859900;
}
.z-meta.z-import .z-keyword, .z-keyword.z-control.z-import, .z-keyword.z-control.z-import.z-from, .z-keyword.z-other.z-import, .z-keyword.z-control.z-at-rule.z-include, .z-keyword.z-control.z-at-rule.z-import {
color: #cb4b16;
}
.z-keyword.z-operator.z-comparison, .z-keyword.z-operator.z-assignment, .z-keyword.z-operator.z-arithmetic {
color: #657b83;
}
.z-storage {
color: #859900;
}
.z-storage.z-modifier {
color: #93a1a1;
}
.z-keyword.z-control.z-class, .z-entity.z-name, .z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class {
color: #b58900;
}
.z-entity.z-other.z-inherited-class {
color: #268bd2;
}
.z-entity.z-other.z-attribute-name {
color: #b58900;
}
.z-support, .z-support.z-type, .z-support.z-class {
color: #859900;
}
.z-entity.z-name.z-function {
color: #b58900;
}
.z-punctuation.z-definition.z-variable {
color: #859900;
}
.z-constant, .z-constant.z-language, .z-meta.z-preprocessor {
color: #b58900;
}
.z-entity.z-name.z-section {
color: #cb4b16;
}
.z-support.z-function.z-construct, .z-keyword.z-other.z-new {
color: #dc322f;
}
.z-constant.z-character, .z-constant.z-other {
color: #cb4b16;
}
.z-entity.z-name.z-tag {
color: #268bd2;
}
.z-punctuation.z-definition.z-tag.z-html, .z-punctuation.z-definition.z-tag.z-begin, .z-punctuation.z-definition.z-tag.z-end {
color: #586e75;
}
.z-support.z-function {
color: #859900;
}
.z-punctuation.z-separator.z-continuation {
color: #dc322f;
}
.z-storage.z-type {
color: #268bd2;
}
.z-support.z-type.z-exception {
color: #cb4b16;
}
.z-keyword.z-other.z-special-method {
color: #cb4b16;
}
.z-invalid {
background-color: #6e2e32;
}
.z-string.z-quoted.z-double, .z-string.z-quoted.z-single {
color: #2aa198;
}
.z-punctuation.z-definition.z-string {
color: #839496;
}
.z-meta.z-brace.z-square, .z-punctuation.z-section.z-brackets {
color: #268bd2;
}
.z-meta.z-brace.z-round, .z-meta.z-brace.z-curly, .z-punctuation.z-section, .z-punctuation.z-section.z-block, .z-punctuation.z-definition.z-parameters, .z-punctuation.z-section.z-group {
color: #657b83;
}
.z-support.z-constant.z-color, .z-invalid.z-deprecated.z-color.z-w3c-non-standard-color-name.z-scss {
color: #b58900;
}
.z-meta.z-selector.z-css {
color: #657b83;
}
.z-entity.z-name.z-tag.z-css, .z-entity.z-name.z-tag.z-scss, .z-source.z-less .z-keyword.z-control.z-html.z-elements, .z-source.z-sass .z-keyword.z-control.z-untitled {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-class {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-id {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-pseudo-element, .z-entity.z-other.z-attribute-name.z-tag.z-pseudo-element, .z-entity.z-other.z-attribute-name.z-pseudo-class, .z-entity.z-other.z-attribute-name.z-tag.z-pseudo-class {
color: #268bd2;
}
.z-text.z-html.z-basic .z-meta.z-tag.z-other.z-html, .z-text.z-html.z-basic .z-meta.z-tag.z-any.z-html, .z-text.z-html.z-basic .z-meta.z-tag.z-block.z-any, .z-text.z-html.z-basic .z-meta.z-tag.z-inline.z-any, .z-text.z-html.z-basic .z-meta.z-tag.z-structure.z-any.z-html, .z-text.z-html.z-basic .z-source.z-js.z-embedded.z-html, .z-punctuation.z-separator.z-key-value.z-html {
color: #657b83;
}
.z-text.z-html.z-basic .z-entity.z-other.z-attribute-name.z-html, .z-meta.z-tag.z-xml .z-entity.z-other.z-attribute-name {
color: #b58900;
}
.z-keyword.z-other.z-special-method.z-ruby {
color: #859900;
}
.z-variable.z-other.z-constant.z-ruby {
color: #b58900;
}
.z-constant.z-other.z-symbol.z-ruby {
color: #2aa198;
}
.z-keyword.z-other.z-special-method.z-ruby {
color: #cb4b16;
}
.z-meta.z-array .z-support.z-function.z-construct.z-php {
color: #b58900;
}
.z-entity.z-name.z-function.z-preprocessor.z-c, .z-meta.z-preprocessor.z-c.z-include, .z-meta.z-preprocessor.z-macro.z-c {
color: #cb4b16;
}
.z-meta.z-preprocessor.z-c.z-include .z-string.z-quoted.z-other.z-lt-gt.z-include.z-c, .z-meta.z-preprocessor.z-c.z-include .z-punctuation.z-definition.z-string.z-begin.z-c, .z-meta.z-preprocessor.z-c.z-include .z-punctuation.z-definition.z-string.z-end.z-c {
color: #2aa198;
}
.z-other.z-package.z-exclude, .z-other.z-remove {
color: #dc322f;
}
.z-other.z-add {
color: #2aa198;
}
.z-punctuation.z-section.z-group.z-tex, .z-punctuation.z-definition.z-arguments.z-begin.z-latex, .z-punctuation.z-definition.z-arguments.z-end.z-latex, .z-punctuation.z-definition.z-arguments.z-latex {
color: #dc322f;
}
.z-meta.z-group.z-braces.z-tex {
color: #b58900;
}
.z-string.z-other.z-math.z-tex {
color: #b58900;
}
.z-variable.z-parameter.z-function.z-latex {
color: #cb4b16;
}
.z-punctuation.z-definition.z-constant.z-math.z-tex {
color: #dc322f;
}
.z-text.z-tex.z-latex .z-constant.z-other.z-math.z-tex, .z-constant.z-other.z-general.z-math.z-tex, .z-constant.z-other.z-general.z-math.z-tex, .z-constant.z-character.z-math.z-tex {
color: #2aa198;
}
.z-string.z-other.z-math.z-tex {
color: #b58900;
}
.z-punctuation.z-definition.z-string.z-begin.z-tex, .z-punctuation.z-definition.z-string.z-end.z-tex {
color: #dc322f;
}
.z-keyword.z-control.z-label.z-latex, .z-text.z-tex.z-latex .z-constant.z-other.z-general.z-math.z-tex {
color: #2aa198;
}
.z-variable.z-parameter.z-definition.z-label.z-latex {
color: #dc322f;
}
.z-support.z-function.z-be.z-latex {
color: #859900;
}
.z-support.z-function.z-section.z-latex {
color: #cb4b16;
}
.z-support.z-function.z-general.z-tex {
color: #2aa198;
}
.z-keyword.z-control.z-ref.z-latex {
color: #2aa198;
}
.z-storage.z-type.z-class.z-python, .z-storage.z-type.z-function.z-python, .z-storage.z-modifier.z-global.z-python {
color: #859900;
}
.z-support.z-type.z-exception.z-python {
color: #b58900;
}
.z-meta.z-scope.z-for-in-loop.z-shell, .z-variable.z-other.z-loop.z-shell {
color: #93a1a1;
}
.z-meta.z-scope.z-case-block.z-shell, .z-meta.z-scope.z-case-body.z-shell {
color: #93a1a1;
}
.z-punctuation.z-definition.z-logical-expression.z-shell {
color: #dc322f;
}
.z-storage.z-modifier.z-c++ {
color: #859900;
}
.z-support.z-function.z-perl {
color: #268bd2;
}
.z-meta.z-diff, .z-meta.z-diff.z-header {
color: #586e75;
}
.z-meta.z-diff.z-range {
color: #268bd2;
}
.z-markup.z-deleted {
color: #dc322f;
}
.z-markup.z-changed {
color: #b58900;
}
.z-markup.z-inserted {
color: #859900;
}
.z-markup.z-warning {
color: #b58900;
}
.z-markup.z-error {
color: #dc322f;
}
.z-markup.z-heading, .z-punctuation.z-definition.z-heading.z-markdown {
color: #b58900;
font-weight: bold;
}
.z-markup.z-quote {
color: #859900;
}
.z-markup.z-italic {
font-style: italic;
}
.z-markup.z-bold {
font-weight: bold;
}
.z-markup.z-underline.z-link.z-markdown, .z-meta.z-link.z-reference .z-constant.z-other.z-reference.z-link.z-markdown {
color: #2aa198;
}
.z-constant.z-other.z-reference.z-link.z-markdown {
color: #6c71c4;
}
.z-meta.z-paragraph.z-markdown .z-meta.z-dummy.z-line-break {
background-color: #586e75;
}
.z-brackethighlighter.z-all {
color: #586e75;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #2aa198;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #586e75;
}
.z-variable.z-other.z-readwrite.z-js, .z-variable.z-other.z-object.z-js, .z-variable.z-other.z-constant.z-js {
color: #839496;
}

View file

@ -0,0 +1,283 @@
/*
* theme "Solarized (light)" generated by syntect
*/
.z-code {
color: #657b83;
background-color: #fdf6e3;
}
.z-comment, .z-meta.z-documentation {
color: #93a1a1;
}
.z-string {
color: #2aa198;
}
.z-string.z-regexp {
color: #2aa198;
}
.z-constant.z-character.z-escape {
color: #dc322f;
}
.z-constant.z-numeric {
color: #6c71c4;
}
.z-variable {
color: #268bd2;
}
.z-variable.z-function {
color: #b58900;
}
.z-variable.z-language {
color: #d33682;
}
.z-keyword {
color: #859900;
}
.z-meta.z-import .z-keyword, .z-keyword.z-control.z-import, .z-keyword.z-control.z-import.z-from, .z-keyword.z-other.z-import, .z-keyword.z-control.z-at-rule.z-include, .z-keyword.z-control.z-at-rule.z-import {
color: #cb4b16;
}
.z-keyword.z-operator.z-comparison, .z-keyword.z-operator.z-assignment, .z-keyword.z-operator.z-arithmetic {
color: #657b83;
}
.z-storage {
color: #859900;
}
.z-storage.z-modifier {
color: #586e75;
}
.z-keyword.z-control.z-class, .z-entity.z-name, .z-entity.z-name.z-class, .z-entity.z-name.z-type.z-class {
color: #b58900;
}
.z-entity.z-other.z-inherited-class {
color: #268bd2;
}
.z-entity.z-other.z-attribute-name {
color: #b58900;
}
.z-support, .z-support.z-type, .z-support.z-class {
color: #859900;
}
.z-entity.z-name.z-function {
color: #b58900;
}
.z-punctuation.z-definition.z-variable {
color: #859900;
}
.z-constant, .z-constant.z-language, .z-meta.z-preprocessor {
color: #b58900;
}
.z-entity.z-name.z-section {
color: #cb4b16;
}
.z-support.z-function.z-construct, .z-keyword.z-other.z-new {
color: #dc322f;
}
.z-constant.z-character, .z-constant.z-other {
color: #cb4b16;
}
.z-entity.z-name.z-tag {
color: #268bd2;
}
.z-punctuation.z-definition.z-tag.z-html, .z-punctuation.z-definition.z-tag.z-begin, .z-punctuation.z-definition.z-tag.z-end {
color: #93a1a1;
}
.z-support.z-function {
color: #859900;
}
.z-punctuation.z-separator.z-continuation {
color: #dc322f;
}
.z-storage.z-type {
color: #268bd2;
}
.z-support.z-type.z-exception {
color: #cb4b16;
}
.z-keyword.z-other.z-special-method {
color: #cb4b16;
}
.z-invalid {
background-color: #ec9489;
}
.z-string.z-quoted.z-double, .z-string.z-quoted.z-single {
color: #2aa198;
}
.z-punctuation.z-definition.z-string {
color: #839496;
}
.z-meta.z-brace.z-square, .z-punctuation.z-section.z-brackets {
color: #268bd2;
}
.z-meta.z-brace.z-round, .z-meta.z-brace.z-curly, .z-punctuation.z-section, .z-punctuation.z-section.z-block, .z-punctuation.z-definition.z-parameters, .z-punctuation.z-section.z-group {
color: #657b83;
}
.z-support.z-constant.z-color, .z-invalid.z-deprecated.z-color.z-w3c-non-standard-color-name.z-scss {
color: #b58900;
}
.z-meta.z-selector.z-css {
color: #657b83;
}
.z-entity.z-name.z-tag.z-css, .z-entity.z-name.z-tag.z-scss, .z-source.z-less .z-keyword.z-control.z-html.z-elements, .z-source.z-sass .z-keyword.z-control.z-untitled {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-class {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-id {
color: #b58900;
}
.z-entity.z-other.z-attribute-name.z-pseudo-element, .z-entity.z-other.z-attribute-name.z-tag.z-pseudo-element, .z-entity.z-other.z-attribute-name.z-pseudo-class, .z-entity.z-other.z-attribute-name.z-tag.z-pseudo-class {
color: #268bd2;
}
.z-text.z-html.z-basic .z-meta.z-tag.z-other.z-html, .z-text.z-html.z-basic .z-meta.z-tag.z-any.z-html, .z-text.z-html.z-basic .z-meta.z-tag.z-block.z-any, .z-text.z-html.z-basic .z-meta.z-tag.z-inline.z-any, .z-text.z-html.z-basic .z-meta.z-tag.z-structure.z-any.z-html, .z-text.z-html.z-basic .z-source.z-js.z-embedded.z-html, .z-punctuation.z-separator.z-key-value.z-html {
color: #657b83;
}
.z-text.z-html.z-basic .z-entity.z-other.z-attribute-name.z-html, .z-meta.z-tag.z-xml .z-entity.z-other.z-attribute-name {
color: #b58900;
}
.z-keyword.z-other.z-special-method.z-ruby {
color: #859900;
}
.z-variable.z-other.z-constant.z-ruby {
color: #b58900;
}
.z-constant.z-other.z-symbol.z-ruby {
color: #2aa198;
}
.z-keyword.z-other.z-special-method.z-ruby {
color: #cb4b16;
}
.z-meta.z-array .z-support.z-function.z-construct.z-php {
color: #b58900;
}
.z-entity.z-name.z-function.z-preprocessor.z-c, .z-meta.z-preprocessor.z-c.z-include, .z-meta.z-preprocessor.z-macro.z-c {
color: #cb4b16;
}
.z-meta.z-preprocessor.z-c.z-include .z-string.z-quoted.z-other.z-lt-gt.z-include.z-c, .z-meta.z-preprocessor.z-c.z-include .z-punctuation.z-definition.z-string.z-begin.z-c, .z-meta.z-preprocessor.z-c.z-include .z-punctuation.z-definition.z-string.z-end.z-c {
color: #2aa198;
}
.z-other.z-package.z-exclude, .z-other.z-remove {
color: #dc322f;
}
.z-other.z-add {
color: #2aa198;
}
.z-punctuation.z-section.z-group.z-tex, .z-punctuation.z-definition.z-arguments.z-begin.z-latex, .z-punctuation.z-definition.z-arguments.z-end.z-latex, .z-punctuation.z-definition.z-arguments.z-latex {
color: #dc322f;
}
.z-meta.z-group.z-braces.z-tex {
color: #b58900;
}
.z-string.z-other.z-math.z-tex {
color: #b58900;
}
.z-variable.z-parameter.z-function.z-latex {
color: #cb4b16;
}
.z-punctuation.z-definition.z-constant.z-math.z-tex {
color: #dc322f;
}
.z-text.z-tex.z-latex .z-constant.z-other.z-math.z-tex, .z-constant.z-other.z-general.z-math.z-tex, .z-constant.z-other.z-general.z-math.z-tex, .z-constant.z-character.z-math.z-tex {
color: #2aa198;
}
.z-string.z-other.z-math.z-tex {
color: #b58900;
}
.z-punctuation.z-definition.z-string.z-begin.z-tex, .z-punctuation.z-definition.z-string.z-end.z-tex {
color: #dc322f;
}
.z-keyword.z-control.z-label.z-latex, .z-text.z-tex.z-latex .z-constant.z-other.z-general.z-math.z-tex {
color: #2aa198;
}
.z-variable.z-parameter.z-definition.z-label.z-latex {
color: #dc322f;
}
.z-support.z-function.z-be.z-latex {
color: #859900;
}
.z-support.z-function.z-section.z-latex {
color: #cb4b16;
}
.z-support.z-function.z-general.z-tex {
color: #2aa198;
}
.z-keyword.z-control.z-ref.z-latex {
color: #2aa198;
}
.z-storage.z-type.z-class.z-python, .z-storage.z-type.z-function.z-python, .z-storage.z-modifier.z-global.z-python {
color: #859900;
}
.z-support.z-type.z-exception.z-python {
color: #b58900;
}
.z-meta.z-scope.z-for-in-loop.z-shell, .z-variable.z-other.z-loop.z-shell {
color: #586e75;
}
.z-meta.z-scope.z-case-block.z-shell, .z-meta.z-scope.z-case-body.z-shell {
color: #586e75;
}
.z-punctuation.z-definition.z-logical-expression.z-shell {
color: #dc322f;
}
.z-storage.z-modifier.z-c++ {
color: #859900;
}
.z-support.z-function.z-perl {
color: #268bd2;
}
.z-meta.z-diff, .z-meta.z-diff.z-header {
color: #93a1a1;
}
.z-meta.z-diff.z-range {
color: #268bd2;
}
.z-markup.z-deleted {
color: #dc322f;
}
.z-markup.z-changed {
color: #b58900;
}
.z-markup.z-inserted {
color: #859900;
}
.z-markup.z-warning {
color: #b58900;
}
.z-markup.z-error {
color: #dc322f;
}
.z-markup.z-heading, .z-punctuation.z-definition.z-heading.z-markdown {
color: #b58900;
font-weight: bold;
}
.z-markup.z-quote {
color: #859900;
}
.z-markup.z-italic {
font-style: italic;
}
.z-markup.z-bold {
font-weight: bold;
}
.z-markup.z-underline.z-link.z-markdown, .z-meta.z-link.z-reference .z-constant.z-other.z-reference.z-link.z-markdown {
color: #2aa198;
}
.z-constant.z-other.z-reference.z-link.z-markdown {
color: #6c71c4;
}
.z-meta.z-paragraph.z-markdown .z-meta.z-dummy.z-line-break {
background-color: #eee8d5;
}
.z-brackethighlighter.z-all {
color: #93a1a1;
}
.z-entity.z-name.z-filename.z-find-in-files {
color: #2aa198;
}
.z-constant.z-numeric.z-line-number.z-find-in-files {
color: #93a1a1;
}
.z-variable.z-other.z-readwrite.z-js, .z-variable.z-other.z-object.z-js, .z-variable.z-other.z-constant.z-js {
color: #657b83;
}

104
public/theme-switcher.js Normal file
View file

@ -0,0 +1,104 @@
// Theme Initialization
(function () {
// Get the default theme from the HTML data-theme attribute.
const defaultTheme = document.documentElement.getAttribute("data-theme");
// Set the data-default-theme attribute only if defaultTheme is not null.
if (defaultTheme) {
document.documentElement.setAttribute("data-default-theme", defaultTheme);
}
// Attempt to retrieve the current theme from the browser's local storage.
const storedTheme = localStorage.getItem("theme");
if (storedTheme && storedTheme !== "system") {
document.documentElement.setAttribute("data-theme", storedTheme);
} else if (defaultTheme && storedTheme !== "system") {
document.documentElement.setAttribute("data-theme", defaultTheme);
} else {
// If no theme is found in local storage and no default theme is set, hand over control to the CSS.
document.documentElement.removeAttribute("data-theme");
}
// Expose defaultTheme to the outer scope.
window.defaultTheme = defaultTheme;
})();
// Icon Update and Theme Switching
function setTheme(theme, saveToLocalStorage = false) {
if (theme === "system") {
document.documentElement.removeAttribute("data-theme");
} else {
document.documentElement.setAttribute("data-theme", theme);
}
if (saveToLocalStorage) {
localStorage.setItem("theme", theme);
} else {
localStorage.removeItem("theme");
}
// Update icon class based on the selected theme.
updateIconClass(theme);
// Update the active button based on the selected theme.
updateActiveButton(theme);
}
function resetTheme() {
// Reset the theme to the default or system preference if no default is set.
setTheme(window.defaultTheme || "system");
}
function switchTheme(theme) {
if (theme === "system") {
resetTheme();
} else {
setTheme(theme, true);
}
}
function updateIconClass(theme) {
const iconElement = document.querySelector("#theme-switcher summary .icon");
// Remove any existing theme classes
iconElement.classList.remove("light", "dark");
// Add the appropriate class based on the selected theme
if (theme === "light") {
iconElement.classList.add("light");
} else if (theme === "dark") {
iconElement.classList.add("dark");
}
}
function updateActiveButton(theme) {
// Remove .active class from all buttons
document.querySelectorAll('#theme-switcher button').forEach(button => {
button.classList.remove('active');
});
// Add .active class to the button corresponding to the current theme
const activeButton = document.querySelector(`#theme-${theme}`);
if (activeButton) {
activeButton.classList.add('active');
}
}
document.getElementById("theme-light").addEventListener("click", function () {
switchTheme("light");
});
document.getElementById("theme-dark").addEventListener("click", function () {
switchTheme("dark");
});
document.getElementById("theme-system").addEventListener("click", function () {
switchTheme("system");
});
// Update icon class on page load based on current theme
const currentTheme = localStorage.getItem("theme") || window.defaultTheme || "system";
updateIconClass(currentTheme);
updateActiveButton(currentTheme);
// Make the switchTheme function accessible globally
window.switchTheme = switchTheme;

1
themes/duckquill Submodule

@ -0,0 +1 @@
Subproject commit 66d2504350d37921be8a31c9cb24c151360fbd6e

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="robots" content="index, follow">
<title>{{ section.title }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100vh;
}
</style>
</head>
<body>
<main>
{{ section.content | safe }}
</main>
<footer>
<div id="footer-container">
<p>YunoHost</p>
</div>
</footer>
</body>
</html>

View file

@ -0,0 +1,2 @@
name = "yunohost"
description = "The default theme for the YunoHost Zola package"