Autocolors
WIP on a new feature: trying to guess current Peertube theme's colors, and apply them to ConverseJS.
This commit is contained in:
parent
fbb2e8345c
commit
8999133dcc
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -8,6 +8,7 @@
|
||||
<link type="text/css" rel="stylesheet" media="screen" href="{{BASE_STATIC_URL}}conversejs/converse.min.css" />
|
||||
<script type="text/javaScript" src="{{BASE_STATIC_URL}}conversejs/converse.min.js"></script>
|
||||
<script type="text/javascript" src="{{BASE_STATIC_URL}}static/builtin.js"></script>
|
||||
{{CONVERSEJS_AUTOCOLORS}}
|
||||
</head>
|
||||
<body class="converse-fullscreen theme-peertube">
|
||||
<noscript>You need to enable JavaScript to run the Converse.js chat app.</noscript>
|
||||
|
@ -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<Route
|
||||
'chat-type', 'chat-room', 'chat-server',
|
||||
'chat-bosh-uri', 'chat-ws-uri',
|
||||
'prosody-room-type',
|
||||
'converse-theme'
|
||||
'converse-theme', 'converse-autocolors'
|
||||
])
|
||||
const chatType: ChatType = (settings['chat-type'] ?? 'disabled') as ChatType
|
||||
|
||||
@ -149,6 +150,53 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise<Route
|
||||
}
|
||||
room = room.replace(/{{CHANNEL_NAME}}/g, channelName)
|
||||
}
|
||||
|
||||
let autocolorsStyles = ''
|
||||
if (
|
||||
settings['converse-autocolors'] &&
|
||||
isAutoColorsAvailable(settings['chat-type'] as ChatType, settings['converse-theme'] as string)
|
||||
) {
|
||||
peertubeHelpers.logger.debug('Trying to load AutoColors...')
|
||||
const autocolors: AutoColors = {
|
||||
mainForeground: req.query._ac_mainForeground?.toString() ?? '',
|
||||
mainBackground: req.query._ac_mainBackground?.toString() ?? '',
|
||||
greyForeground: req.query._ac_greyForeground?.toString() ?? '',
|
||||
greyBackground: req.query._ac_greyBackground?.toString() ?? '',
|
||||
menuForeground: req.query._ac_menuForeground?.toString() ?? '',
|
||||
menuBackground: req.query._ac_menuBackground?.toString() ?? '',
|
||||
inputForeground: req.query._ac_inputForeground?.toString() ?? '',
|
||||
inputBackground: req.query._ac_inputBackground?.toString() ?? '',
|
||||
buttonForeground: req.query._ac_buttonForeground?.toString() ?? '',
|
||||
buttonBackground: req.query._ac_buttonBackground?.toString() ?? '',
|
||||
link: req.query._ac_link?.toString() ?? '',
|
||||
linkHover: req.query._ac_linkHover?.toString() ?? ''
|
||||
}
|
||||
const autoColorsTest = areAutoColorsValid(autocolors)
|
||||
if (autoColorsTest === true) {
|
||||
autocolorsStyles = `
|
||||
<style>
|
||||
: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};
|
||||
}
|
||||
</style>
|
||||
`
|
||||
} 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<Route
|
||||
page = page.replace(/{{AUTHENTICATION_URL}}/g, authenticationUrl)
|
||||
page = page.replace(/{{ADVANCEDCONTROLS}}/g, advancedControls ? 'true' : 'false')
|
||||
page = page.replace(/{{CONVERSEJS_THEME}}/g, converseJSTheme)
|
||||
page = page.replace(/{{CONVERSEJS_AUTOCOLORS}}/g, autocolorsStyles)
|
||||
|
||||
res.status(200)
|
||||
res.type('html')
|
||||
|
@ -282,7 +282,7 @@ Example: height:400px;`,
|
||||
label: 'ConverseJS theme',
|
||||
type: 'select',
|
||||
default: 'peertube' as ConverseJSTheme,
|
||||
private: true,
|
||||
private: false,
|
||||
options: [
|
||||
{ value: 'peertube', label: 'Peertube theme' },
|
||||
{ value: 'default', label: 'Default ConverseJS theme' },
|
||||
@ -291,6 +291,22 @@ Example: height:400px;`,
|
||||
descriptionHTML: 'Please choose the converseJS theme you want to use.'
|
||||
})
|
||||
|
||||
registerSetting({
|
||||
name: 'converse-autocolors',
|
||||
label: 'Automatic color detection',
|
||||
type: 'input-checkbox',
|
||||
default: true,
|
||||
private: false,
|
||||
descriptionHTML:
|
||||
`Try to auto detect colors from user's current theme.<br>
|
||||
When this settings is enabled, the plugin tries to auto-detect colors to apply to the chat theme.<br>
|
||||
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
|
||||
<a href="https://github.com/JohnXLivingston/peertube-plugin-livechat/issues" target="_blank">
|
||||
issue tracker
|
||||
</a>. Don't forget to specify which theme is not working.`
|
||||
})
|
||||
|
||||
// ********** Built-in Prosody advanced settings
|
||||
registerSetting({
|
||||
name: 'prosody-advanced',
|
||||
|
59
shared/lib/autocolors.ts
Normal file
59
shared/lib/autocolors.ts
Normal file
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user