1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-05 10:38:30 +00:00

4.0.0-rc8.6

* Fixed: Update Fine to deal with changes to how the React Root is stored in the DOM.

Behind the Scenes

* Working on the UI for Translation Editing
* Refactor some of the main menu dialog logic into a more generic Dialog class
This commit is contained in:
SirStendec 2018-07-24 16:11:02 -04:00
parent 154a587c87
commit b8f86fe48f
14 changed files with 570 additions and 180 deletions

View file

@ -10,9 +10,10 @@
"dev": "webpack-dev-server --config webpack.web.dev.js", "dev": "webpack-dev-server --config webpack.web.dev.js",
"dev:clips": "webpack-dev-server --config webpack.clips.dev.js", "dev:clips": "webpack-dev-server --config webpack.clips.dev.js",
"dev:babel": "webpack-dev-server --config webpack.web.dev.babel.js", "dev:babel": "webpack-dev-server --config webpack.web.dev.babel.js",
"build:all": "npm run build && npm run build:babel && npm run build:clips && npm run build:clips:babel", "build:all": "npm run build && npm run build:clips",
"build": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production'", "build": "npm run build:prod && npm run build:babel",
"build:clips": "webpack --config webpack.clips.prod.js --define process.env.NODE_ENV='production'", "build:clips": "npm run build:clips:prod && npm run build:clips:babel",
"build:clips:prod": "webpack --config webpack.clips.prod.js --define process.env.NODE_ENV='production'",
"build:clips:babel": "webpack --config webpack.clips.babel.js --define process.env.NODE_ENV='production'", "build:clips:babel": "webpack --config webpack.clips.babel.js --define process.env.NODE_ENV='production'",
"build:stats": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production' --json > stats.json", "build:stats": "webpack --config webpack.web.prod.js --define process.env.NODE_ENV='production' --json > stats.json",
"build:babel": "webpack --config webpack.web.babel.js --define process.env.NODE_ENV='production'", "build:babel": "webpack --config webpack.web.babel.js --define process.env.NODE_ENV='production'",

View file

@ -7,7 +7,7 @@
// ============================================================================ // ============================================================================
import {SERVER} from 'utilities/constants'; import {SERVER} from 'utilities/constants';
import {get, pick_random, has} from 'utilities/object'; import {get, pick_random, has, timeout} from 'utilities/object';
import Module from 'utilities/module'; import Module from 'utilities/module';
@ -69,6 +69,8 @@ export class TranslationManager extends Module {
super(...args); super(...args);
this.inject('settings'); this.inject('settings');
this._seen = new Set;
this.availableLocales = ['en']; //, 'de', 'ja']; this.availableLocales = ['en']; //, 'de', 'ja'];
this.localeData = { this.localeData = {
@ -141,6 +143,12 @@ export class TranslationManager extends Module {
} }
}); });
if ( window.BroadcastChannel ) {
const bc = this._broadcaster = new BroadcastChannel('ffz-i18n');
bc.addEventListener('message',
this._boundHandleMessage = this.handleMessage.bind(this));
}
this._.transformation = TRANSFORMATIONS[this.settings.get('i18n.debug.transform')]; this._.transformation = TRANSFORMATIONS[this.settings.get('i18n.debug.transform')];
this.locale = this.settings.get('i18n.locale'); this.locale = this.settings.get('i18n.locale');
} }
@ -154,6 +162,55 @@ export class TranslationManager extends Module {
} }
handleMessage(event) {
const msg = event.data;
if ( msg.type === 'seen' )
this.see(msg.key, true);
else if ( msg.type === 'request-keys' ) {
this.broadcast({type: 'keys', keys: Array.from(this._seen)})
}
else if ( msg.type === 'keys' )
this.emit(':receive-keys', msg.keys);
}
async getKeys() {
this.broadcast({type: 'request-keys'});
let data;
try {
data = await timeout(this.waitFor(':receive-keys'), 100);
} catch(err) { /* no-op */ }
if ( data )
for(const val of data)
this._seen.add(val);
return this._seen;
}
broadcast(msg) {
if ( this._broadcaster )
this._broadcaster.postMessage(msg)
}
see(key, from_broadcast = false) {
if ( this._seen.has(key) )
return;
this._seen.add(key);
this.emit(':seen', key);
if ( ! from_broadcast )
this.broadcast({type: 'seen', key});
}
toLocaleString(thing) { toLocaleString(thing) {
if ( thing && thing.toLocaleString ) if ( thing && thing.toLocaleString )
return thing.toLocaleString(this._.locale); return thing.toLocaleString(this._.locale);
@ -363,12 +420,14 @@ export class TranslationManager extends Module {
return this._.formatNumber(...args); return this._.formatNumber(...args);
} }
t(...args) { t(key, ...args) {
return this._.t(...args); this.see(key);
return this._.t(key, ...args);
} }
tList(...args) { tList(key, ...args) {
return this._.tList(...args); this.see(key);
return this._.tList(key, ...args);
} }
} }

View file

@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
FrankerFaceZ.Logger = Logger; FrankerFaceZ.Logger = Logger;
const VER = FrankerFaceZ.version_info = { const VER = FrankerFaceZ.version_info = {
major: 4, minor: 0, revision: 0, extra: '-rc8.5', major: 4, minor: 0, revision: 0, extra: '-rc8.6',
commit: __git_commit__, commit: __git_commit__,
build: __webpack_hash__, build: __webpack_hash__,
toString: () => toString: () =>

View file

@ -1,7 +1,7 @@
<template lang="html"> <template lang="html">
<div <div
:class="{ maximized: maximized || exclusive, exclusive, faded }" :class="{ maximized: maximized || exclusive, exclusive, faded }"
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="ffz-dialog 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"> <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> <h3 class="ffz-i-zreknarf ffz-i-pd-1">FrankerFaceZ</h3>

View file

@ -8,11 +8,9 @@ import Module from 'utilities/module';
import {createElement} from 'utilities/dom'; import {createElement} from 'utilities/dom';
import {has, deep_copy} from 'utilities/object'; import {has, deep_copy} from 'utilities/object';
import {parse_path} from 'src/settings'; import Dialog from 'utilities/dialog';
const EXCLUSIVE_SELECTOR = '.twilight-main,.twilight-minimal-root>div,.twilight-root>.tw-full-height,.clips-root', import {parse_path} from 'src/settings';
MAXIMIZED_SELECTOR = '.twilight-main,.twilight-minimal-root,.twilight-root .dashboard-side-nav+.tw-full-height,.clips-root>.tw-full-height .scrollable-area',
SELECTOR = '.twilight-root>.tw-full-height,.twilight-minimal-root>.tw-full-height,.clips-root>.tw-full-height .scrollable-area';
function format_term(term) { function format_term(term) {
return term.replace(/<[^>]*>/g, '').toLocaleLowerCase(); return term.replace(/<[^>]*>/g, '').toLocaleLowerCase();
@ -37,10 +35,7 @@ export default class MainMenu extends Module {
this._settings_tree = null; this._settings_tree = null;
this._settings_count = 0; this._settings_count = 0;
this._menu = null; this.dialog = new Dialog(() => this.buildDialog());
this._visible = true;
this._maximized = false;
this.exclusive = false;
this.has_update = false; this.has_update = false;
this.settings.addUI('profiles', { this.settings.addUI('profiles', {
@ -101,109 +96,43 @@ export default class MainMenu extends Module {
); );
} }
get maximized() {
return this._maximized;
}
set maximized(val) { async onEnable() {
val = Boolean(val); await this.site.awaitElement(Dialog.EXCLUSIVE);
if ( val === this._maximized )
return;
if ( this.enabled ) this.dialog.on('hide', this.destroyDialog, this);
this.toggleSize(); this.dialog.on('resize', () => {
} if ( this._vue )
this._vue.$children[0].maximized = this.dialog.maximized
});
get visible() { this.on('site.menu_button:clicked', this.dialog.toggleVisible, this.dialog);
return this._visible; this.dialog.show();
}
set visible(val) {
val = Boolean(val);
if ( val === this._visible )
return;
if ( this.enabled )
this.toggleVisible();
}
async onEnable(event) {
await this.site.awaitElement(EXCLUSIVE_SELECTOR);
this.on('site.menu_button:clicked', this.toggleVisible);
if ( this._visible ) {
this._visible = false;
this.toggleVisible(event);
}
} }
onDisable() { onDisable() {
if ( this._visible ) { this.dialog.hide();
this.toggleVisible(); this.off('site.menu_button:clicked', this.dialog.toggleVisible, this.dialog);
this._visible = true;
}
this.off('site.menu_button:clicked', this.toggleVisible);
} }
getContainer() {
if ( this.exclusive )
return document.querySelector(EXCLUSIVE_SELECTOR);
if ( this._maximized ) buildDialog() {
return document.querySelector(MAXIMIZED_SELECTOR); if ( this._menu )
return this._menu;
return document.querySelector(SELECTOR); this._vue = new this.vue.Vue({
el: createElement('div'),
render: h => h('main-menu', this.getData())
});
return this._menu = this._vue.$el;
} }
toggleVisible(event) { destroyDialog() {
if ( event && event.button !== 0 ) if ( this._vue )
return; this._vue.$destroy();
const maximized = this._maximized, this._menu = this._vue = null;
visible = this._visible = !this._visible,
main = this.getContainer();
if ( ! visible ) {
if ( maximized )
main.classList.remove('ffz-has-menu');
if ( this._menu ) {
this._menu.remove();
this._vue.$destroy();
this._menu = this._vue = null;
}
return;
}
if ( ! this._menu )
this.createMenu();
if ( maximized )
main.classList.add('ffz-has-menu');
main.appendChild(this._menu);
}
toggleSize(event) {
if ( ! this._visible || event && event.button !== 0 )
return;
const maximized = this._maximized = !this._maximized,
main = this.getContainer(),
old_main = this._menu.parentElement;
if ( maximized )
main.classList.add('ffz-has-menu');
else
old_main.classList.remove('ffz-has-menu');
this._menu.remove();
main.appendChild(this._menu);
this._vue.$children[0].maximized = maximized;
} }
@ -588,32 +517,22 @@ export default class MainMenu extends Module {
settings.keys['home'], // settings[0], settings.keys['home'], // settings[0],
nav_keys: settings.keys, nav_keys: settings.keys,
maximized: this._maximized, maximized: this.dialog.maximized,
resize: e => !this.exclusive && this.toggleSize(e), exclusive: this.dialog.exclusive,
close: e => !this.exclusive && this.toggleVisible(e),
resize: e => ! this.dialog.exclusive && this.dialog.toggleSize(e),
close: e => ! this.dialog.exclusive && this.dialog.toggleVisible(e),
popout: e => { popout: e => {
if ( this.exclusive ) if ( this.dialog.exclusive )
return; return;
this.toggleVisible(e); this.dialog.toggleVisible(e);
if ( ! this.openPopout() ) if ( ! this.openPopout() )
alert(this.i18n.t('popup.error', 'We tried opening a pop-up window and could not. Make sure to allow pop-ups from Twitch.')); alert(this.i18n.t('popup.error', 'We tried opening a pop-up window and could not. Make sure to allow pop-ups from Twitch.')); // eslint-disable-line no-alert
}, },
version: window.FrankerFaceZ.version_info,
exclusive: this.exclusive version: window.FrankerFaceZ.version_info,
} }
} }
createMenu() {
if ( this._menu )
return;
this._vue = new this.vue.Vue({
el: createElement('div'),
render: h => h('main-menu', this.getData())
});
this._menu = this._vue.$el;
}
} }

View file

@ -0,0 +1,130 @@
<template lang="html">
<div
:class="{ maximized: maximized || exclusive, exclusive, faded }"
class="ffz-dialog 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">{{ t('i18n.ui.title', 'Translation Editor') }}</h3>
<div class="tw-flex-grow-1 tw-pd-x-2">
<div class="tw-search-input">
<label for="ffz-main-menu.search" class="tw-hide-accessible">{{ t('i18n.ui.search', 'Search Strings') }}</label>
<div class="tw-relative">
<div class="tw-absolute tw-align-items-center tw-c-text-alt-2 tw-flex tw-full-height tw-input__icon tw-justify-content-center tw-left-0 tw-top-0 tw-z-default">
<figure class="ffz-i-search" />
</div>
<input
id="ffz-main-menu.search"
v-model="query"
:placeholder="t('i18n.ui.search', 'Search Strings')"
type="search"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-l-3 tw-pd-r-1 tw-pd-y-05"
autocapitalize="off"
autocorrect="off"
autocomplete="off"
spellcheck="false"
>
</div>
</div>
</div>
<button v-if="!maximized && !exclusive" class="tw-button-icon tw-mg-x-05" @click="faded = ! faded">
<span class="tw-button-icon__icon">
<figure :class="faded ? 'ffz-i-eye-off' : 'ffz-i-eye'" />
</span>
</button>
<button v-if="!exclusive" class="tw-button-icon tw-mg-x-05 tw-tooltip-wrapper" @click="popout">
<span class="tw-button-icon__icon">
<figure class="ffz-i-link-ext" />
</span>
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-center">
{{ t('i18n.ui.popout', 'Open the Translation Editor in a New Window') }}
</div>
</button>
<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">
<div v-for="(key, idx) of phrases" :key="idx" class="tw-block tw-mg-1">
{{ key }}
</div>
</section>
</div>
</template>
<script>
import displace from 'displacejs';
export default {
data() {
return this.$vnode.data;
},
computed: {
filter() {
return this.query.toLowerCase()
}
},
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;
}
},
methods: {
updateDrag() {
if ( this.maximized )
this.destroyDrag();
else
this.createDrag();
},
destroyDrag() {
if ( this.displace ) {
this.displace.destroy();
this.displace = null;
}
},
createDrag() {
this.$nextTick(() => {
if ( ! this.maximized )
this.displace = displace(this.$el, {
handle: this.$el.querySelector('header'),
highlightInputs: true,
constrain: true
});
})
},
handleResize() {
if ( this.displace )
this.displace.reinit();
},
}
}
</script>

View file

@ -0,0 +1,118 @@
'use strict';
// ============================================================================
// Translation UI
// ============================================================================
import Module from 'utilities/module';
import Dialog from 'utilities/dialog';
import {createElement} from 'utilities/dom';
export default class TranslationUI extends Module {
constructor(...args) {
super(...args);
this.inject('settings');
this.inject('i18n');
this.inject('site');
this.inject('vue');
this.load_requires = ['vue'];
this.dialog = new Dialog(() => this.buildDialog());
}
openPopout() {
const win = window.open(
'https://twitch.tv/popout/frankerfacez/chat?ffz-translate',
'_blank',
'resizable=yes,scrollbars=yes,width=850,height=600'
);
if ( win ) {
win.focus();
return true;
} else {
this.log.warn('Unable to open popout translation window.');
return false;
}
}
async onLoad() {
this.vue.component(
(await import(/* webpackChunkName: "translation-ui" */ './components.js')).default
);
}
async onEnable() {
await this.site.awaitElement(Dialog.EXCLUSIVE);
this.on('i18n:seen', key => {
if ( ! this._vue )
return;
const comp = this._vue.$children[0];
comp.phrases.push(key);
})
this.dialog.on('hide', this.destroyDialog, this);
this.dialog.on('resize', () => {
if ( this._vue )
this._vue.$children[0].maximized = this.dialog.maximized
});
this.dialog.show();
}
onDisable() {
this.dialog.hide();
}
async buildDialog() {
if ( this._dialog )
return this._dialog;
const data = await this.getData();
this._vue = new this.vue.Vue({
el: createElement('div'),
render: h => h('translation-ui', data)
});
return this._dialog = this._vue.$el;
}
destroyDialog() {
if ( this._vue )
this._vue.$destroy();
this._dialog = this._vue = null;
}
async getData() {
return {
query: '',
faded: false,
maximized: this.dialog.maximized,
exclusive: this.dialog.exclusive,
phrases: Array.from(await this.i18n.getKeys()),
resize: e => ! this.dialog.exclusive && this.dialog.toggleSize(e),
close: e => ! this.dialog.exclusive && this.dialog.toggleVisible(e),
popout: e => {
if ( this.dialog.exclusive )
return;
this.dialog.toggleVisible(e);
if ( ! this.openPopout() )
alert(this.i18n.t('popup.error', 'We tried opening a pop-up window and could not. Make sure to allow pop-ups from Twitch.')); // eslint-disable-line no-alert
}
}
}
}

View file

@ -1,42 +0,0 @@
'use strict';
// ============================================================================
// Translation UI
// ============================================================================
import Module from 'utilities/module';
//import {createElement} from 'utilities/dom';
export default class TranslationUI extends Module {
constructor(...args) {
super(...args);
this.inject('settings');
this.inject('site');
this.inject('vue');
//this.should_enable = true;
this._dialog = null;
this._visible = true;
}
async onLoad() {
this.vue.component(
(await import(/* webpackChunkName: "translation-ui" */ './components.js')).default
);
}
async onEnable() {
await this.site.awaitElement('.twilight-root');
this.ps = this.site.web_munch.getModule('ps');
}
onDisable() {
if ( this._visible ) {
this.toggleVisible();
this._visible = true;
}
}
}

View file

@ -87,3 +87,8 @@ export default class Clippy extends BaseSite {
return this._user = session && session.user; return this._user = session && session.user;
} }
} }
Clippy.DIALOG_EXCLUSIVE = '.clips-root';
Clippy.DIALOG_MAXIMIZED = '.clips-root>.tw-full-height .scrollable-area';
Clippy.DIALOG_SELECTOR = '.clips-root>.tw-full-height .scrollable-area';

View file

@ -78,10 +78,18 @@ export default class Twilight extends BaseSite {
// Check for ?ffz-settings in page and open the // Check for ?ffz-settings in page and open the
// settings window in exclusive mode. // settings window in exclusive mode.
const params = new URL(window.location).searchParams; const params = new URL(window.location).searchParams;
if (params && params.has('ffz-settings')) { if ( params ) {
const main_menu = this.resolve('main_menu'); if ( params.has('ffz-settings') ) {
main_menu.exclusive = true; const main_menu = this.resolve('main_menu');
main_menu.enable(); main_menu.dialog.exclusive = true;
main_menu.enable();
}
if ( params.has('ffz-translate') ) {
const translation = this.resolve('translation_ui');
translation.dialog.exclusive = true;
translation.enable();
}
} }
} }
@ -183,3 +191,8 @@ Twilight.ROUTES = {
'prime': '/prime', 'prime': '/prime',
'user': '/:userName' 'user': '/:userName'
} }
Twilight.DIALOG_EXCLUSIVE = '.twilight-main,.twilight-minimal-root>div,.twilight-root>.tw-full-height,.clips-root';
Twilight.DIALOG_MAXIMIZED = '.twilight-main,.twilight-minimal-root,.twilight-root .dashboard-side-nav+.tw-full-height,.clips-root>.tw-full-height .scrollable-area';
Twilight.DIALOG_SELECTOR = '.twilight-root>.tw-full-height,.twilight-minimal-root>.tw-full-height,.clips-root>.tw-full-height .scrollable-area';

View file

@ -34,6 +34,9 @@ export default class Fine extends Module {
} }
this.react_root = this.root_element._reactRootContainer; this.react_root = this.root_element._reactRootContainer;
if ( this.react_root._internalRoot && this.react_root._internalRoot.current )
this.react_root = this.react_root._internalRoot;
this.react = this.react_root.current.child; this.react = this.react_root.current.child;
} }
@ -59,7 +62,7 @@ export default class Fine extends Module {
if ( ! this.accessor ) if ( ! this.accessor )
return; return;
return element[this.accessor] || (element._reactRootContainer && element._reactRootContainer.current); return element[this.accessor] || (element._reactRootContainer && element._reactRootContainer._internalRoot && element._reactRootContainer._internalRoot.current) || (element._reactRootContainer && element._reactRootContainer.current);
} }
getOwner(instance) { getOwner(instance) {

184
src/utilities/dialog.js Normal file
View file

@ -0,0 +1,184 @@
'use strict';
// ============================================================================
// Dialog for Vue
// ============================================================================
import {EventEmitter} from 'utilities/events';
import Site from 'site';
export default class Dialog extends EventEmitter {
constructor(element) {
super();
this._element = null;
if ( typeof element === 'function' )
this.factory = element;
else
this.element = element;
this._visible = false;
this._maximized = false;
this._exclusive = false;
}
// ========================================================================
// Properties and Utility Methods
// ========================================================================
get maximized() {
return this._exclusive || this._maximized;
}
set maximized(val) {
val = Boolean(val);
if ( val === this._maximized )
return;
if ( this._visible )
this.toggleSize();
}
get visible() {
return this._visible;
}
set visible(val) {
val = Boolean(val);
if ( val === this._visible )
return;
this.toggleVisible();
}
get exclusive() {
return this._exclusive;
}
set exclusive(val) {
if ( this._visible )
throw new Error('cannot set exclusive flag when dialog already visible');
this._exclusive = val;
}
get element() {
return this._element;
}
set element(val) {
if ( this._visible )
throw new Error('cannot change element when dialog already visible');
if ( !(val instanceof Node) )
throw new Error('element must be an instance of Node');
this._element = val;
}
show() {
this.visible = true;
}
hide() {
this.visible = false;
}
maximize() {
this.maximized = true;
}
restore() {
this.maximized = false;
}
// ========================================================================
// Element Logic
// ========================================================================
getContainer() {
return document.querySelector(
this._exclusive ? Dialog.EXCLUSIVE :
this._maximized ? Dialog.MAXIMIZED :
Dialog.SELECTOR
);
}
toggleVisible(event) {
if ( event && event.button !== 0 )
return;
const maximized = this.maximized,
visible = this._visible = ! this._visible,
container = this.getContainer();
if ( maximized )
container.classList.toggle('ffz-has-dialog', visible);
if ( ! visible ) {
this._element.remove();
this.emit('hide');
if ( this.factory )
this._element = null;
return;
}
if ( this.factory ) {
const el = this.factory();
if ( el instanceof Promise ) {
el.then(e => {
this._element = e;
container.appendChild(e);
this.emit('show');
}).catch(err => {
this.emit('error', err);
});
return;
} else
this._element = el;
}
container.appendChild(this._element);
this.emit('show');
}
toggleSize(event) {
if ( ! this._visible || event && event.button !== 0 )
return;
this._maximized = !this._maximized;
const maximized = this.maximized,
container = this.getContainer(),
old_container = this._element.parentElement;
if ( container === old_container )
return;
if ( maximized )
container.classList.add('ffz-has-dialog');
else
old_container.classList.remove('ffz-has-dialog');
this._element.remove();
container.appendChild(this._element);
this.emit('resize');
}
}
Dialog.lastZ = 99999999;
Dialog.EXCLUSIVE = Site.DIALOG_EXCLUSIVE;
Dialog.MAXIMIZED = Site.DIALOG_MAXIMIZED;
Dialog.SELECTOR = Site.DIALOG_SELECTOR;

View file

@ -1,4 +1,4 @@
.ffz-main-menu { .ffz-dialog {
&:not(.maximized) { &:not(.maximized) {
position: absolute; position: absolute;
top: 25%; top: 25%;
@ -62,6 +62,6 @@
} }
.ffz-has-menu > :not(.ffz-main-menu) { .ffz-has-dialog > :not(.ffz-dialog) {
visibility: hidden; visibility: hidden;
} }

View file

@ -1,7 +1,7 @@
@import 'icons'; @import 'icons';
@import 'tooltips'; @import 'tooltips';
@import 'widgets'; @import 'widgets';
@import 'main_menu'; @import 'dialog';
@import 'chat'; @import 'chat';