Files
kontextwerk/frontend/src/lib/components/staticPageRows/VoicebotPreview.svelte
2025-10-05 12:55:59 +00:00

164 lines
4.8 KiB
Svelte

<script lang="ts">
import { onMount } from "svelte"
import { mdiBookAccountOutline, mdiCreation, mdiFaceAgent, mdiHours24 } from "@mdi/js"
import ProductCategoryFrame from "../widgets/ProductCategoryFrame.svelte"
import CrinkledSection from "../CrinkledSection.svelte"
import { createVoicebotPreviewController } from "./voicebotPreviewController"
const voiceProperties: Array<{ title: string; icon: string; color: string }> = [
{
title: "24/7 Verfügbar",
icon: mdiHours24,
color: "var(--text-reverse-100)",
},
{
title: "Individuell",
icon: mdiFaceAgent,
color: "#EB5757",
},
{
title: "DSGVO konform",
icon: mdiBookAccountOutline,
color: "var(--text-reverse-100)",
},
{
title: "Intelligent",
icon: mdiCreation,
color: "#EB5757",
},
]
const controller = createVoicebotPreviewController()
const { status, statusHint, toggle, setup, teardown } = controller
const handleKeydown = (event: KeyboardEvent) => {
if (event.key !== "Enter" && event.key !== " ") return
event.preventDefault()
void toggle()
}
onMount(() => {
setup()
return () => teardown()
})
</script>
<CrinkledSection
brightBackground={true}
border={true}
activated={true}
>
{#snippet contentSnippet()}
<ProductCategoryFrame
properties={voiceProperties}
title="Voicebot Demo"
upperDescription="Unsere Voicebots sind rund um die Uhr für Ihre Kunden da und bieten maßgeschneiderte Lösungen, die perfekt auf Ihre Bedürfnisse abgestimmt sind."
lowerDescription="Durch den Einsatz modernster KI-Technologien gewährleisten wir eine intelligente und effiziente Kommunikation, die den höchsten Datenschutzstandards entspricht."
>
{#snippet primaryContent()}
<div
class="img"
class:connected={$status === "connected"}
class:errored={$status === "error"}
role="button"
tabindex="0"
aria-pressed={$status === "connected"}
aria-busy={$status === "connecting"}
aria-label="Voicebot Demo starten"
on:click={() => void toggle()}
on:keydown={handleKeydown}
>
<img
src="/media/iphone.png"
alt="Kontextwerk is calling"
/>
<div class="shadow"></div>
<div
class="voice-overlay"
data-status={$status}
aria-live="polite"
>
<span>{$statusHint}</span>
</div>
</div>
{/snippet}
</ProductCategoryFrame>
{/snippet}
</CrinkledSection>
<style lang="less">
.img {
position: relative;
width: 400px;
min-width: 400px;
max-height: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
border-radius: 1.6rem;
transition:
transform 0.2s ease,
border-color 0.2s ease;
outline: none;
img {
width: 60% !important;
height: 100%;
object-fit: contain;
pointer-events: none;
user-select: none;
}
.voice-overlay {
position: absolute;
bottom: 1.2rem;
left: 50%;
transform: translateX(-50%);
padding: 0.45rem 1.1rem;
border-radius: 999px;
background: rgba(13, 12, 12, 0.8);
color: white;
font-size: 0.8rem;
font-weight: 500;
letter-spacing: 0.01em;
display: flex;
align-items: center;
gap: 0.4rem;
pointer-events: none;
white-space: nowrap;
transition:
background 0.2s ease,
color 0.2s ease;
}
.voice-overlay[data-status="connected"] {
background: rgba(76, 175, 80, 0.85);
}
.voice-overlay[data-status="connecting"] {
background: rgba(255, 152, 0, 0.85);
}
.voice-overlay[data-status="error"] {
background: rgba(235, 87, 87, 0.9);
}
&:hover {
transform: translateY(-4px);
}
&.connected {
}
&.errored {
}
&:focus-visible {
outline: 2px solid var(--primary-200);
outline-offset: 4px;
}
}
</style>