tags-input:

* add a "copy" button
* fix some css class (adding a prefix to avoid side effects)
* other minor fixes
This commit is contained in:
John Livingston
2024-06-13 11:55:02 +02:00
parent 591e0ad3fd
commit 618dc6aeae
6 changed files with 257 additions and 48 deletions

View File

@ -23,6 +23,7 @@ declare const LOC_SHOW_SCROLLBARR: string
declare const LOC_TRANSPARENT_BACKGROUND: string
declare const LOC_TIPS_FOR_STREAMERS: string
declare const LOC_COPY: string
declare const LOC_COPIED: string
declare const LOC_LINK_COPIED: string
declare const LOC_ERROR: string
declare const LOC_OPEN: string

View File

@ -2,14 +2,30 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'
import { LivechatElement } from './livechat'
import { ptTr } from '../directives/translation'
import { html } from 'lit'
import { unsafeHTML } from 'lit/directives/unsafe-html.js'
import { customElement, property, state } from 'lit/decorators.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { classMap } from 'lit/directives/class-map.js'
import { animate, fadeOut, fadeIn } from '@lit-labs/motion'
import { repeat } from 'lit/directives/repeat.js'
// FIXME: find a better way to store this image.
// This content comes from the file assets/images/copy.svg, after svgo cleaning.
// To get the formated content, you can do:
// xmllint dist/client/images/copy.svg --format
// Then replace the main color by «currentColor»
const copySVG = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 4.233 4.233">
<g style="stroke-width:1.00021;stroke-miterlimit:4;stroke-dasharray:none">` +
// eslint-disable-next-line max-len
'<path style="opacity:.998;fill:none;fill-opacity:1;stroke:currentColor;stroke-width:1.17052;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="m4.084 4.046-.616.015-.645-.004a.942.942 0 0 1-.942-.942v-4.398a.94.94 0 0 1 .942-.943H7.22a.94.94 0 0 1 .942.943l-.006.334-.08.962" transform="matrix(.45208 0 0 .45208 -.528 1.295)"/>' +
// eslint-disable-next-line max-len
'<path style="opacity:.998;fill:none;fill-opacity:1;stroke:currentColor;stroke-width:1.17052;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M8.434 5.85c-.422.009-1.338.009-1.76.01-.733.004-2.199 0-2.199 0a.94.94 0 0 1-.942-.941V.52a.94.94 0 0 1 .942-.942h4.398a.94.94 0 0 1 .943.942s.004 1.466 0 2.2c-.003.418-.019 1.251-.006 1.67.024.812-.382 1.439-1.376 1.46z" transform="matrix(.45208 0 0 .45208 -.528 1.295)"/>' +
`</g>
</svg>`
@customElement('livechat-tags-input')
export class TagsInputElement extends LivechatElement {
@property({ attribute: false })
@ -71,30 +87,55 @@ export class TagsInputElement extends LivechatElement {
}
protected override render = (): unknown => {
return html`<ul
id="tags"
class=${classMap({
empty: !this.value.length,
unfocused: this._searchedTagsIndex.length
})}>
${repeat(this.value, tag => tag,
(tag, index) => html`<li key=${index} class="tag" title=${tag} ${animate({
keyframeOptions: {
duration: this.animDuration,
fill: 'both'
},
in: fadeIn,
out: fadeOut
})}>
<span class='tag-name'>${tag}</span>
<span class='tag-close'
@click=${() => this._handleDeleteTag(index)}></span>
</li>`
)}
</ul>
<ul id="tags-searched" class=${classMap({ empty: !this._searchedTagsIndex.length })}>
return html`
<div class=${classMap({
'livechat-empty': !this.value.length,
'livechat-tags-container': true
})}
>
<ul
class=${classMap({
'livechat-empty': !this.value.length,
'livechat-unfocused': this._searchedTagsIndex.length,
'livechat-tags': true
})}>
${repeat(this.value, tag => tag,
(tag, index) => html`<li key=${index} class="livechat-tag" title=${tag} ${animate({
keyframeOptions: {
duration: this.animDuration,
fill: 'both'
},
in: fadeIn,
out: fadeOut
})}>
<span class='livechat-tag-name'>${tag}</span>
<span class='livechat-tag-close'
@click=${() => this._handleDeleteTag(index)}></span>
</li>`
)}
</ul>
${
this.value?.length === 0
? ''
: html`<button
type="button"
class="peertube-plugin-livechat-tags-input-copy"
title=${ptTr(LOC_COPY) as any}
@click=${async (ev: Event) => {
ev.preventDefault()
await navigator.clipboard.writeText(this.value.join(this.separator))
this.ptNotifier.success(await this.ptTranslate(LOC_COPIED))
}}
>${unsafeHTML(copySVG)}</button>`
}
</div>
<ul class=${classMap({
'livechat-empty': !this._searchedTagsIndex.length,
'livechat-tags-searched': true
})}
>
${repeat(this._searchedTagsIndex, index => index,
(index) => html`<li key=${index} class="tag-searched" title=${this.value[index]} ${animate({
(index) => html`<li key=${index} class="livechat-tag-searched" title=${this.value[index]} ${animate({
keyframeOptions: {
duration: this.animDuration,
fill: 'both'
@ -102,8 +143,8 @@ export class TagsInputElement extends LivechatElement {
in: fadeIn,
out: fadeOut
})}>
<span class='tag-name'>${this.value[index]}</span>
<span class='tag-close'
<span class='livechat-tag-name'>${this.value[index]}</span>
<span class='livechat-tag-close'
@click=${() => this._handleDeleteTag(index)}>
</span>
</li>`