3 - Publish the docs site at style.lvl0.xyz
All checks were successful
Build and Push Docs Image / build (push) Successful in 2m10s
All checks were successful
Build and Push Docs Image / build (push) Successful in 2m10s
This commit is contained in:
parent
c7fe30f25f
commit
df07a8ab55
9 changed files with 1857 additions and 1 deletions
41
.forgejo/workflows/build.yml
Normal file
41
.forgejo/workflows/build.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
name: Build and Push Docs Image
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ['v*']
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: docker
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- uses: https://data.forgejo.org/actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: https://data.forgejo.org/docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Forgejo Registry
|
||||
uses: https://data.forgejo.org/docker/login-action@v3
|
||||
with:
|
||||
registry: forge.lvl0.xyz
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Determine tags
|
||||
id: meta
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
TAG="${{ github.ref_name }}"
|
||||
echo "tags=forge.lvl0.xyz/lvl0/ui:${TAG},forge.lvl0.xyz/lvl0/ui:latest" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tags=forge.lvl0.xyz/lvl0/ui:latest" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build and push
|
||||
uses: https://data.forgejo.org/docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/node_modules/
|
||||
/docs/dist/
|
||||
*.tgz
|
||||
10
Dockerfile
Normal file
10
Dockerfile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
FROM node:22-alpine AS builder
|
||||
WORKDIR /site
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run docs:build
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /site/docs/dist /usr/share/nginx/html
|
||||
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
15
docker/nginx.conf
Normal file
15
docker/nginx.conf
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name style.lvl0.xyz;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
307
docs/index.html
Normal file
307
docs/index.html
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>lvl0/ui — style reference</title>
|
||||
<meta name="theme-color" content="#000000">
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body class="bg-black antialiased min-h-screen font-mono text-primary p-6 lg:p-10">
|
||||
<main class="mx-auto w-full max-w-4xl">
|
||||
|
||||
<header class="mb-14">
|
||||
<h1 class="text-primary text-4xl lg:text-5xl font-bold uppercase tracking-widest glow-red-text mb-4">
|
||||
> lvl0/ui
|
||||
</h1>
|
||||
<p class="text-primary/60 text-sm max-w-2xl leading-relaxed">
|
||||
The shared visual style for lvl0 projects. This page is built with the package it
|
||||
documents, so it breaks visibly if the package does. Read the values here rather
|
||||
than from another project.
|
||||
</p>
|
||||
<p class="text-primary/40 text-xs mt-4">
|
||||
<a href="https://forge.lvl0.xyz/lvl0/ui" class="hover:text-primary transition-colors">[SOURCE]</a>
|
||||
<span class="text-bordeaux px-2">|</span>
|
||||
<code>npm i git+ssh://git@forge.lvl0.xyz:2222/lvl0/ui.git#v0.1.0</code>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-10">
|
||||
|
||||
<!-- PALETTE -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-primary text-xs uppercase tracking-wider mb-1">> Palette</h2>
|
||||
<p class="text-primary/50 text-xs mb-6">Click a value to copy. Use token names, never raw <code>red-*</code> steps.</p>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<!-- swatch: primary -->
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20" style="background: var(--color-primary)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-primary</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(63.7% 0.237 25.331)">oklch(63.7% 0.237 25.331)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">House red. Text, active borders, focus, glow source.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20" style="background: var(--color-bordeaux)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-bordeaux</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(25.8% 0.092 26.042)">oklch(25.8% 0.092 26.042)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Secondary. Dividers, resting borders, recessed chrome.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20 border-b-2 border-bordeaux" style="background: var(--color-background)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-background</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(10% 0 0)">oklch(10% 0 0)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Near-black page ground.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20 border-b-2 border-bordeaux" style="background: var(--color-card)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-card</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(12% 0 0)">oklch(12% 0 0)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Raised surface.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20" style="background: var(--color-muted)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-muted</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(20% 0 0)">oklch(20% 0 0)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Muted surface.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20" style="background: var(--color-muted-foreground)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-muted-foreground</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(50% 0.1 25)">oklch(50% 0.1 25)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Muted text.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux">
|
||||
<div class="h-20" style="background: var(--color-destructive)"></div>
|
||||
<div class="p-3 text-xs">
|
||||
<div class="text-primary font-bold">--color-destructive</div>
|
||||
<button class="copy text-primary/50 hover:text-primary transition-colors mt-1" data-v="oklch(57.7% 0.245 27.325)">oklch(57.7% 0.245 27.325)</button>
|
||||
<p class="text-primary/40 mt-2 leading-snug">Destructive actions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="text-primary/60 text-xs uppercase tracking-wider mt-8 mb-3">Chart colours</h3>
|
||||
<div class="grid grid-cols-5 gap-2">
|
||||
<div class="border-2 border-bordeaux"><div class="h-12" style="background: var(--color-chart-1)"></div><div class="p-2 text-[10px] text-primary/50">chart-1</div></div>
|
||||
<div class="border-2 border-bordeaux"><div class="h-12" style="background: var(--color-chart-2)"></div><div class="p-2 text-[10px] text-primary/50">chart-2</div></div>
|
||||
<div class="border-2 border-bordeaux"><div class="h-12" style="background: var(--color-chart-3)"></div><div class="p-2 text-[10px] text-primary/50">chart-3</div></div>
|
||||
<div class="border-2 border-bordeaux"><div class="h-12" style="background: var(--color-chart-4)"></div><div class="p-2 text-[10px] text-primary/50">chart-4</div></div>
|
||||
<div class="border-2 border-bordeaux"><div class="h-12" style="background: var(--color-chart-5)"></div><div class="p-2 text-[10px] text-primary/50">chart-5</div></div>
|
||||
</div>
|
||||
|
||||
<p class="text-primary/40 text-xs mt-4">
|
||||
<code class="text-primary/60">--radius: 0</code> — square corners throughout.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-10">
|
||||
|
||||
<!-- GLOWS -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-primary text-xs uppercase tracking-wider mb-1">> Glows</h2>
|
||||
<p class="text-primary/50 text-xs mb-6">
|
||||
The part a values table cannot convey. All four against the real background.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<div class="border-2 border-primary glow-red p-6 mb-3 text-center text-sm">.glow-red</div>
|
||||
<p class="text-primary/40 text-xs leading-snug">
|
||||
Box-shadow bloom in primary, brightening on <code>:hover</code> and
|
||||
<code>:focus</code>. For bordered elements that are active or focusable.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="p-6 mb-3 text-center">
|
||||
<span class="text-primary text-2xl font-bold uppercase tracking-widest glow-red-text">.glow-red-text</span>
|
||||
</div>
|
||||
<p class="text-primary/40 text-xs leading-snug">
|
||||
Two-layer text-shadow. <strong class="text-primary/70">Use this on text</strong> —
|
||||
<code>.glow-red</code> haloes the element's box, which smudges around a
|
||||
borderless heading instead of tracing the letters.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="border-2 border-bordeaux glow-bordeaux p-6 mb-3 text-center text-sm">.glow-bordeaux</div>
|
||||
<p class="text-primary/40 text-xs leading-snug">
|
||||
Softer bloom for bordeaux-bordered elements. <strong class="text-primary/70">Emits
|
||||
primary-tinted light, not bordeaux</strong> — bordeaux at
|
||||
<code>oklch(25.8%)</code> is too dark to bloom against a near-black ground,
|
||||
so a bordeaux halo is invisible. Dim element, brighter glow, as CRT
|
||||
phosphor behaves.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="p-6 mb-3 flex items-center">
|
||||
<hr class="w-full border-0 border-t-2 border-bordeaux glow-bordeaux-line">
|
||||
</div>
|
||||
<p class="text-primary/40 text-xs leading-snug">
|
||||
<code>.glow-bordeaux-line</code> — a single wide shadow on a hairline has no
|
||||
box to hug and just fades out. This uses a tight core plus a wider spill so a
|
||||
2px rule reads as lit.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-10">
|
||||
|
||||
<!-- FONT -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-primary text-xs uppercase tracking-wider mb-1">> Font</h2>
|
||||
<p class="text-primary/50 text-xs mb-6">
|
||||
<code>.font-digital</code> — 7-Segment by
|
||||
<a href="http://torinak.com/7segment" class="underline hover:text-primary">Jan Bobrowski</a>,
|
||||
SIL OFL 1.1. <code>fonts/OFL.txt</code> must ship wherever the font does.
|
||||
</p>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux p-6 mb-4">
|
||||
<div class="font-digital text-primary text-6xl mb-4">0123456789</div>
|
||||
<div class="font-digital text-primary text-3xl mb-4">0123456789</div>
|
||||
<div class="font-digital text-primary text-lg">0123456789</div>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-destructive p-4">
|
||||
<p class="text-primary/60 text-xs leading-snug">
|
||||
<strong class="text-primary">Numerals only.</strong> Letters render badly —
|
||||
the face has no strokes for most of them:
|
||||
</p>
|
||||
<div class="font-digital text-primary/50 text-2xl mt-3">ABCDEFGHIJKLM</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-10">
|
||||
|
||||
<!-- USAGE -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-primary text-xs uppercase tracking-wider mb-6">> Primary or bordeaux?</h2>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-6 text-xs">
|
||||
<div class="border-2 border-primary glow-red p-5">
|
||||
<h3 class="text-primary font-bold uppercase tracking-wider mb-3">Primary</h3>
|
||||
<ul class="text-primary/60 space-y-2 leading-snug">
|
||||
<li>> All text</li>
|
||||
<li>> Focused input borders</li>
|
||||
<li>> Borders of clickable things</li>
|
||||
<li>> Filled button backgrounds on hover</li>
|
||||
<li>> The source colour of every glow</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="border-2 border-bordeaux glow-bordeaux p-5">
|
||||
<h3 class="text-primary font-bold uppercase tracking-wider mb-3">Bordeaux</h3>
|
||||
<ul class="text-primary/60 space-y-2 leading-snug">
|
||||
<li>> Dividers and rules</li>
|
||||
<li>> Resting input borders</li>
|
||||
<li>> Panel outlines</li>
|
||||
<li>> Row separators</li>
|
||||
<li>> Scrollbar thumbs</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-primary/40 text-xs mt-5 leading-relaxed">
|
||||
The contrast is full red against bordeaux — never two brightnesses of red. An
|
||||
element commonly moves from bordeaux to primary on focus, with its glow rising at
|
||||
the same time, so the state change is signalled twice.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-10">
|
||||
|
||||
<!-- WORKED EXAMPLE -->
|
||||
<section class="mb-16">
|
||||
<h2 class="text-primary text-xs uppercase tracking-wider mb-1">> Worked example</h2>
|
||||
<p class="text-primary/50 text-xs mb-6">
|
||||
The anagram-finder form and results panel — the whole system in one screen.
|
||||
</p>
|
||||
|
||||
<div class="border-2 border-bordeaux p-6">
|
||||
<label for="demo" class="block text-primary text-xs uppercase tracking-wider mb-2">> Letters</label>
|
||||
<input
|
||||
id="demo"
|
||||
type="text"
|
||||
value="eamstoxil"
|
||||
autocomplete="off"
|
||||
class="w-full bg-black border-bordeaux text-primary focus:border-primary text-3xl tracking-wider uppercase rounded-none border-2 focus:ring-0 focus:outline-none transition-all glow-bordeaux px-4 py-3 mb-4"
|
||||
>
|
||||
|
||||
<div class="flex gap-3 mb-8">
|
||||
<button class="w-2/3 bg-black hover:bg-primary text-primary hover:text-black text-sm font-bold border-primary rounded-none border-2 uppercase tracking-wider transition-all glow-bordeaux cursor-pointer px-4 py-2">
|
||||
[FIND WORDS]
|
||||
</button>
|
||||
<a href="#" class="w-1/3 inline-flex items-center justify-center bg-black hover:bg-bordeaux text-primary/60 hover:text-primary text-sm font-bold border-bordeaux hover:border-primary rounded-none border-2 glow-bordeaux uppercase tracking-wider transition-all px-4 py-2">
|
||||
[CLEAR]
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr class="border-0 border-t-2 border-bordeaux glow-bordeaux-line mb-8">
|
||||
|
||||
<section class="border-bordeaux rounded-none border-2 glow-bordeaux">
|
||||
<h3 class="text-primary text-xs uppercase tracking-wider border-bordeaux border-b-2 glow-bordeaux-line px-4 py-2">
|
||||
> 3 matches
|
||||
</h3>
|
||||
<ul class="divide-bordeaux divide-y text-[1.3125rem] max-h-48 overflow-y-auto scrollbar-red">
|
||||
<li class="flex items-baseline justify-between px-4 py-1.5 text-primary hover:bg-bordeaux">
|
||||
<span>steam</span><span class="font-digital text-primary text-2xl">5</span>
|
||||
</li>
|
||||
<li class="flex items-baseline justify-between px-4 py-1.5 text-primary hover:bg-bordeaux">
|
||||
<span>mates</span><span class="font-digital text-primary text-2xl">5</span>
|
||||
</li>
|
||||
<li class="flex items-baseline justify-between px-4 py-1.5 text-primary hover:bg-bordeaux">
|
||||
<span>exalt</span><span class="font-digital text-primary text-2xl">5</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="border-t border-bordeaux pt-4 flex flex-wrap items-center justify-between gap-2 text-xs uppercase tracking-wider text-primary/40">
|
||||
<span>
|
||||
@lvl0/ui 0.1.0
|
||||
<span class="text-bordeaux px-1">|</span>
|
||||
a <a href="https://lvl0.xyz" class="hover:text-primary transition-colors">lvl0</a> project
|
||||
</span>
|
||||
<a href="https://forge.lvl0.xyz/lvl0/ui" rel="license" class="hover:text-primary transition-colors">[SOURCE]</a>
|
||||
</footer>
|
||||
|
||||
</main>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.copy').forEach((b) => {
|
||||
b.addEventListener('click', async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(b.dataset.v);
|
||||
const original = b.textContent;
|
||||
b.textContent = 'copied';
|
||||
setTimeout(() => { b.textContent = original; }, 1000);
|
||||
} catch (e) {
|
||||
/* clipboard unavailable over plain http — leave the value visible */
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
4
docs/styles.css
Normal file
4
docs/styles.css
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
@import 'tailwindcss';
|
||||
@import '../src/index.css';
|
||||
|
||||
@source './index.html';
|
||||
13
docs/vite.config.js
Normal file
13
docs/vite.config.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
export default defineConfig({
|
||||
root: fileURLToPath(new URL('.', import.meta.url)),
|
||||
base: './',
|
||||
plugins: [tailwindcss()],
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
},
|
||||
});
|
||||
1449
package-lock.json
generated
Normal file
1449
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
|
@ -23,8 +23,22 @@
|
|||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"keywords": ["css", "tailwind", "design-tokens", "lvl0"],
|
||||
"keywords": [
|
||||
"css",
|
||||
"tailwind",
|
||||
"design-tokens",
|
||||
"lvl0"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"tailwindcss": "^4.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"docs:dev": "vite --config docs/vite.config.js",
|
||||
"docs:build": "vite build --config docs/vite.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"vite": "^8.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue