mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-04 11:44:00 +00:00
* Added: Initial re-implementation of emote information cards. These have been broken for a while due to changes in Twitch's website preventing us from accessing them. * Added: Setting to hide charity progress elements in chat. * Changed: Emote tool-tips now display emote artists. * Changed: The `Chat Command` chat action can now optionally be sent in another channel. Note that when doing so, you will not receive feedback from your sent message. * Fixed: The 'Viewer Count' tool-tip duplicating itself. * Fixed: Emote menu repeatedly requesting FFZ data. * API Added: Ephemeral profiles can now be created by passing `ephemeral: true` in the options when creating a profile. These profiles are temporary and read-only.
221 lines
No EOL
4.1 KiB
Vue
221 lines
No EOL
4.1 KiB
Vue
<template lang="html">
|
|
<div class="ffz--color-widget">
|
|
<div v-if="showInput" class="tw-relative tw-full-width tw-mg-y-05">
|
|
<input
|
|
v-if="showInput"
|
|
ref="input"
|
|
v-model="color"
|
|
v-bind="$attrs"
|
|
:disabled="disabled"
|
|
type="text"
|
|
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width ffz-input tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
|
|
autocapitalize="off"
|
|
autocorrect="off"
|
|
autocomplete="off"
|
|
@input="onChange"
|
|
>
|
|
|
|
<button
|
|
class="ffz-color-preview tw-absolute tw-top-0 tw-bottom-0 tw-right-0 tw-border-l tw-z-default"
|
|
@click="togglePicker"
|
|
>
|
|
<figure v-if="! valid" class="ffz-i-attention tw-c-text-alert" />
|
|
<figure v-else-if="color" :style="`background-color: ${color}`" />
|
|
<figure v-else class="ffz-i-eyedropper" />
|
|
</button>
|
|
<div
|
|
v-if="open"
|
|
v-on-clickaway="closePicker"
|
|
:class="{'ffz-bottom-100': openUp}"
|
|
class="tw-absolute tw-z-above tw-right-0"
|
|
>
|
|
<chrome-picker :disable-alpha="! alpha" :value="colors" @input="onPick" />
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-else
|
|
:class="{'ffz-il-tooltip__container': hasTooltip}"
|
|
class="tw-relative"
|
|
>
|
|
<button
|
|
class="tw-button tw-button--text ffz-color-preview"
|
|
@click="togglePicker"
|
|
@contextmenu.prevent="maybeResetColor"
|
|
>
|
|
<figure v-if="! valid" class="ffz-i-attention tw-c-text-alert" />
|
|
<figure v-else-if="color" :style="`background-color: ${color}`">
|
|
|
|
</figure>
|
|
<figure v-else class="ffz-i-eyedropper" />
|
|
</button>
|
|
<div
|
|
v-if="open"
|
|
v-on-clickaway="closePicker"
|
|
:class="{'ffz-bottom-100': openUp}"
|
|
class="tw-absolute tw-z-above ffz-il-tooltip--down ffz-il-tooltip--align-right"
|
|
>
|
|
<chrome-picker :disable-alpha="! alpha" :value="colors" @input="onPick" />
|
|
</div>
|
|
<div
|
|
v-if="! open && hasTooltip"
|
|
class="ffz-il-tooltip ffz-il-tooltip--down ffz-il-tooltip--align-right"
|
|
>
|
|
{{ tooltip }}
|
|
<div v-if="nullable" class="tw-regular">
|
|
{{ t('setting.color.nullable', 'Right-Click to Reset') }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import {Color} from 'utilities/color';
|
|
|
|
import {Sketch} from 'vue-color';
|
|
|
|
export default {
|
|
components: {
|
|
'chrome-picker': Sketch
|
|
},
|
|
|
|
props: {
|
|
value: String,
|
|
alpha: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
default: {
|
|
type: String,
|
|
default: '#000'
|
|
},
|
|
nullable: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
validate: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showInput: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
tooltip: {
|
|
type: String,
|
|
default: null
|
|
},
|
|
openUp: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
color: '',
|
|
valid: false,
|
|
open: false
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
hasTooltip() {
|
|
return this.tooltip?.length > 0 || this.nullable
|
|
},
|
|
|
|
colors() {
|
|
try {
|
|
return Color.RGBA.fromCSS(this.color || this.default)
|
|
} catch(err) {
|
|
return {
|
|
hex: this.default
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
value(val) {
|
|
this.color = val;
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
this.color = this.value;
|
|
this._validate();
|
|
},
|
|
|
|
methods: {
|
|
maybeResetColor() {
|
|
if ( this.open )
|
|
return this.open = false;
|
|
|
|
if ( this.nullable ) {
|
|
this.color = '';
|
|
this._validate();
|
|
this.emit();
|
|
}
|
|
},
|
|
|
|
openPicker() {
|
|
this.open = true;
|
|
},
|
|
|
|
closePicker() {
|
|
this.open = false;
|
|
},
|
|
|
|
togglePicker() {
|
|
this.open = ! this.open;
|
|
},
|
|
|
|
onPick(color) {
|
|
if ( this.disabled )
|
|
return;
|
|
|
|
const old_val = this.color;
|
|
|
|
if ( color.rgba.a == 1 )
|
|
this.color = color.hex;
|
|
else {
|
|
const c = color.rgba;
|
|
this.color = `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a})`;
|
|
}
|
|
|
|
if ( old_val !== this.color ) {
|
|
this._validate();
|
|
this.emit();
|
|
}
|
|
},
|
|
|
|
_validate() {
|
|
this.valid = true;
|
|
if ( ! this.color || ! this.color.length || ! this.validate )
|
|
return;
|
|
|
|
try {
|
|
Color.RGBA.fromCSS(this.color);
|
|
} catch(err) {
|
|
this.valid = false;
|
|
}
|
|
},
|
|
|
|
emit() {
|
|
if ( this.valid )
|
|
this.$emit('input', this.color);
|
|
},
|
|
|
|
onChange() {
|
|
this._validate();
|
|
this.emit();
|
|
}
|
|
}
|
|
}
|
|
|
|
</script> |