@casoon/pages-theme 0.12.6 → 0.12.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -270,6 +270,11 @@ to it as well.
270
270
  in `fonts/OFL.txt`), no CDNs, embeds, analytics or cookies.
271
271
  - JavaScript: two small inline scripts (theme before first paint; theme toggle and copy
272
272
  buttons). Tabs work without JavaScript. The one exception is a `Demo` stage, see above.
273
- - Footer on every page: "Ein Projekt von CASOON · Jörn Seidel", licence, Impressum and
274
- Datenschutz (casoon.de), the project catalog on casoon.dev.
273
+ - Footer on every page, in the site's language (`lang`): "A CASOON project · Jörn Seidel",
274
+ licence, imprint and privacy policy (casoon.de), the project catalog on casoon.dev.
275
275
  - Light and dark theme, following `prefers-color-scheme` until the visitor chooses.
276
+
277
+ ## Maintaining
278
+
279
+ Development, releases, the rollout to all project sites and setting up a new one:
280
+ [MAINTAINING.md](MAINTAINING.md).
@@ -28,8 +28,9 @@ const { title, href, label } = Astro.props;
28
28
  text-align: center;
29
29
  }
30
30
  h2 {
31
- max-width: 14ch;
31
+ max-width: 18ch;
32
32
  margin: 0;
33
+ text-wrap: balance;
33
34
  color: #fff;
34
35
  font-size: clamp(40px, 6vw, 70px);
35
36
  font-weight: 600;
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  import config from 'virtual:casoon-pages/config';
3
- import logo from '../assets/casoon-logo.svg';
4
3
  import logoDark from '../assets/casoon-logo-dark.svg';
5
4
  import { t } from '../lib/i18n';
6
5
  import { CASOON_URL, catalogUrl, url } from '../lib/url';
@@ -41,33 +40,35 @@ const columns = [
41
40
  ---
42
41
 
43
42
  <footer class="footer">
44
- <div class="cols">
45
- <div>
46
- <a class="logo" href={CASOON_URL}>
47
- <img class="logo-light" src={logo.src} width="150" height="41" alt="CASOON" />
48
- <img class="logo-dark" src={logoDark.src} width="150" height="41" alt="CASOON" />
49
- </a>
50
- <p>{config.description}</p>
51
- <p class="by">{s.footerBy} · Jörn Seidel</p>
43
+ <div class="top">
44
+ <div class="intro">
45
+ <p class="name">{config.name}</p>
46
+ <p class="description">{config.description}</p>
47
+ </div>
48
+ <div class="cols">
49
+ {
50
+ columns.filter((col) => col.links.length > 0).map((col) => (
51
+ <nav aria-label={col.title}>
52
+ <p class="title">{col.title}</p>
53
+ <ul>
54
+ {col.links.map((link) => (
55
+ <li>
56
+ <a href={link.href}>{link.label}</a>
57
+ </li>
58
+ ))}
59
+ </ul>
60
+ </nav>
61
+ ))
62
+ }
52
63
  </div>
53
- {
54
- columns.filter((col) => col.links.length > 0).map((col) => (
55
- <nav aria-label={col.title}>
56
- <p class="title">{col.title}</p>
57
- <ul>
58
- {col.links.map((link) => (
59
- <li>
60
- <a href={link.href}>{link.label}</a>
61
- </li>
62
- ))}
63
- </ul>
64
- </nav>
65
- ))
66
- }
67
64
  </div>
68
65
  <div class="bottom">
69
- <span>{config.license && `${s.license(config.license)} · `}© {new Date().getFullYear()} Jörn Seidel</span>
66
+ <a class="by" href={CASOON_URL}>
67
+ <img src={logoDark.src} width="150" height="41" alt="CASOON" />
68
+ <span>{s.footerBy} · Jörn Seidel</span>
69
+ </a>
70
70
  <span class="legal">
71
+ <span>{config.license && `${s.license(config.license)} · `}© {new Date().getFullYear()}</span>
71
72
  <a href={IMPRESSUM}>{s.imprint}</a>
72
73
  <a href={DATENSCHUTZ}>{s.privacyPolicy}</a>
73
74
  </span>
@@ -78,47 +79,56 @@ const columns = [
78
79
  /* Black footer in both themes. */
79
80
  .footer {
80
81
  --text: #b4b1ac;
81
- --muted: #b4b1ac;
82
+ --muted: #8f8b85;
82
83
  --heading: #fff;
83
84
  --border: rgb(255 255 255 / 0.12);
84
85
 
85
86
  background: #11100e;
86
87
  color: var(--text);
87
- font-size: 14px;
88
+ font-size: 15px;
88
89
  }
89
- .cols {
90
+ .top {
90
91
  display: grid;
91
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
92
- gap: 40px;
92
+ grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
93
+ gap: 48px 64px;
93
94
  max-width: var(--max);
94
95
  margin: 0 auto;
95
- padding: 80px 24px 48px;
96
+ padding: 96px 24px 72px;
96
97
  }
97
- .logo {
98
- display: inline-block;
99
- margin-bottom: 14px;
98
+ .intro p {
99
+ margin: 0;
100
100
  }
101
- .logo img {
102
- display: block;
103
- width: 120px;
104
- height: auto;
101
+ .name {
102
+ color: var(--heading);
103
+ font-size: clamp(36px, 4.5vw, 56px);
104
+ font-weight: 600;
105
+ letter-spacing: -0.03em;
106
+ line-height: 1;
105
107
  }
106
- .logo-light {
107
- display: none !important;
108
+ .name::after {
109
+ content: '.';
110
+ color: var(--accent-fill);
108
111
  }
109
- p {
110
- margin: 0 0 6px;
111
- max-width: 32ch;
112
+ .intro .description {
113
+ max-width: 34ch;
114
+ margin-top: 20px;
115
+ color: var(--text);
116
+ font-size: 17px;
117
+ line-height: 1.5;
118
+ text-wrap: pretty;
112
119
  }
113
- .by {
114
- color: var(--muted);
115
- font-size: 12.5px;
120
+ .cols {
121
+ display: grid;
122
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
123
+ gap: 32px;
116
124
  }
117
125
  .title {
118
- margin-bottom: 16px;
119
- color: var(--heading);
120
- font-size: 18px;
121
- font-weight: 500;
126
+ margin: 0 0 18px;
127
+ color: var(--muted);
128
+ font-family: var(--font-mono);
129
+ font-size: 12px;
130
+ letter-spacing: 0.08em;
131
+ text-transform: uppercase;
122
132
  }
123
133
  ul {
124
134
  display: flex;
@@ -129,27 +139,50 @@ const columns = [
129
139
  list-style: none;
130
140
  }
131
141
  ul a {
132
- color: var(--text);
142
+ color: var(--heading);
143
+ text-decoration: underline;
144
+ text-decoration-color: transparent;
145
+ text-underline-offset: 4px;
146
+ transition: text-decoration-color 0.2s;
133
147
  }
134
148
  ul a:hover {
135
- color: var(--heading);
149
+ text-decoration-color: currentColor;
150
+ }
151
+ ul a[href^='http']::after {
152
+ content: ' ↗' / '';
153
+ color: var(--muted);
136
154
  }
137
155
  .bottom {
138
156
  display: flex;
139
157
  flex-wrap: wrap;
158
+ align-items: center;
140
159
  justify-content: space-between;
141
- gap: 16px;
160
+ gap: 16px 32px;
142
161
  max-width: var(--max);
143
162
  margin: 0 auto;
144
- padding: 16px 24px 40px;
163
+ padding: 24px 24px 40px;
145
164
  border-top: 1px solid var(--border);
146
165
  color: var(--muted);
147
166
  font-size: 13px;
148
167
  }
168
+ .by {
169
+ display: inline-flex;
170
+ align-items: center;
171
+ gap: 14px;
172
+ color: var(--muted);
173
+ }
174
+ .by img {
175
+ display: block;
176
+ width: 96px;
177
+ height: auto;
178
+ }
179
+ .by:hover {
180
+ color: var(--heading);
181
+ }
149
182
  .legal {
150
183
  display: flex;
151
184
  flex-wrap: wrap;
152
- gap: 18px;
185
+ gap: 8px 20px;
153
186
  }
154
187
  .legal a {
155
188
  color: var(--muted);
@@ -157,4 +190,10 @@ const columns = [
157
190
  .legal a:hover {
158
191
  color: var(--heading);
159
192
  }
193
+ @media (max-width: 760px) {
194
+ .top {
195
+ grid-template-columns: 1fr;
196
+ padding-top: 72px;
197
+ }
198
+ }
160
199
  </style>
@@ -26,10 +26,12 @@ const home = Astro.site && new URL(url(), Astro.site).href;
26
26
  const ogImage = Astro.site && new URL(url('og.png'), Astro.site).href;
27
27
  const sameAs = [config.website, ...config.packages.map((p) => p.href)].filter(Boolean);
28
28
 
29
+ // tokens.css sets --accent with the same selectors and is linked after this inline style, so the
30
+ // selectors repeat :root to outrank it whatever the order in <head> (scripts/test-accent.mjs).
29
31
  const accentCss = config.accent
30
- ? `:root{--accent:${config.accent.light}}` +
31
- `:root[data-theme="dark"]{--accent:${config.accent.dark}}` +
32
- `@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--accent:${config.accent.dark}}}`
32
+ ? `:root:root{--accent:${config.accent.light}}` +
33
+ `:root:root[data-theme="dark"]{--accent:${config.accent.dark}}` +
34
+ `@media (prefers-color-scheme:dark){:root:root:not([data-theme="light"]){--accent:${config.accent.dark}}}`
33
35
  : '';
34
36
 
35
37
  const structuredData = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@casoon/pages-theme",
3
- "version": "0.12.6",
3
+ "version": "0.12.9",
4
4
  "description": "Shared Astro theme for the GitHub Pages sites of CASOON open-source projects",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,6 +44,15 @@
44
44
  "withastro",
45
45
  "casoon"
46
46
  ],
47
+ "scripts": {
48
+ "dev": "pnpm --filter starter-site dev",
49
+ "build": "pnpm --filter starter-site build",
50
+ "preview": "pnpm --filter starter-site preview",
51
+ "check": "biome check .",
52
+ "check:fix": "biome check --write .",
53
+ "type-check": "pnpm --filter starter-site type-check",
54
+ "test:accent": "node scripts/test-accent.mjs"
55
+ },
47
56
  "peerDependencies": {
48
57
  "astro": "^7.3.2"
49
58
  },
@@ -54,5 +63,11 @@
54
63
  "publishConfig": {
55
64
  "access": "public",
56
65
  "provenance": true
57
- }
66
+ },
67
+ "devDependencies": {
68
+ "@axe-core/playwright": "^4.14.0",
69
+ "@biomejs/biome": "^2.6.4",
70
+ "@playwright/test": "^1.64.1"
71
+ },
72
+ "packageManager": "pnpm@10.26.0"
58
73
  }
package/styles/tokens.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
- * Design tokens. Brand colours follow casoon.de,
3
- * adjusted for 4.5:1 text contrast on the page background.
2
+ * Design tokens. Brand colours follow casoon.de, adjusted for 4.5:1 text contrast on the
3
+ * page background and on the sand bands (--bg-deep, --bg-sunken).
4
4
  * --brand carries CASOON, --accent carries the project (override via the
5
5
  * integration's `accent` option).
6
6
  */
@@ -19,9 +19,9 @@
19
19
  --text: #44423f;
20
20
  --heading: #11100e;
21
21
  --muted: #5c5a56;
22
- --brand: #c13a1a;
22
+ --brand: #ad3216;
23
23
  --brand-soft: rgb(236 74 32 / 0.1);
24
- --accent: #c13a1a;
24
+ --accent: #ad3216;
25
25
  --accent-soft: color-mix(in srgb, var(--accent) 10%, transparent);
26
26
  --accent-fill: #d4421d;
27
27
  --accent-top: #e46140;