Add docker build
This commit is contained in:
parent
eff3ae7e57
commit
057e800b1b
10 changed files with 608 additions and 0 deletions
6
.docker/.dockerignore
Normal file
6
.docker/.dockerignore
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
public/
|
||||
.git/
|
||||
.gitignore
|
||||
README.md
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
17
.docker/Dockerfile
Normal file
17
.docker/Dockerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Build stage
|
||||
FROM alpine:latest as builder
|
||||
|
||||
# Install Zola
|
||||
RUN apk add --no-cache zola
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN zola build
|
||||
|
||||
# Runtime stage
|
||||
FROM docker.io/library/nginx:alpine
|
||||
|
||||
COPY --from=builder /app/public /usr/share/nginx/html
|
||||
COPY .docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
34
.docker/build-docker.sh
Executable file
34
.docker/build-docker.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#\!/bin/bash
|
||||
set -e
|
||||
|
||||
# Check if tag is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 <tag>"
|
||||
echo "Example: $0 v0.1.2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configuration
|
||||
REGISTRY="codeberg.org"
|
||||
NAMESPACE="lvl0"
|
||||
IMAGE_NAME="website"
|
||||
TAG="$1"
|
||||
FULL_IMAGE="${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${TAG}"
|
||||
|
||||
echo "Building Docker image: ${FULL_IMAGE}"
|
||||
|
||||
# Build the image
|
||||
docker build -f .docker/Dockerfile -t "${FULL_IMAGE}" .
|
||||
|
||||
# Also tag as latest
|
||||
LATEST_IMAGE="${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:latest"
|
||||
docker tag "${FULL_IMAGE}" "${LATEST_IMAGE}"
|
||||
|
||||
echo "Image built successfully!"
|
||||
echo "Tagged as: ${FULL_IMAGE}"
|
||||
echo "Tagged as: ${LATEST_IMAGE}"
|
||||
echo ""
|
||||
echo "To push to registry, run:"
|
||||
echo "docker login ${REGISTRY}"
|
||||
echo "docker push ${FULL_IMAGE}"
|
||||
echo "docker push ${LATEST_IMAGE}"
|
||||
16
.docker/nginx.conf
Normal file
16
.docker/nginx.conf
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /404.html;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
100
public/404.html
Normal file
100
public/404.html
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<!doctype html>
|
||||
<html class="not-ready lg:text-base overflow-y-scroll scroll-pt-14" lang="en">
|
||||
|
||||
<head prefix="og: https://ogp.me/ns#">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="generator" content="Zola" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<title>404: Page not found | lvl0</title>
|
||||
<meta property="og:site_name" content="lvl0" />
|
||||
<meta property="og:title" content="404: Page not found" />
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- Begin Head inject -->
|
||||
|
||||
<!-- End Head inject -->
|
||||
<link rel="stylesheet" href="https://lvl0.xyz/main.min.css?h=fc65ba308cf36d3ba82c" />
|
||||
<style>
|
||||
:root{--bg: #f4f4f5; --header: #e4e4e7; color-scheme: light;}
|
||||
:root.dark{--bg: #18181b; --header: #27272a; color-scheme: dark;}
|
||||
</style>
|
||||
<meta name="theme-color" data-light="#e4e4e7" data-dark="#27272a" content="#e4e4e7" />
|
||||
<link rel="icon" type="image/x-icon" sizes="16x16" href="https://lvl0.xyz/favicon.ico" />
|
||||
<link rel="apple-touch-icon" type="image/png" href="https://lvl0.xyz/apple-touch-icon.png?h=58bee300054c5308feb3" />
|
||||
<link rel="icon" type="image/png" href="https://lvl0.xyz/android-icon.png?h=8d80ec95446bd2c36826" />
|
||||
<script src="https://lvl0.xyz/js/linkita.min.js?h=1dd3ed42fc674277bc34"></script>
|
||||
<!-- Begin Head End inject -->
|
||||
|
||||
<!-- End Head End inject -->
|
||||
</head>
|
||||
|
||||
<body class="text-black duration-100 ease-out bg-[var(--bg)] dark:text-white">
|
||||
<!-- Header -->
|
||||
<header class="bg-[var(--header)] fixed top-0 z-40 mx-auto min-h-[3.25rem] w-full header-icons">
|
||||
<div class="mx-auto w-full max-w-4xl p-2.5 lg:flex lg:justify-between">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center min-h-8">
|
||||
<a title="Go to home page" accesskey="!"
|
||||
href="https://lvl0.xyz/" class="text-2xl font-semibold">lvl0</a>
|
||||
<button type="button" title="Switch color scheme" accesskey="$"
|
||||
onclick="window.linkita.toggleDarkMode();" ondblclick="window.linkita.resetDarkMode();"
|
||||
class="btn-dark ml-4 h-6 w-6 shrink-0 cursor-pointer text-[0] bg-center bg-no-repeat bg-cover dark:invert [background-image:var(--icon-theme-dark)] dark:[background-image:var(--icon-theme-light)]"
|
||||
></button>
|
||||
</div>
|
||||
<div title="Menu" role="button" accesskey="+" tabindex="0"
|
||||
class="btn-menu relative z-50 flex h-8 w-8 shrink-0 cursor-pointer flex-col items-center justify-center gap-2.5 lg:hidden"
|
||||
onclick="window.linkita.toggleHeaderMenu();"
|
||||
onkeydown="(event.keyCode == 13 || event.keyCode == 32) ? event.preventDefault() || window.linkita.toggleHeaderMenu() : true;"
|
||||
></div>
|
||||
</div>
|
||||
<nav class="flex w-full items-center lg:w-auto">
|
||||
<menu
|
||||
class="nav-wrapper flex w-full flex-col py-2 lg:w-auto lg:flex-row lg:self-center lg:py-0">
|
||||
<li>
|
||||
<a
|
||||
class="primary-link block py-2 text-center text-lg font-medium lg:px-3 lg:py-0"
|
||||
href="/announcements/"
|
||||
>Announcements</a>
|
||||
</li>
|
||||
</menu>
|
||||
<!-- Begin Header Nav inject -->
|
||||
|
||||
<!-- End Header Nav inject -->
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Begin Body Start inject -->
|
||||
|
||||
<!-- End Body Start inject -->
|
||||
<main class="prose prose-neutral relative mx-auto min-h-[calc(100%-4rem)]
|
||||
max-w-3xl break-words px-4 pb-12 pt-28 lg:pt-32 dark:prose-invert prose-pre:rounded-lg prose-img:rounded-lg">
|
||||
|
||||
<h1 class="absolute inset-x-8 bottom-20 top-0 flex items-center justify-center text-6xl">404: Page not found</h1>
|
||||
|
||||
</main>
|
||||
<!-- Footer -->
|
||||
<footer class="mx-auto flex lg:mt-5 max-w-3xl flex-wrap items-center px-4 py-3 text-sm opacity-60">
|
||||
<div class="mr-auto basis-full lg:basis-1/2">
|
||||
© <time datetime="2025">2025</time>
|
||||
</div>
|
||||
<div class="flex basis-full lg:basis-1/2 lg:justify-end">
|
||||
<span class="mr-6 lg:ml-6">
|
||||
<a class="link" href="https://www.getzola.org/" target="_blank">Powered by Zola</a>
|
||||
</span>
|
||||
<a class="link" href="https://www.getzola.org/themes/linkita/" target="_blank">✎ Linkita</a>
|
||||
</div>
|
||||
<!-- Begin Footer inject -->
|
||||
|
||||
<!-- End Footer inject -->
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<!-- Begin Body End inject -->
|
||||
|
||||
<!-- End Body End inject -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
159
public/announcements/incr-stable-release/index.html
Normal file
159
public/announcements/incr-stable-release/index.html
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<!doctype html>
|
||||
<html class="not-ready lg:text-base overflow-y-scroll scroll-pt-14" lang="en">
|
||||
|
||||
<head prefix="og: https://ogp.me/ns# article: https://ogp.me/ns/article#">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="generator" content="Zola" />
|
||||
<title>incr 0.1.2: First Stable Release | lvl0</title>
|
||||
<meta property="og:site_name" content="lvl0" />
|
||||
<meta property="og:title" content="incr 0.1.2: First Stable Release" />
|
||||
<meta property="og:url" content="https://lvl0.xyz/announcements/incr-stable-release/" />
|
||||
<link rel="canonical" href="https://lvl0.xyz/announcements/incr-stable-release/" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="article:published_time" content="2025-08-01T00:00:00+00:00" />
|
||||
<!-- Begin Head inject -->
|
||||
|
||||
<!-- End Head inject -->
|
||||
<link rel="stylesheet" href="https://lvl0.xyz/main.min.css?h=fc65ba308cf36d3ba82c" />
|
||||
<style>
|
||||
:root{--bg: #f4f4f5; --header: #e4e4e7; color-scheme: light;}
|
||||
:root.dark{--bg: #18181b; --header: #27272a; color-scheme: dark;}
|
||||
</style>
|
||||
<meta name="theme-color" data-light="#e4e4e7" data-dark="#27272a" content="#e4e4e7" />
|
||||
<link rel="icon" type="image/x-icon" sizes="16x16" href="https://lvl0.xyz/favicon.ico" />
|
||||
<link rel="apple-touch-icon" type="image/png" href="https://lvl0.xyz/apple-touch-icon.png?h=58bee300054c5308feb3" />
|
||||
<link rel="icon" type="image/png" href="https://lvl0.xyz/android-icon.png?h=8d80ec95446bd2c36826" />
|
||||
<script src="https://lvl0.xyz/js/linkita.min.js?h=1dd3ed42fc674277bc34"></script>
|
||||
<!-- Begin Head End inject -->
|
||||
|
||||
<!-- End Head End inject -->
|
||||
</head>
|
||||
|
||||
<body class="text-black duration-100 ease-out bg-[var(--bg)] dark:text-white">
|
||||
<!-- Header -->
|
||||
<header class="bg-[var(--header)] fixed top-0 z-40 mx-auto min-h-[3.25rem] w-full header-icons">
|
||||
<div class="mx-auto w-full max-w-4xl p-2.5 lg:flex lg:justify-between">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center min-h-8">
|
||||
<a title="Go to home page" accesskey="!"
|
||||
href="https://lvl0.xyz/" class="text-2xl font-semibold">lvl0</a>
|
||||
<button type="button" title="Switch color scheme" accesskey="$"
|
||||
onclick="window.linkita.toggleDarkMode();" ondblclick="window.linkita.resetDarkMode();"
|
||||
class="btn-dark ml-4 h-6 w-6 shrink-0 cursor-pointer text-[0] bg-center bg-no-repeat bg-cover dark:invert [background-image:var(--icon-theme-dark)] dark:[background-image:var(--icon-theme-light)]"
|
||||
></button>
|
||||
</div>
|
||||
<div title="Menu" role="button" accesskey="+" tabindex="0"
|
||||
class="btn-menu relative z-50 flex h-8 w-8 shrink-0 cursor-pointer flex-col items-center justify-center gap-2.5 lg:hidden"
|
||||
onclick="window.linkita.toggleHeaderMenu();"
|
||||
onkeydown="(event.keyCode == 13 || event.keyCode == 32) ? event.preventDefault() || window.linkita.toggleHeaderMenu() : true;"
|
||||
></div>
|
||||
</div>
|
||||
<nav class="flex w-full items-center lg:w-auto">
|
||||
<menu
|
||||
class="nav-wrapper flex w-full flex-col py-2 lg:w-auto lg:flex-row lg:self-center lg:py-0">
|
||||
<li>
|
||||
<a
|
||||
class="primary-link block py-2 text-center text-lg font-medium lg:px-3 lg:py-0"
|
||||
href="/announcements/"
|
||||
>Announcements</a>
|
||||
</li>
|
||||
</menu>
|
||||
<!-- Begin Header Nav inject -->
|
||||
|
||||
<!-- End Header Nav inject -->
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Begin Body Start inject -->
|
||||
|
||||
<!-- End Body Start inject -->
|
||||
<main class="prose prose-neutral relative mx-auto min-h-[calc(100%-4rem)]
|
||||
max-w-3xl break-words px-4 pb-12 pt-28 lg:pt-32 dark:prose-invert prose-pre:rounded-lg prose-img:rounded-lg">
|
||||
|
||||
<article>
|
||||
<!-- Begin Page Start inject -->
|
||||
|
||||
<!-- End Page Start inject -->
|
||||
|
||||
<header class="mb-16">
|
||||
<h1 class="!my-0 pb-2.5">incr 0.1.2: First Stable Release</h1>
|
||||
<!-- Page Info -->
|
||||
<div class="text-sm antialiased opacity-80"><time
|
||||
datetime="2025-08-01T00:00:00+00:00">2025-08-01</time><span
|
||||
class="mx-1">·</span><time
|
||||
datetime="PT0H1M0S">1 min</time>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
<!-- TOC -->
|
||||
<div class="block-bg mb-12 rounded-lg p-2 text-lg">
|
||||
<details>
|
||||
<summary class="select-none py-0.5 lg:py-1 pl-4" accesskey="=">
|
||||
<span class="cursor-pointer">Table of Contents</span>
|
||||
</summary>
|
||||
<div class="px-2">
|
||||
<ul>
|
||||
<li>
|
||||
<a class="no-underline hover:underline" href="https://lvl0.xyz/announcements/incr-stable-release/#what-is-incr">What is incr?</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="no-underline hover:underline" href="https://lvl0.xyz/announcements/incr-stable-release/#key-features">Key Features</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="no-underline hover:underline" href="https://lvl0.xyz/announcements/incr-stable-release/#get-started">Get Started</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<section><p>We're excited to announce the first stable release of <strong>incr</strong> - our FIRE journey tracking tool that focuses on shares, not slogans.</p>
|
||||
<h2 id="what-is-incr">What is incr?</h2>
|
||||
<p>incr is a minimalist tool designed to help you track your Financial Independence, Retire Early (FIRE) journey with precision and clarity. Instead of flashy charts and motivational slogans, incr focuses on what matters: tracking your investment shares and real progress toward financial independence.</p>
|
||||
<h2 id="key-features">Key Features</h2>
|
||||
<ul>
|
||||
<li><strong>Share-based tracking</strong>: Monitor your portfolio in actual shares, not just dollar amounts</li>
|
||||
<li><strong>Self-hosted</strong>: Keep your financial data private and under your control</li>
|
||||
<li><strong>Minimalist design</strong>: Clean, distraction-free interface that focuses on your data</li>
|
||||
<li><strong>Long-term thinking</strong>: Built for the patient investor pursuing financial autonomy</li>
|
||||
</ul>
|
||||
<h2 id="get-started">Get Started</h2>
|
||||
<p>Visit <a href="https://incr.lvl0.xyz">incr.lvl0.xyz</a> to learn more and start tracking your FIRE journey today.</p>
|
||||
</section>
|
||||
<hr />
|
||||
<!-- Post Taxonomies -->
|
||||
|
||||
<!-- Begin Page End inject -->
|
||||
|
||||
<!-- End Page End inject -->
|
||||
</article>
|
||||
|
||||
</main>
|
||||
<!-- Footer -->
|
||||
<footer class="mx-auto flex lg:mt-5 max-w-3xl flex-wrap items-center px-4 py-3 text-sm opacity-60">
|
||||
<div class="mr-auto basis-full lg:basis-1/2">
|
||||
© <time datetime="2025">2025</time>
|
||||
</div>
|
||||
<div class="flex basis-full lg:basis-1/2 lg:justify-end">
|
||||
<span class="mr-6 lg:ml-6">
|
||||
<a class="link" href="https://www.getzola.org/" target="_blank">Powered by Zola</a>
|
||||
</span>
|
||||
<a class="link" href="https://www.getzola.org/themes/linkita/" target="_blank">✎ Linkita</a>
|
||||
</div>
|
||||
<!-- Begin Footer inject -->
|
||||
|
||||
<!-- End Footer inject -->
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<!-- Begin Body End inject -->
|
||||
|
||||
<!-- End Body End inject -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
125
public/announcements/index.html
Normal file
125
public/announcements/index.html
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<!doctype html>
|
||||
<html class="not-ready lg:text-base overflow-y-scroll scroll-pt-14" lang="en">
|
||||
|
||||
<head prefix="og: https://ogp.me/ns#">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="generator" content="Zola" />
|
||||
<title>Announcements | lvl0</title>
|
||||
<meta property="og:site_name" content="lvl0" />
|
||||
<meta property="og:title" content="Announcements" />
|
||||
<meta property="og:url" content="https://lvl0.xyz/announcements/" />
|
||||
<link rel="canonical" href="https://lvl0.xyz/announcements/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- Begin Head inject -->
|
||||
|
||||
<!-- End Head inject -->
|
||||
<link rel="stylesheet" href="https://lvl0.xyz/main.min.css?h=fc65ba308cf36d3ba82c" />
|
||||
<style>
|
||||
:root{--bg: #f4f4f5; --header: #e4e4e7; color-scheme: light;}
|
||||
:root.dark{--bg: #18181b; --header: #27272a; color-scheme: dark;}
|
||||
</style>
|
||||
<meta name="theme-color" data-light="#e4e4e7" data-dark="#27272a" content="#e4e4e7" />
|
||||
<link rel="icon" type="image/x-icon" sizes="16x16" href="https://lvl0.xyz/favicon.ico" />
|
||||
<link rel="apple-touch-icon" type="image/png" href="https://lvl0.xyz/apple-touch-icon.png?h=58bee300054c5308feb3" />
|
||||
<link rel="icon" type="image/png" href="https://lvl0.xyz/android-icon.png?h=8d80ec95446bd2c36826" />
|
||||
<script src="https://lvl0.xyz/js/linkita.min.js?h=1dd3ed42fc674277bc34"></script>
|
||||
<!-- Begin Head End inject -->
|
||||
|
||||
<!-- End Head End inject -->
|
||||
</head>
|
||||
|
||||
<body class="text-black duration-100 ease-out bg-[var(--bg)] dark:text-white">
|
||||
<!-- Header -->
|
||||
<header class="bg-[var(--header)] fixed top-0 z-40 mx-auto min-h-[3.25rem] w-full header-icons">
|
||||
<div class="mx-auto w-full max-w-4xl p-2.5 lg:flex lg:justify-between">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center min-h-8">
|
||||
<a title="Go to home page" accesskey="!"
|
||||
href="https://lvl0.xyz/" class="text-2xl font-semibold">lvl0</a>
|
||||
<button type="button" title="Switch color scheme" accesskey="$"
|
||||
onclick="window.linkita.toggleDarkMode();" ondblclick="window.linkita.resetDarkMode();"
|
||||
class="btn-dark ml-4 h-6 w-6 shrink-0 cursor-pointer text-[0] bg-center bg-no-repeat bg-cover dark:invert [background-image:var(--icon-theme-dark)] dark:[background-image:var(--icon-theme-light)]"
|
||||
></button>
|
||||
</div>
|
||||
<div title="Menu" role="button" accesskey="+" tabindex="0"
|
||||
class="btn-menu relative z-50 flex h-8 w-8 shrink-0 cursor-pointer flex-col items-center justify-center gap-2.5 lg:hidden"
|
||||
onclick="window.linkita.toggleHeaderMenu();"
|
||||
onkeydown="(event.keyCode == 13 || event.keyCode == 32) ? event.preventDefault() || window.linkita.toggleHeaderMenu() : true;"
|
||||
></div>
|
||||
</div>
|
||||
<nav class="flex w-full items-center lg:w-auto">
|
||||
<menu
|
||||
class="nav-wrapper flex w-full flex-col py-2 lg:w-auto lg:flex-row lg:self-center lg:py-0">
|
||||
<li>
|
||||
<a
|
||||
class="primary-link block py-2 text-center text-lg font-medium lg:px-3 lg:py-0"
|
||||
href="/announcements/"
|
||||
>Announcements</a>
|
||||
</li>
|
||||
</menu>
|
||||
<!-- Begin Header Nav inject -->
|
||||
|
||||
<!-- End Header Nav inject -->
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Begin Body Start inject -->
|
||||
|
||||
<!-- End Body Start inject -->
|
||||
<main class="prose prose-neutral relative mx-auto min-h-[calc(100%-4rem)]
|
||||
max-w-3xl break-words px-4 pb-12 pt-28 lg:pt-32 dark:prose-invert prose-pre:rounded-lg prose-img:rounded-lg">
|
||||
|
||||
<h1 class="mb-8">Announcements</h1>
|
||||
<section class="mb-12"><p>Stay updated with the latest news and releases from lvl0.</p>
|
||||
</section>
|
||||
<div class="not-prose">
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<article class="border border-gray-200 dark:border-gray-700 rounded-lg p-6 hover:shadow-md transition-shadow">
|
||||
<h2 class="text-xl font-semibold mb-3">
|
||||
<a href="https://lvl0.xyz/announcements/incr-stable-release/" class="text-blue-600 dark:text-blue-400 hover:underline">
|
||||
incr 0.1.2: First Stable Release
|
||||
</a>
|
||||
</h2>
|
||||
<time class="text-sm text-gray-500 dark:text-gray-400 mb-4 block">
|
||||
August 01, 2025
|
||||
</time>
|
||||
<div class="text-gray-700 dark:text-gray-300 mb-4">
|
||||
We're excited to announce the first stable release of incr - our FIRE journey tracking tool that focuses on shares, not slogans.
|
||||
What is incr?
|
||||
incr is a minimalist tool designed to help you track your…
|
||||
</div>
|
||||
<a href="https://lvl0.xyz/announcements/incr-stable-release/" class="text-blue-600 dark:text-blue-400 hover:underline text-sm font-medium">
|
||||
Read more →
|
||||
</a>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
<!-- Footer -->
|
||||
<footer class="mx-auto flex lg:mt-5 max-w-3xl flex-wrap items-center px-4 py-3 text-sm opacity-60">
|
||||
<div class="mr-auto basis-full lg:basis-1/2">
|
||||
© <time datetime="2025">2025</time>
|
||||
</div>
|
||||
<div class="flex basis-full lg:basis-1/2 lg:justify-end">
|
||||
<span class="mr-6 lg:ml-6">
|
||||
<a class="link" href="https://www.getzola.org/" target="_blank">Powered by Zola</a>
|
||||
</span>
|
||||
<a class="link" href="https://www.getzola.org/themes/linkita/" target="_blank">✎ Linkita</a>
|
||||
</div>
|
||||
<!-- Begin Footer inject -->
|
||||
|
||||
<!-- End Footer inject -->
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<!-- Begin Body End inject -->
|
||||
|
||||
<!-- End Body End inject -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
134
public/index.html
Normal file
134
public/index.html
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<!doctype html>
|
||||
<html class="not-ready lg:text-base overflow-y-scroll scroll-pt-14" lang="en">
|
||||
|
||||
<head prefix="og: https://ogp.me/ns#">
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="generator" content="Zola" />
|
||||
<title>lvl0</title>
|
||||
<meta property="og:site_name" content="lvl0" />
|
||||
<meta property="og:title" content="lvl0" />
|
||||
<meta property="og:url" content="https://lvl0.xyz/" />
|
||||
<link rel="canonical" href="https://lvl0.xyz/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- Begin Head inject -->
|
||||
|
||||
<!-- End Head inject -->
|
||||
<link rel="stylesheet" href="https://lvl0.xyz/main.min.css?h=fc65ba308cf36d3ba82c" />
|
||||
<style>
|
||||
:root{--bg: #f4f4f5; --header: #e4e4e7; color-scheme: light;}
|
||||
:root.dark{--bg: #18181b; --header: #27272a; color-scheme: dark;}
|
||||
</style>
|
||||
<meta name="theme-color" data-light="#e4e4e7" data-dark="#27272a" content="#e4e4e7" />
|
||||
<link rel="icon" type="image/x-icon" sizes="16x16" href="https://lvl0.xyz/favicon.ico" />
|
||||
<link rel="apple-touch-icon" type="image/png" href="https://lvl0.xyz/apple-touch-icon.png?h=58bee300054c5308feb3" />
|
||||
<link rel="icon" type="image/png" href="https://lvl0.xyz/android-icon.png?h=8d80ec95446bd2c36826" />
|
||||
<script src="https://lvl0.xyz/js/linkita.min.js?h=1dd3ed42fc674277bc34"></script>
|
||||
<!-- Begin Head End inject -->
|
||||
|
||||
<!-- End Head End inject -->
|
||||
</head>
|
||||
|
||||
<body class="text-black duration-100 ease-out bg-[var(--bg)] dark:text-white">
|
||||
<!-- Header -->
|
||||
<header class="bg-[var(--header)] fixed top-0 z-40 mx-auto min-h-[3.25rem] w-full header-icons">
|
||||
<div class="mx-auto w-full max-w-4xl p-2.5 lg:flex lg:justify-between">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center min-h-8">
|
||||
<a title="Go to home page" accesskey="!"
|
||||
href="https://lvl0.xyz/" class="text-2xl font-semibold">lvl0</a>
|
||||
<button type="button" title="Switch color scheme" accesskey="$"
|
||||
onclick="window.linkita.toggleDarkMode();" ondblclick="window.linkita.resetDarkMode();"
|
||||
class="btn-dark ml-4 h-6 w-6 shrink-0 cursor-pointer text-[0] bg-center bg-no-repeat bg-cover dark:invert [background-image:var(--icon-theme-dark)] dark:[background-image:var(--icon-theme-light)]"
|
||||
></button>
|
||||
</div>
|
||||
<div title="Menu" role="button" accesskey="+" tabindex="0"
|
||||
class="btn-menu relative z-50 flex h-8 w-8 shrink-0 cursor-pointer flex-col items-center justify-center gap-2.5 lg:hidden"
|
||||
onclick="window.linkita.toggleHeaderMenu();"
|
||||
onkeydown="(event.keyCode == 13 || event.keyCode == 32) ? event.preventDefault() || window.linkita.toggleHeaderMenu() : true;"
|
||||
></div>
|
||||
</div>
|
||||
<nav class="flex w-full items-center lg:w-auto">
|
||||
<menu
|
||||
class="nav-wrapper flex w-full flex-col py-2 lg:w-auto lg:flex-row lg:self-center lg:py-0">
|
||||
<li>
|
||||
<a
|
||||
class="primary-link block py-2 text-center text-lg font-medium lg:px-3 lg:py-0"
|
||||
href="/announcements/"
|
||||
>Announcements</a>
|
||||
</li>
|
||||
</menu>
|
||||
<!-- Begin Header Nav inject -->
|
||||
|
||||
<!-- End Header Nav inject -->
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Begin Body Start inject -->
|
||||
|
||||
<!-- End Body Start inject -->
|
||||
<main class="prose prose-neutral relative mx-auto min-h-[calc(100%-4rem)]
|
||||
max-w-3xl break-words px-4 pb-12 pt-28 lg:pt-32 dark:prose-invert prose-pre:rounded-lg prose-img:rounded-lg">
|
||||
|
||||
<section><p><strong>lvl0 is a starting point.</strong></p>
|
||||
<p>We build tiny, focused tools that support calm productivity, financial independence, and long-term thinking.</p>
|
||||
<p>Our projects embrace minimalism, self-hosting, and the pursuit of autonomy — in tech, finance, and life.</p>
|
||||
<h2 id="current-projects">Current Projects</h2>
|
||||
<p><strong><a href="https://incr.lvl0.xyz">incr</a></strong> — Track your FIRE journey in shares, not slogans. A minimalist tool for monitoring your path to financial independence with precision and clarity.</p>
|
||||
</section>
|
||||
<section class="mt-16 not-prose">
|
||||
<h2 class="text-2xl font-semibold mb-6 text-black dark:text-white">Recent Announcements</h2>
|
||||
<div class="grid gap-6 md:grid-cols-1 lg:grid-cols-3">
|
||||
<article class="border border-gray-200 dark:border-gray-700 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<h3 class="text-lg font-medium mb-2">
|
||||
<a href="https://lvl0.xyz/announcements/incr-stable-release/" class="text-blue-600 dark:text-blue-400 hover:underline">
|
||||
incr 0.1.2: First Stable Release
|
||||
</a>
|
||||
</h3>
|
||||
<time class="text-sm text-gray-500 dark:text-gray-400 mb-3 block">
|
||||
August 01, 2025
|
||||
</time>
|
||||
<div class="text-gray-700 dark:text-gray-300">
|
||||
We're excited to announce the first stable release of incr - our FIRE journey tracking tool that focuses on shares, not slogans.
|
||||
What is incr?
|
||||
incr is…
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="mt-6 text-center">
|
||||
<a href="/announcements/" class="text-blue-600 dark:text-blue-400 hover:underline font-medium">
|
||||
View all announcements →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Page List -->
|
||||
|
||||
|
||||
</main>
|
||||
<!-- Footer -->
|
||||
<footer class="mx-auto flex lg:mt-5 max-w-3xl flex-wrap items-center px-4 py-3 text-sm opacity-60">
|
||||
<div class="mr-auto basis-full lg:basis-1/2">
|
||||
© <time datetime="2025">2025</time>
|
||||
</div>
|
||||
<div class="flex basis-full lg:basis-1/2 lg:justify-end">
|
||||
<span class="mr-6 lg:ml-6">
|
||||
<a class="link" href="https://www.getzola.org/" target="_blank">Powered by Zola</a>
|
||||
</span>
|
||||
<a class="link" href="https://www.getzola.org/themes/linkita/" target="_blank">✎ Linkita</a>
|
||||
</div>
|
||||
<!-- Begin Footer inject -->
|
||||
|
||||
<!-- End Footer inject -->
|
||||
</footer>
|
||||
|
||||
|
||||
|
||||
<!-- Begin Body End inject -->
|
||||
|
||||
<!-- End Body End inject -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
4
public/robots.txt
Normal file
4
public/robots.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
User-agent: *
|
||||
Disallow:
|
||||
Allow: /
|
||||
Sitemap: https://lvl0.xyz/sitemap.xml
|
||||
13
public/sitemap.xml
Normal file
13
public/sitemap.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://lvl0.xyz/</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://lvl0.xyz/announcements/</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://lvl0.xyz/announcements/incr-stable-release/</loc>
|
||||
<lastmod>2025-08-01</lastmod>
|
||||
</url>
|
||||
</urlset>
|
||||
Loading…
Reference in a new issue