From a1a711b015a40c99766022d08e91acb6d4779d45 Mon Sep 17 00:00:00 2001 From: webfussel Date: Wed, 28 May 2025 06:30:44 +0200 Subject: [PATCH] ADD: Pricing charts layout Finished Pricing Charts --- app/assets/css/global.css | 18 ++++- app/assets/css/pricing.css | 112 ++++++++++++++++++++++-------- app/assets/css/spoiler.css | 34 +++++++++ app/components/Booking.vue | 75 +++++++++----------- app/components/Flatrate.vue | 134 +++++++++++++++++++++++++++++------- app/components/Spoiler.vue | 23 +++++++ nuxt.config.ts | 1 + 7 files changed, 300 insertions(+), 97 deletions(-) create mode 100644 app/assets/css/spoiler.css create mode 100644 app/components/Spoiler.vue diff --git a/app/assets/css/global.css b/app/assets/css/global.css index fc616aa..9c4a78b 100755 --- a/app/assets/css/global.css +++ b/app/assets/css/global.css @@ -133,13 +133,27 @@ span.highlight { } span.chip { - background: var(--color-orange); + background: var(--background); + color: var(--color); border-radius: 999px; font-size: 1rem; - color: var(--color-black); height: max-content; padding: .5em 1em; user-select: none; + display: flex; + align-items: center; + gap: .5em; + width: max-content; + + &:not(.dark) { + --background: var(--color-orange); + --color: var(--color-black); + } + + &.dark { + --background: var(--color-orange-dark); + --color: var(--color-white); + } } .card { diff --git a/app/assets/css/pricing.css b/app/assets/css/pricing.css index eef6e34..d91f3b9 100644 --- a/app/assets/css/pricing.css +++ b/app/assets/css/pricing.css @@ -1,6 +1,8 @@ .Pricing { display: grid; - grid-template-rows: 150px auto auto auto 1fr; + grid-template-rows: auto auto 1fr; + grid-template-columns: repeat(3, 1fr); + grid-template-areas: "left middle right" "left middle right" "left middle right"; & article { display: grid; @@ -8,42 +10,85 @@ grid-row: 1 / -1; background-color: var(--color-orange-black); overflow: hidden; + width: 100%; - &:nth-child(2) { + &:nth-child(1) { border-top-left-radius: 20px; border-bottom-left-radius: 20px; - } - - &:nth-child(4) { - border-top-right-radius: 20px; - border-bottom-right-radius: 20px; + grid-area: left; } &:nth-child(3) { + border-top-right-radius: 20px; + border-bottom-right-radius: 20px; + grid-area: right; + } + + &:nth-child(2) { z-index: 100; scale: 1.05; border-radius: 20px; + grid-area: middle; + } + + & .price { + font-size: 3rem; + margin-top: 1rem; + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: .5rem; + + & .post { + font-size: .8rem; + white-space: nowrap; + } + } + + & .claim { + text-align: left; + } + + & .conmin { + font-size: .8rem; + color: var(--color-white-transparent); + text-align: center; + } + + & ul { + display: flex; + flex-direction: column; + gap: 1rem; + font-size: 1rem; + + & li { + display: flex; + align-items: center; + gap: .5rem; + color: var(--color-white); + + & .icon { + flex: 0 0 1.5rem; + + &.yes { + color: var(--color-orange); + } + + &.no { + color: var(--color-white-transparent); + } + } + } } & .value { - padding: 2rem; - text-align: center; - - &.fat { - font-family: 'Roboto Condensed', sans-serif; - font-weight: bold; - font-size: 1.5rem; - } - - &.odd { - background: var(--color-black); - } + font-family: 'Roboto Condensed', sans-serif; } & header, & main, & footer { - padding: var(--spacing-standard); + padding: 1.5rem var(--spacing-standard); display: flex; flex-direction: column; justify-content: center; @@ -51,21 +96,15 @@ & footer { align-items: center; - color: var(--color-orange); gap: .5rem; - - & .price { - font-size: 2rem; - font-weight: bold; - } } - &:nth-child(3) header { + &:nth-child(2) header { background: var(--color-orange); color: var(--color-black); } - &:not(:nth-child(3)) header { + &:not(:nth-child(2)) header { background: var(--color-orange-dark); color: var(--color-white); } @@ -89,4 +128,21 @@ } } } +} + +@media (width <= 1400px) { + .Pricing { + grid-template-rows: auto auto 1fr auto auto 1fr auto auto 1fr; + grid-template-columns: 1fr; + grid-template-areas: "middle" "middle" "middle" "left" "left" "left" "right" "right" "right"; + + & article { + margin-bottom: 2rem; + border-radius: 20px; + + &:nth-child(2) { + scale: 1; + } + } + } } \ No newline at end of file diff --git a/app/assets/css/spoiler.css b/app/assets/css/spoiler.css new file mode 100644 index 0000000..fb9564d --- /dev/null +++ b/app/assets/css/spoiler.css @@ -0,0 +1,34 @@ +.Spoiler { + background: var(--color-black); + padding: 1rem 2rem; + border-radius: 20px; + + & .icon { + color: var(--color-orange); + } + + & summary { + font-size: 1.5rem; + cursor: pointer; + list-style: none; + display: flex; + align-items: center; + gap: 1rem; + font-weight: bold; + } + + & > div { + margin-top: 1rem; + display: flex; + flex-direction: column; + gap: 1rem; + } +} + +@media (width <= 820px) { + .Spoiler { + & summary { + font-size: 1rem; + } + } +} \ No newline at end of file diff --git a/app/components/Booking.vue b/app/components/Booking.vue index b309a5b..d7eacb4 100755 --- a/app/components/Booking.vue +++ b/app/components/Booking.vue @@ -2,12 +2,12 @@

Services.

Du hast also beschlossen, dass du meine Hilfe brauchst. Cool!

-

Hinter meinen Angeboten gibt es keinerlei Abos oder versteckte Kosten. +

Hinter diesen Angeboten gibt es keinerlei Abos oder versteckte Kosten. Aus Transparenzgründen sei aber gesagt, dass sich *alle Preise zzgl. 19 % Umsatzsteuer. verstehen.

Derzeit habe ich keine freien Plätze.

-

Das ändert sich ab 01. Juli 2025.

+

Das ändert sich ab 01. Januar 2026.

One off Projekte

@@ -19,22 +19,26 @@
{{service.title}}

{{service.smallClaim}}

+
+ {{service.price.pre}} + {{typeof service.price.value === 'number' ? intl.format(service.price.value) : service.price.value}} + {{service.price.post}} +
-
    -
  • - +
      +
    • + {{ point }}
- {{service.price.pre ? `${service.price.pre} ` : '' }}{{typeof service.price.value === 'number' ? intl.format(service.price.value) : service.price.value}}
@@ -66,11 +66,12 @@ type Service = { price: { value: number | string pre?: string + post?: string } icon: string button: string link: string - list: string[][] + list: string[] } const intl = new Intl.NumberFormat( @@ -93,15 +94,11 @@ const oneOff : Service[] = [ 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', - ] + 'Untersuchung des Quellcodes', + 'Untersuchung der Performance', + 'Tipps zu CSS und Best Practices', + 'Behebung unkompliziert nachbuchen', + 'Für selbst gebaute Seiten', ], }, { title: 'Projektbuchung', @@ -114,35 +111,29 @@ const oneOff : Service[] = [ 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', - ] + 'Anforderungsanalyse', + 'Kontinuierliche Projekt-Updates', + 'Fixe Kosten und Feature-Sets', + 'Nur 50 % Projektpreis als Anzahlung', + 'Gestaffelte Abrechnung nach Milestones', ], }, { - title: 'Enterprise', + title: 'Schulung', price: { - value: 'Auf Anfrage', + pre: 'ab', + value: 1499, + post: '/ Tag / Person', }, - smallClaim: 'Für die ganz großen Sachen.', - icon: 'building-office', + smallClaim: 'Wenn man\'s selber können muss.', + icon: 'graduation-cap', 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' - ], + 'Anforderungsanalyse', + 'Team-Workshops', + 'Azubi-Betreuung', + '1:1 Mentoring', + 'Abrechnung pro Person und Tag', ], }, ] diff --git a/app/components/Flatrate.vue b/app/components/Flatrate.vue index f8a65de..078474f 100755 --- a/app/components/Flatrate.vue +++ b/app/components/Flatrate.vue @@ -4,35 +4,45 @@

Genieße fusselige Qualität ohne groß herumzurechnen.

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 Entwickler-Flat für planbare Kosten und On-Demand-Entwicklung.

+ Hier gibt's die Entwickler-Flat für planbare Kosten und On-Demand-Entwicklung. Aus Transparenzgründen sei aber gesagt, dass sich *alle Preise zzgl. 19 % Umsatzsteuer. verstehen.

-
-
-

Gleichzeitige Tickets

-

Erreichbarkeit

-

Monatlicher Preis

-
-
- {{service.title}} -

{{service.smallClaim}}

+ Beschd + {{service.title}} +

{{service.smallClaim}}

+

{{intl.format(service.price)}}

-

{{ typeof point === 'number' ? intl.format(point) : point }}

+
+
    +
  • + + {{ service.hours }} Stunden pro Woche zugesichert +
  • +
  • + + {{ points[index] }} +
  • +
+
-
+

Die Mindestvertragslaufzeit beträgt {{ service.contractMin }} Monate.

+ +
+ +
@@ -43,7 +53,11 @@ type Service = { icon: string button: string link: string - list: (string | number)[] + best: boolean + price: number + hours: number + contractMin: number + checks: boolean[] } const intl = new Intl.NumberFormat( @@ -55,6 +69,13 @@ const intl = new Intl.NumberFormat( maximumFractionDigits: 0, }) +const points : string[] = [ + 'Kontakt per E-Mail', + 'Kontakt per Instant Messaging', + 'Kontakt per Video Call', + 'Weiterführende Performance Optimierung', + 'Framework Migration', +] const flatrate : Service[] = [ @@ -64,10 +85,16 @@ const flatrate : Service[] = icon: 'baby-carriage', button: 'Jetzt klar machen', link: 'https://tidycal.com/webfussel/flatrate-casual', - list: [ - '1', - 'E-Mail', - 2950, + best: false, + price: 2950, + hours: 5, + contractMin: 3, + checks: [ + true, + false, + false, + false, + false, ], }, { @@ -76,10 +103,16 @@ const flatrate : Service[] = icon: 'coins', button: 'Jetzt Gold schürfen', link: 'https://tidycal.com/webfussel/flatrate-gold-fussel', - list: [ - '2', - 'E-Mail, Instant-Messaging', - 4950, + best: true, + price: 4950, + hours: 10, + contractMin: 3, + checks: [ + true, + true, + false, + true, + false, ], }, { @@ -88,11 +121,62 @@ const flatrate : Service[] = icon: 'skull', button: 'Jetzt Fett trimmen', link: 'https://tidycal.com/webfussel/flatrate-big-chonker', - list: [ - '3', - 'E-Mail, Instant-Messaging, Video-Chat', - 8950, + best: false, + price: 8950, + hours: 15, + contractMin: 6, + checks: [ + true, + true, + true, + true, + true, ], } ] + +const faq = [ + { + header: 'Was ist eine Entwickler-Flatrate?', + content: [ + 'Die Entwickler-Flatrate ist ein Angebot, bei dem du für eine bestimmte Zeit eine bestimmte Menge an Leistungen erhältst.', + 'Sie wird auch oft als sogenannter "Retainer" bezeichnet und ist eine günstige Art immer wieder anfallende Aufgaben auszulagern.' + ] + }, + { + header: 'Wie läuft die Zusammenarbeit ab?', + content: [ + 'Nach einer ersten Analyse deines Projekts legen wir gemeinsam den Umfang und die monatlichen Aufgaben fest. Du kannst mich je nach Paket auf den vereinbarten Wegen jederzeit kontaktieren.', + 'Die Bearbeitung erfolgt innerhalb der vereinbarten Fristen.', + ] + }, + { + header: 'Wie wird abgerechnet?', + content: [ + 'Du zahlst monatlich einen festen Betrag im Prepaid-Format unabhängig davon wie viele Aufgaben tatsächlich anfallen.', + 'Dadurch kannst du dein Budget besser einplanen und Aufgaben verteilen.' + ] + }, + { + header: 'Kann ich den Retainer jederzeit kündigen?', + content: [ + 'Ja klar. Du musst dabei nur die Mindestvertragslaufzeit beachten - die bezahlte Leistung steht dir weiterhin Fall zu.', + 'Falls wir merken, dass wir für eine Zusammenarbeit mehr als ungeeignet sind, bekommst du dein Geld anteilig der verbleibenden Zeit zurück und verlierst den Anspruch auf Leistungen ab diesem Zeitpunkt.' + ] + }, + { + header: 'Was passiert, wenn ich dich mal weniger brauche?', + content: [ + 'Der monatliche feste Betrag bleibt bestehen. Ähnlich wie bei einer Versicherung bezahlst du hier für den Fall, dass du mich brauchst und erhältst dann entsprechend die vereinbarten Leistungen.', + 'Wenn du merkst, dass du mich nicht mehr brauchst, dann kannst du den Vertrag jederzeit kündigen und die Leistungen auslaufen lassen.' + ] + }, + { + header: 'Für wen lohnt sich sowas überhaupt?', + content: [ + 'Vor allem Unternehmen, bei denen immer wieder Aufgaben anfallen für die sich aber kein komplettes Projekt oder gar eine feste Stelle in der Firma lohnt, profitieren von dieser Art von Leistung.', + 'Sie ist ideal für eine langfristige und zuverlässige Zusammenarbeit.' + ] + } +] diff --git a/app/components/Spoiler.vue b/app/components/Spoiler.vue new file mode 100644 index 0000000..5acddbc --- /dev/null +++ b/app/components/Spoiler.vue @@ -0,0 +1,23 @@ + + + \ No newline at end of file diff --git a/nuxt.config.ts b/nuxt.config.ts index 5185d19..51db06a 100755 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -25,6 +25,7 @@ export default defineNuxtConfig({ '~/assets/css/technology.css', '~/assets/css/person.css', '~/assets/css/button.css', + '~/assets/css/spoiler.css', ], postcss: {