Zum Inhalt springen
UI Kit
Accent

Karten und Pläne

Eine Stadtteilkarte für eigene Pins, ein Stadtplan mit Beschriftung, eine kleine Karte für Kontaktbereiche und ein Grundriss mit Raumnamen. In den Farben des Themes.

Eine von 5 Components in Graphics

2 Variants

Variants

Stadtkarten

Pins auf einer Stadtteilkarte, verbunden mit einer Liste. Der aktive Pin pulsiert und zeigt seinen Namen, die Karte wächst beim Scrollen an ihren Platz.

Grundriss

Ein Grundriss mit Raumnamen in der Sprache der Seite. Zeig auf einen Raum in der Liste und er leuchtet im Plan auf.

Details

Was Karten und Pläne mitbringt, aus Registry und Quellcode gelesen.

Kategorie
Graphics
Bereich
Visuals
Variants
2
Version
1.0.0 · seit 1.0.0
Datei
components/ui/maps.tsx
Bringt mit
utilskit
npm-Pakete
Keine
Sprachen
Texte kommen über Props
Studio
Im Code anpassen

Barrierefreiheit

Aus dem Quellcode der Component abgeleitet.

  • Kommt ohne Client-State aus. Der Server schreibt sie vollständig, sie ist auch ohne JavaScript lesbar.

Bewegung

  • Bringt eigene Animationen mit, ruhig getaktet und ohne Wackeln.

Quellcode

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

Datei anzeigen, 127 Zeilen
components/ui/maps.tsx
'use client';

import { cn, useLocale } from '@/lib/kit';

/*
 * Maps and plans: a small street map with a pin, a city map, a district map
 * without pins and a floor plan. Drawn in the kit tokens, so they follow the
 * theme and the accent.
 */

const ROOMS = {
  en: ['Living', 'Bedroom', 'Kitchen', 'Bath', 'Balcony', 'Hall'],
  de: ['Wohnen', 'Schlafen', 'Küche', 'Bad', 'Balkon', 'Flur'],
};

/** A small street map with a pin, for contact areas */
export function MapSketch({ className }: { className?: string }) {
  return (
    <div className={cn('relative overflow-hidden bg-surface-2', className)} aria-hidden data-clip-ok>
      <svg viewBox="0 0 400 240" preserveAspectRatio="xMidYMid slice" className="absolute inset-0 size-full">
        <g fill="none" stroke="var(--border-strong)" strokeLinecap="round">
          <path d="M-10 70 C 90 60, 160 110, 410 90" strokeWidth="10" stroke="var(--background)" />
          <path d="M120 -10 C 140 80, 110 160, 150 250" strokeWidth="8" stroke="var(--background)" />
          <path d="M-10 190 L 410 160" strokeWidth="6" stroke="var(--background)" />
          <path d="M260 -10 L 290 250" strokeWidth="6" stroke="var(--background)" />
          <path d="M-10 130 H 410 M 60 -10 V 250 M 340 -10 V 250" strokeWidth="1" />
        </g>
        <path d="M300 200 q 30 -30 80 -20 v 70 h -100 z" fill="color-mix(in oklch, var(--success) 18%, transparent)" />
      </svg>
      <div className="absolute left-[46%] top-[38%] -translate-x-1/2 -translate-y-full">
        <span className="absolute left-1/2 top-full size-10 -translate-x-1/2 -translate-y-1/2 animate-kit-pulse rounded-full bg-[color-mix(in_oklab,var(--primary)_25%,transparent)]" />
        <svg viewBox="0 0 24 24" className="relative size-9 drop-shadow-md" fill="var(--primary)" stroke="var(--primary-foreground)" strokeWidth="1.4">
          <path d="M12 22c4.4-4.6 7-8.3 7-11.8a7 7 0 0 0-14 0C5 13.7 7.6 17.4 12 22Z" />
          <circle cx="12" cy="10" r="2.6" fill="var(--primary-foreground)" stroke="none" />
        </svg>
      </div>
    </div>
  );
}

/** A quiet city map with streets, a river and a park. The pin sits in the center. */
export function StreetMap({ className, label }: { className?: string; label?: string }) {
  const road = { fill: 'none', stroke: 'var(--background)', strokeLinecap: 'round' as const };
  const park = { fill: 'color-mix(in oklab, var(--success) 14%, var(--surface-2))' };
  return (
    <div className={cn('relative overflow-hidden bg-surface-2', className)} aria-hidden data-clip-ok>
      <svg viewBox="0 0 800 500" preserveAspectRatio="xMidYMid slice" className="absolute inset-0 size-full">
        <rect width="800" height="500" style={{ fill: 'var(--surface-2)' }} />
        <path d="M520 -10 C 600 80, 760 120, 820 90 V -10 Z" style={park} />
        <rect x="60" y="330" width="140" height="110" rx="8" style={park} />
        <path d="M-20 140 C 120 160, 220 260, 360 280 S 600 300, 820 420" style={{ fill: 'none', stroke: 'color-mix(in oklab, var(--primary) 22%, var(--surface-2))', strokeWidth: 34 }} />
        {[60, 140, 220, 300, 380, 460].map((y) => (
          <path key={`h${y}`} d={`M-10 ${y} H810`} style={{ ...road, strokeWidth: y === 220 ? 14 : 6 }} />
        ))}
        {[80, 180, 290, 400, 520, 630, 740].map((x) => (
          <path key={`v${x}`} d={`M${x} -10 V510`} style={{ ...road, strokeWidth: x === 400 ? 14 : 6 }} />
        ))}
        <path d="M-10 480 L560 -10" style={{ ...road, strokeWidth: 10 }} />
        {[[100, 76, 64, 50], [196, 76, 80, 50], [420, 236, 84, 50], [536, 236, 80, 50], [646, 316, 80, 50], [306, 316, 80, 50], [196, 396, 80, 50], [536, 396, 80, 50]].map(([x, y, w, h], i) => (
          <rect key={i} x={x} y={y} width={w} height={h} rx="4" style={{ fill: 'color-mix(in oklab, var(--foreground) 5%, var(--surface-2))' }} />
        ))}
        <circle cx="400" cy="220" r="56" style={{ fill: 'color-mix(in oklab, var(--primary) 12%, transparent)' }} />
        <circle cx="400" cy="220" r="11" style={{ fill: 'var(--primary)', stroke: 'var(--background)', strokeWidth: 4 }} />
      </svg>
      {label && <span className="absolute left-1/2 top-[44%] -translate-x-1/2 -translate-y-[160%] whitespace-nowrap rounded-md bg-background px-2 py-1 text-[11px] font-medium text-foreground shadow-[var(--shadow-md)]">{label}</span>}
    </div>
  );
}

/** A quiet district map without a pin: streets, a river, parks, blocks. Pins are placed by the block. coast adds a shoreline. */
export function DistrictMap({ className, coast = false }: { className?: string; coast?: boolean }) {
  const road = { fill: 'none', stroke: 'var(--background)', strokeLinecap: 'round' as const };
  const park = { fill: 'color-mix(in oklab, var(--success) 15%, var(--surface-2))' };
  const water = { fill: 'color-mix(in oklab, var(--info) 18%, var(--surface-2))' };
  const block = { fill: 'color-mix(in oklab, var(--foreground) 5%, var(--surface-2))' };
  return (
    <div className={cn('relative overflow-hidden bg-surface-2', className)} aria-hidden data-clip-ok>
      <svg viewBox="0 0 1000 700" preserveAspectRatio="xMidYMid slice" className="absolute inset-0 size-full">
        <rect width="1000" height="700" style={{ fill: 'var(--surface-2)' }} />
        {coast ? <path d="M1010 -10 V 710 H 760 C 700 600, 790 520, 720 420 S 760 200, 700 120 S 760 20, 740 -10 Z" style={water} /> : <path d="M-20 520 C 160 480, 300 560, 480 520 S 760 420, 1020 470" style={{ fill: 'none', stroke: 'color-mix(in oklab, var(--info) 22%, var(--surface-2))', strokeWidth: 40 }} />}
        <rect x="110" y="110" width="170" height="120" rx="10" style={park} />
        <path d="M560 560 C 620 540, 680 600, 660 660 L 520 680 Z" style={park} />
        {[[310, 90, 90, 70], [420, 90, 120, 70], [310, 190, 90, 60], [420, 190, 120, 60], [560, 90, 100, 70], [560, 190, 100, 60], [110, 270, 170, 80], [310, 290, 230, 80], [560, 290, 100, 80], [110, 390, 120, 60], [250, 390, 140, 60], [420, 390, 120, 50], [560, 380, 90, 50], [110, 600, 160, 70], [300, 600, 160, 70]].map(([x, y, w, h], i) => (
          <rect key={i} x={x} y={y} width={w} height={h} rx="6" style={block} />
        ))}
        {[70, 170, 260, 370, 470, 580].map((y) => (
          <path key={`h${y}`} d={`M-10 ${y} H${coast ? 720 : 1010}`} style={{ ...road, strokeWidth: y === 260 ? 16 : 7 }} />
        ))}
        {[90, 295, 405, 550, 680, 850].map((x) => (
          <path key={`v${x}`} d={`M${x} -10 V710`} style={{ ...road, strokeWidth: x === 405 ? 16 : 7, display: coast && x > 700 ? 'none' : undefined }} />
        ))}
        <path d="M-10 690 L 700 -10" style={{ ...road, strokeWidth: 10, opacity: 0.9 }} />
        <path d="M-10 260 H 1010" style={{ fill: 'none', stroke: 'color-mix(in oklab, var(--warning) 30%, var(--background))', strokeWidth: 6, strokeLinecap: 'round' }} />
      </svg>
    </div>
  );
}

/** A floor plan in thin lines, in the theme colors: three rooms, kitchen, bath and a balcony */
export function FloorPlan({ className, labels: labelsProp }: { className?: string; labels?: string[] }) {
  const locale = useLocale();
  const labels = labelsProp ?? ROOMS[locale];
  const wall = { fill: 'none', stroke: 'var(--foreground)', strokeWidth: 6, strokeLinejoin: 'miter' as const };
  const thin = { fill: 'none', stroke: 'var(--border-strong)', strokeWidth: 2 };
  const txt = { fill: 'var(--muted-foreground)', fontSize: 15, fontFamily: 'inherit' } as const;
  return (
    <svg viewBox="0 0 600 420" className={cn('size-full', className)} aria-hidden>
      <rect x="40" y="40" width="520" height="300" style={{ fill: 'var(--background)' }} />
      <rect x="40" y="340" width="260" height="50" style={{ fill: 'color-mix(in oklab, var(--primary) 6%, var(--background))', stroke: 'var(--border-strong)', strokeDasharray: '6 5', strokeWidth: 2 }} />
      <path d="M40 40 H560 V340 H40 Z" style={wall} />
      <path d="M300 40 V150 M300 190 V340 M300 230 H420 M460 230 H560 M420 40 V120 M420 160 V230 M40 220 H120 M160 220 H300" style={wall} />
      <path d="M300 150 a40 40 0 0 1 40 40 M120 220 a40 40 0 0 0 40 -40 M420 120 a40 40 0 0 1 40 40" style={thin} />
      <path d="M90 340 h120" style={{ ...wall, stroke: 'var(--background)', strokeWidth: 8 }} />
      <path d="M90 340 h120" style={{ fill: 'none', stroke: 'var(--border-strong)', strokeWidth: 2 }} />
      <rect x="470" y="60" width="70" height="40" rx="4" style={thin} />
      <rect x="440" y="250" width="100" height="60" rx="16" style={thin} />
      <rect x="60" y="60" width="90" height="120" rx="6" style={thin} />
      <path d="M320 60 h80 v40 h-80 Z M320 290 h60" style={thin} />
      <text x="170" y="140" textAnchor="middle" style={txt}>{labels[0]}</text>
      <text x="170" y="290" textAnchor="middle" style={txt}>{labels[1]}</text>
      <text x="360" y="140" textAnchor="middle" style={txt}>{labels[2]}</text>
      <text x="490" y="210" textAnchor="middle" style={txt}>{labels[3]}</text>
      <text x="170" y="371" textAnchor="middle" style={txt}>{labels[4]}</text>
      <text x="360" y="270" textAnchor="middle" style={txt}>{labels[5]}</text>
    </svg>
  );
}

Häufige Fragen

Wie installiere ich Karten und Pläne?

Mit aiw add @ai-website/maps. Der Befehl legt die Datei components/ui/maps.tsx in dein Projekt, der Code gehört danach dir. Weitere npm-Pakete braucht sie nicht.

Welche Varianten hat Karten und Pläne?

2 Varianten, Stadtkarten und Grundriss.

Kann ein KI-Assistent Karten und Pläne einbauen?

Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Karten und Pläne mit aiw_components und installieren sie mit aiw_add @ai-website/maps.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert