Das WebKit im Schaufenster #
Eine Oberfläche für ein EULANDA-Plugin zu bauen fühlt sich an wie HTML schreiben - nur dass am
Ende kein nacktes Formular steht, sondern ein fertiger, themenfähiger, mehrsprachiger Dialog.
Das WebKit aus EulandaXtools liefert dafür einen ganzen Satz eul-*-Bausteine: Sie kennen Hell-
und Dunkelmodus, sie sind lokalisiert, sie sehen über alle Plugins gleich aus - und man bindet
sie ein, indem man ein Tag schreibt. Kein Framework-Projekt, kein Build-Schritt, keine
Node-Toolchain.
Dieses Kapitel ist die Einladung: ein Rundgang durch die Bausteine, jeweils mit einem Blick in
ein echtes Fenster und der einen Zeile, die ihn erzeugt. Am schnellsten erlebt man das live -
Show-EulWebUiStyleguide öffnet genau diese Galerie als Dialog samt Theme-Umschalter; alle
Abbildungen hier stammen daraus.
Schnellstart: installieren und ausprobieren #
Man braucht nur Windows mit Windows PowerShell - kein Visual Studio, kein Node. Ein PowerShell-Fenster öffnen und das folgende Skript einfügen. Es holt EulandaXtools (nur falls online eine neuere Version liegt) und öffnet anschließend genau diesen Style Guide. Das Skript ist eingeklappt - direkt kopieren oder zum Lesen aufklappen:
Skript anzeigen
# EulandaXtools bei Bedarf aktualisieren und den Style Guide öffnen.
$ProgressPreference = 'SilentlyContinue'
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -Force
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$module = 'EulandaXtools'
$base = "https://files.eulanda.eu/$($module.ToLower())"
# Modulpfad im (ggf. nach OneDrive umgelenkten) Benutzerprofil - Windows PowerShell 5.1
$modulesRoot = Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'WindowsPowerShell\Modules'
$installRoot = Join-Path $modulesRoot $module
# Online-Version von files.eulanda.eu (IIS) lesen
$online = (Invoke-RestMethod "$base/version.txt") -replace '[^\d.]', ''
Write-Host "Online (files.eulanda.eu): $module $online" -ForegroundColor Cyan
# Höchste lokal installierte Version ermitteln
$installed = $null
if (Test-Path $installRoot) {
$installed = Get-ChildItem $installRoot -Directory |
Where-Object { $_.Name -as [version] } |
Sort-Object { [version]$_.Name } -Descending |
Select-Object -First 1 -ExpandProperty Name
}
if ($installed) { Write-Host "Lokal installiert: $module $installed" -ForegroundColor Cyan } else { Write-Host "Lokal installiert: (noch nicht vorhanden)" -ForegroundColor Cyan }
if (-not $installed -or [version]$online -gt [version]$installed) {
Write-Host "Aktualisiere auf $online ..." -ForegroundColor Yellow
$tmp = Join-Path $modulesRoot ".$module-download"
$ext = Join-Path $tmp 'extracted'
if (Test-Path $tmp) { Remove-Item $tmp -Recurse -Force }
New-Item -ItemType Directory -Path $ext -Force | Out-Null
$zip = Join-Path $tmp "$module.zip"
Invoke-WebRequest "$base/$($module.ToLower()).zip" -OutFile $zip
Expand-Archive $zip -DestinationPath $ext -Force
# Das Manifest (.psd1) ist die verbindliche Quelle für die Versionsnummer
$psd1 = Get-ChildItem $ext -Recurse -Filter "$module.psd1" | Select-Object -First 1
if (-not $psd1) { throw "$module.psd1 im Download nicht gefunden." }
$version = (Import-PowerShellDataFile $psd1.FullName).ModuleVersion
$target = Join-Path $installRoot $version
if (Test-Path $target) { Remove-Item $target -Recurse -Force }
New-Item -ItemType Directory -Path $target -Force | Out-Null
Copy-Item (Join-Path $psd1.Directory.FullName '*') $target -Recurse -Force
Get-ChildItem $target -Recurse -File | Unblock-File -ErrorAction SilentlyContinue # Mark of the Web entfernen
Remove-Item $tmp -Recurse -Force
Write-Host "Installiert: $module $version" -ForegroundColor Green
} else {
Write-Host "Bereits aktuell - kein Download." -ForegroundColor Green
}
Write-Host "Starte den Style Guide ..." -ForegroundColor Cyan
Import-Module $module -Force
Show-EulWebUiStyleguide
Was das Skript tut:
- Versionsabgleich: Es liest die Online-Version aus
version.txtund vergleicht sie mit der höchsten lokal installierten - heruntergeladen wird nur, wenn das Web wirklich neuer ist. - Sichere Versionsbestimmung: Der Download landet zuerst in einem Temp-Ordner; die maßgebliche Versionsnummer kommt aus dem Manifest (
.psd1), nicht aus dem Dateinamen. Erst damit entsteht der endgültige Zielordner...\Modules\EulandaXtools\<Version>\. Genau so macht es auch ErpXe beim Nachladen. - OneDrive-fest: Der Modulpfad wird über den Windows-Known-Folder „Eigene Dokumente" aufgelöst - also auch bei nach OneDrive umgeleitetem Dokumente-Ordner.
- Sofort lauffähig:
Set-ExecutionPolicy -Scope Process RemoteSignederlaubt das Laden des EV-signierten Moduls in dieser Sitzung;Unblock-Filenimmt den frisch entpackten Dateien das „Mark of the Web". DanachImport-Module -Force- und der Beispieldialog geht auf.
Ein manuelles Freischalten vorab ist nicht nötig. Das Skript wird in ein PowerShell-Fenster eingefügt (interaktiv ausgeführt, nicht als
.ps1-Datei gestartet) - die Execution Policy blockt nur Skript-/Moduldateien, nicht eingefügte Befehle. Deshalb läuft die erste Zeile auch unter der Standardrichtlinie „Restricted", ohne Adminrechte, undScope Processbetrifft nur diese eine Sitzung. Wer das Skript stattdessen als.ps1speichert und startet, ruft es mitpowershell -ExecutionPolicy Bypass -File <datei>.ps1auf. (Einzige echte Ausnahme: eine per Gruppenrichtlinie zentral erzwungene Policy.)
Ab jetzt steht Show-EulWebUiStyleguide jederzeit bereit und alle eul-*-Bausteine sind einsatzbereit. Und damit der Rundgang:
Buttons #
Der Anfang ist unspektakulär und genau deshalb angenehm: Ein eul-button ist ein Button, der
schon richtig aussieht. Fünf Varianten transportieren die Bedeutung (primary, secondary, ghost,
success, danger), drei Größen die Gewichtung - mehr muss man nicht entscheiden.
Varianten und Größen - jede Farbe trägt eine Bedeutung.
<eul-button variant="success">Speichern</eul-button>
<eul-button variant="ghost"><eul-icon name="settings"></eul-icon></eul-button>
Formularfelder #
Text, E-Mail, Zahl, Auswahl, Checkbox, Radio, Schalter - die üblichen Verdächtigen, aber aus
einem Guss. Das Sahnehäubchen ist eul-tag-input: ein Feld mit Autocomplete, das Vorschläge
filtert und als Chips übernimmt - ideal, wenn der Anwender Spalten oder Schlagworte
zusammenstellt.
Von Text bis Schalter, plus das Tag-Input mit Vorschlagsliste.
<eul-input type="email" placeholder="name@firma.de"></eul-input>
<eul-switch checked>Aktiv</eul-switch>
Form-Layout #
Formulare sollen ohne Handarbeit ordentlich aussehen. eul-form mit eul-form-row legt Label
und Eingabe ab 560 px Breite nebeneinander und stapelt sie darunter - per Container-Query, nicht
per Fensterbreite. Der graue Hilfetext unter einem Feld ist eine einzige Zeile.
Label und Eingabe sortieren sich je nach Platz selbst.
<eul-form>
<div class="eul-form-row">
<label>E-Mail</label>
<div>
<eul-input type="email"></eul-input>
<div class="eul-form-help">Wird für Benachrichtigungen genutzt.</div>
</div>
</div>
</eul-form>
Datepicker #
Datum, Datum mit Uhrzeit, Zeitraum - eul-datepicker deckt alle drei ab, mit deutschem Format
und Kalender-Popup. Ein Attribut entscheidet, welcher Typ.
Drei Picker-Typen aus einer Komponente.
<eul-datepicker type="range" placeholder="von - bis"></eul-datepicker>
HTML-Editor #
Wo der Anwender formatierten Text braucht - ein Anschreiben, eine Mail-Vorlage - liefert
eul-htmleditor einen WYSIWYG-Editor mit drei Toolbar-Stufen. Wichtig fürs Backend:
el.mailHtml gibt sauberes, auf das EULANDA-Subset reduziertes HTML zurück, kein
Editor-Wirrwarr.
Formatierter Text, der als sauberes HTML zurückkommt.
<eul-htmleditor toolbar="mail" height="160"></eul-htmleditor>
const html = document.querySelector('eul-htmleditor').mailHtml;
Cards / Tönungen #
eul-card ist der Rahmen für alles. Über tone bekommt eine Karte eine Bedeutung (info,
success, warning, danger), über elevation Tiefe, über level eine saubere Verschachtelung -
aus drei Attributen entsteht eine ganze Gestaltungssprache.
Variant, Tone, Elevation und verschachtelte Level.
<eul-card tone="warning">Bitte prüfen</eul-card>
Tabs / Accordion #
Zwei klassische Gliederungen, beide rein über CSS-Klassen, ohne eine Zeile JavaScript:
eul-tabs für Reiter nebeneinander, eul-accordion für aufklappbare Abschnitte untereinander.
Je das erste Element trägt selected beziehungsweise open.
Tabs oben, Accordion darunter - rein deklarativ.
<eul-tabs>
<div class="eul-tabs-list">
<button class="eul-tab" selected>Allgemein</button>
<button class="eul-tab">Optionen</button>
</div>
<div class="eul-tab-panel" selected>...</div>
<div class="eul-tab-panel">...</div>
</eul-tabs>
Feedback #
Rückmeldung an den Anwender ist Einzeiler-Sache. EulUI.toast wirft eine kurze Meldung ein
(vier Varianten), EulUI.alert und EulUI.confirm liefern Hinweis und Rückfrage als Promise.
Dazu eul-spinner und eul-progress für alles, was dauert.
Kurzmeldungen, Dialoge und Ladeanzeigen.
EulUI.toast('Gespeichert', { variant: 'success' });
if (await EulUI.confirm('Wirklich löschen?')) { /* ... */ }
Wizard #
Mehrstufige Abläufe - Import, Einrichtung, Migration - führt eul-wizard Schritt für Schritt.
Jede Seite trägt ihren Titel im data-title, die Schritt-Navigation entsteht von selbst.
Geführter Ablauf mit Fortschrittsleiste.
<eul-wizard>
<div class="eul-wizard-content">
<div class="eul-wizard-page" data-title="Start" active>...</div>
<div class="eul-wizard-page" data-title="Prüfen">...</div>
</div>
</eul-wizard>
Tree / Listview #
Hierarchien zeigt eul-tree - mit Checkboxen, Einfachauswahl und einer Echtzeitsuche, die den
Baum beim Tippen filtert. Für flache Listen gibt es eul-listview. Daten kommen als Property,
die Auswahl liest man über .checkedIds oder .selectedId zurück.
Baum mit Sofortfilter und Mehrfachauswahl, plus Liste.
<eul-tree id="t" checkboxes searchable></eul-tree>
document.getElementById('t').data = [
{ id: 'a', label: 'Eigenschaften', children: [{ id: 'farbe', label: 'Farbe' }] }
];
Grid #
Die Tabelle, die im echten Plugin am häufigsten gebraucht wird. eul-grid bringt Suche,
Sortierung und Pagination schon als Attribute mit; Spalten und Zeilen setzt man über .columns
und .data. Sind keine Daten da, erscheint automatisch ein Empty-Overlay.
Volltextsuche, Spaltensortierung und Pagination ohne Zutun.
<eul-grid search sort pagination></eul-grid>
const g = document.querySelector('eul-grid');
g.columns = ['ArtNr', 'Bezeichnung', 'Bestand', 'Preis'];
g.data = rows;
Charts #
Zahlen werden Bild: eul-chart umhüllt Chart.js für Balken, Torte, Linie und Doughnut. Ein
Attribut wählt den Typ, .data nimmt das vertraute Chart.js-Format.
Aus einem Datenobjekt wird ein fertiges Diagramm.
<eul-chart type="bar" height="220"></eul-chart>
document.querySelector('eul-chart').data = {
labels: ['Jan', 'Feb', 'Mär'],
datasets: [{ label: 'Umsatz', data: [42, 48, 55] }]
};
Icons #
40 randscharfe Lucide-Icons als Inline-SVG, skalierbar und einfärbbar. size bestimmt die
Größe, color die Bedeutung - und im Button wird daraus mit einem Tag ein Icon-Button.
Ein konsistentes Icon-Set, das überall passt.
<eul-icon name="trash-2" color="danger"></eul-icon>
<eul-button><eul-icon name="save"></eul-icon> Speichern</eul-button>
EULANDA-Icons #
Eigene Bilddateien - Logos, Symbole - liegen im Modul-Ordner lib/img/ und sind im Dialog als
eulimg/... erreichbar; den Virtual-Host dafür richtet Show-EulWebView2Dialog automatisch
ein. eul-image zeigt sie scharf in jeder Größe.
Modul-eigene Bilder, ohne Pfad-Gefummel.
<eul-image src="eulimg/eulanda-logo.png" width="48"></eul-image>
App-Layout #
Und schließlich der Rahmen, der alles zusammenhält: eul-app mit Kopfleiste und Body, darin
eul-sidebar (Navigationsleiste links, Seiten rechts) oder eul-ribbon (Reiter oben). Der
Seitenwechsel läuft über ein data-page-Attribut - genau dieses Muster trägt auch der Style
Guide selbst.
Der Plugin-Rahmen als Sidebar oder Ribbon.
<eul-sidebar>
<nav slot="nav">
<a data-page="start" active>Start</a>
<a data-page="export">Export</a>
</nav>
<eul-page id="start" active>...</eul-page>
<eul-page id="export">...</eul-page>
</eul-sidebar>
All das kommt aus einem einzigen Bundle, das Show-EulWebView2Dialog automatisch einsetzt -
Design-Tokens, Komponenten, Sprache. Man schreibt die eul-*-Tags, der Rest ist erledigt. Wer
loslegen will: WebView2 in PowerShell zeigt das Gerüst,
Dialog-Aufbau und Bausteine die Struktur dahinter.














