wf4/app/components/SkillsEasy.vue
webfussel 932796aef1 ADD: richtext system
Added richtext system for better card content.
2025-02-21 14:31:35 +01:00

206 lines
6.6 KiB
Vue

<template>
<section id="skills_easy" class="Skills content">
<h2>Jetzt mal ganz konkret.</h2>
<h3>In diesem Abschnitt jetzt mal ganz <span class="highlight">ohne Technik-Blabla</span>.</h3>
<div class="flex-col margin-top gap-default">
<article class="z-2 card flex-row gap-default" v-for="(skill, skillIndex) in skills" :class="[skillIndex % 2 && 'reverse']">
<img :src="skill.img" alt="" class="card-img z-4" />
<div class="flex-col gap-default">
<h3>{{skill.title}}</h3>
<main class="flex-col gap-sm">
<component v-for="({type, content, ...rest}) in skill.text" :is="type" v-bind="rest">
{{ content}}
<template v-if="'children' in rest && rest.children">
<template v-for="({type, content, ...childRest}, childIndex) in rest.children" :key="childIndex">
<template v-if="type === 'text'">
{{ content }}
</template>
<template v-else-if="type === 'a'">
<component :is="type" v-bind="childRest" class="inline-flex-row">
{{ content}} <Icon v-if="'icon' in childRest && childRest.icon" :name="childRest.icon.name" mode="svg" :class="childRest.icon.position === 'end' && 'reverse'" />
</component>
</template>
<template v-else>
<component :is="type" v-bind="childRest">
{{ content}}
</component>
</template>
</template>
</template>
</component>
</main>
</div>
</article>
</div>
</section>
</template>
<script setup lang="ts">
type RichTextBase = {
type: 'text'
content: string
}
type RichTextSimple = {
type: 'p' | 'span'
content: string
class ?: string
children ?: RichText[]
}
type RichTextLink = {
type: 'a'
content: string
href: string
icon ?: {
name: string
position : 'start' | 'end'
}
target ?: string
class ?: string
}
type RichText = RichTextBase | RichTextSimple | RichTextLink
type Skill = {
img: string
title: string
text: RichText[]
}
const skills : Skill[] = [
{
img: 'https://picsum.photos/550/350.webp?random=1',
title: 'Das, was du sehen kannst',
text: [
{
type: 'p',
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',
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',
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',
class: 'margin-top bold',
content: 'Diese Voraussicht, für den Fall der Fälle vorzusorgen: Die gibt\'s bei mir dazu.',
children: [
{
type: 'span',
class: 'highlight',
content: 'Fussel-Ehrenwort.'
}
]
},
],
}, {
img: 'https://picsum.photos/550/350.webp?random=2',
title: 'Da, wo du eintragen kannst',
text: [
{
type: 'p',
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 ',
children: [
{
type: 'span',
class: 'highlight',
content: 'C'
},
{
type: 'text',
content: 'ontent '
},
{
type: 'span',
class: 'highlight',
content: 'M'
},
{
type: 'text',
content: 'anagement '
},
{
type: 'span',
class: 'highlight',
content: 'S'
},
{
type: 'text',
content: 'ystem.'
},
]
},
{
type: 'p',
content: 'Für CMS setze ich in erster Linie auf die cloudbasierte Lösung ',
children: [
{
type: 'a',
target: '_blank',
class: 'text',
href: 'https://www.storyblok.com',
icon: {
name: 'ph:arrow-square-out-duotone',
position: 'end',
},
content: 'Storyblok'
},
{
type: 'text',
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',
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 ',
children: [
{
type: 'a',
target: '_blank',
class: 'text',
href: 'https://www.strapi.io',
icon: {
name: 'ph:arrow-square-out-duotone',
position: 'end',
},
content: 'Strapi'
},
{
type: 'text',
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',
class: 'margin-top bold',
content: 'Nie wieder jemand anderen Fragen zu müssen, um deine Website auf dem neuesten Stand zu halten.',
children: [
{
type: 'span',
class: 'highlight',
content: 'Mit Fussel-Garantie.'
}
]
},
],
}, {
img: 'https://picsum.photos/550/350.webp?random=3',
title: 'Was dabei am Ende rauskommt',
text: [
],
}
]
</script>