Begin integrating components with lit

This commit is contained in:
Mehdi Benadel 2024-05-09 22:32:42 +02:00
parent 9ff4abfce4
commit 2638e137b3
6 changed files with 176 additions and 53 deletions

View File

@ -5,6 +5,7 @@
import type { RegisterClientOptions } from '@peertube/peertube-types/client' import type { RegisterClientOptions } from '@peertube/peertube-types/client'
import { renderConfigurationHome } from './templates/home' import { renderConfigurationHome } from './templates/home'
import { renderConfigurationChannel } from './templates/channel' import { renderConfigurationChannel } from './templates/channel'
import { render } from 'lit'
/** /**
* Registers stuff related to the user's configuration pages. * Registers stuff related to the user's configuration pages.
@ -19,7 +20,7 @@ async function registerConfiguration (clientOptions: RegisterClientOptions): Pro
registerClientRoute({ registerClientRoute({
route: 'livechat/configuration', route: 'livechat/configuration',
onMount: async ({ rootEl }) => { onMount: async ({ rootEl }) => {
rootEl.innerHTML = await renderConfigurationHome(clientOptions) render(await renderConfigurationHome(clientOptions), rootEl)
} }
}) })
@ -28,7 +29,7 @@ async function registerConfiguration (clientOptions: RegisterClientOptions): Pro
onMount: async ({ rootEl }) => { onMount: async ({ rootEl }) => {
const urlParams = new URLSearchParams(window.location.search) const urlParams = new URLSearchParams(window.location.search)
const channelId = urlParams.get('channelId') ?? '' const channelId = urlParams.get('channelId') ?? ''
await renderConfigurationChannel(clientOptions, channelId, rootEl) render(await renderConfigurationChannel(clientOptions, channelId, rootEl), rootEl)
} }
}) })

View File

@ -87,42 +87,34 @@
<tbody> <tbody>
<tr class="button.peertube-livechat-forbidden-words-row-{{fieldNumber}}"> <tr class="button.peertube-livechat-forbidden-words-row-{{fieldNumber}}">
<td> <td>
<label for="peertube-livechat-forbidden-words-{{fieldNumber}}">{{forbiddenWords}}</label>
{{! warning: don't add extra line break in textarea! }} {{! warning: don't add extra line break in textarea! }}
<textarea <textarea
name="forbidden_words_{{fieldNumber}}" name="forbidden_words_{{fieldNumber}}"
id="peertube-livechat-forbidden-words-{{fieldNumber}}" id="peertube-livechat-forbidden-words-{{fieldNumber}}"
class="form-control" class="form-control"
>{{joinedEntries}}</textarea> >{{joinedEntries}}</textarea>
<p class="form-group-description">{{forbiddenWordsDesc2}}</p>
</td> </td>
<label>
<input
type="checkbox"
name="forbidden_words_regexp_{{fieldNumber}}"
value="1"
{{#regexp}}
checked="checked"
{{/regexp}}
/>
{{forbiddenWordsRegexp}}
</label>
<p class="form-group-description">{{forbiddenWordsRegexpDesc}}</p>
<td> <td>
<label> <input
<input type="checkbox"
type="checkbox" name="forbidden_words_regexp_{{fieldNumber}}"
name="forbidden_words_applytomoderators_{{fieldNumber}}" value="1"
value="1" {{#regexp}}
{{#applyToModerators}} checked="checked"
checked="checked" {{/regexp}}
{{/applyToModerators}} />
/>
{{forbiddenWordsApplyToModerators}}
</label>
<p class="form-group-description">{{forbiddenWordsApplyToModeratorsDesc}}</p>
</td> </td>
<label for="peertube-livechat-forbidden-words-label-{{fieldNumber}}">{{forbiddenWordsLabel}}</label> <td>
<input
type="checkbox"
name="forbidden_words_applytomoderators_{{fieldNumber}}"
value="1"
{{#applyToModerators}}
checked="checked"
{{/applyToModerators}}
/>
</td>
<td>
<input <input
type="text" type="text"
name="forbidden_words_label_{{fieldNumber}}" name="forbidden_words_label_{{fieldNumber}}"
@ -130,9 +122,8 @@
id="peertube-livechat-forbidden-words-label-{{fieldNumber}}" id="peertube-livechat-forbidden-words-label-{{fieldNumber}}"
value="{{label}}" value="{{label}}"
/> />
<p class="form-group-description">{{forbiddenWordsLabelDesc}}</p> </td>
<td> <td>
<label for="peertube-livechat-forbidden-words-reason-{{fieldNumber}}">{{forbiddenWordsReason}}</label>
<input <input
type="text" type="text"
name="forbidden_words_reason_{{fieldNumber}}" name="forbidden_words_reason_{{fieldNumber}}"
@ -140,16 +131,15 @@
id="peertube-livechat-forbidden-words-reason-{{fieldNumber}}" id="peertube-livechat-forbidden-words-reason-{{fieldNumber}}"
value="{{reason}}" value="{{reason}}"
/> />
<p class="form-group-description">{{forbiddenWordsReasonDesc}}</p>
</td> </td>
<label for="peertube-livechat-forbidden-words-comments-{{fieldNumber}}">{{forbiddenWordsComments}}</label> <td>
{{! warning: don't add extra line break in textarea! }} {{! warning: don't add extra line break in textarea! }}
<textarea <textarea
name="forbidden_words_comments_{{fieldNumber}}" name="forbidden_words_comments_{{fieldNumber}}"
id="peertube-livechat-forbidden-words-comments-{{fieldNumber}}" id="peertube-livechat-forbidden-words-comments-{{fieldNumber}}"
class="form-control" class="form-control"
>{{comments}}</textarea> >{{comments}}</textarea>
<p class="form-group-description">{{forbiddenWordsCommentsDesc}}</p> </td>
<td> <td>
<button type="button" class="btn btn-danger peertube-livechat-forbidden-words-{{fieldNumber}}-remove">x</button> <button type="button" class="btn btn-danger peertube-livechat-forbidden-words-{{fieldNumber}}-remove">x</button>
</td> </td>

View File

@ -6,6 +6,8 @@ import type { RegisterClientOptions } from '@peertube/peertube-types/client'
import { localizedHelpUrl } from '../../../utils/help' import { localizedHelpUrl } from '../../../utils/help'
import { helpButtonSVG } from '../../../videowatch/buttons' import { helpButtonSVG } from '../../../videowatch/buttons'
import { vivifyConfigurationChannel, getConfigurationChannelViewData } from './logic/channel' import { vivifyConfigurationChannel, getConfigurationChannelViewData } from './logic/channel'
import { TemplateResult, html } from 'lit'
import { unsafeHTML } from 'lit/directives/unsafe-html.js'
// Must use require for mustache, import seems buggy. // Must use require for mustache, import seems buggy.
const Mustache = require('mustache') const Mustache = require('mustache')
@ -21,20 +23,18 @@ async function renderConfigurationChannel (
registerClientOptions: RegisterClientOptions, registerClientOptions: RegisterClientOptions,
channelId: string, channelId: string,
rootEl: HTMLElement rootEl: HTMLElement
): Promise<void> { ): Promise<TemplateResult> {
try { try {
const view = await getConfigurationChannelViewData(registerClientOptions, channelId) const view = await getConfigurationChannelViewData(registerClientOptions, channelId)
await fillViewHelpButtons(registerClientOptions, view) await fillViewHelpButtons(registerClientOptions, view)
await fillLabels(registerClientOptions, view) await fillLabels(registerClientOptions, view)
const content = Mustache.render(MUSTACHE_CONFIGURATION_CHANNEL, view) as string return html`${unsafeHTML(Mustache.render(MUSTACHE_CONFIGURATION_CHANNEL, view))}`
rootEl.innerHTML = content
await vivifyConfigurationChannel(registerClientOptions, rootEl, channelId) await vivifyConfigurationChannel(registerClientOptions, rootEl, channelId)
} catch (err: any) { } catch (err: any) {
registerClientOptions.peertubeHelpers.notifier.error(err.toString()) registerClientOptions.peertubeHelpers.notifier.error(err.toString())
rootEl.innerHTML = '' return html``
} }
} }

View File

@ -5,15 +5,22 @@
import type { RegisterClientOptions } from '@peertube/peertube-types/client' import type { RegisterClientOptions } from '@peertube/peertube-types/client'
import { localizedHelpUrl } from '../../../utils/help' import { localizedHelpUrl } from '../../../utils/help'
import { helpButtonSVG } from '../../../videowatch/buttons' import { helpButtonSVG } from '../../../videowatch/buttons'
// Must use require for mustache, import seems buggy. import { TemplateResult, html } from 'lit';
const Mustache = require('mustache')
interface HomeViewData {
title: string
description: string
please_select: string
channels: any[]
helpButton: TemplateResult
}
/** /**
* Renders the livechat configuration setup home page. * Renders the livechat configuration setup home page.
* @param registerClientOptions Peertube client options * @param registerClientOptions Peertube client options
* @returns The page content * @returns The page content
*/ */
async function renderConfigurationHome (registerClientOptions: RegisterClientOptions): Promise<string> { async function renderConfigurationHome (registerClientOptions: RegisterClientOptions): Promise<TemplateResult> {
const { peertubeHelpers } = registerClientOptions const { peertubeHelpers } = registerClientOptions
try { try {
@ -50,34 +57,33 @@ async function renderConfigurationHome (registerClientOptions: RegisterClientOpt
} }
} }
const view = { const view : HomeViewData = {
title: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_TITLE), title: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_TITLE),
description: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_DESC), description: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_DESC),
please_select: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_PLEASE_SELECT), please_select: await peertubeHelpers.translate(LOC_LIVECHAT_CONFIGURATION_PLEASE_SELECT),
channels: channels.data channels: channels.data,
helpButton: await _fillViewHelpButtons(registerClientOptions)
} }
await _fillViewHelpButtons(registerClientOptions, view)
return Mustache.render(MUSTACHE_CONFIGURATION_HOME, view) as string return renderConfigurationHomeFromTemplate(view)
} catch (err: any) { } catch (err: any) {
peertubeHelpers.notifier.error(err.toString()) peertubeHelpers.notifier.error(err.toString())
return '' return html``
} }
} }
async function _fillViewHelpButtons ( // TODO: refactor with the similar function in channel.ts async function _fillViewHelpButtons ( // TODO: refactor with the similar function in channel.ts
registerClientOptions: RegisterClientOptions, registerClientOptions: RegisterClientOptions
view: any ): Promise<TemplateResult> {
): Promise<void> {
const title = await registerClientOptions.peertubeHelpers.translate(LOC_ONLINE_HELP) const title = await registerClientOptions.peertubeHelpers.translate(LOC_ONLINE_HELP)
const button = async (page: string): Promise<string> => { const button = async (page: string): Promise<TemplateResult> => {
const helpUrl = await localizedHelpUrl(registerClientOptions, { const helpUrl = await localizedHelpUrl(registerClientOptions, {
page page
}) })
const helpIcon = helpButtonSVG() const helpIcon = helpButtonSVG()
return `<a return html`<a
href="${helpUrl}" href="${helpUrl}"
target=_blank target=_blank
title="${title}" title="${title}"
@ -85,7 +91,39 @@ async function _fillViewHelpButtons ( // TODO: refactor with the similar functio
>${helpIcon}</a>` >${helpIcon}</a>`
} }
view.helpButton = await button('documentation/user/streamers/channel') return button('documentation/user/streamers/channel')
}
function renderConfigurationHomeFromTemplate(view: HomeViewData) {
return html`
<div class="margin-content peertube-plugin-livechat-configuration peertube-plugin-livechat-configuration-home">
<h1>
${view.title}
${view.helpButton}
</h1>
<p>${view.description}</p>
<p>${view.please_select}</p>
<ul class="peertube-plugin-livechat-configuration-home-channels">
${view.channels.map((channel) => html`
<li>
<a href="${channel.livechatConfigurationUri}">
${channel.avatar ?
html`<img class="avatar channel" src="${channel.avatar.path}">`
:
html`<div class="avatar channel initial gray"></div>`
}
</a>
<div class="peertube-plugin-livechat-configuration-home-info">
<a href="${channel.livechatConfigurationUri}">
<div>${channel.displayName}</div>
<div>${channel.name}</div>
</a>
</div>
</li>
`)}
</ul>
</div>
`
} }
export { export {

93
package-lock.json generated
View File

@ -15,6 +15,7 @@
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"got": "^11.8.2", "got": "^11.8.2",
"http-proxy": "^1.18.1", "http-proxy": "^1.18.1",
"lit": "^3.1.3",
"log-rotate": "^0.2.8", "log-rotate": "^0.2.8",
"openid-client": "^5.6.5", "openid-client": "^5.6.5",
"validate-color": "^2.2.1", "validate-color": "^2.2.1",
@ -2664,6 +2665,19 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"node_modules/@lit-labs/ssr-dom-shim": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
"integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g=="
},
"node_modules/@lit/reactive-element": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz",
"integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==",
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0"
}
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz",
@ -4095,6 +4109,11 @@
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true "dev": true
}, },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
},
"node_modules/@types/validator": { "node_modules/@types/validator": {
"version": "13.7.1", "version": "13.7.1",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz",
@ -8644,6 +8663,34 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true "dev": true
}, },
"node_modules/lit": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lit/-/lit-3.1.3.tgz",
"integrity": "sha512-l4slfspEsnCcHVRTvaP7YnkTZEZggNFywLEIhQaGhYDczG+tu/vlgm/KaWIEjIp+ZyV20r2JnZctMb8LeLCG7Q==",
"dependencies": {
"@lit/reactive-element": "^2.0.4",
"lit-element": "^4.0.4",
"lit-html": "^3.1.2"
}
},
"node_modules/lit-element": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.5.tgz",
"integrity": "sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==",
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0",
"@lit/reactive-element": "^2.0.4",
"lit-html": "^3.1.2"
}
},
"node_modules/lit-html": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.3.tgz",
"integrity": "sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==",
"dependencies": {
"@types/trusted-types": "^2.0.2"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
@ -14237,6 +14284,19 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@jridgewell/sourcemap-codec": "^1.4.14"
} }
}, },
"@lit-labs/ssr-dom-shim": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
"integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g=="
},
"@lit/reactive-element": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz",
"integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==",
"requires": {
"@lit-labs/ssr-dom-shim": "^1.2.0"
}
},
"@msgpackr-extract/msgpackr-extract-darwin-arm64": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz",
@ -15546,6 +15606,11 @@
"integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==", "integrity": "sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==",
"dev": true "dev": true
}, },
"@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
},
"@types/validator": { "@types/validator": {
"version": "13.7.1", "version": "13.7.1",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.1.tgz",
@ -18891,6 +18956,34 @@
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true "dev": true
}, },
"lit": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lit/-/lit-3.1.3.tgz",
"integrity": "sha512-l4slfspEsnCcHVRTvaP7YnkTZEZggNFywLEIhQaGhYDczG+tu/vlgm/KaWIEjIp+ZyV20r2JnZctMb8LeLCG7Q==",
"requires": {
"@lit/reactive-element": "^2.0.4",
"lit-element": "^4.0.4",
"lit-html": "^3.1.2"
}
},
"lit-element": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.5.tgz",
"integrity": "sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==",
"requires": {
"@lit-labs/ssr-dom-shim": "^1.2.0",
"@lit/reactive-element": "^2.0.4",
"lit-html": "^3.1.2"
}
},
"lit-html": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.1.3.tgz",
"integrity": "sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==",
"requires": {
"@types/trusted-types": "^2.0.2"
}
},
"locate-path": { "locate-path": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",

View File

@ -39,6 +39,7 @@
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"got": "^11.8.2", "got": "^11.8.2",
"http-proxy": "^1.18.1", "http-proxy": "^1.18.1",
"lit": "^3.1.3",
"log-rotate": "^0.2.8", "log-rotate": "^0.2.8",
"openid-client": "^5.6.5", "openid-client": "^5.6.5",
"validate-color": "^2.2.1", "validate-color": "^2.2.1",