+let id = 0;
+
import {escape_regex, deep_copy} from 'utilities/object';
import {load, ICONS as FA_ICONS, ALIASES as FA_ALIASES} from 'utilities/font-awesome';
const FFZ_ICONS = [
+ 'cancel',
'zreknarf',
- 'crown',
- 'verified',
- 'inventory',
- 'ignore',
- 'pin-outline',
- 'pin',
- 'block',
- 'ok',
+ 'search',
'clock',
- 'eye',
- 'eye-off',
- 'trash',
- 'discord',
'star',
'star-empty',
- 'twitch',
- 'twitter',
+ 'down-dir',
+ 'right-dir',
+ 'attention',
+ 'ok',
+ 'cog',
+ 'plus',
+ 'folder-open',
'download',
'upload',
- 'download-cloud',
- 'upload-cloud',
+ 'floppy',
+ 'crown',
+ 'verified',
+ 'heart',
+ 'heart-empty',
'tag',
'tags',
'retweet',
'thumbs-up',
'thumbs-down',
'bell',
- 'bell-off',
'pencil',
'info',
'help',
'calendar',
+ 'left-dir',
+ 'inventory',
'lock',
'lock-open',
'arrows-cw',
+ 'ignore',
+ 'block',
+ 'pin',
+ 'pin-outline',
'gift',
- 'eyedropper',
+ 'discord',
+ 'eye',
+ 'eye-off',
+ 'views',
+ 'conversations',
+ 'channels',
+ 'camera',
+ 'cw',
+ 'up-dir',
+ 'up-big',
+ 'link-ext',
+ 'twitter',
'github',
- 'user-secret'
+ 'gauge',
+ 'download-cloud',
+ 'upload-cloud',
+ 'smile',
+ 'keyboard',
+ 'calendar-empty',
+ 'ellipsis-vert',
+ 'twitch',
+ 'bell-off',
+ 'trash',
+ 'eyedropper',
+ 'user-secret',
+ 'window-maximize',
+ 'window-minimize',
+ 'window-restore',
+ 'window-close'
];
const FFZ_ALIASES = {
@@ -112,6 +144,7 @@ export default {
data() {
return {
+ id: id++,
search: '',
icons: deep_copy(ICONS)
}
@@ -131,11 +164,19 @@ export default {
mounted() {
load();
+
+ this.$nextTick(() => {
+ if ( this.value ) {
+ const el = this.$el.querySelector('.tw-interactable--selected');
+ if ( el )
+ el.scrollIntoViewIfNeeded();
+ }
+ });
},
methods: {
change(val) {
- this.value.icon = val;
+ this.value = val;
this.$emit('input', this.value);
}
}
diff --git a/src/std-components/react-link.vue b/src/std-components/react-link.vue
index 607cb475..d37b54c3 100644
--- a/src/std-components/react-link.vue
+++ b/src/std-components/react-link.vue
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,17 @@
\ No newline at end of file
diff --git a/src/utilities/font-awesome.js b/src/utilities/font-awesome.js
index 79bcab66..3fddecb9 100644
--- a/src/utilities/font-awesome.js
+++ b/src/utilities/font-awesome.js
@@ -237,3 +237,9 @@ export const load = () => {
}));
}
+export const maybeLoad = icon => {
+ if ( loaded || ! String(icon).startsWith('fa-') && ! String(icon).startsWith('ffz-fa') )
+ return;
+
+ load();
+}
\ No newline at end of file
diff --git a/src/utilities/object.js b/src/utilities/object.js
index aeafd272..7b0f0413 100644
--- a/src/utilities/object.js
+++ b/src/utilities/object.js
@@ -2,6 +2,28 @@
const HOP = Object.prototype.hasOwnProperty;
+// Source: https://gist.github.com/jed/982883 (WTFPL)
+export function generateUUID(input) {
+ return input // if the placeholder was passed, return
+ ? ( // a random number from 0 to 15
+ input ^ // unless b is 8,
+ Math.random() // in which case
+ * 16 // a random number from
+ >> input/4 // 8 to 11
+ ).toString(16) // in hexadecimal
+ : ( // or otherwise a concatenated string:
+ [1e7] + // 10000000 +
+ -1e3 + // -1000 +
+ -4e3 + // -4000 +
+ -8e3 + // -80000000 +
+ -1e11 // -100000000000,
+ ).replace( // replacing
+ /[018]/g, // zeroes, ones, and eights with
+ generateUUID // random hex digits
+ );
+}
+
+
export function has(object, key) {
return object ? HOP.call(object, key) : false;
}
diff --git a/src/utilities/vue.js b/src/utilities/vue.js
index fbee5016..9fe56cf6 100644
--- a/src/utilities/vue.js
+++ b/src/utilities/vue.js
@@ -7,6 +7,7 @@
import Module from 'utilities/module';
import {has} from 'utilities/object';
+import {DEBUG} from 'utilities/constants';
export class Vue extends Module {
@@ -18,12 +19,15 @@ export class Vue extends Module {
async onLoad() {
const Vue = window.ffzVue = this.Vue = (await import(/* webpackChunkName: "vue" */ 'vue')).default,
+ ObserveVisibility = await import(/* webpackChunkName: "vue" */ 'vue-observe-visibility'),
RavenVue = await import(/* webpackChunkName: "vue" */ 'raven-js/plugins/vue'),
components = this._components;
this.component((await import(/* webpackChunkName: "vue" */ 'src/std-components/index.js')).default);
- if ( this.root.raven )
+ Vue.use(ObserveVisibility);
+
+ if ( ! DEBUG && this.root.raven )
this.root.raven.addPlugin(RavenVue, Vue);
for(const key in components)
@@ -82,6 +86,11 @@ export class Vue extends Module {
}
});
+ this.on('i18n:transform', () => {
+ this._vue_i18n.locale = this.i18n.locale;
+ this._vue_i18n.phrases = {};
+ });
+
this.on('i18n:changed', () => {
this._vue_i18n.locale = this.i18n.locale;
this._vue_i18n.phrases = {};
@@ -97,6 +106,41 @@ export class Vue extends Module {
vue.prototype.$i18n = this._vue_i18n;
}
+ vue.component('t-list', {
+ props: {
+ tag: {
+ required: false
+ },
+ phrase: {
+ type: String,
+ required: true
+ },
+ default: {
+ type: String,
+ required: true
+ },
+ data: {
+ type: Object,
+ required: false
+ }
+ },
+
+ render(createElement) {
+ return createElement(
+ this.tag || 'span',
+ this.$i18n.tList_(
+ this.phrase,
+ this.default,
+ Object.assign({}, this.data, this.$scopedSlots)
+ ).map(out => {
+ if ( typeof out === 'function' )
+ return out();
+ return out;
+ })
+ );
+ }
+ })
+
vue.mixin({
methods: {
reactNavigate(url, event) {
diff --git a/styles/icons.scss b/styles/icons.scss
index 685ae846..f79dcde0 100644
--- a/styles/icons.scss
+++ b/styles/icons.scss
@@ -121,6 +121,9 @@
.ffz-i-conversations:before { content: '\e82c'; } /* '' */
.ffz-i-channels:before { content: '\e82d'; } /* '' */
.ffz-i-camera:before { content: '\e82e'; } /* '' */
+.ffz-i-cw:before { content: '\e82f'; } /* '' */
+.ffz-i-up-dir:before { content: '\e830'; } /* '' */
+.ffz-i-up-big:before { content: '\e831'; } /* '' */
.ffz-i-link-ext:before { content: '\f08e'; } /* '' */
.ffz-i-twitter:before { content: '\f099'; } /* '' */
.ffz-i-github:before { content: '\f09b'; } /* '' */
diff --git a/styles/widgets.scss b/styles/widgets.scss
index 1b0f8989..336dd178 100644
--- a/styles/widgets.scss
+++ b/styles/widgets.scss
@@ -10,6 +10,7 @@
@import "./widgets/add-ons.scss";
@import "./widgets/color-picker.scss";
+@import "./widgets/icon-picker.scss";
.tw-display-inline { display: inline !important }
diff --git a/styles/widgets/icon-picker.scss b/styles/widgets/icon-picker.scss
new file mode 100644
index 00000000..661f059a
--- /dev/null
+++ b/styles/widgets/icon-picker.scss
@@ -0,0 +1,12 @@
+.ffz--icon-picker__list {
+ max-height: 15rem;
+ font-size: 1.6rem;
+
+ .ffz-icon {
+ width: auto !important;
+
+ > * {
+ pointer-events: none;
+ }
+ }
+}
\ No newline at end of file