Update default styles and templates

Remove hero section styles
Add CSS reset and variables
Improve typography and layout
Update base template with CSS versioning
Restructure list templates with semantic HTML
Add proper container classes
Improve code organization and readability
This commit is contained in:
Ruben 2026-02-10 22:25:44 +01:00
parent ca6d87b885
commit fde5cc4d0e
7 changed files with 171 additions and 345 deletions

View file

@ -4,7 +4,7 @@ Drop markdown, HTML and PHP files in directories to instantly publish online. A
## How it works ## How it works
Your file system is your site structure. Create folders, drop in content files, and they're live. Create `content/about/intro.md` and it turns into `yoursite.com/about/`. Need more presentational controll then what Markdown offers? Drop in an HTML file. Dynamic content? Add a PHP script. No routing configuration, no build step, just save a file, refresh the browser. Your file system is your site structure. Create folders, drop in content files and they're live. Create `content/about/intro.md` and it turns into `yoursite.com/about/`. Need more presentational control then what Markdown offers? Drop in an HTML file. Dynamic content? Add a PHP script. No routing configuration, no build step, just save a file, refresh the browser.
Since everything is just files and folders, you can mount your site via SFTP or WebDAV and edit content directly from your local machine — save a file, and the change is live. Create websites like it's 1996! Since everything is just files and folders, you can mount your site via SFTP or WebDAV and edit content directly from your local machine — save a file, and the change is live. Create websites like it's 1996!

View file

@ -1,112 +0,0 @@
/* Hero section for frontpage */
.hero {
background: linear-gradient(135deg, oklch(95% 0.05 250) 0%, oklch(98% 0.02 250) 100%);
border-radius: 0.75rem;
padding: var(--space-m);
margin-block: var(--space-s);
text-align: center;
& .hero-title {
font-size: clamp(2rem, 5vw, 2.5rem);
margin-block: 0 var(--space-xs);
background: linear-gradient(135deg, oklch(40% 0.15 250), oklch(30% 0.2 280));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: 900;
}
& .hero-subtitle {
font-size: clamp(1rem, 2vw, 1.125rem);
color: var(--color-muted);
margin-block-end: var(--space-m);
max-width: 32rem;
margin-inline: auto;
}
& .cta-button {
display: inline-block;
background: var(--color-accent);
color: white;
padding: var(--space-xs) var(--space-m);
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
margin-block-start: var(--space-xs);
&:hover {
background: oklch(45% 0.15 250);
color: white;
}
}
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
gap: var(--space-s);
margin-block: var(--space-m);
& .feature-card {
background: var(--color-background);
padding: var(--space-s);
border-radius: 0.5rem;
border: 1px solid var(--color-border);
text-align: center;
transition: transform 0.2s, box-shadow 0.2s;
text-decoration: none;
color: inherit;
display: block;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px oklch(0% 0 0 / 0.1);
border-color: var(--color-accent);
}
& .feature-icon {
font-size: 2rem;
display: block;
margin-block-end: var(--space-xs);
}
& .feature-title {
font-weight: bold;
margin-block: var(--space-xs);
color: var(--color-text);
font-size: 0.9rem;
}
& .feature-description {
font-size: 0.85rem;
color: var(--color-muted);
margin: 0;
}
}
}
.stats {
display: flex;
justify-content: center;
gap: var(--space-m);
flex-wrap: wrap;
margin-block-start: var(--space-m);
padding-block-start: var(--space-s);
border-block-start: 1px solid var(--color-border);
& .stat {
text-align: center;
& .stat-value {
display: block;
font-size: 1.25rem;
font-weight: bold;
color: var(--color-accent);
}
& .stat-label {
font-size: 0.8rem;
color: var(--color-muted);
}
}
}

View file

@ -1,8 +1,11 @@
/* RESET */
* { box-sizing: border-box; margin-bottom: 0 }
/* VARIABLES */
:root { :root {
--color-text: oklch(20% 0 0); --color-text: oklch(20% 0 0);
--color-background: oklch(98% 0 0); --color-background: oklch(98% 0 0);
--color-accent: oklch(50% 0.15 250); --color-accent: oklch(50% 0.15 250);
--color-accent-light: oklch(95% 0.05 250);
--color-border: oklch(85% 0 0); --color-border: oklch(85% 0 0);
--color-muted: oklch(50% 0 0); --color-muted: oklch(50% 0 0);
@ -11,17 +14,13 @@
--space-m: 2rem; --space-m: 2rem;
--space-l: 4rem; --space-l: 4rem;
--size-content: 65ch; --size-content: 42rem;
--size-constrained: 42rem;
--size-wide: 90rem;
}
* {
box-sizing: border-box;
} }
/* GLOBAL */
html { html {
font-family: system-ui, sans-serif; font-family: system-ui, sans-serif;
font-size: clamp(16px, 2.3vw, 20px);
line-height: 1.6; line-height: 1.6;
color: var(--color-text); color: var(--color-text);
background: var(--color-background); background: var(--color-background);
@ -30,139 +29,99 @@ html {
body { body {
margin: 0; margin: 0;
display: grid; display: grid;
grid-template-columns:
[full-start] minmax(var(--space-s), 1fr)
[content-start] minmax(0, var(--size-constrained))
[content-end] minmax(var(--space-s), 1fr)
[full-end];
grid-template-rows: auto 1fr auto; grid-template-rows: auto 1fr auto;
min-height: 100vh; min-height: 100vh;
} }
/* CONTENT CENTERING */
.contain, :where(main > article, main > section, main > div) {
display: grid;
grid-template-columns: minmax(var(--space-s), 1fr) minmax(0, var(--size-content)) minmax(var(--space-s), 1fr);
& > * { grid-column: 2 }
}
/* TYPOGRAPHY */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
line-height: 1.2; font-weight: 400;
margin-block: 1.5em 0.5em; line-height: 1.3;
margin-top: 1.3em;
text-wrap: pretty;
} }
h1 { font-size: 2.3rem }
h4 { font-weight: 700 }
h1 { font-size: clamp(2rem, 5vw, 3rem); } p, ul, ol, dl { margin-block: 1em }
h2 { font-size: clamp(1.5rem, 4vw, 2rem); }
h3 { font-size: clamp(1.25rem, 3vw, 1.5rem); }
p, ul, ol, dl {
max-width: var(--size-content);
margin-block: 1em;
}
a { a {
color: var(--color-accent); color: var(--color-accent);
text-underline-offset: 0.2em;
&:hover {
text-decoration: none; text-decoration: none;
} &:hover { text-decoration: underline }
} }
header, main, footer { img { max-width: 100%; height: auto; display: block }
grid-column: content;
}
/* HEADER */
header { header {
border-block-end: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
padding-block: var(--space-s);
& > div {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: var(--space-s); gap: var(--space-s);
align-items: center; align-items: center;
padding-block: var(--space-s);
}
& nav { & nav {
display: flex; display: flex;
gap: var(--space-s); gap: var(--space-s);
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
&:first-child { &:first-child { flex: 1 }
flex: 1;
}
& a { & a {
text-decoration: none; text-decoration: none;
&:hover { text-decoration: underline }
&:hover { &[aria-current] { font-weight: bold }
text-decoration: underline;
}
&[aria-current] {
font-weight: bold;
} }
} }
} }
& .language-switcher { /* MAIN */
margin-inline-start: auto; main { padding-block: var(--space-m) }
}
}
main {
padding-block: var(--space-m);
}
/* FOOTER */
footer { footer {
border-block-start: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
padding-block: var(--space-s); padding-block: var(--space-s);
font-size: 0.875rem; font-size: 0.875rem;
color: var(--color-muted); color: var(--color-muted);
& p { margin: 0 }
& nav {
display: flex;
gap: var(--space-s);
margin-block-end: var(--space-xs);
}
& p {
margin: 0;
}
}
img {
max-width: 100%;
height: auto;
display: block;
} }
/* CODE */
code { code {
background: var(--color-accent-light); background: oklch(95% 0.02 250);
padding: 0.125em 0.25em; padding: 0.125em 0.25em;
border-radius: 0.25em; border-radius: 0.25em;
font-size: 0.9em; font-size: 0.9em;
} }
pre { pre {
background: var(--color-accent-light); background: oklch(95% 0.02 250);
padding: var(--space-s); padding: var(--space-s);
border-radius: 0.5em; border-radius: 0.5em;
overflow-x: auto; overflow-x: auto;
& code { background: none; padding: 0 }
& code {
background: none;
padding: 0;
}
} }
table { /* TABLES */
border-collapse: collapse; table { border-collapse: collapse; width: 100%; margin-block: var(--space-s) }
width: 100%; th, td { padding: var(--space-xs); text-align: start; border-bottom: 1px solid var(--color-border) }
margin-block: var(--space-s); th { font-weight: bold }
}
th, td {
padding: var(--space-xs);
text-align: start;
border-block-end: 1px solid var(--color-border);
}
th {
font-weight: bold;
}
/* BLOCKQUOTES */
blockquote { blockquote {
margin-inline: 0; margin-inline: 0;
padding-inline-start: var(--space-s); padding-inline-start: var(--space-s);
@ -170,9 +129,41 @@ blockquote {
color: var(--color-muted); color: var(--color-muted);
} }
article { /* ARTICLE */
& time { article time { color: var(--color-muted); font-size: 0.875rem }
color: var(--color-muted);
font-size: 0.875rem; /* LIST VIEWS */
.list-item {
margin-bottom: var(--space-m);
& img { margin-bottom: var(--space-xs) }
& h2 { margin-top: 0 }
} }
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
gap: var(--space-m);
}
.card {
border: 1px solid var(--color-border);
border-radius: 0.5rem;
padding: var(--space-s);
& img { margin-bottom: var(--space-xs); border-radius: 0.25rem }
& h3 { margin-top: 0 }
}
.compact-list {
list-style: none;
padding: 0;
& li { border-bottom: 1px solid var(--color-border); padding-block: var(--space-xs) }
& a {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: var(--space-s);
&:hover strong { text-decoration: underline }
}
& time { white-space: nowrap; font-size: 0.875rem }
& p { margin-top: var(--space-xs); color: var(--color-muted); font-size: 0.9rem }
} }

View file

@ -1,3 +1,14 @@
<?php
$customCssPath = dirname(__DIR__, 2) . '/custom/styles/base.css';
$defaultCssPath = __DIR__ . '/../styles/styles.css';
if (file_exists($customCssPath)) {
$cssUrl = '/app/styles/base.css';
$cssHash = hash_file('md5', $customCssPath);
} else {
$cssUrl = '/app/default-styles/styles.css';
$cssHash = hash_file('md5', $defaultCssPath);
}
?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="<?= htmlspecialchars($currentLang ?? 'en') ?>"> <html lang="<?= htmlspecialchars($currentLang ?? 'en') ?>">
<head> <head>
@ -10,7 +21,7 @@
<?php if (!empty($socialImageUrl)): ?> <?php if (!empty($socialImageUrl)): ?>
<meta property="og:image" content="<?= htmlspecialchars($socialImageUrl) ?>"> <meta property="og:image" content="<?= htmlspecialchars($socialImageUrl) ?>">
<?php endif; ?> <?php endif; ?>
<link rel="stylesheet" href="/app/default/styles/styles.css"> <link rel="stylesheet" href="<?= $cssUrl ?>?v=<?= $cssHash ?>">
<?php if (!empty($pageCssUrl)): ?> <?php if (!empty($pageCssUrl)): ?>
<link rel="stylesheet" href="<?= htmlspecialchars($pageCssUrl) ?>?v=<?= htmlspecialchars($pageCssHash ?? '') ?>"> <link rel="stylesheet" href="<?= htmlspecialchars($pageCssUrl) ?>?v=<?= htmlspecialchars($pageCssHash ?? '') ?>">
<?php endif; ?> <?php endif; ?>
@ -19,9 +30,10 @@
<?php endif; ?> <?php endif; ?>
</head> </head>
<body> <body>
<header> <header class="contain">
<div>
<nav> <nav>
<a href="<?= htmlspecialchars($langPrefix ?? '') ?>/"><?= htmlspecialchars($homeLabel ?? ($translations['home'] ?? 'Home')) ?></a> <a href="<?= htmlspecialchars($langPrefix ?? '') ?>/"><?= htmlspecialchars($translations['home'] ?? $homeLabel ?? 'Home') ?></a>
<?php if (!empty($navigation)): ?> <?php if (!empty($navigation)): ?>
<?php foreach ($navigation as $item): ?> <?php foreach ($navigation as $item): ?>
<a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a> <a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a>
@ -35,25 +47,17 @@
<?php endforeach; ?> <?php endforeach; ?>
</nav> </nav>
<?php endif; ?> <?php endif; ?>
</div>
</header> </header>
<main> <main>
<?= $content ?> <?= $wrappedContent ?? $content ?>
</main> </main>
<footer> <footer class="contain">
<nav> <p>Generated in <?= number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2) ?>ms</p>
<a href="https://mastodon.social/@example" rel="me">Mastodon</a>
<a href="https://bsky.app/profile/example.bsky.social">Bluesky</a>
</nav>
<p>
<?php if (!empty($translations['footer_handcoded'])): ?>
<?= htmlspecialchars($translations['footer_handcoded']) ?> <?= number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2) ?><?= htmlspecialchars($translations['footer_page_time'] ?? 'ms') ?>
<?php else: ?>
Generated in <?= number_format((microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2) ?>ms
<?php endif; ?>
</p>
</footer> </footer>
<?php if (!empty($pageJsUrl)): ?> <?php if (!empty($pageJsUrl)): ?>
<script defer src="<?= htmlspecialchars($pageJsUrl) ?>?v=<?= htmlspecialchars($pageJsHash ?? '') ?>"></script> <script defer src="<?= htmlspecialchars($pageJsUrl) ?>?v=<?= htmlspecialchars($pageJsHash ?? '') ?>"></script>
<?php endif; ?> <?php endif; ?>

View file

@ -1,9 +1,10 @@
<?php if (!empty($pageContent)): ?> <?php if (!empty($pageContent)): ?>
<div class="list-intro"> <article class="list-intro">
<?= $pageContent ?> <?= $pageContent ?>
</div> </article>
<?php endif; ?> <?php endif; ?>
<section>
<ul class="compact-list"> <ul class="compact-list">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<li> <li>
@ -19,43 +20,4 @@
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
</section>
<style>
.compact-list {
list-style: none;
padding: 0;
max-width: var(--size-content);
& li {
border-block-end: 1px solid var(--color-border);
padding-block: var(--space-s);
&:first-child {
padding-block-start: 0;
}
}
& a {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: var(--space-s);
text-decoration: none;
&:hover strong {
text-decoration: underline;
}
}
& time {
white-space: nowrap;
font-size: 0.875rem;
}
& p {
margin-block-start: var(--space-xs);
color: var(--color-muted);
font-size: 0.9rem;
}
}
</style>

View file

@ -1,9 +1,10 @@
<?php if (!empty($pageContent)): ?> <?php if (!empty($pageContent)): ?>
<div class="list-intro"> <article class="list-intro">
<?= $pageContent ?> <?= $pageContent ?>
</div> </article>
<?php endif; ?> <?php endif; ?>
<section>
<div class="grid"> <div class="grid">
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<article class="card"> <article class="card">
@ -23,26 +24,4 @@
</article> </article>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
</section>
<style>
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
gap: var(--space-m);
}
.card {
border: 1px solid var(--color-border);
border-radius: 0.5rem;
padding: var(--space-s);
& img {
margin-block-end: var(--space-s);
border-radius: 0.25rem;
}
& h3 {
margin-block-start: 0;
}
}
</style>

View file

@ -1,14 +1,16 @@
<?php if (!empty($pageContent)): ?> <?php if (!empty($pageContent)): ?>
<div class="list-intro"> <article class="list-intro">
<?= $pageContent ?> <?= $pageContent ?>
</div> </article>
<?php endif; ?> <?php endif; ?>
<div class="list"> <section>
<?php foreach ($items as $item): ?> <?php foreach ($items as $item): ?>
<article class="list-item"> <article class="list-item">
<?php if (!empty($item['cover'])): ?> <?php if (!empty($item['cover'])): ?>
<a href="<?= htmlspecialchars($item['url']) ?>">
<img src="<?= htmlspecialchars($item['cover']) ?>" alt=""> <img src="<?= htmlspecialchars($item['cover']) ?>" alt="">
</a>
<?php endif; ?> <?php endif; ?>
<h2><a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a></h2> <h2><a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a></h2>
@ -22,4 +24,4 @@
<?php endif; ?> <?php endif; ?>
</article> </article>
<?php endforeach; ?> <?php endforeach; ?>
</div> </section>