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,62 +1,84 @@
<template lang="html">
<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"
>
<span class="ffz-i-info" />
{{ t('setting.badge-inheritence', 'These values are being overridden by another profile and may not take effect.') }}
</div>
<div class="tw-mg-b-2 tw-align-right">
<button
class="tw-mg-l-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@click="clear"
:disabled="! has_value"
<div class="ffz--badge-visibility tw-pd-t-05">
<div
v-if="source && source !== profile"
class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1"
>
<span class="tw-button__icon tw-button__icon--left">
<figure class="ffz-i-cancel" />
</span>
<span class="tw-button__text">
{{ t('setting.reset-all', 'Reset All to Default') }}
</span>
</button>
</div>
<span class="ffz-i-info" />
{{ t('setting.badge-inheritence', 'These values are being overridden by another profile and may not take effect.') }}
</div>
<section class="ffz--menu-container tw-border-t" v-for="sec in data">
<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)}">
<input
type="checkbox"
class="tw-checkbox__input"
:checked="badgeChecked(i.id)"
:id="i.id"
@click="onChange(i.id, $event)"
<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"
>
<span class="tw-button__icon tw-button__icon--left">
<figure class="ffz-i-cancel" />
</span>
<span class="tw-button__text">
{{ t('setting.reset-all', 'Reset All to Default') }}
</span>
</button>
</div>
<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)"
:key="i.id"
:class="{default: badgeDefault(i.id)}"
class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex"
>
<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 }" />
<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>
<button
class="tw-mg-t-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@click="reset(i.id)"
>
<span class="tw-button__text">Reset</span>
<span class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</span>
</button>
</div>
</label>
</li>
</ul>
</section>
</div>
<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
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"
@click="reset(i.id)"
>
<span class="tw-button__text">Reset</span>
<span class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</span>
</button>
</div>
</label>
</li>
</ul>
</section>
</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="tw-align-center">
<h2>{{ t('home.changelog', 'Changelog') }}</h2>
<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 ref="changes" />
</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,35 +1,32 @@
<template lang="html">
<div class="ffz--home tw-border-t tw-pd-t-1">
<h2>Feedback</h2>
<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">
<h3 class="ffz-i-attention">
Please keep in mind that FrankerFaceZ v4 is under heavy development.
</h3>
</div>
<div class="tw-mg-y-1 tw-c-background-accent tw-c-text-overlay tw-pd-1">
<h3 class="ffz-i-attention">
Please keep in mind that FrankerFaceZ v4 is under heavy development.
</h3>
</div>
<p>
Okay, still here? Great! You can provide feedback and bug reports by
<a href="https://github.com/FrankerFaceZ/FrankerFaceZ/issues" target="_blank" rel="noopener">
<p>
Okay, still here? Great! You can provide feedback and bug reports by
<a href="https://github.com/FrankerFaceZ/FrankerFaceZ/issues" target="_blank" rel="noopener">
opening an issue at our GitHub repository</a>.
You can also <a href="https://twitter.com/FrankerFaceZ" target="_blank" rel="noopener">
You can also <a href="https://twitter.com/FrankerFaceZ" target="_blank" rel="noopener">
tweet at us</a>.
</p>
</p>
<p>
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>
<p>
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>
</template>
<script>
export default {
props: ['item', 'context'],
}
</script>

View file

@ -1,55 +1,55 @@
<template lang="html">
<div class="ffz--widget ffz--filter-editor">
<div ref="list" class="ffz--rule-list">
<section v-for="(rule, idx) in rules">
<div
class="ffz--rule tw-elevation-1 tw-c-background tw-border tw-mg-b-05 tw-pd-y-05 tw-pd-r-1 tw-flex tw-flex-nowrap tw-align-items-start"
tabindex="0"
>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-handle tw-pd-x-05 tw-pd-y-1">
<span class="ffz-i-ellipsis-vert" />
</div>
<div class="tw-flex-shrink-0 tw-pd-y-05">
Channel
</div>
<div class="tw-mg-x-1 tw-flex tw-flex-grow-1">
<div class="tw-flex-shrink-0 tw-mg-r-1">
<select class="tw-select">
<option>is one of</option>
<option>is not one of</option>
</select>
<div class="ffz--widget ffz--filter-editor">
<div ref="list" class="ffz--rule-list">
<section v-for="(rule, idx) in rules">
<div
class="ffz--rule tw-elevation-1 tw-c-background tw-border tw-mg-b-05 tw-pd-y-05 tw-pd-r-1 tw-flex tw-flex-nowrap tw-align-items-start"
tabindex="0"
>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-handle tw-pd-x-05 tw-pd-y-1">
<span class="ffz-i-ellipsis-vert" />
</div>
<div class="tw-flex-grow-1">
<input
type="text"
class="tw-input"
value="SirStendec"
/>
<div class="tw-flex-shrink-0 tw-pd-y-05">
Channel
</div>
<div class="tw-mg-x-1 tw-flex tw-flex-grow-1">
<div class="tw-flex-shrink-0 tw-mg-r-1">
<select class="tw-select">
<option>is one of</option>
<option>is not one of</option>
</select>
</div>
<div class="tw-flex-grow-1">
<input
type="text"
class="tw-input"
value="SirStendec"
>
</div>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center">
<button class="tw-button tw-button--text" @click="del(idx)">
<span class="tw-button__text ffz-i-trash">
{{ t('setting.filters.delete', 'Delete') }}
</span>
</button>
</div>
</div>
</section>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center">
<button class="tw-button tw-button--text" @click="del(idx)">
<span class="tw-button__text ffz-i-trash">
{{ t('setting.filters.delete', 'Delete') }}
</span>
</button>
</div>
</div>
</section>
<button
class="tw-button tw-button--hollow tw-mg-y-1 tw-full-width"
@click="newRule"
>
<span class="tw-button__text ffz-i-plus">
{{ t('', 'Add New Rule') }}
</span>
</button>
</div>
<button
class="tw-button tw-button--hollow tw-mg-y-1 tw-full-width"
@click="newRule"
>
<span class="tw-button__text ffz-i-plus">
{{ t('', 'Add New Rule') }}
</span>
</button>
</div>
</template>
<script>

View file

@ -1,72 +1,72 @@
<template lang="html">
<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>
<span class="tw-c-text-alt">
{{ t('home.tag-line', 'The Twitch Enhancement Suite') }}
</span>
<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>
<span class="tw-c-text-alt">
{{ t('home.tag-line', 'The Twitch Enhancement Suite') }}
</span>
</div>
<section class="tw-pd-t-1 tw-border-t tw-mg-t-1">
<h2>Welcome to the v4.0 Beta</h2>
<p>
This is the initial, beta release of FrankerFaceZ v4.0 with support
for the Twitch website rewrite.
As you'll notice, this release is <strong>not</strong> complete.
There are missing features. There are bugs. If you are a moderator,
you will want to just keep opening a Legacy Chat Popout for now.
</p>
<p>
FrankerFaceZ v4.0 is still under heavy development and there will
be significant changes and improvements in the coming weeks. For
now, here are some of the bigger issues:
</p>
<ul class="tw-mg-b-2">
<li>Settings from the old version are not being imported.</li>
<li>Settings cannot be searched.</li>
<li>Emoji aren't displayed.</li>
<li>The emote menu isn't finished.</li>
<li>Tab-completion and advanced input isn't available.</li>
</ul>
<p>And the biggest features still under development:</p>
<ul class="tw-mg-b-2">
<li>Emoji Rendering</li>
<li>Emotes Menu</li>
<li>Chat Filtering (Highlighted Words, etc.)</li>
<li>Room Status Indicators</li>
<li>Custom Mod Cards</li>
<li>Custom Mod Actions</li>
<li>Recent Highlights</li>
<li>More Channel Metadata</li>
<li>Disable Hosting</li>
<li>Portrait Mode</li>
<li>Importing and exporting settings</li>
<li>User Aliases</li>
<li>Rich Content in Chat (aka Clip Embeds)</li>
</ul>
<p>
For a possibly more up-to-date list of what I'm working on,
please consult <a href="https://trello.com/b/LGcYPFwi/frankerfacez-v4" target="_blank">this Trello board</a>.
</p>
</section>
</div>
<div class="tw-mg-l-1 tw-flex-shrink-0 tweet-column">
<a class="twitter-timeline" data-width="300" data-theme="dark" href="https://twitter.com/FrankerFaceZ?ref_src=twsrc%5Etfw">
Tweets by FrankerFaceZ
</a>
</div>
<section class="tw-pd-t-1 tw-border-t tw-mg-t-1">
<h2>Welcome to the v4.0 Beta</h2>
<p>
This is the initial, beta release of FrankerFaceZ v4.0 with support
for the Twitch website rewrite.
As you'll notice, this release is <strong>not</strong> complete.
There are missing features. There are bugs. If you are a moderator,
you will want to just keep opening a Legacy Chat Popout for now.
</p>
<p>
FrankerFaceZ v4.0 is still under heavy development and there will
be significant changes and improvements in the coming weeks. For
now, here are some of the bigger issues:
</p>
<ul class="tw-mg-b-2">
<li>Settings from the old version are not being imported.</li>
<li>Settings cannot be searched.</li>
<li>Emoji aren't displayed.</li>
<li>The emote menu isn't finished.</li>
<li>Tab-completion and advanced input isn't available.</li>
</ul>
<p>And the biggest features still under development:</p>
<ul class="tw-mg-b-2">
<li>Emoji Rendering</li>
<li>Emotes Menu</li>
<li>Chat Filtering (Highlighted Words, etc.)</li>
<li>Room Status Indicators</li>
<li>Custom Mod Cards</li>
<li>Custom Mod Actions</li>
<li>Recent Highlights</li>
<li>More Channel Metadata</li>
<li>Disable Hosting</li>
<li>Portrait Mode</li>
<li>Importing and exporting settings</li>
<li>User Aliases</li>
<li>Rich Content in Chat (aka Clip Embeds)</li>
</ul>
<p>
For a possibly more up-to-date list of what I'm working on,
please consult <a href="https://trello.com/b/LGcYPFwi/frankerfacez-v4" target="_blank">this Trello board</a>.
</p>
</section>
</div>
<div class="tw-mg-l-1 tw-flex-shrink-0 tweet-column">
<a class="twitter-timeline" data-width="300" data-theme="dark" href="https://twitter.com/FrankerFaceZ?ref_src=twsrc%5Etfw">
Tweets by FrankerFaceZ
</a>
</div>
</div>
</template>

View file

@ -1,78 +1,81 @@
<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 }">
<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">
<!--div class="tw-search-input">
<label for="ffz-main-menu.search" class="hide-accessible">{{ t('main-menu.search', 'Search Settings') }}</label>
<div class="relative">
<div class="tw-input__icon-group">
<div class="tw-input__icon">
<figure class="ffz-i-search" />
<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">
<!--div class="tw-search-input">
<label for="ffz-main-menu.search" class="hide-accessible">{{ t('main-menu.search', 'Search Settings') }}</label>
<div class="relative">
<div class="tw-input__icon-group">
<div class="tw-input__icon">
<figure class="ffz-i-search" />
</div>
</div>
<input type="search" class="tw-input tw-input--icon-left" :placeholder="t('main-menu.search', 'Search Settings')" autocapitalize="off" autocorrect="off" autocomplete="off" id="ffz-main-menu.search">
</div>
<input type="search" class="tw-input tw-input--icon-left" :placeholder="t('main-menu.search', 'Search Settings')" autocapitalize="off" autocorrect="off" autocomplete="off" id="ffz-main-menu.search">
</div>
</div-->
</div>
<button class="tw-button-icon tw-mg-x-05" @click="resize" v-if="!exclusive">
<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">
<span class="tw-button-icon__icon">
<figure class="ffz-i-window-close" />
</span>
</button>
</header>
<section class="tw-border-t tw-full-height tw-full-width tw-flex tw-flex-nowrap tw-overflow-hidden">
<nav class="ffz-vertical-nav tw-c-background-alt-2 tw-border-r tw-full-height tw-flex tw-flex-column tw-flex-shrink-0 tw-flex-nowrap">
<header class="tw-border-b tw-pd-1">
<profile-selector
:context="context"
@navigate="navigate"
/>
</header>
<div class="tw-full-width tw-full-height tw-overflow-hidden tw-flex tw-flex-nowrap tw-relative">
<div class="ffz-vertical-nav__items tw-full-width tw-flex-grow-1 scrollable-area" data-simplebar>
<div class="simplebar-scroll-content">
<div class="simplebar-content">
<menu-tree
:currentItem="currentItem"
:modal="nav"
@change-item="changeItem"
@navigate="navigate"
/>
</div>
</div>
</div>
</div-->
</div>
<footer class="tw-c-text-alt tw-border-t tw-pd-1">
<div>
{{ t('main-menu.version', 'Version %{version}', {version: version.toString()}) }}
</div>
<div class="tw-c-text-alt-2">
{{version.build}}
</div>
</footer>
</nav>
<main class="tw-flex-grow-1 scrollable-area" data-simplebar>
<div class="simplebar-scroll-content">
<div class="simplebar-content">
<menu-page
ref="page"
<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 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>
</button>
</header>
<section class="tw-border-t tw-full-height tw-full-width tw-flex tw-flex-nowrap tw-overflow-hidden">
<nav class="ffz-vertical-nav tw-c-background-alt-2 tw-border-r tw-full-height tw-flex tw-flex-column tw-flex-shrink-0 tw-flex-nowrap">
<header class="tw-border-b tw-pd-1">
<profile-selector
:context="context"
:item="currentItem"
@change-item="changeItem"
@navigate="navigate"
v-if="currentItem"
/>
</header>
<div class="tw-full-width tw-full-height tw-overflow-hidden tw-flex tw-flex-nowrap tw-relative">
<div class="ffz-vertical-nav__items tw-full-width tw-flex-grow-1 scrollable-area" data-simplebar>
<div class="simplebar-scroll-content">
<div class="simplebar-content">
<menu-tree
:current-item="currentItem"
:modal="nav"
@change-item="changeItem"
@navigate="navigate"
/>
</div>
</div>
</div>
</div>
</div>
</main>
</section>
</div>
<footer class="tw-c-text-alt tw-border-t tw-pd-1">
<div>
{{ t('main-menu.version', 'Version %{version}', {version: version.toString()}) }}
</div>
<div class="tw-c-text-alt-2">
{{ version.build }}
</div>
</footer>
</nav>
<main class="tw-flex-grow-1 scrollable-area" data-simplebar>
<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"
/>
</div>
</div>
</main>
</section>
</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">
<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"
<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"
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"
:context="context"
:item="i"
:key="i.full_key"
<component
v-for="i in item.contents"
: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">
<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">
<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>
<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>
</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',
"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."
) }}
{{ 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.")
}}
</div>
</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)"
/>
<template v-if="! item.contents || ! item.contents.length">
<ul class="tw-border-t tw-pd-y-1">
<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
v-for="i in item.contents"
ref="children"
:is="i.component"
:context="context"
:item="i"
:key="i.full_key"
@change-item="changeItem"
@navigate="navigate"
/>
</div>
</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">
<ul class="tw-border-t tw-pd-y-1">
<li class="tw-pd-x-1" v-for="i in item.items">
<a href="#" @click="$emit('change-item', i, false)">
{{ t(i.i18n_key, i.title, i) }}
</a>
</li>
</ul>
</template>
<component
v-for="i in item.contents"
v-bind:is="i.component"
ref="children"
:context="context"
:item="i"
:key="i.full_key"
@change-item="changeItem"
@navigate="navigate"
/>
</div>
</template>
<script>

View file

@ -1,53 +1,52 @@
<template lang="html">
<ul
v-if="modal"
class="ffz--menu-tree"
:role="[root ? 'group' : 'tree']"
:tabindex="tabIndex"
@keyup.up="prevItem"
@keyup.down="nextItem"
@keyup.left="prevLevel"
@keyup.right="nextLevel"
@keyup.*="expandAll"
>
<li
v-for="item in modal"
:key="item.full_key"
:class="[currentItem === item ? 'active' : '']"
role="presentation"
<ul
v-if="modal"
:role="[root ? 'group' : 'tree']"
:tabindex="tabIndex"
class="ffz--menu-tree"
@keyup.up="prevItem"
@keyup.down="nextItem"
@keyup.left="prevLevel"
@keyup.right="nextLevel"
@keyup.*="expandAll"
>
<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"
@click="clickItem(item)"
<li
v-for="item in modal"
:key="item.full_key"
:class="[currentItem === item ? 'active' : '']"
role="presentation"
>
<span
role="presentation"
class="arrow"
:class="[
item.items ? '' : 'ffz--invisible',
item.expanded ? 'ffz-i-down-dir' : 'ffz-i-right-dir'
]"
<div
: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
: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) }}
</span>
<span v-if="item.pill" class="pill">
{{ item.pill_i18n_key ? t(item.pill_i18n_key, item.pill, item) : item.pill }}
</span>
</div>
<menu-tree
v-if="item.items && item.expanded"
:root="item"
:current-item="currentItem"
:modal="item.items"
@change-item="i => $emit('change-item', i)"
/>
<span class="tw-flex-grow-1">
{{ t(item.i18n_key, item.title, item) }}
</span>
<span v-if="item.pill" class="pill">
{{ item.pill_i18n_key ? t(item.pill_i18n_key, item.pill, item) : item.pill }}
</span>
</div>
<menu-tree
:root="item"
:currentItem="currentItem"
:modal="item.items"
v-if="item.items && item.expanded"
@change-item="i => $emit('change-item', i)"
/>
</li>
</ul>
</li>
</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,83 +1,81 @@
<template lang="html">
<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>
<button
class="tw-button tw-button--text"
@click="save"
>
<span class="tw-button__text ffz-i-floppy">
{{ t('settings.profiles.save', 'Save') }}
</span>
</button>
<button
class="tw-mg-l-1 tw-button tw-button--text"
:disabled="item.profile && context.profiles.length < 2"
@click="del"
>
<span class="tw-button__text ffz-i-trash">
{{ t('setting.profiles.delete', 'Delete') }}
</span>
</button>
<!--button class="tw-mg-l-1 tw-button tw-button--text">
<span class="tw-button__text ffz-i-download">
{{ t('setting.profiles.export', 'Export') }}
</span>
</button-->
</div>
<div class="ffz--menu-container tw-border-t">
<header>
{{ t('settings.data_management.profiles.edit.general', 'General') }}
</header>
<div class="ffz--widget tw-flex tw-flex-nowrap">
<label for="ffz:editor:name">
{{ t('settings.data_management.profiles.edit.name', 'Name') }}
</label>
<input
class="tw-input"
ref="name"
id="ffz:editor:name"
v-model="name"
/>
<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" />
<button
class="tw-button tw-button--text"
@click="save"
>
<span class="tw-button__text ffz-i-floppy">
{{ t('settings.profiles.save', 'Save') }}
</span>
</button>
<button
: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">
{{ t('setting.profiles.delete', 'Delete') }}
</span>
</button>
<!--button class="tw-mg-l-1 tw-button tw-button--text">
<span class="tw-button__text ffz-i-download">
{{ t('setting.profiles.export', 'Export') }}
</span>
</button-->
</div>
<div class="ffz--widget tw-flex tw-flex-nowrap">
<label for="ffz:editor:description">
{{ t('settings.data_management.profiles.edit.desc', 'Description') }}
</label>
<div class="ffz--menu-container tw-border-t">
<header>
{{ t('settings.data_management.profiles.edit.general', 'General') }}
</header>
<textarea
class="tw-input"
ref="desc"
id="ffz:editor:description"
v-model="desc"
<div class="ffz--widget tw-flex tw-flex-nowrap">
<label for="ffz:editor:name">
{{ t('settings.data_management.profiles.edit.name', 'Name') }}
</label>
<input
id="ffz:editor:name"
ref="name"
v-model="name"
class="tw-input"
>
</div>
<div class="ffz--widget tw-flex tw-flex-nowrap">
<label for="ffz:editor:description">
{{ t('settings.data_management.profiles.edit.desc', 'Description') }}
</label>
<textarea
id="ffz:editor:description"
ref="desc"
v-model="desc"
class="tw-input"
/>
</div>
</div>
</div>
<div class="ffz--menu-container tw-border-t">
<header>
{{ 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.'
) }}
</section>
<div class="ffz--menu-container tw-border-t">
<header>
{{ 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.')
}}
</section>
<filter-editor
:filters="filters"
:rules="rules"
:context="test_context"
@change="unsaved = true"
<filter-editor
:filters="filters"
:rules="rules"
: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,74 +1,74 @@
<template lang="html">
<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.
</h3>
<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.
</h3>
Creating and editing profiles is disabled until the rule editor is finished.
</div>
<div class="tw-flex tw-align-items-center tw-pd-b-05">
<div class="tw-flex-grow-1">
{{ t('setting.profiles.drag', 'Drag profiles to change their priority.') }}
Creating and editing profiles is disabled until the rule editor is finished.
</div>
<button class="tw-mg-l-1 tw-button tw-button--text" disabled @notclick="edit()">
<span class="tw-button__text ffz-i-plus">
{{ t('setting.profiles.new', 'New Profile') }}
</span>
</button>
<!--button class="tw-mg-l-1 tw-button tw-button--text">
<span class="tw-button__text ffz-i-upload">
{{ t('setting.profiles.import', 'Import…') }}
</span>
</button-->
</div>
<div ref="list" class="ffz--profile-list">
<section
v-for="p in context.profiles"
:key="p.id"
: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}"
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">
<span class="ffz-i-ellipsis-vert" />
</div>
<div class="tw-flex-grow-1">
<h4>{{ t(p.i18n_key, p.title, p) }}</h4>
<div v-if="p.description" class="description">
{{ t(p.desc_i18n_key, p.description, p) }}
</div>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center">
<button class="tw-button tw-button--text" disabled @notclick="edit(p)">
<span class="tw-button__text ffz-i-cog">
{{ t('setting.profiles.configure', 'Configure') }}
</span>
</button>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-border-l tw-mg-l-1 tw-pd-l-1">
<div v-if="p.live" class="ffz--profile__icon ffz-i-ok tw-tooltip-wrapper">
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.active', 'This profile is active.') }}
</div>
</div>
<div v-if="! p.live" class="ffz--profile__icon ffz-i-cancel tw-tooltip-wrapper">
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.inactive', 'This profile is not active.') }}
</div>
</div>
</div>
<div class="tw-flex tw-align-items-center tw-pd-b-05">
<div class="tw-flex-grow-1">
{{ t('setting.profiles.drag', 'Drag profiles to change their priority.') }}
</div>
</section>
<button class="tw-mg-l-1 tw-button tw-button--text" disabled @notclick="edit()">
<span class="tw-button__text ffz-i-plus">
{{ t('setting.profiles.new', 'New Profile') }}
</span>
</button>
<!--button class="tw-mg-l-1 tw-button tw-button--text">
<span class="tw-button__text ffz-i-upload">
{{ t('setting.profiles.import', 'Import…') }}
</span>
</button-->
</div>
<div ref="list" class="ffz--profile-list">
<section
v-for="p in context.profiles"
:key="p.id"
:data-profile="p.id"
>
<div
: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 handle tw-pd-x-05 tw-pd-t-1 tw-pd-b-05">
<span class="ffz-i-ellipsis-vert" />
</div>
<div class="tw-flex-grow-1">
<h4>{{ t(p.i18n_key, p.title, p) }}</h4>
<div v-if="p.description" class="description">
{{ t(p.desc_i18n_key, p.description, p) }}
</div>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center">
<button class="tw-button tw-button--text" disabled @notclick="edit(p)">
<span class="tw-button__text ffz-i-cog">
{{ t('setting.profiles.configure', 'Configure') }}
</span>
</button>
</div>
<div class="tw-flex tw-flex-shrink-0 tw-align-items-center tw-border-l tw-mg-l-1 tw-pd-l-1">
<div v-if="p.live" class="ffz--profile__icon ffz-i-ok tw-tooltip-wrapper">
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.active', 'This profile is active.') }}
</div>
</div>
<div v-if="! p.live" class="ffz--profile__icon ffz-i-cancel tw-tooltip-wrapper">
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.inactive', 'This profile is not active.') }}
</div>
</div>
</div>
</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,79 +1,84 @@
<template lang="html">
<div class="ffz--widget ffz--profile-selector">
<div
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"
@keyup.right.stop.prevent="focusShow"
@keyup.enter="focusShow"
@keyup.space="focusShow"
@click="togglePopup"
>
{{ 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 class="ffz--widget ffz--profile-selector">
<div
class="ffz--profile-list tw-elevation-2 tw-c-background-alt"
@keyup.escape="focusHide"
@focusin="focus"
@focusout="blur"
ref="button"
:class="{active: opened}"
tabindex="0"
class="tw-select"
@keyup.up.stop.prevent="focusShow"
@keyup.left.stop.prevent="focusShow"
@keyup.down.stop.prevent="focusShow"
@keyup.right.stop.prevent="focusShow"
@keyup.enter="focusShow"
@keyup.space="focusShow"
@click="togglePopup"
>
<div class="scrollable-area tw-border-b" data-simplebar>
<div class="simplebar-scroll-content">
<div class="simplebar-content" ref="popup">
<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"
:class="{
live: p.live,
current: p === context.currentProfile
}"
@keydown.up.stop.prevent=""
@keydown.down.stop.prevent=""
@keydown.page-up.stop.prevent=""
@keydown.page-down.stop.prevent=""
@keyup.up.stop="prevItem"
@keyup.down.stop="nextItem"
@keyup.home="firstItem"
@keyup.end="lastItem"
@keyup.page-up.stop="prevPage"
@keyup.page-down.stop="nextPage"
@keyup.enter="changeProfile(p)"
@click="changeProfile(p)"
>
{{ t(context.currentProfile.i18n_key, context.currentProfile.title, context.currentProfile) }}
</div>
<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"
@focusin="focus"
@focusout="blur"
>
<div class="scrollable-area tw-border-b" data-simplebar>
<div class="simplebar-scroll-content">
<div ref="popup" class="simplebar-content">
<div
v-if="p.live"
class="tw-tooltip-wrapper ffz--profile-row__icon ffz-i-ok tw-absolute"
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=""
@keydown.page-down.stop.prevent=""
@keyup.up.stop="prevItem"
@keyup.down.stop="nextItem"
@keyup.home="firstItem"
@keyup.end="lastItem"
@keyup.page-up.stop="prevPage"
@keyup.page-down.stop="nextPage"
@keyup.enter="changeProfile(p)"
@click="changeProfile(p)"
>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.active', 'This profile is active.') }}
<div
v-if="p.live"
class="tw-tooltip-wrapper ffz--profile-row__icon ffz-i-ok tw-absolute"
>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.profiles.active', 'This profile is active.') }}
</div>
</div>
</div>
<h4>{{ t(p.i18n_key, p.title, p) }}</h4>
<div v-if="p.description" class="description">
{{ t(p.desc_i18n_key, p.description, p) }}
<h4>{{ t(p.i18n_key, p.title, p) }}</h4>
<div v-if="p.description" class="description">
{{ t(p.desc_i18n_key, p.description, p) }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tw-pd-y-05 tw-pd-x-05 tw-align-right">
<button class="tw-button tw-button--text" @click="openConfigure">
<span class="tw-button__text ffz-i-cog">
{{ t('setting.profiles.configure', 'Configure') }}
</span>
</button>
<div class="tw-pd-y-05 tw-pd-x-05 tw-align-right">
<button class="tw-button tw-button--text" @click="openConfigure">
<span class="tw-button__text ffz-i-cog">
{{ t('setting.profiles.configure', 'Configure') }}
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>

View file

@ -1,43 +1,46 @@
<template lang="html">
<div class="ffz--widget ffz--checkbox" :class="{inherits: isInherited, default: isDefault}">
<div class="tw-flex tw-align-items-center">
<input
type="checkbox"
class="tw-checkbox__input"
ref="control"
:id="item.full_key"
:checked="value"
@change="onChange"
<div
:class="{inherits: isInherited, default: isDefault}"
class="ffz--widget ffz--checkbox"
>
<div class="tw-flex tw-align-items-center">
<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">
{{ t(item.i18n_key, item.title, item) }}
</label>
<label :for="item.full_key" class="tw-checkbox__label">
{{ t(item.i18n_key, item.title, item) }}
</label>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</button>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</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>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<section
v-if="item.description"
class="tw-c-text-alt-2"
style="padding-left:2.2rem"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
<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" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<section
v-if="item.description"
class="tw-c-text-alt-2"
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,31 +1,31 @@
<template lang="html">
<div class="ffz--widget ffz--hotkey-input">
<label
:for="item.full_key"
v-html="t(item.i18n_key, item.title, item)"
<div class="ffz--widget ffz--hotkey-input">
<label
:for="item.full_key"
v-html="t(item.i18n_key, item.title, item)"
/>
<div class="tw-relative">
<div class="tw-input__icon-group tw-input__icon-group--right">
<div class="tw-input__icon">
<figure class="ffz-i-keyboard" />
<div class="tw-relative">
<div class="tw-input__icon-group tw-input__icon-group--right">
<div class="tw-input__icon">
<figure class="ffz-i-keyboard" />
</div>
</div>
<div
ref="display"
:id="item.full_key"
type="text"
class="tw-mg-05 tw-input tw-input--icon-right"
tabindex="0"
@keyup="onKey"
>
&nbsp;
</div>
</div>
<div
type="text"
class="tw-mg-05 tw-input tw-input--icon-right"
ref="display"
:id="item.full_key"
tabindex="0"
@keyup="onKey"
>
&nbsp;
</div>
</div>
<section
v-if="item.description"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
<section
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,27 +1,36 @@
<template lang="html">
<div class="tw-input">
<header>
{{ t(item.i18n_key, item.title, item) }}
</header>
<section
v-if="item.description"
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
<div class="tw-input">
<header>
{{ t(item.i18n_key, item.title, item) }}
</header>
<section
v-if="item.description"
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,49 +1,55 @@
<template lang="html">
<div class="ffz--widget ffz--select-box" :class="{inherits: isInherited, default: isDefault}">
<div class="tw-flex tw-align-items-center">
<label :for="item.full_key">
{{ t(item.i18n_key, item.title, item) }}
</label>
<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"
@change="onChange"
>
<option v-for="i in data" :selected="i.value === value">
{{ i.i18n_key ? t(i.i18n_key, i.title, i) : i.title }}
</option>
</select>
<select
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"
:key="i.value"
:selected="i.value === value"
>
{{ i.i18n_key ? t(i.i18n_key, i.title, i) : i.title }}
</option>
</select>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</button>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</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>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<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" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<section
v-if="item.description"
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
<section
v-if="item.description"
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,46 +1,48 @@
<template lang="html">
<div class="ffz--widget ffz--text-box" :class="{inherits: isInherited, default: isDefault}">
<div class="tw-flex tw-align-items-center">
<label :for="item.full_key">
{{ t(item.i18n_key, item.title, item) }}
</label>
<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"
/>
<input
ref="control"
:id="item.full_key"
:value="value"
class="tw-mg-05 tw-input tw-display-inline tw-width-auto"
@change="onChange"
>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</button>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"
@click="context.currentProfile = source"
>
<span class="tw-button__text ffz-i-right-dir">
{{ sourceDisplay }}
</span>
</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>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<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" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
<section
v-if="item.description"
class="tw-c-text-alt-2"
v-html="t(item.desc_i18n_key || item.i18n_key + '.description', item.description, item)"
<section
v-if="item.description"
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,154 +1,193 @@
<template lang="html">
<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"
v-show="activeTab === 'auto-host'"
:class="{ active: activeTab === 'auto-host'}">
<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: '.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">
<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>
<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>
<button class="tw-button-icon tw-mg-x-05 ffz--host-remove-user" @click="removeFromHosts">
<figure class="ffz-i-trash"></figure>
</button>
</div>
</div>
</div>
</draggable>
</div>
</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">
<span class="tw-button__text">{{ t('metadata.host.add-channel', 'Add To Auto Host') }}</span>
</button>
<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>
<div class="tab tw-overflow-hidden"
v-show="activeTab === 'settings'"
:class="{ active: activeTab === 'settings'}">
<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">
<div class="simplebar-content">
<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"
id="autoHostSettings:enabled"
data-setting="enabled"
:checked="autoHostSettings.enabled"
@change="updateCheckbox">
<label for="autoHostSettings:enabled" class="tw-checkbox__label">
{{ t('metadata.host.setting.auto-hosting.title', 'Auto Hosting') }}
</label>
<div
v-show="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"
:options="{
draggable: '.ffz--host-user',
animation: 150,
}"
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" />
<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" />
<button class="tw-button-icon tw-mg-x-05 ffz--host-remove-user" @click="removeFromHosts">
<figure class="ffz-i-trash" />
</button>
</div>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.auto-hosting.description', 'Toggle all forms of auto hosting: teammates, host list, and similar channels.') }}<br>
<a href="https://blog.twitch.tv/grow-your-community-with-auto-hosting-e80c1460f6e1" target="_blank" rel="noopener">{{ t('metadata.host.setting.auto-hosting.link', 'Learn More') }}</a>
</section>
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
id="autoHostSettings:team_host"
data-setting="team_host"
:checked="autoHostSettings.team_host"
@change="updateCheckbox">
<label for="autoHostSettings:team_host" class="tw-checkbox__label">
{{ t('metadata.host.setting.team-hosting.title', 'Team Hosting') }}
</label>
</draggable>
</div>
</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" />
<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
v-show="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">
<div class="simplebar-content">
<div class="tw-pd-1">
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input
id="autoHostSettings:enabled"
:checked="autoHostSettings.enabled"
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>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.auto-hosting.description', 'Toggle all forms of auto hosting: teammates, host list, and similar channels.') }}<br>
<a href="https://blog.twitch.tv/grow-your-community-with-auto-hosting-e80c1460f6e1" target="_blank" rel="noopener">{{ t('metadata.host.setting.auto-hosting.link', 'Learn More') }}</a>
</section>
</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. ' +
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input
id="autoHostSettings:team_host"
:checked="autoHostSettings.team_host"
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. " +
'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"
id="autoHostSettings:vodcast_hosting"
data-setting="deprioritize_vodcast"
:checked="!autoHostSettings.deprioritize_vodcast"
@change="updateCheckbox">
<label for="autoHostSettings:vodcast_hosting" class="tw-checkbox__label">
{{ t('metadata.host.setting.vodcast-hosting.title', 'Vodcast Hosting') }}
</label>
</section>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.vodcast-hosting.description', 'Include Vodcasts in auto host.') }}
<a href="https://blog.twitch.tv/vodcast-brings-the-twitch-community-experience-to-uploads-54098498715" target="_blank" rel="noopener">{{ t('metadata.host.setting.vodcast-hosting.link', 'Learn about Vodcasts') }}</a>
</section>
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
id="autoHostSettings:recommended_host"
data-setting="recommended_host"
:checked="autoHostSettings.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>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input
id="autoHostSettings:vodcast_hosting"
:checked="!autoHostSettings.deprioritize_vodcast"
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>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.vodcast-hosting.description', 'Include Vodcasts in auto host.') }}
<a href="https://blog.twitch.tv/vodcast-brings-the-twitch-community-experience-to-uploads-54098498715" target="_blank" rel="noopener">{{ t('metadata.host.setting.vodcast-hosting.link', 'Learn about Vodcasts') }}</a>
</section>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.recommended-hosting.description', 'Streamers on your primary team &amp; host list will always be hosted first') }}
</section>
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input type="checkbox" class="tw-checkbox__input"
id="autoHostSettings:strategy"
data-setting="strategy"
:checked="autoHostSettings.strategy === 'random'"
@change="updateCheckbox">
<label for="autoHostSettings:strategy" class="tw-checkbox__label">
{{ t('metadata.host.setting.strategy.title', 'Randomize Host Order') }}
</label>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input
id="autoHostSettings:recommended_host"
:checked="autoHostSettings.recommended_host"
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>
</div>
<section class="tw-c-text-alt-2 ffz-checkbox-description">
{{ t('metadata.host.setting.recommended-hosting.description', 'Streamers on your primary team &amp; host list will always be hosted first') }}
</section>
</div>
<div class="ffz--widget ffz--checkbox">
<div class="tw-flex tw-align-items-center">
<input
id="autoHostSettings:strategy"
:checked="autoHostSettings.strategy === 'random'"
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>
</div>
<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.") }}
</section>
</div>
<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.') }}
</section>
</div>
</div>
</div>
</div>
</main>
</section>
</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"
@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"
@click="setActiveTab('settings')"
:class="{active: activeTab === 'settings'}">
<span>{{ t('metadata.host.tab.settings', 'Settings') }}</span>
</div>
</main>
</section>
</div>
</footer>
</div>
<footer>
<div class="host-options__tabs-container tw-border-t">
<div
id="host-options__auto-host"
:class="{active: activeTab === 'auto-host'}"
class="host-options__tab tw-pd-x-1"
@click="setActiveTab('auto-host')"
>
<span>{{ t('metadata.host.tab.auto-host', 'Auto Host') }}</span>
</div>
<div
id="host-options__settings"
:class="{active: activeTab === 'settings'}"
class="host-options__tab tw-pd-x-1"
@click="setActiveTab('settings')"
>
<span>{{ t('metadata.host.tab.settings', 'Settings') }}</span>
</div>
</div>
</footer>
</div>
</template>
@ -160,7 +199,7 @@ export default {
draggable
},
data() {
data() {
return this.$vnode.data;
},

View file

@ -1,58 +1,59 @@
<template lang="html">
<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"
role="tablist"
@keyup.home="firstTab"
@keyup.end="lastTab"
@keyup.page-up="prevTab"
@keyup.up="prevTab"
@keyup.left="prevTab"
@keyup.page-down="nextTab"
@keyup.right="nextTab"
@keyup.down="nextTab"
<div
v-if="item.tabs"
class="ffz--tab-container"
@keyup.alt.page-up.stop="focusPrevTab"
@keyup.alt.page-down.stop="focusNextTab"
>
<div
v-for="(i, idx) in item.tabs"
role="tab"
: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' : '']"
@click="selected = idx"
<header
class="tw-flex"
tabindex="0"
role="tablist"
@keyup.home="firstTab"
@keyup.end="lastTab"
@keyup.page-up="prevTab"
@keyup.up="prevTab"
@keyup.left="prevTab"
@keyup.page-down="nextTab"
@keyup.right="nextTab"
@keyup.down="nextTab"
>
{{ 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"
role="tabpanel"
aria-hidden="false"
aria-expanded="true"
>
<section v-if="tab.description" class="tw-pd-b-1">
{{ t(tab.desc_i18n_key, tab.description, tab) }}
</section>
<component
v-for="i in tab.contents"
v-bind:is="i.component"
:currentProfile="currentProfile"
:profiles="profiles"
:context="context"
:item="i"
:key="i.full_key"
<div
v-for="(i, idx) in item.tabs"
:key="i.full_key"
:id="'tab-for-' + i.full_key"
:aria-selected="selected === idx"
:aria-controls="'tab-panel-' + i.full_key"
: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
:id="'tab-panel-' + tab.full_key"
:aria-labelledby="'tab-for-' + tab.full_key"
class="tw-border"
role="tabpanel"
aria-hidden="false"
aria-expanded="true"
>
<section v-if="tab.description" class="tw-pd-b-1">
{{ t(tab.desc_i18n_key, tab.description, tab) }}
</section>
<component
v-for="i in tab.contents"
:is="i.component"
:current-profile="currentProfile"
:profiles="profiles"
:context="context"
:item="i"
:key="i.full_key"
/>
</section>
</div>
</section>
</div>
</template>
<script>