diff --git a/src/app.css b/src/app.css index e34c97c..1b33d34 100644 --- a/src/app.css +++ b/src/app.css @@ -476,6 +476,55 @@ a { } } +/* ======================================== + Nav Item and Footer Links Common Styles + ======================================== */ + +.footer-links, +.nav-item { + display: flex; + gap: var(--space-lg); + justify-content: center; + align-items: center; + + @media (max-width: 480px) { + gap: var(--space-md); + } + + & a { + font-size: var(--font-size-medium); + font-weight: var(--font-weight-medium); + color: var(--color-text-secondary); + text-decoration: none; + transition: color var(--transition-fast); + border-bottom: 1px solid transparent; + padding: var(--space-xs) var(--space-sm); + margin: calc(-1 * var(--space-xs)) calc(-1 * var(--space-sm)); + min-height: 44px; + display: inline-flex; + align-items: center; + + &:hover { + color: var(--color-primary); + border-bottom-color: var(--color-primary); + } + + &:focus-visible { + outline: 4px solid var(--color-focus); + outline-offset: 4px; + border-bottom-color: transparent; + box-shadow: 0 0 0 8px var(--color-focus-outline); + border-radius: 3px; + } + + @media print { + &:after { + content: none; + } + } + } +} + /* ======================================== Responsive Design ======================================== */ diff --git a/src/lib/components/Footer.svelte b/src/lib/components/Footer.svelte index 2425493..fe1d614 100644 --- a/src/lib/components/Footer.svelte +++ b/src/lib/components/Footer.svelte @@ -35,48 +35,4 @@ color: var(--color-text-tertiary); max-width: 100%; } - - .footer-links { - display: flex; - gap: var(--space-lg); - justify-content: center; - align-items: center; - - @media (max-width: 480px) { - gap: var(--space-md); - } - - & a { - font-size: var(--font-size-medium); - font-weight: var(--font-weight-medium); - color: var(--color-text-secondary); - text-decoration: none; - transition: color var(--transition-fast); - border-bottom: 1px solid transparent; - padding: var(--space-xs) var(--space-sm); - margin: calc(-1 * var(--space-xs)) calc(-1 * var(--space-sm)); - min-height: 44px; - display: inline-flex; - align-items: center; - - &:hover { - color: var(--color-primary); - border-bottom-color: var(--color-primary); - } - - &:focus-visible { - outline: 4px solid var(--color-focus); - outline-offset: 4px; - border-bottom-color: transparent; - box-shadow: 0 0 0 8px var(--color-focus-outline); - border-radius: 3px; - } - - @media print { - &:after { - content: none; - } - } - } - } diff --git a/src/lib/components/Navigation.svelte b/src/lib/components/Navigation.svelte new file mode 100644 index 0000000..c742583 --- /dev/null +++ b/src/lib/components/Navigation.svelte @@ -0,0 +1,319 @@ + + + + + diff --git a/src/lib/copyright-year.test.ts b/src/lib/copyright-year.test.ts index e6dd3b2..9d64a6f 100644 --- a/src/lib/copyright-year.test.ts +++ b/src/lib/copyright-year.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'; import { getCurrentYear } from './copyright-year'; describe('getCurrentYear', () => { - it('returns the current calendar year', () => { - expect(getCurrentYear()).toBe(new Date().getFullYear()); - }); + it('returns the current calendar year', () => { + expect(getCurrentYear()).toBe(new Date().getFullYear()); + }); }); diff --git a/src/lib/copyright-year.ts b/src/lib/copyright-year.ts index 7d7573f..8a02ced 100644 --- a/src/lib/copyright-year.ts +++ b/src/lib/copyright-year.ts @@ -3,5 +3,5 @@ * The client-side footer year is updated by static/copyright-year.js. */ export function getCurrentYear(): number { - return new Date().getFullYear(); + return new Date().getFullYear(); } diff --git a/src/lib/data/content.ts b/src/lib/data/content.ts index cef25ec..707f629 100644 --- a/src/lib/data/content.ts +++ b/src/lib/data/content.ts @@ -1,26 +1,26 @@ export const whatWeDoItems = [ - 'Product-focused frontend and UI architecture for modern web applications, with an emphasis on clarity, scalability, and long-term maintainability.', - 'Greenfield product builds and early-stage foundations, getting new projects off the ground quickly with structures designed to grow, not be rewritten.', - 'Performance, Core Web Vitals, rendering strategy, and technical SEO optimization focused on real-world user journeys—not just lab scores.', - 'Accessibility-first engineering, ensuring WCAG-compliant interfaces with semantic markup, keyboard parity, and inclusive interaction patterns.', - 'Modernization and stabilization of existing systems, including refactors, framework upgrades, and untangling overgrown frontend codebases.', - 'End-to-end feature delivery with clear ownership and documentation, spanning frontend and supporting backend work without unnecessary complexity.', + 'Product-focused frontend and UI architecture for modern web applications, with an emphasis on clarity, scalability, and long-term maintainability.', + 'Greenfield product builds and early-stage foundations, getting new projects off the ground quickly with structures designed to grow, not be rewritten.', + 'Performance, Core Web Vitals, rendering strategy, and technical SEO optimization focused on real-world user journeys—not just lab scores.', + 'Accessibility-first engineering, ensuring WCAG-compliant interfaces with semantic markup, keyboard parity, and inclusive interaction patterns.', + 'Modernization and stabilization of existing systems, including refactors, framework upgrades, and untangling overgrown frontend codebases.', + 'End-to-end feature delivery with clear ownership and documentation, spanning frontend and supporting backend work without unnecessary complexity.', ]; export const impactItems = [ - 'Get new products off the ground quickly by establishing durable frontend and platform foundations—clean architecture, clear patterns, and pragmatic defaults designed to scale with teams and traffic.', - 'Improve performance, Core Web Vitals, and technical SEO on high-traffic user journeys through rendering strategy, bundle discipline, and careful attention to real-world loading behavior.', - 'Build accessibility into core UI systems, not as a retrofit—semantic markup, keyboard parity, and screen reader support baked into reusable components and design patterns.', - 'Bring order to complex or aging codebases by simplifying structure, reducing duplication, and clarifying ownership, enabling teams to ship confidently without over-engineering.', - 'Design and evolve shared component libraries and UI systems that improve consistency, velocity, and long-term maintainability across multiple teams.', - 'Partner closely with product, design, and engineering leadership (including marketing teams and non-technical organizations) to translate goals into shippable systems, balancing speed, quality, and technical risk.', + 'Get new products off the ground quickly by establishing durable frontend and platform foundations—clean architecture, clear patterns, and pragmatic defaults designed to scale with teams and traffic.', + 'Improve performance, Core Web Vitals, and technical SEO on high-traffic user journeys through rendering strategy, bundle discipline, and careful attention to real-world loading behavior.', + 'Build accessibility into core UI systems, not as a retrofit—semantic markup, keyboard parity, and screen reader support baked into reusable components and design patterns.', + 'Bring order to complex or aging codebases by simplifying structure, reducing duplication, and clarifying ownership, enabling teams to ship confidently without over-engineering.', + 'Design and evolve shared component libraries and UI systems that improve consistency, velocity, and long-term maintainability across multiple teams.', + 'Partner closely with product, design, and engineering leadership (including marketing teams and non-technical organizations) to translate goals into shippable systems, balancing speed, quality, and technical risk.', ]; export const howWeWorkItems = [ - 'Engagements are consulting-led and senior-driven. I work directly with founders, product leaders, marketing teams, and engineering teams—including organizations without in-house technical staff—to establish direction and deliver solutions with a high degree of autonomy.', - 'Focused, pragmatic scope. Work is scoped to deliver real progress quickly, with an emphasis on building the right foundation rather than over-engineering for hypothetical futures.', - 'Async-friendly, low-friction communication. Clear written updates, documented decisions, and scheduled calls when they add value—not meetings for their own sake.', - 'Quality as a default. Accessibility, performance, and maintainability are built into the work from the start, not added later as cleanup.', - "Flexible engagement models. Hourly or fixed-scope work depending on clarity and needs; longer-term engagements welcome when there's ongoing product momentum.", - 'Clean handoff. Code, documentation, and context are left in a state where internal teams—or future vendors—can confidently extend the work without dependency.', + 'Engagements are consulting-led and senior-driven. I work directly with founders, product leaders, marketing teams, and engineering teams—including organizations without in-house technical staff—to establish direction and deliver solutions with a high degree of autonomy.', + 'Focused, pragmatic scope. Work is scoped to deliver real progress quickly, with an emphasis on building the right foundation rather than over-engineering for hypothetical futures.', + 'Async-friendly, low-friction communication. Clear written updates, documented decisions, and scheduled calls when they add value—not meetings for their own sake.', + 'Quality as a default. Accessibility, performance, and maintainability are built into the work from the start, not added later as cleanup.', + "Flexible engagement models. Hourly or fixed-scope work depending on clarity and needs; longer-term engagements welcome when there's ongoing product momentum.", + 'Clean handoff. Code, documentation, and context are left in a state where internal teams—or future vendors—can confidently extend the work without dependency.', ]; diff --git a/src/lib/data/engagements.ts b/src/lib/data/engagements.ts index f8b498b..a9c1577 100644 --- a/src/lib/data/engagements.ts +++ b/src/lib/data/engagements.ts @@ -1,27 +1,27 @@ export const engagements = [ - { - title: 'Atlassian — Senior UI Engineer (Enterprise SaaS)', - description: - 'Frontend architecture and feature delivery for Confluence integrations, including React 18 migration work and standardizing end-to-end testing practices.', - }, - { - title: 'CarGurus — Principal UI Engineer (Consumer Marketplace)', - description: - 'Built and maintained high-traffic frontend systems, improved Core Web Vitals and technical SEO, and developed shared UI platforms used across teams.', - }, - { - title: 'The TJX Companies (TJ Maxx) — UI Engineer (Enterprise Retail)', - description: - 'Delivered UX improvements for large-scale e-commerce experiences in close partnership with design, QA, and product teams.', - }, - { - title: 'Timberland — Senior Interactive Developer (Global Ecommerce)', - description: - 'Led global web initiatives across brand and e-commerce platforms, acting as a technical bridge between marketing, design, and engineering.', - }, - { - title: 'MFA Boston — Pro Bono Technical Lead (Nonprofit / Fundraising)', - description: - "Designed and built a custom auction application for the MFA's annual Young Patrons fundraiser; subsequently iterated on and supported the platform over multiple years as the event grew, until it concluded during the pandemic.", - }, + { + title: 'Atlassian — Senior UI Engineer (Enterprise SaaS)', + description: + 'Frontend architecture and feature delivery for Confluence integrations, including React 18 migration work and standardizing end-to-end testing practices.', + }, + { + title: 'CarGurus — Principal UI Engineer (Consumer Marketplace)', + description: + 'Built and maintained high-traffic frontend systems, improved Core Web Vitals and technical SEO, and developed shared UI platforms used across teams.', + }, + { + title: 'The TJX Companies (TJ Maxx) — UI Engineer (Enterprise Retail)', + description: + 'Delivered UX improvements for large-scale e-commerce experiences in close partnership with design, QA, and product teams.', + }, + { + title: 'Timberland — Senior Interactive Developer (Global Ecommerce)', + description: + 'Led global web initiatives across brand and e-commerce platforms, acting as a technical bridge between marketing, design, and engineering.', + }, + { + title: 'MFA Boston — Pro Bono Technical Lead (Nonprofit / Fundraising)', + description: + "Designed and built a custom auction application for the MFA's annual Young Patrons fundraiser; subsequently iterated on and supported the platform over multiple years as the event grew, until it concluded during the pandemic.", + }, ]; diff --git a/src/lib/data/experience.ts b/src/lib/data/experience.ts index 05075a6..5772f79 100644 --- a/src/lib/data/experience.ts +++ b/src/lib/data/experience.ts @@ -1,26 +1,26 @@ export const experienceLogos = [ - { src: '/assets/logos/atlassian.svg', alt: 'Atlassian', width: 2500, height: 2500 }, - { - src: '/assets/logos/tjx.svg', - alt: 'TJ Maxx (The TJX Companies)', - width: 2500, - height: 621, - }, - { src: '/assets/logos/cargurus.svg', alt: 'CarGurus', width: 2500, height: 398 }, - { src: '/assets/logos/timberland.svg', alt: 'Timberland', width: 190, height: 35 }, - { src: '/assets/logos/vf.svg', alt: 'VF Corporation', width: 190, height: 155 }, - { - src: '/assets/logos/bottomline.svg', - alt: 'Bottomline Technologies', - width: 2702, - height: 571, - }, - { - src: '/assets/logos/mfa-boston.svg', - alt: 'Museum of Fine Arts Boston', - width: 572, - height: 88, - }, + { src: '/assets/logos/atlassian.svg', alt: 'Atlassian', width: 2500, height: 2500 }, + { + src: '/assets/logos/tjx.svg', + alt: 'TJ Maxx (The TJX Companies)', + width: 2500, + height: 621, + }, + { src: '/assets/logos/cargurus.svg', alt: 'CarGurus', width: 2500, height: 398 }, + { src: '/assets/logos/timberland.svg', alt: 'Timberland', width: 190, height: 35 }, + { src: '/assets/logos/vf.svg', alt: 'VF Corporation', width: 190, height: 155 }, + { + src: '/assets/logos/bottomline.svg', + alt: 'Bottomline Technologies', + width: 2702, + height: 571, + }, + { + src: '/assets/logos/mfa-boston.svg', + alt: 'Museum of Fine Arts Boston', + width: 572, + height: 88, + }, ] as const; export const experienceTextList = experienceLogos.map((l) => l.alt); diff --git a/src/lib/data/home-meta.ts b/src/lib/data/home-meta.ts index 99efa5e..add04a4 100644 --- a/src/lib/data/home-meta.ts +++ b/src/lib/data/home-meta.ts @@ -2,8 +2,8 @@ import type { PageMeta } from '$lib/seo'; import { defaultJsonLdGraph } from './json-ld'; export const homeMeta: PageMeta = { - title: 'mifi Ventures — Software Engineering Consulting | Boston, MA', - description: - 'Boston-based software engineering consulting. Mike Fitzpatrick helps teams build reliable, accessible, high-performance web applications. Specializing in frontend architecture, performance optimization, and modern web development.', - jsonLd: defaultJsonLdGraph, + title: 'mifi Ventures — Software Engineering Consulting | Boston, MA', + description: + 'Boston-based software engineering consulting. Mike Fitzpatrick helps teams build reliable, accessible, high-performance web applications. Specializing in frontend architecture, performance optimization, and modern web development.', + jsonLd: defaultJsonLdGraph, }; diff --git a/src/lib/data/json-ld.ts b/src/lib/data/json-ld.ts index e78221f..ff31353 100644 --- a/src/lib/data/json-ld.ts +++ b/src/lib/data/json-ld.ts @@ -6,145 +6,145 @@ const BASE = 'https://mifi.ventures'; export const defaultJsonLdGraph: Record[] = [ - { - '@type': 'Organization', - '@id': `${BASE}/#organization`, - name: 'mifi Ventures, LLC', - legalName: 'mifi Ventures, LLC', - url: `${BASE}/`, - logo: { '@type': 'ImageObject', url: `${BASE}/favicon.svg` }, - description: - 'Software engineering consulting specializing in product-focused frontend architecture, performance optimization, and accessibility-first engineering.', - founder: { '@id': `${BASE}/#principal` }, - address: { - '@type': 'PostalAddress', - addressLocality: 'Boston', - addressRegion: 'MA', - addressCountry: 'US', + { + '@type': 'Organization', + '@id': `${BASE}/#organization`, + name: 'mifi Ventures, LLC', + legalName: 'mifi Ventures, LLC', + url: `${BASE}/`, + logo: { '@type': 'ImageObject', url: `${BASE}/favicon.svg` }, + description: + 'Software engineering consulting specializing in product-focused frontend architecture, performance optimization, and accessibility-first engineering.', + founder: { '@id': `${BASE}/#principal` }, + address: { + '@type': 'PostalAddress', + addressLocality: 'Boston', + addressRegion: 'MA', + addressCountry: 'US', + }, + geo: { '@type': 'GeoCoordinates', latitude: 42.360082, longitude: -71.05888 }, + areaServed: { '@type': 'Country', name: 'United States' }, + hasOfferCatalog: { '@id': `${BASE}/#services` }, + sameAs: ['https://www.linkedin.com/in/the-mifi', 'https://github.com/the-mifi'], }, - geo: { '@type': 'GeoCoordinates', latitude: 42.360082, longitude: -71.05888 }, - areaServed: { '@type': 'Country', name: 'United States' }, - hasOfferCatalog: { '@id': `${BASE}/#services` }, - sameAs: ['https://www.linkedin.com/in/the-mifi', 'https://github.com/the-mifi'], - }, - { - '@type': 'Person', - '@id': `${BASE}/#principal`, - name: 'Mike Fitzpatrick', - jobTitle: 'Principal Software Engineer and Architect', - description: - 'Senior full-stack engineer and architect helping teams ship reliable, accessible, high-performance web products.', - url: `${BASE}/`, - worksFor: { '@id': `${BASE}/#organization` }, - knowsAbout: [ - 'Frontend Architecture', - 'UI Architecture', - 'React Development', - 'Web Performance Optimization', - 'Core Web Vitals', - 'Technical SEO', - 'Web Accessibility (WCAG)', - 'Component Libraries', - 'Design Systems', - 'JavaScript', - 'TypeScript', - 'Modern Web Development', - 'Greenfield Product Development', - 'Legacy System Modernization', - 'Code Refactoring', - ], - sameAs: ['https://www.linkedin.com/in/the-mifi', 'https://github.com/the-mifi'], - }, - { - '@type': 'WebSite', - '@id': `${BASE}/#website`, - url: `${BASE}/`, - name: 'mifi Ventures', - description: 'Software Engineering Consulting — Boston, MA', - publisher: { '@id': `${BASE}/#organization` }, - potentialAction: { - '@type': 'ReserveAction', - target: { - '@type': 'EntryPoint', - urlTemplate: 'https://cal.mifi.ventures/the-mifi', - }, - name: 'Schedule a 30-minute intro call', + { + '@type': 'Person', + '@id': `${BASE}/#principal`, + name: 'Mike Fitzpatrick', + jobTitle: 'Principal Software Engineer and Architect', + description: + 'Senior full-stack engineer and architect helping teams ship reliable, accessible, high-performance web products.', + url: `${BASE}/`, + worksFor: { '@id': `${BASE}/#organization` }, + knowsAbout: [ + 'Frontend Architecture', + 'UI Architecture', + 'React Development', + 'Web Performance Optimization', + 'Core Web Vitals', + 'Technical SEO', + 'Web Accessibility (WCAG)', + 'Component Libraries', + 'Design Systems', + 'JavaScript', + 'TypeScript', + 'Modern Web Development', + 'Greenfield Product Development', + 'Legacy System Modernization', + 'Code Refactoring', + ], + sameAs: ['https://www.linkedin.com/in/the-mifi', 'https://github.com/the-mifi'], }, - }, - { - '@type': 'WebPage', - '@id': `${BASE}/#webpage`, - url: `${BASE}/`, - name: 'mifi Ventures — Software Engineering Consulting | Boston, MA', - description: - 'Boston-based software engineering consulting. Mike Fitzpatrick helps teams build reliable, accessible, high-performance web applications.', - isPartOf: { '@id': `${BASE}/#website` }, - about: { '@id': `${BASE}/#organization` }, - mainEntity: { '@id': `${BASE}/#organization` }, - primaryImageOfPage: { '@type': 'ImageObject', url: `${BASE}/favicon.svg` }, - inLanguage: 'en-US', - }, - { - '@type': 'OfferCatalog', - '@id': `${BASE}/#services`, - name: 'Software Engineering Consulting Services', - description: 'Consulting services offered by mifi Ventures', - numberOfItems: 6, - itemListElement: [ - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'Frontend and UI Architecture', - description: - 'Product-focused frontend and UI architecture for modern web applications, with an emphasis on clarity, scalability, and long-term maintainability.', + { + '@type': 'WebSite', + '@id': `${BASE}/#website`, + url: `${BASE}/`, + name: 'mifi Ventures', + description: 'Software Engineering Consulting — Boston, MA', + publisher: { '@id': `${BASE}/#organization` }, + potentialAction: { + '@type': 'ReserveAction', + target: { + '@type': 'EntryPoint', + urlTemplate: 'https://cal.mifi.ventures/the-mifi', + }, + name: 'Schedule a 30-minute intro call', }, - }, - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'Greenfield Product Development', - description: - 'Greenfield product builds and early-stage foundations, getting new projects off the ground quickly with structures designed to grow, not be rewritten.', - }, - }, - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'Performance Optimization', - description: - 'Performance, Core Web Vitals, rendering strategy, and technical SEO optimization focused on real-world user journeys.', - }, - }, - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'Accessibility Engineering', - description: - 'Accessibility-first engineering, ensuring WCAG-compliant interfaces with semantic markup, keyboard parity, and inclusive interaction patterns.', - }, - }, - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'System Modernization', - description: - 'Modernization and stabilization of existing systems, including refactors, framework upgrades, and untangling overgrown frontend codebases.', - }, - }, - { - '@type': 'Offer', - itemOffered: { - '@type': 'Service', - name: 'End-to-End Feature Delivery', - description: - 'End-to-end feature delivery with clear ownership and documentation, spanning frontend and supporting backend work without unnecessary complexity.', - }, - }, - ], - }, + }, + { + '@type': 'WebPage', + '@id': `${BASE}/#webpage`, + url: `${BASE}/`, + name: 'mifi Ventures — Software Engineering Consulting | Boston, MA', + description: + 'Boston-based software engineering consulting. Mike Fitzpatrick helps teams build reliable, accessible, high-performance web applications.', + isPartOf: { '@id': `${BASE}/#website` }, + about: { '@id': `${BASE}/#organization` }, + mainEntity: { '@id': `${BASE}/#organization` }, + primaryImageOfPage: { '@type': 'ImageObject', url: `${BASE}/favicon.svg` }, + inLanguage: 'en-US', + }, + { + '@type': 'OfferCatalog', + '@id': `${BASE}/#services`, + name: 'Software Engineering Consulting Services', + description: 'Consulting services offered by mifi Ventures', + numberOfItems: 6, + itemListElement: [ + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'Frontend and UI Architecture', + description: + 'Product-focused frontend and UI architecture for modern web applications, with an emphasis on clarity, scalability, and long-term maintainability.', + }, + }, + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'Greenfield Product Development', + description: + 'Greenfield product builds and early-stage foundations, getting new projects off the ground quickly with structures designed to grow, not be rewritten.', + }, + }, + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'Performance Optimization', + description: + 'Performance, Core Web Vitals, rendering strategy, and technical SEO optimization focused on real-world user journeys.', + }, + }, + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'Accessibility Engineering', + description: + 'Accessibility-first engineering, ensuring WCAG-compliant interfaces with semantic markup, keyboard parity, and inclusive interaction patterns.', + }, + }, + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'System Modernization', + description: + 'Modernization and stabilization of existing systems, including refactors, framework upgrades, and untangling overgrown frontend codebases.', + }, + }, + { + '@type': 'Offer', + itemOffered: { + '@type': 'Service', + name: 'End-to-End Feature Delivery', + description: + 'End-to-end feature delivery with clear ownership and documentation, spanning frontend and supporting backend work without unnecessary complexity.', + }, + }, + ], + }, ]; diff --git a/src/lib/seo.ts b/src/lib/seo.ts index 3292f12..fc45c26 100644 --- a/src/lib/seo.ts +++ b/src/lib/seo.ts @@ -4,50 +4,50 @@ */ export const SEO_DEFAULTS = { - siteName: 'mifi Ventures', - baseUrl: 'https://mifi.ventures', - defaultOgImage: '/assets/og-image.png', - ogImageWidth: 1200, - ogImageHeight: 630, - locale: 'en_US', - twitterCard: 'summary_large_image' as const, - themeColorLight: '#0052cc', - themeColorDark: '#4da6ff', + siteName: 'mifi Ventures', + baseUrl: 'https://mifi.ventures', + defaultOgImage: '/assets/og-image.png', + ogImageWidth: 1200, + ogImageHeight: 630, + locale: 'en_US', + twitterCard: 'summary_large_image' as const, + themeColorLight: '#0052cc', + themeColorDark: '#4da6ff', } as const; export interface PageMeta { - title: string; - description?: string; - canonical?: string; - ogImage?: string; - ogType?: string; - twitterTitle?: string; - twitterDescription?: string; - /** JSON-LD graph nodes (merged with defaults in layout) */ - jsonLd?: Record[]; + title: string; + description?: string; + canonical?: string; + ogImage?: string; + ogType?: string; + twitterTitle?: string; + twitterDescription?: string; + /** JSON-LD graph nodes (merged with defaults in layout) */ + jsonLd?: Record[]; } export interface MergedMeta extends PageMeta { - canonical: string; - ogImage: string; - ogImageAlt: string; - jsonLdGraph: Record[]; + canonical: string; + ogImage: string; + ogImageAlt: string; + jsonLdGraph: Record[]; } /** Merge page meta with site defaults for rendering. */ export function mergeMeta(meta: PageMeta, path: string = '/'): MergedMeta { - const baseUrl = SEO_DEFAULTS.baseUrl; - const canonical = meta.canonical ?? `${baseUrl}${path === '/' ? '' : path}`; - const ogImage = meta.ogImage?.startsWith('http') - ? meta.ogImage - : `${baseUrl}${meta.ogImage?.startsWith('/') ? meta.ogImage : SEO_DEFAULTS.defaultOgImage}`; - const ogImageAlt = meta.title; - const jsonLdGraph = meta.jsonLd ?? []; - return { - ...meta, - canonical, - ogImage, - ogImageAlt, - jsonLdGraph, - }; + const baseUrl = SEO_DEFAULTS.baseUrl; + const canonical = meta.canonical ?? `${baseUrl}${path === '/' ? '' : path}`; + const ogImage = meta.ogImage?.startsWith('http') + ? meta.ogImage + : `${baseUrl}${meta.ogImage?.startsWith('/') ? meta.ogImage : SEO_DEFAULTS.defaultOgImage}`; + const ogImageAlt = meta.title; + const jsonLdGraph = meta.jsonLd ?? []; + return { + ...meta, + canonical, + ogImage, + ogImageAlt, + jsonLdGraph, + }; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 056255e..e46ff86 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,4 +1,5 @@ +
diff --git a/src/routes/+page.ts b/src/routes/+page.ts index a844c0e..3090620 100644 --- a/src/routes/+page.ts +++ b/src/routes/+page.ts @@ -2,5 +2,5 @@ import type { PageLoad } from './$types'; import { homeMeta } from '$lib/data/home-meta'; export const load: PageLoad = () => { - return { meta: homeMeta }; + return { meta: homeMeta }; }; diff --git a/tests/visual.spec.ts-snapshots/home-chromium-darwin.png b/tests/visual.spec.ts-snapshots/home-chromium-darwin.png index 6704952..28f9522 100644 Binary files a/tests/visual.spec.ts-snapshots/home-chromium-darwin.png and b/tests/visual.spec.ts-snapshots/home-chromium-darwin.png differ