REMOVE: RichText

Removed all traces of RichText implementation in Favor of NuxtContent
This commit is contained in:
webfussel 2025-06-10 07:48:21 +02:00
parent 73f09ad76e
commit 4e953392fc
23 changed files with 38 additions and 412 deletions

View file

@ -1,6 +1,6 @@
<template>
<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. Januar 2026</span>.</p>
<p>Derzeit habe ich <Highlight>keine freien Plätze</Highlight>.</p>
<p class="margin-top-small">Das ändert sich ab <Highlight>01. Januar 2026</Highlight>.</p>
</article>
</template>

View file

@ -0,0 +1,3 @@
<template>
<span class="highlight"><slot /></span>
</template>

View file

@ -0,0 +1,3 @@
<template>
<Icon name="ph:arrow-square-out-duotone" mode="svg" />
</template>

View file

@ -0,0 +1,3 @@
<template>
<Icon name="ph:link-simple-duotone" mode="svg" />
</template>

View file

@ -1,40 +0,0 @@
<template>
<component :is="computedComponent.is" v-bind="computedComponent.props" />
</template>
<script setup lang="ts">
import type { RichText } from './Types'
type Props = {
element : RichText
}
const { element } = defineProps<Props>()
const computedComponent = computed(() => {
let is : ReturnType<typeof resolveComponent> = {}
switch (element.type) {
case 'plain':
is = resolveComponent('RichTextPlain')
break
case 'p':
is = resolveComponent('RichTextParagraph')
break
case 'span':
is = resolveComponent('RichTextString')
break
case 'a':
is = resolveComponent('RichTextLink')
break
case 'br':
is = resolveComponent('RichTextNewLine')
break
default:
break
}
return { is, props: { ...element } }
})
</script>

View file

@ -1,18 +0,0 @@
<template>
<a v-if="isExternal" :href="href" :target="target" class="text inline-flex-row">
{{ content }}
<Icon name="ph:arrow-square-out-duotone" mode="svg" />
</a>
<NuxtLink v-else :to="href" class="text inline-flex-row">
{{ content }}
<Icon name="ph:link-simple-duotone" mode="svg" />
</NuxtLink>
</template>
<script setup lang="ts">
import type { RichTextLink } from './Types'
const { href } = defineProps<RichTextLink>()
const isExternal = href.startsWith('http')
</script>

View file

@ -1,3 +0,0 @@
<template>
<br>
</template>

View file

@ -1,11 +0,0 @@
<template>
<p :class="css">
<RichTextGeneral v-for="element in children" :element="element" />
</p>
</template>
<script setup lang="ts">
import type { RichTextParagraph } from './Types'
defineProps<RichTextParagraph>()
</script>

View file

@ -1,9 +0,0 @@
<template>
{{ content }}
</template>
<script setup lang="ts">
import type { RichTextPlain } from './Types'
defineProps<RichTextPlain>()
</script>

View file

@ -1,20 +0,0 @@
<template>
<template v-if="Array.isArray(elements)">
<General v-for="element in elements" :element="element" />
</template>
<template v-else>
<General :element="elements" />
</template>
</template>
<script setup lang="ts">
import type { RichText } from './Types'
import General from './General.vue'
type Props = {
elements : RichText | RichText[]
}
defineProps<Props>()
</script>

View file

@ -1,11 +0,0 @@
<template>
<span :class="css">
{{ content }}
</span>
</template>
<script setup lang="ts">
import type { RichTextSpan } from './Types'
defineProps<RichTextSpan>()
</script>

View file

@ -1,30 +0,0 @@
type RichTextBasis = {
type: string
content: string
css ?: string
}
export type RichTextPlain = RichTextBasis & {
type: 'plain'
}
export type RichTextParagraph = Omit<RichTextBasis, 'content'> & {
type: 'p'
children ?: RichText[]
}
export type RichTextSpan = RichTextBasis & {
type: 'span'
}
export type RichTextLink = RichTextBasis & {
type: 'a'
href: string
target ?: string
}
export type RichTextNewLine = {
type: 'br'
}
export type RichText = RichTextPlain | RichTextParagraph | RichTextSpan | RichTextLink | RichTextNewLine

View file

@ -1,11 +1,11 @@
<template>
<section id="services" class="Services content">
<h1>Projekt buchen</h1>
<h2>Du hast also beschlossen, dass du <span class="highlight">meine Hilfe</span> brauchst. Cool!</h2>
<h2>Du hast also beschlossen, dass du <Highlight>meine Hilfe</Highlight> brauchst. Cool!</h2>
<p class="margin-top">Manchmal brauchen wir alle einfach nur eine Kleinigkeit und wollen uns 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>
<p class="margin-top-small">Hinter diesen 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>
völlig in Ordnung und genau deshalb biete ich dir die Möglichkeit mich gezielt für <Highlight>kleinere Projekte</Highlight> zu buchen.</p>
<p class="margin-top-small">Hinter diesen Angeboten gibt es <Highlight>keinerlei Abos oder versteckte Kosten</Highlight>.
Aus Transparenzgründen sei aber gesagt, dass sich <Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight> verstehen.</p>
<FreeInfo />

View file

@ -1,7 +1,7 @@
<template>
<section id="contact" class="Contact content full gap-default">
<h1>Kontakt <span class="highlight">&</span> Social Media</h1>
<h2>Kannst ruhig in meine <span class="highlight">DMs sliden</span>. Oder in's Postfach.</h2>
<h1>Kontakt <Highlight>&</Highlight> Social Media</h1>
<h2>Kannst ruhig in meine <Highlight>DMs sliden</Highlight>. Oder in's Postfach.</h2>
<article class="z-2 card flex-col gap-sm margin-top">
<h3>Du willst einfach nur 'ne Mail schreiben?</h3>
@ -12,7 +12,7 @@
<article class="z-2 card flex-col gap-sm margin-top">
<h3>Ich auf Social Media</h3>
<p>Falls du irgendwo einen anderen Social Media Account von mir findest, der nicht hier aufgelistet ist, aber aktiv postet, dann ist dieser höchstwahrscheinlich <span class="highlight">Fake</span>.
<p>Falls du irgendwo einen anderen Social Media Account von mir findest, der nicht hier aufgelistet ist, aber aktiv postet, dann ist dieser höchstwahrscheinlich <Highlight>Fake</Highlight>.
<br />Meld' dich gerne bei mir, wenn du so einen findest.
</p>
<ul class="social-media">

View file

@ -1,6 +1,6 @@
<template>
<section id="customers" class="Customers content">
<h1>Kunden <span class="highlight">&</span> Projekte.</h1>
<h1>Kunden <Highlight>&</Highlight> Projekte.</h1>
<h2>Meine bisherigen Geschäftpartner</h2>
<div class="customer-list margin-top gap-default">
<a v-for="customer in customers" :href="customer.link" target="_blank" rel="noopener noreferrer">

View file

@ -1,11 +1,11 @@
<template>
<section id="services" class="Services content">
<h1>Prepaid Flatrates</h1>
<h2>Genieße fusselige <span class="highlight">Qualität</span> ohne groß herumzurechnen.</h2>
<h2>Genieße fusselige <Highlight>Qualität</Highlight> ohne groß herumzurechnen.</h2>
<p class="margin-top">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>
<p class="margin-top-small">Aus Transparenzgründen sei gesagt, dass sich <span class="highlight">alle Preise zzgl. 19 % Umsatzsteuer</span> verstehen.</p>
Hier gibt's die <Highlight>Entwickler-Flat</Highlight> für planbare Kosten und On-Demand-Entwicklung.</p>
<p class="margin-top-small">Aus Transparenzgründen sei gesagt, dass sich <Highlight>alle Preise zzgl. 19 % Umsatzsteuer</Highlight> verstehen.</p>
<FreeInfo />

View file

@ -22,7 +22,7 @@
<span class="tip">Ohne Tracker</span>
</li>
</ul>
<p class="inline-flex-row"><Icon name="ph:copyright-duotone" mode="svg"/> 2024 by <a href="https://webfussel.de">webfussel</a></p>
<p class="inline-flex-row"><Icon name="ph:copyright-duotone" mode="svg"/> 2024 by <NuxtLink to="/">webfussel</NuxtLink></p>
</footer>
</template>

View file

@ -3,10 +3,10 @@
<div class="intro-text flex-col gap-default">
<h1 class="flex-col">
<span class="greeting inline-flex-row">Moin. <Icon name="ph:hand-peace-duotone" mode="svg"/></span>
<span class="my-name-wrapper">Ich bin <span class="highlight">Fiona</span>.</span>
<span class="my-name-wrapper">Ich bin <Highlight>Fiona</Highlight>.</span>
</h1>
<h2>
Component <span class="highlight">&</span> API Entwicklerin
Component <Highlight>&</Highlight> API Entwicklerin
</h2>
<p class="fulltext">
Ich unterstütze Unternehmen dabei, ihre Daten von verschiedenen Endpunkten sauber aufzubereiten

View file

@ -1,7 +1,7 @@
<template>
<section id="skills" class="Skills content">
<h2>Meine Expertise.</h2>
<h3>Dies sind meine <span class="highlight">Spezialgebiete</span> - aber ich bin flexibel!</h3>
<h3>Dies sind meine <Highlight>Spezialgebiete</Highlight> - aber ich bin flexibel!</h3>
<div class="skill-list margin-top gap-default">
<Card v-for="skill in skills" :title="skill.title" titleTag="h3">
<p v-for="(t, i) in skill.text" :class="[i === skill.text.length - 1 && 'bold']">{{t}}</p>

View file

@ -1,13 +1,13 @@
<template>
<section id="skills_easy" class="Skills content">
<h2>Jetzt mal ganz konkret.</h2>
<h3>In diesem Abschnitt ganz <span class="highlight">ohne Technik-Blabla</span>.</h3>
<h3>In diesem Abschnitt ganz <Highlight>ohne Technik-Blabla</Highlight>.</h3>
<div class="skill-container flex-col margin-top gap-default">
<ContentRenderer v-for="skill in skills" :key="skill.id" :value="skill" :style="{ display: 'contents' }" />
</div>
<div class="bottom flex-col margin-top gap-default">
<h3>Verwirkliche jetzt dein Webprojekt.</h3>
<Button href="/booking" class="cta">
<Button href="/booking/" class="cta">
<Icon name="ph:chat-circle-text-duotone" size="1.5em" mode="svg" />
Lass mal reden
</Button>
@ -16,246 +16,5 @@
</template>
<script setup lang="ts">
import type { RichText } from '@/components/RichText/Types'
type Skill = {
img: string
title: string
text: RichText[]
}
const getExplanationImage = (img : string) => getImage('/img/explanations/', img)
// const skills : Skill[] = [
// {
// img: 'components',
// title: 'Das, was du sehen kannst',
// text: [
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Die meisten Anwendungen haben eine grafische Benutzeroberfläche - die so genannte GUI. Wenn etwas graphisch ist, ' +
// 'dann bedeutet das auch natürlich, dass es sinnvoll dargestellt werden muss. Dafür verwenden wir kleine Bausteine, die wir Komponenten nennen.',
// }
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Grundsätzlich lassen sich komplette Anwendungen und auch einfache Webseiten ziemlich cool über Komponenten aufbauen, sodass wir wiederkehrende Elemente ' +
// 'wie Buttons, Textabschnitte, Links oder Teaser immer wieder verwenden können - selbst wenn sich diese in ihren Details wie Farben oder Icons unterscheiden.',
// }
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Diese Komponenten so zu entwickeln, dass sie wirklich flexibel sind und auch perfekt mit dem Design übereinstimmen ist gar nicht so einfach, denn oft sollten sie ' +
// 'auch mehr können als im Design kurzfristig ersichtlich ist.',
// }
// ]
// },
// {
// type: 'p',
// css: 'place-bottom bold',
// children: [
// {
// type: 'plain',
// content: 'Diese Voraussicht, für den Fall der Fälle vorzusorgen:',
// },
// {
// type: 'br',
// },
// {
// type: 'plain',
// content: 'Die gibt\'s bei mir dazu.',
// },
// {
// type: 'br',
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'Fussel-Ehrenwort.'
// }
// ]
// },
// ],
// }, {
// img: 'cms',
// title: 'Da, wo du eintragen kannst',
// text: [
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'In vielen Fällen ist es natürlich praktisch, wenn du einfach Inhalte einer Seite auf das ändern kannst, was gerade aktuell ist, ohne auf andere angewiesen zu sein.'
// + 'Damit das reibungslos möglich ist, entwickle ich dir gerne eine Anwendung oder Homepage, deren Inhalte du komplett selbst auf dem neuesten Stand halten kannst - und zwar '
// + 'mit einem sogenannten CMS - ein ',
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'C'
// },
// {
// type: 'plain',
// content: 'ontent '
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'M'
// },
// {
// type: 'plain',
// content: 'anagement '
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'S'
// },
// {
// type: 'plain',
// content: 'ystem.'
// },
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Für CMS setze ich in erster Linie auf die cloudbasierte Lösung ',
// },
// {
// type: 'a',
// target: '_blank',
// css: 'text',
// href: 'https://www.storyblok.com',
// content: 'Storyblok'
// },
// {
// type: 'plain',
// content: '. Dies stellt für die Meisten eine kostenlose bis kostengünstige Lösung dar ohne viel technisches Wissen mitbringen zu müssen.',
// }
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Falls du aber nicht möchtest, dass deine Daten auf irgendeinem Fremden server liegen - was ich durchaus verstehen kann! - dann gibt es auch die Möglichkeit mit ',
// },
// {
// type: 'a',
// target: '_blank',
// css: 'text',
// href: 'https://www.strapi.io',
// content: 'Strapi'
// },
// {
// type: 'plain',
// content: ' selbst das eigene CMS zu hosten. Das musst du dann aber allerdings selbst erledigen oder ich erledige das für dich für einen Aufpreis.',
// }
// ]
// },
// {
// type: 'p',
// css: 'place-bottom bold',
// children: [
// {
// type: 'plain',
// content: 'Nie wieder jemand anderen Fragen zu müssen, um deine Website auf dem neuesten Stand zu halten.',
// },
// {
// type: 'br',
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'Mit Fussel-Garantie.'
// }
// ]
// },
// ],
// }, {
// img: 'result',
// title: 'Was dabei am Ende rauskommt',
// text: [
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Grundsätzlich lässt sich das ganz einfach zusammenfassen: ',
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'Dein persönlicher Webauftritt.',
// }
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Ob du nun etwas kleineres brauchst, um ein paar Hobbies zu zeigen. Oder vielleicht etwas größeres, weil du dir ein eigenes Business aufbauen willst. Eventuell ein eigener Blog, eine komplette Applikation oder '
// + 'die Möglichkeit für andere Leute deine Daten bereit zu stellen. All das, das kann ich dir mit meinen Fähigkeiten und meiner Erfahrung bieten.'
// }
// ]
// },
// {
// type: 'p',
// children: [
// {
// type: 'plain',
// content: 'Erkunde einfach meine ',
// },
// {
// type: 'a',
// href: '/references',
// content: 'Referenzen'
// },
// {
// type: 'plain',
// content: ' und dir wird auffallen, dass diese äußerst durchmischt und bunt sind. So individuell wie die Projekte meiner bisherigen Kunden wird auch dein Projekt behandelt. Und auch, wenn '
// + 'du glaubst, dass die Referenzen nicht zu deinem Projekt passen, werden wir deine ganz individuelle Lösung gemeinsam erarbeiten.'
// }
// ]
// },
// {
// type: 'p',
// css: 'place-bottom bold',
// children: [
// {
// type: 'plain',
// content: 'Denn jedes Projekt ist etwas eigenes und besonderes.',
// },
// {
// type: 'br',
// },
// {
// type: 'span',
// css: 'highlight',
// content: 'Auch deins.'
// }
// ]
// },
// ],
// }
// ]
const skills = await queryCollection('skills').all()
</script>