271 lines
8.1 KiB
Svelte
271 lines
8.1 KiB
Svelte
<script lang="ts">
|
|
import { page } from '$app/state';
|
|
import { mergeMeta, SEO_DEFAULTS } from '$lib/seo';
|
|
import { homeMeta } from '$lib/data/home/home-meta';
|
|
import Footer from '$lib/components/Footer.svelte';
|
|
|
|
import '../app.css';
|
|
|
|
let { children } = $props();
|
|
|
|
const meta = $derived(page.data?.meta ?? homeMeta);
|
|
const path = $derived(page.url?.pathname ?? '/');
|
|
const merged = $derived(mergeMeta(meta, path));
|
|
|
|
const jsonLdScript = $derived(
|
|
merged.jsonLdGraph.length > 0
|
|
? JSON.stringify({
|
|
'@context': 'https://schema.org',
|
|
'@graph': merged.jsonLdGraph,
|
|
})
|
|
: '',
|
|
);
|
|
|
|
const jsonLdHtml = $derived(
|
|
jsonLdScript
|
|
? '<scr' + 'ipt type="application/ld+json">' + jsonLdScript + '</scr' + 'ipt>'
|
|
: '',
|
|
);
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<script
|
|
defer
|
|
src="https://analytics.mifi.holdings/script.js"
|
|
data-website-id="72ac01ce-e7fc-4582-8593-703f15add8d5"
|
|
></script>
|
|
<script defer src="/assets/js/umami-helper.js"></script>
|
|
|
|
<title>{merged.title}</title>
|
|
<meta name="description" content={merged.description ?? ''} />
|
|
<link rel="canonical" href={merged.canonical} />
|
|
|
|
<link
|
|
rel="preload"
|
|
href="/assets/fonts/fraunces-v38-latin-600.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="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"
|
|
/>
|
|
|
|
<meta
|
|
name="robots"
|
|
content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
|
/>
|
|
<meta name="author" content="Mike Fitzpatrick" />
|
|
<meta name="geo.region" content="US-MA" />
|
|
<meta name="geo.placename" content="Boston" />
|
|
<meta name="geo.position" content="42.360082;-71.058880" />
|
|
<meta name="ICBM" content="42.360082, -71.058880" />
|
|
|
|
<meta
|
|
name="theme-color"
|
|
content={SEO_DEFAULTS.themeColorLight}
|
|
media="(prefers-color-scheme: light)"
|
|
/>
|
|
<meta
|
|
name="theme-color"
|
|
content={SEO_DEFAULTS.themeColorDark}
|
|
media="(prefers-color-scheme: dark)"
|
|
/>
|
|
|
|
<meta property="og:type" content={merged.ogType ?? 'website'} />
|
|
<meta property="og:url" content={merged.canonical} />
|
|
<meta property="og:site_name" content={SEO_DEFAULTS.siteName} />
|
|
<meta property="og:title" content={merged.twitterTitle ?? merged.title} />
|
|
<meta
|
|
property="og:description"
|
|
content={merged.twitterDescription ?? merged.description ?? ''}
|
|
/>
|
|
<meta property="og:image" content={merged.ogImage} />
|
|
<meta property="og:image:width" content={String(SEO_DEFAULTS.ogImageWidth)} />
|
|
<meta property="og:image:height" content={String(SEO_DEFAULTS.ogImageHeight)} />
|
|
<meta property="og:image:alt" content={merged.ogImageAlt} />
|
|
<meta property="og:locale" content={SEO_DEFAULTS.locale} />
|
|
|
|
<meta name="twitter:card" content={SEO_DEFAULTS.twitterCard} />
|
|
<meta name="twitter:url" content={merged.canonical} />
|
|
<meta name="twitter:title" content={merged.twitterTitle ?? merged.title} />
|
|
<meta
|
|
name="twitter:description"
|
|
content={merged.twitterDescription ?? merged.description ?? ''}
|
|
/>
|
|
<meta name="twitter:image" content={merged.ogImage} />
|
|
<meta name="twitter:image:alt" content={merged.ogImageAlt} />
|
|
|
|
<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/apple-touch-icon.png" />
|
|
|
|
{#if jsonLdHtml}
|
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -- static trusted JSON-LD -->
|
|
{@html jsonLdHtml}
|
|
{/if}
|
|
|
|
<script src="/assets/js/copyright-year.js" defer></script>
|
|
<script src="/assets/js/mobile-menu-helper.js" defer></script>
|
|
<script src="/assets/js/cookie-consent.js" defer></script>
|
|
</svelte:head>
|
|
|
|
<a href="#main" class="skip-link" data-umami-event="skip to main content"
|
|
>Skip to main content</a
|
|
>
|
|
{@render children()}
|
|
<Footer />
|
|
<div id="cookie-banner" class="cookie-banner" role="region" aria-label="Cookie consent">
|
|
<div class="cookie-banner-content">
|
|
<p class="cookie-notification-text">
|
|
We use first-party analytics and, if you accept, third-party tools (e.g.
|
|
Google, Microsoft) to understand usage and improve this site. You can accept
|
|
all or reject non-essential analytics.
|
|
<a href="/privacy-policy#analytics-and-tracking">Learn more</a>.
|
|
</p>
|
|
<div class="cookie-banner-actions">
|
|
<button type="button" class="btn btn-primary small" data-consent="accept"
|
|
>Accept all</button
|
|
>
|
|
<button type="button" class="btn btn-secondary small" data-consent="reject"
|
|
>Reject non-essential</button
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<img
|
|
src="https://analytics.mifi.holdings/p/wQ9GYnLIg"
|
|
alt=""
|
|
width="1"
|
|
height="1"
|
|
role="presentation"
|
|
loading="eager"
|
|
/>
|
|
|
|
<style>
|
|
.cookie-banner {
|
|
position: fixed;
|
|
inset-inline: 0;
|
|
bottom: 0;
|
|
z-index: 1000;
|
|
display: none;
|
|
background-color: var(--color-bg-elevated, var(--color-bg));
|
|
color: var(--color-text);
|
|
border-top: 1px solid var(--color-border);
|
|
box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.16);
|
|
|
|
&:global(.is-visible) {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
.cookie-banner-content {
|
|
container: cookie-banner / inline-size;
|
|
max-width: var(--max-narrow-width);
|
|
margin: 0 auto;
|
|
padding: var(--space-md) var(--space-md);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-sm);
|
|
|
|
@media (min-width: 768px) {
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
}
|
|
|
|
.cookie-notification-text {
|
|
margin: 0;
|
|
font-size: var(--font-size-small);
|
|
line-height: var(--line-height-base);
|
|
|
|
@container cookie-banner (width >= 644px) {
|
|
flex: 1 1 auto;
|
|
}
|
|
|
|
@container cookie-banner (width < 644px) {
|
|
flex: 0 0 100%;
|
|
text-align: center;
|
|
width: 100%;
|
|
}
|
|
|
|
& a {
|
|
color: var(--color-primary);
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.16em;
|
|
|
|
&:hover {
|
|
color: var(--color-primary-hover);
|
|
}
|
|
}
|
|
}
|
|
|
|
.cookie-banner-actions {
|
|
display: flex;
|
|
flex-flow: column nowrap;
|
|
justify-content: flex-start;
|
|
|
|
@container cookie-banner (width >= 644px) {
|
|
flex: 0 0 auto;
|
|
gap: var(--space-xs);
|
|
}
|
|
|
|
@container cookie-banner (width < 644px) {
|
|
flex: 0 0 100%;
|
|
gap: var(--space-sm);
|
|
justify-content: center;
|
|
width: 100%;
|
|
|
|
& .btn {
|
|
max-width: 100%;
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
& [data-consent='accept'] {
|
|
background-color: var(--color-primary);
|
|
color: var(--color-bg);
|
|
|
|
&:hover {
|
|
background-color: var(--color-primary-hover);
|
|
}
|
|
}
|
|
|
|
& [data-consent='reject'] {
|
|
background-color: transparent;
|
|
color: var(--color-text);
|
|
border-color: var(--color-primary);
|
|
|
|
&:hover {
|
|
background-color: var(--color-surface-subtle, rgba(148, 163, 184, 0.16));
|
|
}
|
|
}
|
|
}
|
|
</style>
|