Added the Nav... Almost ready for the switcheroo
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
2026-02-01 02:34:32 -03:00
parent 915d53fdba
commit 12fb8c0335
14 changed files with 618 additions and 292 deletions

View File

@@ -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
======================================== */

View File

@@ -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;
}
}
}
}
</style>

View File

@@ -0,0 +1,319 @@
<script lang="ts">
import Wordmark from './Wordmark.svelte';
</script>
<nav id="nav" class="nav" aria-label="Main navigation">
<input
type="checkbox"
id="nav-toggle"
class="nav-toggle-input"
aria-hidden="true"
hidden
/>
<div class="mobile-nav-header">
<span class="mobile nav-header-logo">
<Wordmark />
</span>
<label for="nav-toggle" class="nav-toggle" aria-label="Toggle navigation">
<span class="nav-toggle-inner">
<span class="nav-toggle-line"></span>
<span class="nav-toggle-line"></span>
<span class="nav-toggle-line"></span>
</span>
</label>
</div>
<div class="nav-menu container">
<span class="nav-header-logo desktop">
<Wordmark />
</span>
<ul class="nav-list">
<li class="nav-item">
<a href="#what-we-do" class="nav-link">Services</a>
</li>
<li class="nav-item">
<a href="#impact" class="nav-link">Impact</a>
</li>
<li class="nav-item">
<a href="#how-we-work" class="nav-link">Process</a>
</li>
<li class="nav-item">
<a href="#schedule" class="nav-link">Contact</a>
</li>
</ul>
<div class="nav-item nav-back-to-top">
<a href="#header" class="nav-link">Back to top</a>
</div>
</div>
</nav>
<style>
.nav {
background-color: var(--color-bg);
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
padding: var(--space-md) 0;
position: sticky;
text-align: center;
top: 0;
z-index: 100;
@media (max-width: 768px) {
display: flex;
flex-direction: column;
align-items: stretch;
}
}
.container,
.nav-menu {
display: grid;
grid-template-columns: 1fr auto 1fr;
justify-content: space-between;
align-items: center;
}
.mobile-nav-header {
anchor-name: --mobile-nav-header;
display: none;
justify-content: space-between;
align-items: center;
@media (max-width: 768px) {
display: flex;
}
}
.nav-header-logo {
color: var(--color-text);
display: inline-block;
max-width: 250px;
padding-left: var(--space-md);
&.mobile {
display: none;
}
@media (max-width: 768px) {
&.desktop {
display: none;
}
&.mobile {
display: inline-block;
}
}
}
/* Hamburger toggle: mobile only, animates to X when open */
.nav-toggle-input {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
&:checked {
& ~ .mobile-nav-header .nav-toggle .nav-toggle-line {
&:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
&:nth-child(2) {
opacity: 0;
}
&:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
}
& ~ .nav-menu {
max-height: 80vh;
opacity: 1;
padding-top: var(--space-md);
padding-bottom: var(--space-md);
border-top: 1px solid var(--color-border);
}
}
}
.nav-toggle {
display: none;
align-items: center;
justify-content: flex-end;
flex: 0 0 auto;
padding: var(--space-sm) var(--space-md);
width: calc(24px + var(--space-md) + var(--space-md));
height: calc(31px + var(--space-sm) + var(--space-sm));
cursor: pointer;
color: var(--color-text);
background: transparent;
border: none;
border-radius: var(--space-xs);
transition:
color 0.2s ease,
background-color 0.2s ease;
@media (max-width: 768px) {
display: flex;
}
&:hover {
color: var(--color-primary);
}
&:focus-visible {
outline: 4px solid var(--color-focus);
outline-offset: 4px;
}
}
.nav-toggle-inner {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 24px;
height: 18px;
}
.nav-toggle-line {
display: block;
width: 100%;
height: 2px;
background-color: currentColor;
border-radius: 1px;
transform-origin: center;
transition:
transform 0.25s ease,
opacity 0.2s ease;
@media (prefers-reduced-motion: reduce) {
transition-duration: 0.01ms;
}
}
.nav-list {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
padding: 0;
margin: 0;
}
.nav-item {
margin: 0 var(--space-md);
}
/* Back to top + mobile nav logo: hidden until page is scrolled (CSS scroll-driven animation) */
.nav-back-to-top,
.nav-header-logo {
/* Fallback when scroll-driven animations arent supported: always visible */
opacity: 1;
visibility: visible;
}
/* Mobile: show toggle, collapse menu until opened; menu overlays content via anchor */
@media (max-width: 768px) {
.nav-menu {
display: flex;
flex-direction: column;
align-items: stretch;
max-height: 0;
overflow: hidden;
opacity: 0;
padding-top: 0;
padding-bottom: 0;
border-top: none;
transition:
max-height 0.3s ease,
opacity 0.25s ease,
padding 0.25s ease;
& .nav-list,
& .nav-item {
width: 100%;
}
& .nav-list {
flex-direction: column;
gap: 0;
}
& .nav-item {
margin: 0;
text-align: center;
& a:hover {
border-bottom-color: transparent;
}
}
& .nav-item a,
& .nav-back-to-top a {
display: block;
padding: var(--space-md);
}
@supports (top: anchor(bottom)) {
position: fixed;
position-anchor: --mobile-nav-header;
top: anchor(--mobile-nav-header bottom);
left: anchor(--mobile-nav-header left);
right: anchor(--mobile-nav-header right);
margin: 0;
overflow-y: auto;
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 99;
}
@media (prefers-reduced-motion: reduce) {
transition-duration: 0.01ms;
}
}
}
@supports (animation-timeline: scroll()) {
.nav-back-to-top,
.nav-header-logo {
opacity: 0;
visibility: hidden;
pointer-events: none;
animation: nav-reveal-on-scroll linear;
animation-timeline: scroll(root block);
animation-range: 300px 400px;
animation-fill-mode: both;
}
@keyframes nav-reveal-on-scroll {
from {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
to {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
}
@media (prefers-reduced-motion: reduce) {
.nav-back-to-top,
.nav-header-logo {
animation: none;
opacity: 1;
visibility: visible;
pointer-events: auto;
}
}
}
</style>

View File

@@ -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());
});
});

View File

@@ -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();
}

View File

@@ -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.',
];

View File

@@ -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.",
},
];

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -6,145 +6,145 @@
const BASE = 'https://mifi.ventures';
export const defaultJsonLdGraph: Record<string, unknown>[] = [
{
'@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.',
},
},
],
},
];

View File

@@ -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<string, unknown>[];
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<string, unknown>[];
}
export interface MergedMeta extends PageMeta {
canonical: string;
ogImage: string;
ogImageAlt: string;
jsonLdGraph: Record<string, unknown>[];
canonical: string;
ogImage: string;
ogImageAlt: string;
jsonLdGraph: Record<string, unknown>[];
}
/** 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,
};
}

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import Navigation from '$lib/components/Navigation.svelte';
import Hero from '$lib/components/Hero.svelte';
import ExperienceSection from '$lib/components/ExperienceSection.svelte';
import WhatWeDo from '$lib/components/WhatWeDo.svelte';
@@ -9,6 +10,7 @@
import Footer from '$lib/components/Footer.svelte';
</script>
<Navigation />
<Hero />
<main id="main">
<ExperienceSection />

View File

@@ -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 };
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 KiB

After

Width:  |  Height:  |  Size: 591 KiB