Merge branch 'develop' into toggle-ads

This commit is contained in:
Kainoa Kanter 2022-07-14 17:48:59 -07:00 committed by GitHub
commit a8de112fe0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 183 additions and 169 deletions

View file

@ -9,6 +9,13 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 12.x.x (unreleased)
### Improvements
### Bugfixes
- クライアントが起動しなくなることがある問題を修正 @syuilo
## 12.113.0 (2022/07/13) ## 12.113.0 (2022/07/13)
### Improvements ### Improvements

View file

@ -888,6 +888,7 @@ enableAutoSensitive: "自動NSFW判定"
enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。" enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。"
activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。" activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。"
showAds: "広告を表示する" showAds: "広告を表示する"
navbar: "ナビゲーションバー"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。" description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "12.113.0", "version": "12.114.0-beta.6",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -14,9 +14,11 @@
// ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
(async () => { (async () => {
window.onerror = (e) => { window.onerror = (e) => {
console.error(e);
renderError('SOMETHING_HAPPENED', e); renderError('SOMETHING_HAPPENED', e);
}; };
window.onunhandledrejection = (e) => { window.onunhandledrejection = (e) => {
console.error(e);
renderError('SOMETHING_HAPPENED_IN_PROMISE', e); renderError('SOMETHING_HAPPENED_IN_PROMISE', e);
}; };
@ -47,18 +49,30 @@
localStorage.setItem('localeVersion', v); localStorage.setItem('localeVersion', v);
} else { } else {
await checkUpdate(); await checkUpdate();
renderError('LOCALE_FETCH_FAILED'); renderError('LOCALE_FETCH');
return; return;
} }
} }
//#endregion //#endregion
//#region Script //#region Script
import(`/assets/${CLIENT_ENTRY}`) function importAppScript() {
.catch(async e => { import(`/assets/${CLIENT_ENTRY}`)
await checkUpdate(); .catch(async e => {
renderError('APP_FETCH_FAILED', e); await checkUpdate();
}) console.error(e);
renderError('APP_IMPORT', e);
});
}
// タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
if (document.readyState !== 'loading') {
importAppScript();
} else {
window.addEventListener('DOMContentLoaded', () => {
importAppScript();
});
}
//#endregion //#endregion
//#region Theme //#region Theme
@ -112,35 +126,35 @@
let errorsElement = document.getElementById('errors'); let errorsElement = document.getElementById('errors');
if (!errorsElement) { if (!errorsElement) {
document.documentElement.innerHTML = ` document.body.innerHTML = `
<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> <svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 9v2m0 4v.01"></path> <path d="M12 9v2m0 4v.01"></path>
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path> <path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
</svg> </svg>
<h1>An error has occurred!</h1> <h1>An error has occurred!</h1>
<button class="button-big" onclick="location.reload(true);"> <button class="button-big" onclick="location.reload(true);">
<span class="button-label-big">Refresh</span> <span class="button-label-big">Refresh</span>
</button> </button>
<p class="dont-worry">Don't worry, it's (probably) not your fault.</p> <p class="dont-worry">Don't worry, it's (probably) not your fault.</p>
<p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p> <p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p>
<a href="/flush"> <a href="/flush">
<button class="button-small"> <button class="button-small">
<span class="button-label-small">Clear preferences and cache</span> <span class="button-label-small">Clear preferences and cache</span>
</button> </button>
</a> </a>
<br> <br>
<a href="/cli"> <a href="/cli">
<button class="button-small"> <button class="button-small">
<span class="button-label-small">Start the simple client</span> <span class="button-label-small">Start the simple client</span>
</button> </button>
</a> </a>
<br> <br>
<a href="/bios"> <a href="/bios">
<button class="button-small"> <button class="button-small">
<span class="button-label-small">Start the repair tool</span> <span class="button-label-small">Start the repair tool</span>
</button> </button>
</a> </a>
<br> <br>
<div id="errors"></div> <div id="errors"></div>
`; `;
@ -269,17 +283,22 @@
// eslint-disable-next-line no-inner-declarations // eslint-disable-next-line no-inner-declarations
async function checkUpdate() { async function checkUpdate() {
// TODO: サーバーが落ちている場合などのエラーハンドリング try {
const res = await fetch('/api/meta', { const res = await fetch('/api/meta', {
method: 'POST', method: 'POST',
cache: 'no-cache' cache: 'no-cache'
}); });
const meta = await res.json(); const meta = await res.json();
if (meta.version != v) { if (meta.version != v) {
localStorage.setItem('v', meta.version); localStorage.setItem('v', meta.version);
refresh(); refresh();
}
} catch (e) {
console.error(e);
renderError('UPDATE_CHECK', e);
throw e;
} }
} }

View file

@ -56,7 +56,6 @@
"random-seed": "0.3.0", "random-seed": "0.3.0",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"rollup": "2.76.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sass": "1.53.0", "sass": "1.53.0",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
@ -102,6 +101,7 @@
"@types/ws": "8.5.3", "@types/ws": "8.5.3",
"@typescript-eslint/eslint-plugin": "5.30.6", "@typescript-eslint/eslint-plugin": "5.30.6",
"@typescript-eslint/parser": "5.30.6", "@typescript-eslint/parser": "5.30.6",
"rollup": "2.76.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "10.3.0", "cypress": "10.3.0",
"eslint": "8.19.0", "eslint": "8.19.0",

View file

@ -16,9 +16,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useCssModule } from 'vue'; import { } from 'vue';
useCssModule();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
inline?: boolean; inline?: boolean;

View file

@ -36,7 +36,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { } from 'vue'; import { } from 'vue';
import MkModal from '@/components/ui/modal.vue'; import MkModal from '@/components/ui/modal.vue';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { instanceName } from '@/config'; import { instanceName } from '@/config';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
@ -62,7 +62,7 @@ const modal = $ref<InstanceType<typeof MkModal>>();
const menu = defaultStore.state.menu; const menu = defaultStore.state.menu;
const items = Object.keys(menuDef).filter(k => !menu.includes(k)).map(k => menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({ const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k => navbarItemDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
type: def.to ? 'link' : 'button', type: def.to ? 'link' : 'button',
text: i18n.ts[def.title], text: i18n.ts[def.title],
icon: def.icon, icon: def.icon,

View file

@ -16,7 +16,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { toUnicode } from 'punycode'; import { toUnicode } from 'punycode';
import { useCssModule } from 'vue'; import { } from 'vue';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { host as localHost } from '@/config'; import { host as localHost } from '@/config';
import { $i } from '@/account'; import { $i } from '@/account';
@ -37,8 +37,6 @@ const isMe = $i && (
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention')); const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention'));
bg.setAlpha(0.1); bg.setAlpha(0.1);
const bgCss = bg.toRgbString(); const bgCss = bg.toRgbString();
useCssModule();
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -116,7 +116,7 @@ const setPosition = () => {
let top: number; let top: number;
if (props.targetElement) { if (props.targetElement) {
left = (rect.left + window.pageXOffset) + props.innerMargin; left = (rect.left + props.targetElement.offsetWidth + window.pageXOffset) + props.innerMargin;
top = rect.top + window.pageYOffset + (props.targetElement.offsetHeight / 2); top = rect.top + window.pageYOffset + (props.targetElement.offsetHeight / 2);
} else { } else {
left = props.x + props.innerMargin; left = props.x + props.innerMargin;

View file

@ -8,7 +8,6 @@ import tooltip from './tooltip';
import hotkey from './hotkey'; import hotkey from './hotkey';
import appear from './appear'; import appear from './appear';
import anim from './anim'; import anim from './anim';
import stickyContainer from './sticky-container';
import clickAnime from './click-anime'; import clickAnime from './click-anime';
import panel from './panel'; import panel from './panel';
import adaptiveBorder from './adaptive-border'; import adaptiveBorder from './adaptive-border';
@ -24,7 +23,6 @@ export default function(app: App) {
app.directive('appear', appear); app.directive('appear', appear);
app.directive('anim', anim); app.directive('anim', anim);
app.directive('click-anime', clickAnime); app.directive('click-anime', clickAnime);
app.directive('sticky-container', stickyContainer);
app.directive('panel', panel); app.directive('panel', panel);
app.directive('adaptive-border', adaptiveBorder); app.directive('adaptive-border', adaptiveBorder);
} }

View file

@ -1,17 +0,0 @@
import { Directive } from 'vue';
export default {
mounted(src, binding, vn) {
//const query = binding.value;
const header = src.children[0];
const body = src.children[1];
const currentStickyTop = getComputedStyle(src).getPropertyValue('--stickyTop') || '0px';
src.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`);
if (body) body.dataset.stickyContainerHeaderHeight = header.offsetHeight.toString();
header.style.setProperty('--stickyTop', currentStickyTop);
header.style.position = 'sticky';
header.style.top = 'var(--stickyTop)';
header.style.zIndex = '1';
},
} as Directive;

View file

@ -6,7 +6,7 @@ import { i18n } from '@/i18n';
import { ui } from '@/config'; import { ui } from '@/config';
import { unisonReload } from '@/scripts/unison-reload'; import { unisonReload } from '@/scripts/unison-reload';
export const menuDef = reactive({ export const navbarItemDef = reactive({
notifications: { notifications: {
title: 'notifications', title: 'notifications',
icon: 'fas fa-bell', icon: 'fas fa-bell',

View file

@ -114,15 +114,15 @@ const menuDef = computed(() => [{
to: '/settings/theme', to: '/settings/theme',
active: props.initialPage === 'theme', active: props.initialPage === 'theme',
}, { }, {
icon: 'fas fa-list-ul', icon: 'fas fa-bars',
text: i18n.ts.navbar,
to: '/settings/navbar',
active: props.initialPage === 'navbar',
}, {
icon: 'fas fa-bars-progress',
text: i18n.ts.statusbar, text: i18n.ts.statusbar,
to: '/settings/statusbars', to: '/settings/statusbars',
active: props.initialPage === 'statusbars', active: props.initialPage === 'statusbars',
}, {
icon: 'fas fa-list-ul',
text: i18n.ts.menu,
to: '/settings/menu',
active: props.initialPage === 'menu',
}, { }, {
icon: 'fas fa-music', icon: 'fas fa-music',
text: i18n.ts.sounds, text: i18n.ts.sounds,
@ -225,7 +225,7 @@ const component = computed(() => {
case 'theme': return defineAsyncComponent(() => import('./theme.vue')); case 'theme': return defineAsyncComponent(() => import('./theme.vue'));
case 'theme/install': return defineAsyncComponent(() => import('./theme.install.vue')); case 'theme/install': return defineAsyncComponent(() => import('./theme.install.vue'));
case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue')); case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue'));
case 'menu': return defineAsyncComponent(() => import('./menu.vue')); case 'navbar': return defineAsyncComponent(() => import('./navbar.vue'));
case 'statusbars': return defineAsyncComponent(() => import('./statusbars.vue')); case 'statusbars': return defineAsyncComponent(() => import('./statusbars.vue'));
case 'sounds': return defineAsyncComponent(() => import('./sounds.vue')); case 'sounds': return defineAsyncComponent(() => import('./sounds.vue'));
case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue')); case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue'));
@ -291,6 +291,8 @@ const headerActions = $computed(() => []);
const headerTabs = $computed(() => []); const headerTabs = $computed(() => []);
definePageMetadata(INFO); definePageMetadata(INFO);
// w 890
// h 700
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="_formRoot"> <div class="_formRoot">
<FormTextarea v-model="items" tall manual-save class="_formBlock"> <FormTextarea v-model="items" tall manual-save class="_formBlock">
<template #label>{{ i18n.ts.menu }}</template> <template #label>{{ i18n.ts.navbar }}</template>
<template #caption><button class="_textButton" @click="addItem">{{ i18n.ts.addItem }}</button></template> <template #caption><button class="_textButton" @click="addItem">{{ i18n.ts.addItem }}</button></template>
</FormTextarea> </FormTextarea>
@ -23,7 +23,7 @@ import FormTextarea from '@/components/form/textarea.vue';
import FormRadios from '@/components/form/radios.vue'; import FormRadios from '@/components/form/radios.vue';
import FormButton from '@/components/ui/button.vue'; import FormButton from '@/components/ui/button.vue';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { unisonReload } from '@/scripts/unison-reload'; import { unisonReload } from '@/scripts/unison-reload';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
@ -45,11 +45,11 @@ async function reloadAsk() {
} }
async function addItem() { async function addItem() {
const menu = Object.keys(menuDef).filter(k => !defaultStore.state.menu.includes(k)); const menu = Object.keys(navbarItemDef).filter(k => !defaultStore.state.menu.includes(k));
const { canceled, result: item } = await os.select({ const { canceled, result: item } = await os.select({
title: i18n.ts.addItem, title: i18n.ts.addItem,
items: [...menu.map(k => ({ items: [...menu.map(k => ({
value: k, text: i18n.ts[menuDef[k].title], value: k, text: i18n.ts[navbarItemDef[k].title],
})), { })), {
value: '-', text: i18n.ts.divider, value: '-', text: i18n.ts.divider,
}], }],
@ -81,7 +81,7 @@ const headerActions = $computed(() => []);
const headerTabs = $computed(() => []); const headerTabs = $computed(() => []);
definePageMetadata({ definePageMetadata({
title: i18n.ts.menu, title: i18n.ts.navbar,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
}); });
</script> </script>

View file

@ -12,7 +12,7 @@
<FormSection> <FormSection>
<template #label>{{ i18n.ts.signinHistory }}</template> <template #label>{{ i18n.ts.signinHistory }}</template>
<MkPagination :pagination="pagination"> <MkPagination :pagination="pagination" disable-auto-load>
<template #default="{items}"> <template #default="{items}">
<div> <div>
<div v-for="item in items" :key="item.id" v-panel class="timnmucd"> <div v-for="item in items" :key="item.id" v-panel class="timnmucd">

View file

@ -86,7 +86,6 @@ import FormRadios from '@/components/form/radios.vue';
import FormButton from '@/components/ui/button.vue'; import FormButton from '@/components/ui/button.vue';
import FormRange from '@/components/form/range.vue'; import FormRange from '@/components/form/range.vue';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';

View file

@ -1,12 +1,14 @@
<template> <template>
<div v-sticky-container class="yrzkoczt"> <MkStickyContainer>
<MkTab v-model="include" class="tab"> <template #header>
<option :value="null">{{ $ts.notes }}</option> <MkTab v-model="include" :class="$style.tab">
<option value="replies">{{ $ts.notesAndReplies }}</option> <option :value="null">{{ $ts.notes }}</option>
<option value="files">{{ $ts.withFiles }}</option> <option value="replies">{{ $ts.notesAndReplies }}</option>
</MkTab> <option value="files">{{ $ts.withFiles }}</option>
</MkTab>
</template>
<XNotes :no-gap="true" :pagination="pagination"/> <XNotes :no-gap="true" :pagination="pagination"/>
</div> </MkStickyContainer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -33,12 +35,10 @@ const pagination = {
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" module>
.yrzkoczt { .tab {
> .tab { margin: calc(var(--margin) / 2) 0;
margin: calc(var(--margin) / 2) 0; padding: calc(var(--margin) / 2) 0;
padding: calc(var(--margin) / 2) 0; background: var(--bg);
background: var(--bg);
}
} }
</style> </style>

View file

@ -9,9 +9,9 @@
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: menuDef[item].active }]" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="icon fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> <i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ $ts[navbarItemDef[item].title] }}</span>
<span v-if="menuDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
@ -37,7 +37,7 @@ import { computed, defineAsyncComponent, defineComponent, ref, toRef, watch } fr
import { host } from '@/config'; import { host } from '@/config';
import { search } from '@/scripts/search'; import { search } from '@/scripts/search';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { openAccountMenu } from '@/account'; import { openAccountMenu } from '@/account';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
@ -45,9 +45,9 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const menu = toRef(defaultStore.state, 'menu'); const menu = toRef(defaultStore.state, 'menu');
const otherMenuItemIndicated = computed(() => { const otherMenuItemIndicated = computed(() => {
for (const def in menuDef) { for (const def in navbarItemDef) {
if (menu.value.includes(def)) continue; if (menu.value.includes(def)) continue;
if (menuDef[def].indicated) return true; if (navbarItemDef[def].indicated) return true;
} }
return false; return false;
}); });
@ -57,7 +57,7 @@ export default defineComponent({
accounts: [], accounts: [],
connection: null, connection: null,
menu, menu,
menuDef: menuDef, navbarItemDef: navbarItemDef,
otherMenuItemIndicated, otherMenuItemIndicated,
post: os.post, post: os.post,
search, search,

View file

@ -4,29 +4,38 @@
<button v-click-anime class="item _button account" @click="openAccountMenu"> <button v-click-anime class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button> </button>
<MkA v-click-anime class="item index" active-class="active" to="/" exact> <MkA v-click-anime v-tooltip.right="i18n.ts.timeline" class="item index" active-class="active" to="/" exact>
<i class="icon fas fa-home fa-fw"></i><span class="text">{{ $ts.timeline }}</span> <i class="icon fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span>
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: menuDef[item].active }]" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> <component
<i class="icon fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> :is="navbarItemDef[item].to ? 'MkA' : 'button'"
<span v-if="menuDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)"
v-click-anime v-tooltip.right="i18n.ts[navbarItemDef[item].title]"
class="item _button"
:class="[item, { active: navbarItemDef[item].active }]"
active-class="active"
:to="navbarItemDef[item].to"
v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"
>
<i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ i18n.ts[navbarItemDef[item].title] }}</span>
<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" active-class="active" to="/admin"> <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.right="i18n.ts.controlPanel" class="item" active-class="active" to="/admin">
<i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span> <i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
</MkA> </MkA>
<button v-click-anime class="item _button" @click="more"> <button v-click-anime class="item _button" @click="more">
<i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> <i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" class="indicator"><i class="icon fas fa-circle"></i></span> <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon fas fa-circle"></i></span>
</button> </button>
<MkA v-click-anime class="item" active-class="active" to="/settings"> <MkA v-click-anime v-tooltip.right="i18n.ts.settings" class="item" active-class="active" to="/settings">
<i class="icon fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span> <i class="icon fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span>
</MkA> </MkA>
<button class="item _button post" data-cy-open-post-form @click="os.post"> <button class="item _button post" data-cy-open-post-form @click="os.post">
<i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span> <i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ i18n.ts.note }}</span>
</button> </button>
</div> </div>
</div> </div>
@ -35,17 +44,18 @@
<script lang="ts" setup> <script lang="ts" setup>
import { computed, defineAsyncComponent, ref, watch } from 'vue'; import { computed, defineAsyncComponent, ref, watch } from 'vue';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { i18n } from '@/i18n';
const iconOnly = ref(false); const iconOnly = ref(false);
const menu = computed(() => defaultStore.state.menu); const menu = computed(() => defaultStore.state.menu);
const otherMenuItemIndicated = computed(() => { const otherMenuItemIndicated = computed(() => {
for (const def in menuDef) { for (const def in navbarItemDef) {
if (menu.value.includes(def)) continue; if (menu.value.includes(def)) continue;
if (menuDef[def].indicated) return true; if (navbarItemDef[def].indicated) return true;
} }
return false; return false;
}); });
@ -244,7 +254,7 @@ function more(ev: MouseEvent) {
padding: 18px 0; padding: 18px 0;
width: 100%; width: 100%;
text-align: center; text-align: center;
font-size: $ui-font-size * 1.1; font-size: $ui-font-size;
line-height: initial; line-height: initial;
> .icon, > .icon,

View file

@ -7,9 +7,9 @@
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime v-tooltip="$ts[menuDef[item].title]" class="item _button" :class="item" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-tooltip="$ts[navbarItemDef[item].title]" class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i> <i class="fa-fw" :class="navbarItemDef[item].icon"></i>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
@ -43,7 +43,7 @@ import { defineAsyncComponent, defineComponent } from 'vue';
import { host } from '@/config'; import { host } from '@/config';
import { search } from '@/scripts/search'; import { search } from '@/scripts/search';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { openAccountMenu } from '@/account'; import { openAccountMenu } from '@/account';
import MkButton from '@/components/ui/button.vue'; import MkButton from '@/components/ui/button.vue';
@ -57,7 +57,7 @@ export default defineComponent({
host: host, host: host,
accounts: [], accounts: [],
connection: null, connection: null,
menuDef: menuDef, navbarItemDef: navbarItemDef,
settingsWindowed: false, settingsWindowed: false,
}; };
}, },
@ -68,9 +68,9 @@ export default defineComponent({
}, },
otherNavItemIndicated(): boolean { otherNavItemIndicated(): boolean {
for (const def in this.menuDef) { for (const def in this.navbarItemDef) {
if (this.menu.includes(def)) continue; if (this.menu.includes(def)) continue;
if (this.menuDef[def].indicated) return true; if (this.navbarItemDef[def].indicated) return true;
} }
return false; return false;
}, },
@ -113,7 +113,7 @@ export default defineComponent({
withExtraOperation: true, withExtraOperation: true,
}, ev); }, ev);
}, },
} },
}); });
</script> </script>

View file

@ -14,9 +14,9 @@
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" class="divider"></div>
<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="item" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> <i class="fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ $ts[navbarItemDef[item].title] }}</span>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
@ -45,7 +45,7 @@ import { defineAsyncComponent, defineComponent } from 'vue';
import { host } from '@/config'; import { host } from '@/config';
import { search } from '@/scripts/search'; import { search } from '@/scripts/search';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { openAccountMenu } from '@/account'; import { openAccountMenu } from '@/account';
import MkButton from '@/components/ui/button.vue'; import MkButton from '@/components/ui/button.vue';
import { StickySidebar } from '@/scripts/sticky-sidebar'; import { StickySidebar } from '@/scripts/sticky-sidebar';
@ -62,7 +62,7 @@ export default defineComponent({
host: host, host: host,
accounts: [], accounts: [],
connection: null, connection: null,
menuDef: menuDef, navbarItemDef: navbarItemDef,
iconOnly: false, iconOnly: false,
settingsWindowed: false, settingsWindowed: false,
}; };
@ -74,9 +74,9 @@ export default defineComponent({
}, },
otherNavItemIndicated(): boolean { otherNavItemIndicated(): boolean {
for (const def in this.menuDef) { for (const def in this.navbarItemDef) {
if (this.menu.includes(def)) continue; if (this.menu.includes(def)) continue;
if (this.menuDef[def].indicated) return true; if (this.navbarItemDef[def].indicated) return true;
} }
return false; return false;
}, },
@ -131,7 +131,7 @@ export default defineComponent({
withExtraOperation: true, withExtraOperation: true,
}, ev); }, ev);
}, },
} },
}); });
</script> </script>

View file

@ -47,7 +47,6 @@ import XCommon from './_common_/common.vue';
import { instanceName } from '@/config'; import { instanceName } from '@/config';
import { StickySidebar } from '@/scripts/sticky-sidebar'; import { StickySidebar } from '@/scripts/sticky-sidebar';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu';
import { mainRouter } from '@/router'; import { mainRouter } from '@/router';
import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';

View file

@ -69,12 +69,12 @@ import { v4 as uuid } from 'uuid';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import { deckStore, addColumn as addColumnToStore, loadDeck } from './deck/deck-store'; import { deckStore, addColumn as addColumnToStore, loadDeck } from './deck/deck-store';
import DeckColumnCore from '@/ui/deck/column-core.vue'; import DeckColumnCore from '@/ui/deck/column-core.vue';
import XSidebar from '@/ui/_common_/sidebar.vue'; import XSidebar from '@/ui/_common_/navbar.vue';
import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import MkButton from '@/components/ui/button.vue'; import MkButton from '@/components/ui/button.vue';
import { getScrollContainer } from '@/scripts/scroll'; import { getScrollContainer } from '@/scripts/scroll';
import * as os from '@/os'; import * as os from '@/os';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { $i } from '@/account'; import { $i } from '@/account';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { mainRouter } from '@/router'; import { mainRouter } from '@/router';
@ -105,8 +105,8 @@ const columns = deckStore.reactiveState.columns;
const layout = deckStore.reactiveState.layout; const layout = deckStore.reactiveState.layout;
const menuIndicated = computed(() => { const menuIndicated = computed(() => {
if ($i == null) return false; if ($i == null) return false;
for (const def in menuDef) { for (const def in navbarItemDef) {
if (menuDef[def].indicated) return true; if (navbarItemDef[def].indicated) return true;
} }
return false; return false;
}); });

View file

@ -61,17 +61,17 @@ import { defineAsyncComponent, provide, onMounted, computed, ref, watch, Compute
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import { instanceName } from '@/config'; import { instanceName } from '@/config';
import { StickySidebar } from '@/scripts/sticky-sidebar'; import { StickySidebar } from '@/scripts/sticky-sidebar';
import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { menuDef } from '@/menu'; import { navbarItemDef } from '@/navbar';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { $i } from '@/account'; import { $i } from '@/account';
import { Router } from '@/nirax'; import { Router } from '@/nirax';
import { mainRouter } from '@/router'; import { mainRouter } from '@/router';
import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata';
const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue'));
const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/sidebar.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue'));
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
const DESKTOP_THRESHOLD = 1100; const DESKTOP_THRESHOLD = 1100;
@ -97,9 +97,9 @@ provideMetadataReceiver((info) => {
}); });
const menuIndicated = computed(() => { const menuIndicated = computed(() => {
for (const def in menuDef) { for (const def in navbarItemDef) {
if (def === 'notifications') continue; // if (def === 'notifications') continue; //
if (menuDef[def].indicated) return true; if (navbarItemDef[def].indicated) return true;
} }
return false; return false;
}); });

View file

@ -6,33 +6,33 @@ import { createFilter, dataToEsm } from '@rollup/pluginutils';
import { RollupJsonOptions } from '@rollup/plugin-json'; import { RollupJsonOptions } from '@rollup/plugin-json';
export default function json5(options: RollupJsonOptions = {}): Plugin { export default function json5(options: RollupJsonOptions = {}): Plugin {
const filter = createFilter(options.include, options.exclude); const filter = createFilter(options.include, options.exclude);
const indent = 'indent' in options ? options.indent : '\t'; const indent = 'indent' in options ? options.indent : '\t';
return { return {
name: 'json5', name: 'json5',
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
transform(json, id) { transform(json, id) {
if (id.slice(-6) !== '.json5' || !filter(id)) return null; if (id.slice(-6) !== '.json5' || !filter(id)) return null;
try { try {
const parsed = JSON5.parse(json); const parsed = JSON5.parse(json);
return { return {
code: dataToEsm(parsed, { code: dataToEsm(parsed, {
preferConst: options.preferConst, preferConst: options.preferConst,
compact: options.compact, compact: options.compact,
namedExports: options.namedExports, namedExports: options.namedExports,
indent indent,
}), }),
map: { mappings: '' } map: { mappings: '' },
}; };
} catch (err) { } catch (err) {
const message = 'Could not parse JSON file'; const message = 'Could not parse JSON file';
const position = parseInt(/[\d]/.exec(err.message)[0], 10); const position = parseInt(/[\d]/.exec(err.message)[0], 10);
this.warn({ message, id, position }); this.warn({ message, id, position });
return null; return null;
} }
} },
}; };
} }