feature: Set up basic layout and styles

This commit is contained in:
Keith Solomon
2025-05-24 12:22:24 -05:00
parent bd7e54d7c7
commit 89c725a282
7 changed files with 475 additions and 58 deletions

View File

@@ -3,22 +3,36 @@
@layer theme, base, components, utilities; @layer theme, base, components, utilities;
@layer theme { @layer theme {
:root, :host { :root, :host {
--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", --font-sans: "Raleway", sans-serif;
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace; "Courier New", monospace;
--color-blue-400: oklch(70.7% 0.165 254.624); --color-blue-400: oklch(70.7% 0.165 254.624);
--color-slate-900: oklch(20.8% 0.042 265.755); --color-slate-900: oklch(20.8% 0.042 265.755);
--color-gray-200: oklch(92.8% 0.006 264.531); --color-gray-200: oklch(92.8% 0.006 264.531);
--color-gray-400: oklch(70.7% 0.022 261.325);
--color-gray-800: oklch(27.8% 0.033 256.848); --color-gray-800: oklch(27.8% 0.033 256.848);
--color-white: #fff; --color-black: oklch(0% 0 0);
--color-white: oklch(100% 0 0);
--spacing: 0.25rem; --spacing: 0.25rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-base: 1rem; --text-base: 1rem;
--text-base--line-height: calc(1.5 / 1); --text-base--line-height: calc(1.5 / 1);
--text-4xl: 2.25rem; --radius-sm: 0.25rem;
--text-4xl--line-height: calc(2.5 / 2.25); --default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans); --default-font-family: var(--font-sans);
--default-mono-font-family: var(--font-mono); --default-mono-font-family: var(--font-mono);
--color-primary: oklch(0.57 0.203362 257.1706);
--color-secondary: oklch(0.56 0.0176 257.23);
--color-bodylinks: oklch(0.48 0.0789 211.58);
--color-warning: oklch(84.42% 0.1722 84.93);
--h1: calc(var(--text-base) * 2.25);
--h2: calc(var(--text-base) * 1.75);
--h3: calc(var(--text-base) * 1.5);
--h4: calc(var(--text-base) * 1.25);
--h5: calc(var(--text-base) * 1.125);
--h6: calc(var(--text-base) * 1.05);
} }
} }
@layer base { @layer base {
@@ -167,31 +181,109 @@
} }
} }
@layer utilities { @layer utilities {
.my-2 { .container {
margin-block: calc(var(--spacing) * 2); width: 100%;
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
} }
.my-4 { .mx-auto {
margin-block: calc(var(--spacing) * 4); margin-inline: auto;
} }
.mb-2 { .mt-8 {
margin-bottom: calc(var(--spacing) * 2); margin-top: calc(var(--spacing) * 8);
}
.mr-2 {
margin-right: calc(var(--spacing) * 2);
}
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
.flex {
display: flex;
} }
.table { .table {
display: table; display: table;
} }
.h-8 {
height: calc(var(--spacing) * 8);
}
.w-full {
width: 100%;
}
.border-collapse { .border-collapse {
border-collapse: collapse; border-collapse: collapse;
} }
.resize { .resize {
resize: both; resize: both;
} }
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.justify-center {
justify-content: center;
}
.gap-8 {
gap: calc(var(--spacing) * 8);
}
.space-x-4 {
:where(& > :not(:last-child)) {
--tw-space-x-reverse: 0;
margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse));
margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse)));
}
}
.border { .border {
border-style: var(--tw-border-style); border-style: var(--tw-border-style);
border-width: 1px; border-width: 1px;
} }
.text-4xl { .bg-gray-200 {
font-size: var(--text-4xl); background-color: var(--color-gray-200);
line-height: var(--tw-leading, var(--text-4xl--line-height)); }
.bg-gray-800 {
background-color: var(--color-gray-800);
}
.p-4 {
padding: calc(var(--spacing) * 4);
}
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
.py-4 {
padding-block: calc(var(--spacing) * 4);
}
.py-8 {
padding-block: calc(var(--spacing) * 8);
}
.text-center {
text-align: center;
}
.text-blue-400 {
color: var(--color-blue-400);
}
.text-bodylinks {
color: var(--color-bodylinks);
}
.text-gray-800 {
color: var(--color-gray-800);
}
.text-white {
color: var(--color-white);
} }
.underline { .underline {
text-decoration-line: underline; text-decoration-line: underline;
@@ -200,35 +292,131 @@
outline-style: var(--tw-outline-style); outline-style: var(--tw-outline-style);
outline-width: 1px; outline-width: 1px;
} }
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.hover\:text-gray-400 {
&:hover {
@media (hover: hover) {
color: var(--color-gray-400);
}
}
}
} }
body { body {
width: 100%;
@media (width >= 40rem) {
max-width: 40rem;
}
@media (width >= 48rem) {
max-width: 48rem;
}
@media (width >= 64rem) {
max-width: 64rem;
}
@media (width >= 80rem) {
max-width: 80rem;
}
@media (width >= 96rem) {
max-width: 96rem;
}
margin-inline: auto;
background-color: var(--color-slate-900); background-color: var(--color-slate-900);
padding-inline: calc(var(--spacing) * 4); font-family: var(--font-sans);
padding-block: calc(var(--spacing) * 8);
font-size: var(--text-base); font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height)); line-height: var(--tw-leading, var(--text-base--line-height));
color: var(--color-gray-200); color: var(--color-gray-200);
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
} }
a { ::selection {
color: #00B7FF; background: var(--color-warning);
}
@layer components {
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
margin: 0 0 1rem;
}
h1, .h1 {
font-size: var(--h1);
line-height: 1.2;
}
h2, .h2 {
font-size: var(--h2);
line-height: 1.3;
}
h3, .h3 {
font-size: var(--h3);
line-height: 1.4;
}
h4, .h4 {
font-size: var(--h4);
line-height: 1.5;
}
h5, .h5 {
font-size: var(--h5);
}
h6, .h6 {
font-size: var(--h6);
}
}
a, .link {
color: var(--color-bodylinks);
text-decoration: none;
transition: color 200ms;
cursor: pointer;
&:hover {
color: var(--color-primary);
}
}
h1 a, .h1 a, h2 a, .h2 a, h3 a, .h3 a {
color: inherit;
text-decoration: underline;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
li ul, li ol {
margin: 0 1rem;
}
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
ol ol {
list-style: lower-alpha;
}
ol ol ol {
list-style: lower-roman;
}
ol ol ol ol {
list-style: lower-alpha;
}
pre, code, samp, style {
font-family: monospace;
}
pre {
font-size: 0.875rem;
overflow: auto;
padding: 1.5rem;
}
pre code {
background-color: inherit;
border-radius: 0;
color: inherit;
padding: 0;
}
code {
border-radius: var(--radius-sm);
background-color: color-mix(in srgb, oklch(0% 0 0) 30%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-black) 30%, transparent);
}
padding-inline: 3px;
padding-block: 2px;
font-family: var(--font-mono);
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
color: var(--color-black);
}
hr {
background-color: black;
border: none;
display: block;
height: 1px;
margin: 1rem 0;
width: 100%;
}
@property --tw-space-x-reverse {
syntax: "*";
inherits: false;
initial-value: 0;
} }
@property --tw-border-style { @property --tw-border-style {
syntax: "*"; syntax: "*";
@@ -243,6 +431,7 @@ a {
@layer properties { @layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop { *, ::before, ::after, ::backdrop {
--tw-space-x-reverse: 0;
--tw-border-style: solid; --tw-border-style: solid;
--tw-outline-style: solid; --tw-outline-style: solid;
} }

View File

@@ -1,12 +1,5 @@
@import 'tailwindcss'; @import 'tailwindcss';
@import './colors.css';
@import './typography.css';
@plugin "@tailwindcss/typography"; @plugin "@tailwindcss/typography";
body {
@apply container mx-auto px-4 py-8 text-base text-gray-200 bg-slate-900;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

41
styles/colors.css Normal file
View File

@@ -0,0 +1,41 @@
/* Theme color definitions */
@theme {
--color-black: oklch(0% 0 0);
--color-white: oklch(100% 0 0);
--color-background: oklch(89.75% 0 0);
--color-text: var(--color-black);
--color-primary: oklch(0.57 0.203362 257.1706);
--color-primary-100: color-mix(in oklch, var(--color-primary) 10%, white);
--color-primary-200: color-mix(in oklch, var(--color-primary) 20%, white);
--color-primary-300: color-mix(in oklch, var(--color-primary) 30%, white);
--color-primary-400: color-mix(in oklch, var(--color-primary) 40%, white);
--color-primary-500: color-mix(in oklch, var(--color-primary) 50%, white);
--color-primary-600: color-mix(in oklch, var(--color-primary) 60%, white);
--color-primary-700: color-mix(in oklch, var(--color-primary) 70%, white);
--color-primary-800: color-mix(in oklch, var(--color-primary) 80%, white);
--color-primary-900: color-mix(in oklch, var(--color-primary) 90%, white);
--color-secondary: oklch(0.56 0.0176 257.23);
--color-secondary-100: color-mix(in oklch, var(--color-secondary) 10%, white);
--color-secondary-200: color-mix(in oklch, var(--color-secondary) 20%, white);
--color-secondary-300: color-mix(in oklch, var(--color-secondary) 30%, white);
--color-secondary-400: color-mix(in oklch, var(--color-secondary) 40%, white);
--color-secondary-500: color-mix(in oklch, var(--color-secondary) 50%, white);
--color-secondary-600: color-mix(in oklch, var(--color-secondary) 60%, white);
--color-secondary-700: color-mix(in oklch, var(--color-secondary) 70%, white);
--color-secondary-800: color-mix(in oklch, var(--color-secondary) 80%, white);
--color-secondary-900: color-mix(in oklch, var(--color-secondary) 90%, white);
--color-bodylinks: oklch(0.48 0.0789 211.58);
--color-footlinks: oklch(0.65 0.1104 212.2);
--color-success: oklch(64.01% 0.1751 146.7);
--color-info: oklch(0.55 0.0922 211.57);
--color-warning: oklch(84.42% 0.1722 84.93);
--color-danger: oklch(0.5126 0.1865 22.61);
--color-light: oklch(98.16% 0.0017 247.8);
--color-dark: oklch(34.51% 0.0133 248.2);
}

150
styles/typography.css Normal file
View File

@@ -0,0 +1,150 @@
/* Basic typographical styles */
/**
* All font sizes are based on 16px base font size and 1920px wide screen
* Default size is expressed as percentage of screen width.
* text-14px: 12px-27px, default: 14px
* text-16px: 14px-28px, default: 16px
* text-18px: 14px-30px, default: 18px
* text-20px: 16px-32px, default: 20px
* text-22px: 17px-33px, default: 22px
* text-25px: 18px-35px, default: 25px
* text-30px: 19px-37px, default: 30px
* text-35px: 20px-40px, default: 35px
* text-38px: 22px-48px, default: 38px
* text-40px: 24px-56px, default: 40px
* text-45px: 25px-64px, default: 45px
* text-50px: 27px-72px, default: 50px
* text-55px: 28px-76px, default: 55px
* text-60px: 30px-80px, default: 60px
* text-70px: 30px-76px, default: 70px
* text-75px: 32px-80px, default: 75px
*/
@theme {
--font-sans: "Raleway", sans-serif;
--line-height: 1.6;
--text-base: 1rem;
--text-14px: clamp(0.75rem, 0.7292vw, 1.7rem);
--text-16px: clamp(0.875rem, 0.8333vw, 1.8rem);
--text-18px: clamp(0.875rem, 0.9375vw, 1.9rem);
--text-20px: clamp(1rem, 1.0417vw, 2rem);
--text-22px: clamp(1.1rem, 1.15vw, 2.1rem);
--text-25px: clamp(1.125rem, 1.3021vw, 2.2rem);
--text-30px: clamp(1.185rem, 1.5625vw, 2.35rem);
--text-35px: clamp(1.25rem, 1.8229vw, 2.5rem);
--text-38px: clamp(1.4rem, 1.9791vw, 3rem);
--text-40px: clamp(1.5rem, 2.0834vw, 3.5rem);
--text-45px: clamp(1.6rem, 2.3438vw, 4rem);
--text-50px: clamp(1.7rem, 2.6042vw, 4.5rem);
--text-70px: clamp(1.9rem, 3.6458vw, 4.8rem);
--text-75px: clamp(2rem, 3.9063vw, 5rem);
--h1: calc(var(--text-base) * 2.25);
--h2: calc(var(--text-base) * 1.75);
--h3: calc(var(--text-base) * 1.5);
--h4: calc(var(--text-base) * 1.25);
--h5: calc(var(--text-base) * 1.125);
--h6: calc(var(--text-base) * 1.05);
}
body {
@apply font-sans text-base text-gray-200 bg-slate-900;
}
::selection { background: var(--color-warning); }
@layer components {
h1, h2, h3,
h4, h5, h6 {
font-weight: 700;
margin: 0 0 1rem;
}
h1, .h1 {
font-size: var(--h1);
line-height: 1.2;
}
h2, .h2 {
font-size: var(--h2);
line-height: 1.3;
}
h3, .h3 {
font-size: var(--h3);
line-height: 1.4;
}
h4, .h4 {
font-size: var(--h4);
line-height: 1.5;
}
h5, .h5 { font-size: var(--h5); }
h6, .h6 { font-size: var(--h6); }
}
a, .link {
color: var(--color-bodylinks);
text-decoration: none;
transition: color 200ms;
cursor: pointer;
&:hover { color: var(--color-primary); }
}
h1 a, .h1 a,
h2 a, .h2 a,
h3 a, .h3 a {
color: inherit;
text-decoration: underline;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
li ul, li ol { margin: 0 1rem; }
ul { list-style-type: disc; }
ol { list-style-type: decimal; }
ol ol { list-style: lower-alpha; }
ol ol ol { list-style: lower-roman; }
ol ol ol ol { list-style: lower-alpha; }
pre, code,
samp, style { font-family: monospace; }
pre {
font-size: 0.875rem;
overflow: auto;
padding: 1.5rem;
}
pre code {
background-color: inherit;
border-radius: 0;
color: inherit;
padding: 0;
}
code {
@apply bg-black/30 px-[3px] py-[2px] font-mono text-black text-xs rounded-sm;
}
hr {
background-color: black;
border: none;
display: block;
height: 1px;
margin: 1rem 0;
width: 100%;
}

16
views/footer.ejs Normal file
View File

@@ -0,0 +1,16 @@
<footer class="bg-gray-800 text-white p-4 mt-8">
<div class="container mx-auto text-center">
<div class="flex justify-center gap-8 items-center mb-4">
<p>&copy; <%= new Date().getFullYear() %> <%= title %>. All rights reserved.</p>
<p>Powered by <a href="https://example.com" class="text-bodylinks">Your Company</a></p>
</div>
<p>
<a href="/privacy" class="text-blue-400">Privacy Policy</a> |
<a href="/terms" class="text-blue-400">Terms of Service</a>
</p>
</div>
</footer>
</main>
</body>
</html>

32
views/header.ejs Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Raleway:wght@100..900&display=swap">
<title>
<%= title %>
</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<main class="">
<header class="bg-gray-200 w-full">
<div class="container mx-auto flex justify-between items-center text-gray-800 p-4">
<div class="flex items-center">
<!-- <img src="/images/logo.png" alt="Logo" class="h-8 mr-2"> -->
<h1 class=""><%= title %></h1>
</div>
<nav>
<ul class="flex space-x-4">
<li><a href="/" class="text-white hover:text-gray-400">Home</a></li>
<li><a href="/about" class="text-white hover:text-gray-400">About</a></li>
<li><a href="/contact" class="text-white hover:text-gray-400">Contact</a></li>
</ul>
</nav>
</div>
</header>

View File

@@ -1,12 +1,8 @@
<!DOCTYPE html> <%- include('header'); -%>
<html>
<head> <article class="container mx-auto py-4">
<title><%= title %></title> <h2>Welcome to the <%= title %> EJS Template</h2>
<link rel='stylesheet' href='/stylesheets/style.css' /> <p>This is a simple example of using EJS for templating.</p>
</head> </article>
<body>
<h1 class="text-4xl mb-2"><%= title %></h1> <%- include('footer'); -%>
<hr class="my-4">
<p>Welcome to <%= title %></p>
</body>
</html>