Compare commits

...

11 Commits

Author SHA1 Message Date
Norm f6a5459f91
Merge PR 'client: refactor super-menu component to composition API' (#186)
Reviewed-on: FoundKeyGang/FoundKey#186
2022-10-07 19:50:56 -04:00
Johann150 64e3239566
client: refactor super-menu component to composition API 2022-10-07 11:28:49 +02:00
Johann cee402c591 Translated using Weblate (German)
Currently translated at 100.0% (1366 of 1366 strings)

Translated using Weblate (German)

Currently translated at 100.0% (1366 of 1366 strings)

Translated using Weblate (English)

Currently translated at 99.7% (1363 of 1366 strings)

Co-authored-by: Johann <johann@qwertqwefsday.eu>
Translate-URL: http://translate.akkoma.dev/projects/foundkey/foundkey/de/
Translate-URL: http://translate.akkoma.dev/projects/foundkey/foundkey/en/
Translation: Foundkey/foundkey
2022-10-07 07:39:53 +00:00
Weblate 6a3f8aa4f9 Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/foundkey/foundkey/
Translation: Foundkey/foundkey
2022-10-07 07:39:53 +00:00
Johann150 8311b30b4c
client: fix tolerance for future timestamp 2022-10-07 09:38:44 +02:00
Norm 27cf3c4e05
client: Fix relative timestamps 2022-10-05 02:17:32 -04:00
Norm c20352b22e
backend: update THRESHOLD constants to use time constants 2022-10-05 00:54:16 -04:00
Norm 9084864b34
backend: translate comments in const.ts 2022-10-05 00:52:52 -04:00
Norm def5eb0d2e Merge pull request 'client: remove click-anime directive' (#185) from remove-anime into main 2022-10-05 04:41:32 +00:00
Johann150 f4f83cb091
client: remove click-anime directive 2022-10-04 20:01:14 +02:00
Johann150 93f54e3258
client: refactor components/tab.vue to composition API
Refactoring this component could be done after changing its method of
receiving the list of available tabs by using slots to using an
ordinary parameter. This was possible because all uses of this
component just provided text as the tab labels.

Also removed unused imports of this component.

Also removed the use of the click-anime directive.
2022-10-04 19:54:27 +02:00
18 changed files with 86 additions and 113 deletions

View File

@ -887,7 +887,9 @@ makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktion
classic: "Classic"
muteThread: "Thread stummschalten"
unmuteThread: "Threadstummschaltung aufheben"
threadMuteNotificationsDesc: "Wähle die Benachrichtigungen, die du aus diesem Thread erhalten möchtest. Globale Benachrichtigungs-Einstellungen werden zusätzlich angewandt. Das Deaktivieren einer Benachrichtigung hat Vorrang."
threadMuteNotificationsDesc: "Wähle die Benachrichtigungen, die du aus diesem Thread\
\ erhalten möchtest. Globale Benachrichtigungs-Einstellungen werden zusätzlich angewandt.\
\ Das Deaktivieren einer Benachrichtigung hat Vorrang."
ffVisibility: "Sichtbarkeit von Gefolgten/Followern"
ffVisibilityDescription: "Konfiguriere wer sehen kann, wem du folgst sowie wer dir\
\ folgt."
@ -1558,3 +1560,7 @@ _services:
_github:
connected: GitHub-Account @{login} wurde mit Foundkey-Account @{userName} verknüpft!
disconnected: GitHub-Verknüpfung wurde entfernt.
documentation: Dokumentation
signinHistoryExpires: Frühere Login-Versuche werden aus Datenschutzgründen nach 60
Tagen automatisch gelöscht.
unlimited: Unbegrenzt

View File

@ -479,7 +479,8 @@ youHaveNoGroups: "You have no groups"
joinOrCreateGroup: "Get invited to a group or create your own."
noHistory: "No history available"
signinHistory: "Login history"
signinHistoryExpires: "Data about past login attempts is automatically deleted after 60 days to comply with privacy regulations."
signinHistoryExpires: "Data about past login attempts is automatically deleted after\
\ 60 days to comply with privacy regulations."
disableAnimatedMfm: "Disable MFM with animation"
doing: "Processing..."
category: "Category"
@ -864,7 +865,8 @@ makeReactionsPublicDescription: "This will make the list of all your past reacti
classic: "Classic"
muteThread: "Mute thread"
unmuteThread: "Unmute thread"
threadMuteNotificationsDesc: "Select the notifications you wish to view from this thread. Global notification settings also apply. Disabling takes precedence."
threadMuteNotificationsDesc: "Select the notifications you wish to view from this\
\ thread. Global notification settings also apply. Disabling takes precedence."
ffVisibility: "Follows/Followers Visibility"
ffVisibilityDescription: "Allows you to configure who can see who you follow and who\
\ follows you."

View File

@ -852,8 +852,6 @@ typeToConfirm: "この操作を行うには {x} と入力してください"
deleteAccount: "アカウント削除"
numberOfPageCache: "ページキャッシュ数"
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
document: "ドキュメント"
_emailUnavailable:
used: "既に使用されています"
format: "形式が正しくありません"

View File

@ -1,16 +1,17 @@
export const MAX_NOTE_TEXT_LENGTH = 3000;
// Time constants
export const SECOND = 1000;
export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE;
export const DAY = 24 * HOUR;
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
export const USER_ONLINE_THRESHOLD = 10 * MINUTE;
export const USER_ACTIVE_THRESHOLD = 3 * DAY;
// ブラウザで直接表示することを許可するファイルの種類のリスト
// ここに含まれないものは application/octet-stream としてレスポンスされる
// SVGはXSSを生むので許可しない
// List of file types allowed to be viewed directly in the browser.
// Anything not included here will be reported as application/octet-stream
// SVG is not allowed because it can lead to XSS
export const FILE_TYPE_BROWSERSAFE = [
// Images
'image/png',

View File

@ -52,13 +52,13 @@ const relative = $computed(() => {
if (ago >= HOUR) {
return i18n.t('_ago.hoursAgo', { n: Math.round(ago / HOUR).toString() });
} else if (ago >= MINUTE) {
return i18n.t('_ago.minutesAgo', { n: (~~(ago / MINUTE)).toString() });
return i18n.t('_ago.minutesAgo', { n: Math.floor(ago / MINUTE).toString() });
} else if (ago >= 10 * SECOND) {
return i18n.t('_ago.secondsAgo', { n: (~~(ago % MINUTE)).toString() });
return i18n.t('_ago.secondsAgo', { n: Math.floor(ago / SECOND).toString() });
}
}
if (ago >= -5) {
if (ago >= -5 * SECOND) {
if (props.format === 'date') {
// this is also the catch-all for the formats with hour/minute/second precision
return i18n.ts.today;

View File

@ -3,12 +3,12 @@
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
<div class="main">
<template v-for="item in items">
<button v-if="item.action" v-click-anime class="_button" @click="$event => { item.action($event); close(); }">
<button v-if="item.action" class="_button" @click="$event => { item.action($event); close(); }">
<i class="icon" :class="item.icon"></i>
<div class="text">{{ item.text }}</div>
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
</button>
<MkA v-else v-click-anime :to="item.to" @click.passive="close()">
<MkA v-else :to="item.to" @click.passive="close()">
<i class="icon" :class="item.icon"></i>
<div class="text">{{ item.text }}</div>
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
@ -16,15 +16,15 @@
</template>
</div>
<div class="sub">
<button v-click-anime class="_button" @click="help">
<button class="_button" @click="help">
<i class="fas fa-question-circle icon"></i>
<div class="text">{{ i18n.ts.help }}</div>
</button>
<MkA v-click-anime to="/about" @click.passive="close()">
<MkA to="/about" @click.passive="close()">
<i class="fas fa-info-circle icon"></i>
<div class="text">{{ i18n.ts.instanceInfo }}</div>
</MkA>
<MkA v-click-anime to="/about-foundkey" @click.passive="close()">
<MkA to="/about-foundkey" @click.passive="close()">
<img src="/static-assets/favicon.png" class="icon"/>
<div class="text">{{ i18n.ts.aboutMisskey }}</div>
</MkA>

View File

@ -7,7 +7,7 @@
>
<header>
<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button>
<button v-click-anime v-tooltip="i18n.ts.switchAccount" class="account _button" @click="openAccountMenu">
<button v-tooltip="i18n.ts.switchAccount" class="account _button" @click="openAccountMenu">
<MkAvatar :user="postAccount ?? $i" class="avatar"/>
</button>
<div>

View File

@ -23,21 +23,34 @@
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
type MenuItem = {
text: string;
icon?: string;
danger?: boolean;
active?: boolean;
i?: number;
} & (
{
type: 'a';
href: string;
target?: string;
} | {
type: 'button';
action(MouseEvent): void;
} | {
to: string;
}
);
export default defineComponent({
props: {
def: {
type: Array,
required: true,
},
grid: {
type: Boolean,
required: false,
default: false,
},
},
withDefaults(defineProps<{
def: {
title?: string;
items: MenuItem[];
}[];
grid?: boolean;
}>(), {
grid: false,
});
</script>

View File

@ -1,31 +0,0 @@
import { Directive } from 'vue';
import { defaultStore } from '@/store';
export default {
mounted(el, binding, vn) {
/*
if (!defaultStore.state.animation) return;
el.classList.add('_anime_bounce_standBy');
el.addEventListener('mousedown', () => {
el.classList.add('_anime_bounce_standBy');
el.classList.add('_anime_bounce_ready');
el.addEventListener('mouseleave', () => {
el.classList.remove('_anime_bounce_ready');
});
});
el.addEventListener('click', () => {
el.classList.add('_anime_bounce');
});
el.addEventListener('animationend', () => {
el.classList.remove('_anime_bounce_ready');
el.classList.remove('_anime_bounce');
el.classList.add('_anime_bounce_standBy');
});
*/
},
} as Directive;

View File

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

View File

@ -22,9 +22,9 @@
<MkButton v-else v-tooltip="i18n.ts._gallery.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="post.likedCount > 0" class="count">{{ post.likedCount }}</span></MkButton>
</div>
<div class="other">
<button v-if="$i && $i.id === post.user.id" v-tooltip="i18n.ts.edit" v-click-anime class="_button" @click="edit"><i class="fas fa-pencil-alt fa-fw"></i></button>
<button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button>
<button v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button>
<button v-if="$i && $i.id === post.user.id" v-tooltip="i18n.ts.edit" class="_button" @click="edit"><i class="fas fa-pencil-alt fa-fw"></i></button>
<button v-tooltip="i18n.ts.shareWithNote" class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button>
<button v-tooltip="i18n.ts.share" class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button>
</div>
</div>
<div class="user">

View File

@ -17,8 +17,8 @@
<MkButton v-else v-tooltip="i18n.ts._pages.like" class="button" @click="like()"><i class="far fa-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton>
</div>
<div class="other">
<button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button>
<button v-tooltip="i18n.ts.share" v-click-anime class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button>
<button v-tooltip="i18n.ts.shareWithNote" class="_button" @click="shareWithNote"><i class="fas fa-retweet fa-fw"></i></button>
<button v-tooltip="i18n.ts.share" class="_button" @click="share"><i class="fas fa-share-alt fa-fw"></i></button>
</div>
</div>
<div class="user">

View File

@ -69,15 +69,15 @@
</dl>
</div>
<div class="status">
<MkA v-click-anime :to="userPage(user)" :class="{ active: page === 'index' }">
<MkA :to="userPage(user)" :class="{ active: page === 'index' }">
<b>{{ number(user.notesCount) }}</b>
<span>{{ i18n.ts.notes }}</span>
</MkA>
<MkA v-click-anime :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
<b>{{ number(user.followingCount) }}</b>
<span>{{ i18n.ts.following }}</span>
</MkA>
<MkA v-click-anime :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
<b>{{ number(user.followersCount) }}</b>
<span>{{ i18n.ts.followers }}</span>
</MkA>

View File

@ -515,20 +515,6 @@ hr {
}
}
._anime_bounce {
will-change: transform;
animation: bounce ease 0.7s;
animation-iteration-count: 1;
transform-origin: 50% 50%;
}
._anime_bounce_ready {
will-change: transform;
transform: scaleX(0.90) scaleY(0.90) ;
}
._anime_bounce_standBy {
transition: transform 0.1s ease;
}
@keyframes bounce{
0% {
transform: scaleX(0.90) scaleY(0.90) ;

View File

@ -1,28 +1,28 @@
<template>
<div class="kmwsukvl">
<div>
<button v-click-anime class="item _button account" @click="openAccountMenuWrapper">
<button class="item _button account" @click="openAccountMenuWrapper">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button>
<MkA v-click-anime class="item index" active-class="active" to="/" exact>
<MkA class="item index" active-class="active" to="/" exact>
<i class="fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span>
</MkA>
<template v-for="item in menu" :key="item">
<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="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" 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 } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ i18n.ts[menuDef[item].title] }}</span>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component>
</template>
<div class="divider"></div>
<MkA v-if="iAmModerator" v-click-anime class="item" active-class="active" to="/admin">
<MkA v-if="iAmModerator" class="item" active-class="active" to="/admin">
<i class="fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
</MkA>
<button v-click-anime class="item _button" @click="more">
<button class="item _button" @click="more">
<i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
</button>
<MkA v-click-anime class="item" active-class="active" to="/settings">
<MkA class="item" active-class="active" to="/settings">
<i class="fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span>
</MkA>
<button class="item _button post" data-cy-open-post-form @click="post">

View File

@ -1,28 +1,28 @@
<template>
<div class="mvcprjjd" :class="{ iconOnly }">
<div>
<button v-click-anime class="item _button account" @click="openAccountMenu">
<button class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button>
<MkA v-click-anime class="item index" active-class="active" to="/" exact>
<MkA class="item index" active-class="active" to="/" exact>
<i class="fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span>
</MkA>
<template v-for="item in menu">
<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="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" 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 } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ i18n.ts[menuDef[item].title] }}</span>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component>
</template>
<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" class="item" active-class="active" to="/admin">
<i class="fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
</MkA>
<button v-click-anime class="item _button" @click="more">
<button class="item _button" @click="more">
<i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
</button>
<MkA v-click-anime class="item" active-class="active" to="/settings">
<MkA class="item" active-class="active" to="/settings">
<i class="fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span>
</MkA>
<button class="item _button post" data-cy-open-post-form @click="os.post">

View File

@ -2,30 +2,30 @@
<div class="azykntjl">
<div class="body">
<div class="left">
<MkA v-click-anime v-tooltip="i18n.ts.timeline" class="item index" active-class="active" to="/" exact>
<MkA v-tooltip="i18n.ts.timeline" class="item index" active-class="active" to="/" exact>
<i class="fas fa-home fa-fw"></i>
</MkA>
<template v-for="item in menu">
<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="i18n.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="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-tooltip="i18n.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 } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component>
</template>
<div class="divider"></div>
<MkA v-if="iAmModerator" v-click-anime v-tooltip="i18n.ts.controlPanel" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null">
<MkA v-if="iAmModerator" v-tooltip="i18n.ts.controlPanel" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null">
<i class="fas fa-door-open fa-fw"></i>
</MkA>
<button v-click-anime class="item _button" @click="more">
<button class="item _button" @click="more">
<i class="fas fa-ellipsis-h fa-fw"></i>
<span v-if="otherNavItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
</button>
</div>
<div class="right">
<MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null">
<MkA v-tooltip="i18n.ts.settings" class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null">
<i class="fas fa-cog fa-fw"></i>
</MkA>
<button v-click-anime class="item _button account" @click="openAccountMenuWrapper">
<button class="item _button account" @click="openAccountMenuWrapper">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="acct" :user="$i"/>
</button>
<div class="post" @click="post">

View File

@ -1,6 +1,6 @@
<template>
<div ref="sidebar" class="npcljfve" :class="{ iconOnly }">
<button v-if="$i" v-click-anime class="item _button account" @click="openAccountMenuWrapper">
<button v-if="$i" class="item _button account" @click="openAccountMenuWrapper">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button>
<div class="post" data-cy-open-post-form @click="() => { os.post(); }">
@ -9,30 +9,30 @@
</MkButton>
</div>
<div class="divider"></div>
<MkA v-click-anime class="item index" active-class="active" to="/" exact>
<MkA class="item index" active-class="active" to="/" exact>
<i class="fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span>
</MkA>
<template v-for="item in menu">
<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="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" class="item _button" :class="item" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}">
<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ i18n.ts[menuDef[item].title] }}</span>
<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
</component>
</template>
<div class="divider"></div>
<MkA v-if="iAmModerator" v-click-anime class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null">
<MkA v-if="iAmModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null">
<i class="fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span>
</MkA>
<button v-click-anime class="item _button" @click="more">
<button class="item _button" @click="more">
<i class="fas fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span>
<span v-if="otherNavItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
</button>
<MkA v-click-anime class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null">
<MkA class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null">
<i class="fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span>
</MkA>
<div class="divider"></div>
<div class="about">
<MkA v-click-anime class="link" to="/about">
<MkA class="link" to="/about">
<img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" class="_ghost"/>
</MkA>
</div>