diff --git a/package.json b/package.json index c1680802..57f18d20 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.60.1", + "version": "4.61.0", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/addons.ts b/src/addons.ts index 16b7eb96..ecefcc95 100644 --- a/src/addons.ts +++ b/src/addons.ts @@ -46,6 +46,12 @@ type AddonManagerEvents = { }; +type FullAddonInfo = AddonInfo & { + _search?: string | null; + src: string; +}; + + // ============================================================================ // AddonManager // ============================================================================ @@ -62,7 +68,7 @@ export default class AddonManager extends Module<'addons'> { reload_required: boolean; target: string; - addons: Record; + addons: Record; enabled_addons: string[]; private _loader?: Promise; @@ -239,7 +245,9 @@ export default class AddonManager extends Module<'addons'> { this.emit(':data-loaded'); } - addAddon(addon: AddonInfo, is_dev: boolean = false) { + addAddon(input: AddonInfo, is_dev: boolean = false) { + let addon = input as FullAddonInfo; + const old = this.addons[addon.id]; this.addons[addon.id] = addon; @@ -269,7 +277,7 @@ export default class AddonManager extends Module<'addons'> { this.addons[id] = [addon.id]; } - if ( ! old ) + if ( ! old || Array.isArray(old) ) this.settings.addUI(`addon-changelog.${addon.id}`, { path: `Add-Ons > Changelog > ${addon.name}`, component: 'changelog', @@ -284,6 +292,9 @@ export default class AddonManager extends Module<'addons'> { rebuildAddonSearch() { for(const addon of Object.values(this.addons)) { + if ( Array.isArray(addon) ) + continue; + const terms = new Set([ addon._search, addon.name, @@ -302,11 +313,15 @@ export default class AddonManager extends Module<'addons'> { if ( addon.author_i18n ) terms.add(this.i18n.t(addon.author_i18n, addon.author)); + if ( addon.maintainer_i18n ) + terms.add(this.i18n.t(addon.maintainer_i18n, addon.maintainer)); + if ( addon.description_i18n ) terms.add(this.i18n.t(addon.description_i18n, addon.description)); } - addon.search_terms = [...terms].map(term => term ? term.toLocaleLowerCase() : '').join('\n'); + addon.search_terms = [...terms] + .map(term => term ? term.toLocaleLowerCase() : '').join('\n'); } } diff --git a/src/experiments.ts b/src/experiments.ts index b5ee99df..e1f36069 100644 --- a/src/experiments.ts +++ b/src/experiments.ts @@ -13,6 +13,7 @@ import Cookie from 'js-cookie'; import SHA1 from 'crypto-js/sha1'; import type SettingsManager from './settings'; +import type { ExperimentTypeMap } from 'utilities/types'; declare module 'utilities/types' { interface ModuleMap { @@ -22,7 +23,16 @@ declare module 'utilities/types' { experiments: ExperimentEvents; } interface ProviderTypeMap { - 'experiment-overrides': Record + 'experiment-overrides': { + [K in keyof ExperimentTypeMap]?: ExperimentTypeMap[K]; + } + } + interface PubSubCommands { + reload_experiments: []; + update_experiment: { + key: keyof ExperimentTypeMap, + data: FFZExperimentData | ExperimentGroup[] + }; } } @@ -90,8 +100,19 @@ export type OverrideCookie = { type ExperimentEvents = { ':changed': [key: string, new_value: any, old_value: any]; ':twitch-changed': [key: string, new_value: string | null, old_value: string | null]; - [key: `:changed:${string}`]: [new_value: any, old_value: any]; [key: `:twitch-changed:${string}`]: [new_value: string | null, old_value: string | null]; +} & { + [K in keyof ExperimentTypeMap as `:changed:${K}`]: [new_value: ExperimentTypeMap[K], old_value: ExperimentTypeMap[K] | null]; +}; + + +type ExperimentLogEntry = { + key: string; + name: string; + value: any; + override: boolean; + rarity: number; + type?: string; } @@ -107,7 +128,7 @@ export function isFFZExperiment(exp: ExperimentData): exp is FFZExperimentData { return 'description' in exp; } -function sortExperimentLog(a,b) { +function sortExperimentLog(a: ExperimentLogEntry, b: ExperimentLogEntry) { if ( a.rarity < b.rarity ) return -1; else if ( a.rarity > b.rarity ) @@ -133,9 +154,11 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE // State unique_id?: string; - experiments: Record; + experiments: Partial<{ + [K in keyof ExperimentTypeMap]: FFZExperimentData; + }>; - private cache: Map; + private cache: Map; // Helpers @@ -155,19 +178,20 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE no_filter: true, getExtraTerms: () => { - const values = []; + const values: string[] = []; - for(const exps of [this.experiments, this.getTwitchExperiments()]) { - if ( ! exps ) - continue; + for(const [key, val] of Object.entries(this.experiments)) { + values.push(key); + if ( val.name ) + values.push(val.name); + if ( val.description ) + values.push(val.description); + } - for(const [key, val] of Object.entries(exps)) { - values.push(key); - if ( val.name ) - values.push(val.name); - if ( val.description ) - values.push(val.description); - } + for(const [key, val] of Object.entries(this.getTwitchExperiments())) { + values.push(key); + if ( val.name ) + values.push(val.name); } return values; @@ -178,7 +202,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE unique_id: () => this.unique_id, - ffz_data: () => deep_copy(this.experiments) ?? {}, + ffz_data: () => deep_copy(this.experiments), twitch_data: () => deep_copy(this.getTwitchExperiments()), usingTwitchExperiment: (key: string) => this.usingTwitchExperiment(key), @@ -188,10 +212,10 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE setTwitchOverride: (key: string, val: string) => this.setTwitchOverride(key, val), deleteTwitchOverride: (key: string) => this.deleteTwitchOverride(key), - getAssignment: (key: string) => this.getAssignment(key), - hasOverride: (key: string) => this.hasOverride(key), - setOverride: (key: string, val: any) => this.setOverride(key, val), - deleteOverride: (key: string) => this.deleteOverride(key), + getAssignment: (key: K) => this.getAssignment(key), + hasOverride: (key: keyof ExperimentTypeMap) => this.hasOverride(key), + setOverride: (key: K, val: ExperimentTypeMap[K]) => this.setOverride(key, val), + deleteOverride: (key: keyof ExperimentTypeMap) => this.deleteOverride(key), on: (...args: Parameters) => this.on(...args), off: (...args: Parameters) => this.off(...args) @@ -226,7 +250,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE async loadExperiments() { - let data: Record | null; + let data: Record | null; try { data = await fetchJSON(DEBUG @@ -254,7 +278,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE if ( old_val !== new_val ) { changed++; this.emit(':changed', key, new_val, old_val); - this.emit(`:changed:${key}`, new_val, old_val); + this.emit(`:changed:${key as keyof ExperimentTypeMap}`, new_val as any, old_val as any); } } @@ -265,18 +289,21 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE /** @internal */ onEnable() { this.on('pubsub:command:reload_experiments', this.loadExperiments, this); - this.on('pubsub:command:update_experiment', this.updateExperiment, this); + this.on('pubsub:command:update_experiment', data => { + this.updateExperiment(data.key, data.data); + }, this); } - updateExperiment(key: string, data: FFZExperimentData | ExperimentGroup[]) { + updateExperiment(key: keyof ExperimentTypeMap, data: FFZExperimentData | ExperimentGroup[]) { this.log.info(`Received updated data for experiment "${key}" via PubSub.`, data); if ( Array.isArray(data) ) { - if ( ! this.experiments[key] ) + const existing = this.experiments[key]; + if ( ! existing ) return; - this.experiments[key].groups = data; + existing.groups = data; } else if ( data?.groups ) this.experiments[key] = data; @@ -291,8 +318,8 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE '' ]; - const ffz_assignments = []; - for(const [key, value] of Object.entries(this.experiments)) { + const ffz_assignments: ExperimentLogEntry[] = []; + for(const [key, value] of Object.entries(this.experiments) as [keyof ExperimentTypeMap, FFZExperimentData][]) { const assignment = this.getAssignment(key), override = this.hasOverride(key); @@ -322,7 +349,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE for(const entry of ffz_assignments) out.push(`FFZ | ${entry.name}: ${entry.value}${entry.override ? ' (Override)' : ''} (r:${entry.rarity})`); - const twitch_assignments = [], + const twitch_assignments: ExperimentLogEntry[] = [], channel = this.settings.get('context.channel'); for(const [key, value] of Object.entries(this.getTwitchExperiments())) { @@ -556,7 +583,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE return this.getTwitchAssignment(key, channel); } - _rebuildTwitchKey( + private _rebuildTwitchKey( key: string, is_set: boolean, new_val: string | null @@ -578,7 +605,9 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE // FFZ Experiments - setOverride(key: string, value: unknown = null) { + setOverride< + K extends keyof ExperimentTypeMap + >(key: K, value: ExperimentTypeMap[K]) { const overrides = this.settings.provider.get('experiment-overrides', {}); overrides[key] = value; @@ -587,7 +616,7 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE this._rebuildKey(key); } - deleteOverride(key: string) { + deleteOverride(key: keyof ExperimentTypeMap) { const overrides = this.settings.provider.get('experiment-overrides'); if ( ! overrides || ! has(overrides, key) ) return; @@ -601,33 +630,37 @@ export default class ExperimentManager extends Module<'experiments', ExperimentE this._rebuildKey(key); } - hasOverride(key: string) { + hasOverride(key: keyof ExperimentTypeMap) { const overrides = this.settings.provider.get('experiment-overrides'); return overrides ? has(overrides, key): false; } - get: (key: string) => T | null; + get: ( + key: K + ) => ExperimentTypeMap[K]; - getAssignment(key: string): T | null { + getAssignment( + key: K + ): ExperimentTypeMap[K] { if ( this.cache.has(key) ) - return this.cache.get(key) as T; + return this.cache.get(key) as ExperimentTypeMap[K]; const experiment = this.experiments[key]; if ( ! experiment ) { this.log.warn(`Tried to get assignment for experiment "${key}" which is not known.`); - return null; + return null as ExperimentTypeMap[K]; } const overrides = this.settings.provider.get('experiment-overrides'), out = overrides && has(overrides, key) ? - overrides[key] as T : - ExperimentManager.selectGroup(key, experiment, this.unique_id ?? ''); + overrides[key] : + ExperimentManager.selectGroup(key, experiment, this.unique_id ?? ''); this.cache.set(key, out); - return out; + return out as ExperimentTypeMap[K]; } - _rebuildKey(key: string) { + private _rebuildKey(key: keyof ExperimentTypeMap) { if ( ! this.cache.has(key) ) return; diff --git a/src/modules/chat/actions/actions.jsx b/src/modules/chat/actions/actions.jsx index 6dd2c40d..50f4f3af 100644 --- a/src/modules/chat/actions/actions.jsx +++ b/src/modules/chat/actions/actions.jsx @@ -614,7 +614,7 @@ export default class Actions extends Module { }, onMove: (target, tip, event) => { - this.emit('tooltips:mousemove', target, tip, event) + this.emit('tooltips:hover', target, tip, event) }, onLeave: (target, tip, event) => { @@ -1276,4 +1276,4 @@ export default class Actions extends Module { sendMessage(room, message) { return this.resolve('site.chat').sendMessage(room, message); } -} \ No newline at end of file +} diff --git a/src/modules/chat/overrides.js b/src/modules/chat/overrides.ts similarity index 63% rename from src/modules/chat/overrides.js rename to src/modules/chat/overrides.ts index 88bd35de..c925b195 100644 --- a/src/modules/chat/overrides.js +++ b/src/modules/chat/overrides.ts @@ -4,14 +4,43 @@ // Name and Color Overrides // ============================================================================ -import Module from 'utilities/module'; +import Module, { GenericModule } from 'utilities/module'; import { createElement, ClickOutside } from 'utilities/dom'; import Tooltip from 'utilities/tooltip'; +import type SettingsManager from 'root/src/settings'; -export default class Overrides extends Module { - constructor(...args) { - super(...args); +declare module 'utilities/types' { + interface ModuleMap { + 'chat.overrides': Overrides; + } + interface ModuleEventMap { + 'chat.overrides': OverrideEvents; + } + interface ProviderTypeMap { + 'overrides.colors': Record; + 'overrides.names': Record; + } +} + + +export type OverrideEvents = { + ':changed': [id: string, type: 'name' | 'color', value: string | undefined]; +} + + +export default class Overrides extends Module<'chat.overrides'> { + + // Dependencies + settings: SettingsManager = null as any; + + // State and Caching + color_cache: Record | null; + name_cache: Record | null; + + + constructor(name?: string, parent?: GenericModule) { + super(name, parent); this.inject('settings'); @@ -35,12 +64,15 @@ export default class Overrides extends Module { });*/ } + /** @internal */ onEnable() { this.settings.provider.on('changed', this.onProviderChange, this); } - renderUserEditor(user, target) { - let outside, popup, ve; + renderUserEditor(user: any, target: HTMLElement) { + let outside: ClickOutside | null, + popup: Tooltip | null, + ve: any; const destroy = () => { const o = outside, p = popup, v = ve; @@ -56,7 +88,10 @@ export default class Overrides extends Module { v.$destroy(); } - const parent = document.fullscreenElement || document.body.querySelector('#root>div') || document.body; + const parent = + document.fullscreenElement as HTMLElement + ?? document.body.querySelector('#root>div') + ?? document.body; popup = new Tooltip(parent, [], { logger: this.log, @@ -88,6 +123,9 @@ export default class Overrides extends Module { const vue = this.resolve('vue'), _editor = import(/* webpackChunkName: "overrides" */ './override-editor.vue'); + if ( ! vue ) + throw new Error('unable to load vue'); + const [, editor] = await Promise.all([vue.enable(), _editor]); vue.component('override-editor', editor.default); @@ -118,12 +156,13 @@ export default class Overrides extends Module { onShow: async (t, tip) => { await tip.waitForDom(); requestAnimationFrame(() => { - outside = new ClickOutside(tip.outer, destroy) + if ( tip.outer ) + outside = new ClickOutside(tip.outer, destroy) }); }, onMove: (target, tip, event) => { - this.emit('tooltips:mousemove', target, tip, event) + this.emit('tooltips:hover', target, tip, event) }, onLeave: (target, tip, event) => { @@ -137,30 +176,25 @@ export default class Overrides extends Module { } - onProviderChange(key) { - if ( key === 'overrides.colors' ) + onProviderChange(key: string) { + if ( key === 'overrides.colors' && this.color_cache ) this.loadColors(); - else if ( key === 'overrides.names' ) + else if ( key === 'overrides.names' && this.name_cache ) this.loadNames(); } get colors() { - if ( ! this.color_cache ) - this.loadColors(); - - return this.color_cache; + return this.color_cache ?? this.loadColors(); } get names() { - if ( ! this.name_cache ) - this.loadNames(); - - return this.name_cache; + return this.name_cache ?? this.loadNames(); } loadColors() { - let old_keys, + let old_keys: Set, loaded = true; + if ( ! this.color_cache ) { loaded = false; this.color_cache = {}; @@ -168,24 +202,28 @@ export default class Overrides extends Module { } else old_keys = new Set(Object.keys(this.color_cache)); - for(const [key, val] of Object.entries(this.settings.provider.get('overrides.colors', {}))) { - old_keys.delete(key); - if ( this.color_cache[key] !== val ) { - this.color_cache[key] = val; - if ( loaded ) - this.emit(':changed', key, 'color', val); + const entries = this.settings.provider.get('overrides.colors'); + if ( entries ) + for(const [key, val] of Object.entries(entries)) { + old_keys.delete(key); + if ( this.color_cache[key] !== val ) { + this.color_cache[key] = val; + if ( loaded ) + this.emit(':changed', key, 'color', val); + } } - } for(const key of old_keys) { this.color_cache[key] = undefined; if ( loaded ) this.emit(':changed', key, 'color', undefined); } + + return this.color_cache; } loadNames() { - let old_keys, + let old_keys: Set, loaded = true; if ( ! this.name_cache ) { loaded = false; @@ -194,37 +232,35 @@ export default class Overrides extends Module { } else old_keys = new Set(Object.keys(this.name_cache)); - for(const [key, val] of Object.entries(this.settings.provider.get('overrides.names', {}))) { - old_keys.delete(key); - if ( this.name_cache[key] !== val ) { - this.name_cache[key] = val; - if ( loaded ) - this.emit(':changed', key, 'name', val); + const entries = this.settings.provider.get('overrides.names'); + if ( entries ) + for(const [key, val] of Object.entries(entries)) { + old_keys.delete(key); + if ( this.name_cache[key] !== val ) { + this.name_cache[key] = val; + if ( loaded ) + this.emit(':changed', key, 'name', val); + } } - } for(const key of old_keys) { this.name_cache[key] = undefined; if ( loaded ) this.emit(':changed', key, 'name', undefined); } + + return this.name_cache; } - getColor(id) { - if ( this.colors[id] != null ) - return this.colors[id]; - - return null; + getColor(id: string): string | null { + return this.colors[id] ?? null; } - getName(id) { - if ( this.names[id] != null ) - return this.names[id]; - - return null; + getName(id: string) { + return this.names[id] ?? null; } - setColor(id, color) { + setColor(id: string, color?: string) { if ( this.colors[id] !== color ) { this.colors[id] = color; this.settings.provider.set('overrides.colors', this.colors); @@ -232,7 +268,7 @@ export default class Overrides extends Module { } } - setName(id, name) { + setName(id: string, name?: string) { if ( this.names[id] !== name ) { this.names[id] = name; this.settings.provider.set('overrides.names', this.names); @@ -240,11 +276,11 @@ export default class Overrides extends Module { } } - deleteColor(id) { + deleteColor(id: string) { this.setColor(id, undefined); } - deleteName(id) { + deleteName(id: string) { this.setName(id, undefined); } -} \ No newline at end of file +} diff --git a/src/modules/chat/types.ts b/src/modules/chat/types.ts new file mode 100644 index 00000000..8414127c --- /dev/null +++ b/src/modules/chat/types.ts @@ -0,0 +1,8 @@ + +// ============================================================================ +// Badges +// ============================================================================ + +export type BadgeAssignment = { + id: string; +}; diff --git a/src/modules/chat/user.js b/src/modules/chat/user.ts similarity index 69% rename from src/modules/chat/user.js rename to src/modules/chat/user.ts index 7c699d87..3d42d2cb 100644 --- a/src/modules/chat/user.js +++ b/src/modules/chat/user.ts @@ -5,20 +5,39 @@ // ============================================================================ import {SourcedSet} from 'utilities/object'; +import type Chat from '.'; +import type Room from './room'; +import type { BadgeAssignment } from './types'; export default class User { - constructor(manager, room, id, login) { + + // Parent + manager: Chat; + room: Room | null; + + // State + destroyed: boolean = false; + + _id: string | null; + _login: string | null = null; + + // Storage + emote_sets: SourcedSet | null; + badges: SourcedSet | null; + + + constructor(manager: Chat, room: Room | null, id: string | null, login: string | null) { this.manager = manager; this.room = room; - this.emote_sets = null; //new SourcedSet; - this.badges = null; // new SourcedSet; + this.emote_sets = null; + this.badges = null; this._id = id; this.login = login; if ( id ) - (room || manager).user_ids[id] = this; + (room ?? manager).user_ids[id] = this; } destroy() { @@ -31,6 +50,7 @@ export default class User { this.emote_sets = null; } + // Badges are not referenced, so we can just dump them all. if ( this.badges ) this.badges = null; @@ -45,26 +65,24 @@ export default class User { } } - merge(other) { + merge(other: User) { if ( ! this.login && other.login ) this.login = other.login; - if ( other.emote_sets && other.emote_sets._sources ) { - for(const [provider, sets] of other.emote_sets._sources.entries()) { + if ( other.emote_sets ) + for(const [provider, sets] of other.emote_sets.iterateSources()) { for(const set_id of sets) this.addSet(provider, set_id); } - } - if ( other.badges && other.badges._sources ) { - for(const [provider, badges] of other.badges._sources.entries()) { + if ( other.badges ) + for(const [provider, badges] of other.badges.iterateSources()) { for(const badge of badges) this.addBadge(provider, badge.id, badge); } - } } - _unloadAddon(addon_id) { + _unloadAddon(addon_id: string) { // TODO: This return 0; } @@ -107,9 +125,9 @@ export default class User { // Add Badges // ======================================================================== - addBadge(provider, badge_id, data) { + addBadge(provider: string, badge_id: string, data?: BadgeAssignment) { if ( this.destroyed ) - return; + return false; if ( typeof badge_id === 'number' ) badge_id = `${badge_id}`; @@ -122,8 +140,9 @@ export default class User { if ( ! this.badges ) this.badges = new SourcedSet; - if ( this.badges.has(provider) ) - for(const old_b of this.badges.get(provider)) + const existing = this.badges.get(provider); + if ( existing ) + for(const old_b of existing) if ( old_b.id == badge_id ) { Object.assign(old_b, data); return false; @@ -135,31 +154,35 @@ export default class User { } - getBadge(badge_id) { - if ( ! this.badges ) - return null; + getBadge(badge_id: string) { + if ( this.badges ) + for(const badge of this.badges._cache) + if ( badge.id == badge_id ) + return badge; - for(const badge of this.badges._cache) - if ( badge.id == badge_id ) - return badge; + return null; } - removeBadge(provider, badge_id) { - if ( ! this.badges || ! this.badges.has(provider) ) + removeBadge(provider: string, badge_id: string) { + if ( ! this.badges ) return false; - for(const old_b of this.badges.get(provider)) - if ( old_b.id == badge_id ) { - this.badges.remove(provider, old_b); - //this.manager.badges.unrefBadge(badge_id); - return true; - } + const existing = this.badges.get(provider); + if ( existing ) + for(const old_b of existing) + if ( old_b.id == badge_id ) { + this.badges.remove(provider, old_b); + //this.manager.badges.unrefBadge(badge_id); + return true; + } + + return false; } - removeAllBadges(provider) { - if ( this.destroyed || ! this.badges ) + removeAllBadges(provider: string) { + if ( ! this.badges ) return false; if ( ! this.badges.has(provider) ) @@ -175,7 +198,7 @@ export default class User { // Emote Sets // ======================================================================== - addSet(provider, set_id, data) { + addSet(provider: string, set_id: string, data?: unknown) { if ( this.destroyed ) return; @@ -203,8 +226,8 @@ export default class User { return added; } - removeAllSets(provider) { - if ( this.destroyed || ! this.emote_sets ) + removeAllSets(provider: string) { + if ( ! this.emote_sets ) return false; const sets = this.emote_sets.get(provider); @@ -217,8 +240,8 @@ export default class User { return true; } - removeSet(provider, set_id) { - if ( this.destroyed || ! this.emote_sets ) + removeSet(provider: string, set_id: string) { + if ( ! this.emote_sets ) return; if ( typeof set_id === 'number' ) @@ -235,4 +258,4 @@ export default class User { return false; } -} \ No newline at end of file +} diff --git a/src/modules/main_menu/components/graphql-inspect.vue b/src/modules/main_menu/components/graphql-inspect.vue index c0f9fa72..5d8b366b 100644 --- a/src/modules/main_menu/components/graphql-inspect.vue +++ b/src/modules/main_menu/components/graphql-inspect.vue @@ -119,8 +119,8 @@ export default { result: null }); - this.queryMap[name].variables = deep_copy(query.observableQuery?.variables); - this.queryMap[name].result = deep_copy(query.observableQuery?.lastResult?.data ?? null); + this.queryMap[name].variables = deep_copy(query.observableQuery?.last?.variables ?? query.observableQuery?.variables); + this.queryMap[name].result = deep_copy(query.observableQuery?.lastResult?.data ?? query.observableQuery?.last?.result?.data ?? null); } if ( ! this.current ) diff --git a/src/modules/main_menu/components/home-page.vue b/src/modules/main_menu/components/home-page.vue index 57804e34..4bf58fdb 100644 --- a/src/modules/main_menu/components/home-page.vue +++ b/src/modules/main_menu/components/home-page.vue @@ -190,7 +190,7 @@ diff --git a/src/modules/main_menu/components/menu-page.vue b/src/modules/main_menu/components/menu-page.vue index 029f0645..d6c9f6a4 100644 --- a/src/modules/main_menu/components/menu-page.vue +++ b/src/modules/main_menu/components/menu-page.vue @@ -2,10 +2,47 @@
- {{ t(i.i18n_key, i.title) }} + {{ t(i.i18n_key, i.title) }} {{ t(i.i18n_key, i.title) }} + + + +
@@ -226,4 +263,4 @@ export default { } } - \ No newline at end of file + diff --git a/src/modules/main_menu/components/rich-feed.vue b/src/modules/main_menu/components/rich-feed.vue index 36826979..78f483db 100644 --- a/src/modules/main_menu/components/rich-feed.vue +++ b/src/modules/main_menu/components/rich-feed.vue @@ -1,7 +1,8 @@