Tweaks, fixes, and launch prep

This commit is contained in:
2026-02-06 19:09:48 -03:00
parent 22b21d254c
commit 2959360d65
34 changed files with 496 additions and 81 deletions

View File

@@ -3,12 +3,10 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="preload" href="/assets/js/theme-store.js" as="script" />
<title>mifi.dev</title>
<script src="/assets/js/theme-store.js"></script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<script src="/assets/js/theme-store.js"></script>
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import { onMount } from 'svelte';
import { Moon, SunMoon, Sun } from '@lucide/svelte';
import { getStoredTheme, setTheme } from '$lib/theme';
import type { ThemeMode } from '$lib/theme';
@@ -18,7 +17,8 @@
const themeOffset = $derived(OFFSETS[current]);
onMount(() => {
$effect(() => {
if (typeof document === 'undefined') return;
current = getStoredTheme();
});

View File

@@ -19,6 +19,12 @@ export const GA_MEASUREMENT_IDS: Record<'dev' | 'bio', string> = {
bio: 'G-885B0KYWZ1',
};
/** theme-color meta values per variant (match tokens-{variant}.css --color-bg) */
export const THEME_COLORS: Record<'dev' | 'bio', { light: string; dark: string }> = {
dev: { light: '#f5f4f8', dark: '#131118' }, // hsl(260 20% 98%) / hsl(260 18% 8%)
bio: { light: '#f4f6f9', dark: '#111318' }, // hsl(220 22% 98%) / hsl(220 18% 8%)
};
export const UTM_MEDIUM = 'link';
export const UTM_CAMPAIGN = 'landing';

View File

@@ -17,14 +17,6 @@
font-display: swap;
}
@font-face {
font-family: 'Plus Jakarta Sans';
src: url('/assets/fonts/plus-jakarta-sans-v12-latin-500.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Plus Jakarta Sans';
src: url('/assets/fonts/plus-jakarta-sans-v12-latin-regular.woff2') format('woff2');
@@ -49,19 +41,3 @@
font-style: normal;
font-display: swap;
}
@font-face {
font-family: Inter;
src: url('/assets/fonts/inter-v20-latin-500.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: Inter;
src: url('/assets/fonts/inter-v20-latin-600.woff2') format('woff2');
font-weight: 600;
font-style: normal;
font-display: swap;
}

View File

@@ -1,5 +1,5 @@
import contentData from '$lib/data/links.json';
import { VARIANT_HOSTS, GA_MEASUREMENT_IDS } from '$lib/config';
import { VARIANT_HOSTS, GA_MEASUREMENT_IDS, THEME_COLORS } from '$lib/config';
import type { Site, ContentData, ProcessedLink } from '$lib/data/types';
import type { LayoutServerLoad } from './$types';
import { ContentVariant, HeroLayout } from '$lib/data/constants';
@@ -18,6 +18,9 @@ export type LayoutServerDataOut = {
};
variant: string;
gaMeasurementId: string;
/** theme-color meta values for current variant */
themeColorLight: string;
themeColorDark: string;
};
export const load: LayoutServerLoad<LayoutServerDataOut> = (): LayoutServerDataOut => {
@@ -58,11 +61,14 @@ export const load: LayoutServerLoad<LayoutServerDataOut> = (): LayoutServerDataO
contactLinks: siteDef?.contactLinks,
qrCodeImage: siteDef?.qrCodeImage ?? undefined,
};
const themeColors = THEME_COLORS[variant];
return {
site,
contactLinks,
links: { sections },
variant,
gaMeasurementId: GA_MEASUREMENT_IDS[variant],
themeColorLight: themeColors.light,
themeColorDark: themeColors.dark,
};
};

View File

@@ -1,37 +1,82 @@
<script lang="ts">
import '../app.css';
import type { Snippet } from 'svelte';
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
import type { LayoutData } from './$types';
export let data: LayoutData;
import '../app.css';
const jsonLd = {
let { children, data }: { children: Snippet; data: LayoutData } = $props();
const jsonLd = $derived({
'@context': 'https://schema.org',
'@type': 'WebSite' as const,
name: data.site.title,
url: data.site.url,
description: data.site.metaDescription,
};
});
$: personLd = data.site.person
? {
'@context': 'https://schema.org' as const,
'@type': 'Person' as const,
name: data.site.person.name,
url: data.site.url,
sameAs: data.site.person.sameAs,
}
: null;
const personLd = $derived(
data.site.person
? {
'@context': 'https://schema.org' as const,
'@type': 'Person' as const,
name: data.site.person.name,
url: data.site.url,
sameAs: data.site.person.sameAs,
}
: null
);
// Inject as HTML to avoid Prettier parsing ld+json script body as JS (Babel syntax error)
const ldJsonTag = (payload: string) =>
'<' + 'script type="application/ld+json">' + payload + '<' + '/script>';
$: jsonLdHtml = ldJsonTag(JSON.stringify(jsonLd));
$: personLdHtml = personLd != null ? ldJsonTag(JSON.stringify(personLd)) : '';
const jsonLdHtml = $derived(ldJsonTag(JSON.stringify(jsonLd)));
const personLdHtml = $derived(
personLd != null ? ldJsonTag(JSON.stringify(personLd)) : ''
);
</script>
<svelte:head>
<link rel="stylesheet" href="/assets/tokens-{data.variant}.css" />
<link
rel="preload"
href="/assets/fonts/fraunces-variable-opsz-wght.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<link
rel="preload"
href="/assets/fonts/plus-jakarta-sans-v12-latin-700.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<link
rel="preload"
href="/assets/fonts/plus-jakarta-sans-v12-latin-regular.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<link
rel="preload"
href="/assets/fonts/inter-v20-latin-regular.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/apple-touch-icon.png" />
<meta name="color-scheme" content="light dark" />
<meta name="theme-color" content={data.themeColorLight} media="(prefers-color-scheme: light)" />
<meta name="theme-color" content={data.themeColorDark} media="(prefers-color-scheme: dark)" />
<!-- eslint-disable-next-line svelte/no-at-html-tags -- safe: our own JSON.stringify, no user input -->
{@html jsonLdHtml}
{#if personLdHtml}
@@ -44,4 +89,4 @@
<header class="site-header">
<ThemeToggle />
</header>
<slot />
{@render children()}

View File

@@ -1 +1,2 @@
export const prerender = true;
export const ssr = true;

View File

@@ -22,6 +22,30 @@
<svelte:head>
<title>{data.site.title}</title>
<meta name="description" content={data.site.metaDescription} />
<link rel="canonical" href={data.site.url} />
<meta name="robots" content="index, follow" />
{#if data.site.person?.name}
<meta name="author" content={data.site.person.name} />
{/if}
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={data.site.title} />
<meta property="og:description" content={data.site.metaDescription} />
<meta property="og:url" content={data.site.url} />
<meta property="og:site_name" content={data.site.title} />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="{data.site.url}/assets/images/mifi-{data.variant}-og-image.webp" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={data.site.title} />
<meta name="twitter:description" content={data.site.metaDescription} />
<meta name="twitter:image" content="{data.site.url}/assets/images/mifi-{data.variant}-twitter-image.webp" />
<meta name="twitter:image:width" content="1200" />
<meta name="twitter:image:height" content="1200" />
</svelte:head>
<main id="main-content">