Storage improve (#6976)

* wip

* wip

* wip

* wip

* wip

* Update storage.ts

* wip

* wip

* wip

* wip

* Update storage.ts

* Update storage.ts

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update storage.ts

* wip

* wip

* wip

* wip

* 🍕

* wip

* wip

* wip

* wip

* wip

* wip

* Update deck-storage.ts

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update store.ts

* wip

* wip

* wip

* wip

* Update init.ts

* wip

* wip

* Update pizzax.ts

* wip

* wip

* Update timeline.vue

* Update init.ts

* wip

* wip

* Update init.ts
This commit is contained in:
syuilo 2020-12-19 10:55:52 +09:00 committed by GitHub
parent 57d0c19a98
commit 43930e6a84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
146 changed files with 1458 additions and 1519 deletions

View file

@ -251,8 +251,6 @@
"vue-router": "4.0.1", "vue-router": "4.0.1",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
"vuedraggable": "4.0.1", "vuedraggable": "4.0.1",
"vuex": "4.0.0-rc.2",
"vuex-persistedstate": "3.1.0",
"web-push": "3.4.4", "web-push": "3.4.4",
"webpack": "5.10.1", "webpack": "5.10.1",
"webpack-cli": "4.2.0", "webpack-cli": "4.2.0",

View file

@ -1,12 +0,0 @@
import { ComponentCustomProperties } from 'vue';
import { Store } from 'vuex';
declare module '@vue/runtime-core' {
// tslint:disable-next-line:no-empty-interface
interface State {
}
interface ComponentCustomProperties {
$store: Store<State>;
}
}

86
src/client/account.ts Normal file
View file

@ -0,0 +1,86 @@
import { reactive } from 'vue';
import { apiUrl } from '@/config';
import { waiting } from '@/os';
// TODO: 他のタブと永続化されたstateを同期
type Account = {
id: string;
token: string;
clientData: Record<string, any>;
};
const data = localStorage.getItem('account');
// TODO: 外部からはreadonlyに
export const $i = data ? reactive(JSON.parse(data) as Account) : null;
export function signout() {
localStorage.removeItem('account');
document.cookie = `igi=; path=/`;
location.href = '/';
}
export function getAccounts() {
const accountsData = localStorage.getItem('accounts');
const accounts: { id: Account['id'], token: Account['token'] }[] = accountsData ? JSON.parse(accountsData) : [];
return accounts;
}
export function addAccount(id: Account['id'], token: Account['token']) {
const accounts = getAccounts();
if (!accounts.some(x => x.id === id)) {
localStorage.setItem('accounts', JSON.stringify(accounts.concat([{ id, token }])));
}
}
function fetchAccount(token): Promise<Account> {
return new Promise((done, fail) => {
// Fetch user
fetch(`${apiUrl}/i`, {
method: 'POST',
body: JSON.stringify({
i: token
})
})
.then(res => {
// When failed to authenticate user
if (res.status !== 200 && res.status < 500) {
return signout();
}
// Parse response
res.json().then(i => {
i.token = token;
done(i);
});
})
.catch(fail);
});
}
export function updateAccount(data) {
for (const [key, value] of Object.entries(data)) {
$i[key] = value;
}
}
export function refreshAccount() {
fetchAccount($i.token).then(updateAccount);
}
export async function login(token: Account['token']) {
waiting();
if (_DEV_) console.log('logging as token ', token);
const me = await fetchAccount(token);
localStorage.setItem('account', JSON.stringify(me));
addAccount(me.id, token);
location.reload();
}
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$i: typeof $i;
}
}

View file

@ -1,34 +0,0 @@
// 常にメモリにロードしておく必要がないような設定情報を保管するストレージ
const PREFIX = 'miux:';
export const defaultDeviceSettings = {
sound_masterVolume: 0.3,
sound_note: { type: 'syuilo/down', volume: 1 },
sound_noteMy: { type: 'syuilo/up', volume: 1 },
sound_notification: { type: 'syuilo/pope2', volume: 1 },
sound_chat: { type: 'syuilo/pope1', volume: 1 },
sound_chatBg: { type: 'syuilo/waon', volume: 1 },
sound_antenna: { type: 'syuilo/triple', volume: 1 },
sound_channel: { type: 'syuilo/square-pico', volume: 1 },
sound_reversiPutBlack: { type: 'syuilo/kick', volume: 0.3 },
sound_reversiPutWhite: { type: 'syuilo/snare', volume: 0.3 },
};
export const device = {
get<T extends keyof typeof defaultDeviceSettings>(key: T): typeof defaultDeviceSettings[T] {
// TODO: indexedDBにする
// ただしその際はnullチェックではなくキー存在チェックにしないとダメ
// (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
const value = localStorage.getItem(PREFIX + key);
if (value == null) {
return defaultDeviceSettings[key];
} else {
return JSON.parse(value);
}
},
set(key: keyof typeof defaultDeviceSettings, value: any): any {
localStorage.setItem(PREFIX + key, JSON.stringify(value));
},
};

View file

@ -116,16 +116,6 @@ export default defineComponent({
} }
}; };
update(); update();
this.$store.subscribe((mutation, state) => {
if (mutation.type !== 'device/set') return;
if (mutation?.payload?.key !== 'theme') return;
setTimeout(() => {
this.computedStyle = getComputedStyle(document.documentElement);
}, 250);
});
}, },
beforeUnmount() { beforeUnmount() {

View file

@ -17,8 +17,8 @@
</ol> </ol>
<ol class="emojis" ref="suggests" v-if="emojis.length > 0"> <ol class="emojis" ref="suggests" v-if="emojis.length > 0">
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1"> <li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
<span class="emoji" v-if="emoji.isCustomEmoji"><img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span> <span class="emoji" v-if="emoji.isCustomEmoji"><img :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else-if="!useOsNativeEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span> <span class="emoji" v-else-if="!$store.state.useOsNativeEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else>{{ emoji.emoji }}</span> <span class="emoji" v-else>{{ emoji.emoji }}</span>
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span> <span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span> <span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
@ -128,12 +128,6 @@ export default defineComponent({
} }
}, },
computed: {
useOsNativeEmojis(): boolean {
return this.$store.state.device.useOsNativeEmojis;
}
},
watch: { watch: {
showing() { showing() {
if (!this.showing) { if (!this.showing) {
@ -151,7 +145,7 @@ export default defineComponent({
this.setPosition(); this.setPosition();
//#region Construct Emoji DB //#region Construct Emoji DB
const customEmojis = this.$store.state.instance.meta.emojis; const customEmojis = this.$instance.emojis;
const emojiDefinitions: EmojiDef[] = []; const emojiDefinitions: EmojiDef[] = [];
for (const x of customEmojis) { for (const x of customEmojis) {

View file

@ -28,7 +28,6 @@ declare global {
interface Window extends CaptchaContainer { interface Window extends CaptchaContainer {
} }
} }
import * as os from '@/os';
export default defineComponent({ export default defineComponent({
props: { props: {
@ -101,7 +100,7 @@ export default defineComponent({
if (this.captcha.render && this.$refs.captcha instanceof Element) { if (this.captcha.render && this.$refs.captcha instanceof Element) {
this.captcha.render(this.$refs.captcha, { this.captcha.render(this.$refs.captcha, {
sitekey: this.sitekey, sitekey: this.sitekey,
theme: this.$store.state.device.darkMode ? 'dark' : 'light', theme: this.$store.state.darkMode ? 'dark' : 'light',
callback: this.callback, callback: this.callback,
'expired-callback': this.callback, 'expired-callback': this.callback,
'error-callback': this.callback, 'error-callback': this.callback,

View file

@ -37,12 +37,14 @@ export default defineComponent({
}); });
} }
return h(this.$store.state.device.animation ? TransitionGroup : 'div', { return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? {
class: 'sqadhkmv _list_', class: 'sqadhkmv _list_',
name: 'list', name: 'list',
tag: 'div', tag: 'div',
'data-direction': this.direction, 'data-direction': this.direction,
'data-reversed': this.reversed ? 'true' : 'false', 'data-reversed': this.reversed ? 'true' : 'false',
} : {
class: 'sqadhkmv _list_',
}, this.items.map((item, i) => { }, this.items.map((item, i) => {
const el = this.$slots.default({ const el = this.$slots.default({
item: item item: item

View file

@ -27,6 +27,7 @@ import {
faFilm faFilm
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import ImgWithBlurhash from './img-with-blurhash.vue'; import ImgWithBlurhash from './img-with-blurhash.vue';
import { ColdDeviceStorage } from '@/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -89,12 +90,12 @@ export default defineComponent({
}, },
mounted() { mounted() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement; const audioTag = this.$refs.volumectrl as HTMLAudioElement;
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume; if (audioTag) audioTag.volume = ColdDeviceStorage.get('mediaVolume');
}, },
methods: { methods: {
volumechange() { volumechange() {
const audioTag = this.$refs.volumectrl as HTMLAudioElement; const audioTag = this.$refs.volumectrl as HTMLAudioElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume }); ColdDeviceStorage.set('mediaVolume', audioTag.volume);
} }
} }
}); });

View file

@ -8,11 +8,11 @@
@dragend="onDragend" @dragend="onDragend"
:title="title" :title="title"
> >
<div class="label" v-if="$store.state.i.avatarId == file.id"> <div class="label" v-if="$i.avatarId == file.id">
<img src="/assets/label.svg"/> <img src="/assets/label.svg"/>
<p>{{ $t('avatar') }}</p> <p>{{ $t('avatar') }}</p>
</div> </div>
<div class="label" v-if="$store.state.i.bannerId == file.id"> <div class="label" v-if="$i.bannerId == file.id">
<img src="/assets/label.svg"/> <img src="/assets/label.svg"/>
<p>{{ $t('banner') }}</p> <p>{{ $t('banner') }}</p>
</div> </div>

View file

@ -19,7 +19,7 @@
<template v-if="!hover"><Fa :icon="faFolder" fixed-width/></template> <template v-if="!hover"><Fa :icon="faFolder" fixed-width/></template>
{{ folder.name }} {{ folder.name }}
</p> </p>
<p class="upload" v-if="$store.state.settings.uploadFolder == folder.id"> <p class="upload" v-if="$store.state.uploadFolder == folder.id">
{{ $t('uploadFolder') }} {{ $t('uploadFolder') }}
</p> </p>
<button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button> <button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button>
@ -213,11 +213,8 @@ export default defineComponent({
os.api('drive/folders/delete', { os.api('drive/folders/delete', {
folderId: this.folder.id folderId: this.folder.id
}).then(() => { }).then(() => {
if (this.$store.state.settings.uploadFolder === this.folder.id) { if (this.$store.state.uploadFolder === this.folder.id) {
this.$store.dispatch('settings/set', { this.$store.set('uploadFolder', null);
key: 'uploadFolder',
value: null
});
} }
}).catch(err => { }).catch(err => {
switch(err.id) { switch(err.id) {
@ -238,10 +235,7 @@ export default defineComponent({
}, },
setAsUploadFolder() { setAsUploadFolder() {
this.$store.dispatch('settings/set', { this.$store.set('uploadFolder', this.folder.id);
key: 'uploadFolder',
value: this.folder.id
});
}, },
onContextmenu(e) { onContextmenu(e) {

View file

@ -136,7 +136,7 @@ export default defineComponent({
}, },
mounted() { mounted() {
if (this.$store.state.device.enableInfiniteScroll && this.$refs.loadMoreFiles) { if (this.$store.state.enableInfiniteScroll && this.$refs.loadMoreFiles) {
this.$nextTick(() => { this.$nextTick(() => {
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el) this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
}); });
@ -159,7 +159,7 @@ export default defineComponent({
}, },
activated() { activated() {
if (this.$store.state.device.enableInfiniteScroll) { if (this.$store.state.enableInfiniteScroll) {
this.$nextTick(() => { this.$nextTick(() => {
this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el) this.ilFilesObserver.observe((this.$refs.loadMoreFiles as Vue).$el)
}); });

View file

@ -13,7 +13,7 @@
tabindex="0" tabindex="0"
> >
<MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/> <MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/>
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/> <img v-else :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button> </button>
</div> </div>
<div v-if="searchResultUnicode.length > 0"> <div v-if="searchResultUnicode.length > 0">
@ -45,7 +45,7 @@
<section> <section>
<header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $t('recentUsed') }}</header> <header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $t('recentUsed') }}</header>
<div> <div>
<button v-for="emoji in $store.state.device.recentlyUsedEmojis" <button v-for="emoji in $store.state.recentlyUsedEmojis"
class="_button" class="_button"
@click="chosen(emoji, $event)" @click="chosen(emoji, $event)"
:key="emoji" :key="emoji"
@ -67,7 +67,7 @@
@click="chosen(emoji, $event)" @click="chosen(emoji, $event)"
:key="emoji.name" :key="emoji.name"
> >
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/> <img :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
</button> </button>
</div> </div>
</section> </section>
@ -100,6 +100,7 @@ import MkModal from '@/components/ui/modal.vue';
import Particle from '@/components/particle.vue'; import Particle from '@/components/particle.vue';
import * as os from '@/os'; import * as os from '@/os';
import { isDeviceTouch } from '../scripts/is-device-touch'; import { isDeviceTouch } from '../scripts/is-device-touch';
import { emojiCategories } from '@/instance';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -125,12 +126,12 @@ export default defineComponent({
return { return {
emojilist: markRaw(emojilist), emojilist: markRaw(emojilist),
getStaticImageUrl, getStaticImageUrl,
pinned: this.$store.state.settings.reactions, pinned: this.$store.state.reactions,
width: this.asReactionPicker ? this.$store.state.device.reactionPickerWidth : 3, width: this.asReactionPicker ? this.$store.state.reactionPickerWidth : 3,
height: this.asReactionPicker ? this.$store.state.device.reactionPickerHeight : 2, height: this.asReactionPicker ? this.$store.state.reactionPickerHeight : 2,
big: this.asReactionPicker ? isDeviceTouch : false, big: this.asReactionPicker ? isDeviceTouch : false,
customEmojiCategories: this.$store.getters['instance/emojiCategories'], customEmojiCategories: emojiCategories,
customEmojis: this.$store.state.instance.meta.emojis, customEmojis: this.$instance.emojis,
visibleCategories: {}, visibleCategories: {},
q: null, q: null,
searchResultCustom: [], searchResultCustom: [],
@ -346,10 +347,10 @@ export default defineComponent({
// 使 // 使
if (!this.pinned.includes(key)) { if (!this.pinned.includes(key)) {
let recents = this.$store.state.device.recentlyUsedEmojis; let recents = this.$store.state.recentlyUsedEmojis;
recents = recents.filter((e: any) => e !== key); recents = recents.filter((e: any) => e !== key);
recents.unshift(key); recents.unshift(key);
this.$store.commit('device/set', { key: 'recentlyUsedEmojis', value: recents.splice(0, 16) }); this.$store.set('recentlyUsedEmojis', recents.splice(0, 16));
} }
}, },

View file

@ -12,6 +12,7 @@
._formLabel { ._formLabel {
font-size: 80%; font-size: 80%;
padding: 0 16px 8px 16px; padding: 0 16px 8px 16px;
opacity: 0.8;
&:empty { &:empty {
display: none; display: none;
@ -21,6 +22,7 @@
._formCaption { ._formCaption {
font-size: 80%; font-size: 80%;
padding: 8px 16px 0 16px; padding: 8px 16px 0 16px;
opacity: 0.8;
&:empty { &:empty {
display: none; display: none;

View file

@ -12,6 +12,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { router } from '@/router'; import { router } from '@/router';
import { ui, url } from '@/config'; import { ui, url } from '@/config';
import { popout } from '@/scripts/popout'; import { popout } from '@/scripts/popout';
import { ColdDeviceStorage } from '@/store';
export default defineComponent({ export default defineComponent({
inject: { inject: {
@ -98,8 +99,8 @@ export default defineComponent({
nav() { nav() {
if (this.to.startsWith('/my/messaging')) { if (this.to.startsWith('/my/messaging')) {
if (this.$store.state.device.chatOpenBehavior === 'window') return this.window(); if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
if (this.$store.state.device.chatOpenBehavior === 'popout') return this.popout(); if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();
} }
if (this.behavior) { if (this.behavior) {
@ -111,12 +112,13 @@ export default defineComponent({
if (this.navHook) { if (this.navHook) {
this.navHook(this.to); this.navHook(this.to);
} else { } else {
if (this.$store.state.device.defaultSideView && this.sideViewHook && this.to !== '/') { if (this.$store.state.defaultSideView && this.sideViewHook && this.to !== '/') {
return this.sideViewHook(this.to); return this.sideViewHook(this.to);
} }
if (this.$store.state.device.deckNavWindow && (ui === 'deck') && this.to !== '/') { // TODO: a.vuedeck-sotre
return this.window(); //if (deckStore.state.device.deckNavWindow && (ui === 'deck') && this.to !== '/') {
} // return this.window();
//}
if (ui === 'desktop') { if (ui === 'desktop') {
return this.window(); return this.window();
} }

View file

@ -1,7 +1,7 @@
<template> <template>
<span class="mk-acct" v-once> <span class="mk-acct" v-once>
<span class="name">@{{ user.username }}</span> <span class="name">@{{ user.username }}</span>
<span class="host" v-if="user.host || detail || $store.state.settings.showFullAcct">@{{ user.host || host }}</span> <span class="host" v-if="user.host || detail || $store.state.showFullAcct">@{{ user.host || host }}</span>
</span> </span>
</template> </template>

View file

@ -38,7 +38,7 @@ export default defineComponent({
return this.user.isCat; return this.user.isCat;
}, },
url(): string { url(): string {
return this.$store.state.device.disableShowingAnimatedImages return this.$store.state.disableShowingAnimatedImages
? getStaticImageUrl(this.user.avatarUrl) ? getStaticImageUrl(this.user.avatarUrl)
: this.user.avatarUrl; : this.user.avatarUrl;
}, },

View file

@ -54,13 +54,13 @@ export default defineComponent({
}, },
useOsNativeEmojis(): boolean { useOsNativeEmojis(): boolean {
return this.$store.state.device.useOsNativeEmojis && !this.isReaction; return this.$store.state.useOsNativeEmojis && !this.isReaction;
}, },
ce() { ce() {
let ce = []; let ce = [];
if (this.customEmojis) ce = ce.concat(this.customEmojis); if (this.customEmojis) ce = ce.concat(this.customEmojis);
if (this.$store.state.instance.meta && this.$store.state.instance.meta.emojis) ce = ce.concat(this.$store.state.instance.meta.emojis); if (this.$instance && this.$instance.emojis) ce = ce.concat(this.$instance.emojis);
return ce; return ce;
} }
}, },
@ -72,7 +72,7 @@ export default defineComponent({
const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2)); const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
if (customEmoji) { if (customEmoji) {
this.customEmoji = customEmoji; this.customEmoji = customEmoji;
this.url = this.$store.state.device.disableShowingAnimatedImages this.url = this.$store.state.disableShowingAnimatedImages
? getStaticImageUrl(customEmoji.url) ? getStaticImageUrl(customEmoji.url)
: customEmoji.url; : customEmoji.url;
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.device.animation ? 'zoom' : ''" appear> <transition :name="$store.state.animation ? 'zoom' : ''" appear>
<div class="mjndxjcg"> <div class="mjndxjcg">
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
<p><Fa :icon="faExclamationTriangle"/> {{ $t('somethingHappened') }}</p> <p><Fa :icon="faExclamationTriangle"/> {{ $t('somethingHappened') }}</p>

View file

@ -23,7 +23,7 @@ export default defineComponent({
}, },
methods: { methods: {
search() { search() {
const engine = this.$store.state.settings.webSearchEngine || const engine = this.$store.state.webSearchEngine ||
'https://www.google.com/search?q={{query}}'; 'https://www.google.com/search?q={{query}}';
const url = engine.replace('{{query}}', this.query) const url = engine.replace('{{query}}', this.query)
window.open(url, '_blank'); window.open(url, '_blank');

View file

@ -278,7 +278,7 @@ export default defineComponent({
} }
// TODO: var(--panel) // TODO: var(--panel)
const gridColor = this.$store.state.device.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; const gridColor = this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg'); Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg');
this.chartInstance = markRaw(new Chart(this.$refs.chart, { this.chartInstance = markRaw(new Chart(this.$refs.chart, {

View file

@ -58,7 +58,7 @@ export default defineComponent({
computed: { computed: {
menu(): string[] { menu(): string[] {
return this.$store.state.deviceUser.menu; return this.$store.state.menu;
}, },
}, },

View file

@ -29,6 +29,7 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import * as os from '@/os'; import * as os from '@/os';
import { ColdDeviceStorage } from '@/store';
export default defineComponent({ export default defineComponent({
props: { props: {
@ -45,12 +46,12 @@ export default defineComponent({
}, },
mounted() { mounted() {
const audioTag = this.$refs.audio as HTMLAudioElement; const audioTag = this.$refs.audio as HTMLAudioElement;
if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume; if (audioTag) audioTag.volume = ColdDeviceStorage.get('mediaVolume');
}, },
methods: { methods: {
volumechange() { volumechange() {
const audioTag = this.$refs.audio as HTMLAudioElement; const audioTag = this.$refs.audio as HTMLAudioElement;
this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume }); ColdDeviceStorage.set('mediaVolume', audioTag.volume);
}, },
}, },
}) })

View file

@ -52,13 +52,11 @@ export default defineComponent({
}, },
computed: { computed: {
url(): any { url(): any {
let url = this.$store.state.device.disableShowingAnimatedImages let url = this.$store.state.disableShowingAnimatedImages
? getStaticImageUrl(this.image.thumbnailUrl) ? getStaticImageUrl(this.image.thumbnailUrl)
: this.image.thumbnailUrl; : this.image.thumbnailUrl;
if (this.$store.state.device.loadRemoteMedia) { if (this.raw || this.$store.state.loadRawImages) {
url = null;
} else if (this.raw || this.$store.state.device.loadRawImages) {
url = this.image.url; url = this.image.url;
} }
@ -68,7 +66,7 @@ export default defineComponent({
created() { created() {
// Plugin:register_note_view_interruptor 使watch // Plugin:register_note_view_interruptor 使watch
this.$watch('image', () => { this.$watch('image', () => {
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.image.isSensitive && (this.$store.state.device.nsfw !== 'ignore'); this.hide = (this.$store.state.nsfw === 'force') ? true : this.image.isSensitive && (this.$store.state.nsfw !== 'ignore');
if (this.image.blurhash) { if (this.image.blurhash) {
this.color = extractAvgColorFromBlurhash(this.image.blurhash); this.color = extractAvgColorFromBlurhash(this.image.blurhash);
} }
@ -79,7 +77,7 @@ export default defineComponent({
}, },
methods: { methods: {
onClick() { onClick() {
if (this.$store.state.device.imageNewTab) { if (this.$store.state.imageNewTab) {
window.open(this.image.url, '_blank'); window.open(this.image.url, '_blank');
} else { } else {
os.popup(ImageViewer, { os.popup(ImageViewer, {

View file

@ -48,7 +48,7 @@ export default defineComponent({
} }
}, },
created() { created() {
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.video.isSensitive && (this.$store.state.device.nsfw !== 'ignore'); this.hide = (this.$store.state.nsfw === 'force') ? true : this.video.isSensitive && (this.$store.state.nsfw !== 'ignore');
}, },
}); });
</script> </script>

View file

@ -3,7 +3,7 @@
<span class="me" v-if="isMe">{{ $t('you') }}</span> <span class="me" v-if="isMe">{{ $t('you') }}</span>
<span class="main"> <span class="main">
<span class="username">@{{ username }}</span> <span class="username">@{{ username }}</span>
<span class="host" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span> <span class="host" v-if="(host != localHost) || $store.state.showFullAcct">@{{ toUnicode(host) }}</span>
</span> </span>
</MkA> </MkA>
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else> <a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
@ -50,8 +50,8 @@ export default defineComponent({
return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`; return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`;
}, },
isMe(): boolean { isMe(): boolean {
return this.$store.getters.isSignedIn && ( return this.$i && (
`@${this.username}@${toUnicode(this.host)}` === `@${this.$store.state.i.username}@${toUnicode(localHost)}`.toLowerCase() `@${this.username}@${toUnicode(this.host)}` === `@${this.$i.username}@${toUnicode(localHost)}`.toLowerCase()
); );
} }
}, },

View file

@ -82,22 +82,22 @@ export default defineComponent({
let style; let style;
switch (token.node.props.name) { switch (token.node.props.name) {
case 'tada': { case 'tada': {
style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : ''); style = `font-size: 150%;` + (this.$store.state.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
break; break;
} }
case 'jelly': { case 'jelly': {
const speed = token.node.props.args.speed || '1s'; const speed = token.node.props.args.speed || '1s';
style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); style = (this.$store.state.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
break; break;
} }
case 'twitch': { case 'twitch': {
const speed = token.node.props.args.speed || '0.5s'; const speed = token.node.props.args.speed || '0.5s';
style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : ''; style = this.$store.state.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
break; break;
} }
case 'shake': { case 'shake': {
const speed = token.node.props.args.speed || '0.5s'; const speed = token.node.props.args.speed || '0.5s';
style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : ''; style = this.$store.state.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
break; break;
} }
case 'spin': { case 'spin': {
@ -110,15 +110,15 @@ export default defineComponent({
token.node.props.args.y ? 'mfm-spinY' : token.node.props.args.y ? 'mfm-spinY' :
'mfm-spin'; 'mfm-spin';
const speed = token.node.props.args.speed || '1.5s'; const speed = token.node.props.args.speed || '1.5s';
style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; style = this.$store.state.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
break; break;
} }
case 'jump': { case 'jump': {
style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : ''; style = this.$store.state.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
break; break;
} }
case 'bounce': { case 'bounce': {
style = this.$store.state.device.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : ''; style = this.$store.state.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
break; break;
} }
case 'flip': { case 'flip': {

View file

@ -6,7 +6,7 @@
<XNoteHeader class="header" :note="note" :mini="true"/> <XNoteHeader class="header" :note="note" :mini="true"/>
<div class="body"> <div class="body">
<p v-if="note.cw != null" class="cw"> <p v-if="note.cw != null" class="cw">
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis" /> <Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis" />
<XCwButton v-model:value="showContent" :note="note"/> <XCwButton v-model:value="showContent" :note="note"/>
</p> </p>
<div class="content" v-show="note.cw == null || showContent"> <div class="content" v-show="note.cw == null || showContent">

View file

@ -43,14 +43,14 @@
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/> <MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
<div class="body"> <div class="body">
<p v-if="appearNote.cw != null" class="cw"> <p v-if="appearNote.cw != null" class="cw">
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/> <Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<XCwButton v-model:value="showContent" :note="appearNote"/> <XCwButton v-model:value="showContent" :note="appearNote"/>
</p> </p>
<div class="content" v-show="appearNote.cw == null || showContent"> <div class="content" v-show="appearNote.cw == null || showContent">
<div class="text"> <div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA> <MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote != null">RN:</a> <a class="rp" v-if="appearNote.renote != null">RN:</a>
</div> </div>
<div class="files" v-if="appearNote.files.length > 0"> <div class="files" v-if="appearNote.files.length > 0">
@ -182,7 +182,7 @@ export default defineComponent({
computed: { computed: {
rs() { rs() {
return this.$store.state.settings.reactions; return this.$store.state.reactions;
}, },
keymap(): any { keymap(): any {
return { return {
@ -222,11 +222,11 @@ export default defineComponent({
}, },
isMyNote(): boolean { isMyNote(): boolean {
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.appearNote.userId); return this.$i && (this.$i.id === this.appearNote.userId);
}, },
isMyRenote(): boolean { isMyRenote(): boolean {
return this.$store.getters.isSignedIn && (this.$store.state.i.id === this.note.userId); return this.$i && (this.$i.id === this.note.userId);
}, },
canRenote(): boolean { canRenote(): boolean {
@ -262,14 +262,14 @@ export default defineComponent({
}, },
showTicker() { showTicker() {
if (this.$store.state.device.instanceTicker === 'always') return true; if (this.$store.state.instanceTicker === 'always') return true;
if (this.$store.state.device.instanceTicker === 'remote' && this.appearNote.user.instance) return true; if (this.$store.state.instanceTicker === 'remote' && this.appearNote.user.instance) return true;
return false; return false;
} }
}, },
async created() { async created() {
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection = os.stream; this.connection = os.stream;
} }
@ -282,7 +282,7 @@ export default defineComponent({
this.$emit('update:note', Object.freeze(result)); this.$emit('update:note', Object.freeze(result));
} }
this.muted = await checkWordMute(this.appearNote, this.$store.state.i, this.$store.state.settings.mutedWords); this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords);
if (this.detail) { if (this.detail) {
os.api('notes/children', { os.api('notes/children', {
@ -305,7 +305,7 @@ export default defineComponent({
mounted() { mounted() {
this.capture(true); this.capture(true);
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection.on('_connected_', this.onStreamConnected); this.connection.on('_connected_', this.onStreamConnected);
} }
}, },
@ -313,7 +313,7 @@ export default defineComponent({
beforeUnmount() { beforeUnmount() {
this.decapture(true); this.decapture(true);
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection.off('_connected_', this.onStreamConnected); this.connection.off('_connected_', this.onStreamConnected);
} }
}, },
@ -340,14 +340,14 @@ export default defineComponent({
}, },
capture(withHandler = false) { capture(withHandler = false) {
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id }); this.connection.send(document.body.contains(this.$el) ? 'sn' : 's', { id: this.appearNote.id });
if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated);
} }
}, },
decapture(withHandler = false) { decapture(withHandler = false) {
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection.send('un', { this.connection.send('un', {
id: this.appearNote.id id: this.appearNote.id
}); });
@ -389,7 +389,7 @@ export default defineComponent({
[reaction]: currentCount + 1 [reaction]: currentCount + 1
}; };
if (body.userId === this.$store.state.i.id) { if (body.userId === this.$i.id) {
n.myReaction = reaction; n.myReaction = reaction;
} }
@ -414,7 +414,7 @@ export default defineComponent({
[reaction]: Math.max(0, currentCount - 1) [reaction]: Math.max(0, currentCount - 1)
}; };
if (body.userId === this.$store.state.i.id) { if (body.userId === this.$i.id) {
n.myReaction = null; n.myReaction = null;
} }
@ -434,7 +434,7 @@ export default defineComponent({
choices[choice] = { choices[choice] = {
...choices[choice], ...choices[choice],
votes: choices[choice].votes + 1, votes: choices[choice].votes + 1,
...(body.userId === this.$store.state.i.id ? { ...(body.userId === this.$i.id ? {
isVoted: true isVoted: true
} : {}) } : {})
}; };
@ -614,7 +614,7 @@ export default defineComponent({
getMenu() { getMenu() {
let menu; let menu;
if (this.$store.getters.isSignedIn) { if (this.$i) {
const statePromise = os.api('notes/state', { const statePromise = os.api('notes/state', {
noteId: this.appearNote.id noteId: this.appearNote.id
}); });
@ -649,7 +649,7 @@ export default defineComponent({
text: this.$t('clip'), text: this.$t('clip'),
action: () => this.clip() action: () => this.clip()
}, },
(this.appearNote.userId != this.$store.state.i.id) ? statePromise.then(state => state.isWatching ? { (this.appearNote.userId != this.$i.id) ? statePromise.then(state => state.isWatching ? {
icon: faEyeSlash, icon: faEyeSlash,
text: this.$t('unwatch'), text: this.$t('unwatch'),
action: () => this.toggleWatch(false) action: () => this.toggleWatch(false)
@ -658,7 +658,7 @@ export default defineComponent({
text: this.$t('watch'), text: this.$t('watch'),
action: () => this.toggleWatch(true) action: () => this.toggleWatch(true)
}) : undefined, }) : undefined,
this.appearNote.userId == this.$store.state.i.id ? (this.$store.state.i.pinnedNoteIds || []).includes(this.appearNote.id) ? { this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
icon: faThumbtack, icon: faThumbtack,
text: this.$t('unpin'), text: this.$t('unpin'),
action: () => this.togglePin(false) action: () => this.togglePin(false)
@ -667,7 +667,7 @@ export default defineComponent({
text: this.$t('pin'), text: this.$t('pin'),
action: () => this.togglePin(true) action: () => this.togglePin(true)
} : undefined, } : undefined,
...(this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [ ...(this.$i.isModerator || this.$i.isAdmin ? [
null, null,
{ {
icon: faBullhorn, icon: faBullhorn,
@ -676,7 +676,7 @@ export default defineComponent({
}] }]
: [] : []
), ),
...(this.appearNote.userId != this.$store.state.i.id ? [ ...(this.appearNote.userId != this.$i.id ? [
null, null,
{ {
icon: faExclamationCircle, icon: faExclamationCircle,
@ -691,9 +691,9 @@ export default defineComponent({
}] }]
: [] : []
), ),
...(this.appearNote.userId == this.$store.state.i.id || this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [ ...(this.appearNote.userId == this.$i.id || this.$i.isModerator || this.$i.isAdmin ? [
null, null,
this.appearNote.userId == this.$store.state.i.id ? { this.appearNote.userId == this.$i.id ? {
icon: faEdit, icon: faEdit,
text: this.$t('deleteAndEdit'), text: this.$t('deleteAndEdit'),
action: this.delEdit action: this.delEdit

View file

@ -19,7 +19,7 @@
</XList> </XList>
<div v-show="more && !reversed" style="margin-top: var(--margin);"> <div v-show="more && !reversed" style="margin-top: var(--margin);">
<button class="_loadMore" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> <button class="_loadMore" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $t('loadMore') }}</template> <template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><MkLoading inline/></template> <template v-if="moreFetching"><MkLoading inline/></template>
</button> </button>

View file

@ -5,7 +5,7 @@
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/> <XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
</XList> </XList>
<button class="_loadMore" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> <button class="_loadMore" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $t('loadMore') }}</template> <template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><MkLoading inline/></template> <template v-if="moreFetching"><MkLoading inline/></template>
</button> </button>
@ -59,7 +59,7 @@ export default defineComponent({
computed: { computed: {
allIncludeTypes() { allIncludeTypes() {
return this.includeTypes ?? notificationTypes.filter(x => !this.$store.state.i.mutingNotificationTypes.includes(x)); return this.includeTypes ?? notificationTypes.filter(x => !this.$i.mutingNotificationTypes.includes(x));
} }
}, },
@ -70,9 +70,9 @@ export default defineComponent({
}, },
deep: true deep: true
}, },
// TODO: vue/vuex $store.state.i // TODO: vue/vuex $i
// mutingNotificationTypes // mutingNotificationTypes
'$store.state.i.mutingNotificationTypes': { '$i.mutingNotificationTypes': {
handler() { handler() {
if (this.includeTypes === null) { if (this.includeTypes === null) {
this.reload(); this.reload();

View file

@ -49,9 +49,9 @@ export default defineComponent({
canvas.toBlob(blob => { canvas.toBlob(blob => {
const data = new FormData(); const data = new FormData();
data.append('file', blob); data.append('file', blob);
data.append('i', this.$store.state.i.token); data.append('i', this.$i.token);
if (this.$store.state.settings.uploadFolder) { if (this.$store.state.uploadFolder) {
data.append('folderId', this.$store.state.settings.uploadFolder); data.append('folderId', this.$store.state.uploadFolder);
} }
fetch(apiUrl + '/drive/files/create', { fetch(apiUrl + '/drive/files/create', {

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="mrdgzndn"> <div class="mrdgzndn">
<Mfm :text="text" :is-note="false" :i="$store.state.i" :key="text"/> <Mfm :text="text" :is-note="false" :i="$i" :key="text"/>
<MkUrlPreview v-for="url in urls" :url="url" :key="url" class="url"/> <MkUrlPreview v-for="url in urls" :url="url" :key="url" class="url"/>
</div> </div>
</template> </template>

View file

@ -35,9 +35,9 @@ export default defineComponent({
created() { created() {
this.hpml = new Hpml(this.page, { this.hpml = new Hpml(this.page, {
randomSeed: Math.random(), randomSeed: Math.random(),
visitor: this.$store.state.i, visitor: this.$i,
url: url, url: url,
enableAiScript: !this.$store.state.device.disablePagesScript enableAiScript: !this.$store.state.disablePagesScript
}); });
}, },

View file

@ -135,8 +135,8 @@ export default defineComponent({
poll: null, poll: null,
useCw: false, useCw: false,
cw: null, cw: null,
localOnly: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly, localOnly: this.$store.state.rememberNoteVisibility ? this.$store.state.localOnly : this.$store.state.defaultNoteLocalOnly,
visibility: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility, visibility: this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility,
visibleUsers: [], visibleUsers: [],
autocomplete: null, autocomplete: null,
draghover: false, draghover: false,
@ -198,7 +198,7 @@ export default defineComponent({
}, },
max(): number { max(): number {
return this.$store.state.instance.meta ? this.$store.state.instance.meta.maxNoteTextLength : 1000; return this.$instance ? this.$instance.maxNoteTextLength : 1000;
} }
}, },
@ -223,8 +223,8 @@ export default defineComponent({
const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`; const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`;
// //
if (this.$store.state.i.username == x.username && x.host == null) continue; if (this.$i.username == x.username && x.host == null) continue;
if (this.$store.state.i.username == x.username && x.host == host) continue; if (this.$i.username == x.username && x.host == host) continue;
// //
if (this.text.indexOf(`${mention} `) != -1) continue; if (this.text.indexOf(`${mention} `) != -1) continue;
@ -243,12 +243,12 @@ export default defineComponent({
this.visibility = this.reply.visibility; this.visibility = this.reply.visibility;
if (this.reply.visibility === 'specified') { if (this.reply.visibility === 'specified') {
os.api('users/show', { os.api('users/show', {
userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$store.state.i.id && uid !== this.reply.userId) userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$i.id && uid !== this.reply.userId)
}).then(users => { }).then(users => {
this.visibleUsers.push(...users); this.visibleUsers.push(...users);
}); });
if (this.reply.userId !== this.$store.state.i.id) { if (this.reply.userId !== this.$i.id) {
os.api('users/show', { userId: this.reply.userId }).then(user => { os.api('users/show', { userId: this.reply.userId }).then(user => {
this.visibleUsers.push(user); this.visibleUsers.push(user);
}); });
@ -262,7 +262,7 @@ export default defineComponent({
} }
// keep cw when reply // keep cw when reply
if (this.$store.state.settings.keepCw && this.reply && this.reply.cw) { if (this.$store.keepCw && this.reply && this.reply.cw) {
this.useCw = true; this.useCw = true;
this.cw = this.reply.cw; this.cw = this.reply.cw;
} }
@ -376,7 +376,7 @@ export default defineComponent({
}, },
upload(file: File, name?: string) { upload(file: File, name?: string) {
os.upload(file, this.$store.state.settings.uploadFolder, name).then(res => { os.upload(file, this.$store.state.uploadFolder, name).then(res => {
this.files.push(res); this.files.push(res);
}); });
}, },
@ -399,14 +399,14 @@ export default defineComponent({
}, { }, {
changeVisibility: visibility => { changeVisibility: visibility => {
this.visibility = visibility; this.visibility = visibility;
if (this.$store.state.settings.rememberNoteVisibility) { if (this.$store.state.rememberNoteVisibility) {
this.$store.commit('deviceUser/setVisibility', visibility); this.$store.set('visibility', visibility);
} }
}, },
changeLocalOnly: localOnly => { changeLocalOnly: localOnly => {
this.localOnly = localOnly; this.localOnly = localOnly;
if (this.$store.state.settings.rememberNoteVisibility) { if (this.$store.state.rememberNoteVisibility) {
this.$store.commit('deviceUser/setLocalOnly', localOnly); this.$store.set('localOnly', localOnly);
} }
} }
}, 'closed'); }, 'closed');
@ -440,7 +440,7 @@ export default defineComponent({
const file = item.getAsFile(); const file = item.getAsFile();
const lio = file.name.lastIndexOf('.'); const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : ''; const ext = lio >= 0 ? file.name.slice(lio) : '';
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`; const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
this.upload(file, formatted); this.upload(file, formatted);
} }
} }

View file

@ -53,7 +53,7 @@ export default defineComponent({
}, },
computed: { computed: {
canToggle(): boolean { canToggle(): boolean {
return !this.reaction.match(/@\w/) && this.$store.getters.isSignedIn; return !this.reaction.match(/@\w/) && this.$i;
}, },
}, },
watch: { watch: {

View file

@ -25,7 +25,7 @@ export default defineComponent({
}, },
computed: { computed: {
isMe(): boolean { isMe(): boolean {
return this.$store.getters.isSignedIn && this.$store.state.i.id === this.note.userId; return this.$i && this.$i.id === this.note.userId;
}, },
}, },
}); });

View file

@ -51,7 +51,7 @@ export default defineComponent({
text: '', text: '',
flag: false, flag: false,
radio: 'misskey', radio: 'misskey',
mfm: `Hello world! This is an @example mention. BTW you are @${this.$store.state.i.username}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.` mfm: `Hello world! This is an @example mention. BTW you are @${this.$i.username}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`
} }
}, },

View file

@ -12,7 +12,7 @@
<nav class="nav" :class="{ iconOnly, hidden }" v-show="showing"> <nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
<div> <div>
<button class="item _button account" @click="openAccountMenu"> <button class="item _button account" @click="openAccountMenu">
<MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/> <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
</button> </button>
<MkA class="item index" active-class="active" to="/" exact> <MkA class="item index" active-class="active" to="/" exact>
<Fa :icon="faHome" fixed-width/><span class="text">{{ $t('timeline') }}</span> <Fa :icon="faHome" fixed-width/><span class="text">{{ $t('timeline') }}</span>
@ -25,7 +25,7 @@
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.state.i.isAdmin || $store.state.i.isModerator" @click="oepnInstanceMenu"> <button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$i.isAdmin || $i.isModerator" @click="oepnInstanceMenu">
<Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span> <Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
</button> </button>
<button class="item _button" @click="more"> <button class="item _button" @click="more">
@ -49,6 +49,7 @@ 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 { sidebarDef } from '@/sidebar'; import { sidebarDef } from '@/sidebar';
import { getAccounts, addAccount, login } from '@/account';
export default defineComponent({ export default defineComponent({
data() { data() {
@ -67,7 +68,7 @@ export default defineComponent({
computed: { computed: {
menu(): string[] { menu(): string[] {
return this.$store.state.deviceUser.menu; return this.$store.state.menu;
}, },
otherNavItemIndicated(): boolean { otherNavItemIndicated(): boolean {
@ -84,7 +85,7 @@ export default defineComponent({
this.showing = false; this.showing = false;
}, },
'$store.state.device.sidebarDisplay'() { '$store.reactiveState.sidebarDisplay'() {
this.calcViewState(); this.calcViewState();
}, },
@ -108,8 +109,8 @@ export default defineComponent({
methods: { methods: {
calcViewState() { calcViewState() {
this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.device.sidebarDisplay === 'icon'); this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.sidebarDisplay === 'icon');
this.hidden = (window.innerWidth <= 650) || (this.$store.state.device.sidebarDisplay === 'hide'); this.hidden = (window.innerWidth <= 650);
}, },
show() { show() {
@ -133,7 +134,8 @@ export default defineComponent({
}, },
async openAccountMenu(ev) { async openAccountMenu(ev) {
const accounts = (await os.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id); const storedAccounts = getAccounts();
const accounts = (await os.api('users/show', { userIds: storedAccounts.map(x => x.id) })).filter(x => x.id !== this.$i.id);
const accountItems = accounts.map(account => ({ const accountItems = accounts.map(account => ({
type: 'user', type: 'user',
@ -144,8 +146,8 @@ export default defineComponent({
os.modalMenu([...[{ os.modalMenu([...[{
type: 'link', type: 'link',
text: this.$t('profile'), text: this.$t('profile'),
to: `/@${ this.$store.state.i.username }`, to: `/@${ this.$i.username }`,
avatar: this.$store.state.i, avatar: this.$i,
}, null, ...accountItems, { }, null, ...accountItems, {
icon: faPlus, icon: faPlus,
text: this.$t('addAcount'), text: this.$t('addAcount'),
@ -169,7 +171,7 @@ export default defineComponent({
text: this.$t('dashboard'), text: this.$t('dashboard'),
to: '/instance', to: '/instance',
icon: faTachometerAlt, icon: faTachometerAlt,
}, null, this.$store.state.i.isAdmin ? { }, null, this.$i.isAdmin ? {
type: 'link', type: 'link',
text: this.$t('settings'), text: this.$t('settings'),
to: '/instance/settings', to: '/instance/settings',
@ -230,7 +232,7 @@ export default defineComponent({
addAcount() { addAcount() {
os.popup(import('./signin-dialog.vue'), {}, { os.popup(import('./signin-dialog.vue'), {}, {
done: res => { done: res => {
this.$store.dispatch('addAcount', res); addAccount(res.id, res.i);
os.success(); os.success();
}, },
}, 'closed'); }, 'closed');
@ -239,30 +241,20 @@ export default defineComponent({
createAccount() { createAccount() {
os.popup(import('./signup-dialog.vue'), {}, { os.popup(import('./signup-dialog.vue'), {}, {
done: res => { done: res => {
this.$store.dispatch('addAcount', res); addAccount(res.id, res.i);
this.switchAccountWithToken(res.i); this.switchAccountWithToken(res.i);
}, },
}, 'closed'); }, 'closed');
}, },
switchAccount(account: any) { switchAccount(account: any) {
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token; const storedAccounts = getAccounts();
const token = storedAccounts.find(x => x.id === account.id).token;
this.switchAccountWithToken(token); this.switchAccountWithToken(token);
}, },
switchAccountWithToken(token: string) { switchAccountWithToken(token: string) {
os.waiting(); login(token);
os.api('i', {}, token).then((i: any) => {
this.$store.dispatch('switchAccount', {
...i,
token: token
}).then(() => {
this.$nextTick(() => {
location.reload();
});
});
});
}, },
} }
}); });

View file

@ -56,6 +56,7 @@ import MkInput from './ui/input.vue';
import { apiUrl, host } from '@/config'; import { apiUrl, host } from '@/config';
import { byteify, hexify } from '@/scripts/2fa'; import { byteify, hexify } from '@/scripts/2fa';
import * as os from '@/os'; import * as os from '@/os';
import { login } from '@/account';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -97,7 +98,7 @@ export default defineComponent({
computed: { computed: {
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
}, },
@ -114,8 +115,7 @@ export default defineComponent({
onLogin(res) { onLogin(res) {
if (this.autoSet) { if (this.autoSet) {
localStorage.setItem('i', res.i); login(res.i);
location.reload();
} }
}, },

View file

@ -59,6 +59,7 @@ import MkButton from './ui/button.vue';
import MkInput from './ui/input.vue'; import MkInput from './ui/input.vue';
import MkSwitch from './ui/switch.vue'; import MkSwitch from './ui/switch.vue';
import * as os from '@/os'; import * as os from '@/os';
import { login } from '@/account';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -99,7 +100,7 @@ export default defineComponent({
computed: { computed: {
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
shouldDisableSubmitting(): boolean { shouldDisableSubmitting(): boolean {
@ -184,8 +185,7 @@ export default defineComponent({
this.$emit('signup', res); this.$emit('signup', res);
if (this.autoSet) { if (this.autoSet) {
localStorage.setItem('i', res.i); login(res.i);
location.reload();
} }
}); });
}).catch(() => { }).catch(() => {

View file

@ -4,7 +4,7 @@
<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span> <span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span> <span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA> <MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/> <Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA> <MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
</div> </div>
<details v-if="note.files.length > 0"> <details v-if="note.files.length > 0">

View file

@ -1,5 +1,5 @@
<template> <template>
<XNotes :class="{ _noGap_: !$store.state.device.showGapBetweenNotesInTimeline }" ref="tl" :pagination="pagination" @before="$emit('before')" @after="e => $emit('after', e)" @queue="$emit('queue', $event)"/> <XNotes :class="{ _noGap_: !$store.state.showGapBetweenNotesInTimeline }" ref="tl" :pagination="pagination" @before="$emit('before')" @after="e => $emit('after', e)" @queue="$emit('queue', $event)"/>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -51,9 +51,9 @@ export default defineComponent({
connection2: null, connection2: null,
pagination: null, pagination: null,
baseQuery: { baseQuery: {
includeMyRenotes: this.$store.state.settings.showMyRenotes, includeMyRenotes: this.$store.state.showMyRenotes,
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes, includeRenotedMyNotes: this.$store.state.showRenotedMyNotes,
includeLocalRenotes: this.$store.state.settings.showLocalRenotes includeLocalRenotes: this.$store.state.showLocalRenotes
}, },
query: {}, query: {},
}; };
@ -66,7 +66,7 @@ export default defineComponent({
this.$emit('note'); this.$emit('note');
if (this.sound) { if (this.sound) {
sound.play(note.userId === this.$store.state.i.id ? 'noteMy' : 'note'); sound.play(note.userId === this.$i.id ? 'noteMy' : 'note');
} }
}; };

View file

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.device.animation ? 'fade' : ''" appear> <transition :name="$store.state.animation ? 'fade' : ''" appear>
<div class="nvlagfpb" @contextmenu.prevent.stop="() => {}"> <div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
<MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/> <MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
</div> </div>

View file

@ -1,10 +1,10 @@
<template> <template>
<div class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: showing ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: showing ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<transition :name="$store.state.device.animation ? 'modal-bg' : ''" appear> <transition :name="$store.state.animation ? 'modal-bg' : ''" appear>
<div class="bg _modalBg" v-if="showing" @click="onBgClick"></div> <div class="bg _modalBg" v-if="showing" @click="onBgClick"></div>
</transition> </transition>
<div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content"> <div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content">
<transition :name="$store.state.device.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @after-enter="childRendered"> <transition :name="$store.state.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @after-enter="childRendered">
<slot v-if="showing"></slot> <slot v-if="showing"></slot>
</transition> </transition>
</div> </div>

View file

@ -5,7 +5,7 @@
<slot name="empty"></slot> <slot name="empty"></slot>
</div> </div>
<div class="more" v-show="more" key="_more_"> <div class="more" v-show="more" key="_more_">
<MkButton class="button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary> <MkButton class="button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
<template v-if="!moreFetching">{{ $t('loadMore') }}</template> <template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><MkLoading inline/></template> <template v-if="moreFetching"><MkLoading inline/></template>
</MkButton> </MkButton>

View file

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.device.animation ? 'window' : ''" appear @after-leave="$emit('closed')"> <transition :name="$store.state.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
<div class="ebkgocck" v-if="showing"> <div class="ebkgocck" v-if="showing">
<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown"> <div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
<div class="header" @contextmenu.prevent.stop="onContextmenu"> <div class="header" @contextmenu.prevent.stop="onContextmenu">

View file

@ -4,7 +4,7 @@
<iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen /> <iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
</div> </div>
<div v-else-if="tweetId && tweetExpanded" class="twitter" ref="twitter"> <div v-else-if="tweetId && tweetExpanded" class="twitter" ref="twitter">
<iframe ref="tweet" scrolling="no" frameborder="no" :style="{ position: 'relative', left: `${tweetLeft}px`, width: `${tweetLeft < 0 ? 'auto' : '100%'}`, height: `${tweetHeight}px` }" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${$store.state.device.darkMode ? 'dark' : 'light'}&amp;id=${tweetId}`"></iframe> <iframe ref="tweet" scrolling="no" frameborder="no" :style="{ position: 'relative', left: `${tweetLeft}px`, width: `${tweetLeft < 0 ? 'auto' : '100%'}`, height: `${tweetHeight}px` }" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&amp;hideCard=false&amp;hideThread=false&amp;lang=en&amp;theme=${$store.state.darkMode ? 'dark' : 'light'}&amp;id=${tweetId}`"></iframe>
</div> </div>
<div v-else class="mk-url-preview" v-size="{ max: [400, 350] }"> <div v-else class="mk-url-preview" v-size="{ max: [400, 350] }">
<transition name="zoom" mode="out-in"> <transition name="zoom" mode="out-in">

View file

@ -8,7 +8,7 @@
</div> </div>
<div class="description"> <div class="description">
<div class="mfm" v-if="user.description"> <div class="mfm" v-if="user.description">
<Mfm :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> <Mfm :text="user.description" :author="user" :i="$i" :custom-emojis="user.emojis"/>
</div> </div>
<span v-else style="opacity: 0.7;">{{ $t('noAccountDescription') }}</span> <span v-else style="opacity: 0.7;">{{ $t('noAccountDescription') }}</span>
</div> </div>
@ -23,7 +23,7 @@
<p>{{ $t('followers') }}</p><span>{{ user.followersCount }}</span> <p>{{ $t('followers') }}</p><span>{{ user.followersCount }}</span>
</div> </div>
</div> </div>
<MkFollowButton class="koudoku-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/> <MkFollowButton class="koudoku-button" v-if="$i && user.id != $i.id" :user="user" mini/>
</div> </div>
</template> </template>

View file

@ -8,7 +8,7 @@
<div class="users"> <div class="users">
<MkUserInfo class="user" v-for="user in users" :user="user" :key="user.id"/> <MkUserInfo class="user" v-for="user in users" :user="user" :key="user.id"/>
</div> </div>
<button class="more" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :class="{ fetching: moreFetching }" v-show="more" :disabled="moreFetching"> <button class="more" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :class="{ fetching: moreFetching }" v-show="more" :disabled="moreFetching">
<template v-if="moreFetching"><Fa icon="spinner" pulse fixed-width/></template>{{ moreFetching ? $t('loading') : $t('loadMore') }} <template v-if="moreFetching"><Fa icon="spinner" pulse fixed-width/></template>{{ moreFetching ? $t('loading') : $t('loadMore') }}
</button> </button>
</div> </div>

View file

@ -9,7 +9,7 @@
<p class="username"><MkAcct :user="user"/></p> <p class="username"><MkAcct :user="user"/></p>
</div> </div>
<div class="description"> <div class="description">
<Mfm v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> <Mfm v-if="user.description" :text="user.description" :author="user" :i="$i" :custom-emojis="user.emojis"/>
</div> </div>
<div class="status"> <div class="status">
<div> <div>
@ -22,7 +22,7 @@
<p>{{ $t('followers') }}</p><span>{{ user.followersCount }}</span> <p>{{ $t('followers') }}</p><span>{{ user.followersCount }}</span>
</div> </div>
</div> </div>
<MkFollowButton class="koudoku-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/> <MkFollowButton class="koudoku-button" v-if="$i && user.id != $i.id" :user="user" mini/>
</div> </div>
<div v-else> <div v-else>
<MkLoading/> <MkLoading/>

View file

@ -79,7 +79,7 @@ export default defineComponent({
}); });
this.recentUsers = await os.api('users/show', { this.recentUsers = await os.api('users/show', {
userIds: this.$store.state.device.recentlyUsedUsers userIds: this.$store.state.recentlyUsedUsers
}); });
}, },
@ -108,10 +108,10 @@ export default defineComponent({
this.$refs.dialog.close(); this.$refs.dialog.close();
// 使 // 使
let recents = this.$store.state.device.recentlyUsedUsers; let recents = this.$store.state.recentlyUsedUsers;
recents = recents.filter(x => x !== this.selected.id); recents = recents.filter(x => x !== this.selected.id);
recents.unshift(this.selected.id); recents.unshift(this.selected.id);
this.$store.commit('device/set', { key: 'recentlyUsedUsers', value: recents.splice(0, 16) }); this.$store.set('recentlyUsedUsers', recents.splice(0, 16));
}, },
cancel() { cancel() {

View file

@ -14,7 +14,7 @@
</div> </div>
</MkA> </MkA>
</div> </div>
<button class="more _button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching"> <button class="more _button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching">
<template v-if="!moreFetching">{{ $t('loadMore') }}</template> <template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><Fa :icon="faSpinner" pulse fixed-width/></template> <template v-if="moreFetching"><Fa :icon="faSpinner" pulse fixed-width/></template>
</button> </button>

View file

@ -4,26 +4,54 @@
import '@/style.scss'; import '@/style.scss';
import { createApp } from 'vue'; // TODO: そのうち消す
if (localStorage.getItem('vuex') != null) {
const vuex = JSON.parse(localStorage.getItem('vuex'));
localStorage.setItem('accounts', JSON.stringify(vuex.device.accounts));
localStorage.setItem('miux:themes', JSON.stringify(vuex.device.themes));
for (const [k, v] of Object.entries(vuex.device.userData)) {
localStorage.setItem('pizzax::base::' + k, JSON.stringify({
widgets: v.widgets
}));
if (v.deck) {
localStorage.setItem('pizzax::deck::' + k, JSON.stringify({
columns: v.deck.columns,
layout: v.deck.layout,
}));
}
}
localStorage.removeItem('vuex');
}
import { createApp, watch } from 'vue';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import widgets from './widgets'; import widgets from '@/widgets';
import directives from './directives'; import directives from '@/directives';
import components from '@/components'; import components from '@/components';
import { version, apiUrl, ui } from '@/config'; import { version, ui } from '@/config';
import { store } from './store'; import { router } from '@/router';
import { router } from './router';
import { applyTheme } from '@/scripts/theme'; import { applyTheme } from '@/scripts/theme';
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { i18n, lang } from './i18n'; import { i18n, lang } from '@/i18n';
import { stream, isMobile, dialog } from '@/os'; import { stream, isMobile, dialog } from '@/os';
import * as sound from './scripts/sound'; import * as sound from '@/scripts/sound';
import { $i, refreshAccount, login, updateAccount, signout } from '@/account';
import { defaultStore, ColdDeviceStorage } from '@/store';
import { fetchInstance, instance } from '@/instance';
console.info(`Misskey v${version}`); console.info(`Misskey v${version}`);
if (_DEV_) { if (_DEV_) {
console.warn('Development mode!!!'); console.warn('Development mode!!!');
(window as any).$i = $i;
(window as any).$store = defaultStore;
window.addEventListener('error', event => { window.addEventListener('error', event => {
console.error(event); console.error(event);
/* /*
@ -81,80 +109,52 @@ html.setAttribute('lang', lang);
//#endregion //#endregion
//#region Fetch user //#region Fetch user
const signout = () => { if ($i && $i.token) {
store.dispatch('logout'); if (_DEV_) {
location.href = '/'; console.log('account cache found. refreshing...');
};
// ユーザーをフェッチしてコールバックする
const fetchme = (token) => new Promise((done, fail) => {
// Fetch user
fetch(`${apiUrl}/i`, {
method: 'POST',
body: JSON.stringify({
i: token
})
})
.then(res => {
// When failed to authenticate user
if (res.status !== 200 && res.status < 500) {
return signout();
} }
// Parse response refreshAccount();
res.json().then(i => {
i.token = token;
done(i);
});
})
.catch(fail);
});
// キャッシュがあったとき
if (store.state.i != null) {
// TODO: i.token が null になるケースってどんな時だっけ?
if (store.state.i.token == null) {
signout();
}
// 後から新鮮なデータをフェッチ
fetchme(store.state.i.token).then(freshData => {
store.dispatch('mergeMe', freshData);
});
} else { } else {
// Get token from localStorage if (_DEV_) {
let i = localStorage.getItem('i'); console.log('no account cache found.');
}
// 連携ログインの場合用にCookieを参照する // 連携ログインの場合用にCookieを参照する
if (i == null || i === 'null') { const i = (document.cookie.match(/igi=(\w+)/) || [null, null])[1];
i = (document.cookie.match(/igi=(\w+)/) || [null, null])[1];
}
if (i != null && i !== 'null') { if (i != null && i !== 'null') {
if (_DEV_) {
console.log('signing...');
}
try { try {
document.body.innerHTML = '<div>Please wait...</div>'; document.body.innerHTML = '<div>Please wait...</div>';
const me = await fetchme(i); await login(i);
await store.dispatch('login', me);
location.reload(); location.reload();
} catch (e) { } catch (e) {
// Render the error screen // Render the error screen
// TODO: ちゃんとしたコンポーネントをレンダリングする(v10とかのトラブルシューティングゲーム付きのやつみたいな) // TODO: ちゃんとしたコンポーネントをレンダリングする(v10とかのトラブルシューティングゲーム付きのやつみたいな)
document.body.innerHTML = '<div id="err">Oops!</div>'; document.body.innerHTML = '<div id="err">Oops!</div>';
} }
} else {
if (_DEV_) {
console.log('not signed in');
}
} }
} }
//#endregion //#endregion
store.dispatch('instance/fetch').then(() => { fetchInstance().then(() => {
// Init service worker // Init service worker
//if (this.store.state.instance.meta.swPublickey) this.registerSw(this.store.state.instance.meta.swPublickey); //if (this.store.state.instance.meta.swPublickey) this.registerSw(this.store.state.instance.meta.swPublickey);
}); });
stream.init(store.state.i); stream.init($i);
const app = createApp(await ( const app = createApp(await (
window.location.search === '?zen' ? import('@/ui/zen.vue') : window.location.search === '?zen' ? import('@/ui/zen.vue') :
!store.getters.isSignedIn ? import('@/ui/visitor.vue') : !$i ? import('@/ui/visitor.vue') :
ui === 'deck' ? import('@/ui/deck.vue') : ui === 'deck' ? import('@/ui/deck.vue') :
ui === 'desktop' ? import('@/ui/desktop.vue') : ui === 'desktop' ? import('@/ui/desktop.vue') :
import('@/ui/default.vue') import('@/ui/default.vue')
@ -164,7 +164,12 @@ if (_DEV_) {
app.config.performance = true; app.config.performance = true;
} }
app.use(store); app.config.globalProperties = {
$i,
$store: defaultStore,
$instance: instance,
};
app.use(router); app.use(router);
app.use(i18n); app.use(i18n);
// eslint-disable-next-line vue/component-definition-name-casing // eslint-disable-next-line vue/component-definition-name-casing
@ -180,46 +185,34 @@ await router.isReady();
app.mount('body'); app.mount('body');
// 他のタブと永続化されたstateを同期 watch(defaultStore.reactiveState.darkMode, (darkMode) => {
window.addEventListener('storage', e => {
if (e.key === 'vuex') {
store.replaceState({
...store.state,
...JSON.parse(e.newValue)
});
} else if (e.key === 'i') {
location.reload();
}
}, false);
store.watch(state => state.device.darkMode, darkMode => {
import('@/scripts/theme').then(({ builtinThemes }) => { import('@/scripts/theme').then(({ builtinThemes }) => {
const themes = builtinThemes.concat(store.state.device.themes); const themes = builtinThemes.concat(ColdDeviceStorage.get('themes'));
applyTheme(themes.find(x => x.id === (darkMode ? store.state.device.darkTheme : store.state.device.lightTheme))); applyTheme(themes.find(x => x.id === (darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'))));
}); });
}); });
//#region Sync dark mode //#region Sync dark mode
if (store.state.device.syncDeviceDarkMode) { if (ColdDeviceStorage.get('syncDeviceDarkMode')) {
store.commit('device/set', { key: 'darkMode', value: isDeviceDarkmode() }); defaultStore.set('darkMode', isDeviceDarkmode());
} }
window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => {
if (store.state.device.syncDeviceDarkMode) { if (ColdDeviceStorage.get('syncDeviceDarkMode')) {
store.commit('device/set', { key: 'darkMode', value: mql.matches }); defaultStore.set('darkMode', mql.matches);
} }
}); });
//#endregion //#endregion
store.watch(state => state.device.useBlurEffectForModal, v => { watch(defaultStore.reactiveState.useBlurEffectForModal, v => {
document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none');
}, { immediate: true }); }, { immediate: true });
let reloadDialogShowing = false; let reloadDialogShowing = false;
stream.on('_disconnected_', async () => { stream.on('_disconnected_', async () => {
if (store.state.device.serverDisconnectedBehavior === 'reload') { if (defaultStore.state.serverDisconnectedBehavior === 'reload') {
location.reload(); location.reload();
} else if (store.state.device.serverDisconnectedBehavior === 'dialog') { } else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') {
if (reloadDialogShowing) return; if (reloadDialogShowing) return;
reloadDialogShowing = true; reloadDialogShowing = true;
const { canceled } = await dialog({ const { canceled } = await dialog({
@ -240,13 +233,13 @@ stream.on('emojiAdded', data => {
//store.commit('instance/set', ); //store.commit('instance/set', );
}); });
for (const plugin of store.state.deviceUser.plugins.filter(p => p.active)) { for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) {
import('./plugin').then(({ install }) => { import('./plugin').then(({ install }) => {
install(plugin); install(plugin);
}); });
} }
if (store.getters.isSignedIn) { if ($i) {
if ('Notification' in window) { if ('Notification' in window) {
// 許可を得ていなかったらリクエスト // 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') { if (Notification.permission === 'default') {
@ -258,103 +251,73 @@ if (store.getters.isSignedIn) {
// 自分の情報が更新されたとき // 自分の情報が更新されたとき
main.on('meUpdated', i => { main.on('meUpdated', i => {
store.dispatch('mergeMe', i); updateAccount(i);
}); });
main.on('readAllNotifications', () => { main.on('readAllNotifications', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadNotification: false });
hasUnreadNotification: false
});
}); });
main.on('unreadNotification', () => { main.on('unreadNotification', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadNotification: true });
hasUnreadNotification: true
});
}); });
main.on('unreadMention', () => { main.on('unreadMention', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadMentions: true });
hasUnreadMentions: true
});
}); });
main.on('readAllUnreadMentions', () => { main.on('readAllUnreadMentions', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadMentions: false });
hasUnreadMentions: false
});
}); });
main.on('unreadSpecifiedNote', () => { main.on('unreadSpecifiedNote', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadSpecifiedNotes: true });
hasUnreadSpecifiedNotes: true
});
}); });
main.on('readAllUnreadSpecifiedNotes', () => { main.on('readAllUnreadSpecifiedNotes', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadSpecifiedNotes: false });
hasUnreadSpecifiedNotes: false
});
}); });
main.on('readAllMessagingMessages', () => { main.on('readAllMessagingMessages', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadMessagingMessage: false });
hasUnreadMessagingMessage: false
});
}); });
main.on('unreadMessagingMessage', () => { main.on('unreadMessagingMessage', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadMessagingMessage: true });
hasUnreadMessagingMessage: true
});
sound.play('chatBg'); sound.play('chatBg');
}); });
main.on('readAllAntennas', () => { main.on('readAllAntennas', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadAntenna: false });
hasUnreadAntenna: false
});
}); });
main.on('unreadAntenna', () => { main.on('unreadAntenna', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadAntenna: true });
hasUnreadAntenna: true
});
sound.play('antenna'); sound.play('antenna');
}); });
main.on('readAllAnnouncements', () => { main.on('readAllAnnouncements', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadAnnouncement: false });
hasUnreadAnnouncement: false
});
}); });
main.on('readAllChannels', () => { main.on('readAllChannels', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadChannel: false });
hasUnreadChannel: false
});
}); });
main.on('unreadChannel', () => { main.on('unreadChannel', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadChannel: true });
hasUnreadChannel: true
});
sound.play('channel'); sound.play('channel');
}); });
main.on('readAllAnnouncements', () => { main.on('readAllAnnouncements', () => {
store.dispatch('mergeMe', { updateAccount({ hasUnreadAnnouncement: false });
hasUnreadAnnouncement: false
});
}); });
main.on('clientSettingUpdated', x => { main.on('clientSettingUpdated', x => {
store.commit('settings/set', { updateAccount({
key: x.key, clientData: {
value: x.value [x.key]: x.value
}
}); });
}); });
@ -364,4 +327,3 @@ if (store.getters.isSignedIn) {
signout(); signout();
}); });
} }

45
src/client/instance.ts Normal file
View file

@ -0,0 +1,45 @@
import { computed, reactive } from 'vue';
import { api } from './os';
// TODO: 他のタブと永続化されたstateを同期
type Instance = {
emojis: {
category: string;
}[];
};
const data = localStorage.getItem('instance');
// TODO: instanceをリアクティブにするかは再考の余地あり
export const instance: Instance = reactive(data ? JSON.parse(data) : {
// TODO: set default values
});
export async function fetchInstance() {
const meta = await api('meta', {
detail: false
});
for (const [k, v] of Object.entries(meta)) {
instance[k] = v;
}
localStorage.setItem('instance', JSON.stringify(instance));
}
export const emojiCategories = computed(() => {
const categories = new Set();
for (const emoji of instance.emojis) {
categories.add(emoji.category);
}
return Array.from(categories);
});
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$instance: typeof instance;
}
}

View file

@ -1,12 +1,11 @@
import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vue'; import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vue';
import { EventEmitter } from 'eventemitter3'; import { EventEmitter } from 'eventemitter3';
import Stream from '@/scripts/stream'; import Stream from '@/scripts/stream';
import { store } from '@/store';
import { apiUrl, debug } from '@/config'; import { apiUrl, debug } from '@/config';
import MkPostFormDialog from '@/components/post-form-dialog.vue'; import MkPostFormDialog from '@/components/post-form-dialog.vue';
import MkWaitingDialog from '@/components/waiting-dialog.vue'; import MkWaitingDialog from '@/components/waiting-dialog.vue';
import { resolve } from '@/router'; import { resolve } from '@/router';
import { device } from './cold-storage'; import { $i } from './account';
const ua = navigator.userAgent.toLowerCase(); const ua = navigator.userAgent.toLowerCase();
export const isMobile = /mobile|iphone|ipad|android/.test(ua); export const isMobile = /mobile|iphone|ipad|android/.test(ua);
@ -40,7 +39,7 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
const promise = new Promise((resolve, reject) => { const promise = new Promise((resolve, reject) => {
// Append a credential // Append a credential
if (store.getters.isSignedIn) (data as any).i = store.state.i.token; if ($i) (data as any).i = $i.token;
if (token !== undefined) (data as any).i = token; if (token !== undefined) (data as any).i = token;
// Send request // Send request
@ -368,7 +367,7 @@ export function upload(file: File, folder?: any, name?: string) {
uploads.value.push(ctx); uploads.value.push(ctx);
const data = new FormData(); const data = new FormData();
data.append('i', store.state.i.token); data.append('i', $i.token);
data.append('force', 'true'); data.append('force', 'true');
data.append('file', file); data.append('file', file);

View file

@ -1,5 +1,5 @@
<template> <template>
<transition :name="$store.state.device.animation ? 'zoom' : ''" appear> <transition :name="$store.state.animation ? 'zoom' : ''" appear>
<div class="_section"> <div class="_section">
<div class="mjndxjch _content"> <div class="mjndxjch _content">
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>

View file

@ -7,7 +7,7 @@
<img src="/assets/icons/512.png" alt="" class="icon" ref="icon" @load="iconLoaded" draggable="false"/> <img src="/assets/icons/512.png" alt="" class="icon" ref="icon" @load="iconLoaded" draggable="false"/>
<div class="misskey">Misskey</div> <div class="misskey">Misskey</div>
<div class="version">v{{ version }}</div> <div class="version">v{{ version }}</div>
<span class="emoji" v-for="emoji in easterEggEmojis" :key="emoji.id" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$store.state.instance.meta.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span> <span class="emoji" v-for="emoji in easterEggEmojis" :key="emoji.id" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :custom-emojis="$instance.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div> </div>
</section> </section>
<section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity"> <section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity">
@ -144,7 +144,7 @@ export default defineComponent({
methods: { methods: {
iconLoaded() { iconLoaded() {
const emojis = this.$store.state.settings.reactions; const emojis = this.$store.state.reactions;
const containerWidth = this.$refs.about.offsetWidth; const containerWidth = this.$refs.about.offsetWidth;
for (let i = 0; i < 32; i++) { for (let i = 0; i < 32; i++) {
this.easterEggEmojis.push({ this.easterEggEmojis.push({

View file

@ -59,7 +59,7 @@ export default defineComponent({
computed: { computed: {
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
}, },
}); });

View file

@ -2,12 +2,12 @@
<div class="_section"> <div class="_section">
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content"> <MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content">
<section class="_card announcement _vMargin" v-for="(announcement, i) in items" :key="announcement.id"> <section class="_card announcement _vMargin" v-for="(announcement, i) in items" :key="announcement.id">
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> <div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
<div class="_content"> <div class="_content">
<Mfm :text="announcement.text"/> <Mfm :text="announcement.text"/>
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> <img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
</div> </div>
<div class="_footer" v-if="$store.getters.isSignedIn && !announcement.isRead"> <div class="_footer" v-if="$i && !announcement.isRead">
<MkButton @click="read(items, announcement, i)" primary><Fa :icon="faCheck"/> {{ $t('gotIt') }}</MkButton> <MkButton @click="read(items, announcement, i)" primary><Fa :icon="faCheck"/> {{ $t('gotIt') }}</MkButton>
</div> </div>
</section> </section>

View file

@ -1,8 +1,8 @@
<template> <template>
<div class="" v-if="$store.getters.isSignedIn && fetching"> <div class="" v-if="$i && fetching">
<MkLoading/> <MkLoading/>
</div> </div>
<div v-else-if="$store.getters.isSignedIn"> <div v-else-if="$i">
<XForm <XForm
class="form" class="form"
ref="form" ref="form"
@ -33,6 +33,7 @@ import { defineComponent } from 'vue';
import XForm from './auth.form.vue'; import XForm from './auth.form.vue';
import MkSignin from '@/components/signin.vue'; import MkSignin from '@/components/signin.vue';
import * as os from '@/os'; import * as os from '@/os';
import { login } from '@/account';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -52,7 +53,7 @@ export default defineComponent({
} }
}, },
mounted() { mounted() {
if (!this.$store.getters.isSignedIn) return; if (!this.$i) return;
// Fetch session // Fetch session
os.api('auth/session/show', { os.api('auth/session/show', {
@ -83,8 +84,7 @@ export default defineComponent({
location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`; location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
} }
}, onLogin(res) { }, onLogin(res) {
localStorage.setItem('i', res.i); login(res.i);
location.reload();
} }
} }
}); });

View file

@ -16,11 +16,11 @@
<div class="fade"></div> <div class="fade"></div>
</div> </div>
<div class="description" v-if="channel.description"> <div class="description" v-if="channel.description">
<Mfm :text="channel.description" :is-note="false" :i="$store.state.i"/> <Mfm :text="channel.description" :is-note="false" :i="$i"/>
</div> </div>
</div> </div>
<XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed v-if="$store.getters.isSignedIn"/> <XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed v-if="$i"/>
<XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/> <XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
</div> </div>

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="_section" style="padding: 0;" v-if="$store.getters.isSignedIn"> <div class="_section" style="padding: 0;" v-if="$i">
<MkTab class="_content" v-model:value="tab"> <MkTab class="_content" v-model:value="tab">
<option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_channel.featured') }}</option> <option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_channel.featured') }}</option>
<option value="following"><Fa :icon="faHeart"/> {{ $t('_channel.following') }}</option> <option value="following"><Fa :icon="faHeart"/> {{ $t('_channel.following') }}</option>

View file

@ -2,7 +2,7 @@
<div v-if="clip" class="_section"> <div v-if="clip" class="_section">
<div class="okzinsic _content _panel _vMargin"> <div class="okzinsic _content _panel _vMargin">
<div class="description" v-if="clip.description"> <div class="description" v-if="clip.description">
<Mfm :text="clip.description" :is-note="false" :i="$store.state.i"/> <Mfm :text="clip.description" :is-note="false" :i="$i"/>
</div> </div>
<div class="user"> <div class="user">
<MkAvatar :user="clip.user" class="avatar"/> <MkUserName :user="clip.user" :nowrap="false"/> <MkAvatar :user="clip.user" class="avatar"/> <MkUserName :user="clip.user" :nowrap="false"/>
@ -58,7 +58,7 @@ export default defineComponent({
computed: { computed: {
isOwned(): boolean { isOwned(): boolean {
return this.$store.getters.isSignedIn && this.clip && (this.$store.state.i.id === this.clip.userId); return this.$i && this.clip && (this.$i.id === this.clip.userId);
} }
}, },

View file

@ -142,7 +142,7 @@ export default defineComponent({
computed: { computed: {
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
tagUsers(): any { tagUsers(): any {
return { return {

View file

@ -16,7 +16,7 @@
<p class="acct">@{{ acct(req.follower) }}</p> <p class="acct">@{{ acct(req.follower) }}</p>
</div> </div>
<div class="description" v-if="req.follower.description" :title="req.follower.description"> <div class="description" v-if="req.follower.description" :title="req.follower.description">
<Mfm :text="req.follower.description" :is-note="false" :author="req.follower" :i="$store.state.i" :custom-emojis="req.follower.emojis" :plain="true" :nowrap="true"/> <Mfm :text="req.follower.description" :is-note="false" :author="req.follower" :i="$i" :custom-emojis="req.follower.emojis" :plain="true" :nowrap="true"/>
</div> </div>
<div class="actions"> <div class="actions">
<button class="_button" @click="accept(req.follower)"><Fa :icon="faCheck"/></button> <button class="_button" @click="accept(req.follower)"><Fa :icon="faCheck"/></button>

View file

@ -160,7 +160,7 @@ export default defineComponent({
computed: { computed: {
gridColor() { gridColor() {
// TODO: var(--panel) // TODO: var(--panel)
return this.$store.state.device.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; return this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
}, },
}, },

View file

@ -122,7 +122,7 @@ export default defineComponent({
computed: { computed: {
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
}, },

View file

@ -206,7 +206,7 @@ export default defineComponent({
}, },
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
isBlocked() { isBlocked() {

View file

@ -63,7 +63,7 @@ export default defineComponent({
this.fetchJobs(); this.fetchJobs();
// TODO: var(--panel) // TODO: var(--panel)
const gridColor = this.$store.state.device.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; const gridColor = this.$store.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg'); Chart.defaults.global.defaultFontColor = getComputedStyle(document.documentElement).getPropertyValue('--fg');

View file

@ -259,6 +259,7 @@ import MkInfo from '@/components/ui/info.vue';
import { url } from '@/config'; import { url } from '@/config';
import getAcct from '../../../misc/acct/render'; import getAcct from '../../../misc/acct/render';
import * as os from '@/os'; import * as os from '@/os';
import { fetchInstance } from '@/instance';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -565,7 +566,7 @@ export default defineComponent({
summalyProxy: this.summalyProxy, summalyProxy: this.summalyProxy,
useStarForReactionFallback: this.useStarForReactionFallback, useStarForReactionFallback: this.useStarForReactionFallback,
}).then(() => { }).then(() => {
this.$store.dispatch('instance/fetch'); fetchInstance();
if (withDialog) { if (withDialog) {
os.success(); os.success();
} }

View file

@ -24,7 +24,7 @@
</div> </div>
<div class="_section"> <div class="_section">
<div class="_content"> <div class="_content">
<MkSwitch v-if="user.host == null && $store.state.i.isAdmin && (moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $t('moderator') }}</MkSwitch> <MkSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $t('moderator') }}</MkSwitch>
<MkSwitch @update:value="toggleSilence" v-model:value="silenced">{{ $t('silence') }}</MkSwitch> <MkSwitch @update:value="toggleSilence" v-model:value="silenced">{{ $t('silence') }}</MkSwitch>
<MkSwitch @update:value="toggleSuspend" v-model:value="suspended">{{ $t('suspend') }}</MkSwitch> <MkSwitch @update:value="toggleSuspend" v-model:value="suspended">{{ $t('suspend') }}</MkSwitch>
</div> </div>

View file

@ -6,7 +6,7 @@
<div class="history" v-if="messages.length > 0"> <div class="history" v-if="messages.length > 0">
<MkA v-for="(message, i) in messages" <MkA v-for="(message, i) in messages"
class="message _panel" class="message _panel"
:class="{ isMe: isMe(message), isRead: message.groupId ? message.reads.includes($store.state.i.id) : message.isRead }" :class="{ isMe: isMe(message), isRead: message.groupId ? message.reads.includes($i.id) : message.isRead }"
:to="message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`" :to="message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
:data-index="i" :data-index="i"
:key="message.id" :key="message.id"
@ -88,7 +88,7 @@ export default defineComponent({
getAcct, getAcct,
isMe(message) { isMe(message) {
return message.userId == this.$store.state.i.id; return message.userId == this.$i.id;
}, },
onMessage(message) { onMessage(message) {
@ -111,7 +111,7 @@ export default defineComponent({
if (found.recipientId) { if (found.recipientId) {
found.isRead = true; found.isRead = true;
} else if (found.groupId) { } else if (found.groupId) {
found.reads.push(this.$store.state.i.id); found.reads.push(this.$i.id);
} }
} }
} }

View file

@ -91,8 +91,8 @@ export default defineComponent({
const file = items[0].getAsFile(); const file = items[0].getAsFile();
const lio = file.name.lastIndexOf('.'); const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : ''; const ext = lio >= 0 ? file.name.slice(lio) : '';
const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.settings.pastedFileName).replace(/{{number}}/g, '1')}${ext}`; const formatted = `${formatTimeString(new Date(file.lastModified), this.$store.state.pastedFileName).replace(/{{number}}/g, '1')}${ext}`;
const name = this.$store.state.settings.pasteDialog const name = this.$store.state.pasteDialog
? await os.dialog({ ? await os.dialog({
title: this.$t('enterFileName'), title: this.$t('enterFileName'),
input: { input: {
@ -163,7 +163,7 @@ export default defineComponent({
}, },
upload(file: File, name?: string) { upload(file: File, name?: string) {
os.upload(file, this.$store.state.settings.uploadFolder, name).then(res => { os.upload(file, this.$store.state.uploadFolder, name).then(res => {
this.file = res; this.file = res;
}); });
}, },

View file

@ -7,7 +7,7 @@
<img src="/assets/remove.png" alt="Delete"/> <img src="/assets/remove.png" alt="Delete"/>
</button> </button>
<div class="content" v-if="!message.isDeleted"> <div class="content" v-if="!message.isDeleted">
<Mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/> <Mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$i"/>
<div class="file" v-if="message.file"> <div class="file" v-if="message.file">
<a :href="message.file.url" rel="noopener" target="_blank" :title="message.file.name"> <a :href="message.file.url" rel="noopener" target="_blank" :title="message.file.name">
<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/> <img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/>
@ -56,7 +56,7 @@ export default defineComponent({
}, },
computed: { computed: {
isMe(): boolean { isMe(): boolean {
return this.message.userId === this.$store.state.i.id; return this.message.userId === this.$i.id;
}, },
urls(): string[] { urls(): string[] {
if (this.message.text) { if (this.message.text) {

View file

@ -110,7 +110,7 @@ const Component = defineComponent({
mounted() { mounted() {
this.fetch(); this.fetch();
if (this.$store.state.device.enableInfiniteScroll) { if (this.$store.state.enableInfiniteScroll) {
this.$nextTick(() => this.ilObserver.observe(this.$refs.loadMore as Element)); this.$nextTick(() => this.ilObserver.observe(this.$refs.loadMore as Element));
} }
}, },
@ -224,7 +224,7 @@ const Component = defineComponent({
const _isBottom = isBottom(this.$el, 64); const _isBottom = isBottom(this.$el, 64);
this.messages.push(message); this.messages.push(message);
if (message.userId != this.$store.state.i.id && !document.hidden) { if (message.userId != this.$i.id && !document.hidden) {
this.connection.send('read', { this.connection.send('read', {
id: message.id id: message.id
}); });
@ -235,7 +235,7 @@ const Component = defineComponent({
this.$nextTick(() => { this.$nextTick(() => {
this.scrollToBottom(); this.scrollToBottom();
}); });
} else if (message.userId != this.$store.state.i.id) { } else if (message.userId != this.$i.id) {
// Notify // Notify
this.notifyNewMessage(); this.notifyNewMessage();
} }
@ -299,7 +299,7 @@ const Component = defineComponent({
onVisibilitychange() { onVisibilitychange() {
if (document.hidden) return; if (document.hidden) return;
for (const message of this.messages) { for (const message of this.messages) {
if (message.userId !== this.$store.state.i.id && !message.isRead) { if (message.userId !== this.$i.id && !message.isRead) {
this.connection.send('read', { this.connection.send('read', {
id: message.id id: message.id
}); });

View file

@ -238,7 +238,7 @@ export default defineComponent({
preview_hashtag: '#test', preview_hashtag: '#test',
preview_url: `https://example.com`, preview_url: `https://example.com`,
preview_link: `[${this.$t('_mfm.dummy')}](https://example.com)`, preview_link: `[${this.$t('_mfm.dummy')}](https://example.com)`,
preview_emoji: `:${this.$store.state.instance.meta.emojis[0].name}:`, preview_emoji: `:${this.$instance.emojis[0].name}:`,
preview_bold: `**${this.$t('_mfm.dummy')}**`, preview_bold: `**${this.$t('_mfm.dummy')}**`,
preview_small: `<small>${this.$t('_mfm.dummy')}</small>`, preview_small: `<small>${this.$t('_mfm.dummy')}</small>`,
preview_center: `<center>${this.$t('_mfm.dummy')}</center>`, preview_center: `<center>${this.$t('_mfm.dummy')}</center>`,

View file

@ -1,5 +1,5 @@
<template> <template>
<div v-if="$store.getters.isSignedIn"> <div v-if="$i">
<div class="waiting _section" v-if="state == 'waiting'"> <div class="waiting _section" v-if="state == 'waiting'">
<div class="_content"> <div class="_content">
<MkLoading/> <MkLoading/>
@ -41,6 +41,7 @@ import { defineComponent } from 'vue';
import MkSignin from '@/components/signin.vue'; import MkSignin from '@/components/signin.vue';
import MkButton from '@/components/ui/button.vue'; import MkButton from '@/components/ui/button.vue';
import * as os from '@/os'; import * as os from '@/os';
import { login } from '@/account';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -88,8 +89,7 @@ export default defineComponent({
this.state = 'denied'; this.state = 'denied';
}, },
onLogin(res) { onLogin(res) {
localStorage.setItem('i', res.i); login(res.i);
location.reload();
} }
} }
}); });

View file

@ -141,7 +141,7 @@ export default defineComponent({
title: this.$t('_pages.newPage'), title: this.$t('_pages.newPage'),
icon: faPencilAlt, icon: faPencilAlt,
}), }),
author: this.$store.state.i, author: this.$i,
readonly: false, readonly: false,
page: null, page: null,
pageId: null, pageId: null,

View file

@ -21,9 +21,9 @@
<div class="_section links"> <div class="_section links">
<div class="_content"> <div class="_content">
<MkA :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</MkA> <MkA :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</MkA>
<template v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId"> <template v-if="$i && $i.id === page.userId">
<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</MkA> <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</MkA>
<button v-if="$store.state.i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $t('unpin') }}</button> <button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $t('unpin') }}</button>
<button v-else @click="pin(true)" class="link _textButton">{{ $t('pin') }}</button> <button v-else @click="pin(true)" class="link _textButton">{{ $t('pin') }}</button>
</template> </template>
</div> </div>

View file

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<MkTab v-model:value="tab" v-if="$store.getters.isSignedIn"> <MkTab v-model:value="tab" v-if="$i">
<option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_pages.featured') }}</option> <option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_pages.featured') }}</option>
<option value="my"><Fa :icon="faEdit"/> {{ $t('_pages.my') }}</option> <option value="my"><Fa :icon="faEdit"/> {{ $t('_pages.my') }}</option>
<option value="liked"><Fa :icon="faHeart"/> {{ $t('_pages.liked') }}</option> <option value="liked"><Fa :icon="faHeart"/> {{ $t('_pages.liked') }}</option>

View file

@ -22,11 +22,11 @@
</div> </div>
<div class="board"> <div class="board">
<div class="labels-x" v-if="$store.state.settings.gamesReversiShowBoardLabels"> <div class="labels-x" v-if="$store.state.gamesReversiShowBoardLabels">
<span v-for="i in game.map[0].length">{{ String.fromCharCode(64 + i) }}</span> <span v-for="i in game.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
</div> </div>
<div class="flex"> <div class="flex">
<div class="labels-y" v-if="$store.state.settings.gamesReversiShowBoardLabels"> <div class="labels-y" v-if="$store.state.gamesReversiShowBoardLabels">
<div v-for="i in game.map.length">{{ i }}</div> <div v-for="i in game.map.length">{{ i }}</div>
</div> </div>
<div class="cells" :style="cellsStyle"> <div class="cells" :style="cellsStyle">
@ -35,7 +35,7 @@
@click="set(i)" @click="set(i)"
:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`" :title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`"
> >
<template v-if="$store.state.settings.gamesReversiUseAvatarStones || true"> <template v-if="$store.state.gamesReversiUseAvatarStones || true">
<img v-if="stone === true" :src="blackUser.avatarUrl" alt="black"> <img v-if="stone === true" :src="blackUser.avatarUrl" alt="black">
<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white"> <img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white">
</template> </template>
@ -45,11 +45,11 @@
</template> </template>
</div> </div>
</div> </div>
<div class="labels-y" v-if="$store.state.settings.gamesReversiShowBoardLabels"> <div class="labels-y" v-if="$store.state.gamesReversiShowBoardLabels">
<div v-for="i in game.map.length">{{ i }}</div> <div v-for="i in game.map.length">{{ i }}</div>
</div> </div>
</div> </div>
<div class="labels-x" v-if="$store.state.settings.gamesReversiShowBoardLabels"> <div class="labels-x" v-if="$store.state.gamesReversiShowBoardLabels">
<span v-for="i in game.map[0].length">{{ String.fromCharCode(64 + i) }}</span> <span v-for="i in game.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
</div> </div>
</div> </div>
@ -126,14 +126,14 @@ export default defineComponent({
computed: { computed: {
iAmPlayer(): boolean { iAmPlayer(): boolean {
if (!this.$store.getters.isSignedIn) return false; if (!this.$i) return false;
return this.game.user1Id == this.$store.state.i.id || this.game.user2Id == this.$store.state.i.id; return this.game.user1Id == this.$i.id || this.game.user2Id == this.$i.id;
}, },
myColor(): Color { myColor(): Color {
if (!this.iAmPlayer) return null; if (!this.iAmPlayer) return null;
if (this.game.user1Id == this.$store.state.i.id && this.game.black == 1) return true; if (this.game.user1Id == this.$i.id && this.game.black == 1) return true;
if (this.game.user2Id == this.$store.state.i.id && this.game.black == 2) return true; if (this.game.user2Id == this.$i.id && this.game.black == 2) return true;
return false; return false;
}, },
@ -234,7 +234,7 @@ export default defineComponent({
isMyTurn(): boolean { isMyTurn(): boolean {
if (!this.iAmPlayer) return false; if (!this.iAmPlayer) return false;
if (this.turnUser() == null) return false; if (this.turnUser() == null) return false;
return this.turnUser().id == this.$store.state.i.id; return this.turnUser().id == this.$i.id;
}, },
set(pos) { set(pos) {

View file

@ -169,13 +169,13 @@ export default defineComponent({
return categories.filter((item, pos) => categories.indexOf(item) == pos); return categories.filter((item, pos) => categories.indexOf(item) == pos);
}, },
isAccepted(): boolean { isAccepted(): boolean {
if (this.game.user1Id == this.$store.state.i.id && this.game.user1Accepted) return true; if (this.game.user1Id == this.$i.id && this.game.user1Accepted) return true;
if (this.game.user2Id == this.$store.state.i.id && this.game.user2Accepted) return true; if (this.game.user2Id == this.$i.id && this.game.user2Accepted) return true;
return false; return false;
}, },
isOpAccepted(): boolean { isOpAccepted(): boolean {
if (this.game.user1Id != this.$store.state.i.id && this.game.user1Accepted) return true; if (this.game.user1Id != this.$i.id && this.game.user1Accepted) return true;
if (this.game.user2Id != this.$store.state.i.id && this.game.user2Accepted) return true; if (this.game.user2Id != this.$i.id && this.game.user2Accepted) return true;
return false; return false;
} }
}, },
@ -186,8 +186,8 @@ export default defineComponent({
this.connection.on('initForm', this.onInitForm); this.connection.on('initForm', this.onInitForm);
this.connection.on('message', this.onMessage); this.connection.on('message', this.onMessage);
if (this.game.user1Id != this.$store.state.i.id && this.game.form1) this.form = this.game.form1; if (this.game.user1Id != this.$i.id && this.game.form1) this.form = this.game.form1;
if (this.game.user2Id != this.$store.state.i.id && this.game.form2) this.form = this.game.form2; if (this.game.user2Id != this.$i.id && this.game.form2) this.form = this.game.form2;
}, },
beforeUnmount() { beforeUnmount() {
@ -233,12 +233,12 @@ export default defineComponent({
}, },
onInitForm(x) { onInitForm(x) {
if (x.userId == this.$store.state.i.id) return; if (x.userId == this.$i.id) return;
this.form = x.form; this.form = x.form;
}, },
onMessage(x) { onMessage(x) {
if (x.userId == this.$store.state.i.id) return; if (x.userId == this.$i.id) return;
this.messages.unshift(x.message); this.messages.unshift(x.message);
}, },

View file

@ -91,7 +91,7 @@ export default defineComponent({
}, },
mounted() { mounted() {
if (this.$store.getters.isSignedIn) { if (this.$i) {
this.connection = os.stream.useSharedConnection('gamesReversi'); this.connection = os.stream.useSharedConnection('gamesReversi');
this.connection.on('invited', this.onInvited); this.connection.on('invited', this.onInvited);

View file

@ -62,6 +62,7 @@ import MkButton from '@/components/ui/button.vue';
import MkSelect from '@/components/ui/select.vue'; import MkSelect from '@/components/ui/select.vue';
import { selectFile } from '@/scripts/select-file'; import { selectFile } from '@/scripts/select-file';
import * as os from '@/os'; import * as os from '@/os';
import { ColdDeviceStorage } from '@/store';
let room: Room; let room: Room;
@ -107,7 +108,7 @@ export default defineComponent({
...parseAcct(this.acct) ...parseAcct(this.acct)
}); });
this.isMyRoom = this.$store.getters.isSignedIn && (this.$store.state.i.id === this.user.id); this.isMyRoom = this.$i && (this.$i.id === this.user.id);
const roomInfo = await os.api('room/show', { const roomInfo = await os.api('room/show', {
userId: this.user.id userId: this.user.id
@ -117,7 +118,7 @@ export default defineComponent({
this.carpetColor = roomInfo.carpetColor; this.carpetColor = roomInfo.carpetColor;
room = new Room(this.user, this.isMyRoom, roomInfo, this.$el, { room = new Room(this.user, this.isMyRoom, roomInfo, this.$el, {
graphicsQuality: this.$store.state.device.roomGraphicsQuality, graphicsQuality: ColdDeviceStorage.get('roomGraphicsQuality'),
onChangeSelect: obj => { onChangeSelect: obj => {
this.objectSelected = obj != null; this.objectSelected = obj != null;
if (obj) { if (obj) {
@ -132,7 +133,7 @@ export default defineComponent({
}); });
} }
}, },
useOrthographicCamera: this.$store.state.device.roomUseOrthographicCamera useOrthographicCamera: ColdDeviceStorage.get('roomUseOrthographicCamera'),
}); });
}, },

View file

@ -2,8 +2,8 @@
<section class="_card"> <section class="_card">
<div class="_title"><Fa :icon="faLock"/> {{ $t('twoStepAuthentication') }}</div> <div class="_title"><Fa :icon="faLock"/> {{ $t('twoStepAuthentication') }}</div>
<div class="_content"> <div class="_content">
<MkButton v-if="!data && !$store.state.i.twoFactorEnabled" @click="register">{{ $t('_2fa.registerDevice') }}</MkButton> <MkButton v-if="!data && !$i.twoFactorEnabled" @click="register">{{ $t('_2fa.registerDevice') }}</MkButton>
<template v-if="$store.state.i.twoFactorEnabled"> <template v-if="$i.twoFactorEnabled">
<p>{{ $t('_2fa.alreadyRegistered') }}</p> <p>{{ $t('_2fa.alreadyRegistered') }}</p>
<MkButton @click="unregister">{{ $t('unregister') }}</MkButton> <MkButton @click="unregister">{{ $t('unregister') }}</MkButton>
@ -13,14 +13,14 @@
<h2 class="heading">{{ $t('securityKey') }}</h2> <h2 class="heading">{{ $t('securityKey') }}</h2>
<p>{{ $t('_2fa.securityKeyInfo') }}</p> <p>{{ $t('_2fa.securityKeyInfo') }}</p>
<div class="key-list"> <div class="key-list">
<div class="key" v-for="key in $store.state.i.securityKeysList"> <div class="key" v-for="key in $i.securityKeysList">
<h3>{{ key.name }}</h3> <h3>{{ key.name }}</h3>
<div class="last-used">{{ $t('lastUsed') }}<MkTime :time="key.lastUsed"/></div> <div class="last-used">{{ $t('lastUsed') }}<MkTime :time="key.lastUsed"/></div>
<MkButton @click="unregisterKey(key)">{{ $t('unregister') }}</MkButton> <MkButton @click="unregisterKey(key)">{{ $t('unregister') }}</MkButton>
</div> </div>
</div> </div>
<MkSwitch v-model:value="usePasswordLessLogin" @update:value="updatePasswordLessLogin" v-if="$store.state.i.securityKeysList.length > 0">{{ $t('passwordLessLogin') }}</MkSwitch> <MkSwitch v-model:value="usePasswordLessLogin" @update:value="updatePasswordLessLogin" v-if="$i.securityKeysList.length > 0">{{ $t('passwordLessLogin') }}</MkSwitch>
<MkInfo warn v-if="registration && registration.error">{{ $t('error') }} {{ registration.error }}</MkInfo> <MkInfo warn v-if="registration && registration.error">{{ $t('error') }} {{ registration.error }}</MkInfo>
<MkButton v-if="!registration || registration.error" @click="addSecurityKey">{{ $t('_2fa.registerKey') }}</MkButton> <MkButton v-if="!registration || registration.error" @click="addSecurityKey">{{ $t('_2fa.registerKey') }}</MkButton>
@ -42,7 +42,7 @@
</ol> </ol>
</template> </template>
</template> </template>
<div v-if="data && !$store.state.i.twoFactorEnabled"> <div v-if="data && !$i.twoFactorEnabled">
<ol style="margin: 0; padding: 0 0 0 1em;"> <ol style="margin: 0; padding: 0 0 0 1em;">
<li> <li>
<i18n-t keypath="_2fa.step1" tag="span"> <i18n-t keypath="_2fa.step1" tag="span">
@ -96,7 +96,7 @@ export default defineComponent({
}, },
data: null, data: null,
supportsCredentials: !!navigator.credentials, supportsCredentials: !!navigator.credentials,
usePasswordLessLogin: this.$store.state.i.usePasswordLessLogin, usePasswordLessLogin: this.$i.usePasswordLessLogin,
registration: null, registration: null,
keyName: '', keyName: '',
token: null, token: null,
@ -136,7 +136,7 @@ export default defineComponent({
this.updatePasswordLessLogin(); this.updatePasswordLessLogin();
}).then(() => { }).then(() => {
os.success(); os.success();
this.$store.state.i.twoFactorEnabled = false; this.$i.twoFactorEnabled = false;
}); });
}); });
}, },
@ -146,7 +146,7 @@ export default defineComponent({
token: this.token token: this.token
}).then(() => { }).then(() => {
os.success(); os.success();
this.$store.state.i.twoFactorEnabled = true; this.$i.twoFactorEnabled = true;
}).catch(e => { }).catch(e => {
os.dialog({ os.dialog({
type: 'error', type: 'error',
@ -213,9 +213,9 @@ export default defineComponent({
name: 'Misskey' name: 'Misskey'
}, },
user: { user: {
id: byteify(this.$store.state.i.id, 'ascii'), id: byteify(this.$i.id, 'ascii'),
name: this.$store.state.i.username, name: this.$i.username,
displayName: this.$store.state.i.name, displayName: this.$i.name,
}, },
pubKeyCredParams: [{ alg: -7, type: 'public-key' }], pubKeyCredParams: [{ alg: -7, type: 'public-key' }],
timeout: 60000, timeout: 60000,

View file

@ -2,13 +2,13 @@
<FormBase> <FormBase>
<FormKeyValueView> <FormKeyValueView>
<template #key>ID</template> <template #key>ID</template>
<template #value><span class="_monospace">{{ $store.state.i.id }}</span></template> <template #value><span class="_monospace">{{ $i.id }}</span></template>
</FormKeyValueView> </FormKeyValueView>
<FormGroup> <FormGroup>
<FormKeyValueView> <FormKeyValueView>
<template #key>{{ $t('registeredDate') }}</template> <template #key>{{ $t('registeredDate') }}</template>
<template #value><MkTime :time="$store.state.i.createdAt" mode="detail"/></template> <template #value><MkTime :time="$i.createdAt" mode="detail"/></template>
</FormKeyValueView> </FormKeyValueView>
</FormGroup> </FormGroup>
@ -104,27 +104,27 @@
<template #label>{{ $t('other') }}</template> <template #label>{{ $t('other') }}</template>
<FormKeyValueView> <FormKeyValueView>
<template #key>emailVerified</template> <template #key>emailVerified</template>
<template #value>{{ $store.state.i.emailVerified ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.emailVerified ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
<FormKeyValueView> <FormKeyValueView>
<template #key>twoFactorEnabled</template> <template #key>twoFactorEnabled</template>
<template #value>{{ $store.state.i.twoFactorEnabled ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.twoFactorEnabled ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
<FormKeyValueView> <FormKeyValueView>
<template #key>securityKeys</template> <template #key>securityKeys</template>
<template #value>{{ $store.state.i.securityKeys ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.securityKeys ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
<FormKeyValueView> <FormKeyValueView>
<template #key>usePasswordLessLogin</template> <template #key>usePasswordLessLogin</template>
<template #value>{{ $store.state.i.usePasswordLessLogin ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.usePasswordLessLogin ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
<FormKeyValueView> <FormKeyValueView>
<template #key>isModerator</template> <template #key>isModerator</template>
<template #value>{{ $store.state.i.isModerator ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.isModerator ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
<FormKeyValueView> <FormKeyValueView>
<template #key>isAdmin</template> <template #key>isAdmin</template>
<template #value>{{ $store.state.i.isAdmin ? $t('yes') : $t('no') }}</template> <template #value>{{ $i.isAdmin ? $t('yes') : $t('no') }}</template>
</FormKeyValueView> </FormKeyValueView>
</FormGroup> </FormGroup>
</FormBase> </FormBase>
@ -171,7 +171,7 @@ export default defineComponent({
this.$emit('info', this.INFO); this.$emit('info', this.INFO);
os.api('users/stats', { os.api('users/stats', {
userId: this.$store.state.i.id userId: this.$i.id
}).then(stats => { }).then(stats => {
this.stats = stats; this.stats = stats;
}); });

View file

@ -5,17 +5,17 @@
<div class="_title"><Fa :icon="faColumns"/> </div> <div class="_title"><Fa :icon="faColumns"/> </div>
<div class="_content"> <div class="_content">
<div>{{ $t('defaultNavigationBehaviour') }}</div> <div>{{ $t('defaultNavigationBehaviour') }}</div>
<MkSwitch v-model:value="deckNavWindow">{{ $t('openInWindow') }}</MkSwitch> <MkSwitch v-model:value="navWindow">{{ $t('openInWindow') }}</MkSwitch>
</div> </div>
<div class="_content"> <div class="_content">
<MkSwitch v-model:value="deckAlwaysShowMainColumn"> <MkSwitch v-model:value="alwaysShowMainColumn">
{{ $t('_deck.alwaysShowMainColumn') }} {{ $t('_deck.alwaysShowMainColumn') }}
</MkSwitch> </MkSwitch>
</div> </div>
<div class="_content"> <div class="_content">
<div>{{ $t('_deck.columnAlign') }}</div> <div>{{ $t('_deck.columnAlign') }}</div>
<MkRadio v-model="deckColumnAlign" value="left">{{ $t('left') }}</MkRadio> <MkRadio v-model="columnAlign" value="left">{{ $t('left') }}</MkRadio>
<MkRadio v-model="deckColumnAlign" value="center">{{ $t('center') }}</MkRadio> <MkRadio v-model="columnAlign" value="center">{{ $t('center') }}</MkRadio>
</div> </div>
</section> </section>
@ -38,6 +38,7 @@ import FormBase from '@/components/form/base.vue';
import FormGroup from '@/components/form/group.vue'; import FormGroup from '@/components/form/group.vue';
import { clientDb, set } from '@/db'; import { clientDb, set } from '@/db';
import * as os from '@/os'; import * as os from '@/os';
import { deckStore } from '@/ui/deck/deck-store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -67,20 +68,9 @@ export default defineComponent({
}, },
computed: { computed: {
deckNavWindow: { navWindow: deckStore.makeGetterSetter('navWindow'),
get() { return this.$store.state.device.deckNavWindow; }, alwaysShowMainColumn: deckStore.makeGetterSetter('alwaysShowMainColumn'),
set(value) { this.$store.commit('device/set', { key: 'deckNavWindow', value }); } columnAlign: deckStore.makeGetterSetter('columnAlign'),
},
deckAlwaysShowMainColumn: {
get() { return this.$store.state.device.deckAlwaysShowMainColumn; },
set(value) { this.$store.commit('device/set', { key: 'deckAlwaysShowMainColumn', value }); }
},
deckColumnAlign: {
get() { return this.$store.state.device.deckColumnAlign; },
set(value) { this.$store.commit('device/set', { key: 'deckColumnAlign', value }); }
},
}, },
mounted() { mounted() {

View file

@ -28,9 +28,9 @@ export default defineComponent({
}, },
async created() { async created() {
if (this.$store.state.settings.uploadFolder) { if (this.$store.state.uploadFolder) {
this.uploadFolder = await os.api('drive/folders/show', { this.uploadFolder = await os.api('drive/folders/show', {
folderId: this.$store.state.settings.uploadFolder folderId: this.$store.state.uploadFolder
}); });
} }
}, },
@ -38,11 +38,11 @@ export default defineComponent({
methods: { methods: {
chooseUploadFolder() { chooseUploadFolder() {
os.selectDriveFolder(false).then(async folder => { os.selectDriveFolder(false).then(async folder => {
await this.$store.dispatch('settings/set', { key: 'uploadFolder', value: folder ? folder.id : null }); this.$store.set('uploadFolder', folder ? folder.id : null);
os.success(); os.success();
if (this.$store.state.settings.uploadFolder) { if (this.$store.state.uploadFolder) {
this.uploadFolder = await os.api('drive/folders/show', { this.uploadFolder = await os.api('drive/folders/show', {
folderId: this.$store.state.settings.uploadFolder folderId: this.$store.state.uploadFolder
}); });
} else { } else {
this.uploadFolder = null; this.uploadFolder = null;

View file

@ -3,8 +3,8 @@
<FormGroup> <FormGroup>
<FormInput v-model:value="emailAddress" type="email"> <FormInput v-model:value="emailAddress" type="email">
{{ $t('emailAddress') }} {{ $t('emailAddress') }}
<template #desc v-if="$store.state.i.email && !$store.state.i.emailVerified">{{ $t('verificationEmailSent') }}</template> <template #desc v-if="$i.email && !$i.emailVerified">{{ $t('verificationEmailSent') }}</template>
<template #desc v-else-if="emailAddress === $store.state.i.email && $store.state.i.emailVerified">{{ $t('emailVerified') }}</template> <template #desc v-else-if="emailAddress === $i.email && $i.emailVerified">{{ $t('emailVerified') }}</template>
</FormInput> </FormInput>
</FormGroup> </FormGroup>
<FormButton @click="save" primary>{{ $t('save') }}</FormButton> <FormButton @click="save" primary>{{ $t('save') }}</FormButton>
@ -44,7 +44,7 @@ export default defineComponent({
}, },
created() { created() {
this.emailAddress = this.$store.state.i.email; this.emailAddress = this.$i.email;
}, },
mounted() { mounted() {

View file

@ -3,9 +3,9 @@
<FormGroup> <FormGroup>
<template #label>{{ $t('emailAddress') }}</template> <template #label>{{ $t('emailAddress') }}</template>
<FormLink to="/settings/email/address"> <FormLink to="/settings/email/address">
<template v-if="$store.state.i.email && !$store.state.i.emailVerified" #icon><Fa :icon="faExclamationTriangle" style="color: var(--warn);"/></template> <template v-if="$i.email && !$i.emailVerified" #icon><Fa :icon="faExclamationTriangle" style="color: var(--warn);"/></template>
<template v-else-if="$store.state.i.email && $store.state.i.emailVerified" #icon><Fa :icon="faCheck" style="color: var(--success);"/></template> <template v-else-if="$i.email && $i.emailVerified" #icon><Fa :icon="faCheck" style="color: var(--success);"/></template>
{{ $store.state.i.email || $t('notSet') }} {{ $i.email || $t('notSet') }}
</FormLink> </FormLink>
</FormGroup> </FormGroup>
</FormBase> </FormBase>

View file

@ -38,7 +38,7 @@
<FormSwitch v-model:value="disableShowingAnimatedImages">{{ $t('disableShowingAnimatedImages') }}</FormSwitch> <FormSwitch v-model:value="disableShowingAnimatedImages">{{ $t('disableShowingAnimatedImages') }}</FormSwitch>
<FormSwitch v-model:value="useSystemFont">{{ $t('useSystemFont') }}</FormSwitch> <FormSwitch v-model:value="useSystemFont">{{ $t('useSystemFont') }}</FormSwitch>
<FormSwitch v-model:value="useOsNativeEmojis">{{ $t('useOsNativeEmojis') }} <FormSwitch v-model:value="useOsNativeEmojis">{{ $t('useOsNativeEmojis') }}
<div><Mfm text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div> <div><Mfm text="🍮🍦🍭🍩🍰🍫🍬🥞🍪" :key="useOsNativeEmojis"/></div>
</FormSwitch> </FormSwitch>
</FormGroup> </FormGroup>
@ -96,6 +96,8 @@ import MkLink from '@/components/link.vue';
import { langs } from '@/config'; import { langs } from '@/config';
import { clientDb, set } from '@/db'; import { clientDb, set } from '@/db';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store';
import { ColdDeviceStorage } from '@/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -126,85 +128,22 @@ export default defineComponent({
}, },
computed: { computed: {
serverDisconnectedBehavior: { serverDisconnectedBehavior: defaultStore.makeGetterSetter('serverDisconnectedBehavior'),
get() { return this.$store.state.device.serverDisconnectedBehavior; }, reduceAnimation: defaultStore.makeGetterSetter('animation', v => !v, v => !v),
set(value) { this.$store.commit('device/set', { key: 'serverDisconnectedBehavior', value }); } useBlurEffectForModal: defaultStore.makeGetterSetter('useBlurEffectForModal'),
}, showGapBetweenNotesInTimeline: defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'),
disableAnimatedMfm: defaultStore.makeGetterSetter('animatedMfm', v => !v, v => !v),
reduceAnimation: { useOsNativeEmojis: defaultStore.makeGetterSetter('useOsNativeEmojis'),
get() { return !this.$store.state.device.animation; }, disableShowingAnimatedImages: defaultStore.makeGetterSetter('disableShowingAnimatedImages'),
set(value) { this.$store.commit('device/set', { key: 'animation', value: !value }); } loadRawImages: defaultStore.makeGetterSetter('loadRawImages'),
}, imageNewTab: defaultStore.makeGetterSetter('imageNewTab'),
nsfw: defaultStore.makeGetterSetter('nsfw'),
useBlurEffectForModal: { disablePagesScript: defaultStore.makeGetterSetter('disablePagesScript'),
get() { return this.$store.state.device.useBlurEffectForModal; }, showFixedPostForm: defaultStore.makeGetterSetter('showFixedPostForm'),
set(value) { this.$store.commit('device/set', { key: 'useBlurEffectForModal', value: value }); } defaultSideView: defaultStore.makeGetterSetter('defaultSideView'),
}, chatOpenBehavior: ColdDeviceStorage.makeGetterSetter('chatOpenBehavior'),
instanceTicker: defaultStore.makeGetterSetter('instanceTicker'),
showGapBetweenNotesInTimeline: { enableInfiniteScroll: defaultStore.makeGetterSetter('enableInfiniteScroll'),
get() { return this.$store.state.device.showGapBetweenNotesInTimeline; },
set(value) { this.$store.commit('device/set', { key: 'showGapBetweenNotesInTimeline', value: value }); }
},
disableAnimatedMfm: {
get() { return !this.$store.state.device.animatedMfm; },
set(value) { this.$store.commit('device/set', { key: 'animatedMfm', value: !value }); }
},
useOsNativeEmojis: {
get() { return this.$store.state.device.useOsNativeEmojis; },
set(value) { this.$store.commit('device/set', { key: 'useOsNativeEmojis', value }); }
},
imageNewTab: {
get() { return this.$store.state.device.imageNewTab; },
set(value) { this.$store.commit('device/set', { key: 'imageNewTab', value }); }
},
disablePagesScript: {
get() { return this.$store.state.device.disablePagesScript; },
set(value) { this.$store.commit('device/set', { key: 'disablePagesScript', value }); }
},
showFixedPostForm: {
get() { return this.$store.state.device.showFixedPostForm; },
set(value) { this.$store.commit('device/set', { key: 'showFixedPostForm', value }); }
},
defaultSideView: {
get() { return this.$store.state.device.defaultSideView; },
set(value) { this.$store.commit('device/set', { key: 'defaultSideView', value }); }
},
chatOpenBehavior: {
get() { return this.$store.state.device.chatOpenBehavior; },
set(value) { this.$store.commit('device/set', { key: 'chatOpenBehavior', value }); }
},
instanceTicker: {
get() { return this.$store.state.device.instanceTicker; },
set(value) { this.$store.commit('device/set', { key: 'instanceTicker', value }); }
},
loadRawImages: {
get() { return this.$store.state.device.loadRawImages; },
set(value) { this.$store.commit('device/set', { key: 'loadRawImages', value }); }
},
disableShowingAnimatedImages: {
get() { return this.$store.state.device.disableShowingAnimatedImages; },
set(value) { this.$store.commit('device/set', { key: 'disableShowingAnimatedImages', value }); }
},
nsfw: {
get() { return this.$store.state.device.nsfw; },
set(value) { this.$store.commit('device/set', { key: 'nsfw', value }); }
},
enableInfiniteScroll: {
get() { return this.$store.state.device.enableInfiniteScroll; },
set(value) { this.$store.commit('device/set', { key: 'enableInfiniteScroll', value }); }
},
}, },
watch: { watch: {

View file

@ -41,13 +41,13 @@
import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, ref, watch } from 'vue'; import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, ref, watch } from 'vue';
import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes } from '@fortawesome/free-solid-svg-icons'; import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes } from '@fortawesome/free-solid-svg-icons';
import { faLaugh, faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons'; import { faLaugh, faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons';
import { store } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import FormLink from '@/components/form/link.vue'; import FormLink from '@/components/form/link.vue';
import FormGroup from '@/components/form/group.vue'; import FormGroup from '@/components/form/group.vue';
import FormBase from '@/components/form/base.vue'; import FormBase from '@/components/form/base.vue';
import FormButton from '@/components/form/button.vue'; import FormButton from '@/components/form/button.vue';
import { scroll } from '../../scripts/scroll'; import { scroll } from '@/scripts/scroll';
import { signout } from '@/account';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -101,7 +101,6 @@ export default defineComponent({
case 'plugins': return defineAsyncComponent(() => import('./plugins.vue')); case 'plugins': return defineAsyncComponent(() => import('./plugins.vue'));
case 'import-export': return defineAsyncComponent(() => import('./import-export.vue')); case 'import-export': return defineAsyncComponent(() => import('./import-export.vue'));
case 'account-info': return defineAsyncComponent(() => import('./account-info.vue')); case 'account-info': return defineAsyncComponent(() => import('./account-info.vue'));
case 'regedit': return defineAsyncComponent(() => import('./regedit.vue'));
case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue')); case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue'));
default: return null; default: return null;
} }
@ -125,8 +124,7 @@ export default defineComponent({
onInfo, onInfo,
component, component,
logout: () => { logout: () => {
store.dispatch('logout'); signout();
location.href = '/';
}, },
faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope, faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope,
}; };

View file

@ -57,11 +57,11 @@ export default defineComponent({
computed: { computed: {
integrations() { integrations() {
return this.$store.state.i.integrations; return this.$i.integrations;
}, },
meta() { meta() {
return this.$store.state.instance.meta; return this.$instance;
}, },
}, },
@ -74,7 +74,7 @@ export default defineComponent({
mounted() { mounted() {
this.$emit('info', this.INFO); this.$emit('info', this.INFO);
document.cookie = `igi=${this.$store.state.i.token}; path=/;` + document.cookie = `igi=${this.$i.token}; path=/;` +
` max-age=31536000;` + ` max-age=31536000;` +
(document.location.protocol.startsWith('https') ? ' secure' : ''); (document.location.protocol.startsWith('https') ? ' secure' : '');

View file

@ -58,7 +58,7 @@ export default defineComponent({
}, },
configure() { configure() {
const includingTypes = notificationTypes.filter(x => !this.$store.state.i.mutingNotificationTypes.includes(x)); const includingTypes = notificationTypes.filter(x => !this.$i.mutingNotificationTypes.includes(x));
os.popup(import('@/components/notification-setting-window.vue'), { os.popup(import('@/components/notification-setting-window.vue'), {
includingTypes, includingTypes,
showGlobalToggle: false, showGlobalToggle: false,
@ -68,7 +68,7 @@ export default defineComponent({
await os.apiWithDialog('i/update', { await os.apiWithDialog('i/update', {
mutingNotificationTypes: notificationTypes.filter(x => !value.includes(x)), mutingNotificationTypes: notificationTypes.filter(x => !value.includes(x)),
}).then(i => { }).then(i => {
this.$store.state.i.mutingNotificationTypes = i.mutingNotificationTypes; this.$i.mutingNotificationTypes = i.mutingNotificationTypes;
}); });
} }
}, 'closed'); }, 'closed');

View file

@ -1,6 +1,6 @@
<template> <template>
<FormBase> <FormBase>
<FormSwitch :value="$store.state.i.injectFeaturedNote" @update:value="onChangeInjectFeaturedNote"> <FormSwitch :value="$i.injectFeaturedNote" @update:value="onChangeInjectFeaturedNote">
{{ $t('showFeaturedNotesInTimeline') }} {{ $t('showFeaturedNotesInTimeline') }}
</FormSwitch> </FormSwitch>

View file

@ -15,7 +15,7 @@
<details> <details>
<summary><Fa :icon="faFolderOpen"/> {{ $t('manage') }}</summary> <summary><Fa :icon="faFolderOpen"/> {{ $t('manage') }}</summary>
<MkSelect v-model:value="selectedPluginId"> <MkSelect v-model:value="selectedPluginId">
<option v-for="x in $store.state.deviceUser.plugins" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in plugins" :value="x.id" :key="x.id">{{ x.name }}</option>
</MkSelect> </MkSelect>
<template v-if="selectedPlugin"> <template v-if="selectedPlugin">
<div style="margin: -8px 0 8px 0;"> <div style="margin: -8px 0 8px 0;">
@ -55,6 +55,7 @@ import MkSelect from '@/components/ui/select.vue';
import MkInfo from '@/components/ui/info.vue'; import MkInfo from '@/components/ui/info.vue';
import MkSwitch from '@/components/ui/switch.vue'; import MkSwitch from '@/components/ui/switch.vue';
import * as os from '@/os'; import * as os from '@/os';
import { ColdDeviceStorage } from '@/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -68,6 +69,7 @@ export default defineComponent({
data() { data() {
return { return {
script: '', script: '',
plugins: ColdDeviceStorage.get('plugins'),
selectedPluginId: null, selectedPluginId: null,
faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog
} }
@ -76,11 +78,22 @@ export default defineComponent({
computed: { computed: {
selectedPlugin() { selectedPlugin() {
if (this.selectedPluginId == null) return null; if (this.selectedPluginId == null) return null;
return this.$store.state.deviceUser.plugins.find(x => x.id === this.selectedPluginId); return this.plugins.find(x => x.id === this.selectedPluginId);
}, },
}, },
methods: { methods: {
installPlugin({ id, meta, ast, token }) {
ColdDeviceStorage.set('plugins', this.plugins.concat({
...meta,
id,
active: true,
configData: {},
token: token,
ast: ast
}));
},
async install() { async install() {
let ast; let ast;
try { try {
@ -137,7 +150,7 @@ export default defineComponent({
}, 'closed'); }, 'closed');
}); });
this.$store.commit('deviceUser/installPlugin', { this.installPlugin({
id: uuid(), id: uuid(),
meta: { meta: {
name, version, author, description, permissions, config name, version, author, description, permissions, config
@ -154,7 +167,7 @@ export default defineComponent({
}, },
uninstall() { uninstall() {
this.$store.commit('deviceUser/uninstallPlugin', this.selectedPluginId); ColdDeviceStorage.set('plugins', this.plugins.filter(x => x.id !== this.selectedPluginId));
os.success(); os.success();
this.$nextTick(() => { this.$nextTick(() => {
location.reload(); location.reload();
@ -171,10 +184,9 @@ export default defineComponent({
const { canceled, result } = await os.form(this.selectedPlugin.name, config); const { canceled, result } = await os.form(this.selectedPlugin.name, config);
if (canceled) return; if (canceled) return;
this.$store.commit('deviceUser/configPlugin', { const plugins = ColdDeviceStorage.get('plugins');
id: this.selectedPluginId, plugins.find(p => p.id === this.selectedPluginId).configData = result;
config: result ColdDeviceStorage.set('plugins', plugins);
});
this.$nextTick(() => { this.$nextTick(() => {
location.reload(); location.reload();
@ -182,10 +194,9 @@ export default defineComponent({
}, },
changeActive(plugin, active) { changeActive(plugin, active) {
this.$store.commit('deviceUser/changePluginActive', { const plugins = ColdDeviceStorage.get('plugins');
id: plugin.id, plugins.find(p => p.id === plugin.id).active = active;
active: active ColdDeviceStorage.set('plugins', plugins);
});
this.$nextTick(() => { this.$nextTick(() => {
location.reload(); location.reload();

View file

@ -35,6 +35,7 @@ import FormSelect from '@/components/form/select.vue';
import FormBase from '@/components/form/base.vue'; import FormBase from '@/components/form/base.vue';
import FormGroup from '@/components/form/group.vue'; import FormGroup from '@/components/form/group.vue';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -60,27 +61,16 @@ export default defineComponent({
}, },
computed: { computed: {
defaultNoteVisibility: { defaultNoteVisibility: defaultStore.makeGetterSetter('defaultNoteVisibility'),
get() { return this.$store.state.settings.defaultNoteVisibility; }, defaultNoteLocalOnly: defaultStore.makeGetterSetter('defaultNoteLocalOnly'),
set(value) { this.$store.dispatch('settings/set', { key: 'defaultNoteVisibility', value }); } rememberNoteVisibility: defaultStore.makeGetterSetter('rememberNoteVisibility'),
},
defaultNoteLocalOnly: {
get() { return this.$store.state.settings.defaultNoteLocalOnly; },
set(value) { this.$store.dispatch('settings/set', { key: 'defaultNoteLocalOnly', value }); }
},
rememberNoteVisibility: {
get() { return this.$store.state.settings.rememberNoteVisibility; },
set(value) { this.$store.dispatch('settings/set', { key: 'rememberNoteVisibility', value }); }
},
}, },
created() { created() {
this.isLocked = this.$store.state.i.isLocked; this.isLocked = this.$i.isLocked;
this.autoAcceptFollowed = this.$store.state.i.autoAcceptFollowed; this.autoAcceptFollowed = this.$i.autoAcceptFollowed;
this.noCrawle = this.$store.state.i.noCrawle; this.noCrawle = this.$i.noCrawle;
this.isExplorable = this.$store.state.i.isExplorable; this.isExplorable = this.$i.isExplorable;
}, },
mounted() { mounted() {

View file

@ -1,8 +1,8 @@
<template> <template>
<FormBase> <FormBase>
<FormGroup> <FormGroup>
<div class="_formItem _formPanel llvierxe" :style="{ backgroundImage: $store.state.i.bannerUrl ? `url(${ $store.state.i.bannerUrl })` : null }"> <div class="_formItem _formPanel llvierxe" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }">
<MkAvatar class="avatar" :user="$store.state.i"/> <MkAvatar class="avatar" :user="$i"/>
</div> </div>
<FormButton @click="changeAvatar" primary>{{ $t('_profile.changeAvatar') }}</FormButton> <FormButton @click="changeAvatar" primary>{{ $t('_profile.changeAvatar') }}</FormButton>
<FormButton @click="changeBanner" primary>{{ $t('_profile.changeBanner') }}</FormButton> <FormButton @click="changeBanner" primary>{{ $t('_profile.changeBanner') }}</FormButton>
@ -100,24 +100,24 @@ export default defineComponent({
}, },
created() { created() {
this.name = this.$store.state.i.name; this.name = this.$i.name;
this.description = this.$store.state.i.description; this.description = this.$i.description;
this.location = this.$store.state.i.location; this.location = this.$i.location;
this.birthday = this.$store.state.i.birthday; this.birthday = this.$i.birthday;
this.avatarId = this.$store.state.i.avatarId; this.avatarId = this.$i.avatarId;
this.bannerId = this.$store.state.i.bannerId; this.bannerId = this.$i.bannerId;
this.isBot = this.$store.state.i.isBot; this.isBot = this.$i.isBot;
this.isCat = this.$store.state.i.isCat; this.isCat = this.$i.isCat;
this.alwaysMarkNsfw = this.$store.state.i.alwaysMarkNsfw; this.alwaysMarkNsfw = this.$i.alwaysMarkNsfw;
this.fieldName0 = this.$store.state.i.fields[0] ? this.$store.state.i.fields[0].name : null; this.fieldName0 = this.$i.fields[0] ? this.$i.fields[0].name : null;
this.fieldValue0 = this.$store.state.i.fields[0] ? this.$store.state.i.fields[0].value : null; this.fieldValue0 = this.$i.fields[0] ? this.$i.fields[0].value : null;
this.fieldName1 = this.$store.state.i.fields[1] ? this.$store.state.i.fields[1].name : null; this.fieldName1 = this.$i.fields[1] ? this.$i.fields[1].name : null;
this.fieldValue1 = this.$store.state.i.fields[1] ? this.$store.state.i.fields[1].value : null; this.fieldValue1 = this.$i.fields[1] ? this.$i.fields[1].value : null;
this.fieldName2 = this.$store.state.i.fields[2] ? this.$store.state.i.fields[2].name : null; this.fieldName2 = this.$i.fields[2] ? this.$i.fields[2].name : null;
this.fieldValue2 = this.$store.state.i.fields[2] ? this.$store.state.i.fields[2].value : null; this.fieldValue2 = this.$i.fields[2] ? this.$i.fields[2].value : null;
this.fieldName3 = this.$store.state.i.fields[3] ? this.$store.state.i.fields[3].name : null; this.fieldName3 = this.$i.fields[3] ? this.$i.fields[3].name : null;
this.fieldValue3 = this.$store.state.i.fields[3] ? this.$store.state.i.fields[3].value : null; this.fieldValue3 = this.$i.fields[3] ? this.$i.fields[3].value : null;
}, },
mounted() { mounted() {
@ -227,10 +227,10 @@ export default defineComponent({
alwaysMarkNsfw: !!this.alwaysMarkNsfw, alwaysMarkNsfw: !!this.alwaysMarkNsfw,
}).then(i => { }).then(i => {
this.saving = false; this.saving = false;
this.$store.state.i.avatarId = i.avatarId; this.$i.avatarId = i.avatarId;
this.$store.state.i.avatarUrl = i.avatarUrl; this.$i.avatarUrl = i.avatarUrl;
this.$store.state.i.bannerId = i.bannerId; this.$i.bannerId = i.bannerId;
this.$store.state.i.bannerUrl = i.bannerUrl; this.$i.bannerUrl = i.bannerUrl;
if (notify) { if (notify) {
os.success(); os.success();

View file

@ -43,8 +43,8 @@ import FormInput from '@/components/form/input.vue';
import FormRadios from '@/components/form/radios.vue'; import FormRadios from '@/components/form/radios.vue';
import FormBase from '@/components/form/base.vue'; import FormBase from '@/components/form/base.vue';
import FormButton from '@/components/form/button.vue'; import FormButton from '@/components/form/button.vue';
import { defaultSettings } from '@/store';
import * as os from '@/os'; import * as os from '@/os';
import { defaultStore } from '@/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -67,24 +67,14 @@ export default defineComponent({
handler: this.preview handler: this.preview
} }
}, },
reactions: JSON.parse(JSON.stringify(this.$store.state.settings.reactions)), reactions: JSON.parse(JSON.stringify(this.$store.state.reactions)),
faLaugh, faSave, faEye, faUndo, faPlus faLaugh, faSave, faEye, faUndo, faPlus
} }
}, },
computed: { computed: {
useFullReactionPicker: { reactionPickerWidth: defaultStore.makeGetterSetter('reactionPickerWidth'),
get() { return this.$store.state.device.useFullReactionPicker; }, reactionPickerHeight: defaultStore.makeGetterSetter('reactionPickerHeight'),
set(value) { this.$store.commit('device/set', { key: 'useFullReactionPicker', value: value }); }
},
reactionPickerWidth: {
get() { return this.$store.state.device.reactionPickerWidth; },
set(value) { this.$store.commit('device/set', { key: 'reactionPickerWidth', value: value }); }
},
reactionPickerHeight: {
get() { return this.$store.state.device.reactionPickerHeight; },
set(value) { this.$store.commit('device/set', { key: 'reactionPickerHeight', value: value }); }
},
}, },
watch: { watch: {
@ -102,7 +92,7 @@ export default defineComponent({
methods: { methods: {
save() { save() {
this.$store.dispatch('settings/set', { key: 'reactions', value: this.reactions }); this.$store.set('reactions', this.reactions);
}, },
remove(reaction, ev) { remove(reaction, ev) {
@ -129,7 +119,7 @@ export default defineComponent({
}); });
if (canceled) return; if (canceled) return;
this.reactions = JSON.parse(JSON.stringify(defaultSettings.reactions)); this.reactions = JSON.parse(JSON.stringify(this.$store.def.reactions.default));
}, },
chooseEmoji(ev) { chooseEmoji(ev) {

Some files were not shown because too many files have changed in this diff Show more