ソースを参照

Create baseline theme

Billy Barrow 2 年 前
コミット
66400e302a

+ 2 - 1
config.php

@@ -3,11 +3,12 @@
 define("SITE_URL", "http://localhost:8080");
 define("SITE_NAME", "Billy's Blog Site");
 define("SITE_TAGLINE", "A log of the web");
+define("SITE_BANNER", null);
 define("SITE_LANGUAGE", "en-nz");
 define("PUBLICATION_DIR", "ppubs");
 define("PUBLICATION_NAME", "Post");
 define("DATE_FORMAT", "l d F Y, H:i");
 define("USE_PPIX", false);
-define("THEME", "classic");
+define("THEME", "baseline");
 
 ?>

+ 3 - 0
ppix.php

@@ -51,6 +51,9 @@ class Ppix {
         $tags = array();
         for ($i=0; $i < $count; $i++) { 
             $tag_data = unpack("Cstrlen/Vcolid", fread($this->handle, 5));
+            if($tag_data["strlen"] == 0) {
+                continue;
+            }
             $tag = fread($this->handle, $tag_data["strlen"]);
             $tags[$tag] = $tag_data["colid"];
         }

+ 6 - 6
theme.php

@@ -75,12 +75,12 @@ function content_html($content) {
     return $fun($content);
 }
 
-function content_end($ppub, $path) {
+function content_end($ppub) {
     $fun = THEME . "_content_end";
     if(!function_exists($fun)) {
-        return base_content_end($ppub, $path);
+        return base_content_end($ppub);
     }
-    return $fun($ppub, $path);
+    return $fun($ppub);
 }
 
 function video_start($ppub, $path, $video) {
@@ -88,7 +88,7 @@ function video_start($ppub, $path, $video) {
     if(!function_exists($fun)) {
         return base_video_start($ppub, $path, $video);
     }
-    return $fun($ppub, $path);
+    return $fun($ppub, $path, $video);
 }
 
 function video_html($content) {
@@ -99,10 +99,10 @@ function video_html($content) {
     return $fun($content);
 }
 
-function video_end($ppub, $path) {
+function video_end($ppub) {
     $fun = THEME . "_video_end";
     if(!function_exists($fun)) {
-        return base_video_end($ppub, $path);
+        return base_video_end($ppub);
     }
     return $fun($ppub, $path);
 }

+ 340 - 0
themes/baseline/baseline.css

@@ -0,0 +1,340 @@
+/* Reset */
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+    margin: 0;
+    padding: 0;
+    border: 0;
+    font-size: 100%;
+    font: inherit;
+    vertical-align: baseline;
+}
+
+* {
+    box-sizing: border-box;
+}
+
+/* Variables */
+:root {
+    --desktop-font-size: 1.2rem/1.5;
+    --mobile-font-size: 1rem/1.4;
+    --text-color: #2d2d2d;
+    --muted-color: #858585;
+    --link-color: blue;
+    --link-color-alt: darkblue;
+
+    --primary-color: lightsteelblue;
+    --secondary-color: aliceblue;
+    --tertiary-color: whitesmoke;
+
+    --page-baground: #eeeeee;
+    --content-background: #ffffff;
+
+    --display-font: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto, Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji", "Segoe UI Symbol";
+    --primary-font: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto, Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji", "Segoe UI Symbol";
+    --secondary-font: "Georgia", serif;
+    --monospace-font: monospace;
+
+    --roundness: 0.5rem;
+}
+
+/* Typography */
+body {
+    color: var(--text-color);
+    margin: 0 auto;
+    max-width: 75ch;
+    padding: 0 0.5rem;
+    background-color: var(--page-baground);
+}
+body, input, button {
+    font: var(--desktop-font-size) var(--primary-font);
+}
+
+h1,h2,h3,h4,h5,h6,p,blockquote,dl,img,figure {
+    margin: 2rem 0;
+}
+
+h1,h2,h3,h4,h5,h6 { font-weight: bold; line-height: 1.2; font-family: var(--display-font); }
+h1 { font-size: 200%; }
+h2 { font-size: 150%; }
+h3 { font-size: 120%; }
+h4,h5,h6 { font-size: 100%; }
+h5, h6 { text-transform: uppercase; }
+
+header h1 { border-bottom: 1px solid;}
+
+p { margin: 2rem 0; }
+
+a,a:visited { color: var(--link-color); }
+a:hover,a:focus { color: var(--link-color-alt); }
+
+strong, time, b { font-weight: bold; }
+em, dfn, i { font-style: italic; }
+sub { font-size: 60%; vertical-align: bottom; }
+small { font-size: 80%; }
+
+blockquote, q {
+    background: var(--secondary-color);
+    border-left: 10px solid var(--primary-color);
+    display: block;
+    font-family: var(--secondary-font);
+    padding: 1rem;
+    border-radius: var(--roundness);
+}
+blockquote p:first-child { margin-top: 0; }
+blockquote p:last-child { margin-bottom: 0; }
+cite {
+    font-family: var(--secondary-font);
+    font-style: italic;
+    font-weight: bold;
+    margin-top: 1rem;
+}
+
+kbd,code,samp,pre,var { font-family: var(--monospace-font); }
+code, pre {
+    background: var(--tertiary-color);
+    overflow: auto;
+    padding: 0.5rem 1rem;
+}
+code pre , pre code { padding: 0; }
+
+h1+h2,
+h3+h4{
+    margin-top: -1.2em;
+    margin-bottom: 1.2em;
+    color: var(--muted-color)
+}
+
+/* Elements */
+hr {
+    background: var(--text-color);
+    border: 0;
+    height: 1px;
+    margin: 4rem 0;
+}
+
+img {
+    display: block;
+    height: auto; 
+    max-width: 100%; 
+}
+
+figure {
+    border: 1px solid var(--primary-color);
+    display: inline-block;
+    padding: 1rem;
+    width: 100%;
+}
+figure img { margin: 0 auto; }
+figure figcaption { font-size: 80%; margin-top: 0.5rem; text-align: center; }
+
+ul, ol { margin: 2rem 0; padding: 0 0 0 4rem; }
+
+dl dd { padding-left: 2rem; }
+
+table {
+    border: 1px solid var(--primary-color);
+    border-collapse: collapse;
+    table-layout: fixed;
+    text-align: left;
+    width: 100%;
+}
+table caption { margin: 2rem 0; }
+table tr { border-bottom: 1px solid var(--primary-color); }
+table tbody tr:nth-child(even) { background: var(--tertiary-color); }
+table th { background: var(--secondary-color); font-weight: bold; }
+table th, table td { padding: 1rem; }
+table th:not(last-of-type), table td:not(last-of-type) { border-right: 1px solid var(--primary-color); }
+
+input,
+button { 
+    appearance: none; 
+    border: 1px solid var(--muted-color);
+    display: block;
+    margin: 0.5rem 0;
+    padding: 0.8rem; 
+    border-radius: var(--roundness);
+    background-color: var(--page-background);
+    color: var(--text-color);
+}
+input:focus,
+input:active {
+     background-color: var(--secondary-color); border-color: var(--primary-color);
+}
+
+input[type=button],
+input[type=submit],
+input[type=reset],
+button {
+    padding: 0.2rem 0.8rem; 
+    background-color: var(--tertiary-color);
+    display: inline-block;
+}
+
+input[type=button]:hover,
+input[type=submit]:hover,
+input[type=reset]:hover,
+button:hover {
+    background-color: var(--secondary-color);
+}
+
+input[type=button]:active,
+input[type=submit]:active,
+input[type=reset]:active,
+button:active {
+    background-color: var(--secondary-color);
+    border-color: var(--primary-color);
+    color: var(--muted-color);
+}
+input[type=button]:focus,
+input[type=submit]:focus,
+input[type=reset]:focus,
+button:focus {
+     border-color: var(--primary-color);
+}
+
+header[role=banner] {
+    background: var(--content-background);
+    background-position: center;
+    background-size: cover;
+
+    margin-top: -32px;
+    padding-top: 32px;
+    padding-bottom: 32px;
+    margin-bottom: 32px;
+
+    width: 100vw;
+    margin-left: calc(-50vw + min(75ch, 100vw)/2 - 0.5rem);
+    padding-left: calc(50vw - min(75ch, 100vw)/2 + 1.5rem);
+    padding-right: calc(50vw - min(75ch, 100vw)/2 + 1.5rem);
+
+    box-shadow: 0px 0px 10px rgba(75, 75, 75, 0.6);
+}
+
+article,
+section {
+    background-color: var(--content-background);
+    border-radius: var(--roundness);
+    
+    margin: 0 0 1em;
+    width: 100%;
+    
+    page-break-inside: avoid;
+    break-inside: avoid-column; 
+
+    box-sizing: border-box;
+    padding: 8px 18px 18px 18px;
+    border: 1px solid var(--tertiary-color);
+    overflow: hidden;
+
+}
+section > img:first-child {
+    margin: -8px -18px 8px -18px;
+    max-width: calc(100% + 36px);
+}
+
+/* Classes */
+.muted {
+    color: var(--muted-color);
+}
+
+.border-primary {
+    border-color: var(--primary-color);
+}
+.border-secondary {
+    border-color: var(--secondary-color);
+}
+.border-tertiary {
+    border-color: var(--tertiary-color);
+}
+
+.background-primary {
+    background-color: var(--primary-color);
+}
+.background-secondary {
+    background-color: var(--secondary-color);
+}
+.background-tertiary {
+    background-color: var(--tertiary-color);
+}
+
+section ul.compressed {
+    margin-top: auto;
+}
+ul.compressed {
+    list-style: none;
+    padding-left: 0px;
+    margin: 0px;
+}
+ul.compressed li {
+    display: inline-block;
+    margin-right: 18px;
+    margin-bottom: 8px;
+}
+
+.larger {
+    width: 130%;
+    margin-left: -15%;
+}
+
+section.subtle {
+    background-color: transparent;
+    border-color: transparent;
+}
+
+.tight {
+    margin-bottom: 0px;
+    margin-top: 0px;
+}
+
+span.icon {
+    text-decoration: none !important;
+    display: inline-block;
+    margin-right: 1ch;
+}
+
+
+/* Mobile Styling */
+@media screen and (max-width: 75ch) {
+    body, input {
+        font: var(--mobile-font-size) var(--primary-font);
+    }
+    table { table-layout: auto; }
+}
+
+@media screen and (max-width: 130ch) {
+    .larger {
+        margin-left: 0px;
+        width: auto;
+    }
+}
+
+/* Dark mode support */
+@media (prefers-color-scheme: dark) {
+    :root {
+        --text-color: #fff;
+        --muted-color: #c5c5c5;
+        --link-color: orange;
+        --link-color-alt: yellow;
+        --primary-color: orange;
+        --secondary-color: black;
+        --tertiary-color: #2d2d2d;
+
+        --page-baground: #2b2b2b;
+        --content-background: #191919;
+    }
+
+    header[role=banner] {
+        box-shadow: inset 0px -3px 5px rgba(75, 75, 75, 1);
+    }
+}

+ 87 - 0
themes/baseline/content_template.php

@@ -0,0 +1,87 @@
+<?php
+
+function baseline_content_start($ppub, $path) {
+    $metadata = $ppub->metadata;
+    ?>
+
+<!DOCTYPE html>
+<html lang="<?php echo($metadata["language"] ?? SITE_LANGUAGE);?>">
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
+        <title><?php echo(htmlentities($metadata["title"]));?> - <?php echo(SITE_NAME);?></title>
+        <meta name="description" content="<?php echo(htmlentities($metadata["description"]));?>">
+        <meta name="author" content="<?php echo(htmlentities($metadata["author"]));?>">
+        <link rel="stylesheet" href="<?php echo(SITE_URL);?>/themes/baseline/baseline.css">
+        <link rel="alternate" type="application/x-ppub" title="<?php echo(htmlentities($metadata["title"]));?> (as PPUB)" href="?download=true" />
+        <style type="text/css">
+            <?php baseline_banner_css() ?>
+        </style>
+    </head>
+    <body>
+    <header role="banner">
+        <h1>
+            <a style="color: var(--text-color); text-decoration: none; display: inline-block;" href="<?php echo(SITE_URL);?>"><?php echo(SITE_NAME);?></a>
+        </h1>
+
+        <?php baseline_navigation(); ?>
+    </header>
+    <?php
+}
+
+function baseline_content_html($content) {
+    echo "<section>";
+    echo $content;
+    echo "</section>";
+}
+
+function baseline_content_end($ppub) {
+    ?>
+    <footer>
+        <section>
+        <p><strong><?php echo(htmlentities($ppub->metadata["title"]));?></strong>
+        <?php if($ppub->metadata["author"] != null) {
+            preg_match("/^([^<]*(?= *<|$))<*([^>]*)>*/", $ppub->metadata["author"], $author);
+         ?>
+        <br/><?php echo(PUBLICATION_NAME);?> authored by <?php
+            if(isset($author[2]) && $author[2] != '') {
+                echo("<a href=\"mailto:".$author[2]."\">");
+                echo(htmlentities(trim($author[1])));
+                echo("</a>");
+            } else {
+                echo(htmlentities($ppub->metadata["author"]));
+            }
+        ?>.
+        <?php } if ($ppub->metadata["tags"] != null and USE_PPIX) { ?>
+        <br/>Tagged with: 
+        <?php
+            foreach(explode(" ", $ppub->metadata["tags"]) as $tag) {
+                ?>
+                <a href="<?php echo(SITE_URL);?>/?tag=<?php echo(urlencode($tag));?>"><?php echo(htmlentities($tag));?></a>
+                <?php
+            }
+        ?>
+        <?php } if ($ppub->metadata["date"] != null) { ?>
+        <br/>Last updated on <?php echo(htmlentities((new DateTime($ppub->metadata["date"]))->format(DATE_FORMAT)));?>.
+        <br/><?php } if ($ppub->metadata["copyright"] != null) { ?>
+        <?php echo($ppub->metadata["copyright"]);?>
+        <?php } if ($ppub->metadata["licence"] != null) { ?>
+        <a href="<?php echo($ppub->metadata["licence"]);?>">See Licence</a>
+        <?php } ?>
+        <ul class="compressed">
+            <li><a href="<?php echo(SITE_URL);?>/">Return to <?php echo(PUBLICATION_NAME);?> Index</a></li>
+            <li><a href="<?php echo(SITE_URL);?>/feed.rss">Subscribe to <?php echo(SITE_NAME);?> RSS</a></li>
+            <li><a href="?download=true">Download <?php echo(PUBLICATION_NAME);?> PPUB</a></li>
+        </ul>
+        </section>
+        <section class="subtle">
+        <p class="tight"><strong><?php echo($_SERVER['SERVER_NAME'])?></strong>
+        <br/><small>Site powered by <a href="https://git.sr.ht/~tilo15/php-ppub/" target="_blank">php-ppub</a> and <a href="https://parsedown.org" target="_blank">Parsedown</a>.</p>
+        </section>
+    </footer>
+    </body>
+</html>
+    <?php
+}
+
+?>

+ 133 - 0
themes/baseline/index_template.php

@@ -0,0 +1,133 @@
+<?php
+
+function baseline_index_start($index_type, $arg) {
+
+    ?>
+
+<!DOCTYPE html>
+<html lang="<?php echo(SITE_LANGUAGE);?>">
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
+        <title><?php echo(PUBLICATION_NAME)?> Index - <?php echo(SITE_NAME);?></title>
+        <link rel="stylesheet" href="<?php echo(SITE_URL);?>/themes/baseline/baseline.css">
+        <link rel="alternate" type="application/rss+xml" title="<?php echo(SITE_NAME);?> RSS Feed" href="<?php echo(SITE_URL);?>/feed.rss" />
+        <style type="text/css">
+                section img {
+                    filter: saturate(0.4);
+                    transition: filter 0.2s;
+                }
+                section:hover img {
+                    filter: saturate(1);
+                }
+                section a img {
+                    margin: -8px -18px 8px -18px;
+                    max-width: calc(100% + 36px);
+                }
+                <?php baseline_banner_css() ?>
+        </style>
+    </head>
+    <body>
+    <header role="banner">
+        <h1><a style="color: var(--text-color); text-decoration: none;" href="<?php echo(SITE_URL);?>"><?php echo(SITE_NAME);?></a></h1>
+        <?php baseline_navigation(); ?>
+    </header>
+
+        
+    <?php if(USE_PPIX) { ?>
+    <section class="border-primary" style="padding: 2rem;">
+        <?php
+        if($index_type == INDEX_TYPE_MAIN) {
+            ?>
+            <form action="./" >
+                <label for="q"><span class="icon">🔎</span>Search this site:</label><br>
+                <input style="width: 100%;" type="text" id="q" name="q" placeholder="Search...">
+            </form> 
+            <?php
+            if(count($arg) > 0) { ?>
+            <details>
+                <summary>Browse by tags</summary>
+                <ul class="compressed" style="margin-top: 5px;">
+                <?php
+                foreach ($arg as $tag) {
+                    ?>
+                    <li><a href="?tag=<?php echo(urlencode($tag));?>"><?php echo(htmlentities($tag));?></a></li>
+                    <?php
+                }
+                ?>
+                </ul>
+            </details>
+            <?php }
+        }
+
+        if($index_type == INDEX_TYPE_TAG) {
+            ?>
+            <label><span class="icon">🏷️</span>Tagged with <em><?php echo(htmlentities($arg));?></em></label>
+        <?php
+        }
+
+        if($index_type == INDEX_TYPE_SEARCH) {
+            ?>
+            <form action="./">
+                <label for="q"><span class="icon">🔎</span>Search query:</label><br>
+                <input style="width: 100%;" type="text" id="q" name="q" value="<?php echo(htmlentities($arg));?>">
+            </form> 
+        <?php
+        }
+
+        ?>
+    </section>
+    <?php
+    }
+}
+
+function baseline_index_no_content($index_type, $arg) {
+    if($index_type == INDEX_TYPE_SEARCH) {
+        echo('<section class="border-primary background-secondary" style="padding: 2rem;"><label><span class="icon">ℹ️</span>Nothing found for search query &quot;' . htmlentities($arg) . "&quot.</label></section>");
+    }
+    if($index_type == INDEX_TYPE_MAIN) {
+        echo('<section class="border-primary background-secondary" style="padding: 2rem;"><label><span class="icon">ℹ️</span>There doesn\'t seem to be anything here yet. Be sure to check back soon!</label></section>');
+    }
+}
+
+function baseline_index_listing($ppub, $url) {
+    ?>
+
+<section>
+    <a href="<?php echo($url);?>">
+    <?php 
+        if($ppub->metadata["poster"] != null) {
+            echo("<img src=\"" . $url . "/" . $ppub->metadata["poster"] . "\" alt='' />");
+        }
+    ?>
+    <h3><?php echo(htmlentities($ppub->metadata["title"]));?></h3></a>
+    <p><?php echo(htmlentities($ppub->metadata["description"]));?></p>
+    <ul class="compressed">
+        <?php
+            if(USE_PPIX) {
+                foreach(explode(" ", $ppub->metadata["tags"]) as $tag) {
+                    ?>
+                    <li><a href="<?php echo(SITE_URL);?>/?tag=<?php echo(urlencode($tag));?>"><?php echo(htmlentities($tag));?></a></li>
+                    <?php
+                }
+            }
+        ?>
+    </ul>
+</section>
+    <?php
+}
+
+function baseline_index_end() {
+    ?>
+    <footer>
+        <section class="subtle">
+        <p class="tight"><strong><?php echo($_SERVER['SERVER_NAME'])?></strong>
+        <br/><small>Site powered by <a href="https://git.sr.ht/~tilo15/php-ppub/" target="_blank">php-ppub</a> and <a href="https://parsedown.org" target="_blank">Parsedown</a>.</p>
+        </section>
+    </footer>
+    </body>
+</html>
+    <?php
+}
+
+?>

+ 30 - 0
themes/baseline/navigation.php

@@ -0,0 +1,30 @@
+<?php
+
+function baseline_navigation() {
+    ?>
+    <ul class="compressed">
+        <li><a href="<?php echo(SITE_URL);?>/"><span class="icon">📰</span>Latest</a></li>
+        <li><a href="<?php echo(SITE_URL);?>/feed.rss"><span class="icon">🛜</span>RSS Feed</a></li>
+    </ul>
+    <?php
+}
+
+function baseline_banner_css() {
+    if(SITE_BANNER != null) { ?>
+        header[role="banner"] {
+            background:
+                url("<?php echo(SITE_BANNER); ?>");
+        }
+        @media (prefers-color-scheme: dark) {
+            header[role="banner"] {
+                background:
+                    linear-gradient(
+                        rgba(43, 54, 65, 0.6),
+                        rgba(43, 54, 65, 0.6)
+                    ),
+                    url("<?php echo(SITE_BANNER); ?>");
+            }
+        }
+        <?php 
+    }
+}

+ 7 - 0
themes/baseline/theme.php

@@ -0,0 +1,7 @@
+<?php
+include("navigation.php");
+
+include("index_template.php");
+include("content_template.php");
+include("video_template.php");
+?>

+ 17 - 0
themes/baseline/video_template.php

@@ -0,0 +1,17 @@
+<?php
+
+function baseline_video_start($ppub, $path, $video) {
+    baseline_content_start($ppub, $path);
+
+    echo("<section style='padding: 0; margin-bottom: 3rem;' class='larger'>");
+    generate_embed($path, $video);
+    echo("</section>");
+}
+
+function baseline_video_html($content) {
+    baseline_content_html($content);
+}
+
+function baseline_video_end($ppub) {
+    baseline_content_end($ppub);
+}