Kiosk Template Prompt für v0
Für Touchscreen-Kioske – interaktive Displays in Shopping Centern. Für Center-Websites gibt es den Website Template Prompt.
Dein Design-Creator-Moment
Einfach kopieren, einfügen, fertig. v0 übernimmt die Technik – du entscheidest über das Design.
So geht's (3 Schritte)
- Öffne v0 – v0.dev → Neuer Chat
- Kopiere den gesamten Prompt aus dem Block unten (ab „TASK“) und füge ihn ein
- Optional: Füge deine Ideen hinzu – z. B. „große Touch-Buttons“, „Glassmorphism“, „helles Theme“, „coole Übergänge“
Tipp: Starte einfach mit dem Prompt. Wenn dir etwas nicht gefällt, sag v0 „mach die Buttons größer“ oder „andere Farben“. Du kannst jederzeit nachjustieren – das macht den Prozess aus.
Prompt kopieren und in v0 einfügen
Klicke auf den Button oben – der gesamte Prompt wird kopiert. Oder markiere den Block unten mit Strg/Cmd+A und kopiere manuell.
TASK: Erstelle ein interaktives Kiosk-Template für Touchscreen-Displays in Shopping Centern – mit Home-Screen, Quick-Links (Shops, Centerplan, Services, Aktuelles) und Screen-Navigation. Technik: Next.js 14, TypeScript, Tailwind CSS, Framer Motion.
CONTEXT: Das Template wird in CockpitOS Digital Signage eingebunden. Alle Inhalte (Name, Logo, Shops, Events) kommen dynamisch aus Props – nichts hardcoden. Touch-optimiert (große Buttons)!
DEIN FREIRAUM: Layout, Farben, Glassmorphism, Animationen – alles deine Wahl! Experimentiere ruhig. Wichtig ist nur die korrekte Datenstruktur und Screen-Navigation.
---
## TECHNISCHE PUNKTE (minimal)
- Client Component (`'use client'`) – für Touch
- Alle Inhalte aus Props (config, shops, services, content) – keine Hardcodes
- Screens: Home, Shops, Shop Detail, Centerplan, Services, Aktuelles
- next/image, große Touch-Targets (min. 60px), Fallbacks für leere Daten
---
## STRUKTUR
- KioskTemplate.tsx (Haupt-Component), screens/ (HomeScreen, ShopsScreen, ShopDetailScreen, CenterplanScreen, ServicesScreen, AktuellesScreen)
- Props: config (centerName, logo, colors, theme), shops[], services[], content[] (News/Events/Offers)
- Details siehe Technische Details unten (für Entwickler)
---
## ZUSAMMENFASSUNG
Erstelle ein Touch-Kiosk-Template mit Screens (Home, Shops, Centerplan, Services, Aktuelles). Client Component, Props für config/shops/services/content. Große Buttons, Fallbacks. Nach Export: CockpitOS-Entwickler integrieren.
Viel Erfolg!
Technische Details (für Entwickler – nicht in v0 kopieren)
Interfaces, Code-Beispiele, Integration
SCREEN-KOMPONENTEN
Beispiel: HomeScreen
// screens/HomeScreen.tsx
'use client';
import Image from 'next/image';
import Link from 'next/link';
import type { KioskConfig, Shop } from '../types';
interface HomeScreenProps {
config: KioskConfig;
shops: Shop[];
onNavigate: (screen: any) => void;
}
export function HomeScreen({ config, shops, onNavigate }: HomeScreenProps) {
return (
<div className="h-full flex flex-col">
{/* Hero Section */}
<div className="relative h-[40vh] flex items-center justify-center">
{config.heroImage && (
<Image
src={config.heroImage}
alt={config.centerName}
fill
className="object-cover"
/>
)}
<div className="relative z-10 text-center text-white">
<h1 className="text-5xl font-bold mb-4">{config.welcomeText || 'Willkommen'}</h1>
<p className="text-2xl">{config.welcomeSubtext || 'Schön, dass du da bist!'}</p>
</div>
</div>
{/* Quick Links */}
<div className="flex-1 grid grid-cols-2 gap-6 p-8">
<button
onClick={() => onNavigate({ type: 'shops' })}
className="p-8 rounded-2xl text-white text-2xl font-bold transition-transform hover:scale-105"
style={{ backgroundColor: config.quickLinkColors?.shops || config.colors?.primary }}
>
Shops
</button>
<button
onClick={() => onNavigate({ type: 'centerplan' })}
className="p-8 rounded-2xl text-white text-2xl font-bold transition-transform hover:scale-105"
style={{ backgroundColor: config.quickLinkColors?.centerplan || config.colors?.primary }}
>
Centerplan
</button>
<button
onClick={() => onNavigate({ type: 'services' })}
className="p-8 rounded-2xl text-white text-2xl font-bold transition-transform hover:scale-105"
style={{ backgroundColor: config.quickLinkColors?.services || config.colors?.primary }}
>
Services
</button>
<button
onClick={() => onNavigate({ type: 'aktuelles' })}
className="p-8 rounded-2xl text-white text-2xl font-bold transition-transform hover:scale-105"
style={{ backgroundColor: config.quickLinkColors?.aktuelles || config.colors?.primary }}
>
Aktuelles
</button>
</div>
</div>
);
}
5. LINKS & BILDER (Next.js Best Practices)
Links
// RICHTIG: Für Navigation zwischen Screens verwende onNavigate Callback
onNavigate({ type: 'shops' })
// RICHTIG: Externe Links mit <a>
<a
href={shop.website}
target="_blank"
rel="noopener noreferrer"
>
Website
</a>
Bilder
// RICHTIG: next/image für alle Bilder
import Image from 'next/image';
<Image
src={config.logo || '/placeholder-logo.png'}
alt={config.centerName}
width={200}
height={60}
className="h-12 w-auto"
/>
6. DESIGN-GUIDELINES
Glassmorphism (wenn aktiviert)
{config.glassmorphism && (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
{/* Content */}
</div>
)}
Touch-Optimierung
// Große Touch-Targets (mindestens 44x44px)
<button className="min-h-[60px] min-w-[60px] p-4">
{/* Touch-optimiert */}
</button>
Animations (wenn aktiviert)
import { motion } from 'framer-motion';
{config.animations && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
{/* Content */}
</motion.div>
)}
7. DATEN-FALLBACKS (MUSS implementiert werden)
// Keine Shops → Alternative Content zeigen
{shops.length === 0 ? (
<div className="p-8 text-center">
<p className="text-xl">Aktuell keine Shops verfügbar</p>
<button onClick={() => onNavigate({ type: 'services' })}>
Zu den Services
</button>
</div>
) : (
<ShopGrid shops={shops} />
)}
// Kein Hero-Image → Gradient + Pattern
{!config.heroImage ? (
<div
className="absolute inset-0 bg-gradient-to-br"
style={{
background: `linear-gradient(135deg, ${config.colors?.primary} 0%, ${config.colors?.accent || config.colors?.primary} 100%)`
}}
/>
) : (
<Image src={config.heroImage} ... />
)}
8. CHECKLISTE (für CockpitOS-Kompatibilität)
- Client Component (
'use client') - Modulare Screens (Home, Shops, Centerplan, Services, Aktuelles)
- next/image, keine hardcoded Daten
- Touch-optimiert (große Buttons)
- Fallbacks für leere States
- Glassmorphism & Animations optional
- Responsive für verschiedene Kiosk-Größen
9. OUTPUT-ANFORDERUNGEN
FILES
components/templates/kiosk-[template-name]/
├── index.ts
├── KioskTemplate.tsx
├── config.ts
├── screens/
│ ├── HomeScreen.tsx
│ ├── ShopsScreen.tsx
│ ├── ShopDetailScreen.tsx
│ ├── CenterplanScreen.tsx
│ ├── ServicesScreen.tsx
│ ├── AktuellesScreen.tsx
│ └── AktuellesDetailScreen.tsx
├── components/
│ ├── Header.tsx
│ └── Footer.tsx
├── types.ts
└── README.md
DATA_REQUIREMENTS.md
# Daten-Anforderungen für Kiosk Template [Template-Name]
## Zwingend erforderlich (MUSS befüllt sein)
- config.centerName
- config.colors.primary
- shops[] (mindestens 1 Shop)
- services[] (mindestens 1 Service)
- content[] (mindestens 1 Content-Item)
## Optional (empfohlen)
- config.logo
- config.heroImage oder config.heroMedia
- config.backgroundGradient
- config.quickLinkColors
- config.glassmorphism (default: true)
- config.animations (default: true)
## Defaults (werden verwendet wenn nicht vorhanden)
- Logo: /placeholder-logo.png
- Hero: Gradient mit Primary-Farbe
- Theme: dark
- Glassmorphism: true
- Animations: true
10. Bitte vermeiden
- API-Calls (Daten kommen als Props)
- Hardcoded Inhalte
- Externe Dependencies außer Next.js, React, Tailwind, Framer Motion
- Lorem-Ipsum-Texte (visuelle Fallbacks OK)
11. ZUSAMMENFASSUNG
Erstelle ein visuell fertiges, interaktives Kiosk-Template mit:
- Props-Interface (KioskConfig, shops, services, content)
- Client Component (für Touch)
- Modularen Screens (Home, Shops, Centerplan, Services, Aktuelles)
- next/image, Touch-optimierte Buttons
- DATA_REQUIREMENTS.md + IMPLEMENTATION_NOTES.md
- Responsive für verschiedene Kiosk-Größen
Layout und Stil sind frei wählbar – Hauptsache, die Daten kommen aus Props und es funktioniert in CockpitOS.
Beispiel: Minimales Kiosk-Template-Scaffold
// KioskTemplate.tsx
'use client';
import { useState } from 'react';
import { HomeScreen } from './screens/HomeScreen';
import { ShopsScreen } from './screens/ShopsScreen';
import type { KioskTemplateProps } from './types';
import { defaultConfig } from './config';
type Screen = { type: 'home' } | { type: 'shops' };
export function KioskTemplate({
config: configOverride,
shops = [],
services = [],
content = [],
kioskConfig
}: KioskTemplateProps) {
const config = { ...defaultConfig, ...configOverride, ...kioskConfig };
const [currentScreen, setCurrentScreen] = useState<Screen>({ type: 'home' });
const navigateTo = (screen: Screen) => {
setCurrentScreen(screen);
};
return (
<div className="h-screen w-screen">
{currentScreen.type === 'home' && (
<HomeScreen config={config} shops={shops} onNavigate={navigateTo} />
)}
{currentScreen.type === 'shops' && (
<ShopsScreen shops={shops} onNavigate={navigateTo} />
)}
</div>
);
}
Das Template wird dann nahtlos in CockpitOS integriert und kann pro Center konfiguriert werden.
12. HÄUFIGE FEHLER & WIE MAN SIE VERMEIDET
Fehler 1: Server Component statt Client Component
// FALSCH - Website Template verwendet Server Component
export function KioskTemplate(...) { // Kein 'use client'
// RICHTIG - Kiosk Template MUSS Client Component sein
'use client';
export function KioskTemplate(...) {
Fehler 2: Hardcoded Inhalte
// FALSCH - Hardcoded Text
<h1>Willkommen im Palais Vest</h1>
// RICHTIG - Aus Config
<h1>{config.welcomeText || 'Willkommen'}</h1>
Fehler 3: Zu kleine Touch-Targets
// FALSCH - Zu klein für Touch
<button className="p-2">Klick</button>
// RICHTIG - Mindestens 44x44px
<button className="min-h-[60px] min-w-[60px] p-4 text-xl">
Klick
</button>
Fehler 4: Keine Fallbacks für fehlende Daten
// FALSCH - Leerer State wenn keine Shops
<ShopGrid shops={shops} />
// RICHTIG - Fallback implementiert
{shops.length > 0 ? (
<ShopGrid shops={shops} />
) : (
<div className="p-8 text-center">
<p className="text-xl mb-4">Aktuell keine Shops verfügbar</p>
<button onClick={() => onNavigate({ type: 'services' })}>
Zu den Services
</button>
</div>
)}
13. BEST PRACTICES FÜR SCREENS
HomeScreen mit Hero & Quick Links
// screens/HomeScreen.tsx
'use client';
import Image from 'next/image';
import type { KioskConfig, Shop } from '../types';
interface HomeScreenProps {
config: KioskConfig;
shops: Shop[];
onNavigate: (screen: any) => void;
}
export function HomeScreen({ config, shops, onNavigate }: HomeScreenProps) {
return (
<div className="h-full flex flex-col">
{/* Hero Section */}
<div className="relative h-[40vh] flex items-center justify-center">
{config.heroImage ? (
<Image
src={config.heroImage}
alt={config.centerName}
fill
className="object-cover"
priority
/>
) : (
<div
className="absolute inset-0 bg-gradient-to-br"
style={{
background: `linear-gradient(135deg, ${config.colors?.primary} 0%, ${config.colors?.accent || config.colors?.primary} 100%)`
}}
/>
)}
<div className="relative z-10 text-center text-white px-4">
<h1 className="text-5xl md:text-6xl font-bold mb-4">
{config.welcomeText || 'Willkommen'}
</h1>
<p className="text-2xl md:text-3xl">
{config.welcomeSubtext || 'Schön, dass du da bist!'}
</p>
</div>
</div>
{/* Quick Links - Touch-optimiert */}
<div className="flex-1 grid grid-cols-2 gap-6 p-8">
<button
onClick={() => onNavigate({ type: 'shops' })}
className="
min-h-[120px]
p-8
rounded-2xl
text-white
text-2xl
font-bold
transition-transform
hover:scale-105
active:scale-95
focus:outline-none
focus:ring-4
focus:ring-white/50
"
style={{ backgroundColor: config.quickLinkColors?.shops || config.colors?.primary }}
aria-label="Zu den Shops navigieren"
>
Shops
</button>
{/* Weitere Quick Links... */}
</div>
</div>
);
}
ShopsScreen mit Filter & Suche
// screens/ShopsScreen.tsx
'use client';
import { useState } from 'react';
import Image from 'next/image';
import type { Shop } from '../types';
interface ShopsScreenProps {
shops: Shop[];
onNavigate: (screen: any) => void;
}
export function ShopsScreen({ shops, onNavigate }: ShopsScreenProps) {
const [searchTerm, setSearchTerm] = useState('');
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const filteredShops = shops.filter(shop => {
const matchesSearch = shop.name.toLowerCase().includes(searchTerm.toLowerCase());
const matchesCategory = !selectedCategory || shop.category === selectedCategory;
return matchesSearch && matchesCategory;
});
const categories = Array.from(new Set(shops.map(s => s.category).filter(Boolean)));
return (
<div className="h-full flex flex-col">
{/* Header */}
<header className="p-6 bg-white/10 backdrop-blur-xl border-b border-white/20">
<h2 className="text-3xl font-bold text-white mb-4">Shops</h2>
{/* Suche */}
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Shop suchen..."
className="
w-full
p-4
text-lg
rounded-xl
bg-white/20
backdrop-blur-sm
border border-white/30
text-white
placeholder-white/60
focus:outline-none
focus:ring-2
focus:ring-white/50
"
/>
{/* Kategorien-Filter */}
{categories.length > 0 && (
<div className="flex gap-2 mt-4 flex-wrap">
<button
onClick={() => setSelectedCategory(null)}
className={`
px-4 py-2 rounded-lg text-sm font-semibold transition-colors
${selectedCategory === null
? 'bg-white text-primary'
: 'bg-white/20 text-white hover:bg-white/30'
}
`}
>
Alle
</button>
{categories.map(cat => (
<button
key={cat}
onClick={() => setSelectedCategory(cat)}
className={`
px-4 py-2 rounded-lg text-sm font-semibold transition-colors
${selectedCategory === cat
? 'bg-white text-primary'
: 'bg-white/20 text-white hover:bg-white/30'
}
`}
>
{cat}
</button>
))}
</div>
)}
</header>
{/* Shop-Liste */}
<div className="flex-1 overflow-y-auto p-6">
{filteredShops.length === 0 ? (
<div className="text-center py-12">
<p className="text-xl text-white/80">Keine Shops gefunden</p>
</div>
) : (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{filteredShops.map(shop => (
<button
key={shop.id}
onClick={() => onNavigate({ type: 'shop-detail', shop })}
className="
group
relative
aspect-square
rounded-2xl
overflow-hidden
bg-white/10
backdrop-blur-sm
border border-white/20
transition-all
hover:scale-105
active:scale-95
focus:outline-none
focus:ring-4
focus:ring-white/50
"
aria-label={`${shop.name} öffnen`}
>
{shop.logo ? (
<Image
src={shop.logo}
alt={shop.name}
fill
className="object-contain p-4"
/>
) : (
<div className="h-full flex items-center justify-center">
<span className="text-white text-lg font-semibold">{shop.name}</span>
</div>
)}
</button>
))}
</div>
)}
</div>
</div>
);
}
14. GLASSMORPHISM & ANIMATIONS
Glassmorphism-Effekt
// Glassmorphism-Komponente
{config.glassmorphism && (
<div className="
bg-white/10
backdrop-blur-xl
border border-white/20
rounded-2xl
p-6
shadow-xl
">
{/* Content */}
</div>
)}
Framer Motion Animations
import { motion, AnimatePresence } from 'framer-motion';
{config.animations && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
{/* Content */}
</motion.div>
)}
// Screen-Transitions
<AnimatePresence mode="wait">
{currentScreen.type === 'home' && (
<motion.div
key="home"
initial={{ opacity: 0, x: -100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 100 }}
transition={{ duration: 0.3 }}
>
<HomeScreen {...props} />
</motion.div>
)}
</AnimatePresence>
15. TOUCH-OPTIMIERUNG
Große Touch-Targets
// Mindestens 60x60px für Kiosk-Buttons
<button className="
min-h-[60px]
min-w-[60px]
p-4
text-xl
font-semibold
rounded-xl
transition-transform
active:scale-95
">
Touch-Button
</button>
Hover & Active States
// Hover für Desktop, Active für Touch
<button className="
transition-all
hover:scale-105
active:scale-95
focus:outline-none
focus:ring-4
focus:ring-primary/50
">
Button
</button>
Swipe-Gesten (optional)
// Mit react-swipeable oder ähnlicher Library
import { useSwipeable } from 'react-swipeable';
const handlers = useSwipeable({
onSwipedLeft: () => onNavigate({ type: 'next-screen' }),
onSwipedRight: () => onNavigate({ type: 'previous-screen' }),
});
<div {...handlers}>
{/* Swipeable Content */}
</div>
16. PERFORMANCE-OPTIMIERUNGEN
Lazy Loading für Screens
// Screens dynamisch laden
const ShopsScreen = dynamic(() => import('./screens/ShopsScreen'), {
loading: () => <LoadingScreen />
});
const ServicesScreen = dynamic(() => import('./screens/ServicesScreen'), {
loading: () => <LoadingScreen />
});
Bild-Optimierung
// Priority nur für Hero-Bilder
<Image
src={config.heroImage}
alt={config.centerName}
fill
priority // Nur für Above-the-Fold
/>
// Lazy Loading für Shop-Logos
<Image
src={shop.logo}
alt={shop.name}
fill
loading="lazy" // Für Listen
/>
17. ACCESSIBILITY FÜR KIOSKS
Keyboard-Navigation
// Keyboard-Navigation zwischen Screens
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
if (e.key === 'ArrowLeft') {
// Vorheriger Screen
} else if (e.key === 'ArrowRight') {
// Nächster Screen
} else if (e.key === 'Escape') {
// Zurück zum Home
onNavigate({ type: 'home' });
}
};
window.addEventListener('keydown', handleKeyPress);
return () => window.removeEventListener('keydown', handleKeyPress);
}, []);
ARIA-Labels für Touch-Interaktionen
<button
onClick={() => onNavigate({ type: 'shops' })}
aria-label="Zu den Shops navigieren"
aria-pressed={currentScreen.type === 'shops'}
>
Shops
</button>
Focus-Management
// Focus auf ersten Button nach Screen-Wechsel
useEffect(() => {
if (currentScreen.type === 'shops') {
const firstButton = document.querySelector('[data-shop-button]');
if (firstButton instanceof HTMLElement) {
firstButton.focus();
}
}
}, [currentScreen]);
18. FINALE CHECKLISTE VOR DEM EXPORT
Bevor du das Template exportierst, prüfe:
- Client Component (
'use client'im Haupt-Template) - Alle Texte kommen aus Config/Props (keine Hardcodes)
- Touch-optimiert (mindestens 60x60px Buttons)
- Fallbacks für alle optionalen Daten implementiert
- Glassmorphism unterstützt (wenn in Config aktiviert)
- Animations unterstützt (wenn in Config aktiviert)
- Responsive Design (verschiedene Kiosk-Größen)
- Keyboard-Navigation funktioniert
- Screen-Transitions smooth
- Performance optimiert (Lazy Loading, Bild-Optimierung)
- DATA_REQUIREMENTS.md erstellt
- IMPLEMENTATION_NOTES.md erstellt
- README.md mit Template-Beschreibung erstellt
Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /en/templates/kiosk-prompt