diff --git a/CHANGELOG.md b/CHANGELOG.md index a26138fe..87021408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ ### Features * UI/UX improvements. Now using a custom ConverseJS build. +* Auto color detection: when using ConverseJS, the plugin tries to guess colors to apply to its theme. ### Breaking changes * If you have some CSS customization for the plugin, it may be broken. +* Auto color detection can have bad result for some Peertube theme. If so, you can disable it in the settings. ## v4.0.3 diff --git a/client/admin-plugin-client-plugin.ts b/client/admin-plugin-client-plugin.ts index c98d080c..343f02be 100644 --- a/client/admin-plugin-client-plugin.ts +++ b/client/admin-plugin-client-plugin.ts @@ -227,6 +227,14 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re options.formValues['chat-type'] === ('builtin-converse' as ChatType) || options.formValues['chat-type'] === ('builtin-prosody' as ChatType) ) + case 'converse-autocolors': + return !( + ( + options.formValues['chat-type'] === ('builtin-converse' as ChatType) || + options.formValues['chat-type'] === ('builtin-prosody' as ChatType) + ) && + options.formValues['converse-theme'] === 'peertube' + ) case 'chat-uri': case 'chat-type-help-external-uri': return options.formValues['chat-type'] !== ('external-uri' as ChatType) diff --git a/client/videowatch-client-plugin.ts b/client/videowatch-client-plugin.ts index 787b5108..ef0be018 100644 --- a/client/videowatch-client-plugin.ts +++ b/client/videowatch-client-plugin.ts @@ -1,5 +1,6 @@ -import { videoHasWebchat } from 'shared/lib/video' import type { ChatType } from 'shared/lib/types' +import { videoHasWebchat } from 'shared/lib/video' +import { AutoColors, isAutoColorsAvailable, areAutoColorsValid } from 'shared/lib/autocolors' interface VideoWatchLoadedHookOptions { videojs: any @@ -60,9 +61,78 @@ function register ({ registerHook, peertubeHelpers }: RegisterOptions): void { logger.error('No iframe uri') return null } + + if (isAutoColorsAvailable(settings['chat-type'] as ChatType, settings['converse-theme'])) { + logger.info('We have to try to compute autocolors.') + try { + const autocolors = computeAutoColors() + if (autocolors) { + const url = new URL(iframeUri, window.location.origin) + for (const p in autocolors) { + url.searchParams.set('_ac_' + p, autocolors[p as keyof AutoColors]) + } + iframeUri = url.href + } + } catch (err) { + logger.error(`Failed computing autocolors: '${err as string}'`) + } + } + return iframeUri } + function computeAutoColors (): AutoColors | null { + if (!window.getComputedStyle) { + logger.warn('[AutoColors] getComputedStyle is not available, aborting.') + return null + } + // Searching for one of these button: + const button = document.querySelector('.publish-button, .peertube-button-link') + if (!button) { + logger.warn('[AutoColors] Cant find a button, aborting.') + return null + } + const buttonStyles = window.getComputedStyle(button) + logger.info('[AutoColors] found button styles') + + const main = document.querySelector('#content') + if (!main) { + logger.warn('[AutoColors] Cant find main, aborting.') + return null + } + const mainStyles = window.getComputedStyle(main) + logger.info('[AutoColors] found main styles') + + const menu = document.querySelector('.menu-link') + if (!menu) { + logger.warn('[AutoColors] Cant find menu, aborting.') + return null + } + const menuStyles = window.getComputedStyle(menu) + logger.info('[AutoColors] found menu styles') + + const autocolors: AutoColors = { + mainForeground: mainStyles.color, + mainBackground: mainStyles.backgroundColor, + greyForeground: '#000', + greyBackground: '#000', + menuForeground: menuStyles.color, + menuBackground: menuStyles.backgroundColor, + inputForeground: '#000', + inputBackground: '#000', + buttonForeground: buttonStyles.color, + buttonBackground: buttonStyles.backgroundColor, + link: '#000', + linkHover: '#000' + } + const autoColorsTest = areAutoColorsValid(autocolors) + if (autoColorsTest !== true) { + logger.warn('[AutoColors] Computed colors are not valid, dropping. Invalid values: ' + autoColorsTest.join(', ')) + return null + } + return autocolors + } + function displayButton ( buttonContainer: HTMLElement, name: string, diff --git a/conversejs/index.html b/conversejs/index.html index f1d7d16a..804f128d 100644 --- a/conversejs/index.html +++ b/conversejs/index.html @@ -8,6 +8,7 @@ + {{CONVERSEJS_AUTOCOLORS}} diff --git a/server/lib/routers/webchat.ts b/server/lib/routers/webchat.ts index 24182368..7342349c 100644 --- a/server/lib/routers/webchat.ts +++ b/server/lib/routers/webchat.ts @@ -8,6 +8,7 @@ import { asyncMiddleware } from '../middlewares/async' import { getProsodyDomain } from '../prosody/config/domain' import { getAPIKey } from '../apikey' import { getChannelInfosById, getChannelNameById } from '../database/channel' +import { isAutoColorsAvailable, areAutoColorsValid, AutoColors } from '../../../shared/lib/autocolors' import * as path from 'path' const bodyParser = require('body-parser') const got = require('got') @@ -42,7 +43,7 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise + :root { + --peertube-main-foreground: ${autocolors.mainForeground}; + --peertube-main-background: ${autocolors.mainBackground}; + --peertube-grey-foreground: ${autocolors.greyForeground}; + --peertube-grey-background: ${autocolors.greyBackground}; + --peertube-menu-foreground: ${autocolors.menuForeground}; + --peertube-menu-background: ${autocolors.menuBackground}; + --peertube-input-foreground: ${autocolors.inputForeground}; + --peertube-input-background: ${autocolors.inputBackground}; + --peertube-button-foreground: ${autocolors.buttonForeground}; + --peertube-button-background: ${autocolors.buttonBackground}; + --peertube-link: ${autocolors.link}; + --peertube-link-hover: ${autocolors.linkHover}; + } + + ` + } else { + peertubeHelpers.logger.error('Provided AutoColors are invalid.', autoColorsTest) + } + } else { + peertubeHelpers.logger.debug('No AutoColors.') + } // ... then inject it in the page. page = page.replace(/{{ROOM}}/g, room) page = page.replace(/{{BOSH_SERVICE_URL}}/g, boshUri) @@ -156,6 +204,7 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise +When this settings is enabled, the plugin tries to auto-detect colors to apply to the chat theme.
+If this is not correctly working for some of your Peertube theme, you can disable this option. +You can report the bug on the official + + issue tracker +. Don't forget to specify which theme is not working.` + }) + // ********** Built-in Prosody advanced settings registerSetting({ name: 'prosody-advanced', diff --git a/shared/lib/autocolors.ts b/shared/lib/autocolors.ts new file mode 100644 index 00000000..c0877744 --- /dev/null +++ b/shared/lib/autocolors.ts @@ -0,0 +1,59 @@ +import type { ChatType } from './types' + +type AutoColorValue = string + +interface AutoColors { + mainForeground: AutoColorValue + mainBackground: AutoColorValue + greyForeground: AutoColorValue + greyBackground: AutoColorValue + menuForeground: AutoColorValue + menuBackground: AutoColorValue + inputForeground: AutoColorValue + inputBackground: AutoColorValue + buttonForeground: AutoColorValue + buttonBackground: AutoColorValue + link: AutoColorValue + linkHover: AutoColorValue +} + +/** + * @param chatType value of the settings 'chat-type' + * @param theme value of the settings 'converse-theme' + * @returns true if the theme can use autocolors + */ +function isAutoColorsAvailable (chatType: ChatType, theme: string): boolean { + if (chatType !== 'builtin-prosody' && chatType !== 'builtin-converse') { + return false + } + return theme === 'peertube' // currently the only theme that can handle autocolors. +} + +/** + * @param autocolors + * @returns true if ok. Else a string array with invalid values. + */ +function areAutoColorsValid (autocolors: AutoColors): true | string[] { + const errors: string[] = [] + for (const k in autocolors) { + const color = autocolors[k as keyof AutoColors] + // FIXME: there are missing cases. For now there are only basic values formats. + if ( + !/^rgb\(\d{1,3},\s*\d{1,3},\s*\d{1,3}\)$/.test(color) && + !/^rgba\(\d{1,3},\s*\d{1,3},\s*\d{1,3},\s*(1|0|0?.\d+)\)$/.test(color) && + !/^#[0-9a-fA-F]{3,6}$/.test(color) + ) { + errors.push(color) + } + } + if (errors.length) { + return errors + } + return true +} + +export { + AutoColors, + isAutoColorsAvailable, + areAutoColorsValid +}