Some icons and basic tweaks for the visuals
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful

This commit is contained in:
2026-02-01 13:37:07 -03:00
parent 52c0fd5e2d
commit 4bcce26a74
11 changed files with 221 additions and 15 deletions

View File

@@ -50,5 +50,8 @@
"typescript-eslint": "^8.54.0",
"vite": "^6.0.0",
"vitest": "^4.0.18"
},
"dependencies": {
"@lucide/svelte": "^0.563.1"
}
}

13
pnpm-lock.yaml generated
View File

@@ -7,6 +7,10 @@ settings:
importers:
.:
dependencies:
'@lucide/svelte':
specifier: ^0.563.1
version: 0.563.1(svelte@5.49.1)
devDependencies:
'@eslint/js':
specifier: ^9.39.2
@@ -647,6 +651,11 @@ packages:
'@keyv/serialize@1.1.1':
resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==}
'@lucide/svelte@0.563.1':
resolution: {integrity: sha512-Kt+MbnE5D9RsuI/csmf7M+HWxALe57x3A0DhQ8pPnnUpneh7zuldrYjlT+veWtk+tVnp5doQtaAAxLujzIlhBw==}
peerDependencies:
svelte: ^5
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -2910,6 +2919,10 @@ snapshots:
'@keyv/serialize@1.1.1': {}
'@lucide/svelte@0.563.1(svelte@5.49.1)':
dependencies:
svelte: 5.49.1
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5

View File

@@ -375,6 +375,13 @@ a {
}
}
.icon-button {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-xs);
}
/* PRIMARY CTA
Use the CTA/button tokens (defined in BOTH modes) to guarantee contrast.
This fixes the dark-mode purple/white contrast violation without changing your purple brand accents. */

View File

@@ -1,3 +1,9 @@
<script lang="ts">
import LinkedInIcon from './Icon/LinkedIn.svelte';
import GithubIcon from './Icon/Github.svelte';
import ExternalLinkIcon from './Icon/ExternalLink.svelte';
</script>
<footer class="footer">
<div class="container">
<p class="copyright">
@@ -5,17 +11,27 @@
</p>
<nav class="footer-links" aria-label="Social media links">
<a
class="link"
href="https://linkedin.com/in/the-mifi"
target="_blank"
rel="noopener noreferrer"
aria-label="LinkedIn profile (opens in new tab)">LinkedIn</a
aria-label="LinkedIn profile (opens in new tab)"
>
<LinkedInIcon size="15" />
LinkedIn
<ExternalLinkIcon aria-label="Opens in new tab" size="15" />
</a>
<a
class="link"
href="https://github.com/the-mifi"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub profile (opens in new tab)">GitHub</a
aria-label="GitHub profile (opens in new tab)"
>
<GithubIcon size="15" />
GitHub
<ExternalLinkIcon aria-label="Opens in new tab" size="15" />
</a>
</nav>
</div>
</footer>
@@ -35,4 +51,11 @@
color: var(--color-text-tertiary);
max-width: 100%;
}
.link {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-xs);
}
</style>

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import ExternalLinkIcon from './Icon/ExternalLink.svelte';
import FiletypePdfIcon from './Icon/FiletypePdf.svelte';
import Logo from './Logo.svelte';
</script>
@@ -13,20 +15,22 @@
<div class="cta-group">
<a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_medium=hero_cta"
class="btn btn-primary"
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
>
Schedule a 30-minute intro call
<ExternalLinkIcon aria-label="Opens in new tab" size="17" />
</a>
<a
href="/downloads/resume.pdf"
class="btn btn-secondary"
class="btn btn-secondary icon-button"
download
aria-label="Download Mike Fitzpatrick's resume as PDF"
>
Download resume
<FiletypePdfIcon aria-label="PDF format file" size="17" />
</a>
</div>
</div>

View File

@@ -0,0 +1,30 @@
<script lang="ts">
const {
'aria-label': ariaLabel,
class: className,
color = 'currentColor',
size,
} = $props<{
'aria-label'?: string;
class?: string;
color?: string;
size?: number;
}>();
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill={color}
class={className}
aria-label={ariaLabel}
aria-hidden={!ariaLabel}
role={ariaLabel ? undefined : 'presentation'}
width={size}
height={size}
>
<path
d="M10 6V8H5V19H16V14H18V20C18 20.5523 17.5523 21 17 21H4C3.44772 21 3 20.5523 3 20V7C3 6.44772 3.44772 6 4 6H10ZM21 3V11H19L18.9999 6.413L11.2071 14.2071L9.79289 12.7929L17.5849 5H13V3H21Z"
>
</path>
</svg>

View File

@@ -0,0 +1,30 @@
<script lang="ts">
const {
'aria-label': ariaLabel,
class: className,
color = 'currentColor',
size,
} = $props<{
'aria-label'?: string;
class?: string;
color?: string;
size?: number;
}>();
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill={color}
class={className}
aria-label={ariaLabel}
aria-hidden={!ariaLabel}
role={ariaLabel ? undefined : 'presentation'}
width={size}
height={size}
>
<path
d="M5 4H15V8H19V20H5V4ZM3.9985 2C3.44749 2 3 2.44405 3 2.9918V21.0082C3 21.5447 3.44476 22 3.9934 22H20.0066C20.5551 22 21 21.5489 21 20.9925L20.9997 7L16 2H3.9985ZM10.4999 7.5C10.4999 9.07749 10.0442 10.9373 9.27493 12.6534C8.50287 14.3757 7.46143 15.8502 6.37524 16.7191L7.55464 18.3321C10.4821 16.3804 13.7233 15.0421 16.8585 15.49L17.3162 13.5513C14.6435 12.6604 12.4999 9.98994 12.4999 7.5H10.4999ZM11.0999 13.4716C11.3673 12.8752 11.6042 12.2563 11.8037 11.6285C12.2753 12.3531 12.8553 13.0182 13.5101 13.5953C12.5283 13.7711 11.5665 14.0596 10.6352 14.4276C10.7999 14.1143 10.9551 13.7948 11.0999 13.4716Z"
>
</path>
</svg>

View File

@@ -0,0 +1,30 @@
<script lang="ts">
const {
'aria-label': ariaLabel,
class: className,
color = 'currentColor',
size,
} = $props<{
'aria-label'?: string;
class?: string;
color?: string;
size?: number;
}>();
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill={color}
class={className}
aria-label={ariaLabel}
aria-hidden={!ariaLabel}
role={ariaLabel ? undefined : 'presentation'}
width={size}
height={size}
>
<path
d="M12.001 2C6.47598 2 2.00098 6.475 2.00098 12C2.00098 16.425 4.86348 20.1625 8.83848 21.4875C9.33848 21.575 9.52598 21.275 9.52598 21.0125C9.52598 20.775 9.51348 19.9875 9.51348 19.15C7.00098 19.6125 6.35098 18.5375 6.15098 17.975C6.03848 17.6875 5.55098 16.8 5.12598 16.5625C4.77598 16.375 4.27598 15.9125 5.11348 15.9C5.90098 15.8875 6.46348 16.625 6.65098 16.925C7.55098 18.4375 8.98848 18.0125 9.56348 17.75C9.65098 17.1 9.91348 16.6625 10.201 16.4125C7.97598 16.1625 5.65098 15.3 5.65098 11.475C5.65098 10.3875 6.03848 9.4875 6.67598 8.7875C6.57598 8.5375 6.22598 7.5125 6.77598 6.1375C6.77598 6.1375 7.61348 5.875 9.52598 7.1625C10.326 6.9375 11.176 6.825 12.026 6.825C12.876 6.825 13.726 6.9375 14.526 7.1625C16.4385 5.8625 17.276 6.1375 17.276 6.1375C17.826 7.5125 17.476 8.5375 17.376 8.7875C18.0135 9.4875 18.401 10.375 18.401 11.475C18.401 15.3125 16.0635 16.1625 13.8385 16.4125C14.201 16.725 14.5135 17.325 14.5135 18.2625C14.5135 19.6 14.501 20.675 14.501 21.0125C14.501 21.275 14.6885 21.5875 15.1885 21.4875C19.259 20.1133 21.9999 16.2963 22.001 12C22.001 6.475 17.526 2 12.001 2Z"
>
</path>
</svg>

View File

@@ -0,0 +1,30 @@
<script lang="ts">
const {
'aria-label': ariaLabel,
class: className,
color = 'currentColor',
size,
} = $props<{
'aria-label'?: string;
class?: string;
color?: string;
size?: number;
}>();
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill={color}
class={className}
aria-label={ariaLabel}
aria-hidden={!ariaLabel}
role={ariaLabel ? undefined : 'presentation'}
width={size}
height={size}
>
<path
d="M18.3362 18.339H15.6707V14.1622C15.6707 13.1662 15.6505 11.8845 14.2817 11.8845C12.892 11.8845 12.6797 12.9683 12.6797 14.0887V18.339H10.0142V9.75H12.5747V10.9207H12.6092C12.967 10.2457 13.837 9.53325 15.1367 9.53325C17.8375 9.53325 18.337 11.3108 18.337 13.6245V18.339H18.3362ZM7.00373 8.57475C6.14573 8.57475 5.45648 7.88025 5.45648 7.026C5.45648 6.1725 6.14648 5.47875 7.00373 5.47875C7.85873 5.47875 8.55173 6.1725 8.55173 7.026C8.55173 7.88025 7.85798 8.57475 7.00373 8.57475ZM8.34023 18.339H5.66723V9.75H8.34023V18.339ZM19.6697 3H4.32923C3.59498 3 3.00098 3.5805 3.00098 4.29675V19.7033C3.00098 20.4202 3.59498 21 4.32923 21H19.6675C20.401 21 21.001 20.4202 21.001 19.7033V4.29675C21.001 3.5805 20.401 3 19.6675 3H19.6697Z"
>
</path>
</svg>

View File

@@ -51,17 +51,17 @@
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;
padding-top: var(--space-sm);
position: sticky;
text-align: center;
top: 0;
z-index: 100;
@media (max-width: 768px) {
align-items: stretch;
display: flex;
flex-direction: column;
align-items: stretch;
padding: var(--space-md) 0;
}
}
@@ -281,29 +281,56 @@
}
@supports (animation-timeline: scroll()) {
/* Shadow on pseudo-element; only opacity is animated (composited) */
.nav::after {
content: '';
position: absolute;
inset: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
pointer-events: none;
opacity: 0;
animation: nav-shadow-on-scroll linear;
animation-timeline: scroll(root block);
animation-range: 0 100px;
animation-fill-mode: both;
will-change: opacity;
}
@keyframes nav-shadow-on-scroll {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.nav::after {
animation: none;
opacity: 1;
}
}
/* Composited-only animation: opacity only (visibility/pointer-events not animated) */
.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;
will-change: opacity, visibility;
will-change: opacity;
}
@keyframes nav-reveal-on-scroll {
from {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
to {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
}

View File

@@ -1,3 +1,7 @@
<script lang="ts">
import ExternalLinkIcon from './Icon/ExternalLink.svelte';
</script>
<section
id="schedule"
class="section schedule-section"
@@ -8,12 +12,13 @@
<p class="schedule-text">Ready to discuss your project?</p>
<a
href="https://cal.mifi.ventures/the-mifi/30min?utm_source=website&utm_medium=cta&utm_campaign=schedule_call&utm_medium=schedule_section_cta"
class="btn btn-primary"
class="btn btn-primary icon-button"
target="_blank"
rel="noopener noreferrer"
aria-label="Schedule a 30-minute intro call (opens in new tab)"
>
Schedule a 30-minute intro call
<ExternalLinkIcon aria-label="Opens in new tab" size="17" />
</a>
</div>
</section>
@@ -32,4 +37,8 @@
line-height: var(--line-height-relaxed);
max-width: 100%;
}
.btn {
margin: 0 auto;
}
</style>