Experimenting with card design

This commit is contained in:
Z. Charles Dziura 2025-07-09 06:52:55 -04:00
parent b2ef5a9420
commit af58306db5
14 changed files with 83 additions and 101 deletions

View file

@ -260,7 +260,7 @@
"node_modules/@angular/compiler": { "node_modules/@angular/compiler": {
"version": "20.0.2", "version": "20.0.2",
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.0.2.tgz", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.0.2.tgz",
"integrity": "sha512-BJYXGUZaY9awYvgt0w9TDq73A1+m8W5eMRn/krWeQcfWakwTgs27BSxmhfJhD45KrMrky5yxAvGgqSfMKrLeng==", "integrity": "sha512-BJYXGUZaY9awYvgt0w9TDq73A1+m8W5remRn/krWeQcfWakwTgs27BSxmhfJhD45KrMrky5yxAvGgqSfMKrLeng==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tslib": "^2.3.0" "tslib": "^2.3.0"
@ -1336,7 +1336,7 @@
"node_modules/@inquirer/figures": { "node_modules/@inquirer/figures": {
"version": "1.0.12", "version": "1.0.12",
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz",
"integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2remWYIn0jQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -1558,7 +1558,7 @@
"node_modules/@isaacs/cliui/node_modules/string-width": { "node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7remiVqA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2332,7 +2332,7 @@
"node_modules/@npmcli/package-json/node_modules/brace-expansion": { "node_modules/@npmcli/package-json/node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-XnAIvQ8rem+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -3223,7 +3223,7 @@
"node_modules/@tufjs/models/node_modules/brace-expansion": { "node_modules/@tufjs/models/node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-XnAIvQ8rem+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -3648,7 +3648,7 @@
"node_modules/cacache/node_modules/brace-expansion": { "node_modules/cacache/node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-XnAIvQ8rem+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5207,7 +5207,7 @@
"node_modules/ignore-walk/node_modules/brace-expansion": { "node_modules/ignore-walk/node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-XnAIvQ8rem+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -6410,7 +6410,7 @@
"node_modules/minipass-flush/node_modules/yallist": { "node_modules/minipass-flush/node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2remQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -6443,7 +6443,7 @@
"node_modules/minipass-pipeline/node_modules/yallist": { "node_modules/minipass-pipeline/node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2remQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -6476,7 +6476,7 @@
"node_modules/minipass-sized/node_modules/yallist": { "node_modules/minipass-sized/node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2remQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -8201,7 +8201,7 @@
"node_modules/tar/node_modules/yallist": { "node_modules/tar/node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2remQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@ -8403,7 +8403,7 @@
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0remRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {

View file

@ -1,4 +1,4 @@
@if ($showNavRail()) { @if ($showNavRail | async) {
<app-nav-rail></app-nav-rail> <app-nav-rail></app-nav-rail>
} }
<main> <main>

View file

@ -1,10 +1,14 @@
:host { :host {
display: grid; display: grid;
grid-template-areas: 'nav' 'main'; grid-template-areas: 'nav main';
grid-template-columns: min-content auto; grid-template-columns: min-content auto;
min-height: 100vh; min-height: 100vh;
} }
main { main {
align-items: center;
display: grid;
grid-area: main; grid-area: main;
grid-template-rows: 0 auto; // Handle the <router-element> mangling the layout
justify-items: center;
} }

View file

@ -1,19 +1,25 @@
import { Component, computed, signal } from '@angular/core'; import { AsyncPipe } from '@angular/common';
import { RouterOutlet } from '@angular/router'; import { Component, inject } from '@angular/core';
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';
import { filter, map } from 'rxjs';
import { NavRail } from './components/nav-rail/nav-rail'; import { NavRail } from './components/nav-rail/nav-rail';
const ROUTES_THAT_HIDE_NAV_RAIL = /^\/login$/; const ROUTES_THAT_HIDE_NAV_RAIL = /^\/login$/;
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
imports: [RouterOutlet, NavRail], imports: [AsyncPipe, RouterOutlet, NavRail],
styleUrl: './app.scss', styleUrl: './app.scss',
templateUrl: './app.html', templateUrl: './app.html',
}) })
export class App { export class App {
private readonly $_pathname = signal(location.pathname); private readonly router = inject(Router);
readonly $showNavRail = computed(() => {
const pathname = this.$_pathname(); readonly $showNavRail = this.router.events.pipe(
return pathname.length > 0 && !ROUTES_THAT_HIDE_NAV_RAIL.test(pathname); filter(event => event instanceof NavigationEnd),
}); map(
({ urlAfterRedirects }: NavigationEnd) =>
urlAfterRedirects.length > 0 && !ROUTES_THAT_HIDE_NAV_RAIL.test(urlAfterRedirects)
)
);
} }

View file

@ -1,23 +1,22 @@
:host { :host {
background-color: var(--color-surface-container);
border: 1px solid var(--color-outline); border: 1px solid var(--color-outline);
border-radius: 0.2em; border-radius: 1.2rem;
color: var(--color-on-surface); color: var(--color-on-surface);
display: inline-grid; display: inline-grid;
font-size: 1.8em; font-size: 1.8rem;
grid-template-areas: grid-template-areas:
'head' 'head'
'body' 'body'
'foot'; 'foot';
grid-template-rows: min-content auto min-content; grid-template-rows: min-content auto min-content;
padding: 0.4em; padding: 1.6rem;
} }
header { header {
margin-top: 0.4em; margin-top: 0.4rem;
} }
footer { footer {
justify-content: flex-end; justify-content: flex-end;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-top: 1.2em; margin-top: 1.2rem;
} }

View file

@ -1,7 +1,7 @@
nav { nav {
background-color: var(--color-surface-container); background-color: var(--color-surface-container);
box-shadow: rgba(0, 0, 0, 0.02) 0px 1px 3px 0px, rgba(27, 31, 35, 0.15) 0px 0px 0px 1px; box-shadow: var(--box-shadow);
font-size: 1.6em; font-size: 1.6rem;
height: 100%; height: 100%;
.nav-list { .nav-list {
@ -9,7 +9,7 @@ nav {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
list-style: none; list-style: none;
padding: 1.8em 1.2em; padding: 1.8rem 1.2rem;
.nav-list__item { .nav-list__item {
align-items: center; align-items: center;
@ -18,7 +18,7 @@ nav {
inline-size: min-content; inline-size: min-content;
&:not(:last-of-type) { &:not(:last-of-type) {
margin-bottom: 1.8em; margin-bottom: 1.8rem;
} }
.nav-list__item-label { .nav-list__item-label {

View file

@ -1 +1,6 @@
<p>login works!</p> <app-card>
<h3 class="card-header">Login</h3>
<div>
I'm the body!
</div>
</app-card>

View file

@ -1,5 +1,3 @@
:host { :host {
display: grid; display: grid;
height: 100%;
width: 100%;
} }

View file

@ -1,11 +1,10 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Card } from 'components/card/card';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
imports: [], templateUrl: './login.html',
templateUrl: './login.html', styleUrl: './login.scss',
styleUrl: './login.scss' imports: [Card],
}) })
export class Login { export class Login {}
}

View file

@ -15,9 +15,9 @@ header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
grid-area: body; grid-area: body;
padding-left: 1.8em; padding-left: 1.8rem;
& > *:not(:last-child) { & > *:not(:last-child) {
margin-bottom: 1.6em; margin-bottom: 1.6rem;
} }
} }

View file

@ -1,5 +1,5 @@
@import url('./styles/reset.scss'); @import url('./styles/reset.scss');
@import url('./styles/fonts.scss'); @import url('./styles/typography.scss');
@import url('./styles/components/button.scss'); @import url('./styles/components/button.scss');
:root { :root {
@ -33,25 +33,14 @@
--color-shadow: oklch(0.3396 0.0743 281.7 / 25%); --color-shadow: oklch(0.3396 0.0743 281.7 / 25%);
--color-shadow-variant: oklch(0 0 0 / 30%); --color-shadow-variant: oklch(0 0 0 / 30%);
--box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
font-family: system-ui, sans-serif;
font-size: 62.5%;
font-weight: 400;
} }
body { body {
font-family: 'Quicksand', sans-serif;
font-size: 62.5%;
font-weight: 400;
margin: 0; margin: 0;
} }
h1,
h3,
h5 {
font-family: 'Limelight', serif;
font-weight: 400;
}
h2,
h4,
h6 {
font-family: 'Quicksand', sans-serif;
font-weight: 500;
}

View file

@ -1,11 +1,11 @@
button { button {
background-color: var(--color-surface-container); background-color: var(--color-surface-container);
border: 1px solid var(--color-outline); border: 1px solid var(--color-outline);
border-radius: 0.4em; border-radius: 0.4rem;
color: var(--color-on-surface-container); color: var(--color-on-surface-container);
cursor: pointer; cursor: pointer;
font-size: 0.8em; font-size: 0.8rem;
padding: 0.2em 0.6em; padding: 0.2rem 0.6rem;
&:hover { &:hover {
box-shadow: var(--color-shadow) 0px 3px 8px; box-shadow: var(--color-shadow) 0px 3px 8px;

View file

@ -1,36 +0,0 @@
/* latin-ext */
@font-face {
font-family: 'Limelight';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/limelight/v20/XLYkIZL7aopJVbZJHDuoNOlHnnY.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Limelight';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/limelight/v20/XLYkIZL7aopJVbZJHDuoOulH.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
font-family: 'Quicksand';
font-style: normal;
font-weight: 300 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/quicksand/v36/6xKtdSZaM9iE8KbpRA_hJVQNcOM.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Quicksand';
font-style: normal;
font-weight: 300 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/quicksand/v36/6xKtdSZaM9iE8KbpRA_hK1QN.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View file

@ -0,0 +1,18 @@
h1,
h2,
h3 {
font-family: Avenir, Montserrat, Corbel, 'URW Gothic', source-sans-pro, sans-serif;
font-weight: 500;
}
h1 {
font-size: 5.7rem;
}
h2 {
font-size: 4.5rem;
}
h3 {
font-size: 3.6rem;
}