Compare commits
11 Commits
a2242809b2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
ddcfc8d8d2
|
|||
|
dac44e1b12
|
|||
|
5eb34a0c59
|
|||
|
ef40d25e6a
|
|||
|
718165aa23
|
|||
|
c15adf8e3c
|
|||
|
72f0eab718
|
|||
|
beffd5f4e8
|
|||
|
0c4823d263
|
|||
|
c912cde7f5
|
|||
|
c8d7c168c8
|
@@ -21,16 +21,16 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- set -e
|
- set -e
|
||||||
- apk add --no-cache jq
|
- apk add --no-cache jq
|
||||||
- APP_VERSION=$(jq -r .version package.json | sed 's/^v//')
|
- APP_VERSION=$(jq -r .version package.json | tr -d '\r\n' | sed 's/^v//')
|
||||||
- echo "=== Building Docker image ==="
|
- echo "=== Building Docker image ==="
|
||||||
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
- 'echo "Commit SHA: ${CI_COMMIT_SHA:0:8}"'
|
||||||
- 'echo "Registry repo: $REGISTRY_REPO"'
|
- 'echo "Registry repo: $REGISTRY_REPO"'
|
||||||
- 'echo "App version: $APP_VERSION"'
|
- 'echo "App version: $APP_VERSION"'
|
||||||
- |
|
- |
|
||||||
docker build \
|
docker build \
|
||||||
--tag $REGISTRY_REPO:${CI_COMMIT_SHA} \
|
--tag "$REGISTRY_REPO:$CI_COMMIT_SHA" \
|
||||||
--tag $REGISTRY_REPO:latest \
|
--tag "$REGISTRY_REPO:latest" \
|
||||||
--tag $REGISTRY_REPO:${APP_VERSION} \
|
--tag "$REGISTRY_REPO:$APP_VERSION" \
|
||||||
--label "git.commit=${CI_COMMIT_SHA}" \
|
--label "git.commit=${CI_COMMIT_SHA}" \
|
||||||
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
--label "git.branch=${CI_COMMIT_BRANCH}" \
|
||||||
.
|
.
|
||||||
@@ -87,7 +87,7 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- set -e
|
- set -e
|
||||||
- apk add --no-cache jq
|
- apk add --no-cache jq
|
||||||
- APP_VERSION=$(jq -r .version package.json | sed 's/^v//')
|
- APP_VERSION=$(jq -r .version package.json | tr -d '\r\n' | sed 's/^v//')
|
||||||
- echo "=== Pushing to registry ==="
|
- echo "=== Pushing to registry ==="
|
||||||
- 'echo "Registry: $REGISTRY_URL"'
|
- 'echo "Registry: $REGISTRY_URL"'
|
||||||
- 'echo "Repository: $REGISTRY_REPO"'
|
- 'echo "Repository: $REGISTRY_REPO"'
|
||||||
@@ -96,9 +96,9 @@ steps:
|
|||||||
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" \
|
echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_URL" \
|
||||||
-u "$REGISTRY_USERNAME" \
|
-u "$REGISTRY_USERNAME" \
|
||||||
--password-stdin
|
--password-stdin
|
||||||
- docker push $REGISTRY_REPO:${CI_COMMIT_SHA}
|
- 'docker push $REGISTRY_REPO:$CI_COMMIT_SHA'
|
||||||
- docker push $REGISTRY_REPO:latest
|
- 'docker push $REGISTRY_REPO:latest'
|
||||||
- docker push $REGISTRY_REPO:${APP_VERSION}
|
- 'docker push $REGISTRY_REPO:$APP_VERSION'
|
||||||
- echo "✓ Images pushed successfully"
|
- echo "✓ Images pushed successfully"
|
||||||
depends_on:
|
depends_on:
|
||||||
- 'Docker image build'
|
- 'Docker image build'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mifi-ventures-landing",
|
"name": "mifi-ventures-landing",
|
||||||
"version": "4.0.0",
|
"version": "4.0.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "https://git.mifi.dev/mifi-ventures/landing.git",
|
"repository": "https://git.mifi.dev/mifi-ventures/landing.git",
|
||||||
"packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268",
|
"packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268",
|
||||||
@@ -12,11 +12,11 @@
|
|||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"format": "prettier --write \"src/**/*.{ts,js,svelte,css,json}\"",
|
"format": "prettier --write \"src/**/*.{ts,js,svelte,css,json}\" \"static/**/*.{css,html,js}\"",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"lint:css": "stylelint \"src/**/*.css\" \"src/**/*.svelte\"",
|
"lint:css": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" \"static/**/*.css\"",
|
||||||
"lint:css:fix": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" --fix",
|
"lint:css:fix": "stylelint \"src/**/*.css\" \"src/**/*.svelte\" \"static/**/*.css\" --fix",
|
||||||
"preview": "serve dist -p 4173",
|
"preview": "serve dist -p 4173",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:unit": "vitest run",
|
"test:unit": "vitest run",
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ docker run --rm \
|
|||||||
npx serve dist -p 4173 &
|
npx serve dist -p 4173 &
|
||||||
sleep 2
|
sleep 2
|
||||||
pnpm exec playwright test
|
pnpm exec playwright test
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
'
|
'
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ if [ -n "$CI" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if command -v docker >/dev/null 2>&1; then
|
if command -v docker >/dev/null 2>&1; then
|
||||||
exec bash "$(dirname "$0")/run-e2e-in-docker.sh"
|
bash "$(dirname "$0")/run-e2e-in-docker.sh"
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# No Docker: run in current environment (e.g. devcontainer; same image as CI)
|
# No Docker: run in current environment (e.g. devcontainer; same image as CI)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ if command -v docker >/dev/null 2>&1; then
|
|||||||
sleep 2
|
sleep 2
|
||||||
pnpm exec playwright test --update-snapshots
|
pnpm exec playwright test --update-snapshots
|
||||||
'
|
'
|
||||||
|
pnpm install --config.confirmModulesPurge=false
|
||||||
else
|
else
|
||||||
echo "Updating snapshots in the current environment (matches CI when using the devcontainer)."
|
echo "Updating snapshots in the current environment (matches CI when using the devcontainer)."
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
49
src/app.css
@@ -131,6 +131,50 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================================
|
||||||
|
Local Font Faces
|
||||||
|
======================================== */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
Base Styles
|
Base Styles
|
||||||
======================================== */
|
======================================== */
|
||||||
@@ -178,6 +222,11 @@ body {
|
|||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong,
|
||||||
|
b {
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
Skip Link (Accessibility)
|
Skip Link (Accessibility)
|
||||||
======================================== */
|
======================================== */
|
||||||
|
|||||||
@@ -47,13 +47,6 @@
|
|||||||
type="font/woff2"
|
type="font/woff2"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
|
||||||
as="font"
|
|
||||||
type="font/woff2"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
@@ -61,13 +54,6 @@
|
|||||||
type="font/woff2"
|
type="font/woff2"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/assets/fonts/inter-v20-latin-italic.woff2"
|
|
||||||
as="font"
|
|
||||||
type="font/woff2"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
rel="preload"
|
rel="preload"
|
||||||
href="/assets/fonts/inter-v20-latin-500.woff2"
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
|||||||
@@ -50,7 +50,9 @@
|
|||||||
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
||||||
{#each section.body as para}
|
{#each section.body as para}
|
||||||
<p>
|
<p>
|
||||||
{#if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
{#if section.id === 'contact' && para === 'mifi Ventures LLC'}
|
||||||
|
<strong>{para}</strong>
|
||||||
|
{:else if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
||||||
<a href="mailto:legal@mifi.ventures"
|
<a href="mailto:legal@mifi.ventures"
|
||||||
>legal@mifi.ventures</a
|
>legal@mifi.ventures</a
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
<h2 id={`${section.id}-heading`}>{section.heading}</h2>
|
||||||
{#each section.body as para}
|
{#each section.body as para}
|
||||||
<p>
|
<p>
|
||||||
{#if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
{#if section.id === 'contact' && para === 'mifi Ventures LLC'}
|
||||||
|
<strong>{para}</strong>
|
||||||
|
{:else if section.id === 'contact' && para === 'legal@mifi.ventures'}
|
||||||
<a href="mailto:legal@mifi.ventures"
|
<a href="mailto:legal@mifi.ventures"
|
||||||
>legal@mifi.ventures</a
|
>legal@mifi.ventures</a
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,20 +1,66 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>404 Not Found — mifi Ventures</title>
|
<link
|
||||||
<meta name="theme-color" content="#0052cc" media="(prefers-color-scheme: light)">
|
rel="preload"
|
||||||
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)">
|
href="/assets/fonts/fraunces-v38-latin-600.woff2"
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
as="font"
|
||||||
<link rel="stylesheet" href="/assets/error-pages.css">
|
type="font/woff2"
|
||||||
</head>
|
crossorigin="anonymous"
|
||||||
<body class="error-page">
|
/>
|
||||||
<main>
|
<link
|
||||||
<div class="emoji" aria-hidden="true">🔍</div>
|
rel="preload"
|
||||||
<h1>404 Not Found</h1>
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
<p>This page went off to find itself. We’re not sure it’s coming back.</p>
|
as="font"
|
||||||
<p><a href="/">Back to mifi Ventures →</a></p>
|
type="font/woff2"
|
||||||
</main>
|
crossorigin="anonymous"
|
||||||
</body>
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-600.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<title>404 Not Found — mifi Ventures</title>
|
||||||
|
<meta
|
||||||
|
name="theme-color"
|
||||||
|
content="#0052cc"
|
||||||
|
media="(prefers-color-scheme: light)"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="stylesheet" href="/assets/error-pages.css" />
|
||||||
|
</head>
|
||||||
|
<body class="error-page">
|
||||||
|
<main>
|
||||||
|
<div class="emoji" aria-hidden="true">🔍</div>
|
||||||
|
<h1 data-testid="404-title">404 Not Found</h1>
|
||||||
|
<p>This page went off to find itself. We’re not sure it’s coming back.</p>
|
||||||
|
<p><a href="/">Back to mifi Ventures →</a></p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,20 +1,66 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>410 Gone — mifi Ventures</title>
|
<link
|
||||||
<meta name="theme-color" content="#0052cc" media="(prefers-color-scheme: light)">
|
rel="preload"
|
||||||
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)">
|
href="/assets/fonts/fraunces-v38-latin-600.woff2"
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
as="font"
|
||||||
<link rel="stylesheet" href="/assets/error-pages.css">
|
type="font/woff2"
|
||||||
</head>
|
crossorigin="anonymous"
|
||||||
<body class="error-page">
|
/>
|
||||||
<main>
|
<link
|
||||||
<div class="emoji" aria-hidden="true">👋</div>
|
rel="preload"
|
||||||
<h1>410 Gone</h1>
|
href="/assets/fonts/inter-v20-latin-regular.woff2"
|
||||||
<p>This page has left the building. We’ve moved on—and so should you.</p>
|
as="font"
|
||||||
<p><a href="/">Back to mifi Ventures →</a></p>
|
type="font/woff2"
|
||||||
</main>
|
crossorigin="anonymous"
|
||||||
</body>
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-500.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-600.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/inter-v20-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/assets/fonts/fraunces-v38-latin-700.woff2"
|
||||||
|
as="font"
|
||||||
|
type="font/woff2"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<title>410 Gone — mifi Ventures</title>
|
||||||
|
<meta
|
||||||
|
name="theme-color"
|
||||||
|
content="#0052cc"
|
||||||
|
media="(prefers-color-scheme: light)"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#4da6ff" media="(prefers-color-scheme: dark)" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="stylesheet" href="/assets/error-pages.css" />
|
||||||
|
</head>
|
||||||
|
<body class="error-page">
|
||||||
|
<main>
|
||||||
|
<div class="emoji" aria-hidden="true">👋</div>
|
||||||
|
<h1 data-testid="410-title">410 Gone</h1>
|
||||||
|
<p>This page has left the building. We’ve moved on—and so should you.</p>
|
||||||
|
<p><a href="/">Back to mifi Ventures →</a></p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -32,28 +32,47 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Local fonts — same paths as +layout.svelte preloads */
|
/* Local fonts — same paths as +layout.svelte preloads */
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: Inter;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
src: url('/assets/fonts/inter-v20-latin-regular.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: Inter;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Fraunces';
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/inter-v20-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
src: url('/assets/fonts/fraunces-v38-latin-600.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Fraunces;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('/assets/fonts/fraunces-v38-latin-700.woff2') format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
/* Error page layout */
|
/* Error page layout */
|
||||||
.error-page {
|
.error-page {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -67,15 +86,18 @@
|
|||||||
color: var(--ep-text);
|
color: var(--ep-text);
|
||||||
background-color: var(--ep-bg-alt);
|
background-color: var(--ep-bg-alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page main {
|
.error-page main {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 2rem 1.5rem;
|
padding: 2rem 1.5rem;
|
||||||
max-width: 28rem;
|
max-width: 28rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page .emoji {
|
.error-page .emoji {
|
||||||
font-size: 4rem;
|
font-size: 4rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page h1 {
|
.error-page h1 {
|
||||||
font-family: var(--ep-font-heading);
|
font-family: var(--ep-font-heading);
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@@ -83,19 +105,23 @@
|
|||||||
margin: 0 0 0.75rem;
|
margin: 0 0 0.75rem;
|
||||||
color: var(--ep-text);
|
color: var(--ep-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page p {
|
.error-page p {
|
||||||
margin: 0 0 1.5rem;
|
margin: 0 0 1.5rem;
|
||||||
color: var(--ep-text-secondary);
|
color: var(--ep-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a {
|
.error-page a {
|
||||||
color: var(--ep-primary);
|
color: var(--ep-primary);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a:hover {
|
.error-page a:hover {
|
||||||
color: var(--ep-primary-hover);
|
color: var(--ep-primary-hover);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-page a:focus-visible {
|
.error-page a:focus-visible {
|
||||||
outline: 2px solid var(--ep-primary);
|
outline: 2px solid var(--ep-primary);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
|
|||||||
@@ -11,6 +11,43 @@
|
|||||||
var BANNER_VISIBLE_CLASS = 'is-visible';
|
var BANNER_VISIBLE_CLASS = 'is-visible';
|
||||||
var hasLoadedThirdParty = false;
|
var hasLoadedThirdParty = false;
|
||||||
|
|
||||||
|
// Trusted Types support (for CSP `require-trusted-types-for 'script'`)
|
||||||
|
// Clarity's tag script looks up window.trustedTypePolicies[policyName] to load its inner script;
|
||||||
|
// we must expose the policy there for Safari (and other browsers) to avoid TT violations.
|
||||||
|
var ttPolicy = null;
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
window.trustedTypes &&
|
||||||
|
typeof window.trustedTypes.createPolicy === 'function'
|
||||||
|
) {
|
||||||
|
ttPolicy = window.trustedTypes.createPolicy('mifi-ventures-policy', {
|
||||||
|
createScriptURL: function (url) {
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ttPolicy && !window.trustedTypePolicies) {
|
||||||
|
window.trustedTypePolicies = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ttPolicy) {
|
||||||
|
window.trustedTypePolicies['mifi-ventures-policy'] = ttPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
ttPolicy = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setScriptSrc(el, url) {
|
||||||
|
if (!el) return;
|
||||||
|
if (ttPolicy) {
|
||||||
|
// When Trusted Types are enforced, wrap URLs via our policy
|
||||||
|
el.src = ttPolicy.createScriptURL(url);
|
||||||
|
} else {
|
||||||
|
el.src = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadThirdPartyAnalytics() {
|
function loadThirdPartyAnalytics() {
|
||||||
if (hasLoadedThirdParty) return;
|
if (hasLoadedThirdParty) return;
|
||||||
hasLoadedThirdParty = true;
|
hasLoadedThirdParty = true;
|
||||||
@@ -19,14 +56,16 @@
|
|||||||
try {
|
try {
|
||||||
var gtagScript = document.createElement('script');
|
var gtagScript = document.createElement('script');
|
||||||
gtagScript.async = true;
|
gtagScript.async = true;
|
||||||
gtagScript.src =
|
setScriptSrc(
|
||||||
'https://www.googletagmanager.com/gtag/js?id=G-36F29PDKRT';
|
gtagScript,
|
||||||
|
'https://www.googletagmanager.com/gtag/js?id=G-36F29PDKRT',
|
||||||
|
);
|
||||||
|
|
||||||
gtagScript.onload = function () {
|
gtagScript.onload = function () {
|
||||||
// Load the existing ga-init.js helper once gtag is ready
|
// Load the existing ga-init.js helper once gtag is ready
|
||||||
var gaInit = document.createElement('script');
|
var gaInit = document.createElement('script');
|
||||||
gaInit.defer = true;
|
gaInit.defer = true;
|
||||||
gaInit.src = '/assets/js/ga-init.js';
|
setScriptSrc(gaInit, '/assets/js/ga-init.js');
|
||||||
document.head.appendChild(gaInit);
|
document.head.appendChild(gaInit);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -36,12 +75,29 @@
|
|||||||
console.error('Failed to load Google Analytics', e);
|
console.error('Failed to load Google Analytics', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Microsoft Clarity
|
// Microsoft Clarity – use the official loader snippet so that
|
||||||
|
// window.clarity is defined before the tag script runs.
|
||||||
try {
|
try {
|
||||||
var clarityScript = document.createElement('script');
|
(function (c, l, a, r, i, t, y) {
|
||||||
clarityScript.defer = true;
|
c[a] =
|
||||||
clarityScript.src = 'https://www.clarity.ms/tag/vuo5q3yf79?ref=bwt';
|
c[a] ||
|
||||||
document.head.appendChild(clarityScript);
|
function () {
|
||||||
|
(c[a].q = c[a].q || []).push(arguments);
|
||||||
|
};
|
||||||
|
t = l.createElement(r);
|
||||||
|
t.async = 1;
|
||||||
|
setScriptSrc(
|
||||||
|
t,
|
||||||
|
`https://www.clarity.ms/tag/${i}?trustedTypes=mifi-ventures-policy`,
|
||||||
|
);
|
||||||
|
y = l.getElementsByTagName(r)[0];
|
||||||
|
y.parentNode.insertBefore(t, y);
|
||||||
|
})(window, document, 'clarity', 'script', 'vuo5q3yf79');
|
||||||
|
|
||||||
|
window.clarity('consentv2', {
|
||||||
|
ad_Storage: 'granted',
|
||||||
|
analytics_Storage: 'granted',
|
||||||
|
});
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
console.error('Failed to load Microsoft Clarity', e2);
|
console.error('Failed to load Microsoft Clarity', e2);
|
||||||
}
|
}
|
||||||
@@ -110,4 +166,3 @@
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
var el = document.getElementById('copyright-year');
|
var el = document.getElementById('copyright-year');
|
||||||
if (el) el.textContent = new Date().getFullYear();
|
if (el) el.textContent = new Date().getFullYear();
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
window.dataLayer = window.dataLayer || [];
|
window.dataLayer = window.dataLayer || [];
|
||||||
function gtag(){ window.dataLayer.push(arguments); }
|
function gtag() {
|
||||||
|
window.dataLayer.push(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
gtag("js", new Date());
|
gtag('js', new Date());
|
||||||
gtag("config", "G-36F29PDKRT", {
|
gtag('config', 'G-36F29PDKRT', {
|
||||||
// optional, but often helpful:
|
// optional, but often helpful:
|
||||||
anonymize_ip: true,
|
anonymize_ip: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
const MOBILE_BREAKPOINT_PX = 768;
|
const MOBILE_BREAKPOINT_PX = 768;
|
||||||
|
|
||||||
/** All focusable elements inside the menu (links). */
|
/** All focusable elements inside the menu (links). */
|
||||||
const getMenuFocusables = (menu) =>
|
const getMenuFocusables = (menu) => menu.querySelectorAll('a[href]');
|
||||||
menu.querySelectorAll('a[href]');
|
|
||||||
|
|
||||||
const mobileMenuHelper = () => {
|
const mobileMenuHelper = () => {
|
||||||
const mobileMenu = document.getElementById('nav-menu');
|
const mobileMenu = document.getElementById('nav-menu');
|
||||||
@@ -15,10 +14,7 @@ const mobileMenuHelper = () => {
|
|||||||
const syncMenuAriaHidden = () => {
|
const syncMenuAriaHidden = () => {
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
const hidden = !mobileMenuToggle.checked;
|
const hidden = !mobileMenuToggle.checked;
|
||||||
mobileMenu.setAttribute(
|
mobileMenu.setAttribute('aria-hidden', hidden ? 'true' : 'false');
|
||||||
'aria-hidden',
|
|
||||||
hidden ? 'true' : 'false',
|
|
||||||
);
|
|
||||||
// inert removes the subtree from the a11y tree and makes descendants non-focusable
|
// inert removes the subtree from the a11y tree and makes descendants non-focusable
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
mobileMenu.setAttribute('inert', '');
|
mobileMenu.setAttribute('inert', '');
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
// Umami: safe track (no-op if script blocked or not loaded)
|
// Umami: safe track (no-op if script blocked or not loaded)
|
||||||
function umamiTrack(name, data) {
|
function umamiTrack(name, data) {
|
||||||
if (
|
if (typeof window.umami !== 'undefined' && typeof window.umami.track === 'function') {
|
||||||
typeof window.umami !== 'undefined' &&
|
|
||||||
typeof window.umami.track === 'function'
|
|
||||||
) {
|
|
||||||
if (data != null) window.umami.track(name, data);
|
if (data != null) window.umami.track(name, data);
|
||||||
else window.umami.track(name);
|
else window.umami.track(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ describe('cookie-consent.js', () => {
|
|||||||
dom = createBannerDOM();
|
dom = createBannerDOM();
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
});
|
});
|
||||||
@@ -62,7 +61,6 @@ describe('cookie-consent.js', () => {
|
|||||||
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
|
|
||||||
@@ -82,7 +80,6 @@ describe('cookie-consent.js', () => {
|
|||||||
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
const appendChildSpy = vi.spyOn(document.head, 'appendChild');
|
||||||
|
|
||||||
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
const code = readFileSync(SCRIPT_PATH, 'utf8');
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval(code);
|
eval(code);
|
||||||
document.dispatchEvent(new Event('DOMContentLoaded'));
|
document.dispatchEvent(new Event('DOMContentLoaded'));
|
||||||
|
|
||||||
|
|||||||
@@ -140,4 +140,16 @@ test.describe('visual regression', () => {
|
|||||||
await expect(page.locator('#cookie-banner')).not.toBeVisible();
|
await expect(page.locator('#cookie-banner')).not.toBeVisible();
|
||||||
await expect(page).toHaveScreenshot('terms-of-service.png', { fullPage: true });
|
await expect(page).toHaveScreenshot('terms-of-service.png', { fullPage: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('404 page matches snapshot', async ({ page }) => {
|
||||||
|
await page.goto('/404');
|
||||||
|
await expect(page).toHaveTitle(/404 | mifi Ventures/);
|
||||||
|
await expect(page).toHaveScreenshot('404.png', { fullPage: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('410 page matches snapshot', async ({ page }) => {
|
||||||
|
await page.goto('/410');
|
||||||
|
await expect(page).toHaveTitle(/410 | mifi Ventures/);
|
||||||
|
await expect(page).toHaveScreenshot('410.png', { fullPage: true });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
BIN
tests/visual.spec.ts-snapshots/404-chromium-desktop-linux.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
tests/visual.spec.ts-snapshots/404-chromium-mobile-linux.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
tests/visual.spec.ts-snapshots/410-chromium-desktop-linux.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
tests/visual.spec.ts-snapshots/410-chromium-mobile-linux.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 554 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 571 KiB After Width: | Height: | Size: 611 KiB |
|
Before Width: | Height: | Size: 784 KiB After Width: | Height: | Size: 566 KiB |
|
Before Width: | Height: | Size: 801 KiB After Width: | Height: | Size: 845 KiB |
|
Before Width: | Height: | Size: 397 KiB After Width: | Height: | Size: 297 KiB |
|
Before Width: | Height: | Size: 398 KiB After Width: | Height: | Size: 430 KiB |
|
Before Width: | Height: | Size: 805 KiB After Width: | Height: | Size: 583 KiB |
|
Before Width: | Height: | Size: 817 KiB After Width: | Height: | Size: 872 KiB |
|
Before Width: | Height: | Size: 927 KiB After Width: | Height: | Size: 683 KiB |
|
Before Width: | Height: | Size: 941 KiB After Width: | Height: | Size: 1011 KiB |
|
Before Width: | Height: | Size: 703 KiB After Width: | Height: | Size: 544 KiB |
|
Before Width: | Height: | Size: 695 KiB After Width: | Height: | Size: 748 KiB |
|
Before Width: | Height: | Size: 886 KiB After Width: | Height: | Size: 635 KiB |
|
Before Width: | Height: | Size: 891 KiB After Width: | Height: | Size: 961 KiB |
|
Before Width: | Height: | Size: 494 KiB After Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 532 KiB |