ADD: A LOT of pricing chart stuff

Added new pricing chart layout
This commit is contained in:
webfussel 2025-03-19 15:03:11 +01:00
parent a204be8ddc
commit f263a5574a
14 changed files with 563 additions and 284 deletions

View file

@ -4,26 +4,44 @@
cursor: pointer;
padding: 1rem 1.5rem;
outline: 3px solid transparent;
box-shadow: 0 0 0 0 var(--color-orange);
border-radius: 99999px;
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
font-weight: bold;
&.default {
background: var(--color-orange);
color: var(--color-black);
box-shadow: 0 0 0 0 var(--color-orange);
&:hover {
outline-color: var(--color-black);
box-shadow: 0 0 0 6px var(--color-orange);
}
}
&.dark {
background: var(--color-orange-black);
color: var(--color-white);
box-shadow: 0 0 0 0 var(--color-orange-black);
&:hover {
outline-color: var(--color-orange);
box-shadow: 0 0 0 6px var(--color-black);
}
}
&.white {
background: var(--color-white);
color: var(--color-black);
}
box-shadow: 0 0 0 0 var(--color-white);
&:hover {
outline-color: var(--color-black);
box-shadow: 0 0 0 6px var(--color-orange);
&:hover {
outline-color: var(--color-black);
box-shadow: 0 0 0 6px var(--color-white);
}
}
&.cta {
@ -72,4 +90,8 @@
padding-left: calc(var(--size) * 2);
margin-left: calc(var(--size) * -1 - 25px);
}
}
.button-wrapper {
border-radius: 99999px;
}

View file

@ -46,6 +46,7 @@
--color-black-transparent: #2a2723aa;
--color-orange: #ff9100;
--color-orange-dark: #945400;
--color-orange-light: #ffc36f;
--color-orange-black: #332b22;
}
@ -235,10 +236,18 @@ span.chip {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
.z-2-all {
box-shadow: 0 0 6px rgba(0, 0, 0, 0.16), 0 0 6px rgba(0, 0, 0, 0.23);
}
.z-3 {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
}
.z-3-all {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23), 0 -10px 20px rgba(0, 0, 0, 0.19), 0 -6px 6px rgba(0, 0, 0, 0.23);
}
.z-4 {
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
}

View file

@ -34,7 +34,6 @@
font-family: 'Roboto Condensed', sans-serif;
font-size: 1.5rem;
flex: 1.5;
cursor: default;
display: flex;
align-items: center;
gap: 1rem;

172
app/assets/css/pricing.css Normal file
View file

@ -0,0 +1,172 @@
.Pricing {
display: grid;
grid-template-columns: max-content 1fr max-content;
border-radius: 20px;
& article:first-child {
border-radius: 20px 20px 0 0;
& header,
& main,
& footer {
padding-bottom: 1.5rem;
}
& header {
background-color: var(--color-orange-dark);
color: var(--color-white);
& .bg-icon {
top: 60%;
}
}
& .cols {
& li .value {
font-size: 1.5rem;
font-weight: bold;
}
}
}
& article:last-child {
border-radius: 0 0 20px 20px;
& header,
& main,
& footer {
padding-top: 1.5rem;
}
& header {
background-color: var(--color-orange-dark);
color: var(--color-white);
}
& .cols {
& li .value {
font-size: 1.5rem;
font-weight: bold;
}
}
}
& article:nth-child(2) {
width: 105%;
margin-left: -2.5%;
margin-right: -2.5%;
border-radius: 20px;
z-index: 2;
& header {
--size-difference: 7rem;
width: calc(100% - 2rem);
padding-top: var(--size-difference);
padding-bottom: var(--size-difference);
background-color: var(--color-orange);
color: var(--color-black);
& .bg-icon {
right: 20%;
}
}
& ul {
& li .value {
font-size: 3rem;
font-weight: bold;
}
}
}
& article {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
background-color: var(--color-orange-black);
overflow: hidden;
& header,
& main,
& footer {
padding: var(--spacing-standard);
display: flex;
flex-direction: column;
justify-content: center;
}
& footer {
align-items: center;
color: var(--color-orange);
gap: .5rem;
& .price {
font-size: 2rem;
font-weight: bold;
}
}
& main {
background-color: var(--color-orange-black);
z-index: 1;
}
& header {
position: relative;
padding-right: 8rem;
width: calc(100% + 8rem);
& strong {
font-size: 2rem;
z-index: 1;
}
& .bg-icon {
position: absolute;
top: 50%;
right: 40%;
translate: 50% -50%;
font-size: 6rem;
opacity: 0.15;
}
}
& li {
display: flex;
align-items: center;
gap: .5rem;
}
& .list {
display: flex;
flex-direction: column;
gap: .5rem;
& .point-icon {
color: var(--color-orange);
}
}
& .list-container {
display: flex;
justify-content: center;
gap: 4rem;
}
& .cols {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-evenly;
gap: 1rem;
& li {
flex-direction: column;
}
& .color-icon {
color: var(--color-orange);
}
}
}
}

View file

@ -3,46 +3,7 @@
background-color: var(--color-orange-black);
background-repeat: no-repeat;
.service-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-template-rows: repeat(4, auto);
& article {
grid-row: span 4;
display: grid;
grid-template-rows: subgrid;
position: relative;
& .chip {
position: absolute;
right: -1rem;
top: calc(-1rem - 3px);
}
& header {
display: flex;
}
& ul {
gap: 1rem;
& li {
display: flex;
align-items: center;
gap: 1rem;
}
}
& .color-icon {
color: var(--color-orange);
}
& .extra {
margin-top: auto;
}
}
}
.network-list {
width: 100%;

150
app/components/Booking.vue Executable file
View file

@ -0,0 +1,150 @@
<template>
<section id="services" class="Services content">
<h2>Services.</h2>
<h3>Du hast also beschlossen, dass du <span class="highlight">meine Hilfe</span> brauchst. Cool!</h3>
<p class="margin-top">Hinter meinen Angeboten gibt es <span class="highlight">keinerlei Abos oder versteckte Kosten</span>.
Aus Transparenzgründen sei aber gesagt, dass sich <span class="highlight">*alle Preise zzgl. 19 % Umsatzsteuer</span>. verstehen.</p>
<article class="z-2 card flex-col margin-top font-big text-center">
<p>Derzeit habe ich <span class="highlight">keine freien Plätze</span>.</p>
<p class="margin-top-small">Das ändert sich ab <span class="highlight">01. Juli 2025</span>.</p>
</article>
<h3 class="margin-top-big">One off Projekte</h3>
<p class="margin-top-small">Manchmal brauchen wir alle einfach nur eine Kleinigkeit und will sich nicht lange binden. Das ist natürlich
völlig in Ordnung und genau deshalb biete ich dir die Möglichkeit mich gezielt für <span class="highlight">kleinere Projekte</span> zu buchen.</p>
<div class="Pricing margin-top">
<article v-for="(service, index) in oneOff" :class="{ 'z-3-all': index === 1, 'z-2-all': index !== 1}">
<header>
<strong>{{service.title}}</strong>
<p>{{service.smallClaim}}</p>
<div aria-hidden="true" class="bg-icon">
<Icon :name="`ph:${service.icon}-thin`" size="1.5em" mode="svg" />
</div>
</header>
<main>
<div class="list-container">
<ul class="list" v-for="(list, index) in service.list" :key="index">
<li v-for="point in list">
<Icon class="point-icon" name="ph:caret-circle-double-right-duotone" size="1.5em" mode="svg" />
<span class="label">{{ point }}</span>
</li>
</ul>
</div>
</main>
<footer>
<span class="price">{{service.price.pre ? `${service.price.pre} ` : '' }}{{typeof service.price.value === 'number' ? intl.format(service.price.value) : service.price.value}}</span>
<div class="button-wrapper z-2">
<Button :href="service.link" aria-label="Zur externen Seite Terminbuchung" :design="index === 1 ? 'default' : 'white'">
{{ service.button }}
</Button>
</div>
</footer>
</article>
</div>
<article class="z-2 card flex-col gap-default margin-top">
<h3>Keinen Bock auf Telen? Understandable.</h3>
<p>Dann schreib mir einfach gerne direkt eine E-Mail an
<ClientOnly><a class="mail" href="mailto:anfragen@webfussel.de">anfragen@webfussel.de<Icon name="ph:envelope-duotone" aria-hidden="true" alt="mail icon" size="1.2em" mode="svg" /></a></ClientOnly>
</p>
<h3>Keine Kohle? Kommt vor.</h3>
<p>Meld dich trotzdem. Eventuell ist dein Projekt ja cool genug, dass ich dir da auch entsprechend entgegenkommen kann. :)</p>
</article>
<h3 id="network" class="margin-top-big">Mein Netzwerk</h3>
<p class="margin-top">Doch auch wenn ich mal voll ausgelastet bin - keine Sorge!
Mein <span class="highlight">Netzwerk an Profis</span> kann dir sicher auch weiterhelfen.
</p>
</section>
</template>
<script setup lang="ts">
type Service = {
title: string
smallClaim: string
price: {
value: number | string
pre?: string
}
icon: string
button: string
link: string
list: string[][]
}
const intl = new Intl.NumberFormat(
'de-DE',
{
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
const oneOff : Service[] = [
{
title: 'Quick Check',
price: {
value: 149,
},
smallClaim: 'A11y, bugs, schlechter Code.',
icon: 'magnifying-glass',
button: 'Jetzt untersuchen',
link: 'https://tidycal.com/webfussel/quick-check',
list: [
[
'Untersuchung des Quellcodes',
'Untersuchung der Performance',
'Tipps zu CSS und Best Practices',
],
[
'Behebung unkompliziert nachbuchen',
'Für selbst gebaute Seiten',
]
],
}, {
title: 'Projektbuchung',
price: {
pre: 'ab',
value: 999,
},
smallClaim: 'Deine Vision.',
icon: 'trend-up',
button: 'Jetzt durchstarten',
link: 'https://tidycal.com/webfussel/project-booking',
list: [
[
'Anforderungsanalyse',
'Kontinuierliche Projekt-Updates',
'Fixe Kosten und Feature-Sets',
],
[
'Nur 50 % Projektpreis als Anzahlung',
'Gestaffelte Abrechnung nach Milestones',
]
],
}, {
title: 'Enterprise',
price: {
value: 'Auf Anfrage',
},
smallClaim: 'Für die ganz großen Sachen.',
icon: 'building-office',
button: 'Frag nach!',
link: 'https://tidycal.com/webfussel/project-booking',
list: [
[
'Anforderungsanalyse',
'Kontinuierliche Projekt-Updates',
'Fixe Kosten und Feature-Sets',
],
[
'Nur 50 % Projektpreis als Anzahlung',
'Gestaffelte Abrechnung nach Milestones'
],
],
},
]
</script>

View file

@ -9,7 +9,7 @@
type Props = {
type ?: 'a' | 'button'
href ?: string
design ?: string
design ?: 'default' | 'dark' | 'white'
}
const {

128
app/components/Flatrate.vue Executable file
View file

@ -0,0 +1,128 @@
<template>
<section id="services" class="Services content">
<h2>Prepaid Flatrates.</h2>
<h3>Genieße fusselige Qualität ohne groß herumzurechnen.</h3>
<p class="margin-top-small">Bei dir fällt ständig was an oder du hast ein langlaufendes Projekt, bei dem du immer wieder mal Unterstützung brauchst? Kein Ding.
Hier gibt's die <span class="highlight">Entwickler-Flat</span> für planbare Kosten und On-Demand-Entwicklung.</p>
<div class="Pricing margin-top">
<article v-for="(service, index) in flatrate" :class="{ 'z-3-all': index === 1, 'z-2-all': index !== 1}">
<header>
<strong>{{service.title}}</strong>
<p>{{service.smallClaim}}</p>
<div aria-hidden="true" class="bg-icon">
<Icon :name="`ph:${service.icon}-thin`" size="1.5em" mode="svg" />
</div>
</header>
<main>
<ul class="cols">
<li v-for="point in service.list">
<span class="value">{{ typeof point.value === 'number' ? intl.format(point.value) : point.value }}</span>
<span class="label">{{ point.label }}</span>
</li>
</ul>
</main>
<footer>
<!-- <span class="price">{{intl.format(service.price)}}</span>-->
<div class="button-wrapper z-2">
<Button :href="service.link" aria-label="Zur externen Seite Terminbuchung" :design="index === 1 ? 'default' : 'white'">
{{ service.button }}
</Button>
</div>
</footer>
</article>
</div>
</section>
</template>
<script setup lang="ts">
type Service = {
title: string
smallClaim: string
icon: string
button: string
link: string
list: {
label: string
value: string | number
}[]
}
const intl = new Intl.NumberFormat(
'de-DE',
{
style: 'currency',
currency: 'EUR',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})
const flatrate : Service[] =
[
{
title: 'Casual',
smallClaim: 'Für kleine Aufgaben nebenbei.',
icon: 'baby-carriage',
button: 'Jetzt klar machen',
link: 'https://tidycal.com/webfussel/flatrate-casual',
list: [
{
label: 'Ticket gleichzeitig',
value: '1',
},
{
label: 'Erreichbarkeit',
value: 'Ganz okay',
},
{
label: 'Monatlich',
value: 2950,
},
],
},
{
title: 'Gold-Fussel',
smallClaim: 'Wenn\'s mal wieder zu viel wird.',
icon: 'coins',
button: 'Jetzt Gold schürfen',
link: 'https://tidycal.com/webfussel/flatrate-gold-fussel',
list: [
{
label: 'Tickets gleichzeitig',
value: '2',
},
{
label: 'Erreichbarkeit',
value: 'Mo - Fr',
},
{
label: 'Monatlich',
value: 4950,
},
],
},
{
title: 'Big Chonker',
smallClaim: 'Für die richtig großen Sachen.',
icon: 'skull',
button: 'Jetzt Fett trimmen',
link: 'https://tidycal.com/webfussel/flatrate-big-chonker',
list: [
{
label: 'Tickets gleichzeitig',
value: '3',
},
{
label: 'Erreichbarkeit',
value: 'Ja.',
},
{
label: 'Monatlich',
value: 8950,
},
],
}
]
</script>

View file

@ -2,10 +2,12 @@
<div ref="stickyWatch" />
<header ref="header" class="Header">
<div ref="headerWrapper" class="wrapper z-0">
<strong>
<Icon class="logo" name="wf:logo" mode="svg" size="40px" />
webfussel
</strong>
<NuxtLink to="/" aria-label="Link zur Startseite">
<strong>
<Icon class="logo" name="wf:logo" mode="svg" size="40px" />
webfussel
</strong>
</NuxtLink>
<input id="navToggle" v-model="isBurgerOpen" type="checkbox">
<label :aria-label="burgerLabel" for="navToggle">
<span/><span/><span/><span/>
@ -37,21 +39,21 @@ const burgerLabel = computed(() => isBurgerOpen.value ? burgerCloseLabel : burge
const nav = [
{
to: `/`,
label: 'Home',
icon: 'house',
'aria-label': 'Link dieser Seite: Startseite'
to: `/booking`,
label: 'Projektbuchung',
icon: 'calendar-check',
aria: 'Link dieser Seite: Preise'
},
{
to: `/services`,
label: 'Leistungen',
icon: 'coins',
to: `/flatrate`,
label: 'Flatrate',
icon: 'piggy-bank',
aria: 'Link dieser Seite: Preise'
},
{
to: `/references`,
label: 'Referenzen',
icon: 'at',
icon: 'sparkle',
aria: 'Link dieser Seite: Referenzen'
},
{

View file

@ -1,224 +0,0 @@
<template>
<section id="services" class="Services content">
<h2>Services.</h2>
<h3>Du hast also beschlossen, dass du <span class="highlight">meine Hilfe</span> brauchst. Cool!</h3>
<p class="margin-top">Hinter meinen Angeboten gibt es <span class="highlight">keinerlei Abos oder versteckte Kosten</span>.
Aus Transparenzgründen sei aber gesagt, dass sich <span class="highlight">*alle Preise zzgl. 19 % Umsatzsteuer</span>. verstehen.</p>
<article class="z-2 card flex-col margin-top font-big text-center">
<p>Derzeit habe ich <span class="highlight">keine freien Plätze</span>.</p>
<p class="margin-top-small">Das ändert sich ab <span class="highlight">01. Juli 2025</span>.</p>
</article>
<h3 class="margin-top-big">One off Projekte</h3>
<p class="margin-top-small">Manchmal brauchen wir alle einfach nur eine Kleinigkeit und will sich nicht lange binden. Das ist natürlich
völlig in Ordnung und genau deshalb biete ich dir die Möglichkeit mich gezielt für <span class="highlight">kleinere Projekte</span> zu buchen.</p>
<div class="service-list margin-top gap-default">
<article v-for="service in oneOff" class="z-2 card flex-col gap-default">
<h3 class="flex-col gap-default">
<span>{{service.title}}</span>
<span class="highlight">{{'pre' in service.price ? `${service.price.pre} ` : ''}}{{service.price.value}} * {{service.price.period}}</span>
</h3>
<p>{{service.smallClaim}}</p>
<Button :href="service.link" class="cta" aria-label="Zur externen Seite Terminbuchung">
{{ service.button }}
<Icon :name="`ph:${service.icon}-duotone`" size="1.5em" mode="svg" />
</Button>
<ul class="flex-col">
<li v-for="point in service.list">
<Icon class="color-icon" name="ph:caret-circle-double-right-duotone" aria-hidden="true" alt="checkmark icon" size="1.5em" mode="svg" />
<span>{{point}}</span>
</li>
</ul>
</article>
</div>
<h3 class="margin-top-big">Prepaid Flatrates</h3>
<p class="margin-top-small">Bei dir fällt ständig was an oder du hast ein langlaufendes Projekt, bei dem du immer wieder mal Unterstützung brauchst? Kein Ding.
Hier gibt's die <span class="highlight">Entwickler-Flat</span> für planbare Kosten und On-Demand-Entwicklung.</p>
<div class="service-list margin-top gap-default">
<article v-for="service in flatrate" class="z-2 card flex-col gap-default">
<h3 class="flex-col gap-default">
<span>{{service.title}}</span>
<span class="highlight">{{'pre' in service.price ? `${service.price.pre} ` : ''}}{{service.price.value}} * {{service.price.period}}</span>
</h3>
<p>{{service.smallClaim}}</p>
<Button :href="service.link" class="cta" aria-label="Zur externen Seite Terminbuchung">
{{ service.button }}
<Icon :name="`ph:${service.icon}-duotone`" size="1.5em" mode="svg" />
</Button>
<ul class="flex-col">
<li v-for="point in service.list">
<Icon class="color-icon" name="ph:caret-circle-double-right-duotone" aria-hidden="true" alt="checkmark icon" size="1.5em" mode="svg" />
<span>{{point}}</span>
</li>
</ul>
</article>
</div>
<article class="z-2 card flex-col gap-default margin-top">
<h3>Keinen Bock auf Telen? Understandable.</h3>
<p>Dann schreib mir einfach gerne direkt eine E-Mail an
<ClientOnly><a class="mail" href="mailto:anfragen@webfussel.de">anfragen@webfussel.de<Icon name="ph:envelope-duotone" aria-hidden="true" alt="mail icon" size="1.2em" mode="svg" /></a></ClientOnly>
</p>
<h3>Keine Kohle? Kommt vor.</h3>
<p>Meld dich trotzdem. Eventuell ist dein Projekt ja cool genug, dass ich dir da auch entsprechend entgegenkommen kann. :)</p>
</article>
<h3 id="network" class="margin-top-big">Mein Netzwerk</h3>
<p class="margin-top">Doch auch wenn ich mal voll ausgelastet bin - keine Sorge!
Mein <span class="highlight">Netzwerk an Profis</span> kann dir sicher auch weiterhelfen.
</p>
<ClientOnly>
<div class="network-list margin-top">
<div class="scroll-container gap-default">
<Person ref="persons" v-for="person in network" v-bind="person" />
</div>
</div>
</ClientOnly>
</section>
</template>
<script setup lang="ts">
type Service = {
title: string
price: {
pre ?: string
value: number
period: string
}
smallClaim: string
icon: string
button: string
link: string
list: string[]
}
const oneOff : Service[] = [
{
title: 'Quick Check',
price: {
value: 149,
period: '/ Einmalig',
},
smallClaim: 'Du hast eine Homepage und willst mal drüber schauen lassen?',
icon: 'magnifying-glass',
button: 'Jetzt untersuchen',
link: 'https://tidycal.com/webfussel/quick-check',
list: [
'Untersuchung des Quellcodes',
'Untersuchung der Performance',
'Tipps zu CSS und Best Practices',
'Behebung unkompliziert nachbuchen',
'Für selbst gebaute Seiten',
],
}, {
title: 'Projektbuchung',
price: {
pre: 'ab',
value: 999,
period: '/ Gestaffelt'
},
smallClaim: 'Umsetzung deiner Vision. Von einzelnen Tickets bis hin zu kompletten Anwendungen.',
icon: 'trend-up',
button: 'Jetzt durchstarten',
link: 'https://tidycal.com/webfussel/project-booking',
list: [
'Anforderungsanalyse',
'Kontinuierliche Projekt-Updates',
'Fixe Kosten und Feature-Sets',
'Nur 50 % Projektpreis als Anzahlung',
'Gestaffelte Abrechnung nach Milestones'
],
},
]
const flatrate : Service[] =
[
{
title: 'Casual',
price: {
value: 4950,
period: '/ Monat',
},
smallClaim: 'Bei dir fällt immer mal was an und du willst nicht jedes mal neu buchen?',
icon: 'hand-grabbing',
button: 'Jetzt klar machen',
link: 'https://tidycal.com/webfussel/hourly-booking',
list: [
'1 Ticket gleichzeitig',
'Meetings alle 2 Wochen',
'Zur Mitte des Monats kündbar',
],
}, {
title: 'Gold-Fussel',
price: {
value: 8450,
period: '/ Monat',
},
smallClaim: 'Du hast häufig mehrere Aufgaben zu verteilen, aber eure Entwickler sind dauerhaft mit dem Tagesgeschäft ausgebucht?',
icon: 'crown',
button: 'Jetzt Gold schürfen',
link: 'https://tidycal.com/webfussel/hourly-booking',
list: [
'3 Tickets gleichzeitig',
'Wöchentliche Meetings',
'Zur Mitte des Monats kündbar',
],
}
]
const shuffle = <T>(unshuffled : T[]) => unshuffled
.map(value => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value)
const network = shuffle([
{
name: 'Robert Janus',
img: 'robert',
tags: ['Digitalberatung', 'Webentwicklung', 'eCommerce'],
flavour: 'Website, SEO und Conversions. Auf einen Klick.',
link: 'https://robertjanus.de/webertoire',
},
// {
// name: 'Matthias Lehmann',
// img: 'matthias',
// tags: ['Onlineportale für Patienten', 'Kunden', 'Mitarbeiter'],
// flavour: 'Software die macht, was DU willst!',
// link: 'https://mind-deploy.de',
// },
{
name: 'Maximilian Schluer',
img: 'max',
tags: ['iOS Development', 'Software-QA'],
flavour: 'Kann dein iOS-Team unterstützen oder dein Software-Qualitätsproblem lösen egal welches.',
link: 'https://max-schluer.de',
},
// {
// name: 'Maria Salcedo',
// img: 'maria',
// tags: ['Backend', 'DevOps', 'Architektur'],
// flavour: 'Effizient und kommunikativ. "You build it, you run it."',
// link: 'https://masagu.dev',
// },
{
name: 'Judith Böhlert',
img: 'judith',
tags: ['Full-stack', 'Frontend'],
flavour: 'MVPs und Prototypen - schnell, schick und ohne Drama.',
link: 'https://judithboehlert.com',
},
{
name: 'Kevin Damiani',
img: 'kevin',
tags: ['Webentwicklung', 'Frontend'],
flavour: 'Erfahrener Frontend-Entwickler mit Fokus auf Performance, Barrierefreiheit und moderne Technologien.',
link: 'https://kevin-damiani.de',
},
])
</script>

View file

@ -1,5 +1,5 @@
<template>
<div>
<Services />
<Booking />
</div>
</template>

View file

@ -3,6 +3,60 @@
<Intro />
<Skills />
<Customers />
<Services />
<Booking />
</div>
</template>
<script setup lang="ts">
const shuffle = <T>(unshuffled : T[]) => unshuffled
.map(value => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value)
const network = shuffle([
{
name: 'Robert Janus',
img: 'robert',
tags: ['Digitalberatung', 'Webentwicklung', 'eCommerce'],
flavour: 'Website, SEO und Conversions. Auf einen Klick.',
link: 'https://robertjanus.de/webertoire',
},
// {
// name: 'Matthias Lehmann',
// img: 'matthias',
// tags: ['Onlineportale für Patienten', 'Kunden', 'Mitarbeiter'],
// flavour: 'Software die macht, was DU willst!',
// link: 'https://mind-deploy.de',
// },
{
name: 'Maximilian Schluer',
img: 'max',
tags: ['iOS Development', 'Software-QA'],
flavour: 'Kann dein iOS-Team unterstützen oder dein Software-Qualitätsproblem lösen egal welches.',
link: 'https://max-schluer.de',
},
// {
// name: 'Maria Salcedo',
// img: 'maria',
// tags: ['Backend', 'DevOps', 'Architektur'],
// flavour: 'Effizient und kommunikativ. "You build it, you run it."',
// link: 'https://masagu.dev',
// },
{
name: 'Judith Böhlert',
img: 'judith',
tags: ['Full-stack', 'Frontend'],
flavour: 'MVPs und Prototypen - schnell, schick und ohne Drama.',
link: 'https://judithboehlert.com',
},
{
name: 'Kevin Damiani',
img: 'kevin',
tags: ['Webentwicklung', 'Frontend'],
flavour: 'Erfahrener Frontend-Entwickler mit Fokus auf Performance, Barrierefreiheit und moderne Technologien.',
link: 'https://kevin-damiani.de',
},
])
</script>

5
app/pages/flatrate.vue Executable file
View file

@ -0,0 +1,5 @@
<template>
<div>
<Flatrate />
</div>
</template>

View file

@ -19,6 +19,7 @@ export default defineNuxtConfig({
'~/assets/css/header.css',
'~/assets/css/intro.css',
'~/assets/css/skills.css',
'~/assets/css/pricing.css',
'~/assets/css/customers.css',
'~/assets/css/services.css',
'~/assets/css/footer.css',