1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00

The Big Linting Commit.

* Add linting for Vue files.
* Fix a bunch of linting problems in Vue files.
* Update README with notes about configuring editors.
This commit is contained in:
SirStendec 2018-03-30 17:58:56 -04:00
parent 8dbcf434cd
commit f9f5f0affa
23 changed files with 1114 additions and 971 deletions

View file

@ -3,9 +3,13 @@ module.exports = {
"browser": true,
"es6": true
},
"extends": "eslint:recommended",
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"plugin:vue/recommended"
],
"plugins": ["vue"],
"parserOptions": {
"parser": "babel-eslint",
"ecmaVersion": 8,
"sourceType": "module"
},
@ -62,6 +66,7 @@ module.exports = {
"no-useless-constructor": ["error"],
"no-useless-rename": ["error"],
"no-var": ["error"],
"no-cond-assign": ["warn"],
"object-shorthand": ["warn"],
"prefer-arrow-callback": ["warn", {"allowUnboundThis": true}],
"prefer-const": ["warn", {"ignoreReadBeforeAssign": true}],
@ -72,7 +77,7 @@ module.exports = {
"yield-star-spacing": ["warn"],
"indent": [
"error",
"warn",
"tab",
{
"SwitchCase": 1
@ -89,6 +94,20 @@ module.exports = {
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"vue/html-indent": [
"warn",
"tab"
],
"vue/max-attributes-per-line": "off",
"vue/require-prop-types": "off",
"vue/require-default-prop": "off",
"vue/html-closing-bracket-newline": [
"error",
{
"singleline": "never",
"multiline": "always"
}
]
}
};

View file

@ -1,7 +1,7 @@
FrankerFaceZ
============
Copyright (c) 2017 Dan Salvato LLC
Copyright (c) 2018 Dan Salvato LLC
Licensed under the Apache License, Version 2.0. See LICENSE.
@ -13,17 +13,40 @@ FrankerFaceZ uses node.js to manage development dependencies and to run an HTTP
server for development. To get everything you need:
1. Install node.js and npm
2. Run ```npm install``` within the FrankerFaceZ directory.
2. Run `npm install` within the FrankerFaceZ directory.
From there, you can use npm to build the extension from source simply by
running ```npm run build```. For development, you can instruct gulp to watch
the source files for changes and re-build automatically with ```npm start```
From there, you can use npm to build FrankerFaceZ from source simply by
running `npm run build`. For development, you can instruct gulp to watch
the source files for changes and re-build automatically with `npm start`
FrankerFaceZ comes with a local development server that listens on port 8000
and it serves up local development copies of files, falling back to the CDN
when a local copy of a file isn't present.
To make FrankerFaceZ load from your local development server, you must set
the local storage variable ```ffzDebugMode``` to true. Just run the following
in your console on Twitch: ```localStorage.ffzDebugMode = true;```
the local storage variable `ffzDebugMode` to true. Just run the following
in your console on Twitch: `localStorage.ffzDebugMode = true;`
It should be noted that this project is not a browser extension that you
would load in your browser's extensions system. You still need the FrankerFaceZ
extension or user-script for your browser.
Editor Settings
===============
Please make sure that your editor is configured to use tabs rather than spaces
for indentation and that lines are ended with `\n`. It's recommended that you
configure linting support for your editor as well.
If you're using Visual Studio Code, make sure to install the ESLint extension
and add the following to your workspace settings:
```json
{
"eslint.validate": [
"javascript",
"vue"
]
}```

23
package-lock.json generated
View file

@ -3037,6 +3037,15 @@
}
}
},
"eslint-plugin-vue": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-4.4.0.tgz",
"integrity": "sha512-UHeE0aTEv9A/9xe8J6X7rDLMbwV6GuQFKAscMyLEv49Y4wK4KwQiifr2X0MsNsVlmccrDUyjI9KO4DuFTkPP9A==",
"dev": true,
"requires": {
"vue-eslint-parser": "2.0.3"
}
},
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
@ -9358,6 +9367,20 @@
"loose-envify": "1.3.1"
}
},
"vue-eslint-parser": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz",
"integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==",
"dev": true,
"requires": {
"debug": "3.1.0",
"eslint-scope": "3.7.1",
"eslint-visitor-keys": "1.0.0",
"espree": "3.5.4",
"esquery": "1.0.0",
"lodash": "4.17.4"
}
},
"vue-hot-reload-api": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz",

View file

@ -6,6 +6,7 @@
"main": "script.js",
"scripts": {
"start": "webpack-dev-server --config webpack.web.dev.js",
"eslint": "eslint \"src/**/*.{js,vue}\"",
"build": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production'",
"build:babel": "webpack --config webpack.web.babel.js --define process.env.NODE_ENV='production'",
"build:prod": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production'",
@ -22,6 +23,7 @@
"copy-webpack-plugin": "^4.5.1",
"css-loader": "^0.28.10",
"eslint": "^4.18.2",
"eslint-plugin-vue": "^4.4.0",
"extract-loader": "^1.0.2",
"file-loader": "^1.1.11",
"less": "^2.7.3",

View file

@ -1,8 +1,8 @@
<template lang="html">
<div class="ffz--badge-visibility tw-pd-t-05">
<div class="ffz--badge-visibility tw-pd-t-05">
<div
class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1"
v-if="source && source !== profile"
class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1"
>
<span class="ffz-i-info" />
{{ t('setting.badge-inheritence', 'These values are being overridden by another profile and may not take effect.') }}
@ -10,9 +10,9 @@
<div class="tw-mg-b-2 tw-align-right">
<button
:disabled="! has_value"
class="tw-mg-l-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@click="clear"
:disabled="! has_value"
>
<span class="tw-button__icon tw-button__icon--left">
<figure class="ffz-i-cancel" />
@ -23,24 +23,46 @@
</button>
</div>
<section class="ffz--menu-container tw-border-t" v-for="sec in data">
<section
v-for="sec in data"
:key="sec.title"
class="ffz--menu-container tw-border-t"
>
<header>{{ sec.title }}</header>
<ul class="tw-flex tw-flex-wrap tw-align-content-start">
<li v-for="i in sort(sec.badges)" class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex" :class="{default: badgeDefault(i.id)}">
<li
v-for="i in sort(sec.badges)"
:key="i.id"
:class="{default: badgeDefault(i.id)}"
class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex"
>
<input
type="checkbox"
class="tw-checkbox__input"
:checked="badgeChecked(i.id)"
:id="i.id"
type="checkbox"
class="tw-checkbox__input"
@click="onChange(i.id, $event)"
>
<label class="tw-checkbox__label tw-flex" :for="i.id">
<div class="preview-image ffz-badge tw-mg-r-1 tw-flex-shrink-0" :style="{backgroundColor: i.color, backgroundImage: i.styleImage }" />
<label :for="i.id" class="tw-checkbox__label tw-flex">
<div
:style="{backgroundColor: i.color, backgroundImage: i.styleImage }"
class="preview-image ffz-badge tw-mg-r-1 tw-flex-shrink-0"
/>
<div>
<h5>{{ i.name }}</h5>
<section class="tw-mg-t-05" v-if="i.versions && i.versions.length > 1">
<span v-for="v in i.versions" data-tooltip-type="html" class="ffz-badge ffz-tooltip" :title="v.name" :style="{backgroundColor: i.color, backgroundImage: v.styleImage}" />
<section
v-if="i.versions && i.versions.length > 1"
class="tw-mg-t-05"
>
<span
v-for="v in i.versions"
:key="v.name"
:title="v.name"
:style="{backgroundColor: i.color, backgroundImage: v.styleImage}"
data-tooltip-type="html"
class="ffz-badge ffz-tooltip"
/>
</section>
<button
class="tw-mg-t-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@ -56,7 +78,7 @@
</li>
</ul>
</section>
</div>
</div>
</template>
<script>

View file

@ -1,12 +1,11 @@
<template lang="html">
<div class="ffz--changelog tw-border-t tw-pd-t-1">
<div class="ffz--changelog tw-border-t tw-pd-t-1">
<div class="tw-align-center">
<h2>{{ t('home.changelog', 'Changelog') }}</h2>
</div>
<div ref="changes" />
</div>
</div>
</template>
@ -17,6 +16,10 @@ import {SERVER} from 'utilities/constants';
export default {
props: ['item', 'context'],
mounted() {
this.fetch(`${SERVER}/script/changelog.html`, this.$refs.changes);
},
methods: {
fetch(url, container) {
const done = data => {
@ -38,13 +41,8 @@ export default {
fetch(url)
.then(resp => resp.ok ? resp.text() : null)
.then(done)
.catch(err => done(null));
.catch(() => done(null));
}
},
mounted() {
this.fetch(`${SERVER}/script/changelog.html`, this.$refs.changes);
}
}
</script>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="ffz--home tw-border-t tw-pd-t-1">
<div class="ffz--home tw-border-t tw-pd-t-1">
<h2>Feedback</h2>
<div class="tw-mg-y-1 tw-c-background-accent tw-c-text-overlay tw-pd-1">
@ -21,15 +21,12 @@
When creating a GitHub issue, please check that someone else hasn't
already created one for what you'd like to discuss or report.
</p>
</div>
</div>
</template>
<script>
export default {
props: ['item', 'context'],
}
</script>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="ffz--widget ffz--filter-editor">
<div class="ffz--widget ffz--filter-editor">
<div ref="list" class="ffz--rule-list">
<section v-for="(rule, idx) in rules">
<div
@ -26,7 +26,7 @@
type="text"
class="tw-input"
value="SirStendec"
/>
>
</div>
</div>
@ -49,7 +49,7 @@
{{ t('', 'Add New Rule') }}
</span>
</button>
</div>
</div>
</template>
<script>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="ffz--home tw-flex tw-flex-nowrap">
<div class="ffz--home tw-flex tw-flex-nowrap">
<div class="tw-flex-grow-1">
<div class="tw-align-center">
<h1 class="ffz-i-zreknarf ffz-i-pd-1">FrankerFaceZ</h1>
@ -66,7 +66,7 @@
Tweets by FrankerFaceZ
</a>
</div>
</div>
</div>
</template>

View file

@ -1,5 +1,8 @@
<template lang="html">
<div class="ffz-main-menu tw-elevation-3 tw-c-background-alt tw-c-text tw-border tw-flex tw-flex-nowrap tw-flex-column" :class="{ maximized: maximized || exclusive, exclusive }">
<div
:class="{ maximized: maximized || exclusive, exclusive }"
class="ffz-main-menu tw-elevation-3 tw-c-background-alt tw-c-text tw-border tw-flex tw-flex-nowrap tw-flex-column"
>
<header class="tw-c-background tw-full-width tw-align-items-center tw-flex tw-flex-nowrap" @dblclick="resize">
<h3 class="ffz-i-zreknarf ffz-i-pd-1">FrankerFaceZ</h3>
<div class="tw-flex-grow-1 tw-pd-x-2">
@ -15,12 +18,12 @@
</div>
</div-->
</div>
<button class="tw-button-icon tw-mg-x-05" @click="resize" v-if="!exclusive">
<button v-if="!exclusive" class="tw-button-icon tw-mg-x-05" @click="resize">
<span class="tw-button-icon__icon">
<figure :class="{'ffz-i-window-maximize': !maximized, 'ffz-i-window-restore': maximized}" />
</span>
</button>
<button class="tw-button-icon tw-mg-x-05" @click="close" v-if="!exclusive">
<button v-if="!exclusive" class="tw-button-icon tw-mg-x-05" @click="close">
<span class="tw-button-icon__icon">
<figure class="ffz-i-window-close" />
</span>
@ -39,7 +42,7 @@
<div class="simplebar-scroll-content">
<div class="simplebar-content">
<menu-tree
:currentItem="currentItem"
:current-item="currentItem"
:modal="nav"
@change-item="changeItem"
@navigate="navigate"
@ -53,7 +56,7 @@
{{ t('main-menu.version', 'Version %{version}', {version: version.toString()}) }}
</div>
<div class="tw-c-text-alt-2">
{{version.build}}
{{ version.build }}
</div>
</footer>
</nav>
@ -61,18 +64,18 @@
<div class="simplebar-scroll-content">
<div class="simplebar-content">
<menu-page
v-if="currentItem"
ref="page"
:context="context"
:item="currentItem"
@change-item="changeItem"
@navigate="navigate"
v-if="currentItem"
/>
</div>
</div>
</main>
</section>
</div>
</div>
</template>
<script>
@ -84,6 +87,12 @@ export default {
return this.$vnode.data;
},
watch: {
maximized() {
this.updateDrag();
}
},
created() {
this.context.context._add_user();
},
@ -92,6 +101,22 @@ export default {
this.context.context._remove_user();
},
mounted() {
this.updateDrag();
this._on_resize = this.handleResize.bind(this);
window.addEventListener('resize', this._on_resize);
},
beforeDestroy() {
this.destroyDrag();
if ( this._on_resize ) {
window.removeEventListener('resize', this._on_resize);
this._on_resize = null;
}
},
methods: {
changeProfile() {
const new_id = this.$refs.profiles.value,
@ -153,28 +178,6 @@ export default {
this.changeItem(item);
}
},
watch: {
maximized() {
this.updateDrag();
}
},
mounted() {
this.updateDrag();
this._on_resize = this.handleResize.bind(this);
window.addEventListener('resize', this._on_resize);
},
beforeDestroy() {
this.destroyDrag();
if ( this._on_resize ) {
window.removeEventListener('resize', this._on_resize);
this._on_resize = null;
}
}
}
</script>

View file

@ -1,21 +1,21 @@
<template lang="html">
<div v-bind:class="classes" v-if="item.contents">
<div v-if="item.contents" :class="classes">
<header v-if="! item.no_header">
{{ t(item.i18n_key, item.title, item) }}
</header>
<section
v-if="item.description"
v-html="t(item.desc_i18n_key, item.description, item)"
class="tw-pd-b-1"
v-html="t(item.desc_i18n_key, item.description, item)"
/>
<component
v-for="i in item.contents"
v-bind:is="i.component"
:is="i.component"
:context="context"
:item="i"
:key="i.full_key"
/>
</div>
</div>
</template>
<script>

View file

@ -1,51 +1,49 @@
<template lang="html">
<div class="ffz--menu-page">
<header class="tw-mg-b-1">
<template v-for="i in breadcrumbs">
<div class="ffz--menu-page">
<header class="tw-mg-b-1">
<span v-for="i in breadcrumbs" :key="i.full_key">
<a v-if="i !== item" href="#" @click="$emit('change-item', i, false)">{{ t(i.i18n_key, i.title, i) }}</a>
<strong v-if="i === item">{{ t(i.i18n_key, i.title, i) }}</strong>
<template v-if="i !== item">&raquo; </template>
</template>
</header>
<section v-if="! context.currentProfile.live && item.profile_warning !== false" class="tw-border-t tw-pd-t-1 tw-pd-b-2">
</span>
</header>
<section v-if="! context.currentProfile.live && item.profile_warning !== false" class="tw-border-t tw-pd-t-1 tw-pd-b-2">
<div class="tw-c-background-accent tw-c-text-overlay tw-pd-1">
<h3 class="ffz-i-attention">
{{ t('setting.profiles.inactive', "This profile isn't active.") }}
</h3>
{{ t(
'setting.profiles.inactive.description',
{{ t('setting.profiles.inactive.description',
"This profile's rules don't match the current context and it therefore isn't currently active, so you " +
"won't see changes you make here reflected on Twitch."
) }}
"won't see changes you make here reflected on Twitch.")
}}
</div>
</section>
<section
</section>
<section
v-if="item.description"
class="tw-border-t tw-pd-y-1"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
</section>
<template v-if="! item.contents || ! item.contents.length">
<template v-if="! item.contents || ! item.contents.length">
<ul class="tw-border-t tw-pd-y-1">
<li class="tw-pd-x-1" v-for="i in item.items">
<li v-for="i in item.items" :key="i.full_key" class="tw-pd-x-1">
<a href="#" @click="$emit('change-item', i, false)">
{{ t(i.i18n_key, i.title, i) }}
</a>
</li>
</ul>
</template>
<component
</template>
<component
v-for="i in item.contents"
v-bind:is="i.component"
ref="children"
:is="i.component"
:context="context"
:item="i"
:key="i.full_key"
@change-item="changeItem"
@navigate="navigate"
/>
</div>
</div>
</template>
<script>

View file

@ -1,15 +1,15 @@
<template lang="html">
<ul
<ul
v-if="modal"
class="ffz--menu-tree"
:role="[root ? 'group' : 'tree']"
:tabindex="tabIndex"
class="ffz--menu-tree"
@keyup.up="prevItem"
@keyup.down="nextItem"
@keyup.left="prevLevel"
@keyup.right="nextLevel"
@keyup.*="expandAll"
>
>
<li
v-for="item in modal"
:key="item.full_key"
@ -17,20 +17,19 @@
role="presentation"
>
<div
class="tw-flex__item tw-flex tw-flex-nowrap tw-align-items-center tw-pd-y-05 tw-pd-r-05"
role="treeitem"
:aria-expanded="item.expanded"
:aria-selected="currentItem === item"
class="tw-flex__item tw-flex tw-flex-nowrap tw-align-items-center tw-pd-y-05 tw-pd-r-05"
role="treeitem"
@click="clickItem(item)"
>
<span
role="presentation"
class="arrow"
:class="[
item.items ? '' : 'ffz--invisible',
item.expanded ? 'ffz-i-down-dir' : 'ffz-i-right-dir'
]"
role="presentation"
class="arrow"
/>
<span class="tw-flex-grow-1">
{{ t(item.i18n_key, item.title, item) }}
@ -40,14 +39,14 @@
</span>
</div>
<menu-tree
:root="item"
:currentItem="currentItem"
:modal="item.items"
v-if="item.items && item.expanded"
:root="item"
:current-item="currentItem"
:modal="item.items"
@change-item="i => $emit('change-item', i)"
/>
</li>
</ul>
</ul>
</template>
<script>
@ -120,7 +119,7 @@ export default {
this.$emit('change-item', i.parent);
},
nextItem(e) {
nextItem() {
if ( this.root ) return;
const i = this.currentItem;

View file

@ -1,7 +1,7 @@
<template lang="html">
<div class="ffz--profile-editor">
<div class="ffz--profile-editor">
<div class="tw-flex tw-align-items-center tw-border-t tw-pd-1">
<div class="tw-flex-grow-1"></div>
<div class="tw-flex-grow-1" />
<button
class="tw-button tw-button--text"
@click="save"
@ -11,8 +11,8 @@
</span>
</button>
<button
class="tw-mg-l-1 tw-button tw-button--text"
:disabled="item.profile && context.profiles.length < 2"
class="tw-mg-l-1 tw-button tw-button--text"
@click="del"
>
<span class="tw-button__text ffz-i-trash">
@ -37,11 +37,11 @@
</label>
<input
class="tw-input"
ref="name"
id="ffz:editor:name"
ref="name"
v-model="name"
/>
class="tw-input"
>
</div>
<div class="ffz--widget tw-flex tw-flex-nowrap">
@ -50,10 +50,10 @@
</label>
<textarea
class="tw-input"
ref="desc"
id="ffz:editor:description"
ref="desc"
v-model="desc"
class="tw-input"
/>
</div>
</div>
@ -63,10 +63,9 @@
{{ t('settings.data_management.profiles.edit.rules', 'Rules') }}
</header>
<section class="tw-pd-b-1">
{{ t(
'settings.data_management.profiles.edit.rules.description',
'Rules allows you to define a series of conditions under which this profile will be active.'
) }}
{{ t('settings.data_management.profiles.edit.rules.description',
'Rules allows you to define a series of conditions under which this profile will be active.')
}}
</section>
<filter-editor
@ -75,9 +74,8 @@
:context="test_context"
@change="unsaved = true"
/>
</div>
</div>
</div>
</template>
<script>
@ -100,17 +98,6 @@ export default {
}
},
created() {
this.context.context.on('context_changed', this.updateContext, this);
this.updateContext();
this.revert();
},
beforeDestroy() {
this.context.context.off('context_changed', this.updateContext, this);
},
watch: {
name() {
if ( this.name !== this.old_name )
@ -123,6 +110,16 @@ export default {
}
},
created() {
this.context.context.on('context_changed', this.updateContext, this);
this.updateContext();
this.revert();
},
beforeDestroy() {
this.context.context.off('context_changed', this.updateContext, this);
},
methods: {
revert() {
const profile = this.item.profile;
@ -131,7 +128,7 @@ export default {
profile.i18n_key ?
this.t(profile.i18n_key, profile.title, profile) :
profile.title :
'Unnamed Profile',
'Unnamed Profile';
this.old_desc = this.desc = profile ?
profile.desc_i18n_key ?

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="ffz--widget ffz--profile-manager tw-border-t tw-pd-y-1">
<div class="ffz--widget ffz--profile-manager tw-border-t tw-pd-y-1">
<div class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1">
<h3 class="ffz-i-attention">
This feature is not yet finished.
@ -30,11 +30,11 @@
:data-profile="p.id"
>
<div
class="ffz--profile tw-elevation-1 tw-c-background tw-border tw-pd-y-05 tw-pd-r-1 tw-mg-y-05 tw-flex tw-flex-nowrap"
:class="{live: p.live}"
class="ffz--profile tw-elevation-1 tw-c-background tw-border tw-pd-y-05 tw-pd-r-1 tw-mg-y-05 tw-flex tw-flex-nowrap"
tabindex="0"
>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-handle tw-pd-x-05 tw-pd-t-1 tw-pd-b-05">
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center handle tw-pd-x-05 tw-pd-t-1 tw-pd-b-05">
<span class="ffz-i-ellipsis-vert" />
</div>
@ -68,7 +68,7 @@
</div>
</section>
</div>
</div>
</div>
</template>
<script>
@ -78,6 +78,28 @@ import Sortable from 'sortablejs';
export default {
props: ['item', 'context'],
mounted() {
this._sortable = Sortable.create(this.$refs.list, {
draggable: 'section',
filter: 'button',
onUpdate: event => {
const id = event.item.dataset.profile,
profile = this.context.profile_keys[id];
if ( profile )
profile.move(event.newIndex);
}
});
},
beforeDestroy() {
if ( this._sortable )
this._sortable.destroy();
this._sortable = null;
},
methods: {
edit(profile) {
const item = {
@ -100,30 +122,7 @@ export default {
item.contents[0].parent = item;
this.$emit('change-item', item);
}
},
mounted() {
this._sortable = Sortable.create(this.$refs.list, {
draggable: 'section',
filter: 'button',
onUpdate: (event) => {
const id = event.item.dataset.profile,
profile = this.context.profile_keys[id];
if ( profile )
profile.move(event.newIndex);
}
});
},
beforeDestroy() {
if ( this._sortable )
this._sortable.destroy();
this._sortable = null;
}
}
</script>

View file

@ -1,10 +1,10 @@
<template lang="html">
<div class="ffz--widget ffz--profile-selector">
<div class="ffz--widget ffz--profile-selector">
<div
ref="button"
:class="{active: opened}"
tabindex="0"
class="tw-select"
:class="{active: opened}"
ref="button"
@keyup.up.stop.prevent="focusShow"
@keyup.left.stop.prevent="focusShow"
@keyup.down.stop.prevent="focusShow"
@ -15,7 +15,11 @@
>
{{ t(context.currentProfile.i18n_key, context.currentProfile.title, context.currentProfile) }}
</div>
<div v-if="opened" v-on-clickaway="hide" class="tw-balloon tw-block tw-balloon--lg tw-balloon--down tw-balloon--left">
<div
v-on-clickaway="hide"
v-if="opened"
class="tw-balloon tw-block tw-balloon--lg tw-balloon--down tw-balloon--left"
>
<div
class="ffz--profile-list tw-elevation-2 tw-c-background-alt"
@keyup.escape="focusHide"
@ -24,15 +28,16 @@
>
<div class="scrollable-area tw-border-b" data-simplebar>
<div class="simplebar-scroll-content">
<div class="simplebar-content" ref="popup">
<div ref="popup" class="simplebar-content">
<div
v-for="(p, idx) in context.profiles"
tabindex="0"
class="ffz--profile-row tw-relative tw-border-b tw-pd-y-05 tw-pd-r-3 tw-pd-l-1"
v-for="p in context.profiles"
:key="p.id"
:class="{
live: p.live,
current: p === context.currentProfile
}"
tabindex="0"
class="ffz--profile-row tw-relative tw-border-b tw-pd-y-05 tw-pd-r-3 tw-pd-l-1"
@keydown.up.stop.prevent=""
@keydown.down.stop.prevent=""
@keydown.page-up.stop.prevent=""
@ -73,7 +78,7 @@
</div>
</div>
</div>
</div>
</div>
</template>
<script>

View file

@ -1,16 +1,19 @@
<template lang="html">
<div class="ffz--widget ffz--checkbox" :class="{inherits: isInherited, default: isDefault}">
<div
:class="{inherits: isInherited, default: isDefault}"
class="ffz--widget ffz--checkbox"
>
<div class="tw-flex tw-align-items-center">
<input
type="checkbox"
class="tw-checkbox__input"
ref="control"
:id="item.full_key"
:checked="value"
type="checkbox"
class="tw-checkbox__input"
@change="onChange"
>
<label class="tw-checkbox__label" :for="item.full_key">
<label :for="item.full_key" class="tw-checkbox__label">
{{ t(item.i18n_key, item.title, item) }}
</label>
@ -25,7 +28,7 @@
</button>
<button v-if="has_value" class="tw-mg-l-05 tw-button tw-button--text tw-tooltip-wrapper" @click="clear">
<span class="tw-button__text ffz-i-cancel"></span>
<span class="tw-button__text ffz-i-cancel" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
@ -37,7 +40,7 @@
style="padding-left:2.2rem"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
</div>
</div>
</template>
<script>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="ffz--widget ffz--hotkey-input">
<div class="ffz--widget ffz--hotkey-input">
<label
:for="item.full_key"
v-html="t(item.i18n_key, item.title, item)"
@ -11,10 +11,10 @@
</div>
</div>
<div
type="text"
class="tw-mg-05 tw-input tw-input--icon-right"
ref="display"
:id="item.full_key"
type="text"
class="tw-mg-05 tw-input tw-input--icon-right"
tabindex="0"
@keyup="onKey"
>
@ -25,7 +25,7 @@
v-if="item.description"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
</div>
</div>
</template>
<script>

View file

@ -1,5 +1,5 @@
<template lang="html">
<div class="tw-input">
<div class="tw-input">
<header>
{{ t(item.i18n_key, item.title, item) }}
</header>
@ -8,20 +8,29 @@
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
<div v-for="(i, idx) in data" class="tw-mg-l-1">
<input type="radio" :name="item.full_key" :id="item.full_key + idx" :value="i.value" class="tw-radio__input">
<label :for="item.full_key + idx" class="tw-pd-y-05 tw-radio__label">{{ t(i.i18n_key, i.title, i) }}</label>
<div v-for="(i, idx) in data" :key="idx" class="tw-mg-l-1">
<input
:name="item.full_key"
:id="item.full_key + idx"
:value="i.value"
type="radio"
class="tw-radio__input"
>
<label
:for="item.full_key + idx"
class="tw-pd-y-05 tw-radio__label"
>
{{ t(i.i18n_key, i.title, i) }}
</label>
</div>
</div>
</div>
</template>
<script>
import SettingMixin from '../setting-mixin';
export default {
mixins: [SettingMixin],
props: ['item', 'context']
}
</script>

View file

@ -1,17 +1,24 @@
<template lang="html">
<div class="ffz--widget ffz--select-box" :class="{inherits: isInherited, default: isDefault}">
<div
:class="{inherits: isInherited, default: isDefault}"
class="ffz--widget ffz--select-box"
>
<div class="tw-flex tw-align-items-center">
<label :for="item.full_key">
{{ t(item.i18n_key, item.title, item) }}
</label>
<select
class="tw-mg-05 tw-select tw-display-inline tw-width-auto"
ref="control"
:id="item.full_key"
class="tw-mg-05 tw-select tw-display-inline tw-width-auto"
@change="onChange"
>
<option v-for="i in data" :selected="i.value === value">
<option
v-for="i in data"
:key="i.value"
:selected="i.value === value"
>
{{ i.i18n_key ? t(i.i18n_key, i.title, i) : i.title }}
</option>
</select>
@ -27,7 +34,7 @@
</button>
<button v-if="has_value" class="tw-mg-l-05 tw-button tw-button--text tw-tooltip-wrapper" @click="clear">
<span class="tw-button__text ffz-i-cancel"></span>
<span class="tw-button__text ffz-i-cancel" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
@ -39,11 +46,10 @@
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
</div>
</div>
</template>
<script>
import SettingMixin from '../setting-mixin';
export default {
@ -60,5 +66,4 @@ export default {
}
}
}
</script>

View file

@ -1,17 +1,20 @@
<template lang="html">
<div class="ffz--widget ffz--text-box" :class="{inherits: isInherited, default: isDefault}">
<div
:class="{inherits: isInherited, default: isDefault}"
class="ffz--widget ffz--text-box"
>
<div class="tw-flex tw-align-items-center">
<label :for="item.full_key">
{{ t(item.i18n_key, item.title, item) }}
</label>
<input
class="tw-mg-05 tw-input tw-display-inline tw-width-auto"
ref="control"
:id="item.full_key"
@change="onChange"
:value="value"
/>
class="tw-mg-05 tw-input tw-display-inline tw-width-auto"
@change="onChange"
>
<button
v-if="source && source !== profile"
@ -24,7 +27,7 @@
</button>
<button v-if="has_value" class="tw-mg-l-05 tw-button tw-button--text tw-tooltip-wrapper" @click="clear">
<span class="tw-button__text ffz-i-cancel"></span>
<span class="tw-button__text ffz-i-cancel" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
@ -36,11 +39,10 @@
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
/>
</div>
</div>
</template>
<script>
import SettingMixin from '../setting-mixin';
export default {
@ -55,5 +57,4 @@ export default {
}
}
}
</script>

View file

@ -1,29 +1,41 @@
<template lang="html">
<div class="ffz-auto-host-options tw-c-background">
<div class="ffz-auto-host-options tw-c-background">
<header class="tw-full-width tw-align-items-center tw-flex tw-flex-nowrap">
<h4>{{ t('metadata.host.title', 'Auto Host Management') }}</h4>
</header>
<div class="tab tw-overflow-hidden"
<div
v-show="activeTab === 'auto-host'"
:class="{ active: activeTab === 'auto-host'}">
:class="{ active: activeTab === 'auto-host'}"
class="tab tw-overflow-hidden"
>
<section class="tw-border-t tw-full-width tw-full-height">
<main class="tw-flex-grow-1 scrollable-area" data-simplebar="init">
<div class="simplebar-scroll-content">
<draggable v-model="hosts" class="simplebar-content" :options="{
<draggable
v-model="hosts"
:options="{
draggable: '.ffz--host-user',
animation: 150,
}" @update="rearrangeHosts">
<div v-for="host in hosts" class="tw-border-t ffz--host-user" :key="host._id" :data-id="host._id">
}"
class="simplebar-content"
@update="rearrangeHosts"
>
<div
v-for="host in hosts"
:key="host._id"
:data-id="host._id"
class="tw-border-t ffz--host-user"
>
<div class="tw-interactable">
<div class="tw-align-items-center tw-flex tw-flex-row tw-flex-nowrap tw-mg-x-1">
<figure class="ffz-i-ellipsis-vert handle"></figure>
<figure class="ffz-i-ellipsis-vert handle" />
<div class="ffz-channel-avatar">
<img :src="host.logo" :alt="host.display_name + '(' + host.name + ')'">
</div>
<p class="tw-ellipsis tw-flex-grow-1 tw-mg-l-1 tw-font-size-5">{{ host.name }}</p>
<div class="tw-flex-grow-1 tw-pd-x-2"></div>
<div class="tw-flex-grow-1 tw-pd-x-2" />
<button class="tw-button-icon tw-mg-x-05 ffz--host-remove-user" @click="removeFromHosts">
<figure class="ffz-i-trash"></figure>
<figure class="ffz-i-trash" />
</button>
</div>
</div>
@ -33,15 +45,21 @@
</main>
</section>
<header class="tw-border-t tw-full-width tw-align-items-center tw-flex tw-flex-noxwrap tw-pd-1">
<div class="tw-flex-grow-1 tw-pd-x-2"></div>
<button class="tw-button tw-button--hollow tw-mg-x-05" :class="{'tw-button--disabled': addedToHosts}" @click="addToAutoHosts">
<div class="tw-flex-grow-1 tw-pd-x-2" />
<button
:class="{'tw-button--disabled': addedToHosts}"
class="tw-button tw-button--hollow tw-mg-x-05"
@click="addToAutoHosts"
>
<span class="tw-button__text">{{ t('metadata.host.add-channel', 'Add To Auto Host') }}</span>
</button>
</header>
</div>
<div class="tab tw-overflow-hidden"
<div
v-show="activeTab === 'settings'"
:class="{ active: activeTab === 'settings'}">
:class="{ active: activeTab === 'settings'}"
class="tab tw-overflow-hidden"
>
<section class="tw-border-t tw-full-width tw-full-height">
<main class="tw-flex-grow-1 scrollable-area" data-simplebar="init">
<div class="simplebar-scroll-content">
@ -49,11 +67,14 @@
<div class="tw-pd-1">
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
<input
id="autoHostSettings:enabled"
data-setting="enabled"
:checked="autoHostSettings.enabled"
@change="updateCheckbox">
type="checkbox"
class="tw-checkbox__input"
data-setting="enabled"
@change="updateCheckbox"
>
<label for="autoHostSettings:enabled" class="tw-checkbox__label">
{{ t('metadata.host.setting.auto-hosting.title', 'Auto Hosting') }}
</label>
@ -65,28 +86,34 @@
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
<input
id="autoHostSettings:team_host"
data-setting="team_host"
:checked="autoHostSettings.team_host"
@change="updateCheckbox">
type="checkbox"
class="tw-checkbox__input"
data-setting="team_host"
@change="updateCheckbox"
>
<label for="autoHostSettings:team_host" class="tw-checkbox__label">
{{ t('metadata.host.setting.team-hosting.title', 'Team Hosting') }}
</label>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.team-hosting.description',
'Automatically host random channels from your team when you\'re not live. ' +
"Automatically host random channels from your team when you're not live. " +
'Team channels will be hosted before any channels in your host list.') }}
</section>
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
<input
id="autoHostSettings:vodcast_hosting"
data-setting="deprioritize_vodcast"
:checked="!autoHostSettings.deprioritize_vodcast"
@change="updateCheckbox">
type="checkbox"
class="tw-checkbox__input"
data-setting="deprioritize_vodcast"
@change="updateCheckbox"
>
<label for="autoHostSettings:vodcast_hosting" class="tw-checkbox__label">
{{ t('metadata.host.setting.vodcast-hosting.title', 'Vodcast Hosting') }}
</label>
@ -98,11 +125,14 @@
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
<input
id="autoHostSettings:recommended_host"
data-setting="recommended_host"
:checked="autoHostSettings.recommended_host"
@change="updateCheckbox">
type="checkbox"
class="tw-checkbox__input"
data-setting="recommended_host"
@change="updateCheckbox"
>
<label for="autoHostSettings:recommended_host" class="tw-checkbox__label">
{{ t('metadata.host.setting.recommended-hosting.title', 'Auto Host Channels Similar To Yours') }}
</label>
@ -113,11 +143,14 @@
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
<input
id="autoHostSettings:strategy"
data-setting="strategy"
:checked="autoHostSettings.strategy === 'random'"
@change="updateCheckbox">
type="checkbox"
class="tw-checkbox__input"
data-setting="strategy"
@change="updateCheckbox"
>
<label for="autoHostSettings:strategy" class="tw-checkbox__label">
{{ t('metadata.host.setting.strategy.title', 'Randomize Host Order') }}
</label>
@ -125,7 +158,7 @@
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.strategy.description',
'If enabled, auto-hosts will be picked at random. ' +
'Otherwise they\'re picked in order.') }}
"Otherwise they're picked in order.") }}
</section>
</div>
</div>
@ -136,19 +169,25 @@
</div>
<footer>
<div class="host-options__tabs-container tw-border-t">
<div id="host-options__auto-host" class="host-options__tab tw-pd-x-1"
<div
id="host-options__auto-host"
:class="{active: activeTab === 'auto-host'}"
class="host-options__tab tw-pd-x-1"
@click="setActiveTab('auto-host')"
:class="{active: activeTab === 'auto-host'}">
>
<span>{{ t('metadata.host.tab.auto-host', 'Auto Host') }}</span>
</div>
<div id="host-options__settings" class="host-options__tab tw-pd-x-1"
<div
id="host-options__settings"
:class="{active: activeTab === 'settings'}"
class="host-options__tab tw-pd-x-1"
@click="setActiveTab('settings')"
:class="{active: activeTab === 'settings'}">
>
<span>{{ t('metadata.host.tab.settings', 'Settings') }}</span>
</div>
</div>
</footer>
</div>
</div>
</template>

View file

@ -1,10 +1,10 @@
<template lang="html">
<div
<div
v-if="item.tabs"
class="ffz--tab-container"
@keyup.alt.page-up.stop="focusPrevTab"
@keyup.alt.page-down.stop="focusNextTab"
>
>
<header
class="tw-flex"
tabindex="0"
@ -20,21 +20,22 @@
>
<div
v-for="(i, idx) in item.tabs"
role="tab"
:key="i.full_key"
:id="'tab-for-' + i.full_key"
:aria-selected="selected === idx"
:aria-controls="'tab-panel-' + i.full_key"
class="tab tw-pd-y-05 tw-pd-x-1"
:class="[selected === idx ? 'active' : '']"
role="tab"
class="tab tw-pd-y-05 tw-pd-x-1"
@click="selected = idx"
>
{{ t(i.i18n_key, i.title, i) }}
</div>
</header>
<section
class="tw-border"
:id="'tab-panel-' + tab.full_key"
:aria-labelledby="'tab-for-' + tab.full_key"
class="tw-border"
role="tabpanel"
aria-hidden="false"
aria-expanded="true"
@ -44,15 +45,15 @@
</section>
<component
v-for="i in tab.contents"
v-bind:is="i.component"
:currentProfile="currentProfile"
:is="i.component"
:current-profile="currentProfile"
:profiles="profiles"
:context="context"
:item="i"
:key="i.full_key"
/>
</section>
</div>
</div>
</template>
<script>