diff --git a/apps/desktop/element.io/healthchat/config.json b/apps/desktop/element.io/healthchat/config.json index 8603c7ec75..0fb25e2d2b 100644 --- a/apps/desktop/element.io/healthchat/config.json +++ b/apps/desktop/element.io/healthchat/config.json @@ -8,21 +8,14 @@ "bug_report_endpoint_url": "https://element.io/bugreports/submit", "default_country_code": "GB", "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.healthchat.ch", - "server_name": "healthchat.ch" - }, - "m.identity_server": { - "base_url": "" - } + "m.homeserver": { "base_url": "https://matrix.healthchat.ch", "server_name": "healthchat.ch" }, + "m.identity_server": { "base_url": "" } }, "default_theme": "custom-HealthChat Light", "disable_custom_urls": true, "disable_guests": true, "element_call": {}, - "embedded_pages": { - "homeUrl": "" - }, + "embedded_pages": { "homeUrl": "" }, "enable_presence_by_hs_url": "", "features": {}, "help_url": "https://www.healthchat.ch", @@ -30,19 +23,11 @@ "integrations_rest_url": "https://scalar.vector.im/api", "integrations_ui_url": "https://scalar.vector.im/", "integrations_widgets_urls": ["https://scalar.vector.im/api"], - "jitsi": { - "preferred_domain": "jitsi.healthchat.ch" - }, + "jitsi": { "preferred_domain": "jitsi.healthchat.ch" }, "logout_redirect_url": "", "matrix_to_url": "https://to.healthchat.ch", - "room_directory": { - "servers": ["matrix.org"] - }, - "sso_redirect_options": { - "immediate": true, - "on_welcome_page": true, - "on_login_page": true - }, + "room_directory": { "servers": ["matrix.org"] }, + "sso_redirect_options": { "immediate": true, "on_welcome_page": true, "on_login_page": true }, "setting_defaults": { "UIFeature.deactivate": false, "UIFeature.advancedEncryption": false, @@ -52,7 +37,6 @@ "UIFeature.advancedSettings": false, "UIFeature.feedback": false, "custom_themes": [ - "HealthChat Light", { "name": "HealthChat Light", "is_dark": false, @@ -80,11 +64,18 @@ "reaction-row-button-selected-bg-color": "#d9d9d9", "togglesw-off-color": "#9b9898", "avatar-background-colors": ["#12325c", "#1f4d85", "#376A91"], - "username-colors": ["#12325c", "#2a4063", "#1f4d85", "#376A91", "#473e3e", "#1f4d85", "#2a4063", "#12325c"] - }, - "fonts": { - "general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif" + "username-colors": [ + "#12325c", + "#2a4063", + "#1f4d85", + "#376A91", + "#473e3e", + "#1f4d85", + "#2a4063", + "#12325c" + ] }, + "fonts": { "general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif" }, "compound": { "--cpd-color-text-action-accent": "#1f4d85", "--cpd-color-bg-action-primary-rest": "#1f4d85", @@ -99,8 +90,5 @@ "show_labs_settings": false, "update_base_url": "https://healthchat.ch/packages/desktop/update/", "modules": ["/modules/healthchat-module.js"], - "ch.healthchat": { - "api_base_url": "https://api.healthchat.ch", - "elements_base_url": "/webapp/modules/elements" - } + "ch.healthchat": { "api_base_url": "https://api.healthchat.ch", "elements_base_url": "/webapp/modules/elements" } } diff --git a/apps/web/config.json b/apps/web/config.json index 77ea15ae9e..9fbd77bce0 100644 --- a/apps/web/config.json +++ b/apps/web/config.json @@ -8,44 +8,25 @@ "bug_report_endpoint_url": "https://element.io/bugreports/submit", "default_country_code": "GB", "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix.healthchat.ch", - "server_name": "healthchat.ch" - }, - "m.identity_server": { - "base_url": "" - } + "m.homeserver": { "base_url": "https://matrix.healthchat.ch", "server_name": "healthchat.ch" }, + "m.identity_server": { "base_url": "" } }, "default_theme": "custom-HealthChat Light", "disable_custom_urls": true, "disable_guests": true, "element_call": {}, - "embedded_pages": { - "homeUrl": "" - }, + "embedded_pages": { "homeUrl": "" }, "enable_presence_by_hs_url": "", "features": {}, "integrations_jitsi_widget_url": "https://scalar.vector.im/api/widgets/jitsi.html", "integrations_rest_url": "https://scalar.vector.im/api", "integrations_ui_url": "https://scalar.vector.im/", - "integrations_widgets_urls": [ - "https://scalar.vector.im/api" - ], - "jitsi": { - "preferred_domain": "jitsi.healthchat.ch" - }, + "integrations_widgets_urls": ["https://scalar.vector.im/api"], + "jitsi": { "preferred_domain": "jitsi.healthchat.ch" }, "logout_redirect_url": "", "matrix_to_url": "https://to.healthchat.ch", - "room_directory": { - "servers": [ - "matrix.org" - ] - }, - "sso_redirect_options": { - "immediate": true, - "on_welcome_page": true, - "on_login_page": true - }, + "room_directory": { "servers": ["matrix.org"] }, + "sso_redirect_options": { "immediate": true, "on_welcome_page": true, "on_login_page": true }, "setting_defaults": { "UIFeature.deactivate": false, "UIFeature.advancedEncryption": false, @@ -55,7 +36,6 @@ "UIFeature.advancedSettings": false, "UIFeature.feedback": false, "custom_themes": [ - "HealthChat Light", { "name": "HealthChat Light", "is_dark": false, @@ -74,8 +54,8 @@ "timeline-highlights-color": "#d9d9d9", "timeline-text-color": "#473e3e", "timeline-text-secondary-color": "#9b9898", - "secondary-content": "#6e6a6a", - "tertiary-content": "#6e6a6a", + "secondary-content": "#9b9898", + "tertiary-content": "#9b9898", "focus-bg-color": "#d9d9d9", "menu-selected-color": "#d9d9d9", "other-user-pill-bg-color": "#376A91", @@ -83,30 +63,30 @@ "reaction-row-button-selected-bg-color": "#d9d9d9", "togglesw-off-color": "#9b9898", "avatar-background-colors": ["#12325c", "#1f4d85", "#376A91"], - "username-colors": ["#12325c", "#2a4063", "#1f4d85", "#376A91", "#473e3e", "#1f4d85", "#2a4063", "#12325c"] - }, - "fonts": { - "general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif" + "username-colors": [ + "#12325c", + "#2a4063", + "#1f4d85", + "#376A91", + "#473e3e", + "#1f4d85", + "#2a4063", + "#12325c" + ] }, + "fonts": { "general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif" }, "compound": { "--cpd-color-text-action-accent": "#1f4d85", "--cpd-color-bg-action-primary-rest": "#1f4d85", "--cpd-color-bg-action-primary-hovered": "#2a4063", "--cpd-color-bg-action-primary-pressed": "#12325c", "--cpd-color-text-link-external": "#1f4d85", - "--cpd-color-icon-accent-tertiary": "#376A91", - "--cpd-color-icon-tertiary": "#5c6470", - "--cpd-color-icon-quaternary": "#7c8591", - "--cpd-color-icon-accent-primary": "#1f4d85", - "--cpd-color-icon-info-primary": "#1f4d85" + "--cpd-color-icon-accent-tertiary": "#376A91" } } ] }, "show_labs_settings": false, "modules": ["/modules/healthchat-module.js"], - "ch.healthchat": { - "api_base_url": "http://localhost:5001", - "elements_base_url": "/modules/elements" - } + "ch.healthchat": { "api_base_url": "http://localhost:5001", "elements_base_url": "/modules/elements" } } diff --git a/apps/web/element.io/healthchat/HealthChat-Light-Theme.json b/apps/web/element.io/healthchat/HealthChat-Light-Theme.json new file mode 100644 index 0000000000..f178418d59 --- /dev/null +++ b/apps/web/element.io/healthchat/HealthChat-Light-Theme.json @@ -0,0 +1,41 @@ +{ + "name": "HealthChat Light", + "is_dark": false, + "colors": { + "accent-color": "#1f4d85", + "primary-color": "#1f4d85", + "alert": "#df8e1d", + "warning-color": "#d20f39", + "sidebar-color": "#12325c", + "roomlist-background-color": "#f5f5f5", + "roomlist-highlights-color": "#d9d9d9", + "roomlist-separator-color": "#9b9898", + "roomlist-text-color": "#473e3e", + "roomlist-text-secondary-color": "#9b9898", + "timeline-background-color": "#ffffff", + "timeline-highlights-color": "#d9d9d9", + "timeline-text-color": "#473e3e", + "timeline-text-secondary-color": "#9b9898", + "secondary-content": "#9b9898", + "tertiary-content": "#9b9898", + "focus-bg-color": "#d9d9d9", + "menu-selected-color": "#d9d9d9", + "other-user-pill-bg-color": "#376A91", + "room-highlight-color": "#376A91", + "reaction-row-button-selected-bg-color": "#d9d9d9", + "togglesw-off-color": "#9b9898", + "avatar-background-colors": ["#12325c", "#1f4d85", "#376A91"], + "username-colors": ["#12325c", "#2a4063", "#1f4d85", "#376A91", "#473e3e", "#1f4d85", "#2a4063", "#12325c"] + }, + "fonts": { + "general": "\"Century Gothic\", \"Futura\", \"Trebuchet MS\", \"Arial\", sans-serif" + }, + "compound": { + "--cpd-color-text-action-accent": "#1f4d85", + "--cpd-color-bg-action-primary-rest": "#1f4d85", + "--cpd-color-bg-action-primary-hovered": "#2a4063", + "--cpd-color-bg-action-primary-pressed": "#12325c", + "--cpd-color-text-link-external": "#1f4d85", + "--cpd-color-icon-accent-tertiary": "#376A91" + } +} diff --git a/apps/web/element.io/healthchat/README b/apps/web/element.io/healthchat/README new file mode 100644 index 0000000000..be4470ac9f --- /dev/null +++ b/apps/web/element.io/healthchat/README @@ -0,0 +1,25 @@ +HealthChat theme — single source of truth +========================================= + + HealthChat-Light-Theme.json The canonical "HealthChat Light" theme. + +Edit the palette HERE and nowhere else. apps/web/scripts/healthchat-sync-theme.mjs injects +it into the element-web configs that ship it: + + - apps/web/config.json (dev server; also baked into the web image) + - apps/desktop/element.io/healthchat/config.json (desktop variant, bundled into the app) + +After editing, run: + pnpm --filter element-web healthchat:theme +`pnpm lint` runs `healthchat:theme:check`, which fails if a config is out of sync — so an +un-propagated edit is caught in CI. + +Production web deployment +------------------------- +The production web client is deployed by matrix-docker-ansible-deploy, whose +matrix-client-element role renders config.json from host_vars (no upstream role change). +It carries an INLINE copy of this theme in + inventory/host_vars/matrix.healthchat.ch/vars.yml + (matrix_client_element_setting_defaults_custom_themes) +When you change the theme here, re-copy it into that host_vars block. themes_enabled is off +there, so the (stale) Novaloop-AG/element-themes repo does not append an older theme. diff --git a/apps/web/package.json b/apps/web/package.json index 2735153070..ce56c6fe80 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -18,13 +18,15 @@ "i18n:lint": "matrix-i18n-lint && prettier --log-level=silent --write src/i18n/strings/ --ignore-path /dev/null", "i18n:diff": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && pnpm i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json", "rethemendex": "sh ./res/css/rethemendex.sh", + "healthchat:theme": "node scripts/healthchat-sync-theme.mjs", + "healthchat:theme:check": "node scripts/healthchat-sync-theme.mjs --check", "build": "nx build", "build-stats": "nx build --json=webpack-stats.json", "vendor:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js && mv src/vector/modernizr.js src/vector/modernizr.cjs", "vendor:jitsi": "curl -s https://meet.element.io/libs/external_api.min.js > ./res/jitsi_external_api.min.js", "dist": "./scripts/package.sh", "start": "nx start", - "lint": "pnpm lint:types && pnpm lint:js && pnpm lint:style", + "lint": "pnpm healthchat:theme:check && pnpm lint:types && pnpm lint:js && pnpm lint:style", "lint:js": "eslint --max-warnings 0 src test playwright module_system", "lint:js-fix": "eslint --fix src test playwright module_system", "lint:types": "nx lint:types", diff --git a/apps/web/scripts/healthchat-sync-theme.mjs b/apps/web/scripts/healthchat-sync-theme.mjs new file mode 100644 index 0000000000..9786cac5af --- /dev/null +++ b/apps/web/scripts/healthchat-sync-theme.mjs @@ -0,0 +1,70 @@ +#!/usr/bin/env node +/* + * HealthChat theme sync. + * + * Single source of truth for the "HealthChat Light" theme lives in + * apps/web/element.io/healthchat/HealthChat-Light-Theme.json + * This script injects it into every element-web config that ships the theme, so the palette + * is authored once and never drifts between the dev and desktop configs. + * + * The production web deployment (matrix-docker-ansible-deploy) renders its config.json from + * host_vars and carries an inline copy of this theme; re-copy this file there when it changes. + * + * Usage: + * node apps/web/scripts/healthchat-sync-theme.mjs # write the theme into all configs + * node apps/web/scripts/healthchat-sync-theme.mjs --check # exit 1 if any config is out of sync + * + * Run `pnpm --filter element-web healthchat:theme` after editing the canonical theme; + * the --check variant runs in lint/CI to catch an un-synced edit. + */ +import { readFileSync, writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; +import prettier from "prettier"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(scriptDir, "../../.."); + +const CANONICAL = resolve(repoRoot, "apps/web/element.io/healthchat/HealthChat-Light-Theme.json"); + +// Configs that must carry the theme in setting_defaults.custom_themes. +const TARGETS = [ + "apps/web/config.json", // dev server config (also served by the web Docker image) + "apps/desktop/element.io/healthchat/config.json", // desktop variant config bundled into the app +]; + +const check = process.argv.includes("--check"); + +const theme = JSON.parse(readFileSync(CANONICAL, "utf8")); + +let changed = 0; +for (const rel of TARGETS) { + const path = resolve(repoRoot, rel); + const raw = readFileSync(path, "utf8"); + const config = JSON.parse(raw); + config.setting_defaults ??= {}; + config.setting_defaults.custom_themes = [theme]; + + // Format identically to `prettier --write` so the output is byte-for-byte what the + // repo's formatting lint expects, keeping --check stable. + const options = await prettier.resolveConfig(path); + const next = await prettier.format(JSON.stringify(config), { ...options, filepath: path }); + + if (next === raw) { + continue; + } + changed++; + if (check) { + console.error(`out of sync: ${rel} (run: pnpm --filter element-web healthchat:theme)`); + } else { + writeFileSync(path, next); + console.log(`synced theme -> ${rel}`); + } +} + +if (check) { + if (changed > 0) process.exit(1); + console.log("all configs in sync with the canonical HealthChat theme"); +} else if (changed === 0) { + console.log("all configs already in sync"); +}