Zum Inhalt springen
UI Kit
Accent

Flip Cards als Wendekarten

Karten mit Vorder- und Rückseite, die sich in 3D umdrehen, per Hover, Klick, Tippen oder Tastatur. Die verdeckte Seite ist inert, beide Seiten teilen sich eine Zelle, nichts springt, und bei reduzierter Bewegung wird überblendet.

5 VariantsEine von 6 Components in 3D-Flächen

Zwei Seiten, eine ruhige Karte

Eine Wendekarte hält die Vorderseite kurz und legt die Details auf die Rückseite. Diese drehen sich in 3D per Hover, Klick, Tippen oder Tastatur, und die verdeckte Seite ist inert, Screenreader und Tabulator treffen also nur die sichtbare Seite. Beide Seiten teilen sich eine Zelle, das Raster drumherum bleibt still, bei reduzierter Bewegung wird überblendet.

„Team zum Umdrehen“ dreht Porträts zu einer kurzen Bio mit Kontaktlink. „Mythos oder Fakt“ dreht Fragen zu ihrer Antwort, markiert als Mythos oder Fakt, gut für Einwände oder ein Quiz. „Produkte mit Details“ wendet Bild, Name und Preis zu Eckdaten und Knopf. „Zahlen, die hochklappen“ klappen nach oben wie eine Bahnhofstafel und zeigen, was hinter einer Zahl steht. Der „Gutschein“ dreht einen großen Gutschein zu Code und drei Schritten zum Einlösen.

Schreib die Vorderseite als Frage oder Aufhänger, die Rückseite als Antwort. Halte beide Seiten ähnlich lang, dann wirken die Karten gleichmäßig. Am Handy dreht ein Tippen die Karte, zeig also deutlich, dass es eine Rückseite gibt.

Variants

Team zum UmdrehenNeu in 1.2

Porträts, die sich beim Hover zu einer kurzen Vorstellung mit Kontaktlink drehen. Tippen oder Enter dreht sie auch, Escape dreht zurück.

Mythos oder FaktNeu in 1.2

Fragen, die sich per Klick zu ihrer Antwort drehen, markiert als Mythos oder Fakt. Gut für Einwände, ein Quiz oder FAQ mit Spieltrieb.

Produkte mit DetailsNeu in 1.2

Ein Bild mit Name und Preis dreht sich zu seinen Details, einer kurzen Liste und dem Knopf. Die Karte behält ihre Größe, das Raster darunter bleibt ruhig.

Zahlen, die hochklappenNeu in 1.2

Große Zahlen, die per Klick nach oben klappen und zeigen, was dahinter steht. Die Drehung nach oben liest sich wie eine Anzeigetafel.

GutscheinNeu in 1.2

Ein großer Gutschein im Akzent. Ein Klick dreht ihn zum Code und drei Schritten zum Einlösen, der Knopf zum Zurückdrehen bleibt in seiner Ecke.

Details

Was Wendekarten mitbringt, aus Registry und Quellcode gelesen.

Kategorie
3D-Flächen
Bereich
Visuals
Variants
5
Version
1.0.0 · seit 1.2.0
Datei
components/ui/flip-card.tsx
Bringt mit
utilskitsectionbuttoniconrevealmotiondepth
npm-Pakete
Keine
Sprachen
Englisch und Deutsch, 7 eigene Texte
Studio
Im Code anpassen

Props

Die Schnittstelle FlipCardsProps aus components/ui/flip-card.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch. Nimmt außerdem alle Props von Omit<React.HTMLAttributes<HTMLElement>, 'title'> an.

  • variantoptional
    FlipCardsVariant

    teamfactsproductstatsgift

  • eyebrowoptional
    string
  • titleoptional
    React.ReactNode
  • descriptionoptional
    string
  • itemsPflicht
    FlipItem[]
  • mediaoptional
    React.ReactNode[]

    team: portraits; product: pictures; gift: the design on the front

  • actionoptional
    { label: string; href?: string }

    product, gift: the button on the back

  • triggeroptional
    'hover' | 'click'

    Override how the cards turn

Eingebaute Texte

Diese Texte schreibt Wendekarten selbst. Die Sprache folgt dem KitProvider, über die Prop labels ersetzt du einzelne.

Alle 7 Texte anzeigen
turnEnglisch Turn overDeutsch Umdrehen
turnBackEnglisch Turn backDeutsch Zurückdrehen
mythEnglisch MythDeutsch Mythos
factEnglisch FactDeutsch Stimmt
redeemEnglisch How to redeemDeutsch So löst du ein
codeEnglisch CodeDeutsch Code
mailEnglisch Write an emailDeutsch E-Mail schreiben

Barrierefreiheit

Aus dem Quellcode der Component abgeleitet.

  • Wendekarten reagiert selbst auf die Tasten Escape.
  • Setzt aria-expanded, damit Screenreader Zweck und Zustand ansagen.
  • Ergänzt Text für Screenreader, wo Icons und Grafiken allein stehen.
  • Zeigt bei Bedienung mit der Tastatur einen sichtbaren Fokusring.
  • Der Server rendert den Startzustand vollständig, JavaScript ergänzt nur die Interaktion.

Bewegung

  • Erscheint beim ersten Sichtkontakt mit einem kurzen Auftritt (kit-rise, useInView).
  • Bei reduzierter Bewegung (prefers-reduced-motion) bleibt sie ruhig. 1 Stellen im Code schalten Bewegung dann ab.

Quellcode

Die Datei, die aiw add in dein Projekt legt. Sie gehört danach dir.

Datei anzeigen, 377 Zeilen
components/ui/flip-card.tsx
'use client';

import { useEffect, useState } from 'react';
import { cn, prefersReducedMotion, useTexts } from '@/lib/kit';
import { Eyebrow } from '@/components/ui/section';
import { Button } from '@/components/ui/button';
import { Icon, type IconName } from '@/components/ui/icon';
import { Reveal } from '@/components/ui/reveal';
import { Stagger } from '@/components/ui/motion';
import { ease3d } from '@/components/ui/depth';

/*
 * Cards with a front and a back that turn over in 3D. A card turns on hover (mouse and pen), on a
 * click or tap, and with Enter or Space on its turn button; Escape turns it back. The hidden side is
 * inert, so the keyboard and screen readers only meet the side in view. Both sides share one grid
 * cell, the card is as tall as its taller side and nothing below jumps.
 *
 * With reduced motion the sides cross fade instead of turning. Without JavaScript a hover card still
 * turns on hover, a click card shows its front with the back in the document for screen readers.
 *
 *   team     portraits that turn to a short bio and a contact link
 *   facts    questions that turn to their answer, myth or fact
 *   product  a product picture that turns to its details and a button
 *   stats    numbers that flip upward to what is behind them
 *   gift     one large voucher, the front a design, the back the code and how to redeem it
 *
 *   <FlipCard front={…} back={…} trigger="click" axis="x" label="Revenue" />   a single card
 */

export type FlipCardsVariant = 'team' | 'facts' | 'product' | 'stats' | 'gift';

const TEXTS = {
  en: { turn: 'Turn over', turnBack: 'Turn back', myth: 'Myth', fact: 'Fact', redeem: 'How to redeem', code: 'Code', mail: 'Write an email' },
  de: { turn: 'Umdrehen', turnBack: 'Zurückdrehen', myth: 'Mythos', fact: 'Stimmt', redeem: 'So löst du ein', code: 'Code', mail: 'E-Mail schreiben' },
};

/* ------------------------------------------------------------------ */
/* The single card                                                     */
/* ------------------------------------------------------------------ */

export interface FlipCardProps {
  front: React.ReactNode;
  back: React.ReactNode;
  /** hover turns on mouse over and on click, click only on click. Default hover. */
  trigger?: 'hover' | 'click';
  /** y turns sideways, x flips upward. Default y. */
  axis?: 'x' | 'y';
  /** Name of the card for the turn button, e.g. the person or the question */
  label: string;
  /** Start on the back */
  defaultFlipped?: boolean;
  /** Classes of both faces (radius, border, background) */
  faceClassName?: string;
  className?: string;
  labels?: Partial<(typeof TEXTS)['en']>;
}

const FOCUS = 'focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-solid focus-visible:outline-primary';

/** A card with two sides that turns over in 3D. */
export function FlipCard({ front, back, trigger = 'hover', axis = 'y', label, defaultFlipped = false, faceClassName, className, labels }: FlipCardProps) {
  const t = useTexts(TEXTS, labels);
  const [flipped, setFlipped] = useState(defaultFlipped);
  const [ready, setReady] = useState(false);
  const [fade, setFade] = useState(false);
  useEffect(() => {
    setReady(true);
    setFade(prefersReducedMotion());
  }, []);
  const rot = axis === 'y' ? 'rotateY' : 'rotateX';
  const hover = trigger === 'hover';
  const enter = (e: React.PointerEvent) => hover && e.pointerType !== 'touch' && setFlipped(true);
  const leave = (e: React.PointerEvent) => hover && e.pointerType !== 'touch' && setFlipped(false);
  const face = cn('relative [grid-area:1/1] [backface-visibility:hidden] [-webkit-backface-visibility:hidden]', faceClassName);
  // Before hydration a hover card turns with CSS alone, afterwards the state leads
  const cssHover = hover && !ready ? 'group-hover/flip:[transform:var(--flip-to)]' : '';

  return (
    <div
      className={cn('group/flip relative [perspective:1400px]', className)}
      onPointerEnter={enter}
      onPointerLeave={leave}
      onKeyDown={(e) => {
        if (e.key === 'Escape' && flipped) setFlipped(false);
      }}
    >
      <div
        className={cn('grid h-full [transform-style:preserve-3d] transition-transform duration-700 motion-reduce:transition-none', cssHover)}
        style={{ transform: !fade && flipped ? `${rot}(180deg)` : undefined, transitionTimingFunction: ease3d, ['--flip-to' as string]: `${rot}(180deg)` }}
      >
        <div className={cn(face, fade ? 'transition-[opacity,visibility] duration-300' : 'transition-[visibility] duration-700', fade && flipped && 'opacity-0', ready && flipped && 'invisible')} inert={ready && flipped ? true : undefined}>
          {front}
          <button type="button" aria-expanded={false} onClick={() => setFlipped(true)} className={cn('absolute inset-0 z-10 cursor-pointer rounded-[inherit]', FOCUS)}>
            <span className="sr-only">
              {t.turn}: {label}
            </span>
          </button>
        </div>
        <div
          className={cn(face, fade ? 'transition-[opacity,visibility] duration-300' : 'transition-[visibility] duration-700', fade && !flipped && 'opacity-0', ready && !flipped && 'invisible')}
          style={fade ? undefined : { transform: `${rot}(180deg)` }}
          inert={ready && !flipped ? true : undefined}
        >
          {back}
          <button
            type="button"
            aria-expanded
            onClick={() => setFlipped(false)}
            className={cn('absolute right-3 top-3 z-10 flex size-11 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground sm:size-9', FOCUS)}
          >
            <Icon name="rotate-ccw" size={16} />
            <span className="sr-only">
              {t.turnBack}: {label}
            </span>
          </button>
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */

export interface FlipItem {
  title: string;
  /** team: role; facts: myth or fact as 'myth' | 'fact'; product: price; stats: the number */
  meta?: string;
  /** the text on the back */
  text?: string;
  /** product, gift: points on the back */
  points?: string[];
  icon?: IconName;
  href?: string;
}

export interface FlipCardsProps extends Omit<React.HTMLAttributes<HTMLElement>, 'title'> {
  variant?: FlipCardsVariant;
  eyebrow?: string;
  title?: React.ReactNode;
  description?: string;
  items: FlipItem[];
  /** team: portraits; product: pictures; gift: the design on the front */
  media?: React.ReactNode[];
  /** product, gift: the button on the back */
  action?: { label: string; href?: string };
  /** Override how the cards turn */
  trigger?: 'hover' | 'click';
  labels?: Partial<(typeof TEXTS)['en']>;
}

const CARD = 'rounded-2xl border border-border bg-card shadow-[var(--highlight),var(--shadow-md)]';

function Head({ eyebrow, title, description, center = true }: Pick<FlipCardsProps, 'eyebrow' | 'title' | 'description'> & { center?: boolean }) {
  if (!title) return null;
  return (
    <Reveal className={cn('max-w-[42rem]', center && 'mx-auto text-center')}>
      {eyebrow && <Eyebrow>{eyebrow}</Eyebrow>}
      <h2 className="text-balance text-h2 font-semibold text-foreground">{title}</h2>
      {description && <p className={cn('mt-4 max-w-[36rem] text-pretty text-lead text-muted-foreground', center && 'mx-auto')}>{description}</p>}
    </Reveal>
  );
}

/** A hint in the corner of a front side that it turns */
function TurnHint() {
  return (
    <span aria-hidden className="absolute right-3 top-3 flex size-8 items-center justify-center rounded-full bg-[color-mix(in_oklab,var(--card)_80%,transparent)] text-muted-foreground shadow-[var(--shadow-sm)] backdrop-blur transition-transform duration-500 group-hover/flip:rotate-180">
      <Icon name="rotate-cw" size={14} />
    </span>
  );
}

/** Cards that turn over to show what is on their back. */
export function FlipCards({ variant = 'team', eyebrow, title, description, items, media = [], action, trigger, labels, className, ...rest }: FlipCardsProps) {
  const t = useTexts(TEXTS, labels);
  const pic = (i: number) => (media.length ? media[i % media.length] : null);

  if (variant === 'gift') {
    const it = items[0];
    if (!it) return null;
    return (
      <section {...rest} className={cn('relative overflow-x-clip py-20 sm:py-28', className)}>
        <div className="kit-container grid grid-cols-1 items-center gap-12 md:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:gap-20">
          <div>
            <Head eyebrow={eyebrow} title={title} description={description} center={false} />
            {action && (
              <div className="mt-8">
                <Button href={action.href} icon="arrow-right" className="max-sm:w-full">
                  {action.label}
                </Button>
              </div>
            )}
          </div>
          <FlipCard
            trigger={trigger ?? 'click'}
            label={it.title}
            labels={labels}
            className="mx-auto w-full max-w-[32rem]"
            faceClassName="rounded-3xl"
            front={
              <div className="relative aspect-[1.586] overflow-hidden rounded-3xl bg-[color-mix(in_oklab,var(--primary)_80%,black)] text-white shadow-[var(--shadow-lg)]">
                <div data-clip-ok className="absolute inset-0 opacity-70 [&>*]:size-full">{pic(0)}</div>
                <span aria-hidden className="absolute inset-0 bg-[linear-gradient(160deg,color-mix(in_oklab,var(--primary)_25%,transparent),color-mix(in_oklab,var(--primary)_55%,black))]" />
                <div className="relative flex h-full flex-col justify-between p-6 sm:p-8">
                  <p className="text-[13px] font-medium uppercase tracking-[0.12em] opacity-85">{eyebrow}</p>
                  <div className="flex items-end justify-between gap-4">
                    <p className="text-[clamp(1.6rem,1.2rem+1.6vw,2.4rem)] font-semibold leading-[1.05] tracking-[-0.03em]">{it.title}</p>
                    {it.meta && <p className="shrink-0 text-[clamp(1.6rem,1.2rem+1.6vw,2.4rem)] font-semibold tabular-nums">{it.meta}</p>}
                  </div>
                </div>
                <TurnHint />
              </div>
            }
            back={
              <div className="flex aspect-[1.586] flex-col rounded-3xl border border-border bg-card p-6 shadow-[var(--highlight),var(--shadow-lg)] sm:p-8">
                <p className="text-[13px] text-muted-foreground">{t.code}</p>
                <p className="mt-1 text-[clamp(1.2rem,1rem+1vw,1.6rem)] font-semibold tracking-[0.14em] text-foreground">{it.text}</p>
                <p className="mt-auto text-[13px] font-medium text-foreground">{t.redeem}</p>
                <ol className="mt-2 grid gap-1 text-[13.5px] text-muted-foreground sm:gap-1.5">
                  {(it.points ?? []).map((p, i) => (
                    <li key={p} className="flex gap-2.5">
                      <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-[color-mix(in_oklab,var(--primary)_14%,var(--card))] text-[11px] font-semibold text-primary">{i + 1}</span>
                      <span className="min-w-0">{p}</span>
                    </li>
                  ))}
                </ol>
              </div>
            }
          />
        </div>
      </section>
    );
  }

  const cols = variant === 'facts' ? 'sm:grid-cols-2 lg:grid-cols-3' : variant === 'stats' || items.length >= 4 ? 'sm:grid-cols-2 lg:grid-cols-4' : 'sm:grid-cols-2 lg:grid-cols-3';
  const how = trigger ?? (variant === 'facts' || variant === 'stats' ? 'click' : 'hover');

  return (
    <section {...rest} className={cn('relative py-20 sm:py-28', className)}>
      <div className="kit-container">
        <Head eyebrow={eyebrow} title={title} description={description} />
        <Stagger as="ul" className={cn('grid grid-cols-1 gap-5 lg:gap-6', title && 'mt-12 sm:mt-16', cols)}>
          {items.map((it, i) => (
            <li key={i} className="flex">
              {variant === 'team' && (
                <FlipCard
                  trigger={how}
                  label={it.title}
                  labels={labels}
                  className="w-full"
                  faceClassName="rounded-2xl"
                  front={
                    <div className={cn(CARD, 'h-full p-3')}>
                      <div className="aspect-[4/5] overflow-hidden rounded-xl bg-surface [&>*]:size-full">{pic(i)}</div>
                      <div className="px-2 pb-1 pt-4">
                        <h3 className="text-[17px] font-semibold text-foreground">{it.title}</h3>
                        {it.meta && <p className="text-[14px] text-muted-foreground">{it.meta}</p>}
                      </div>
                      <TurnHint />
                    </div>
                  }
                  back={
                    <div className={cn(CARD, 'flex h-full flex-col bg-[color-mix(in_oklab,var(--primary)_7%,var(--card))] p-6')}>
                      <p className="pr-10 text-[17px] font-semibold text-foreground">{it.title}</p>
                      {it.meta && <p className="text-[14px] text-primary">{it.meta}</p>}
                      <p className="mt-4 text-pretty text-[14.5px] leading-relaxed text-muted-foreground">{it.text}</p>
                      {it.href && (
                        <a href={it.href} className={cn('mt-auto inline-flex min-h-11 cursor-pointer items-center gap-2 pt-6 text-[14px] font-medium text-foreground hover:text-primary', FOCUS)}>
                          <Icon name="mail" size={16} />
                          {t.mail}
                        </a>
                      )}
                    </div>
                  }
                />
              )}
              {variant === 'facts' && (
                <FlipCard
                  trigger={how}
                  label={it.title}
                  labels={labels}
                  className="w-full"
                  faceClassName="rounded-2xl"
                  front={
                    <div className={cn(CARD, 'flex h-full min-h-[13rem] flex-col p-6 sm:p-7')}>
                      <span className="flex size-10 items-center justify-center rounded-xl bg-[color-mix(in_oklab,var(--primary)_12%,var(--card))] text-primary">
                        <Icon name={it.icon ?? 'help-circle'} size={19} />
                      </span>
                      <p className="mt-auto pt-6 text-balance text-[18px] font-semibold leading-snug text-foreground">{it.title}</p>
                      <TurnHint />
                    </div>
                  }
                  back={
                    <div className={cn(CARD, 'flex h-full min-h-[13rem] flex-col p-6 sm:p-7', it.meta === 'fact' ? 'bg-[color-mix(in_oklab,var(--success)_9%,var(--card))]' : 'bg-[color-mix(in_oklab,var(--primary)_7%,var(--card))]')}>
                      <span className={cn('inline-flex w-fit items-center gap-1.5 rounded-md px-2 py-1 text-[12.5px] font-semibold', it.meta === 'fact' ? 'bg-[color-mix(in_oklab,var(--success)_16%,var(--card))] text-success-foreground' : 'bg-[color-mix(in_oklab,var(--primary)_14%,var(--card))] text-primary')}>
                        <Icon name={it.meta === 'fact' ? 'check' : 'x'} size={13} />
                        {it.meta === 'fact' ? t.fact : t.myth}
                      </span>
                      <p className="mt-4 text-pretty pr-6 text-[15px] leading-relaxed text-foreground">{it.text}</p>
                    </div>
                  }
                />
              )}
              {variant === 'product' && (
                <FlipCard
                  trigger={how}
                  label={it.title}
                  labels={labels}
                  className="w-full"
                  faceClassName="rounded-2xl"
                  front={
                    <div className={cn(CARD, 'flex h-full flex-col p-3')}>
                      <div className="aspect-square overflow-hidden rounded-xl bg-surface [&>*]:size-full">{pic(i)}</div>
                      <div className="flex items-baseline justify-between gap-3 px-2 pb-2 pt-4">
                        <h3 className="text-[16px] font-semibold text-foreground">{it.title}</h3>
                        {it.meta && <span className="shrink-0 text-[15px] font-semibold tabular-nums text-foreground">{it.meta}</span>}
                      </div>
                      <TurnHint />
                    </div>
                  }
                  back={
                    <div className={cn(CARD, 'flex h-full flex-col p-6')}>
                      <p className="pr-10 text-[16px] font-semibold text-foreground">{it.title}</p>
                      {it.text && <p className="mt-2 text-[14px] leading-relaxed text-muted-foreground">{it.text}</p>}
                      <dl className="mt-5 grid gap-2 border-t border-border pt-4 text-[13.5px]">
                        {(it.points ?? []).map((p) => {
                          const [k, v] = p.split('|');
                          return (
                            <div key={p} className="flex justify-between gap-3">
                              <dt className="text-muted-foreground">{k}</dt>
                              <dd className="text-right font-medium text-foreground">{v}</dd>
                            </div>
                          );
                        })}
                      </dl>
                      <div className="mt-auto pt-6">
                        <Button href={it.href ?? action?.href} size="sm" className="w-full" iconLeft="cart">
                          {action?.label ?? it.title}
                        </Button>
                      </div>
                    </div>
                  }
                />
              )}
              {variant === 'stats' && (
                <FlipCard
                  trigger={how}
                  axis="x"
                  label={it.title}
                  labels={labels}
                  className="w-full"
                  faceClassName="rounded-2xl"
                  front={
                    <div className={cn(CARD, 'flex h-full min-h-[11.5rem] flex-col justify-between p-6')}>
                      <p className="text-[14px] text-muted-foreground">{it.title}</p>
                      <p className="text-[clamp(2.4rem,1.8rem+2vw,3.4rem)] font-semibold leading-none tracking-[-0.045em] tabular-nums text-foreground">{it.meta}</p>
                      <TurnHint />
                    </div>
                  }
                  back={
                    <div className={cn(CARD, 'flex h-full min-h-[11.5rem] flex-col bg-[color-mix(in_oklab,var(--primary)_8%,var(--card))] p-6')}>
                      <p className="flex items-center gap-2 pr-10 text-[14px] font-medium text-primary">
                        <Icon name={it.icon ?? 'info'} size={15} />
                        {it.title}
                      </p>
                      <p className="mt-3 text-pretty text-[14.5px] leading-relaxed text-foreground">{it.text}</p>
                    </div>
                  }
                />
              )}
            </li>
          ))}
        </Stagger>
      </div>
    </section>
  );
}

Häufige Fragen

Wie installiere ich Wendekarten?

Mit aiw add @ai-website/flip-card. Der Befehl legt die Datei components/ui/flip-card.tsx in dein Projekt, der Code gehört danach dir. Mit dabei sind section, button, icon, reveal, motion und depth. Weitere npm-Pakete braucht sie nicht.

Welche Varianten hat Wendekarten?

5 Varianten, Team zum Umdrehen, Mythos oder Fakt, Produkte mit Details, Zahlen, die hochklappen und Gutschein. Du wählst sie mit der Prop variant, zum Beispiel variant="facts".

Kann ich die Texte von Wendekarten übersetzen?

Ja. Wendekarten bringt 7 eigene Texte auf Deutsch und Englisch mit, etwa „Umdrehen“, „Zurückdrehen“ und „Mythos“. Die Sprache folgt dem KitProvider, einzelne Texte ersetzt du über die Prop labels.

Kann ein KI-Assistent Wendekarten einbauen?

Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Wendekarten mit aiw_components und installieren sie mit aiw_add @ai-website/flip-card. Nenn im Prompt die Variante, etwa variant="team", dann schreibt der Assistent deine Inhalte direkt in die Props.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert