diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/apply-opencentauri-fluidd-theme.py b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/apply-opencentauri-fluidd-theme.py
new file mode 100644
index 00000000..04543ef4
--- /dev/null
+++ b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/apply-opencentauri-fluidd-theme.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python3
+import json
+import re
+import sys
+from pathlib import Path
+
+
+APP_NAME = "OpenCentauri"
+DESCRIPTION = "OpenCentauri web interface for the Elegoo Centauri Carbon"
+PRIMARY_COLOR = "#D8DADC"
+LOGO_SRC = "logo_opencentauri.svg"
+ICON_SRC = "carbon-logo-red.webp"
+WORDMARK_SRC = "opencentauri-logo-small.png"
+THEME_CSS = "opencentauri-theme.css"
+
+
+def replace_once(text, old, new, path):
+ if old not in text:
+ raise RuntimeError(f"{path}: expected text not found: {old[:80]!r}")
+ return text.replace(old, new, 1)
+
+
+def patch_index_html(webroot):
+ path = webroot / "index.html"
+ text = path.read_text()
+ text = re.sub(r"
.*?", f"{APP_NAME}", text, count=1)
+ # Add data-fluidd-theme to html tag for immediate CSS scoping (prevents FOUC)
+ text = text.replace("", f'')
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'\s*\n',
+ "\n",
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ text = re.sub(
+ r'',
+ f'',
+ text,
+ count=1,
+ )
+ if THEME_CSS not in text:
+ text = text.replace(
+ '',
+ f'\n ',
+ 1,
+ )
+ path.write_text(text)
+
+
+def patch_manifest(webroot):
+ path = webroot / "manifest.webmanifest"
+ manifest = json.loads(path.read_text())
+ manifest.update(
+ {
+ "name": APP_NAME,
+ "short_name": APP_NAME,
+ "description": DESCRIPTION,
+ "theme_color": PRIMARY_COLOR,
+ "icons": [
+ {
+ "src": ICON_SRC,
+ "sizes": "128x128",
+ "type": "image/webp",
+ "purpose": "any maskable",
+ }
+ ],
+ }
+ )
+ path.write_text(json.dumps(manifest, separators=(",", ":")))
+
+
+def patch_config(webroot):
+ path = webroot / "config.json"
+ config = json.loads(path.read_text())
+ presets = [p for p in config.get("themePresets", []) if p.get("name") != APP_NAME]
+ presets.insert(
+ 0,
+ {
+ "name": APP_NAME,
+ "color": PRIMARY_COLOR,
+ "isDark": True,
+ "logo": {
+ "src": LOGO_SRC,
+ "dark": "#232323",
+ "light": "#ffffff",
+ },
+ },
+ )
+ config["themePresets"] = presets
+ # Set OpenCentauri as the default active theme for new users
+ config["theme"] = {
+ "color": PRIMARY_COLOR,
+ "isDark": True,
+ "logo": {
+ "src": LOGO_SRC,
+ "dark": "#232323",
+ "light": "#ffffff",
+ },
+ }
+ path.write_text(json.dumps(config, indent=2) + "\n")
+
+
+def patch_main_bundle(webroot):
+ """Patch the main JS bundle to add theme-aware dataset toggling."""
+ bundles = sorted((webroot / "assets").glob("index-*.js"))
+ if len(bundles) != 1:
+ raise RuntimeError(f"{webroot}: expected exactly one assets/index-*.js bundle, found {len(bundles)}")
+
+ path = bundles[0]
+ text = path.read_text()
+
+ # Patch onThemeChange to toggle a data attribute for CSS scoping.
+ # We detect OpenCentauri by logo src (not name) because the name field
+ # persists across theme switches via Fluidd's object-merge in updateTheme.
+ old_on_theme_change = "async onThemeChange(e,t){let n=Io.framework.theme;n.dark=t.isDark,n.currentTheme.primary=t.color,n.currentTheme[`primary-offset`]=new ft(t.color).desaturate(5).darken(10).toHexString(),n.themes.dark.logo=t.logo.light,n.themes.light.logo=t.logo.dark}"
+ new_on_theme_change = 'async onThemeChange(e,t){let n=Io.framework.theme;n.dark=t.isDark,n.currentTheme.primary=t.color,n.currentTheme[`primary-offset`]=new ft(t.color).desaturate(5).darken(10).toHexString(),n.themes.dark.logo=t.logo.light,n.themes.light.logo=t.logo.dark;document.documentElement.dataset.fluiddTheme=(t.logo?.src===`logo_opencentauri.svg`)?`OpenCentauri`:``}'
+ text = replace_once(text, old_on_theme_change, new_on_theme_change, path)
+
+ # Override the default favicon globally (all themes show OpenCentauri favicon)
+ old_icon = 'get defaultIconDataUrl(){let e=``;return`data:image/svg+xml;base64,${btoa(e)}`}'
+ new_icon = f'get defaultIconDataUrl(){{return`./{ICON_SRC}`}}'
+ text = replace_once(text, old_icon, new_icon, path)
+
+ path.write_text(text)
+
+
+def patch_state_chunk(webroot):
+ """Patch the initial Vuex state so OpenCentauri is the default theme."""
+ chunks = sorted((webroot / "assets").glob("state-*.js"))
+ if not chunks:
+ return # Not all builds have this chunk
+
+ old_theme = "theme:{isDark:!0,logo:{src:`logo_fluidd.svg`},color:`#2196F3`,backgroundLogo:!0}"
+ new_theme = f"theme:{{isDark:!0,logo:{{src:`{LOGO_SRC}`}},color:`{PRIMARY_COLOR}`,backgroundLogo:!0}}"
+
+ for path in chunks:
+ text = path.read_text()
+ if old_theme in text:
+ text = text.replace(old_theme, new_theme)
+ path.write_text(text)
+ return # Patched successfully
+
+ raise RuntimeError(f"{webroot}/assets: expected hardcoded default theme not found in any state chunk")
+
+
+def verify_assets(webroot):
+ for name in (ICON_SRC, WORDMARK_SRC, LOGO_SRC, THEME_CSS):
+ path = webroot / name
+ if not path.exists():
+ raise RuntimeError(f"{path}: missing OpenCentauri theme asset")
+
+
+def main():
+ if len(sys.argv) != 2:
+ raise SystemExit(f"usage: {Path(sys.argv[0]).name} /path/to/fluidd-webroot")
+
+ webroot = Path(sys.argv[1])
+ verify_assets(webroot)
+ patch_index_html(webroot)
+ patch_manifest(webroot)
+ patch_config(webroot)
+ patch_main_bundle(webroot)
+ patch_state_chunk(webroot)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/carbon-logo-red.webp b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/carbon-logo-red.webp
new file mode 100755
index 00000000..68194f9a
Binary files /dev/null and b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/carbon-logo-red.webp differ
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/logo_opencentauri.svg b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/logo_opencentauri.svg
new file mode 100644
index 00000000..ce9afaa4
--- /dev/null
+++ b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/logo_opencentauri.svg
@@ -0,0 +1,10638 @@
+
+
+
+
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon-gray.webp b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon-gray.webp
new file mode 100644
index 00000000..0f78be7a
Binary files /dev/null and b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon-gray.webp differ
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon.webp b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon.webp
new file mode 100644
index 00000000..0afad0c3
Binary files /dev/null and b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-icon.webp differ
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-logo-small.png b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-logo-small.png
new file mode 100644
index 00000000..da6de1e7
Binary files /dev/null and b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-logo-small.png differ
diff --git a/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-theme.css b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-theme.css
new file mode 100644
index 00000000..bd2a73a9
--- /dev/null
+++ b/meta-opencentauri/recipes-apps/fluidd/files/opencentauri-fluidd-theme/opencentauri-theme.css
@@ -0,0 +1,281 @@
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application {
+ --oc-bg: #050505;
+ --oc-surface: #111111;
+ --oc-surface-raised: #171717;
+ --oc-surface-muted: #1f1f1f;
+ --oc-border: rgba(255, 255, 255, 0.12);
+ --oc-border-strong: rgba(255, 255, 255, 0.2);
+ --oc-text: rgba(255, 255, 255, 0.92);
+ --oc-text-muted: rgba(255, 255, 255, 0.62);
+ --oc-text-disabled: rgba(255, 255, 255, 0.38);
+ --oc-primary: #d8dadc;
+ --oc-primary-muted: #aeb2b6;
+ --oc-success: #8fa392;
+ --oc-info: #8d98a6;
+ --oc-warning: #b9a77a;
+ --oc-error: #b98282;
+ --v-primary-base: var(--oc-primary);
+ --v-primary-lighten1: #eeeeee;
+ --v-primary-darken1: #aeb2b6;
+ --v-primary-offset-base: #aeb2b6;
+ --v-secondary-base: #8d8d8d;
+ --v-card-heading-base: #1b1b1b;
+ --v-btncolor-base: #202020;
+ --v-btncolor-lighten1: #292929;
+ --v-btncolor-lighten2: #333333;
+ --v-btncolor-darken1: #161616;
+ --v-btncolor-darken2: #101010;
+ --v-btncolor-darken4: #050505;
+ --v-drawer-base: #080808;
+ --v-appbar-base: #050505;
+ --v-success-base: var(--oc-success);
+ --v-info-base: var(--oc-info);
+ --v-warning-base: var(--oc-warning);
+ --v-error-base: var(--oc-error);
+ color: var(--oc-text);
+ background: var(--oc-bg) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-main,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-main__wrap,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-application--wrap {
+ background: transparent !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-app-bar,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-toolbar,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-toolbar__content,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-toolbar__extension {
+ background-color: var(--oc-bg) !important;
+ border-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-navigation-drawer,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-navigation-drawer .v-navigation-drawer__content,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-list {
+ background-color: #080808 !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-card,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-sheet,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-menu__content,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-dialog,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-expansion-panels .v-expansion-panel,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-data-table,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-tabs-items,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-picker,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-stepper {
+ color: var(--oc-text) !important;
+ background-color: var(--oc-surface) !important;
+ border-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-card,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-sheet,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-menu__content,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-dialog,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-expansion-panels .v-expansion-panel {
+ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark .v-card .v-card__title.collapsable-card-title,
+[data-fluidd-theme="OpenCentauri"] .theme--dark .card-heading,
+[data-fluidd-theme="OpenCentauri"] .theme--dark .v-toolbar.card-heading,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-toolbar.card-heading {
+ color: var(--oc-text) !important;
+ background-color: var(--oc-surface-muted) !important;
+ border-bottom: thin solid var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-card__subtitle,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-list-item__subtitle,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .dim--text,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .text--secondary {
+ color: var(--oc-text-muted) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-icon,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-label,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-input,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-select__selection,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application input,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application textarea {
+ color: var(--oc-text) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-list-item--disabled,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn--disabled,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-input--is-disabled,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .text--disabled {
+ color: var(--oc-text-disabled) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-list-item:hover:before,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-list-item--active:before,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-tab:before,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn:before {
+ background-color: #ffffff !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-list-item--active,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-tab--active,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn.primary,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn.accent {
+ color: #ffffff !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn.primary,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn.accent {
+ background-color: #2a2a2a !important;
+ border: thin solid var(--oc-border-strong) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-btn:not(.v-btn--text):not(.v-btn--icon):not(.v-btn--plain) {
+ box-shadow: none !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-chip,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-alert,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-snack__wrapper {
+ color: var(--oc-text) !important;
+ background-color: var(--oc-surface-raised) !important;
+ border-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-alert.success,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-chip.success {
+ background-color: rgba(143, 163, 146, 0.18) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-alert.info,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-chip.info {
+ background-color: rgba(141, 152, 166, 0.18) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-alert.warning,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-chip.warning {
+ background-color: rgba(185, 167, 122, 0.2) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-alert.error,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-chip.error {
+ background-color: rgba(185, 130, 130, 0.2) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-badge__badge {
+ background-color: #333333 !important;
+ color: #ffffff !important;
+ border: 2px solid #ffffff !important;
+ border-radius: 50% !important;
+ box-sizing: border-box;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-data-table > .v-data-table__wrapper > table > thead > tr > th,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-data-table > .v-data-table__wrapper > table > tbody > tr > td {
+ color: var(--oc-text) !important;
+ border-bottom-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-data-table > .v-data-table__wrapper > table > tbody > tr:hover:not(.v-data-table__expanded__content):not(.v-data-table__empty-wrapper),
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .file-system .theme--dark.v-data-table tr > td.actions div {
+ background-color: var(--oc-surface-raised) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .file-system .theme--dark.v-data-table tr > td.actions div:before {
+ background: linear-gradient(90deg, rgba(23, 23, 23, 0) 0%, var(--oc-surface-raised) 100%) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-text-field > .v-input__control > .v-input__slot,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-select > .v-input__control > .v-input__slot,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-input--selection-controls__input,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-slider__track-background {
+ background-color: #0d0d0d !important;
+ border-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-input__slot:before,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-input__slot:after,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-divider {
+ border-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-progress-linear__background,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-slider__track-background {
+ background-color: #2a2a2a !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-progress-linear__determinate,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-slider__track-fill,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-slider__thumb,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-tabs-slider {
+ background-color: var(--oc-primary-muted) !important;
+ border-color: var(--oc-primary-muted) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-navigation-drawer__border,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-toolbar--extended .v-toolbar__content,
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .v-card:not(.collapsed) .v-card__title.collapsable-card-title {
+ box-shadow: none !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark.v-application .background-logo {
+ width: min(38vw, 560px) !important;
+ height: auto !important;
+ opacity: 0.3 !important;
+ filter: grayscale(1) invert(1) brightness(1.15) contrast(1.05) !important;
+}
+[data-fluidd-theme="OpenCentauri"] .toolbar-logo .logo-wrapper,
+[data-fluidd-theme="OpenCentauri"] .toolbar-logo .logo-wrapper svg {
+ width: 56px;
+ height: 56px;
+}
+
+[data-fluidd-theme="OpenCentauri"] .theme--dark .toolbar-logo {
+ background-color: var(--oc-bg) !important;
+ border-right-color: var(--oc-border) !important;
+}
+
+[data-fluidd-theme="OpenCentauri"] .toolbar-logo .logo-wrapper {
+ background-image: url("./logo_opencentauri.svg");
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 48px 48px;
+ filter: grayscale(1) invert(1) brightness(0.82);
+}
+
+[data-fluidd-theme="OpenCentauri"] .toolbar-logo .logo-wrapper svg {
+ display: block;
+ opacity: 0;
+}
+
+[data-fluidd-theme="OpenCentauri"] .printer-title {
+ display: flex;
+ align-items: center;
+ min-width: 128px;
+}
+
+[data-fluidd-theme="OpenCentauri"] .printer-title > a {
+ display: block;
+ width: min(240px, 42vw);
+ height: 30px;
+ overflow: hidden;
+ color: transparent;
+ font-size: 0;
+ line-height: 0;
+ background-image: url("./opencentauri-logo-small.png");
+ background-repeat: no-repeat;
+ background-position: left center;
+ background-size: contain;
+}
+
+@media only screen and (max-width: 599px) {
+ [data-fluidd-theme="OpenCentauri"] .toolbar-title {
+ max-width: 72%;
+ padding-left: 8px;
+ }
+
+ [data-fluidd-theme="OpenCentauri"] .printer-title > a {
+ width: min(210px, 58vw);
+ height: 24px;
+ }
+}
diff --git a/meta-opencentauri/recipes-apps/fluidd/fluidd_1.37.0.bb b/meta-opencentauri/recipes-apps/fluidd/fluidd_1.37.0.bb
index 81f3428f..d0ee54c4 100644
--- a/meta-opencentauri/recipes-apps/fluidd/fluidd_1.37.0.bb
+++ b/meta-opencentauri/recipes-apps/fluidd/fluidd_1.37.0.bb
@@ -6,10 +6,13 @@ HOMEPAGE = "https://github.com/fluidd-core/fluidd"
LICENSE = "GPL-3.0-only"
LIC_FILES_CHKSUM = "file://index.html;md5=e465c9484b3a1201b4cff1978e78b863"
+inherit python3native
+
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI = "https://github.com/fluidd-core/fluidd/releases/download/v${PV}/fluidd.zip;downloadfilename=fluidd-${PV}.zip;subdir=fluidd \
file://fluidd.cfg \
+ file://opencentauri-fluidd-theme \
"
SRC_URI[sha256sum] = "b9f003a82ea9061a77c5b2f47c5cdd15c58c8f5f5532960e811be2b01cf0a00b"
@@ -31,6 +34,13 @@ do_install() {
# Install static web files
install -d ${D}/var/www/fluidd
cp -r ${S}/* ${D}/var/www/fluidd/
+ install -m 0644 \
+ ${WORKDIR}/opencentauri-fluidd-theme/logo_opencentauri.svg \
+ ${WORKDIR}/opencentauri-fluidd-theme/carbon-logo-red.webp \
+ ${WORKDIR}/opencentauri-fluidd-theme/opencentauri-logo-small.png \
+ ${WORKDIR}/opencentauri-fluidd-theme/opencentauri-theme.css \
+ ${D}/var/www/fluidd/
+ ${PYTHON} ${WORKDIR}/opencentauri-fluidd-theme/apply-opencentauri-fluidd-theme.py ${D}/var/www/fluidd
# Install default fluidd config
install -d ${D}${sysconfdir}/klipper