feat: surface availability and operations evidence
This commit is contained in:
@@ -224,7 +224,7 @@ onUnmounted(() => removePageListeners());
|
||||
</header>
|
||||
|
||||
<main id="portfolio-content" class="portfolio-main" tabindex="-1">
|
||||
<HeroJourney :identity="content.identity" @explore="navigation.onSectionLinkClick" />
|
||||
<HeroJourney :identity="content.identity" :email="content.contact.email" @explore="navigation.onSectionLinkClick" />
|
||||
|
||||
<PortfolioSection id="profile" :layout="sectionLayouts.profile" :heading="sectionLabel('profile')">
|
||||
<p>{{ content.profile.introduction }}</p>
|
||||
|
||||
@@ -9,14 +9,14 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<div class="contact-destination">
|
||||
<p class="contact-destination__copy">Thanks for making the trip. The road's open if you'd like to build something together.</p>
|
||||
<a class="contact-link" :href="`mailto:${contact.email}`">Start a conversation</a>
|
||||
<p class="contact-destination__copy">{{ contact.introduction }}</p>
|
||||
<a class="contact-link" :href="`mailto:${contact.email}`">Email Luca</a>
|
||||
<p class="contact-destination__email">{{ contact.email }}</p>
|
||||
<p class="contact-destination__cv">{{ contact.cvMessage }}</p>
|
||||
</div>
|
||||
<ul class="contact-social">
|
||||
<li v-for="link in contact.social" :key="link.service">
|
||||
<a class="contact-social-link" :href="link.url" target="_blank" rel="noopener noreferrer">
|
||||
<a class="contact-social-link" :href="link.url" target="_blank" rel="me noopener noreferrer">
|
||||
<BrandIcon :label="link.service" />
|
||||
<span>{{ link.service }}</span>
|
||||
</a>
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { PortfolioContent } from '@/content/types';
|
||||
|
||||
defineProps<{
|
||||
identity: Readonly<PortfolioContent['identity']>;
|
||||
email: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -16,7 +17,11 @@ const emit = defineEmits<{
|
||||
<h1 id="start-heading" tabindex="-1">{{ identity.name }}</h1>
|
||||
<p class="hero-journey__role">{{ identity.role }}</p>
|
||||
<p class="hero-journey__value">{{ identity.valueProposition }}</p>
|
||||
<a class="hero-journey__action" href="#selected-builds" @click="emit('explore', $event)">Explore work</a>
|
||||
<p class="hero-journey__availability">{{ identity.availability }}</p>
|
||||
<div class="hero-journey__actions">
|
||||
<a class="hero-journey__action hero-journey__action--primary" :href="`mailto:${email}`">Email Luca</a>
|
||||
<a class="hero-journey__action" href="#selected-builds" @click="emit('explore', $event)">Explore work</a>
|
||||
</div>
|
||||
</div>
|
||||
<p class="print-portfolio-label" aria-hidden="true">Portfolio</p>
|
||||
</section>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import OperationsProof from './OperationsProof.vue';
|
||||
import type { InfrastructureCaseStudy } from "@/content/types";
|
||||
|
||||
defineProps<{ infrastructure: Readonly<InfrastructureCaseStudy> }>();
|
||||
@@ -118,5 +119,6 @@ defineProps<{ infrastructure: Readonly<InfrastructureCaseStudy> }>();
|
||||
>: {{ band.summary }}
|
||||
</li>
|
||||
</ul>
|
||||
<OperationsProof id="nextcloud-migration" :operation="infrastructure.featuredOperation" />
|
||||
</article>
|
||||
</template>
|
||||
|
||||
16
src/components/OperationsProof.vue
Normal file
16
src/components/OperationsProof.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import type { FeaturedOperation } from '@/content/types';
|
||||
|
||||
defineProps<{ id: string; operation: Readonly<FeaturedOperation> }>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="operations-proof" data-featured-operation :aria-labelledby="`${id}-heading`">
|
||||
<h4 :id="`${id}-heading`">{{ operation.title }}</h4>
|
||||
<p>{{ operation.context }}</p>
|
||||
<ol>
|
||||
<li v-for="action in operation.actions" :key="action">{{ action }}</li>
|
||||
</ol>
|
||||
<p class="operations-proof__outcome"><strong>Outcome:</strong> {{ operation.outcome }}</p>
|
||||
</section>
|
||||
</template>
|
||||
@@ -23,6 +23,19 @@
|
||||
font-size: var(--step-0);
|
||||
}
|
||||
|
||||
.hero-journey__availability {
|
||||
max-inline-size: 52ch;
|
||||
color: var(--text-muted);
|
||||
font-size: var(--step--1);
|
||||
}
|
||||
|
||||
.hero-journey__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero-journey__action,
|
||||
.project-link,
|
||||
.contact-link,
|
||||
@@ -43,6 +56,17 @@
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.hero-journey__action--primary {
|
||||
padding-inline: 0.9rem;
|
||||
border: 1px solid var(--cyan);
|
||||
background: var(--cyan);
|
||||
color: #041017;
|
||||
}
|
||||
|
||||
.hero-journey__action--primary::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.hero-journey__action::after {
|
||||
content: "→";
|
||||
transition: transform var(--transition);
|
||||
@@ -189,6 +213,50 @@
|
||||
background: rgb(5 12 23 / 90%);
|
||||
}
|
||||
|
||||
.operations-proof {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
|
||||
gap: var(--space-2) var(--space-3);
|
||||
margin-block-start: var(--space-3);
|
||||
padding-block-start: var(--space-3);
|
||||
border-block-start: 2px solid var(--line-strong);
|
||||
}
|
||||
|
||||
.operations-proof > h4,
|
||||
.operations-proof__outcome {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.operations-proof > h4 {
|
||||
color: var(--text);
|
||||
font-size: var(--step-0);
|
||||
}
|
||||
|
||||
.operations-proof > p:not(.operations-proof__outcome),
|
||||
.operations-proof > ol {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.operations-proof > ol {
|
||||
padding-inline-start: 1.2rem;
|
||||
}
|
||||
|
||||
.operations-proof__outcome {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 48rem) {
|
||||
.operations-proof {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.operations-proof > h4,
|
||||
.operations-proof__outcome {
|
||||
grid-column: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.portfolio-section[data-layout="full-diagram"] figure {
|
||||
background: rgb(10 24 38 / 72%);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
|
||||
.hero-journey__content {
|
||||
display: grid;
|
||||
min-inline-size: 0;
|
||||
inline-size: min(34rem, 39vw);
|
||||
gap: 1rem;
|
||||
padding: clamp(1.4rem, 2.2vw, 2.1rem);
|
||||
|
||||
@@ -50,6 +50,20 @@
|
||||
margin-block-start: 0.4rem;
|
||||
}
|
||||
|
||||
.hero-journey__actions,
|
||||
.operations-proof {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.operations-proof {
|
||||
margin-block-start: 1rem;
|
||||
padding-block-start: 1rem;
|
||||
}
|
||||
|
||||
.operations-proof > * + * {
|
||||
margin-block-start: 0.6rem;
|
||||
}
|
||||
|
||||
.print-portfolio-label {
|
||||
display: block;
|
||||
margin-block: 0.25rem 1rem;
|
||||
|
||||
Reference in New Issue
Block a user