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
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
- Mit KI bauen
- Per MCP in Claude, Cursor, Copilot und Codex
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
'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.