Add modern CSS reset and styling system
Implement responsive grid layout Add CSS variables for consistent theming Create button component with states Improve header and footer structure Add page load time measurement Enhance list template with styling Update template structure with semantic HTML Implement dynamic CSS file loading Add favicon support Improve navigation with active state Add page and section class names to body Implement conditional date display in list items
This commit is contained in:
parent
fa416d68c5
commit
1aa4d6a83b
3 changed files with 268 additions and 53 deletions
|
|
@ -1,47 +1,191 @@
|
||||||
/* MINIMAL RESET */
|
/* MINIMAL CSS RESET*/
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin-bottom: 0; }
|
||||||
|
|
||||||
/* GLOBAL */
|
/* VARIABLES */
|
||||||
body {
|
:root {
|
||||||
font-family: system-ui, sans-serif;
|
--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
line-height: 1.6;
|
--font-heading: Georgia, "Times New Roman", serif;
|
||||||
color: #333;
|
--color-primary: #4a90e2;
|
||||||
max-width: 800px;
|
--color-primary: oklch(0.65 0.15 250);
|
||||||
margin: 0 auto;
|
--color-secondary: #2c5aa0;
|
||||||
padding: 1rem;
|
--color-secondary: oklch(0.50 0.12 250);
|
||||||
|
--color-light: #f0f4f8;
|
||||||
|
--color-light: oklch(0.97 0.01 250);
|
||||||
|
--color-grey: #404040;
|
||||||
|
--color-grey: oklch(0.37 0 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* GLOBAL */
|
||||||
|
html { font-family: var(--font-body); font-size: clamp(16px, 2.3vw, 20px); scroll-behavior: smooth; }
|
||||||
|
body { margin: 0; color: var(--color-grey) }
|
||||||
|
p, ul, ol, aside { line-height: 1.5em; hyphens: auto }
|
||||||
img { max-width: 100%; height: auto; }
|
img { max-width: 100%; height: auto; }
|
||||||
|
h1 { color: var(--color-primary); font-size: 2.3rem }
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.3em;
|
||||||
|
margin-top: 1.3em;
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover { color: var(--color-secondary) }
|
||||||
|
}
|
||||||
|
|
||||||
a { color: #0066cc; text-decoration: none; }
|
.grid-container {
|
||||||
a:hover { text-decoration: underline; }
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-areas: "header" "main" "footer";
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain, :where(main>article, main>aside, main>section) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(.4rem, 1fr) minmax(0, 42rem) minmax(.3rem, 1fr);
|
||||||
|
> * {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.escape {
|
||||||
|
grid-column: 1 / -1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* HEADER */
|
/* HEADER */
|
||||||
header {
|
header {
|
||||||
border-bottom: 2px solid #eee;
|
border-bottom: 3px #00000022 solid;
|
||||||
padding-bottom: 1rem;
|
grid-area: header;
|
||||||
margin-bottom: 2rem;
|
> div {
|
||||||
}
|
padding-bottom: .2rem;
|
||||||
|
display: flex;
|
||||||
|
.logo {
|
||||||
|
margin-right: .3rem;
|
||||||
|
svg {
|
||||||
|
width: 7rem;
|
||||||
|
height: 100%;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
header h1 { font-size: 1.5rem; }
|
nav {
|
||||||
|
display:flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content:flex-end;
|
||||||
|
flex: 1;
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: .4rem;
|
||||||
|
padding: 0;
|
||||||
|
justify-content: flex-end;
|
||||||
|
a {
|
||||||
|
margin-left:0.4rem;
|
||||||
|
margin-top:0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* MAIN */
|
/* MAIN */
|
||||||
main { margin-bottom: 2rem; }
|
main {
|
||||||
|
grid-area: main;
|
||||||
|
background-color: var(--color-light);
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
|
||||||
article { margin-bottom: 2rem; }
|
aside { margin-top: 1.3em }
|
||||||
|
article {
|
||||||
h1 {
|
.intro {
|
||||||
font-size: 1.8rem;
|
font-size: 1.2rem;
|
||||||
margin-bottom: 0.5rem;
|
line-height: 1.35em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
margin-top: 1.3rem;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p { margin-bottom: 1rem; }
|
/* BUTTONS */
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 2rem;
|
||||||
|
padding: 0.35rem 1rem;
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--color-grey);
|
||||||
|
outline: 0.08rem var(--color-grey) solid;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-grey);
|
||||||
|
color: white;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &.active {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inverted {
|
||||||
|
background-color: transparent;
|
||||||
|
color: white;
|
||||||
|
outline: 0.08rem white solid;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: white;
|
||||||
|
color: var(--color-primary);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active, &.active {
|
||||||
|
background-color: var(--color-light);
|
||||||
|
color: var(--color-primary);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
color: white;
|
||||||
|
background-color: var(--color-grey);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bigger {
|
||||||
|
font-size: 1.2em;
|
||||||
|
padding: calc(0.35rem * 1.2) calc(1rem * 1.2);
|
||||||
|
border-radius: calc(1rem * 1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FOOTER */
|
||||||
|
|
||||||
/* FOOTER */
|
|
||||||
footer {
|
footer {
|
||||||
border-top: 2px solid #eee;
|
color: var(--color-light);
|
||||||
padding-top: 1rem;
|
a {
|
||||||
|
color: var(--color-light);
|
||||||
|
&:hover { color: white; text-decoration: underline }
|
||||||
|
}
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
grid-area: footer;
|
||||||
|
> div {
|
||||||
|
margin: 1rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.9rem;
|
.generated { font-size: .6rem }
|
||||||
color: #666;
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,63 @@
|
||||||
|
<?php
|
||||||
|
$startTime = microtime(true);
|
||||||
|
$publicDir = realpath($_SERVER['DOCUMENT_ROOT']);
|
||||||
|
$customCssPath = __DIR__ . '/../../custom/styles/base.css';
|
||||||
|
$defaultCssPath = __DIR__ . '/../styles/base.css';
|
||||||
|
$cssPath = file_exists($customCssPath) ? $customCssPath : $defaultCssPath;
|
||||||
|
$cssUrl = file_exists($customCssPath) ? '/app/styles/base.css' : '/app/default-styles/base.css';
|
||||||
|
$cssHash = file_exists($cssPath) ? hash_file('md5', $cssPath) : 'file_not_found';
|
||||||
|
if (isset($GLOBALS['_SERVER']['SCRIPT_FILENAME'])) { $includingFile = $_SERVER['SCRIPT_FILENAME']; }
|
||||||
|
if (!empty($includingFile)) { $pageName = pathinfo($includingFile, PATHINFO_FILENAME); }
|
||||||
|
if (!in_array(basename(dirname($includingFile)), ['latest', 'live', 'frozen']) && basename(dirname($includingFile)) !== '') { $dirName = basename(dirname($includingFile)); }
|
||||||
|
function getActiveClass($href) { return rtrim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/') === rtrim($href, '/') ? 'active' : ''; }
|
||||||
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="<?= $currentLang ?? 'en' ?>">
|
<html lang="<?= htmlspecialchars($currentLang ?? 'en') ?>">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="<?= file_exists(dirname(dirname(__DIR__)) . '/custom/styles/base.css') ? '/app/styles/base.css' : '/app/default-styles/base.css' ?>">
|
<link rel="stylesheet" href="<?= $cssUrl ?>?v=<?= $cssHash ?>">
|
||||||
<title><?= htmlspecialchars($pageTitle ?? 'Site') ?></title>
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||||
|
<link rel="icon" href="/favicon.png" type="image/png">
|
||||||
|
<title><?= htmlspecialchars($pageTitle ?? 'Site Title') ?></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
<header>
|
<body class="<?php if (isset($dirName)) echo 'section-' . $dirName . ' '; ?><?php if (isset($pageName)) echo 'page-' . $pageName; ?>">
|
||||||
<h1><a href="/">Webfolder demo</a></h1>
|
<div class="grid-container">
|
||||||
<?php if (!empty($navigation)): ?>
|
<header class="contain">
|
||||||
<nav>
|
<div>
|
||||||
<ul>
|
<div class="logo">
|
||||||
<?php foreach ($navigation as $item): ?>
|
<a href="/">
|
||||||
<li><a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a></li>
|
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||||
<?php endforeach; ?>
|
<text x="10" y="40" font-family="Arial, sans-serif" font-size="32" font-weight="bold" fill="currentColor">LOGO</text>
|
||||||
</ul>
|
</svg>
|
||||||
</nav>
|
</a>
|
||||||
<?php endif; ?>
|
</div>
|
||||||
</header>
|
<nav>
|
||||||
<main>
|
<ul>
|
||||||
<?= $content ?>
|
<a href="/" class="button <?php echo getActiveClass('/'); ?>"><li><?= htmlspecialchars($translations['home'] ?? 'Home') ?></li></a>
|
||||||
</main>
|
<?php if (!empty($navigation)): ?>
|
||||||
<footer>
|
<?php foreach ($navigation as $item): ?>
|
||||||
<p>© <?= date('Y') ?> <?= htmlspecialchars($translations['footer_copyright'] ?? '') ?></p>
|
<a href="<?= htmlspecialchars($item['url']) ?>" class="button <?php echo getActiveClass($item['url']); ?>"><li><?= htmlspecialchars($item['title']) ?></li></a>
|
||||||
</footer>
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<?php echo $content ?? ''; ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div class="contain">
|
||||||
|
<p><?= htmlspecialchars($translations['footer_text'] ?? 'Footer content goes here') ?></p>
|
||||||
|
<?php $endTime = microtime(true); $pageLoadTime = round(($endTime - $startTime) * 1000, 2); ?>
|
||||||
|
<p class="generated"><?= htmlspecialchars($translations['footer_handcoded'] ?? 'This page was generated in') ?> <?php echo $pageLoadTime; ?><?= htmlspecialchars($translations['footer_page_time'] ?? 'ms') ?></p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,55 @@
|
||||||
|
<?php if (!empty($pageContent)): ?>
|
||||||
|
<article class="list-intro">
|
||||||
|
<?= $pageContent ?>
|
||||||
|
</article>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
<?php foreach ($items as $item): ?>
|
<?php foreach ($items as $item): ?>
|
||||||
<article>
|
<article>
|
||||||
<?php if ($item['cover']): ?>
|
<?php if ($item['cover']): ?>
|
||||||
<img src="<?= htmlspecialchars($item['cover']) ?>" alt="<?= htmlspecialchars($item['title']) ?>">
|
<a href="<?= htmlspecialchars($item['url']) ?>">
|
||||||
|
<img src="<?= htmlspecialchars($item['cover']) ?>" alt="<?= htmlspecialchars($item['title']) ?>">
|
||||||
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<h1>
|
<h1>
|
||||||
<a href="<?= htmlspecialchars($item['url']) ?>">
|
<a href="<?= htmlspecialchars($item['url']) ?>">
|
||||||
<?= htmlspecialchars($item['title']) ?>
|
<?= htmlspecialchars($item['title']) ?>
|
||||||
</a>
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
<p><?= htmlspecialchars($item['date']) ?></p>
|
<?php if (($metadata['show_date'] ?? true) && !empty($item['date'])): ?>
|
||||||
|
<p><?= htmlspecialchars($item['date']) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
<?php if ($item['summary']): ?>
|
<?php if ($item['summary']): ?>
|
||||||
<p><?= htmlspecialchars($item['summary']) ?></p>
|
<p><?= htmlspecialchars($item['summary']) ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<a href="<?= htmlspecialchars($item['url']) ?>" class="button"><?= htmlspecialchars($translations['read_more'] ?? 'Read more') ?></a>
|
||||||
</article>
|
</article>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
main > article {
|
||||||
|
> article {
|
||||||
|
background-color: white;
|
||||||
|
padding: 0;
|
||||||
|
padding-bottom: 1.3rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> :not(img, a) {
|
||||||
|
padding-left: 1rem;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue