Skip to content

Custom Components

Celestia bietet eine umfassende Bibliothek von Komponenten, aber manchmal benötigen Projekte spezifische Lösungen. Dieser Leitfaden beschreibt, wie Custom Components erstellt werden, die nahtlos in Celestia integriert sind.

Domain-spezifische Komponenten:

  • ProductCard mit spezifischen Datenfeldern
  • DashboardWidgets mit Business-Logik
  • Branchenspezifische Formulare

Projekt-spezifische Layouts:

  • Unique Page Layouts
  • Spezielle Navigation-Strukturen
  • Custom Footer-Varianten

Temporäre Lösungen:

  • Kampagnen-spezifische Komponenten
  • Experimente und Prototypen
  • Schnelle Iterationen

Generische UI-Elemente:

  • Buttons (nutze Celestia Button)
  • Inputs (nutze Celestia Form Components)
  • Cards (nutze Celestia Card)

Wenn generische Lösung möglich:

  • Komponente ist in 3+ Projekten nützlich → Contributen zu Celestia
  • Standard-Pattern mit Custom-Styling → Nutze Celestia Props

Design Tokens:

  • Nutze Celestia Design Tokens
  • Keine Hardcoded-Werte
  • Konsistente Spacing-Scale
  • Standard-Typografie

Interaktionsmuster:

  • Gleiche Hover/Fokus-States
  • Konsistente Animationen
  • Bekannte Patterns
  • Accessibility-Standards

Code-Qualität:

  • Gleiche Struktur wie Celestia
  • TypeScript
  • Getestet
  • Dokumentiert

Kapselung:

  • Isolierte Komponenten
  • Klare Props-API
  • Wenige Abhängigkeiten
  • Einfache Tests

Dokumentation:

  • JSDoc Kommentare
  • Usage-Beispiele
  • Props-Dokumentation
  • Bekannte Einschränkungen

Fragen:

  • Wird diese Komponente mehrfach verwendet?
  • Gibt es ähnliche Komponenten in Celestia?
  • Ist diese Funktionalität projektspezifisch?
  • Welche States und Varianten benötigt sie?

Spezifikation:

  • Design-Mockups
  • Interaktions-Flows
  • Props-Interface
  • Edge Cases

In Figma:

  • Celestia-Library als Basis
  • Design Tokens verwenden
  • Alle States designen
  • Responsive berücksichtigen

Review:

  • Design Review einholen
  • Celestia-Team konsultieren bei Unsicherheit
  • Accessibility prüfen

Setup:

/src/components/
└── custom/
└── CustomComponent/
├── CustomComponent.astro
├── CustomComponent.test.ts
└── index.ts

Template:

CustomComponent.astro
---
import type { HTMLAttributes } from 'astro/types';
import { clsx } from 'clsx';
interface Props extends HTMLAttributes<'div'> {
variant?: 'default' | 'highlighted';
size?: 'sm' | 'md' | 'lg';
}
const {
variant = 'default',
size = 'md',
class: className,
...rest
} = Astro.props;
const classes = clsx(
'custom-component',
`custom-component variant-${variant}`,
`custom-component variant-${size}`,
className
);
---
<div class={classes} {...rest}>
<slot />
</div>
<style>
.custom-component {
/* Nutze Celestia Design Tokens */
padding: var(--spacing-4);
border-radius: var(--border-radius-md);
background: var(--color-background-subtle);
}
.custom-component variant-highlighted {
background: var(--color-background-primary);
color: var(--color-text-on-primary);
}
.custom-component variant-sm {
padding: var(--spacing-2);
}
.custom-component variant-lg {
padding: var(--spacing-6);
}
</style>

Unit Tests:

import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { CustomComponent } from './CustomComponent';
describe('CustomComponent', () => {
it('renders with default props', () => {
render(<CustomComponent>Content</CustomComponent>);
expect(screen.getByText('Content')).toBeInTheDocument();
});
it('applies variant class', () => {
render(<CustomComponent variant="highlighted">Content</CustomComponent>);
expect(screen.getByText('Content')).toHaveClass('custom-component variant-highlighted');
});
});

Visual Tests:

  • Storybook Stories erstellen
  • Alle Varianten und States
  • Responsive Darstellung
  • Dark Mode

Accessibility:

  • axe-core Scan
  • Tastatur-Navigation
  • Screenreader-Test

README:

# CustomComponent
Kurze Beschreibung der Komponente.
## Installation
```typescript
import { CustomComponent } from '@/components/custom/CustomComponent';
<CustomComponent variant="highlighted" size="lg">
Content here
</CustomComponent>
PropTypeDefaultDescription
variant’default’ | ‘highlighted''default’Visual style
size’sm’ | ‘md’ | ‘lg''md’Component size

## Integration mit Celestia
### Komposition
**Custom Component nutzt Celestia:**
```astro
---
import { Button } from '../../components/starwind/button';
import { Card } from '../../components/starwind/card';
---
<div class="custom-widget">
<Card>
<CardHeader>Title</CardHeader>
<CardContent>
<p>Content</p>
</CardContent>
<CardFooter>
<Button variant="primary">Action</Button>
</CardFooter>
</Card>
</div>

Erweiterung von Celestia:

---
import { Button } from '../../components/starwind/button';
---
<Button class="custom-button">
Custom Label
</Button>
<style>
.custom-button {
/* Zusätzliche Styles */
text-transform: uppercase;
letter-spacing: 0.05em;
}
</style>
  • Celestia Design Tokens nutzen
  • Konsistente Naming-Conventions
  • Props-Interface definieren
  • Tests schreiben
  • Dokumentation erstellen
  • Celestia-Komponenten komponieren
  • Accessibility beachten
  • Mobile-First entwickeln
  • Celestia-Patterns brechen
  • Hardcoded-Werte verwenden
  • Zu viele Custom-Komponenten erstellen
  • Ohne Tests deployen
  • Ohne Dokumentation
  • Accessibility ignorieren
  • Design Tokens umgehen
  • Konsistenz aufgeben

Wenn die Komponente:

  • In mehreren Projekten nützlich ist
  • Generische Funktionalität bietet
  • Celestia-Standards erfüllt
  • Vollständig getestet ist

1. Vorschlag einreichen:

  • Feature Request erstellen
  • Use Cases beschreiben
  • Design-Vorschlag

2. Review:

  • Celestia-Team prüft
  • Design Review
  • Technical Review

3. Implementation:

  • Nach Celestia-Standards
  • Vollständige Tests
  • Dokumentation

4. Release:

  • In Celestia integriert
  • Verfügbar für alle
  • Migration von Custom zu Celestia
ProductCard.astro
---
import { Card, CardHeader, CardContent, CardFooter } from '../starwind/card';
import { Button } from '../starwind/button';
import { Badge } from '../starwind/badge';
interface Props {
title: string;
price: number;
image: string;
badge?: string;
onAddToCart?: () => void;
}
const { title, price, image, badge, onAddToCart } = Astro.props;
---
<Card class="product-card">
<div class="product-card-image">
<img src={image} alt={title} />
{badge && <Badge variant="accent">{badge}</Badge>}
</div>
<CardHeader>
<h3>{title}</h3>
</CardHeader>
<CardContent>
<p class="product-card-price">{price}</p>
</CardContent>
<CardFooter>
<Button onclick={onAddToCart}>In den Warenkorb</Button>
</CardFooter>
</Card>
<style>
.product-card {
max-width: 300px;
}
.product-card-image {
position: relative;
aspect-ratio: 1;
}
.product-card-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.product-card-price {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
}
</style>

Custom Components erweitern Celestia für spezifische Bedürfnisse. Wenn sie gut gemacht sind, können sie später zu Celestia contributen und der gesamten Organisation zugutekommen.