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 */
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
/* MINIMAL CSS RESET*/
|
||||
* { margin-bottom: 0; }
|
||||
|
||||
/* GLOBAL */
|
||||
body {
|
||||
font-family: system-ui, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
/* VARIABLES */
|
||||
:root {
|
||||
--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--font-heading: Georgia, "Times New Roman", serif;
|
||||
--color-primary: #4a90e2;
|
||||
--color-primary: oklch(0.65 0.15 250);
|
||||
--color-secondary: #2c5aa0;
|
||||
--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; }
|
||||
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; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.grid-container {
|
||||
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 {
|
||||
border-bottom: 2px solid #eee;
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
border-bottom: 3px #00000022 solid;
|
||||
grid-area: header;
|
||||
> 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 { margin-bottom: 2rem; }
|
||||
main {
|
||||
grid-area: main;
|
||||
background-color: var(--color-light);
|
||||
padding-bottom: 2rem;
|
||||
|
||||
article { margin-bottom: 2rem; }
|
||||
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 0.5rem;
|
||||
aside { margin-top: 1.3em }
|
||||
article {
|
||||
.intro {
|
||||
font-size: 1.2rem;
|
||||
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 {
|
||||
border-top: 2px solid #eee;
|
||||
padding-top: 1rem;
|
||||
color: var(--color-light);
|
||||
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;
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
.generated { font-size: .6rem }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
<html lang="<?= $currentLang ?? 'en' ?>">
|
||||
<html lang="<?= htmlspecialchars($currentLang ?? 'en') ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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' ?>">
|
||||
<title><?= htmlspecialchars($pageTitle ?? 'Site') ?></title>
|
||||
<link rel="stylesheet" href="<?= $cssUrl ?>?v=<?= $cssHash ?>">
|
||||
<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>
|
||||
<body>
|
||||
<header>
|
||||
<h1><a href="/">Webfolder demo</a></h1>
|
||||
<?php if (!empty($navigation)): ?>
|
||||
<nav>
|
||||
<ul>
|
||||
<?php foreach ($navigation as $item): ?>
|
||||
<li><a href="<?= htmlspecialchars($item['url']) ?>"><?= htmlspecialchars($item['title']) ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
<main>
|
||||
<?= $content ?>
|
||||
</main>
|
||||
<footer>
|
||||
<p>© <?= date('Y') ?> <?= htmlspecialchars($translations['footer_copyright'] ?? '') ?></p>
|
||||
</footer>
|
||||
|
||||
<body class="<?php if (isset($dirName)) echo 'section-' . $dirName . ' '; ?><?php if (isset($pageName)) echo 'page-' . $pageName; ?>">
|
||||
<div class="grid-container">
|
||||
<header class="contain">
|
||||
<div>
|
||||
<div class="logo">
|
||||
<a href="/">
|
||||
<svg width="200" height="60" viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
||||
<text x="10" y="40" font-family="Arial, sans-serif" font-size="32" font-weight="bold" fill="currentColor">LOGO</text>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<nav>
|
||||
<ul>
|
||||
<a href="/" class="button <?php echo getActiveClass('/'); ?>"><li><?= htmlspecialchars($translations['home'] ?? 'Home') ?></li></a>
|
||||
<?php if (!empty($navigation)): ?>
|
||||
<?php foreach ($navigation as $item): ?>
|
||||
<a href="<?= htmlspecialchars($item['url']) ?>" class="button <?php echo getActiveClass($item['url']); ?>"><li><?= htmlspecialchars($item['title']) ?></li></a>
|
||||
<?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>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,55 @@
|
|||
<?php if (!empty($pageContent)): ?>
|
||||
<article class="list-intro">
|
||||
<?= $pageContent ?>
|
||||
</article>
|
||||
<?php endif; ?>
|
||||
|
||||
<article>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<article>
|
||||
<?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; ?>
|
||||
<h1>
|
||||
<a href="<?= htmlspecialchars($item['url']) ?>">
|
||||
<?= htmlspecialchars($item['title']) ?>
|
||||
</a>
|
||||
</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']): ?>
|
||||
<p><?= htmlspecialchars($item['summary']) ?></p>
|
||||
<?php endif; ?>
|
||||
<a href="<?= htmlspecialchars($item['url']) ?>" class="button"><?= htmlspecialchars($translations['read_more'] ?? 'Read more') ?></a>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</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