- Vue 71.1%
- TypeScript 27.3%
- CSS 1.6%
|
All checks were successful
publish-package / publish (push) Successful in 1m45s
|
||
|---|---|---|
| .forgejo/workflows | ||
| public | ||
| src | ||
| .eslintrc.cjs | ||
| .gitignore | ||
| .prettierrc | ||
| LICENSE | ||
| package-content.excalidraw | ||
| package-content.png | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.app.json | ||
| tsconfig.json | ||
| tsconfig.node.json | ||
| vite.config.ts | ||
ff-admin-core
Basis-UI-Funktionalität für ff-admin Anwendungen als wiederverwendbares npm-Package.
📋 Inhaltsverzeichnis
- Übersicht
- Was übernimmt das Package?
- Installation
- Konfiguration
- Verwendung
- Erweiterung
- CSS-Klassen & Theming
Übersicht
@ff-admin/core stellt Basis-UI-Komponenten, Layouts, Stores, Router, Enums und Helper für FF-Admin Anwendungen bereit. Das Package sorgt für eine konsistente UI-Struktur und wiederverwendbare Funktionalität in allen Anwendungen.
Was übernimmt das Package?
🖥️ Basis-UI-Inhalte
- Wiederverwendbare UI-Komponenten (z.B. Layouts, Tabs, Modals, Icons, Progress Bars)
- Stores für globale State-Verwaltung (Pinia)
- Router-Konfiguration und Guards
- Enum-Definitionen für Permissions, Module, Sections etc.
- Helper-Funktionen für UI und Kommunikation
- Socket.IO Client-Integration
- PWA-Unterstützung
- Konsistente Styles und globale CSS
Das Package stellt die Basis für alle FF-Admin Anwendungen bereit und sorgt für ein einheitliches UI und Verhalten.
Installation
npm install @ff-admin/core
Wichtig: in der viteConfig der Anwendung muss die Dependency Optimization für das package deaktiviert werden.
export default defineConfig({
plugins: [
vue(),
VitePWA({ /* deine config */ }), // falls pwa benötigt
// ... andere plugins
],
optimizeDeps: {
exclude: ['@ff-admin/core']
}
})
Peer Dependencies
Das Package benötigt folgende Peer Dependencies:
vue>= 3.0.0pinia>= 2.0.0vue-router>= 4.0.0
Verwendung & Erweiterung
Das Package wird typischerweise in den zentralen Dateien der Anwendung (z.B. core-setup.ts, main.ts, router/index.ts) eingebunden und konfiguriert. Die Erweiterung erfolgt über TypeScript-Interfaces, um projektspezifische Funktionalität und Enums zu ergänzen.
Einbindung und Initialisierung
- Importiere das Package und initialisiere zentrale Services (z.B. HTTP, Socket, Konfigurationswerte).
- Binde globale Komponenten, Stores und Router ein.
- Konfiguriere Namespaces, Enums und weitere projektspezifische Typen über Interface-Erweiterungen.
Beispielhafter Ablauf (vereinfacht):
// Importiere das Package und zentrale Services
import "@ff-admin/core";
import { configureSocketNamespace, HTTPManager, NavigationConfigVals, PackageConfigVals, SocketManager } from "@ff-admin/core";
// (Optional) Erweiterung von Typen für projektspezifische Enums und Namespaces
declare module "@ff-admin/core" {
interface PermissionSectionMap {
// Eigene Berechtigungs-Section hinzufügen
mySection: void;
}
interface PermissionModuleMap {
// Eigene Berechtigungs-Module hinzufügen
myModule: void;
anotherModule: void;
}
interface SettingTopicMap {
myApp: void;
}
interface SettingValueMapping {
"myApp.apiKey": string;
"myApp.timeout": number;
"myApp.baseUrl": string;
}
interface ModuleSettingTopicMap {
myModule: void;
}
interface ModuleSettingValueMapping {
"myModule.setting1": string;
"myModule.setting2": number;
"myModule.enabled": boolean;
}
interface SocketNamespaceMap {
myCustomNamespace: "/custom";
anotherNamespace: "/another";
}
}
// Konfigurationswerte setzen
PackageConfigVals.serverAddress = "...";
PackageConfigVals.devMode = true;
PackageConfigVals.clientVersion = ""; // Alternativ package JSON auslesen
// Initialisierung und Konfiguration
HTTPManager.init();
SocketManager.init();
configureSocketNamespace({
myCustomNamespace: "/custom",
anotherNamespace: "/another",
});
// Angabe der Navigationsstruktur
NavigationConfigVals.defaultActiveNavigation = "configuration"
NavigationConfigVals.topLevel = [/*...*/]
// direktes setzen der Struktur
NavigationConfigVals.navigation = {/*...*/}
// oder einzelne Keys setzen
NavigationConfigVals.setNavigationKey("configuration", {/*...*/})
Werte wie im Backend müssen nur für den SocketNamespace definiert werden. Alle anderen Konfigurationswerte werden über den Server bezogen.
Integration in die App
- Binde das Package in die Hauptdatei deiner App ein (z.B. in
main.ts). - Verwende die bereitgestellten Komponenten, Stores, Router und Helper in deiner Anwendung.
- Nutze die Basisrouten und Guards aus dem Package und ergänze sie bei Bedarf um eigene Routen.
Beispiel (allgemein):
import "./core-setup";
import { createApp } from "vue";
import { createPinia } from "pinia";
import router from "./router";
import App from "./App.vue";
const app = createApp(App);
app.use(createPinia());
app.use(router);
// Weitere globale Properties oder Plugins
PackageConfigVals.router = router;
app.mount("#app");
CSS-Klassen & Theming
Einbindung in der Anwendung
Damit Styling und Tailwind-Utilities korrekt funktionieren, sind drei Schritte notwendig:
1. vite.config.ts — Tailwind-Plugin einbinden
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
tailwindcss(),
// ... weitere Plugins
],
optimizeDeps: {
exclude: ["@ff-admin/core"],
},
});
2. src/main.css — CSS in der richtigen Reihenfolge importieren
/* 1. Tailwind selbst */
@import "tailwindcss";
/* 2. Rohe Theme-Konfiguration des Package, damit der App-Build
die Tokens und Variants kennt */
@import "@ff-admin/core/theme.css";
/* 3. Fertig kompilierte Package-Styles (Komponenten, Base-Layer) */
@import "@ff-admin/core/style.css";
/* 4. Scan-Pfad für Package-Templates, damit Tailwind deren
verwendete Klassen generiert */
@source "../node_modules/@ff-admin/core/dist/**/*.{js,vue}";
3. src/main.ts — CSS-Datei laden
import "./main.css";
Was die drei Dateien leisten
| Import | Typ | Zweck |
|---|---|---|
@ff-admin/core/theme.css |
Roh (unkompiliert) | Gibt dem Tailwind-Compiler der App die Custom-Tokens (--color-primary etc.) und die hover-Variant ohne @media (hover: hover) |
tailwindcss |
Tailwind | Generiert alle Utility-Klassen für die App inkl. der Package-Tokens |
@ff-admin/core/style.css |
Kompiliert | Fertige Styles der Package-Komponenten (Base-Layer, Component-Klassen) |
Theming — CSS-Variablen
Das gesamte Farbschema leitet sich aus einem einzigen Hue-Wert (0–360, HSL-Farbkreis) ab. Der Wert wird über die Admin-Einstellungen gesetzt und per Pinia-Store zur Laufzeit auf document.documentElement angewendet.
| Variable | Berechnung | Verwendung |
|---|---|---|
--hue |
0–360 (Standard: 4 = Rot) |
Einziger konfigurierbarer Wert |
--primary |
hsl(var(--hue) 100% 30%) |
Hauptfarbe (Buttons, Rahmen, Header) |
--primary-hover |
hsl(var(--hue) 100% 25%) |
Hover-Zustand von Primary |
--primary-subtle |
hsl(var(--hue) 100% 93%) |
Heller Hintergrund (aktive Tabs, Hover-Flächen) |
--accent |
hsl(var(--hue) 80% 40%); |
Akzent |
--success |
#7ac142 (fix) |
Erfolg |
--failed |
#ff0000 (fix) |
Fehler |
Alle Variablen sind über Tailwind als Farbklassen verfügbar (z. B. bg-primary, text-primary-subtle, border-primary-hover).
Navigation
.nav-tab
Basis-Klasse für einen Tab in einer Tab-Leiste (z. B. Passwort / TOTP). Wird mit .nav-tab-active oder .nav-tab-inactive kombiniert.
<p class="w-1/2 nav-tab" :class="tab === 'pw' ? 'nav-tab-active' : 'nav-tab-inactive'" @click="tab = 'pw'">
Passwort
</p>
| Klasse | Beschreibung |
|---|---|
.nav-tab |
Gemeinsame Basis: flex items-center justify-center, Padding, Schriftgröße |
.nav-tab-active |
Aktiver Tab: bg-primary-subtle, Unterstrich in Primary-Farbe |
.nav-tab-inactive |
Inaktiver Tab: Hover bg-primary-subtle |
.nav-toplevel-active / .nav-toplevel-inactive
Für Top-Level-Navigationslinks in der Hauptnavigation (Desktop: ausgefüllter Primary-Hintergrund, Mobil: nur Textfarbe).
.sidebar-link / .sidebar-link-active
Für Einträge in der Seitenleiste. .sidebar-link-active fügt einen linken Primary-Balken und subtilen Hintergrund hinzu.
<div class="sidebar-link" :class="isActive ? 'sidebar-link-active' : ''">Eintrag</div>
Karten & Panels
.card
Weißes, abgerundetes Panel mit horizontalen Trennlinien (divide-y-2 divide-gray-300). Eignet sich für mehrteilige Bereiche.
<div class="card">
<div class="card-header">…</div>
<div class="p-4">Inhalt</div>
</div>
.card-plain
Wie .card, aber ohne Trennlinien. Für schlichte weiße Panels.
.card-header
Kopfzeile innerhalb einer .card: horizontale Flex-Zeile mit justify-between, Innenabstand.
Listen-Einträge
Alle Listeneinträge (Benutzer, Rollen, Web-API-Keys, Backups, Sitzungen …) folgen diesem Schema:
<div class="list-card">
<div class="list-card-header">
<span>Titel</span>
<span>Aktion</span>
</div>
<div class="list-card-body">
<div class="list-card-row">
<span class="list-card-row-label">Label</span>
<span class="list-card-row-value">Wert</span>
</div>
</div>
</div>
| Klasse | Beschreibung |
|---|---|
.list-card |
Äußerer Rahmen mit Primary-Border, abgerundet |
.list-card-header |
Primary-Hintergrund, weißer Text, justify-between |
.list-card-body |
Innenbereich mit Padding und vertikalem Gap |
.list-card-row |
Horizontale Zeile für Label + Wert |
.list-card-row-label |
Feste Mindestbreite (min-w-16) für linksbündige Labels |
.list-card-row-value |
Wächst flexibel, schneidet zu langen Text ab |
Modals
Alle Modals verwenden eine einheitliche Struktur:
<div class="modal-wrapper">
<div class="modal-title">
<p>Modal-Titel</p>
</div>
<!-- Formularfelder -->
<div class="modal-footer">
<div class="modal-footer-inner">
<button>Abbrechen</button>
<div class="modal-submit-row">
<button primary>Bestätigen</button>
</div>
</div>
</div>
</div>
| Klasse | Beschreibung |
|---|---|
.modal-wrapper |
Max-Breite md:max-w-md, volle Breite |
.modal-title |
Zentrierte Flex-Spalte; > p bekommt text-xl font-medium |
.modal-footer |
Rechtsbündige Fußzeile |
.modal-footer-inner |
Horizontale Zeile mit Gap und vertikalem Padding |
.modal-submit-row |
Flex-Zeile für mehrstufige Submit-Aktionen (z. B. Bestätigung + Spinner) |
Weitere Utility-Klassen
.badge
Kleines Tag/Chip-Pill für Labels, Rollen, Kanäle o. Ä.
<span class="badge">Admin</span>
Stil: px-2 py-0.5 bg-gray-200 border border-gray-400 rounded-full text-xs
.menu-item
Eintrag in einem Kontext- oder Dropdown-Menü. Hover verwendet bg-primary-subtle.
<div class="menu-item" @click="copy">
<CopyIcon />
<span>Kopieren</span>
</div>
.pagination-btn
Einzelne Zelle in einer Pagination-Leiste. first: und last: runden die Enden ab.
<ul class="flex">
<li class="pagination-btn">«</li>
<li class="pagination-btn">1</li>
<li class="pagination-btn">»</li>
</ul>
Öffentliche Seiten (Login, Setup, Reset, Invite)
Für vollseitige zentrierte Seiten ohne Sidebar:
<div class="public-page">
<div class="public-page-inner">
<div class="public-page-header">
<img src="…" alt="Logo" class="h-20 w-auto" />
<h1 class="public-page-title">Seitentitel</h1>
</div>
<!-- Formular oder Inhalt -->
</div>
</div>
| Klasse | Beschreibung |
|---|---|
.public-page |
grow flex items-center justify-center, responsives Padding |
.public-page-inner |
max-w-md w-full space-y-8 |
.public-page-header |
Flex-Spalte, zentriert, gap-4 |
.public-page-title |
text-4xl font-extrabold text-gray-900 text-center |
Buttons
Buttons bekommen ihre Variante über HTML-Attribute (kein separates CSS von außen nötig):
<button primary>Primär-Aktion</button>
<button primary-outline>Sekundär-Aktion</button>
<button disabled>Deaktiviert</button>
| Attribut | Stil |
|---|---|
primary |
Ausgefüllter Primary-Hintergrund, weißer Text, Hover dunkler |
primary-outline |
Primary-Rahmen, transparenter Hintergrund; Hover füllt sich mit Primary |
disabled / :disabled |
opacity-75, kein Klick möglich |
Lizenz
AGPL-3.0-only
Author
JK Effects
