dml_frontend/components/SchemaCoder.vue
2025-06-03 09:18:45 +02:00

180 lines
4.9 KiB
Vue

<template>
<div class="schema-typer">
<span class="token-tag">&lt;<span class="token-tag-name">script</span> <span class="token-attr">type</span>=<span class="token-string">"application/ld+json"</span>&gt;</span><br >
<span
v-for="(line, lineIndex) in displayedLines"
:key="lineIndex"
class="code-line"
>
<template v-for="(segment, index) in line" :key="index">
<span :class="segment.class">{{ segment.text }}</span>
</template>
<template v-if="(lineIndex === currentLine || (isTypingDone && lineIndex === displayedLines.length - 1)) && showCursor">
<span class="cursor">|</span>
</template>
<br >
</span>
<span class="token-tag">&lt;/<span class="token-tag-name">script</span>&gt;</span>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const schema = `{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "So machen wir deine Website KI-kompatibel",
"description": "Wir optimieren deine Website gezielt für künstliche Intelligenz. Strukturiert, effizient und zukunftssicher.",
"step1": "Wir integrieren strukturierte Daten nach schema.org, damit KI-Systeme Inhalte korrekt interpretieren können.",
"step2": "Wir überarbeiten den Quellcode mit semantischem HTML und klaren Überschriften zur besseren maschinellen Lesbarkeit.",
"step3": "Wir stellen relevante Inhalte zusätzlich in maschinenfreundlichen Formaten wie JSON-LD oder über APIs bereit.",
"step4": "Wir sorgen für barrierefreie Gestaltung und klare Sprache, so verstehen auch KI-Sprachmodelle deine Inhalte besser.",
"step5": "Wir ergänzen deine Seiten mit Metadaten wie OpenGraph, Twitter Cards und Robots-Tags für optimalen Kontext.",
"estimatedTime": "ca. 45 Minuten Analyse + Umsetzung je nach Umfang",
"image": "/images/ki-optimierung.jpg"
}`
function parseLine(line) {
const segments = []
const regex = /("[^"]+":)|("[^"]+")|(\d+)|(true|false|null)|(\s+|[{}[\],:])/g
let match
let lastIndex = 0
while ((match = regex.exec(line)) !== null) {
const start = match.index
if (start > lastIndex) {
segments.push({ text: line.slice(lastIndex, start), class: 'token-text' })
}
const [matched, key, str, num, bool, symbol] = match
let cls = 'token-text'
if (key) cls = 'token-key'
else if (str) cls = 'token-string'
else if (num) cls = 'token-number'
else if (bool) cls = 'token-boolean'
else if (symbol) cls = 'token-text'
segments.push({ text: matched, class: cls })
lastIndex = start + matched.length
}
if (lastIndex < line.length) {
segments.push({ text: line.slice(lastIndex), class: 'token-text' })
}
return segments
}
const lines = schema.split('\n').map(parseLine)
const displayedLines = ref([])
const showCursor = ref(true)
const currentLine = ref(0)
const isTypingDone = ref(false)
const startTyping = () => {
let lineIndex = 0
let charIndex = 0
displayedLines.value.push([])
const typeChar = () => {
if (lineIndex >= lines.length) {
isTypingDone.value = true
return
}
const segment = lines[lineIndex][charIndex]
if (segment) {
displayedLines.value[lineIndex].push(segment)
charIndex++
} else {
lineIndex++
charIndex = 0
currentLine.value = lineIndex
if (lineIndex < lines.length) displayedLines.value.push([])
}
setTimeout(typeChar, Math.random() * 80 + 40)
}
typeChar()
setInterval(() => (showCursor.value = !showCursor.value), 500)
}
onMounted(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
observer.disconnect()
startTyping()
}
}, { threshold: 0.3 })
const el = document.querySelector('.schema-typer')
if (el) observer.observe(el)
})
</script>
<style lang="sass" scoped>
.schema-typer
background-color: #1e1e1e
padding: 1.5rem
margin: 2rem
border-radius: 0.5rem
font-family: monospace
font-size: 0.7rem
color: #ffffff
overflow-x: auto
overflow-y: auto
line-height: 1.4
height: auto
min-height: 450px
width: 400px
transform: rotate(6deg)
box-shadow: -3px 3px 6px 4px grey
span
margin: 0
padding: 0
.code-line
display: block
line-height: 1.2
.token-tag
color: #569cd6
.token-tag-name
color: #4ec9b0
.token-attr
color: #c586c0
.token-key
color: #9cdcfe
margin-left: 1rem
.token-string
color: #ce9178
.token-number
color: #b5cea8
.token-boolean
color: #dcdcaa
.token-text
color: #d4d4d4
margin-left: .2rem
.cursor
display: inline-block
width: 1ch
background-color: white
animation: blink 1s steps(2, start) infinite
@keyframes blink
to
visibility: hidden
</style>