Compare commits
25 Commits
dev
...
f31552e791
Author | SHA1 | Date | |
---|---|---|---|
f31552e791 | |||
000bb3ea47 | |||
297f96ab99 | |||
3112316e7d | |||
1ca991e4b9 | |||
c827757fb8 | |||
01c994aa13 | |||
1de4bf249b | |||
28c29f0d30 | |||
8a832250a0 | |||
225f2af48b | |||
2144038970 | |||
512a810122 | |||
2e5696f767 | |||
1751b590aa | |||
a95f13943f | |||
7f23f234cd | |||
b227a41a43 | |||
bf5f265116 | |||
1cf12f91f0 | |||
00eec8be70 | |||
542e432596 | |||
0791f417f3 | |||
2439dfa78d | |||
e0248abb46 |
@@ -4,9 +4,6 @@ on: pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Skip if PR base is master/dev
|
||||
if: github.base_ref != 'master' && github.base_ref != 'dev'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1 @@
|
||||
public/
|
||||
*.swp
|
||||
|
45
Makefile
45
Makefile
@@ -1,41 +1,10 @@
|
||||
# -------- Config --------
|
||||
SHELL := /bin/sh
|
||||
all: clean format build
|
||||
|
||||
ZOLA ?= zola
|
||||
BIOME ?= npx biome
|
||||
format:
|
||||
biome format --write .
|
||||
|
||||
BUILD_DIR := public
|
||||
|
||||
# -------- Targets --------
|
||||
.PHONY: help serve build clean format lint fix fix-unsafe check ci
|
||||
|
||||
help: ## Show this help
|
||||
@awk 'BEGIN{FS":.*##"; printf "\nTargets:\n"} /^[a-zA-Z0-9_.-]+:.*##/{printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST); echo
|
||||
|
||||
serve: ## Run Zola dev server (http://127.0.0.1:1111)
|
||||
$(ZOLA) serve
|
||||
|
||||
build: ## Build site into ./public
|
||||
$(ZOLA) build
|
||||
|
||||
clean: ## Remove ./public
|
||||
rm -rf "$(BUILD_DIR)"
|
||||
|
||||
format: ## Format JS/JSON/CSS with Biome (no linting)
|
||||
$(BIOME) format --write .
|
||||
|
||||
lint: ## Lint with Biome (no writes)
|
||||
$(BIOME) ci .
|
||||
|
||||
fix: ## Lint+auto-fix safe changes with Biome
|
||||
$(BIOME) check --write .
|
||||
|
||||
fix-unsafe: ## Lint+auto-fix incl. unsafe (e.g., template literals)
|
||||
$(BIOME) check --write --unsafe .
|
||||
|
||||
check: ## Zola link/content checks
|
||||
$(ZOLA) check
|
||||
|
||||
ci: ## CI-friendly: lint (Biome) + Zola checks
|
||||
$(BIOME) ci . && $(ZOLA) check
|
||||
build:
|
||||
zola build
|
||||
|
||||
clean:
|
||||
rm -rf public/
|
||||
|
47
README.md
47
README.md
@@ -1,27 +1,28 @@
|
||||
# fr/website
|
||||
# Website
|
||||
- My personal website https://www.filiprojek.cz
|
||||
- Written in [Zola](https://getzola.org)
|
||||
|
||||
Personal website of **Filip Rojek** built with **[Zola](https://www.getzola.org/)** (Tera templates, SASS).
|
||||
## To run development server
|
||||
- `zola serve`
|
||||
- Then it can be access at http://127.0.0.1:1111/
|
||||
|
||||
Live content: posts and projects.
|
||||
## To Do
|
||||
- [ ] Docker?
|
||||
- [ ] redesign contact
|
||||
- [ ] redesign about
|
||||
- [ ] check about text content
|
||||
- [ ] responsibility
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
### Prerequisites
|
||||
- Zola (install from your distro or see https://www.getzola.org/documentation/getting-started/installation/)
|
||||
|
||||
### Develop
|
||||
```bash
|
||||
# run local dev server
|
||||
zola serve
|
||||
# default: http://127.0.0.1:1111
|
||||
````
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
# render to ./public
|
||||
zola build
|
||||
```
|
||||
# Projects
|
||||
- nork
|
||||
- website
|
||||
- debrepo
|
||||
- auto irrigation
|
||||
- auto awning close
|
||||
- FofrTasks
|
||||
- FofrMess
|
||||
- pkmples.cz
|
||||
- deguapp?
|
||||
- wpa_tui?
|
||||
- dotfiles
|
||||
|
||||
|
34
biome.json
34
biome.json
@@ -1,41 +1,15 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.2.2/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
|
||||
"files": {
|
||||
"includes": ["**", "!public", "!content", "!templates", "!static/img", "!**/*.min.js"]
|
||||
"ignore": [".vscode/", "node_modules/", "public/"]
|
||||
},
|
||||
"formatter": {
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"enabled": false,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"lineWidth": 100,
|
||||
"quoteStyle": "double",
|
||||
"jsxQuoteStyle": "double",
|
||||
"trailingCommas": "all",
|
||||
"semicolons": "always"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"formatter": {
|
||||
"lineWidth": 100
|
||||
}
|
||||
},
|
||||
"css": {
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"lineWidth": 100,
|
||||
"quoteStyle": "single"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,25 +3,25 @@ title = "About"
|
||||
template = "about.html"
|
||||
+++
|
||||
|
||||
I am an IT student at Charles University in Prague (Faculty of Education).
|
||||
## About
|
||||
I am student of IT at Charles University in Prague (Faculty of Education).
|
||||
|
||||
As a member of [Microlab](https://microlab.space), the university's hackerspace, I collaborate on various hardware and software projects. Additionally, I contribute to the open-source community as a package maintainer for [Void Linux](https://voidlinux.org).
|
||||
My programming journey began in high school, where I developed a passion for `Linux` and co-founded [Fofrweb](https://fofrweb.com). Together with a classmate, I created web applications using `Node.js` and `Vue.js`, all hosted on my own Linux server.
|
||||
|
||||
As a member of [Microlab](https://microlab.space), the university's hacker space, I engage with fellow tech enthusiasts. Additionally, I contribute to the open-source community as a package maintainer for [Void Linux](https://voidlinux.org).
|
||||
|
||||
## Work
|
||||
I currently work as a Linux engineer. Most of my work involves Debian based systems - desktops (Raspberry Pi, Intel NUC) and servers.
|
||||
|
||||
Currently employed as a Linux DevOps engineer, focusing primarily on Debian-based systems across a variety of hardware platforms.
|
||||
|
||||
I also create custom websites from time to time.
|
||||
I also create custom websites from time to time.
|
||||
|
||||
## Projects
|
||||
|
||||
Most of my projects are hosted on my private Gitea instance and GitHub:
|
||||
|
||||
- Gitea: [git.filiprojek.cz/fr](https://git.filiprojek.cz/fr)
|
||||
Most of my projects are hosted on Gitea and GitHub:
|
||||
- Gitea: [git.filiprojek.cz](https://git.filiprojek.cz/fr)
|
||||
- GitHub: [github.com/filiprojek](https://github.com/filiprojek)
|
||||
|
||||
## Contact
|
||||
|
||||
- <a href="mailto:filip@filiprojek.cz">filip@filiprojek.cz</a>
|
||||
- [@filiprojek](https://t.me/filiprojek) on Telegram
|
||||
- PGP: [0x7E65EA58C6075F09](https://keys.openpgp.org/vks/v1/by-fingerprint/CA3D9BE28315B49164130CD97E65EA58C6075F09)
|
||||
|
||||
|
@@ -1,91 +0,0 @@
|
||||
+++
|
||||
title = "Unix pass and Android Password Store with YubiKey"
|
||||
date = 2025-01-01
|
||||
description = "Setting Up Unix pass with YubiKey and Android Password Store"
|
||||
+++
|
||||
|
||||
Using a secure and versatile password manager is a must for managing your digital life, and [pass](https://www.passwordstore.org/), the Unix password manager, is a fantastic choice. If you store your GPG key on a YubiKey and use the [Android Password Store](https://github.com/android-password-store/Android-Password-Store) app with [OpenKeychain](https://github.com/open-keychain/open-keychain), this guide will help you set everything up while addressing a common compatibility issue with `throw-keyids` in `gpg.conf`.
|
||||
|
||||
## What You’ll Need
|
||||
|
||||
- A YubiKey configured with your GPG key (see the excellent [YubiKey-Guide by drduh](https://github.com/drduh/YubiKey-Guide)).
|
||||
- The [pass](https://www.passwordstore.org/) command-line utility.
|
||||
- [OpenKeychain](https://github.com/open-keychain/open-keychain) installed on your Android device.
|
||||
- The [Android Password Store](https://github.com/android-password-store/Android-Password-Store) app.
|
||||
|
||||
## Configuring `pass` with a YubiKey-Stored GPG Key
|
||||
|
||||
1. **Set up your YubiKey and GPG key**
|
||||
- Follow the steps in [drduh’s YubiKey guide](https://github.com/drduh/YubiKey-Guide) to create and configure your GPG key on your YubiKey.
|
||||
|
||||
2. **Install `pass`**
|
||||
- Install the `pass` utility on your Linux system. Most distributions have it in their package repositories:
|
||||
|
||||
```bash
|
||||
apt install pass # For Debian/Ubuntu-based distros
|
||||
xbps-install -S pass # For Void Linux
|
||||
```
|
||||
|
||||
3. **Initialize `pass` with your GPG key**
|
||||
- Run the following command to initialize the `.password-store` directory:
|
||||
|
||||
```bash
|
||||
pass init <KEYID>
|
||||
```
|
||||
- Replace `<KEYID>` with your GPG key ID stored on the YubiKey.
|
||||
|
||||
4. **Sync passwords to your Android device**
|
||||
- Clone your `.password-store` repository to your Android device and set up the `Password Store` app with `OpenKeychain`.
|
||||
|
||||
## The `throw-keyids` Issue
|
||||
|
||||
While working through this issue, I found a helpful discussion in [GitHub issue #173](https://github.com/android-password-store/Android-Password-Store/issues/173) for the Android Password Store repository. This thread provided insights that clarified the root cause of the problem and its resolution.
|
||||
|
||||
During setup, you might encounter an error in the Android Password Store app. OpenKeychain could report that the `.gpg` files are encrypted for a different key, even if they are not. This issue arises due to the `throw-keyids` option in `~/.gnupg/gpg.conf`.
|
||||
|
||||
### What Does `throw-keyids` Do?
|
||||
|
||||
The `throw-keyids` option in `gpg.conf` hides the recipient’s key ID during encryption. While this enhances privacy by preventing others from identifying the intended recipient(s), it can cause issues with OpenKeychain. OpenKeychain relies on visible key IDs to identify the correct decryption key, and without them, it assumes the files were encrypted for an unknown key.
|
||||
|
||||
### Fixing the Issue
|
||||
|
||||
To resolve this, you need to disable `throw-keyids` and re-encrypt your password store.
|
||||
|
||||
1. **Comment Out `throw-keyids` in `gpg.conf`**
|
||||
- Open `~/.gnupg/gpg.conf` in your favorite text editor and comment out the line:
|
||||
|
||||
```
|
||||
# throw-keyids
|
||||
```
|
||||
|
||||
2. **Re-encrypt Your Password Store**
|
||||
- Run the following command to re-encrypt all passwords with the new GPG options:
|
||||
|
||||
```bash
|
||||
PASSWORD_STORE_GPG_OPTS="--no-throw-keyids" pass init <KEYID>
|
||||
```
|
||||
|
||||
- Replace `<KEYID>` with your GPG key ID.
|
||||
|
||||
3. **Optional: Update Your Environment**
|
||||
- To ensure `--no-throw-keyids` is always used, add the following line to your `~/.bashrc`:
|
||||
|
||||
```bash
|
||||
export PASSWORD_STORE_GPG_OPTS='--no-throw-keyids' # Fix for OpenKeychain
|
||||
```
|
||||
|
||||
- While this step is not strictly necessary (since the change in `gpg.conf` resolves the issue), it can serve as a safeguard.
|
||||
|
||||
4. **Sync the Updated Password Store**
|
||||
- Push the updated `.password-store` to your remote repository and pull it on your Android device.
|
||||
|
||||
## Conclusion
|
||||
|
||||
With these steps, you can seamlessly use `pass` with a YubiKey and the Android Password Store app. The issue with `throw-keyids` is a minor hurdle that can be resolved by adjusting your `gpg.conf` and re-encrypting your password store. Disabling `throw-keyids` makes your key IDs visible, which slightly reduces privacy but is necessary for compatibility with OpenKeychain.
|
||||
|
||||
For further details on `pass`, GPG, or YubiKey, refer to their respective documentation. A secure password manager setup like this ensures your sensitive information stays safe across devices.
|
||||
|
||||
# References
|
||||
- [Standard unix password manager](https://www.passwordstore.org/)
|
||||
- [drduh's YubiKey Guide](https://github.com/drduh/YubiKey-Guide)
|
||||
- [Android Password Store issue](https://github.com/android-password-store/Android-Password-Store/issues/173#issuecomment-453686599)
|
@@ -1,39 +1,18 @@
|
||||
+++
|
||||
title = "Debrepo"
|
||||
date = 2023-05-01
|
||||
description = "Lightweight tool to create and manage Debian APT repositories"
|
||||
description = "A Debian repository management tool"
|
||||
|
||||
[extra]
|
||||
state = "stable"
|
||||
+++
|
||||
|
||||
**Debrepo** is a lightweight tool for creating and managing Debian repositories for `*.deb` packages — a simple alternative to heavier tools like `reprepro` or `aptly`.
|
||||
# Debrepo
|
||||
A Debian repository management tool.
|
||||
|
||||
#### **Key Features:**
|
||||
* **Init repository structure** (`debrepo init`)
|
||||
* **Add / delete packages** (`debrepo add`, `debrepo del`)
|
||||
* **List packages** (`debrepo list`)
|
||||
* **Built-in static serving** for quick testing (`debrepo serve`)
|
||||
* **Minimal deps:** `sh`, `dpkg`, `gpg`, `python3`
|
||||
## About
|
||||
`Debrepo` is a software tool designed for creating and managing Debian repositories for `*.deb` packages, providing a lightweight and user-friendly alternative to more complex tools like `reprepo` or `aptly`. While these alternatives may offer more advanced features, Debrepo focuses on providing essential functionality and ease of use for repository management, allowing users to easily add, remove, and update packages within their repositories. With Debrepo, users can efficiently manage their Debian repositories without the unnecessary complexity of more advanced tools.
|
||||
|
||||
#### **Quick usage**
|
||||
```bash
|
||||
# create repo structure
|
||||
debrepo init /path/to/repo
|
||||
|
||||
# add a package
|
||||
debrepo add ./build/foo_1.0_amd64.deb
|
||||
|
||||
# list & remove
|
||||
debrepo list
|
||||
debrepo del foo_1.0_amd64
|
||||
|
||||
# serve locally (for testing)
|
||||
debrepo serve
|
||||
````
|
||||
|
||||
Find the source here:
|
||||
|
||||
* Primary (Gitea): [https://git.filiprojek.cz/fr/debrepo](https://git.filiprojek.cz/fr/debrepo)
|
||||
* GitHub (mirror): [https://github.com/filiprojek/debrepo](https://github.com/filiprojek/debrepo)
|
||||
## Links
|
||||
- [Git](https://git.filiprojek.cz/fr/debrepo)
|
||||
|
||||
|
@@ -1,24 +1,22 @@
|
||||
+++
|
||||
title = "WALauncher"
|
||||
date = 2024-12-15
|
||||
description = "A lightweight launcher for your web apps, an alternative to Muximux"
|
||||
description = "A lightweight launcher for your web apps, an alternative to Muximux "
|
||||
|
||||
[extra]
|
||||
state = "done"
|
||||
+++
|
||||
|
||||
**WALauncher** is a lightweight, web-based application launcher created as a modern alternative to [Muximux](https://github.com/mescon/Muximux). It is designed for effectively managing web applications such as Servarr, yet it offers extensive customization options suitable for various web-based services.
|
||||
The **WALauncher** project is a lightweight, web-based application launcher designed as a modern and streamlined alternative to [Muximux](https://github.com/mescon/Muximux). It’s perfect for managing web applications like Servarr apps but is highly customizable to support any web-based services.
|
||||
|
||||
WALauncher enables users to organize their web services into a user-friendly dashboard, making it ideal for home servers or personal projects.
|
||||
WALauncher provides a sleek, user-friendly interface for consolidating your web services into a single, accessible dashboard, making it an efficient tool for home servers or personal projects.
|
||||
|
||||
#### **Key Features:**
|
||||
#### **Key Features**
|
||||
- **Minimalistic Design:** Intuitive layout for easy access to all your web apps.
|
||||
- **Docker Support:** Deploy effortlessly using the provided Docker setup for consistent and reliable hosting.
|
||||
- **Customizable:** Configure apps, icons, titles, and additional options to fit your preferences.
|
||||
- **Open Source:** Contribute to or modify the project to suit your needs.
|
||||
|
||||
* **Minimalistic Design:** Intuitive layout for easy access to all your web apps.
|
||||
* **Docker Support:** Deploy effortlessly using the provided Docker setup for consistent and reliable hosting.
|
||||
* **Customizable:** Configure apps, icons, titles, and additional options to fit your preferences.
|
||||
* **Open Source:** Contribute to or modify the project to suit your needs.
|
||||
|
||||
WALauncher combines simplicity and functionality for managing your web services with minimal overhead. It’s a solution you can easily deploy and adapt to your workflow.
|
||||
|
||||
Visit the [GitHub](https://github.com/filiprojek/walauncher) repository for additional information and screenshots.
|
||||
WALauncher combines simplicity and functionality for managing your web services with minimal overhead. It’s a solution you can easily deploy and adapt to your workflow.
|
||||
|
||||
Visit the [GitHub](https://github.com/filiprojek/walauncher) repository for more details, screenshots, and support. Start managing your web apps with ease!
|
||||
|
48
postbuild.sh
48
postbuild.sh
@@ -7,40 +7,30 @@ timestamp=$(date +%s)
|
||||
# Define an array of folders to skip
|
||||
skip_folders=("img" "svg" "fonts")
|
||||
|
||||
# Function to check if a path is within a skipped folder
|
||||
is_skipped_folder() {
|
||||
local path=$1
|
||||
for skip in "${skip_folders[@]}"; do
|
||||
if [[ "$path" == */$skip/* ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to add timestamp to CSS files and update HTML imports
|
||||
update_css_references() {
|
||||
find "$public_dir" -type f -name "*$css_extension" | while read -r css_file; do
|
||||
if is_skipped_folder "$css_file"; then
|
||||
continue
|
||||
# Find all CSS files in the root of the public directory
|
||||
for css_file in "$public_dir"/*$css_extension; do
|
||||
if [[ -f "$css_file" ]]; then
|
||||
base_name=$(basename "$css_file" "$css_extension")
|
||||
new_name="${base_name}-${timestamp}${css_extension}"
|
||||
|
||||
# Rename the CSS file
|
||||
mv "$css_file" "$public_dir/$new_name"
|
||||
echo "Renamed: $css_file -> $new_name"
|
||||
|
||||
# Update all HTML files in the root and 'archiv' folder
|
||||
for html_file in "$public_dir"/*.html "$public_dir/archiv/"*.html; do
|
||||
if [[ -f "$html_file" ]]; then
|
||||
sed -i "s|$base_name$css_extension|$new_name|g" "$html_file"
|
||||
echo "Updated references in: $html_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
base_dir=$(dirname "$css_file")
|
||||
base_name=$(basename "$css_file" "$css_extension")
|
||||
new_name="${base_name}-${timestamp}${css_extension}"
|
||||
new_path="${base_dir}/${new_name}"
|
||||
|
||||
# Rename the CSS file
|
||||
mv "$css_file" "$new_path"
|
||||
echo "Renamed: $css_file -> $new_path"
|
||||
|
||||
# Update all HTML files under public recursively
|
||||
find "$public_dir" -type f -name "*.html" | while read -r html_file; do
|
||||
sed -i "s|$base_name$css_extension|$new_name|g" "$html_file"
|
||||
echo "Updated references in: $html_file"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Add timestamp to CSS files and update HTML references (including archiv/index.html)
|
||||
update_css_references
|
||||
|
||||
|
||||
|
@@ -1,20 +1,9 @@
|
||||
.about {
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p {
|
||||
h3, h4, h5, h6, p {
|
||||
margin-top: .5rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
@@ -22,6 +11,5 @@
|
||||
p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
margin-bottom: 3rem; // space for footer
|
||||
}
|
||||
|
||||
|
@@ -24,30 +24,6 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.latest-projects-posts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-top: 5rem;
|
||||
margin-bottom: 2rem;
|
||||
.project {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 1rem 0;
|
||||
width: 100%;
|
||||
max-width: 40%;
|
||||
gap: 1rem;
|
||||
.title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.description {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
#pgp {
|
||||
display: none;
|
||||
@@ -55,9 +31,5 @@
|
||||
#pgpmobile {
|
||||
display: inline-block;
|
||||
}
|
||||
.latest-projects-posts .project {
|
||||
margin: 1rem 5%;
|
||||
max-width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -51,7 +51,6 @@ code {
|
||||
|
||||
.copy-code-wrapper {
|
||||
position: relative;
|
||||
margin-block-start: 1em; // Fixes wrong margin when code block is inside listed item
|
||||
}
|
||||
|
||||
.copy-code {
|
||||
@@ -67,7 +66,13 @@ code {
|
||||
@media (max-width: 768px) {
|
||||
.project-wrapper {
|
||||
max-width: 100%;
|
||||
margin: 0rem 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.project-wrapper {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100dvh;
|
||||
min-height: 100vmax;
|
||||
font-family: 'Source Code Pro', monospace;
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
@@ -79,8 +79,7 @@ footer {
|
||||
align-items: center;
|
||||
align-self: flex-end;
|
||||
margin-top: auto;
|
||||
margin-bottom: max(2rem, env(safe-area-inset-bottom)); /* Account for safe area */
|
||||
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
|
@@ -1,28 +1,30 @@
|
||||
const codes = document.querySelectorAll("pre");
|
||||
let codes = document.querySelectorAll("pre")
|
||||
|
||||
codes.forEach((code) => {
|
||||
const elWrapper = document.createElement("div");
|
||||
elWrapper.classList.add("copy-code-wrapper");
|
||||
codes.forEach(code => {
|
||||
const elWrapper = document.createElement("div")
|
||||
elWrapper.classList.add("copy-code-wrapper")
|
||||
|
||||
const el = document.createElement("span");
|
||||
el.textContent = "Copy";
|
||||
el.classList.add("copy-code");
|
||||
|
||||
elWrapper.appendChild(el);
|
||||
const el = document.createElement("span")
|
||||
el.textContent = "Copy"
|
||||
el.classList.add("copy-code")
|
||||
|
||||
code.parentNode.insertBefore(elWrapper, code);
|
||||
elWrapper.appendChild(el)
|
||||
|
||||
let textContent = "";
|
||||
code.childNodes.forEach((child) => {
|
||||
textContent += child.textContent;
|
||||
});
|
||||
code.parentNode.insertBefore(elWrapper, code)
|
||||
|
||||
let textContent = ""
|
||||
code.childNodes.forEach(child => {
|
||||
textContent += child.textContent;
|
||||
})
|
||||
|
||||
elWrapper.addEventListener("click", (e) => {
|
||||
e.preventDefault()
|
||||
navigator.clipboard.writeText(textContent)
|
||||
el.textContent = "Copied!"
|
||||
setTimeout(() => {
|
||||
el.textContent = "Copy"
|
||||
}, 5000);
|
||||
})
|
||||
})
|
||||
|
||||
elWrapper.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(textContent);
|
||||
el.textContent = "Copied!";
|
||||
setTimeout(() => {
|
||||
el.textContent = "Copy";
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
|
107
static/js/console.js
Normal file
107
static/js/console.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const c = document.querySelector(".console")
|
||||
const ps1 = "[fr@website ~]$ "
|
||||
const motd = "Welcome to my website!<br>You can use `help` for more informations :)"
|
||||
let line = "";
|
||||
|
||||
function exec(command) {
|
||||
switch (command[0]) {
|
||||
case "help":
|
||||
line = "help<br>author<br>contact<br>clear<br>echo"
|
||||
break;
|
||||
case "author":
|
||||
line = "Filip Rojek, 2023"
|
||||
break
|
||||
case "contact":
|
||||
line = "Filip Rojek <<a href='mailto: filip@filiprojek.cz'>filip@filiprojek.cz</a>><br>web: <a href='https://filiprojek.cz' target='_blank'>www.filiprojek.cz</a><br>telegram: <a href='https://t.me/filiprojek' target='_blank'>@filiprojek</a>"
|
||||
break
|
||||
case "clear":
|
||||
write("000ctrll")
|
||||
return false
|
||||
case "echo":
|
||||
line = ""
|
||||
command.forEach((cmd, i) => {
|
||||
if (i === 0) return
|
||||
line += cmd + " "
|
||||
});
|
||||
line = line.substring(0, line.length - 1) // remove last space
|
||||
break
|
||||
default:
|
||||
line = "frsh: " + command[0] + ": command not found"
|
||||
break;
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
function write(key, payload) {
|
||||
switch(key) {
|
||||
case "Enter":
|
||||
command = c.lastChild.textContent.replace(ps1, "")
|
||||
command = command.split(" ");
|
||||
let out = exec(command)
|
||||
if(out !== false) {
|
||||
line = document.createElement("p")
|
||||
line.innerHTML += out
|
||||
line.innerHTML += "<br>"
|
||||
c.appendChild(line)
|
||||
line = document.createElement("p")
|
||||
line.innerHTML += ps1
|
||||
c.appendChild(line)
|
||||
}
|
||||
command = ""
|
||||
break
|
||||
case "000ctrll":
|
||||
c.innerHTML = ""
|
||||
if(payload == motd) c.innerHTML = motd
|
||||
line = document.createElement("p")
|
||||
line.innerHTML += ps1
|
||||
c.appendChild(line)
|
||||
break
|
||||
case "000backspace":
|
||||
if(c.lastChild.textContent.slice(0, -1) !== ps1.slice(0, -1)) {
|
||||
c.lastChild.innerHTML = c.lastChild.textContent.slice(0, -1)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
c.lastChild.innerHTML += key
|
||||
}
|
||||
}
|
||||
|
||||
function customCtrlShortcuts(plusKey) {
|
||||
document.addEventListener("keydown", e => {
|
||||
if(e.ctrlKey && e.key == plusKey) {
|
||||
e.preventDefault()
|
||||
write("000ctrl"+plusKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// On load init the terminal
|
||||
window.addEventListener("load", () => {
|
||||
write("000ctrll", motd)
|
||||
if (navigator.userAgent.toLowerCase().includes("mobile")) {
|
||||
const mi = document.querySelector(".mobile-input")
|
||||
mi.style="opacity: 0; width: 0; height: 0"
|
||||
c.addEventListener("click", e => {
|
||||
mi.focus()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Capture the keypress
|
||||
window.addEventListener("keypress", e => {
|
||||
e.preventDefault()
|
||||
write(e.key)
|
||||
})
|
||||
|
||||
window.addEventListener("keydown", e => {
|
||||
if(e.key == "Backspace") {
|
||||
e.preventDefault()
|
||||
write("000backspace")
|
||||
}
|
||||
})
|
||||
|
||||
// Register custom ctrl shortcuts
|
||||
customCtrlShortcuts("l") // ctrl + l
|
||||
customCtrlShortcuts("c") // ctrl + c
|
@@ -1,24 +1,26 @@
|
||||
const burger = document.querySelector(".hamburger");
|
||||
const links = document.querySelector(".links");
|
||||
const body = document.querySelector("body");
|
||||
const main = document.querySelector("main");
|
||||
const burger = document.querySelector(".hamburger")
|
||||
const links = document.querySelector(".links")
|
||||
const body = document.querySelector("body")
|
||||
const main = document.querySelector("main")
|
||||
|
||||
let shown = false;
|
||||
let shown = false
|
||||
|
||||
burger.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
|
||||
if (!shown) {
|
||||
links.style.display = "flex"
|
||||
body.classList.add("disable-scroll")
|
||||
burger.textContent = "x"
|
||||
main.style.visibility = "hidden"
|
||||
} else {
|
||||
links.style.display = "none"
|
||||
body.classList.remove("disable-scroll")
|
||||
burger.textContent = "☰"
|
||||
main.style.visibility = "visible"
|
||||
}
|
||||
|
||||
shown = !shown
|
||||
})
|
||||
|
||||
if (!shown) {
|
||||
links.style.display = "flex";
|
||||
body.classList.add("disable-scroll");
|
||||
burger.textContent = "x";
|
||||
main.style.visibility = "hidden";
|
||||
} else {
|
||||
links.style.display = "none";
|
||||
body.classList.remove("disable-scroll");
|
||||
burger.textContent = "☰";
|
||||
main.style.visibility = "visible";
|
||||
}
|
||||
|
||||
shown = !shown;
|
||||
});
|
||||
|
@@ -6,7 +6,6 @@
|
||||
|
||||
{% block content %}
|
||||
<section class="about content">
|
||||
<h1>{{ page.title }}</h1>
|
||||
{{ page.content | safe }}
|
||||
{{ page.content | safe }}
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
@@ -28,7 +28,6 @@
|
||||
<script defer src="/js/mobile-navbar.js"></script>
|
||||
{% block styles %}
|
||||
{% endblock styles %}
|
||||
<script defer data-domain="filiprojek.cz" src="https://analytics.fofrweb.com/js/script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
@@ -61,7 +60,6 @@
|
||||
{% endblock content %}
|
||||
</main>
|
||||
<footer>
|
||||
<p>Built using <a href="https://getzola.org" target="_blank">Zola SSG</a></p>
|
||||
<p>Build time: {{ now() | date(format="%Y-%m-%d %H:%M") }},
|
||||
{% if config.extra.git %}
|
||||
<a href="{{ config.extra.git }}" target="_blank">Source</a>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<section>
|
||||
<p>Filip Rojek <filip@filiprojek.cz></p>
|
||||
<br>
|
||||
<p>Linux sysadmin, software engineer <a href="https://www.fofrweb.com/" target="_blank">@fofrweb</a>,<br> GNU/Linux <a href="http://voidlinux.org" target="_blank">Void</a> contributor and student at Charles University in Prague<span class="underscore">_</span><p>
|
||||
<p>Linux sysadmin, backend node.js & php developer <a href="https://www.fofrweb.com/" target="_blank">@fofrweb</a>,<br> GNU/Linux <a href="http://voidlinux.org" target="_blank">Void</a> user, student and coffee enthusiast<span class="underscore">_</span><p>
|
||||
<br>
|
||||
<p>PGP: <a href="https://keys.openpgp.org/vks/v1/by-fingerprint/CA3D9BE28315B49164130CD97E65EA58C6075F09" target="_blank">0x7E65EA58C6075F09</a></p>
|
||||
<br>
|
||||
@@ -22,38 +22,5 @@
|
||||
</script>
|
||||
</section>
|
||||
|
||||
{# how many items to show #}
|
||||
{% set n = 6 %}
|
||||
|
||||
{# fetch sections #}
|
||||
{% set posts = get_section(path="posts/_index.md") %}
|
||||
{% set projects = get_section(path="projects/_index.md") %}
|
||||
|
||||
{# merge, sort by date (desc), take first n #}
|
||||
{% set latest = posts.pages
|
||||
| concat(with=projects.pages)
|
||||
| sort(attribute="date")
|
||||
| reverse
|
||||
| slice(end=n)
|
||||
%}
|
||||
|
||||
<section class="latest-projects-posts">
|
||||
<h2>Latest projects & posts</h2>
|
||||
{% for page in latest %}
|
||||
<div class="project">
|
||||
<a class="title" href="{{ page.permalink }}">{{ page.title }}</a>
|
||||
<p class="description">
|
||||
{% if page.description %}{{ page.description }}{% else %}…{% endif %}
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
{{ page.date }}
|
||||
{% if page.path is starting_with("posts/") %} · Post
|
||||
{% elif page.path is starting_with("projects/") %} · Project
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
{% endblock content %}
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
<hr>
|
||||
<p>{{ project.date }}</p>
|
||||
<p>{{ project.date }} | {{ project.extra.state}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
Reference in New Issue
Block a user