CSS grid layout for home including sicky footer

Adrian Simmons created

Signed-off-by: Adrian Simmons <adrian@perlucida.co.uk>

Change summary

ws/static/home.html           |  23 ++-
ws/static/login.html          |   2 
ws/static/new.html            |   2 
ws/static/select-release.html |   2 
ws/static/styles.css          | 211 ++++++++++++++++++++++--------------
5 files changed, 149 insertions(+), 91 deletions(-)

Detailed changes

ws/static/home.html 🔗

@@ -20,14 +20,18 @@
         <link rel="stylesheet" href="/static/styles.css" />
     </head>
     <body>
+        <div class="container">
         <header>
-            <h1>Willow</h1>
-            <nav>
-                <a href="/new">Track a new project</a>
-                <a href="/logout">Log out</a>
-            </nav>
+            <div class="wrapper">
+                <h1>Willow</h1>
+                <nav>
+                    <a href="/new">Track a new project</a>
+                    <a href="/logout">Log out</a>
+                </nav>
+            </div>
         </header>
-        <main class="two_column">
+        <main>
+            <div class="wrapper two_column">
             <div class="projects">
                 <!-- Range through projects that aren't yet up-to-date -->
                 {{- range . -}}
@@ -79,6 +83,13 @@
                 </div>
                 {{- end -}}
             </div>
+            </div>
         </main>
+        <footer>
+            <div class="wrapper">
+                <p>Willow &mdash; <a href="https://git.sr.ht/~amolith/willow">SourceHut</a> &mdash; <a href="https://todo.sr.ht/~amolith/willow">Issues</a></p>
+            </div>
+        </footer>
+        </div>
     </body>
 </html>

ws/static/login.html 🔗

@@ -19,7 +19,7 @@
         <link rel="preload" href="/static/styles.css" as="style" />
         <link rel="stylesheet" href="/static/styles.css" />
     </head>
-    <body class="wrapper">
+    <body class="old-wrapper">
         <h1>Willow</h1>
         <form method="post">
             <div class="input">

ws/static/new.html 🔗

@@ -19,7 +19,7 @@
         <link rel="preload" href="/static/styles.css" as="style" />
         <link rel="stylesheet" href="/static/styles.css" />
     </head>
-    <body class="wrapper">
+    <body class="old-wrapper">
         <h1>Willow</h1>
         <form method="post">
             <div class="input">

ws/static/select-release.html 🔗

@@ -19,7 +19,7 @@
         <link rel="preload" href="/static/styles.css" as="style" />
         <link rel="stylesheet" href="/static/styles.css" />
     </head>
-    <body class="wrapper">
+    <body class="old-wrapper">
         <h1>Willow</h1>
         <form method="post">
             <div class="input">

ws/static/styles.css 🔗

@@ -37,153 +37,200 @@
 }
 
 html {
-    margin: auto auto;
-    color: var(--text);
-    background: var(--page-background);
-    font-family: 'Atkinson Hyperlegible', sans-serif;
-    scroll-behavior: smooth;
+	margin: auto auto;
+	color: var(--text);
+	background: var(--page-background);
+	font-family: 'Atkinson Hyperlegible', sans-serif;
+	scroll-behavior: smooth;
 }
 
 a {
-    color: var(--link);
+	color: var(--link);
 }
 
 a:visited {
-    color: var(--link);
+	color: var(--link);
 }
 
+/* Grid layout */
+.container {
+	width: auto;
+	min-height: 100vh;
+}
+
+@supports (display: grid) {
+	.container {
+		display: grid;
+		grid-template-rows: [header] auto [main] 1fr [footer] auto;
+		}
+
+	.container > header,
+	.container > main,
+	.container > footer {
+		display: grid;
+		grid-template-columns:
+			[page-start] minmax(1em, 1fr) [content] minmax(240px, 92ch) [page-end] minmax(1em, 1fr);
+	}
+
+	.container > main {
+		grid-template-rows: [top-gutter] 1em [content] 1fr [bottom-gutter] 1em;
+	}
+
+	.container > footer {
+		grid-template-rows: [top-gutter] 2em [content] 1fr [bottom-gutter] 0.5em;
+	}
+
+	.container > header {
+		grid-template-rows: [top-gutter] 0.5em [content] 1fr [bottom-gutter] 0.5em;
+	}
+
+	header .wrapper,
+	main .wrapper,
+	footer .wrapper {
+		grid-row: content;
+		grid-column: content;
+	}
+}
+
+/* End grid layout */
+
 .two_column {
-    display: flex;
-/*    gap: 30px;*/
-    flex-direction: row;
-    margin: auto auto;
-    max-width: 1040px;
-    height: 92vh;
+	display: flex;
+	gap: 20px;
+	flex-direction: row;
 }
 
 .two_column > * > * {
-    margin: 20px;
+	margin: 20px 0;
 }
 
 .projects, .release_notes {
-    overflow: scroll;
-    flex: 0 0 540px;
+	flex: 1 1 50%;
 }
 
 .release_note.card:not(:target) { display: none;  }
 .release_note.card:target       { display: block; }
 
 .return_to_project {
-    display: none;
+	display: none;
 }
 
 .card {
-    border: 2px solid var(--card-border);
-    background: var(--card-background);
-    border-radius: 5px;
-    margin: 20px;
-    padding: 20px 20px 0 20px;
-    box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
+	border: 2px solid var(--card-border);
+	background: var(--card-background);
+	border-radius: 5px;
+	margin: 20px 0;
+	padding: 20px 20px 0 20px;
+	box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
 }
 
 .card > h3 {
-    margin-top: 0;
+	margin-top: 0;
 }
 
 .card > p:first-of-type {
-    margin-bottom: 16px;
+	margin-bottom: 16px;
 }
 
 .card > p:last-of-type {
-    margin-bottom: 16px;
+	margin-bottom: 16px;
 }
 
 .close, .delete { float: right; }
 .delete { font-size: 12px; }
 .close > a {
-    text-decoration: none;
-    color: var(--card-border);
+	text-decoration: none;
+	color: var(--card-border);
 }
 @media (prefers-color-scheme: dark) {
-    .close > a {
-        color: var(--text);
-    }
+	.close > a {
+		color: var(--text);
+	}
 }
 
 .card > pre, .card > div > pre { overflow: scroll; }
 
-.wrapper {
-    max-width: 500px;
-    margin: auto auto;
+.old-wrapper { /* used on non-home pages */
+	max-width: 500px;
+	margin: auto auto;
 }
 
-header {
-    width: 100%;
-    max-width: 1040px;
-    margin: 0 auto;
-    display: flex;
-    flex-wrap: wrap;
-    justify-content: space-between;
-    align-content: center;
+header .wrapper {
+	display: flex;
+	flex-wrap: wrap;
+	justify-content: space-between;
+	align-content: center;
 }
 
 header h1 {
-    margin-block: 1.2rem;
+	margin-block: 1.2rem;
 }
 
 header nav {
-    display: flex;
-    justify-content: flex-end;
-    align-content: baseline;
-    flex: 1 1 auto;
-    margin-block: 1.2rem;
+	display: flex;
+	justify-content: flex-end;
+	align-content: baseline;
+	flex: 1 1 auto;
+	margin-block: 1.2rem;
 }
 
 header nav a,
 header nav a:visited {
-    display: block;
-    text-decoration: underline;
-    color: var(--text);
-    font-size: 1.2rem;
-    font-weight: bold;
-    line-height: 1;
-    border-radius: 0.5rem;
-    padding: 0.6rem 0.5rem 0.4rem;
+	display: block;
+	text-decoration: underline;
+	color: var(--text);
+	font-size: 1.2rem;
+	font-weight: bold;
+	line-height: 1;
+	border-radius: 0.5rem;
+	padding: 0.6rem 0.5rem 0.4rem;
 }
 
 header nav a + a {
-    margin-inline-start: 1rem;
+	margin-inline-start: 1rem;
+}
+
+header nav a:last-of-type {
+	padding-inline-end: 0;
 }
 
 header nav a[href="/new"],
 header nav a[href="/new"]:visited {
-    text-decoration: none;
-    color: var(--action);
-    border-color: var(--action);
-    background-color: transparent;
-    border: 1px solid var(--action);
+	text-decoration: none;
+	color: var(--action);
+	border-color: var(--action);
+	background-color: transparent;
+	border: 1px solid var(--action);
+}
+
+
+footer .wrapper {
+	display: flex;
+	flex-wrap: wrap;
+	justify-content: space-between;
+	align-content: center;
 }
 
 @media only screen and (max-width: 1000px) {
-    div[id] {
-        display: block;
-    }
-
-    .two_column {
-        flex-direction: column;
-    }
-
-    .projects, .release_notes {
-        overflow: visible;
-        flex: 0 0 100%;
-    }
-
-    .return_to_project {
-        display: block;
-    }
-
-    .close {
-        display: none;
-    }
+	div[id] {
+		display: block;
+	}
+
+	.two_column {
+		flex-direction: column;
+	}
+
+	.projects, .release_notes {
+		overflow: visible;
+		flex: 1 1 100%;
+	}
+
+	.return_to_project {
+		display: block;
+	}
+
+	.close {
+		display: none;
+	}
 }