Compare commits

...

2 Commits

Author SHA1 Message Date
minori 7f0ef13c0a deps: update @types/jsdom to 28.0.0
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 2m33s
Node.js CI / CI (pull_request) Successful in 2m44s
2026-03-06 07:04:12 -08:00
hikari 7d8c6bf21c fix: load Google Fonts correctly with strict CSP (#77)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m42s
Node.js CI / CI (push) Successful in 1m47s
## Summary

- Allows `fonts.googleapis.com` in `style-src` and `fonts.gstatic.com` in `font-src` so the browser can load Google Fonts
- Adds preconnect hints and the Google Fonts import (Griffy, Kalam, Creepster, Henny Penny) to `index.html`
- Sets the body font to Kalam and heading font to Griffy, with utility classes for Creepster and Henny Penny
- Disables Angular's `inlineCritical` optimisation, which was causing the stylesheet to be deferred via `onload="this.media='all'"` — an inline event handler blocked by the strict `script-src` CSP, preventing the heading font rules from ever applying to screen media

## Test plan

- [ ] Rebuild and reload the app
- [ ] Verify headings render in Griffy
- [ ] Verify body text renders in Kalam
- [ ] Check DevTools Styles tab confirms the `h1-h6` font-family rule is matched

 This PR was created with help from Hikari~ 🌸

Reviewed-on: #77
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-03-05 10:32:19 -08:00
6 changed files with 44 additions and 9 deletions
+2 -2
View File
@@ -14,11 +14,11 @@ const helmetPlugin: FastifyPluginAsync = async (app) => {
directives: {
defaultSrc: ["'self'"],
// Angular uses inline styles for component encapsulation, so we need to allow them
styleSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
imgSrc: ["'self'", "data:", "https:"],
scriptSrc: ["'self'"],
connectSrc: ["'self'", process.env.FRONTEND_URL ?? "http://localhost:4200"],
fontSrc: ["'self'", "data:"],
fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
+5
View File
@@ -25,6 +25,11 @@
},
"configurations": {
"production": {
"optimization": {
"styles": {
"inlineCritical": false
}
},
"budgets": [
{
"type": "initial",
+3
View File
@@ -8,6 +8,9 @@
<meta name="description" content="Naomi's curated collection of games, books, music, shows, manga, and art. Browse, engage, and suggest new additions!" />
<meta name="theme-color" content="#9d4edd" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Creepster&family=Griffy&family=Henny+Penny&family=Kalam:wght@300;400;700&display=swap" rel="stylesheet" />
<script defer src="https://analytics.nhcarrigan.com/js/pa-YUXAn1vhhRttySUAw_LMN.js"></script>
<script>
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
+22 -1
View File
@@ -38,7 +38,7 @@
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
font-family: 'Kalam', cursive;
font-size: 14pt;
line-height: 1.6;
color: var(--foreground);
@@ -75,10 +75,30 @@ body::after {
pointer-events: none;
}
@keyframes wiggle {
0%, 100% { transform: rotate(-2deg); }
50% { transform: rotate(2deg); }
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
line-height: 1.2;
color: var(--witch-purple);
font-family: 'Griffy', cursive;
}
h1 {
animation: wiggle 4s ease-in-out infinite;
display: inline-block;
}
.witchy-accent,
.spooky-title {
font-family: 'Creepster', cursive;
}
.mystical-text {
font-family: 'Henny Penny', cursive;
}
a {
@@ -121,6 +141,7 @@ select:focus {
// Button base styles
button {
font-family: inherit;
transition: all 0.3s;
}
+1 -1
View File
@@ -73,7 +73,7 @@
"@swc/helpers": "0.5.18",
"@types/dompurify": "3.2.0",
"@types/jest": "30.0.0",
"@types/jsdom": "27.0.0",
"@types/jsdom": "28.0.0",
"@types/jsonwebtoken": "9.0.10",
"@types/node": "20.19.9",
"@typescript-eslint/utils": "8.56.0",
+11 -5
View File
@@ -166,8 +166,8 @@ importers:
specifier: 30.0.0
version: 30.0.0
'@types/jsdom':
specifier: 27.0.0
version: 27.0.0
specifier: 28.0.0
version: 28.0.0
'@types/jsonwebtoken':
specifier: 9.0.10
version: 9.0.10
@@ -3438,8 +3438,8 @@ packages:
'@types/jest@30.0.0':
resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==}
'@types/jsdom@27.0.0':
resolution: {integrity: sha512-NZyFl/PViwKzdEkQg96gtnB8wm+1ljhdDay9ahn4hgb+SfVtPCbm3TlmDUFXTA+MGN3CijicnMhG18SI5H3rFw==}
'@types/jsdom@28.0.0':
resolution: {integrity: sha512-A8TBQQC/xAOojy9kM8E46cqT00sF0h7dWjV8t8BJhUi2rG6JRh7XXQo/oLoENuZIQEpXsxLccLCnknyQd7qssQ==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -8940,6 +8940,9 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@7.22.0:
resolution: {integrity: sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==}
undici@7.18.2:
resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==}
engines: {node: '>=20.18.1'}
@@ -14110,11 +14113,12 @@ snapshots:
expect: 30.2.0
pretty-format: 30.2.0
'@types/jsdom@27.0.0':
'@types/jsdom@28.0.0':
dependencies:
'@types/node': 20.19.9
'@types/tough-cookie': 4.0.5
parse5: 7.3.0
undici-types: 7.22.0
'@types/json-schema@7.0.15': {}
@@ -20632,6 +20636,8 @@ snapshots:
undici-types@6.21.0: {}
undici-types@7.22.0: {}
undici@7.18.2: {}
undici@7.22.0: {}