Flixy heißt ab hier Halo

Reine Umbenennung, kein Verhalten geändert — bewusst als eigener Commit,
damit „umbenannt" und „umgebaut" im Nachhinein auseinanderzuhalten sind.

712 mal `Flixy`, 778 mal `flixy`, 7 mal `FLIXY` in 169 Dateien, dazu 25
Pfade. Ziele: `Halo`, `HaloTV`, `HaloTopShelf`, `HaloUITests`, `HaloKit` mit
`HaloDesign`, `HaloDownloads`, `HaloPlayback` und `HaloProbe`. `MediaKit`,
`JellyfinKit` und `DownloadWidget` tragen den Namen nicht und bleiben.

`docs/superpowers/specs/` ist ausgenommen. Datierte Entwurfsdokumente sind
ein Protokoll getroffener Entscheidungen; sie nachträglich umzuschreiben
hiesse, die Vergangenheit zu glätten.

**Die Bundle-ID wandert mit** — ausdrücklich so gewollt, mit bekanntem Preis:
`com.scarriffleservices.halo` ist für iOS eine *andere* App. Die installierte
Fassung bleibt daneben stehen, mit Downloads und Anmeldung in ihrem Container;
Halo startet leer. Einmal neu anmelden, heruntergeladene Folgen einmal neu
laden. Dasselbe gilt für die App-Gruppe, die sich TV-App und Top Shelf teilen.

**Eine Folge davon, die beim Entscheiden noch nicht auf dem Tisch lag:** der
Aufräumschritt aus dem vorigen Commit kommt an die alten Plex-Token nicht mehr
heran. Der Schlüsselbund grenzt nach Team und Bundle-Kennung ab — was unter
`…flixy` liegt, ist für `…halo` unerreichbar. Erledigt wird es trotzdem, nur
anders: **die alte App löschen.** iOS räumt deren Schlüsselbund-Einträge beim
Deinstallieren mit ab. Der Code bleibt stehen, weil er für jeden Stand vor
dieser Umbenennung richtig ist und im Jahr einen Startvergleich kostet.

Die Projektdatei ist aus `project.yml` neu erzeugt, der alte Ordner gelöscht
statt umbenannt — sie steht ohnehin nicht im Repo.

Das Verzeichnis des Repos selbst heißt weiter `Flixy`; das umzubenennen ist
ein Handgriff ausserhalb des Projekts.

368 Tests grün. iOS und tvOS bauen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-03 11:12:32 +02:00
co-authored by Claude Opus 5
parent 2fcf6821c8
commit 4b9a1e7b67
280 changed files with 1456 additions and 1456 deletions
+334
View File
@@ -0,0 +1,334 @@
/* ============================================================================
Halo für Jellyfin Web
----------------------------------------------------------------------------
Bringt Jellyfins Weboberfläche auf die Farben, Schrift und Formen der
Halo-App. Es ist ein Kleid, kein Umbau: die Oberfläche bleibt Jellyfins,
sie sieht nur anders aus.
EINBAUEN
Jellyfin-Dashboard → Allgemein → „Benutzerdefiniertes CSS“ — alles hier
hineinkopieren, speichern, Seite neu laden. Gilt serverweit für alle
Browser, also auch auf Windows. Wieder loswerden: Feld leeren.
AUFGEBAUT AUF MESSUNG, NICHT AUF VERMUTUNG
Die Variablennamen und Klassen stammen aus einer laufenden Jellyfin-
Instanz (Stand 09/2026), nicht aus dem Gedächtnis. Der größte Teil der
Wirkung entsteht dadurch, dass Jellyfins **eigene** Farbvariablen
umgebogen werden — das hält das Ganze kurz und überlebt Updates besser
als eine Sammlung einzeln überschriebener Regeln.
========================================================================= */
:root {
/* ---- Die Akzentfarbe -----------------------------------------------
Zum Wechseln nur diese eine Zeile ändern. Die Palette der App:
Ember #E5484D · Tangerine #F76B15 · Amber #FFB224 · Lime #99D52A
Mint #3DD68C · Teal #12A594 · Sky #52A9FF · Indigo #7C77E8
Orchid #C04AC9 · Rose #F76190
Voreingestellt ist Orchid — die Farbe, die auf dem iPad eingestellt
ist. Die App selbst kommt ab Werk mit Mint. */
--halo-accent: #C04AC9;
/* ---- Die Flächen der App, von hinten nach vorn ---------------------- */
--halo-canvas: #0B0B0D; /* Seitenhintergrund */
--halo-surface: #141417; /* Karten, Kopfbereiche */
--halo-elevated: #1D1D21; /* Blätter, Menüs */
--halo-placeholder: #26262B; /* Platzhalter, gedrückte Zustände */
--halo-text: #F5F5F7;
--halo-text-secondary: #A0A0A8;
--halo-text-muted: #6E6E76;
--halo-destructive: #E5484D;
--halo-separator: rgba(255, 255, 255, 0.10);
/* ---- Formen --------------------------------------------------------- */
--halo-radius-card: 8px;
--halo-radius-control: 10px;
--halo-radius-sheet: 16px;
--halo-radius-panel: 22px; /* die schwebende Leiste */
/* ---- Schrift --------------------------------------------------------
Der größte einzelne Hebel. Jellyfin liefert Noto Sans aus; die
Systemschrift macht aus derselben Seite sofort eine, die auf den
Rechner gehört — SF auf Mac und iPhone, Segoe UI Variable auf
Windows 11. */
--halo-font: -apple-system, BlinkMacSystemFont, "SF Pro Text",
"Segoe UI Variable Text", "Segoe UI", system-ui,
Roboto, "Helvetica Neue", sans-serif;
/* ---- Jellyfins eigene Variablen umbiegen ---------------------------
Hier entsteht der Großteil der Wirkung: Jellyfin baut auf einer
MUI-Palette auf, und wer die verstellt, verstellt alles, was darauf
aufsetzt — inklusive Bauteilen, die dieses CSS gar nicht kennt. */
--jf-palette-background-default: var(--halo-canvas);
--jf-palette-background-defaultChannel: 11 11 13;
--jf-palette-background-paper: var(--halo-surface);
--jf-palette-background-paperChannel: 20 20 23;
--jf-palette-primary-main: var(--halo-accent);
--jf-palette-primary-dark: var(--halo-accent);
--jf-palette-primary-light: var(--halo-accent);
--jf-palette-secondary-main: var(--halo-accent);
--jf-palette-secondary-dark: var(--halo-accent);
--jf-palette-secondary-light: var(--halo-accent);
/* Schrift auf dem Akzent: hell, weil die Palette der App durchweg
kräftige Farben hat. Bei einem hellen Akzent (Amber, Lime) hier auf
#101013 stellen, sonst verschwindet die Beschriftung. */
--jf-palette-primary-contrastText: #FFFFFF;
--jf-palette-secondary-contrastText: #FFFFFF;
--jf-palette-text-primary: var(--halo-text);
--jf-palette-text-secondary: var(--halo-text-secondary);
--jf-palette-text-disabled: var(--halo-text-muted);
--jf-palette-text-icon: var(--halo-text-secondary);
--jf-palette-divider: var(--halo-separator);
--jf-palette-error-main: var(--halo-destructive);
--jf-palette-error-dark: #B4373B;
--jf-palette-error-light: #EC6E72;
--jf-palette-action-hover: rgba(255, 255, 255, 0.06);
--jf-palette-action-selected: rgba(255, 255, 255, 0.12);
--jf-palette-action-disabled: var(--halo-text-muted);
/* Die Kopfleiste trägt die Insel — sie selbst bleibt durchsichtig. */
--jf-palette-AppBar-defaultBg: transparent;
--jf-palette-AppBar-darkBg: transparent;
--jf-card-borderRadius: var(--halo-radius-card);
--jf-shape-borderRadius: var(--halo-radius-control);
}
/* ---- Grundfläche und Schrift --------------------------------------------
`html` bekommt seinen Hintergrund bei Jellyfin unmittelbar gesetzt und
nicht über die Palette — deshalb steht er hier noch einmal ausdrücklich. */
html {
background-color: var(--halo-canvas) !important;
font-family: var(--halo-font) !important;
color: var(--halo-text);
}
body,
button,
input,
select,
textarea,
.emby-button,
.emby-input,
.emby-select,
.cardText,
.sectionTitle {
font-family: var(--halo-font) !important;
}
.backgroundContainer,
.mainAnimatedPage {
background-color: var(--halo-canvas) !important;
}
/* ---- Die Kopfleiste als schwebende Insel --------------------------------
Das Merkmal der App: die Navigation ist eine Fläche mit Abstand ringsum,
nicht ein Balken, der am Rand klebt. Der Inhalt läuft dahinter durch.
`backdrop-filter` ist der Kern — und der Grund, warum es auf Safari und
Chrome überzeugender aussieht als auf älteren Firefox-Fassungen. Wo er
fehlt, bleibt eine schlicht gefüllte Fläche; unschön ist das nicht. */
.skinHeader {
background: rgba(20, 20, 23, 0.72) !important;
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
border: 1px solid var(--halo-separator);
border-radius: var(--halo-radius-panel);
margin: 10px 12px 0;
width: calc(100% - 24px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}
.skinHeader-withBackground {
background: rgba(20, 20, 23, 0.72) !important;
}
/* ---- Die Seitenleiste ---------------------------------------------------- */
.mainDrawer {
background-color: var(--halo-surface) !important;
border-right: 1px solid var(--halo-separator);
}
.navMenuOption {
border-radius: var(--halo-radius-control);
margin: 2px 8px;
}
.navMenuOption-selected {
background: var(--halo-elevated) !important;
color: var(--halo-accent) !important;
}
/* ---- Karten -------------------------------------------------------------
Die Poster sind das, was man auf einer Startseite hauptsächlich sieht;
ihre Rundung bestimmt den Eindruck stärker als jede Farbe. Acht Punkt,
wie in der App. */
.cardImageContainer,
.cardContent,
.cardScalable,
.cardOverlayContainer {
border-radius: var(--halo-radius-card) !important;
}
.cardBox {
margin: 0.5em !important;
}
.cardText {
color: var(--halo-text);
}
.cardText-secondary {
color: var(--halo-text-secondary);
}
.defaultCardBackground,
.defaultCardBackground1,
.defaultCardBackground2,
.defaultCardBackground3,
.defaultCardBackground4,
.defaultCardBackground5 {
background-color: var(--halo-placeholder) !important;
}
/* Der Fortschrittsbalken auf angefangenen Titeln — in der App trägt er den
Akzent, und er ist dünner als Jellyfins Voreinstellung. */
.itemProgressBarForeground {
background-color: var(--halo-accent) !important;
}
.itemProgressBar {
height: 3px !important;
border-radius: 2px;
background-color: rgba(255, 255, 255, 0.18) !important;
}
/* ---- Knöpfe -------------------------------------------------------------- */
.emby-button,
.button-flat,
.detailButton {
border-radius: var(--halo-radius-control) !important;
font-family: var(--halo-font) !important;
}
.emby-button.raised {
background: var(--halo-elevated);
color: var(--halo-text);
}
.emby-button.raised.button-submit,
.button-submit {
background: var(--halo-accent) !important;
color: #FFFFFF !important;
}
/* Die Kapselform der App für die Hauptknöpfe einer Detailseite. */
.detailPagePrimaryContainer .emby-button,
.mainDetailButtons .emby-button {
border-radius: 999px !important;
}
/* ---- Eingabefelder ------------------------------------------------------- */
.emby-input,
.emby-select,
.emby-textarea {
background-color: var(--halo-elevated) !important;
border: 1px solid var(--halo-separator) !important;
border-radius: var(--halo-radius-control) !important;
color: var(--halo-text) !important;
}
.emby-input:focus,
.emby-select:focus {
border-color: var(--halo-accent) !important;
outline: none;
}
.inputLabel,
.selectLabel,
.fieldDescription {
color: var(--halo-text-secondary) !important;
}
/* ---- Blätter, Menüs, Dialoge --------------------------------------------- */
.dialog,
.formDialog,
.actionSheet,
.paper-icon-button-light + .actionSheet {
background-color: var(--halo-elevated) !important;
border-radius: var(--halo-radius-sheet) !important;
border: 1px solid var(--halo-separator);
}
.actionSheetMenuItem:hover,
.listItem:hover {
background-color: var(--jf-palette-action-hover) !important;
}
/* ---- Detailseite --------------------------------------------------------- */
.detailPagePrimaryContainer,
.detailPageSecondaryContainer,
.detailRibbon {
background: transparent !important;
}
.detailSectionContent,
.detailTableBodyCell {
color: var(--halo-text-secondary);
}
/* Das Hintergrundbild soll nach unten in die Seitenfarbe auslaufen, statt an
einer Kante aufzuhören — dieselbe Verlaufsidee wie im Aufmacher der App. */
.itemBackdrop {
-webkit-mask-image: linear-gradient(to bottom,
rgba(0, 0, 0, 1) 0%,
rgba(0, 0, 0, 0.85) 45%,
rgba(0, 0, 0, 0) 100%);
mask-image: linear-gradient(to bottom,
rgba(0, 0, 0, 1) 0%,
rgba(0, 0, 0, 0.85) 45%,
rgba(0, 0, 0, 0) 100%);
}
/* ---- Überschriften ------------------------------------------------------- */
.sectionTitle {
color: var(--halo-text) !important;
font-weight: 600;
letter-spacing: -0.01em;
}
/* ---- Trennlinien und Kleinkram ------------------------------------------- */
.listItem-border,
.detailTableBodyCell,
hr {
border-color: var(--halo-separator) !important;
}
::selection {
background: var(--halo-accent);
color: #FFFFFF;
}
/* Die Bildlaufleisten dunkel halten — eine helle Leiste am Rand ist das
Erste, was eine sonst dunkle Seite verrät. */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.14);
border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.22);
}