mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-07 12:36:57 +00:00
Refine preferences (#15597)
* wip * wip * wip * test * wip rollup pluginでsearchIndexの情報生成 * wip * SPDX * wip: markerIdを自動付与 * rollupでビルド時・devモード時に毎回uuidを生成するように * 開発サーバーでだけ必要な挙動は開発サーバーのみで * 条件が逆 * wip: childrenの生成 * update comment * update comment * rename auto generated file * hashをパスと行数から決定 * Update privacy.vue * Update privacy.vue * wip * Update general.vue * Update general.vue * wip * wip * Update SearchMarker.vue * wip * Update profile.vue * Update mute-block.vue * Update mute-block.vue * Update general.vue * Update general.vue * childrenがduplicate key errorを吐く問題をいったん解決 * マーカーの形を成形 * loggerを置きかえ * とりあえず省略記法に対応 * Refactor and Format codes * wip * Update settings-search-index.ts * wip * wip * とりあえず不確定要因の仮置きidを削除 * hashの生成を正規化(絶対パスになっていたのを緩和) * pathの入力を省略可能に * adminでもパス生成できるように * Update settings-search-index.ts * Update privacy.vue * wip * build searchIndex * wip * build * Update general.vue * build * Update sounds.vue * build * build * Update sounds.vue * 🎨 * 🎨 * Update privacy.vue * Update privacy.vue * Update security.vue * create-search-indexを多少改善 * build * Update 2fa.vue * wip * 必ずtransformCodeCacheを利用するように, キャッシュの明確な受け渡しを定義 * キャッシュはdevServerでなくても更新 * Revert "wip" This reverts commit 41bffd3a13f55618bf939dc1c9acb2a77ead4054. * inlining * wip * Update theme.vue * 🎨 * wip normalize * Update theme.vue * キャッシュのパス変換 * build * wip * wip * Update SearchMarker.vue * i18n.ts['key'] の形式が取り出せない問題のFix * build * 仮でpath入れ * 必ず絶対パスが使われるように * wip * 🎨 * storybookビルド時はcreateSearchIndexをしない * inliningの構造化 * format code * Update index.vue * wip * wip * 🎨 * wip * wip * wip * wip * wip * wip * wip * wip * clean up * wip * wip * wip * Update rollup-plugin-unwind-css-module-class-name.test.ts * Update navbar.vue * clean up * wip * wip * wip * wip * wip * Update preferences-backups.vue * Update common.ts * Update preferences.ts * wip * wip * wip * wip * Update MkPreferenceContainer.vue * Update MkPreferenceContainer.vue * Update MkPreferenceContainer.vue * enhance: 検索で上下矢印を使用することで検索結果を移動できるように * Update main-boot.ts * refactor * wip * Update sounds.vue * fix(frontend): PageWindowでSearchMarkerが動作するように * enhance(frontend): SearchMarkerの点滅を一定時間で止める * wip * lint fix * fix: 子要素監視が抜けていたのを修正 * アニメーションの回数はCSSで制御するように * refactor * enhance(frontend): 検索インデックス作成時のログを削減 * revert * fix * fix * Update preferences.ts * Update preferences.ts * wip * Update preferences.ts * wip * 🎨 * wip * Update MkPreferenceContainer.vue * wip * Update preferences.ts * wip * Update preferences.ts * Update preferences.ts * wip * wip * Update preferences.ts * wip * wip * Update preferences.ts * Update CHANGELOG.md * Update preferences.ts * Update deck-store.ts * deckStoreをdefaultStoreに統合 * wip * defaultStore -> store * Update profile.ts * wip * refactor * wip: plugin * plugin * plugin * plugin * Update plugin.ts * wip * Update plugin.vue * Update preferences.ts * Update main-boot.ts * wip * fix test * Update plugin.vue * Update plugin.vue * Update utility.ts * wip * wip * Update utility.ts * wip * wip * clean up * Update utility.ts --------- Co-authored-by: tai-cha <dev@taichan.site> Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com> Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
This commit is contained in:
parent
05cdc095c0
commit
d30ddd4c2e
181 changed files with 3437 additions and 2463 deletions
|
@ -4,7 +4,8 @@
|
||||||
-
|
-
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
-
|
- Feat: 設定の管理が強化されました
|
||||||
|
- 自動でバックアップされるように
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
-
|
-
|
||||||
|
|
80
locales/index.d.ts
vendored
80
locales/index.d.ts
vendored
|
@ -5278,6 +5278,86 @@ export interface Locale extends ILocale {
|
||||||
* アクセシビリティ
|
* アクセシビリティ
|
||||||
*/
|
*/
|
||||||
"accessibility": string;
|
"accessibility": string;
|
||||||
|
/**
|
||||||
|
* 設定のプロファイル
|
||||||
|
*/
|
||||||
|
"preferencesProfile": string;
|
||||||
|
/**
|
||||||
|
* 設定IDをコピー
|
||||||
|
*/
|
||||||
|
"copyPreferenceId": string;
|
||||||
|
/**
|
||||||
|
* 初期値に戻す
|
||||||
|
*/
|
||||||
|
"resetToDefaultValue": string;
|
||||||
|
/**
|
||||||
|
* アカウントで上書き
|
||||||
|
*/
|
||||||
|
"overrideByAccount": string;
|
||||||
|
/**
|
||||||
|
* 無題
|
||||||
|
*/
|
||||||
|
"untitled": string;
|
||||||
|
/**
|
||||||
|
* 名前はありません
|
||||||
|
*/
|
||||||
|
"noName": string;
|
||||||
|
/**
|
||||||
|
* スキップ
|
||||||
|
*/
|
||||||
|
"skip": string;
|
||||||
|
/**
|
||||||
|
* 復元
|
||||||
|
*/
|
||||||
|
"restore": string;
|
||||||
|
"_preferencesProfile": {
|
||||||
|
/**
|
||||||
|
* プロファイル名
|
||||||
|
*/
|
||||||
|
"profileName": string;
|
||||||
|
/**
|
||||||
|
* このデバイスを識別する名前を設定してください。
|
||||||
|
*/
|
||||||
|
"profileNameDescription": string;
|
||||||
|
/**
|
||||||
|
* 例: 「メインPC」、「スマホ」など
|
||||||
|
*/
|
||||||
|
"profileNameDescription2": string;
|
||||||
|
};
|
||||||
|
"_preferencesBackup": {
|
||||||
|
/**
|
||||||
|
* 自動バックアップ
|
||||||
|
*/
|
||||||
|
"autoBackup": string;
|
||||||
|
/**
|
||||||
|
* バックアップから復元
|
||||||
|
*/
|
||||||
|
"restoreFromBackup": string;
|
||||||
|
/**
|
||||||
|
* バックアップが見つかりませんでした
|
||||||
|
*/
|
||||||
|
"noBackupsFoundTitle": string;
|
||||||
|
/**
|
||||||
|
* 自動で作成されたバックアップは見つかりませんでしたが、バックアップファイルを手動で保存している場合、それをインポートして復元することはできます。
|
||||||
|
*/
|
||||||
|
"noBackupsFoundDescription": string;
|
||||||
|
/**
|
||||||
|
* 復元するバックアップを選択してください
|
||||||
|
*/
|
||||||
|
"selectBackupToRestore": string;
|
||||||
|
/**
|
||||||
|
* 自動バックアップを有効にするにはプロファイル名の設定が必要です。
|
||||||
|
*/
|
||||||
|
"youNeedToNameYourProfileToEnableAutoBackup": string;
|
||||||
|
/**
|
||||||
|
* このデバイスで設定の自動バックアップは有効になっていません。
|
||||||
|
*/
|
||||||
|
"autoPreferencesBackupIsNotEnabledForThisDevice": string;
|
||||||
|
/**
|
||||||
|
* 設定のバックアップが見つかりました
|
||||||
|
*/
|
||||||
|
"backupFound": string;
|
||||||
|
};
|
||||||
"_accountSettings": {
|
"_accountSettings": {
|
||||||
/**
|
/**
|
||||||
* コンテンツの表示にログインを必須にする
|
* コンテンツの表示にログインを必須にする
|
||||||
|
|
|
@ -1315,6 +1315,29 @@ markAsSensitiveConfirm: "このメディアをセンシティブとして設定
|
||||||
unmarkAsSensitiveConfirm: "このメディアのセンシティブ指定を解除しますか?"
|
unmarkAsSensitiveConfirm: "このメディアのセンシティブ指定を解除しますか?"
|
||||||
preferences: "環境設定"
|
preferences: "環境設定"
|
||||||
accessibility: "アクセシビリティ"
|
accessibility: "アクセシビリティ"
|
||||||
|
preferencesProfile: "設定のプロファイル"
|
||||||
|
copyPreferenceId: "設定IDをコピー"
|
||||||
|
resetToDefaultValue: "初期値に戻す"
|
||||||
|
overrideByAccount: "アカウントで上書き"
|
||||||
|
untitled: "無題"
|
||||||
|
noName: "名前はありません"
|
||||||
|
skip: "スキップ"
|
||||||
|
restore: "復元"
|
||||||
|
|
||||||
|
_preferencesProfile:
|
||||||
|
profileName: "プロファイル名"
|
||||||
|
profileNameDescription: "このデバイスを識別する名前を設定してください。"
|
||||||
|
profileNameDescription2: "例: 「メインPC」、「スマホ」など"
|
||||||
|
|
||||||
|
_preferencesBackup:
|
||||||
|
autoBackup: "自動バックアップ"
|
||||||
|
restoreFromBackup: "バックアップから復元"
|
||||||
|
noBackupsFoundTitle: "バックアップが見つかりませんでした"
|
||||||
|
noBackupsFoundDescription: "自動で作成されたバックアップは見つかりませんでしたが、バックアップファイルを手動で保存している場合、それをインポートして復元することはできます。"
|
||||||
|
selectBackupToRestore: "復元するバックアップを選択してください"
|
||||||
|
youNeedToNameYourProfileToEnableAutoBackup: "自動バックアップを有効にするにはプロファイル名の設定が必要です。"
|
||||||
|
autoPreferencesBackupIsNotEnabledForThisDevice: "このデバイスで設定の自動バックアップは有効になっていません。"
|
||||||
|
backupFound: "設定のバックアップが見つかりました"
|
||||||
|
|
||||||
_accountSettings:
|
_accountSettings:
|
||||||
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
requireSigninToViewContents: "コンテンツの表示にログインを必須にする"
|
||||||
|
|
|
@ -68,9 +68,9 @@ queueMicrotask(() => {
|
||||||
import('../src/directives'),
|
import('../src/directives'),
|
||||||
import('../src/widgets'),
|
import('../src/widgets'),
|
||||||
import('../src/scripts/theme'),
|
import('../src/scripts/theme'),
|
||||||
import('../src/store'),
|
import('../src/preferences'),
|
||||||
import('../src/os'),
|
import('../src/os'),
|
||||||
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { defaultStore }, os]) => {
|
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => {
|
||||||
setup((app) => {
|
setup((app) => {
|
||||||
moduleInitialized = true;
|
moduleInitialized = true;
|
||||||
if (app[appInitialized]) {
|
if (app[appInitialized]) {
|
||||||
|
@ -83,7 +83,7 @@ queueMicrotask(() => {
|
||||||
widgets(app);
|
widgets(app);
|
||||||
misskeyOS = os;
|
misskeyOS = os;
|
||||||
if (isChromatic()) {
|
if (isChromatic()) {
|
||||||
defaultStore.set('animation', false);
|
prefer.set('animation', false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -104,9 +104,9 @@ const preview = {
|
||||||
}
|
}
|
||||||
}).catch(() => {})
|
}).catch(() => {})
|
||||||
: Promise.resolve();
|
: Promise.resolve();
|
||||||
const resetDefaultStorePromise = import('../src/store').then(({ defaultStore }) => {
|
const resetDefaultStorePromise = import('../src/store').then(({ store }) => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
defaultStore.init();
|
store.init();
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {
|
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {
|
||||||
initLocalStorage();
|
initLocalStorage();
|
||||||
|
|
|
@ -58,7 +58,7 @@ describe(normalizeClass.name, () => {
|
||||||
|
|
||||||
it('Composition API (standard)', () => {
|
it('Composition API (standard)', () => {
|
||||||
const ast = parse(`
|
const ast = parse(`
|
||||||
import { c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js';
|
import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js';
|
||||||
import { M as MkContainer } from './MkContainer-!~{03M}~.js';
|
import { M as MkContainer } from './MkContainer-!~{03M}~.js';
|
||||||
import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js';
|
import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js';
|
||||||
import './photoswipe-!~{003}~.js';
|
import './photoswipe-!~{003}~.js';
|
||||||
|
@ -74,7 +74,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
||||||
let fetching = ref(true);
|
let fetching = ref(true);
|
||||||
let images = ref([]);
|
let images = ref([]);
|
||||||
function thumbnail(image) {
|
function thumbnail(image) {
|
||||||
return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
|
return store.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const image = [
|
const image = [
|
||||||
|
@ -173,7 +173,7 @@ export { index_photos as default };
|
||||||
`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' });
|
`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' });
|
||||||
unwindCssModuleClassName(ast);
|
unwindCssModuleClassName(ast);
|
||||||
expect(generate(ast)).toBe(`
|
expect(generate(ast)).toBe(`
|
||||||
import {c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js';
|
import {c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js';
|
||||||
import {M as MkContainer} from './MkContainer-!~{03M}~.js';
|
import {M as MkContainer} from './MkContainer-!~{03M}~.js';
|
||||||
import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js';
|
import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js';
|
||||||
import './photoswipe-!~{003}~.js';
|
import './photoswipe-!~{003}~.js';
|
||||||
|
@ -190,7 +190,7 @@ const index_photos = defineComponent({
|
||||||
let fetching = ref(true);
|
let fetching = ref(true);
|
||||||
let images = ref([]);
|
let images = ref([]);
|
||||||
function thumbnail(image) {
|
function thumbnail(image) {
|
||||||
return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
|
return store.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"];
|
const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"];
|
||||||
|
@ -268,7 +268,7 @@ export {index_photos as default};
|
||||||
it('Composition API (with `useCssModule()`)', () => {
|
it('Composition API (with `useCssModule()`)', () => {
|
||||||
const ast = parse(`
|
const ast = parse(`
|
||||||
import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js';
|
import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js';
|
||||||
import { d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js';
|
import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js';
|
||||||
|
|
||||||
function isDebuggerEnabled(id) {
|
function isDebuggerEnabled(id) {
|
||||||
try {
|
try {
|
||||||
|
@ -393,7 +393,7 @@ const _sfc_main = defineComponent({
|
||||||
el.style.left = "";
|
el.style.left = "";
|
||||||
}
|
}
|
||||||
return () => h(
|
return () => h(
|
||||||
defaultStore.state.animation ? TransitionGroup : "div",
|
prefer.s.animation ? TransitionGroup : "div",
|
||||||
{
|
{
|
||||||
class: {
|
class: {
|
||||||
[$style["date-separated-list"]]: true,
|
[$style["date-separated-list"]]: true,
|
||||||
|
@ -402,7 +402,7 @@ const _sfc_main = defineComponent({
|
||||||
[$style["direction-down"]]: props.direction === "down",
|
[$style["direction-down"]]: props.direction === "down",
|
||||||
[$style["direction-up"]]: props.direction === "up"
|
[$style["direction-up"]]: props.direction === "up"
|
||||||
},
|
},
|
||||||
...defaultStore.state.animation ? {
|
...prefer.s.animation ? {
|
||||||
name: "list",
|
name: "list",
|
||||||
tag: "div",
|
tag: "div",
|
||||||
onBeforeLeave,
|
onBeforeLeave,
|
||||||
|
@ -441,7 +441,7 @@ export { MkDateSeparatedList as M };
|
||||||
unwindCssModuleClassName(ast);
|
unwindCssModuleClassName(ast);
|
||||||
expect(generate(ast)).toBe(`
|
expect(generate(ast)).toBe(`
|
||||||
import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js';
|
import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js';
|
||||||
import {d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js';
|
import {d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js';
|
||||||
function isDebuggerEnabled(id) {
|
function isDebuggerEnabled(id) {
|
||||||
try {
|
try {
|
||||||
return localStorage.getItem(\`DEBUG_\${id}\`) !== null;
|
return localStorage.getItem(\`DEBUG_\${id}\`) !== null;
|
||||||
|
@ -555,7 +555,7 @@ const _sfc_main = defineComponent({
|
||||||
el.style.top = "";
|
el.style.top = "";
|
||||||
el.style.left = "";
|
el.style.left = "";
|
||||||
}
|
}
|
||||||
return () => h(defaultStore.state.animation ? TransitionGroup : "div", {
|
return () => h(prefer.s.animation ? TransitionGroup : "div", {
|
||||||
class: {
|
class: {
|
||||||
[$style["date-separated-list"]]: true,
|
[$style["date-separated-list"]]: true,
|
||||||
[$style["date-separated-list-nogap"]]: props.noGap,
|
[$style["date-separated-list-nogap"]]: props.noGap,
|
||||||
|
@ -563,7 +563,7 @@ const _sfc_main = defineComponent({
|
||||||
[$style["direction-down"]]: props.direction === "down",
|
[$style["direction-down"]]: props.direction === "down",
|
||||||
[$style["direction-up"]]: props.direction === "up"
|
[$style["direction-up"]]: props.direction === "up"
|
||||||
},
|
},
|
||||||
...defaultStore.state.animation ? {
|
...prefer.s.animation ? {
|
||||||
name: "list",
|
name: "list",
|
||||||
tag: "div",
|
tag: "div",
|
||||||
onBeforeLeave,
|
onBeforeLeave,
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
import { computed, watch, version as vueVersion } from 'vue';
|
import { computed, watch, version as vueVersion } from 'vue';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
import { version, lang, updateLocale, locale } from '@@/js/config.js';
|
import { version, lang, updateLocale, locale } from '@@/js/config.js';
|
||||||
|
import defaultLightTheme from '@@/themes/l-light.json5';
|
||||||
|
import defaultDarkTheme from '@@/themes/d-green-lime.json5';
|
||||||
import type { App } from 'vue';
|
import type { App } from 'vue';
|
||||||
import widgets from '@/widgets/index.js';
|
import widgets from '@/widgets/index.js';
|
||||||
import directives from '@/directives/index.js';
|
import directives from '@/directives/index.js';
|
||||||
|
@ -14,7 +16,7 @@ import { applyTheme } from '@/scripts/theme.js';
|
||||||
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js';
|
||||||
import { updateI18n, i18n } from '@/i18n.js';
|
import { updateI18n, i18n } from '@/i18n.js';
|
||||||
import { $i, refreshAccount, login } from '@/account.js';
|
import { $i, refreshAccount, login } from '@/account.js';
|
||||||
import { defaultStore, ColdDeviceStorage } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { fetchInstance, instance } from '@/instance.js';
|
||||||
import { deviceKind, updateDeviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind, updateDeviceKind } from '@/scripts/device-kind.js';
|
||||||
import { reloadChannel } from '@/scripts/unison-reload.js';
|
import { reloadChannel } from '@/scripts/unison-reload.js';
|
||||||
|
@ -26,6 +28,7 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { setupRouter } from '@/router/main.js';
|
import { setupRouter } from '@/router/main.js';
|
||||||
import { createMainRouter } from '@/router/definition.js';
|
import { createMainRouter } from '@/router/definition.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
export async function common(createVue: () => App<Element>) {
|
export async function common(createVue: () => App<Element>) {
|
||||||
console.info(`Misskey v${version}`);
|
console.info(`Misskey v${version}`);
|
||||||
|
@ -38,7 +41,7 @@ export async function common(createVue: () => App<Element>) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(window as any).$i = $i;
|
(window as any).$i = $i;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(window as any).$store = defaultStore;
|
(window as any).$store = store;
|
||||||
|
|
||||||
window.addEventListener('error', event => {
|
window.addEventListener('error', event => {
|
||||||
console.error(event);
|
console.error(event);
|
||||||
|
@ -123,7 +126,7 @@ export async function common(createVue: () => App<Element>) {
|
||||||
html.setAttribute('lang', lang);
|
html.setAttribute('lang', lang);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
await defaultStore.ready;
|
await store.ready;
|
||||||
await deckStore.ready;
|
await deckStore.ready;
|
||||||
|
|
||||||
const fetchInstanceMetaPromise = fetchInstance();
|
const fetchInstanceMetaPromise = fetchInstance();
|
||||||
|
@ -151,56 +154,63 @@ export async function common(createVue: () => App<Element>) {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため)
|
// NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため)
|
||||||
watch(defaultStore.reactiveState.darkMode, (darkMode) => {
|
watch(store.reactiveState.darkMode, (darkMode) => {
|
||||||
applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'));
|
applyTheme(darkMode
|
||||||
|
? (prefer.s.darkTheme ?? defaultDarkTheme)
|
||||||
|
: (prefer.s.lightTheme ?? defaultLightTheme),
|
||||||
|
);
|
||||||
}, { immediate: miLocalStorage.getItem('theme') == null });
|
}, { immediate: miLocalStorage.getItem('theme') == null });
|
||||||
|
|
||||||
document.documentElement.dataset.colorScheme = defaultStore.state.darkMode ? 'dark' : 'light';
|
document.documentElement.dataset.colorScheme = store.state.darkMode ? 'dark' : 'light';
|
||||||
|
|
||||||
const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme'));
|
const darkTheme = prefer.model('darkTheme');
|
||||||
const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme'));
|
const lightTheme = prefer.model('lightTheme');
|
||||||
|
|
||||||
watch(darkTheme, (theme) => {
|
watch(darkTheme, (theme) => {
|
||||||
if (defaultStore.state.darkMode) {
|
if (store.state.darkMode) {
|
||||||
applyTheme(theme);
|
applyTheme(theme ?? defaultDarkTheme);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(lightTheme, (theme) => {
|
watch(lightTheme, (theme) => {
|
||||||
if (!defaultStore.state.darkMode) {
|
if (!store.state.darkMode) {
|
||||||
applyTheme(theme);
|
applyTheme(theme ?? defaultLightTheme);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region Sync dark mode
|
//#region Sync dark mode
|
||||||
if (ColdDeviceStorage.get('syncDeviceDarkMode')) {
|
if (prefer.s.syncDeviceDarkMode) {
|
||||||
defaultStore.set('darkMode', isDeviceDarkmode());
|
store.set('darkMode', isDeviceDarkmode());
|
||||||
}
|
}
|
||||||
|
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mql) => {
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mql) => {
|
||||||
if (ColdDeviceStorage.get('syncDeviceDarkMode')) {
|
if (prefer.s.syncDeviceDarkMode) {
|
||||||
defaultStore.set('darkMode', mql.matches);
|
store.set('darkMode', mql.matches);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
if (prefer.s.darkTheme && store.state.darkMode) {
|
||||||
|
if (miLocalStorage.getItem('themeId') !== prefer.s.darkTheme.id) applyTheme(prefer.s.darkTheme);
|
||||||
|
} else if (prefer.s.lightTheme && !store.state.darkMode) {
|
||||||
|
if (miLocalStorage.getItem('themeId') !== prefer.s.lightTheme.id) applyTheme(prefer.s.lightTheme);
|
||||||
|
}
|
||||||
|
|
||||||
fetchInstanceMetaPromise.then(() => {
|
fetchInstanceMetaPromise.then(() => {
|
||||||
if (defaultStore.state.themeInitial) {
|
// TODO: instance.defaultLightTheme/instance.defaultDarkThemeが不正な形式だった場合のケア
|
||||||
if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(instance.defaultLightTheme));
|
if (prefer.s.lightTheme == null && instance.defaultLightTheme != null) prefer.set('lightTheme', JSON.parse(instance.defaultLightTheme));
|
||||||
if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(instance.defaultDarkTheme));
|
if (prefer.s.darkTheme == null && instance.defaultDarkTheme != null) prefer.set('darkTheme', JSON.parse(instance.defaultDarkTheme));
|
||||||
defaultStore.set('themeInitial', false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(defaultStore.reactiveState.overridedDeviceKind, (kind) => {
|
watch(store.reactiveState.overridedDeviceKind, (kind) => {
|
||||||
updateDeviceKind(kind);
|
updateDeviceKind(kind);
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(defaultStore.reactiveState.useBlurEffectForModal, v => {
|
watch(prefer.r.useBlurEffectForModal, v => {
|
||||||
document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
|
document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(defaultStore.reactiveState.useBlurEffect, v => {
|
watch(prefer.r.useBlurEffect, v => {
|
||||||
if (v) {
|
if (v) {
|
||||||
document.documentElement.style.removeProperty('--MI-blur');
|
document.documentElement.style.removeProperty('--MI-blur');
|
||||||
} else {
|
} else {
|
||||||
|
@ -214,7 +224,7 @@ export async function common(createVue: () => App<Element>) {
|
||||||
navigator.wakeLock.request('screen');
|
navigator.wakeLock.request('screen');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (defaultStore.state.keepScreenOn && 'wakeLock' in navigator) {
|
if (prefer.s.keepScreenOn && 'wakeLock' in navigator) {
|
||||||
navigator.wakeLock.request('screen')
|
navigator.wakeLock.request('screen')
|
||||||
.then(onVisibilityChange)
|
.then(onVisibilityChange)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
|
@ -5,26 +5,29 @@
|
||||||
|
|
||||||
import { createApp, defineAsyncComponent, markRaw } from 'vue';
|
import { createApp, defineAsyncComponent, markRaw } from 'vue';
|
||||||
import { ui } from '@@/js/config.js';
|
import { ui } from '@@/js/config.js';
|
||||||
import { common } from './common.js';
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { common } from './common.js';
|
||||||
import type { Component } from 'vue';
|
import type { Component } from 'vue';
|
||||||
|
import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { alert, confirm, popup, post, toast } from '@/os.js';
|
import { alert, confirm, popup, post, toast } from '@/os.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i, signout, updateAccountPartial } from '@/account.js';
|
import { $i, signout, updateAccountPartial } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
import { ColdDeviceStorage, store } from '@/store.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
||||||
import { initializeSw } from '@/scripts/initialize-sw.js';
|
import { initializeSw } from '@/scripts/initialize-sw.js';
|
||||||
import { deckStore } from '@/ui/deck/deck-store.js';
|
|
||||||
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { makeHotkey } from '@/scripts/hotkey.js';
|
import { makeHotkey } from '@/scripts/hotkey.js';
|
||||||
import type { Keymap } from '@/scripts/hotkey.js';
|
|
||||||
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
import { deckStore } from '@/ui/deck/deck-store.js';
|
||||||
|
import { launchPlugin } from '@/plugin.js';
|
||||||
|
|
||||||
export async function mainBoot() {
|
export async function mainBoot() {
|
||||||
const { isClientUpdated } = await common(() => {
|
const { isClientUpdated } = await common(() => {
|
||||||
|
@ -34,7 +37,7 @@ export async function mainBoot() {
|
||||||
if (!$i) uiStyle = 'visitor';
|
if (!$i) uiStyle = 'visitor';
|
||||||
|
|
||||||
if (searchParams.has('zen')) uiStyle = 'zen';
|
if (searchParams.has('zen')) uiStyle = 'zen';
|
||||||
if (uiStyle === 'deck' && deckStore.state.useSimpleUiForNonRootPages && location.pathname !== '/') uiStyle = 'zen';
|
if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && location.pathname !== '/') uiStyle = 'zen';
|
||||||
|
|
||||||
if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
|
if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
|
||||||
|
|
||||||
|
@ -73,9 +76,9 @@ export async function mainBoot() {
|
||||||
|
|
||||||
let reloadDialogShowing = false;
|
let reloadDialogShowing = false;
|
||||||
stream.on('_disconnected_', async () => {
|
stream.on('_disconnected_', async () => {
|
||||||
if (defaultStore.state.serverDisconnectedBehavior === 'reload') {
|
if (prefer.s.serverDisconnectedBehavior === 'reload') {
|
||||||
location.reload();
|
location.reload();
|
||||||
} else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') {
|
} else if (prefer.s.serverDisconnectedBehavior === 'dialog') {
|
||||||
if (reloadDialogShowing) return;
|
if (reloadDialogShowing) return;
|
||||||
reloadDialogShowing = true;
|
reloadDialogShowing = true;
|
||||||
const { canceled } = await confirm({
|
const { canceled } = await confirm({
|
||||||
|
@ -102,18 +105,14 @@ export async function mainBoot() {
|
||||||
removeCustomEmojis(emojiData.emojis);
|
removeCustomEmojis(emojiData.emojis);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) {
|
for (const plugin of prefer.s.plugins.filter(p => p.active)) {
|
||||||
import('@/plugin.js').then(async ({ install }) => {
|
launchPlugin(plugin);
|
||||||
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=242740
|
|
||||||
await new Promise(r => setTimeout(r, 0));
|
|
||||||
install(plugin);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (defaultStore.state.enableSeasonalScreenEffect) {
|
if (prefer.s.enableSeasonalScreenEffect) {
|
||||||
const month = new Date().getMonth() + 1;
|
const month = new Date().getMonth() + 1;
|
||||||
if (defaultStore.state.hemisphere === 'S') {
|
if (prefer.s.hemisphere === 'S') {
|
||||||
// ▼南半球
|
// ▼南半球
|
||||||
if (month === 7 || month === 8) {
|
if (month === 7 || month === 8) {
|
||||||
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
|
||||||
|
@ -138,8 +137,99 @@ export async function mainBoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($i) {
|
if ($i) {
|
||||||
defaultStore.loaded.then(() => {
|
store.loaded.then(async () => {
|
||||||
if (defaultStore.state.accountSetupWizard !== -1) {
|
// prefereces migration
|
||||||
|
// TODO: そのうち消す
|
||||||
|
if (store.state.menu.length > 0) {
|
||||||
|
const themes = await misskeyApi('i/registry/get', { scope: ['client'], key: 'themes' }).catch(() => []);
|
||||||
|
if (themes.length > 0) {
|
||||||
|
prefer.set('themes', themes);
|
||||||
|
}
|
||||||
|
const plugins = ColdDeviceStorage.get('plugins');
|
||||||
|
prefer.set('plugins', plugins.map(p => ({
|
||||||
|
...p,
|
||||||
|
installId: (p as any).id,
|
||||||
|
id: undefined,
|
||||||
|
})));
|
||||||
|
prefer.set('lightTheme', ColdDeviceStorage.get('lightTheme'));
|
||||||
|
prefer.set('darkTheme', ColdDeviceStorage.get('darkTheme'));
|
||||||
|
prefer.set('syncDeviceDarkMode', ColdDeviceStorage.get('syncDeviceDarkMode'));
|
||||||
|
prefer.set('keepCw', store.state.keepCw);
|
||||||
|
prefer.set('collapseRenotes', store.state.collapseRenotes);
|
||||||
|
prefer.set('rememberNoteVisibility', store.state.rememberNoteVisibility);
|
||||||
|
prefer.set('uploadFolder', store.state.uploadFolder);
|
||||||
|
prefer.set('keepOriginalUploading', store.state.keepOriginalUploading);
|
||||||
|
prefer.set('menu', store.state.menu);
|
||||||
|
prefer.set('statusbars', store.state.statusbars);
|
||||||
|
prefer.set('pinnedUserLists', store.state.pinnedUserLists);
|
||||||
|
prefer.set('serverDisconnectedBehavior', store.state.serverDisconnectedBehavior);
|
||||||
|
prefer.set('nsfw', store.state.nsfw);
|
||||||
|
prefer.set('highlightSensitiveMedia', store.state.highlightSensitiveMedia);
|
||||||
|
prefer.set('animation', store.state.animation);
|
||||||
|
prefer.set('animatedMfm', store.state.animatedMfm);
|
||||||
|
prefer.set('advancedMfm', store.state.advancedMfm);
|
||||||
|
prefer.set('showReactionsCount', store.state.showReactionsCount);
|
||||||
|
prefer.set('enableQuickAddMfmFunction', store.state.enableQuickAddMfmFunction);
|
||||||
|
prefer.set('loadRawImages', store.state.loadRawImages);
|
||||||
|
prefer.set('imageNewTab', store.state.imageNewTab);
|
||||||
|
prefer.set('disableShowingAnimatedImages', store.state.disableShowingAnimatedImages);
|
||||||
|
prefer.set('emojiStyle', store.state.emojiStyle);
|
||||||
|
prefer.set('menuStyle', store.state.menuStyle);
|
||||||
|
prefer.set('useBlurEffectForModal', store.state.useBlurEffectForModal);
|
||||||
|
prefer.set('useBlurEffect', store.state.useBlurEffect);
|
||||||
|
prefer.set('showFixedPostForm', store.state.showFixedPostForm);
|
||||||
|
prefer.set('showFixedPostFormInChannel', store.state.showFixedPostFormInChannel);
|
||||||
|
prefer.set('enableInfiniteScroll', store.state.enableInfiniteScroll);
|
||||||
|
prefer.set('useReactionPickerForContextMenu', store.state.useReactionPickerForContextMenu);
|
||||||
|
prefer.set('showGapBetweenNotesInTimeline', store.state.showGapBetweenNotesInTimeline);
|
||||||
|
prefer.set('instanceTicker', store.state.instanceTicker);
|
||||||
|
prefer.set('emojiPickerScale', store.state.emojiPickerScale);
|
||||||
|
prefer.set('emojiPickerWidth', store.state.emojiPickerWidth);
|
||||||
|
prefer.set('emojiPickerHeight', store.state.emojiPickerHeight);
|
||||||
|
prefer.set('emojiPickerStyle', store.state.emojiPickerStyle);
|
||||||
|
prefer.set('reportError', store.state.reportError);
|
||||||
|
prefer.set('squareAvatars', store.state.squareAvatars);
|
||||||
|
prefer.set('showAvatarDecorations', store.state.showAvatarDecorations);
|
||||||
|
prefer.set('numberOfPageCache', store.state.numberOfPageCache);
|
||||||
|
prefer.set('showNoteActionsOnlyHover', store.state.showNoteActionsOnlyHover);
|
||||||
|
prefer.set('showClipButtonInNoteFooter', store.state.showClipButtonInNoteFooter);
|
||||||
|
prefer.set('reactionsDisplaySize', store.state.reactionsDisplaySize);
|
||||||
|
prefer.set('limitWidthOfReaction', store.state.limitWidthOfReaction);
|
||||||
|
prefer.set('forceShowAds', store.state.forceShowAds);
|
||||||
|
prefer.set('aiChanMode', store.state.aiChanMode);
|
||||||
|
prefer.set('devMode', store.state.devMode);
|
||||||
|
prefer.set('mediaListWithOneImageAppearance', store.state.mediaListWithOneImageAppearance);
|
||||||
|
prefer.set('notificationPosition', store.state.notificationPosition);
|
||||||
|
prefer.set('notificationStackAxis', store.state.notificationStackAxis);
|
||||||
|
prefer.set('enableCondensedLine', store.state.enableCondensedLine);
|
||||||
|
prefer.set('keepScreenOn', store.state.keepScreenOn);
|
||||||
|
prefer.set('disableStreamingTimeline', store.state.disableStreamingTimeline);
|
||||||
|
prefer.set('useGroupedNotifications', store.state.useGroupedNotifications);
|
||||||
|
prefer.set('dataSaver', store.state.dataSaver);
|
||||||
|
prefer.set('enableSeasonalScreenEffect', store.state.enableSeasonalScreenEffect);
|
||||||
|
prefer.set('enableHorizontalSwipe', store.state.enableHorizontalSwipe);
|
||||||
|
prefer.set('useNativeUiForVideoAudioPlayer', store.state.useNativeUIForVideoAudioPlayer);
|
||||||
|
prefer.set('keepOriginalFilename', store.state.keepOriginalFilename);
|
||||||
|
prefer.set('alwaysConfirmFollow', store.state.alwaysConfirmFollow);
|
||||||
|
prefer.set('confirmWhenRevealingSensitiveMedia', store.state.confirmWhenRevealingSensitiveMedia);
|
||||||
|
prefer.set('contextMenu', store.state.contextMenu);
|
||||||
|
prefer.set('skipNoteRender', store.state.skipNoteRender);
|
||||||
|
prefer.set('showSoftWordMutedWord', store.state.showSoftWordMutedWord);
|
||||||
|
prefer.set('confirmOnReact', store.state.confirmOnReact);
|
||||||
|
prefer.set('sound.masterVolume', store.state.sound_masterVolume);
|
||||||
|
prefer.set('sound.notUseSound', store.state.sound_notUseSound);
|
||||||
|
prefer.set('sound.useSoundOnlyWhenActive', store.state.sound_useSoundOnlyWhenActive);
|
||||||
|
prefer.set('sound.on.note', store.state.sound_note as any);
|
||||||
|
prefer.set('sound.on.noteMy', store.state.sound_noteMy as any);
|
||||||
|
prefer.set('sound.on.notification', store.state.sound_notification as any);
|
||||||
|
prefer.set('sound.on.reaction', store.state.sound_reaction as any);
|
||||||
|
store.set('deck.profile', deckStore.state.profile);
|
||||||
|
store.set('deck.columns', deckStore.state.columns);
|
||||||
|
store.set('deck.layout', deckStore.state.layout);
|
||||||
|
store.set('menu', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.state.accountSetupWizard !== -1) {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
|
@ -154,7 +244,7 @@ export async function mainBoot() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAnnouncementCreated (ev: { announcement: Misskey.entities.Announcement }) {
|
function onAnnouncementCreated(ev: { announcement: Misskey.entities.Announcement }) {
|
||||||
const announcement = ev.announcement;
|
const announcement = ev.announcement;
|
||||||
if (announcement.display === 'dialog') {
|
if (announcement.display === 'dialog') {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
|
||||||
|
@ -412,7 +502,7 @@ export async function mainBoot() {
|
||||||
post();
|
post();
|
||||||
},
|
},
|
||||||
'd': () => {
|
'd': () => {
|
||||||
defaultStore.set('darkMode', !defaultStore.state.darkMode);
|
store.set('darkMode', !store.state.darkMode);
|
||||||
},
|
},
|
||||||
's': () => {
|
's': () => {
|
||||||
mainRouter.push('/search');
|
mainRouter.push('/search');
|
||||||
|
|
|
@ -54,17 +54,18 @@ import contains from '@/scripts/contains.js';
|
||||||
import { acct } from '@/filters/user.js';
|
import { acct } from '@/filters/user.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { customEmojis } from '@/custom-emojis.js';
|
import { customEmojis } from '@/custom-emojis.js';
|
||||||
import { searchEmoji } from '@/scripts/search-emoji.js';
|
import { searchEmoji } from '@/scripts/search-emoji.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const lib = emojilist.filter(x => x.category !== 'flags');
|
const lib = emojilist.filter(x => x.category !== 'flags');
|
||||||
|
|
||||||
const emojiDb = computed(() => {
|
const emojiDb = computed(() => {
|
||||||
//#region Unicode Emoji
|
//#region Unicode Emoji
|
||||||
const char2path = defaultStore.reactiveState.emojiStyle.value === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
|
const char2path = prefer.r.emojiStyle.value === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
|
||||||
|
|
||||||
const unicodeEmojiDB: EmojiDef[] = lib.map(x => ({
|
const unicodeEmojiDB: EmojiDef[] = lib.map(x => ({
|
||||||
emoji: x.char,
|
emoji: x.char,
|
||||||
|
@ -72,7 +73,7 @@ const emojiDb = computed(() => {
|
||||||
url: char2path(x.char),
|
url: char2path(x.char),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) {
|
for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
|
||||||
for (const [emoji, keywords] of Object.entries(index)) {
|
for (const [emoji, keywords] of Object.entries(index)) {
|
||||||
for (const k of keywords) {
|
for (const k of keywords) {
|
||||||
unicodeEmojiDB.push({
|
unicodeEmojiDB.push({
|
||||||
|
@ -154,10 +155,10 @@ function complete(type: string, value: any) {
|
||||||
emit('done', { type, value });
|
emit('done', { type, value });
|
||||||
emit('closed');
|
emit('closed');
|
||||||
if (type === 'emoji') {
|
if (type === 'emoji') {
|
||||||
let recents = defaultStore.state.recentlyUsedEmojis;
|
let recents = store.state.recentlyUsedEmojis;
|
||||||
recents = recents.filter((emoji: any) => emoji !== value);
|
recents = recents.filter((emoji: any) => emoji !== value);
|
||||||
recents.unshift(value);
|
recents.unshift(value);
|
||||||
defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32));
|
store.set('recentlyUsedEmojis', recents.splice(0, 32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +238,7 @@ function exec() {
|
||||||
} else if (props.type === 'emoji') {
|
} else if (props.type === 'emoji') {
|
||||||
if (!props.q || props.q === '') {
|
if (!props.q || props.q === '') {
|
||||||
// 最近使った絵文字をサジェスト
|
// 最近使った絵文字をサジェスト
|
||||||
emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[];
|
emojis.value = store.state.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
|
import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
// APIs provided by Captcha services
|
// APIs provided by Captcha services
|
||||||
// see: https://docs.hcaptcha.com/configuration/#javascript-api
|
// see: https://docs.hcaptcha.com/configuration/#javascript-api
|
||||||
|
@ -154,7 +154,7 @@ async function requestRender() {
|
||||||
|
|
||||||
captchaWidgetId.value = captcha.value.render(elem, {
|
captchaWidgetId.value = captcha.value.render(elem, {
|
||||||
sitekey: props.sitekey,
|
sitekey: props.sitekey,
|
||||||
theme: defaultStore.state.darkMode ? 'dark' : 'light',
|
theme: store.state.darkMode ? 'dark' : 'light',
|
||||||
callback: callback,
|
callback: callback,
|
||||||
'expired-callback': () => callback(undefined),
|
'expired-callback': () => callback(undefined),
|
||||||
'error-callback': () => callback(undefined),
|
'error-callback': () => callback(undefined),
|
||||||
|
|
|
@ -54,7 +54,7 @@ import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
|
@ -161,7 +161,7 @@ const render = () => {
|
||||||
chartInstance.destroy();
|
chartInstance.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const maxes = chartData.series.map((x, i) => Math.max(...x.data.map(d => d.y)));
|
const maxes = chartData.series.map((x, i) => Math.max(...x.data.map(d => d.y)));
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { computed, ref, watch } from 'vue';
|
||||||
import { bundledLanguagesInfo } from 'shiki/langs';
|
import { bundledLanguagesInfo } from 'shiki/langs';
|
||||||
import type { BundledLanguage } from 'shiki/langs';
|
import type { BundledLanguage } from 'shiki/langs';
|
||||||
import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js';
|
import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
code: string;
|
code: string;
|
||||||
|
@ -22,7 +22,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const highlighter = await getHighlighter();
|
const highlighter = await getHighlighter();
|
||||||
const darkMode = defaultStore.reactiveState.darkMode;
|
const darkMode = store.reactiveState.darkMode;
|
||||||
const codeLang = ref<BundledLanguage | 'aiscript'>('js');
|
const codeLang = ref<BundledLanguage | 'aiscript'>('js');
|
||||||
|
|
||||||
const [lightThemeName, darkThemeName] = await Promise.all([
|
const [lightThemeName, darkThemeName] = await Promise.all([
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</button>
|
</button>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<MkLoading />
|
<MkLoading/>
|
||||||
</template>
|
</template>
|
||||||
<XCode v-if="show && lang" :code="code" :lang="lang"/>
|
<XCode v-if="show && lang" :code="code" :lang="lang"/>
|
||||||
<pre v-else-if="show" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre>
|
<pre v-else-if="show" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre>
|
||||||
|
@ -28,9 +28,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { defineAsyncComponent, ref } from 'vue';
|
import { defineAsyncComponent, ref } from 'vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import MkLoading from '@/components/global/MkLoading.vue';
|
import MkLoading from '@/components/global/MkLoading.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
code: string;
|
code: string;
|
||||||
|
@ -42,7 +42,7 @@ const props = withDefaults(defineProps<{
|
||||||
forceShow: false,
|
forceShow: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const show = ref(props.forceShow === true ? true : !defaultStore.state.dataSaver.code);
|
const show = ref(props.forceShow === true ? true : !prefer.s.dataSaver.code);
|
||||||
|
|
||||||
const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue'));
|
const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue'));
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''"
|
||||||
@enter="enter"
|
@enter="enter"
|
||||||
@afterEnter="afterEnter"
|
@afterEnter="afterEnter"
|
||||||
@leave="leave"
|
@leave="leave"
|
||||||
|
@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -6,10 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<Transition
|
<Transition
|
||||||
appear
|
appear
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
|
||||||
>
|
>
|
||||||
<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
|
<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
|
||||||
<MkMenu :items="items" :align="'left'" @close="emit('closed')"/>
|
<MkMenu :items="items" :align="'left'" @close="emit('closed')"/>
|
||||||
|
@ -22,7 +22,7 @@ import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import contains from '@/scripts/contains.js';
|
import contains from '@/scripts/contains.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -35,13 +35,13 @@ import { onMounted, shallowRef, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
import { apiUrl } from '@@/js/config.js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { apiUrl } from '@@/js/config.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
|
import { getProxiedImageUrl } from '@/scripts/media-proxy.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
|
(ev: 'ok', cropped: Misskey.entities.DriveFile): void;
|
||||||
|
@ -81,8 +81,8 @@ const ok = async () => {
|
||||||
formData.append('i', $i!.token);
|
formData.append('i', $i!.token);
|
||||||
if (props.uploadFolder) {
|
if (props.uploadFolder) {
|
||||||
formData.append('folderId', props.uploadFolder);
|
formData.append('folderId', props.uploadFolder);
|
||||||
} else if (props.uploadFolder !== null && defaultStore.state.uploadFolder) {
|
} else if (props.uploadFolder !== null && prefer.s.uploadFolder) {
|
||||||
formData.append('folderId', defaultStore.state.uploadFolder);
|
formData.append('folderId', prefer.s.uploadFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.fetch(apiUrl + '/drive/files/create', {
|
window.fetch(apiUrl + '/drive/files/create', {
|
||||||
|
|
|
@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, h, TransitionGroup, useCssModule } from 'vue';
|
import { defineComponent, h, TransitionGroup, useCssModule } from 'vue';
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
import type { MisskeyEntity } from '@/types/date-separated-list.js';
|
||||||
import MkAd from '@/components/global/MkAd.vue';
|
import MkAd from '@/components/global/MkAd.vue';
|
||||||
import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js';
|
import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import type { MisskeyEntity } from '@/types/date-separated-list.js';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -150,7 +150,7 @@ export default defineComponent({
|
||||||
[$style['direction-up']]: props.direction === 'up',
|
[$style['direction-up']]: props.direction === 'up',
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => defaultStore.state.animation ? h(TransitionGroup, {
|
return () => prefer.s.animation ? h(TransitionGroup, {
|
||||||
class: classes,
|
class: classes,
|
||||||
name: 'list',
|
name: 'list',
|
||||||
tag: 'div',
|
tag: 'div',
|
||||||
|
|
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template v-if="!hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template>
|
<template v-if="!hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template>
|
||||||
{{ folder.name }}
|
{{ folder.name }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="defaultStore.state.uploadFolder == folder.id" :class="$style.upload">
|
<p v-if="prefer.s.uploadFolder == folder.id" :class="$style.upload">
|
||||||
{{ i18n.ts.uploadFolder }}
|
{{ i18n.ts.uploadFolder }}
|
||||||
</p>
|
</p>
|
||||||
<button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked">
|
<button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked">
|
||||||
|
@ -40,9 +40,9 @@ import type { MenuItem } from '@/types/menu.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
folder: Misskey.entities.DriveFolder;
|
folder: Misskey.entities.DriveFolder;
|
||||||
|
@ -244,8 +244,8 @@ function deleteFolder() {
|
||||||
misskeyApi('drive/folders/delete', {
|
misskeyApi('drive/folders/delete', {
|
||||||
folderId: props.folder.id,
|
folderId: props.folder.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (defaultStore.state.uploadFolder === props.folder.id) {
|
if (prefer.s.uploadFolder === props.folder.id) {
|
||||||
defaultStore.set('uploadFolder', null);
|
prefer.set('uploadFolder', null);
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
|
@ -266,7 +266,7 @@ function deleteFolder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAsUploadFolder() {
|
function setAsUploadFolder() {
|
||||||
defaultStore.set('uploadFolder', props.folder.id);
|
prefer.set('uploadFolder', props.folder.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onContextmenu(ev: MouseEvent) {
|
function onContextmenu(ev: MouseEvent) {
|
||||||
|
@ -295,7 +295,7 @@ function onContextmenu(ev: MouseEvent) {
|
||||||
danger: true,
|
danger: true,
|
||||||
action: deleteFolder,
|
action: deleteFolder,
|
||||||
}];
|
}];
|
||||||
if (defaultStore.state.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menu = menu.concat([{ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFolderId,
|
text: i18n.ts.copyFolderId,
|
||||||
|
|
|
@ -106,10 +106,10 @@ import XFile from '@/components/MkDrive.file.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { uploadFile, uploads } from '@/scripts/upload.js';
|
import { uploadFile, uploads } from '@/scripts/upload.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
initialFolder?: Misskey.entities.DriveFolder;
|
initialFolder?: Misskey.entities.DriveFolder;
|
||||||
|
@ -142,7 +142,7 @@ const selectedFiles = ref<Misskey.entities.DriveFile[]>([]);
|
||||||
const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]);
|
const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]);
|
||||||
const uploadings = uploads;
|
const uploadings = uploads;
|
||||||
const connection = useStream().useChannel('drive');
|
const connection = useStream().useChannel('drive');
|
||||||
const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい
|
const keepOriginal = ref<boolean>(prefer.s.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい
|
||||||
|
|
||||||
// ドロップされようとしているか
|
// ドロップされようとしているか
|
||||||
const draghover = ref(false);
|
const draghover = ref(false);
|
||||||
|
@ -716,7 +716,7 @@ function onContextmenu(ev: MouseEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (defaultStore.state.enableInfiniteScroll && loadMoreFiles.value) {
|
if (prefer.s.enableInfiniteScroll && loadMoreFiles.value) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
ilFilesObserver.observe(loadMoreFiles.value?.$el);
|
ilFilesObserver.observe(loadMoreFiles.value?.$el);
|
||||||
});
|
});
|
||||||
|
@ -737,7 +737,7 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
if (defaultStore.state.enableInfiniteScroll) {
|
if (prefer.s.enableInfiniteScroll) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
ilFilesObserver.observe(loadMoreFiles.value?.$el);
|
ilFilesObserver.observe(loadMoreFiles.value?.$el);
|
||||||
});
|
});
|
||||||
|
|
|
@ -134,14 +134,15 @@ import * as os from '@/os.js';
|
||||||
import { isTouchUsing } from '@/scripts/touch.js';
|
import { isTouchUsing } from '@/scripts/touch.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
|
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
showPinned?: boolean;
|
showPinned?: boolean;
|
||||||
pinnedEmojis?: string[];
|
pinnedEmojis?: string[];
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
asDrawer?: boolean;
|
asDrawer?: boolean;
|
||||||
asWindow?: boolean;
|
asWindow?: boolean;
|
||||||
|
@ -163,8 +164,9 @@ const {
|
||||||
emojiPickerScale,
|
emojiPickerScale,
|
||||||
emojiPickerWidth,
|
emojiPickerWidth,
|
||||||
emojiPickerHeight,
|
emojiPickerHeight,
|
||||||
recentlyUsedEmojis,
|
} = prefer.r;
|
||||||
} = defaultStore.reactiveState;
|
|
||||||
|
const recentlyUsedEmojis = store.reactiveState.recentlyUsedEmojis;
|
||||||
|
|
||||||
const recentlyUsedEmojisDef = computed(() => {
|
const recentlyUsedEmojisDef = computed(() => {
|
||||||
return recentlyUsedEmojis.value.map(getDef);
|
return recentlyUsedEmojis.value.map(getDef);
|
||||||
|
@ -317,7 +319,7 @@ watch(q, () => {
|
||||||
}
|
}
|
||||||
if (matches.size >= max) return matches;
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) {
|
for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
|
||||||
for (const emoji of emojis) {
|
for (const emoji of emojis) {
|
||||||
if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) {
|
if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) {
|
||||||
matches.add(emoji);
|
matches.add(emoji);
|
||||||
|
@ -334,7 +336,7 @@ watch(q, () => {
|
||||||
}
|
}
|
||||||
if (matches.size >= max) return matches;
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) {
|
for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
|
||||||
for (const emoji of emojis) {
|
for (const emoji of emojis) {
|
||||||
if (index[emoji.char].some(k => k.startsWith(newQ))) {
|
if (index[emoji.char].some(k => k.startsWith(newQ))) {
|
||||||
matches.add(emoji);
|
matches.add(emoji);
|
||||||
|
@ -351,7 +353,7 @@ watch(q, () => {
|
||||||
}
|
}
|
||||||
if (matches.size >= max) return matches;
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) {
|
for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
|
||||||
for (const emoji of emojis) {
|
for (const emoji of emojis) {
|
||||||
if (index[emoji.char].some(k => k.includes(newQ))) {
|
if (index[emoji.char].some(k => k.includes(newQ))) {
|
||||||
matches.add(emoji);
|
matches.add(emoji);
|
||||||
|
@ -413,7 +415,7 @@ function computeButtonTitle(ev: MouseEvent): void {
|
||||||
|
|
||||||
function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) {
|
function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) {
|
||||||
const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
|
const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
|
||||||
if (el && defaultStore.state.animation) {
|
if (el && prefer.s.animation) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
@ -427,10 +429,10 @@ function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef,
|
||||||
|
|
||||||
// 最近使った絵文字更新
|
// 最近使った絵文字更新
|
||||||
if (!pinned.value?.includes(key)) {
|
if (!pinned.value?.includes(key)) {
|
||||||
let recents = defaultStore.state.recentlyUsedEmojis;
|
let recents = store.state.recentlyUsedEmojis;
|
||||||
recents = recents.filter((emoji) => emoji !== key);
|
recents = recents.filter((emoji) => emoji !== key);
|
||||||
recents.unshift(key);
|
recents.unshift(key);
|
||||||
defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32));
|
store.set('recentlyUsedEmojis', recents.splice(0, 32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="modal"
|
ref="modal"
|
||||||
v-slot="{ type, maxHeight }"
|
v-slot="{ type, maxHeight }"
|
||||||
:zPriority="'middle'"
|
:zPriority="'middle'"
|
||||||
:preferType="defaultStore.state.emojiPickerStyle"
|
:preferType="prefer.s.emojiPickerStyle"
|
||||||
:hasInteractionWithOtherFocusTrappedEls="true"
|
:hasInteractionWithOtherFocusTrappedEls="true"
|
||||||
:transparentBg="true"
|
:transparentBg="true"
|
||||||
:manualShowing="manualShowing"
|
:manualShowing="manualShowing"
|
||||||
|
@ -40,16 +40,16 @@ import * as Misskey from 'misskey-js';
|
||||||
import { shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
|
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
manualShowing?: boolean | null;
|
manualShowing?: boolean | null;
|
||||||
src?: HTMLElement;
|
src?: HTMLElement;
|
||||||
showPinned?: boolean;
|
showPinned?: boolean;
|
||||||
pinnedEmojis?: string[],
|
pinnedEmojis?: string[],
|
||||||
asReactionPicker?: boolean;
|
asReactionPicker?: boolean;
|
||||||
targetNote?: Misskey.entities.Note;
|
targetNote?: Misskey.entities.Note;
|
||||||
choseAndClose?: boolean;
|
choseAndClose?: boolean;
|
||||||
}>(), {
|
}>(), {
|
||||||
manualShowing: null,
|
manualShowing: null,
|
||||||
showPinned: true,
|
showPinned: true,
|
||||||
|
|
|
@ -14,10 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.folderToggleEnterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.folderToggleEnterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.folderToggleLeaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.folderToggleLeaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.folderToggleEnterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.folderToggleEnterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.folderToggleLeaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.folderToggleLeaveTo : ''"
|
||||||
@enter="enter"
|
@enter="enter"
|
||||||
@afterEnter="afterEnter"
|
@afterEnter="afterEnter"
|
||||||
@leave="leave"
|
@leave="leave"
|
||||||
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, shallowRef, watch } from 'vue';
|
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||||
|
|
||||||
const miLocalStoragePrefix = 'ui:folder:' as const;
|
const miLocalStoragePrefix = 'ui:folder:' as const;
|
||||||
|
|
|
@ -27,10 +27,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened">
|
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened">
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''"
|
||||||
@enter="enter"
|
@enter="enter"
|
||||||
@afterEnter="afterEnter"
|
@afterEnter="afterEnter"
|
||||||
@leave="leave"
|
@leave="leave"
|
||||||
|
@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, ref, shallowRef } from 'vue';
|
import { nextTick, onMounted, ref, shallowRef } from 'vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { getBgColor } from '@/scripts/get-bg-color.js';
|
import { getBgColor } from '@/scripts/get-bg-color.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -45,7 +45,8 @@ import { i18n } from '@/i18n.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
user: Misskey.entities.UserDetailed,
|
user: Misskey.entities.UserDetailed,
|
||||||
|
@ -100,7 +101,7 @@ async function onClick() {
|
||||||
userId: props.user.id,
|
userId: props.user.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (defaultStore.state.alwaysConfirmFollow) {
|
if (prefer.s.alwaysConfirmFollow) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }),
|
text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }),
|
||||||
|
@ -120,11 +121,11 @@ async function onClick() {
|
||||||
} else {
|
} else {
|
||||||
await misskeyApi('following/create', {
|
await misskeyApi('following/create', {
|
||||||
userId: props.user.id,
|
userId: props.user.id,
|
||||||
withReplies: defaultStore.state.defaultWithReplies,
|
withReplies: store.state.defaultWithReplies,
|
||||||
});
|
});
|
||||||
emit('update:user', {
|
emit('update:user', {
|
||||||
...props.user,
|
...props.user,
|
||||||
withReplies: defaultStore.state.defaultWithReplies,
|
withReplies: store.state.defaultWithReplies,
|
||||||
});
|
});
|
||||||
hasPendingFollowRequestFromYou.value = true;
|
hasPendingFollowRequestFromYou.value = true;
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
post: Misskey.entities.GalleryPost;
|
post: Misskey.entities.GalleryPost;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const hover = ref(false);
|
const hover = ref(false);
|
||||||
const safe = computed(() => defaultStore.state.nsfw === 'ignore' || defaultStore.state.nsfw === 'respect' && !props.post.isSensitive);
|
const safe = computed(() => prefer.s.nsfw === 'ignore' || prefer.s.nsfw === 'respect' && !props.post.isSensitive);
|
||||||
const show = computed(() => safe.value || hover.value);
|
const show = computed(() => safe.value || hover.value);
|
||||||
|
|
||||||
function enterHover(): void {
|
function enterHover(): void {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { onMounted, nextTick, watch, shallowRef, ref } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
import { initChart } from '@/scripts/init-chart.js';
|
import { initChart } from '@/scripts/init-chart.js';
|
||||||
|
@ -106,7 +106,7 @@ async function renderChart() {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300';
|
const color = store.state.darkMode ? '#b4e900' : '#86b300';
|
||||||
|
|
||||||
// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする
|
// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする
|
||||||
const max = values.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3;
|
const max = values.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3;
|
||||||
|
|
|
@ -28,12 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef, computed, nextTick, watch } from 'vue';
|
import { ref, shallowRef, computed, nextTick, watch } from 'vue';
|
||||||
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { isHorizontalSwipeSwiping as isSwiping } from '@/scripts/touch.js';
|
import { isHorizontalSwipeSwiping as isSwiping } from '@/scripts/touch.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const rootEl = shallowRef<HTMLDivElement>();
|
const rootEl = shallowRef<HTMLDivElement>();
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const tabModel = defineModel<string>('tab');
|
const tabModel = defineModel<string>('tab');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -44,7 +43,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'swiped', newKey: string, direction: 'left' | 'right'): void;
|
(ev: 'swiped', newKey: string, direction: 'left' | 'right'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const shouldAnimate = computed(() => defaultStore.reactiveState.enableHorizontalSwipe.value || defaultStore.reactiveState.animation.value);
|
const shouldAnimate = computed(() => prefer.r.enableHorizontalSwipe.value || prefer.r.animation.value);
|
||||||
|
|
||||||
// ▼ しきい値 ▼ //
|
// ▼ しきい値 ▼ //
|
||||||
|
|
||||||
|
@ -72,7 +71,7 @@ const isSwipingForClass = ref(false);
|
||||||
let swipeAborted = false;
|
let swipeAborted = false;
|
||||||
|
|
||||||
function touchStart(event: TouchEvent) {
|
function touchStart(event: TouchEvent) {
|
||||||
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return;
|
if (!prefer.r.enableHorizontalSwipe.value) return;
|
||||||
|
|
||||||
if (event.touches.length !== 1) return;
|
if (event.touches.length !== 1) return;
|
||||||
|
|
||||||
|
@ -83,7 +82,7 @@ function touchStart(event: TouchEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchMove(event: TouchEvent) {
|
function touchMove(event: TouchEvent) {
|
||||||
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return;
|
if (!prefer.r.enableHorizontalSwipe.value) return;
|
||||||
|
|
||||||
if (event.touches.length !== 1) return;
|
if (event.touches.length !== 1) return;
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ function touchEnd(event: TouchEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return;
|
if (!prefer.r.enableHorizontalSwipe.value) return;
|
||||||
|
|
||||||
if (event.touches.length !== 0) return;
|
if (event.touches.length !== 0) return;
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''">
|
<div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''">
|
||||||
<TransitionGroup
|
<TransitionGroup
|
||||||
:duration="defaultStore.state.animation && props.transition?.duration || undefined"
|
:duration="prefer.s.animation && props.transition?.duration || undefined"
|
||||||
:enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined"
|
:enterActiveClass="prefer.s.animation && props.transition?.enterActiveClass || undefined"
|
||||||
:leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined"
|
:leaveActiveClass="prefer.s.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined"
|
||||||
:enterFromClass="defaultStore.state.animation && props.transition?.enterFromClass || undefined"
|
:enterFromClass="prefer.s.animation && props.transition?.enterFromClass || undefined"
|
||||||
:leaveToClass="defaultStore.state.animation && props.transition?.leaveToClass || undefined"
|
:leaveToClass="prefer.s.animation && props.transition?.leaveToClass || undefined"
|
||||||
:enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined"
|
:enterToClass="prefer.s.animation && props.transition?.enterToClass || undefined"
|
||||||
:leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined"
|
:leaveFromClass="prefer.s.animation && props.transition?.leaveFromClass || undefined"
|
||||||
>
|
>
|
||||||
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
|
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
|
||||||
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
|
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
|
||||||
|
@ -60,7 +60,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
||||||
import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch, ref } from 'vue';
|
import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch, ref } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { render } from 'buraha';
|
import { render } from 'buraha';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
transition?: {
|
transition?: {
|
||||||
|
|
|
@ -30,8 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import { navbarItemDef } from '@/navbar.js';
|
import { navbarItemDef } from '@/navbar.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
src?: HTMLElement;
|
src?: HTMLElement;
|
||||||
|
@ -50,7 +50,7 @@ const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'pop
|
||||||
|
|
||||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
|
|
||||||
const menu = defaultStore.state.menu;
|
const menu = prefer.s.menu;
|
||||||
|
|
||||||
const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k => navbarItemDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
|
const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k => navbarItemDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
|
||||||
type: def.to ? 'link' : 'button',
|
type: def.to ? 'link' : 'button',
|
||||||
|
|
|
@ -10,20 +10,20 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
:class="[
|
:class="[
|
||||||
$style.audioContainer,
|
$style.audioContainer,
|
||||||
(audio.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive,
|
(audio.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive,
|
||||||
]"
|
]"
|
||||||
@contextmenu.stop
|
@contextmenu.stop
|
||||||
@keydown.stop
|
@keydown.stop
|
||||||
>
|
>
|
||||||
<button v-if="hide" :class="$style.hidden" @click="show">
|
<button v-if="hide" :class="$style.hidden" @click="show">
|
||||||
<div :class="$style.hiddenTextWrapper">
|
<div :class="$style.hiddenTextWrapper">
|
||||||
<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b>
|
<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b>
|
||||||
<b v-else style="display: block;"><i class="ti ti-music"></i> {{ defaultStore.state.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b>
|
<b v-else style="display: block;"><i class="ti ti-music"></i> {{ prefer.s.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b>
|
||||||
<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.nativeAudioContainer">
|
<div v-else-if="prefer.s.useNativeUiForVideoAudioPlayer" :class="$style.nativeAudioContainer">
|
||||||
<audio
|
<audio
|
||||||
ref="audioEl"
|
ref="audioEl"
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
|
@ -93,13 +93,13 @@ import * as Misskey from 'misskey-js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import type { Keymap } from '@/scripts/hotkey.js';
|
import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import { hms } from '@/filters/hms.js';
|
import { hms } from '@/filters/hms.js';
|
||||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
audio: Misskey.entities.DriveFile;
|
audio: Misskey.entities.DriveFile;
|
||||||
|
@ -155,10 +155,10 @@ const playerEl = shallowRef<HTMLDivElement>();
|
||||||
const audioEl = shallowRef<HTMLAudioElement>();
|
const audioEl = shallowRef<HTMLAudioElement>();
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore'));
|
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore'));
|
||||||
|
|
||||||
async function show() {
|
async function show() {
|
||||||
if (props.audio.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
|
if (props.audio.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.ts.sensitiveMediaRevealConfirm,
|
text: i18n.ts.sensitiveMediaRevealConfirm,
|
||||||
|
@ -240,7 +240,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
menu.push({ type: 'divider' }, ...details);
|
menu.push({ type: 'divider' }, ...details);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu.push({ type: 'divider' }, {
|
menu.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
|
@ -407,7 +407,7 @@ onDeactivated(() => {
|
||||||
elapsedTimeMs.value = 0;
|
elapsedTimeMs.value = 0;
|
||||||
durationMs.value = 0;
|
durationMs.value = 0;
|
||||||
bufferedEnd.value = 0;
|
bufferedEnd.value = 0;
|
||||||
hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore');
|
hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore');
|
||||||
stopAudioElWatch();
|
stopAudioElWatch();
|
||||||
onceInit = false;
|
onceInit = false;
|
||||||
if (mediaTickFrameId) {
|
if (mediaTickFrameId) {
|
||||||
|
|
|
@ -27,9 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import MkMediaAudio from '@/components/MkMediaAudio.vue';
|
import MkMediaAudio from '@/components/MkMediaAudio.vue';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
media: Misskey.entities.DriveFile;
|
media: Misskey.entities.DriveFile;
|
||||||
|
@ -38,7 +38,7 @@ const props = defineProps<{
|
||||||
const hide = ref(true);
|
const hide = ref(true);
|
||||||
|
|
||||||
async function show() {
|
async function show() {
|
||||||
if (props.media.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
|
if (props.media.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.ts.sensitiveMediaRevealConfirm,
|
text: i18n.ts.sensitiveMediaRevealConfirm,
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" @click="onclick">
|
<div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive]" @click="onclick">
|
||||||
<component
|
<component
|
||||||
:is="disableImageLink ? 'div' : 'a'"
|
:is="disableImageLink ? 'div' : 'a'"
|
||||||
v-bind="disableImageLink ? {
|
v-bind="disableImageLink ? {
|
||||||
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<ImgWithBlurhash
|
<ImgWithBlurhash
|
||||||
:hash="image.blurhash"
|
:hash="image.blurhash"
|
||||||
:src="(defaultStore.state.dataSaver.media && hide) ? null : url"
|
:src="(prefer.s.dataSaver.media && hide) ? null : url"
|
||||||
:forceBlurhash="hide"
|
:forceBlurhash="hide"
|
||||||
:cover="hide || cover"
|
:cover="hide || cover"
|
||||||
:alt="image.comment || image.name"
|
:alt="image.comment || image.name"
|
||||||
|
@ -32,8 +32,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template v-if="hide">
|
<template v-if="hide">
|
||||||
<div :class="$style.hiddenText">
|
<div :class="$style.hiddenText">
|
||||||
<div :class="$style.hiddenTextWrapper">
|
<div :class="$style.hiddenTextWrapper">
|
||||||
<b v-if="image.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b>
|
<b v-if="image.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b>
|
||||||
<b v-else style="display: block;"><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && image.size ? bytes(image.size) : i18n.ts.image }}</b>
|
<b v-else style="display: block;"><i class="ti ti-photo"></i> {{ prefer.s.dataSaver.media && image.size ? bytes(image.size) : i18n.ts.image }}</b>
|
||||||
<span v-if="controls" style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
<span v-if="controls" style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,10 +58,10 @@ import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
image: Misskey.entities.DriveFile;
|
image: Misskey.entities.DriveFile;
|
||||||
|
@ -77,9 +77,9 @@ const props = withDefaults(defineProps<{
|
||||||
|
|
||||||
const hide = ref(true);
|
const hide = ref(true);
|
||||||
|
|
||||||
const url = computed(() => (props.raw || defaultStore.state.loadRawImages)
|
const url = computed(() => (props.raw || prefer.s.loadRawImages)
|
||||||
? props.image.url
|
? props.image.url
|
||||||
: defaultStore.state.disableShowingAnimatedImages
|
: prefer.s.disableShowingAnimatedImages
|
||||||
? getStaticImageUrl(props.image.url)
|
? getStaticImageUrl(props.image.url)
|
||||||
: props.image.thumbnailUrl,
|
: props.image.thumbnailUrl,
|
||||||
);
|
);
|
||||||
|
@ -91,7 +91,7 @@ async function onclick(ev: MouseEvent) {
|
||||||
|
|
||||||
if (hide.value) {
|
if (hide.value) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (props.image.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
|
if (props.image.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.ts.sensitiveMediaRevealConfirm,
|
text: i18n.ts.sensitiveMediaRevealConfirm,
|
||||||
|
@ -105,7 +105,7 @@ async function onclick(ev: MouseEvent) {
|
||||||
|
|
||||||
// Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする
|
// Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする
|
||||||
watch(() => props.image, () => {
|
watch(() => props.image, () => {
|
||||||
hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.image.isSensitive && defaultStore.state.nsfw !== 'ignore');
|
hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.image.isSensitive && prefer.s.nsfw !== 'ignore');
|
||||||
}, {
|
}, {
|
||||||
deep: true,
|
deep: true,
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
@ -166,7 +166,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
menuItems.push({ type: 'divider' }, ...details);
|
menuItems.push({ type: 'divider' }, ...details);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menuItems.push({ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
|
|
|
@ -12,9 +12,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="[
|
:class="[
|
||||||
$style.medias,
|
$style.medias,
|
||||||
count === 1 ? [$style.n1, {
|
count === 1 ? [$style.n1, {
|
||||||
[$style.n116_9]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '16_9',
|
[$style.n116_9]: prefer.s.mediaListWithOneImageAppearance === '16_9',
|
||||||
[$style.n11_1]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '1_1',
|
[$style.n11_1]: prefer.s.mediaListWithOneImageAppearance === '1_1',
|
||||||
[$style.n12_3]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '2_3',
|
[$style.n12_3]: prefer.s.mediaListWithOneImageAppearance === '2_3',
|
||||||
}] : count === 2 ? $style.n2 : count === 3 ? $style.n3 : count === 4 ? $style.n4 : $style.nMany,
|
}] : count === 2 ? $style.n2 : count === 3 ? $style.n3 : count === 4 ? $style.n4 : $style.nMany,
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
|
@ -33,13 +33,13 @@ import * as Misskey from 'misskey-js';
|
||||||
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
import PhotoSwipeLightbox from 'photoswipe/lightbox';
|
||||||
import PhotoSwipe from 'photoswipe';
|
import PhotoSwipe from 'photoswipe';
|
||||||
import 'photoswipe/style.css';
|
import 'photoswipe/style.css';
|
||||||
|
import { FILE_TYPE_BROWSERSAFE } from '@@/js/const.js';
|
||||||
import XBanner from '@/components/MkMediaBanner.vue';
|
import XBanner from '@/components/MkMediaBanner.vue';
|
||||||
import XImage from '@/components/MkMediaImage.vue';
|
import XImage from '@/components/MkMediaImage.vue';
|
||||||
import XVideo from '@/components/MkMediaVideo.vue';
|
import XVideo from '@/components/MkMediaVideo.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { FILE_TYPE_BROWSERSAFE } from '@@/js/const.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { focusParent } from '@/scripts/focus.js';
|
import { focusParent } from '@/scripts/focus.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
mediaList: Misskey.entities.DriveFile[];
|
mediaList: Misskey.entities.DriveFile[];
|
||||||
|
@ -75,7 +75,7 @@ async function calcAspectRatio() {
|
||||||
return `${Math.max(ratio, img.properties.width / img.properties.height).toString()} / 1`;
|
return `${Math.max(ratio, img.properties.width / img.properties.height).toString()} / 1`;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (defaultStore.state.mediaListWithOneImageAppearance) {
|
switch (prefer.s.mediaListWithOneImageAppearance) {
|
||||||
case '16_9':
|
case '16_9':
|
||||||
gallery.value.style.aspectRatio = ratioMax(16 / 9);
|
gallery.value.style.aspectRatio = ratioMax(16 / 9);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="[
|
:class="[
|
||||||
$style.videoContainer,
|
$style.videoContainer,
|
||||||
controlsShowing && $style.active,
|
controlsShowing && $style.active,
|
||||||
(video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive,
|
(video.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive,
|
||||||
]"
|
]"
|
||||||
@mouseover="onMouseOver"
|
@mouseover="onMouseOver"
|
||||||
@mouseleave="onMouseLeave"
|
@mouseleave="onMouseLeave"
|
||||||
|
@ -20,13 +20,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
>
|
>
|
||||||
<button v-if="hide" :class="$style.hidden" @click="show">
|
<button v-if="hide" :class="$style.hidden" @click="show">
|
||||||
<div :class="$style.hiddenTextWrapper">
|
<div :class="$style.hiddenTextWrapper">
|
||||||
<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b>
|
<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b>
|
||||||
<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b>
|
<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ prefer.s.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b>
|
||||||
<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
<span style="display: block;">{{ i18n.ts.clickToShow }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.videoRoot">
|
<div v-else-if="prefer.s.useNativeUiForVideoAudioPlayer" :class="$style.videoRoot">
|
||||||
<video
|
<video
|
||||||
ref="videoEl"
|
ref="videoEl"
|
||||||
:class="$style.video"
|
:class="$style.video"
|
||||||
|
@ -116,13 +116,13 @@ import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import { hms } from '@/filters/hms.js';
|
import { hms } from '@/filters/hms.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { exitFullscreen, requestFullscreen } from '@/scripts/fullscreen.js';
|
import { exitFullscreen, requestFullscreen } from '@/scripts/fullscreen.js';
|
||||||
import hasAudio from '@/scripts/media-has-audio.js';
|
import hasAudio from '@/scripts/media-has-audio.js';
|
||||||
import MkMediaRange from '@/components/MkMediaRange.vue';
|
import MkMediaRange from '@/components/MkMediaRange.vue';
|
||||||
import { $i, iAmModerator } from '@/account.js';
|
import { $i, iAmModerator } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
video: Misskey.entities.DriveFile;
|
video: Misskey.entities.DriveFile;
|
||||||
|
@ -175,10 +175,10 @@ function hasFocus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'));
|
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.video.isSensitive && prefer.s.nsfw !== 'ignore'));
|
||||||
|
|
||||||
async function show() {
|
async function show() {
|
||||||
if (props.video.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) {
|
if (props.video.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.ts.sensitiveMediaRevealConfirm,
|
text: i18n.ts.sensitiveMediaRevealConfirm,
|
||||||
|
@ -265,7 +265,7 @@ function showMenu(ev: MouseEvent) {
|
||||||
menu.push({ type: 'divider' }, ...details);
|
menu.push({ type: 'divider' }, ...details);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menu.push({ type: 'divider' }, {
|
menu.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
|
@ -502,7 +502,7 @@ onDeactivated(() => {
|
||||||
elapsedTimeMs.value = 0;
|
elapsedTimeMs.value = 0;
|
||||||
durationMs.value = 0;
|
durationMs.value = 0;
|
||||||
bufferedEnd.value = 0;
|
bufferedEnd.value = 0;
|
||||||
hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore');
|
hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.video.isSensitive && prefer.s.nsfw !== 'ignore');
|
||||||
stopVideoElWatch();
|
stopVideoElWatch();
|
||||||
onceInit = false;
|
onceInit = false;
|
||||||
if (mediaTickFrameId) {
|
if (mediaTickFrameId) {
|
||||||
|
|
|
@ -19,8 +19,8 @@ import { computed } from 'vue';
|
||||||
import { host as localHost } from '@@/js/config.js';
|
import { host as localHost } from '@@/js/config.js';
|
||||||
import type { MkABehavior } from '@/components/global/MkA.vue';
|
import type { MkABehavior } from '@/components/global/MkA.vue';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
username: string;
|
username: string;
|
||||||
|
@ -36,7 +36,7 @@ const isMe = $i && (
|
||||||
`@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase()
|
`@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar
|
const avatarUrl = computed(() => prefer.s.disableShowingAnimatedImages || prefer.s.dataSaver.avatar
|
||||||
? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
||||||
: `/avatar/@${props.username}@${props.host}`,
|
: `/avatar/@${props.username}@${props.host}`,
|
||||||
);
|
);
|
||||||
|
|
|
@ -43,13 +43,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch, ref, shallowRef, computed } from 'vue';
|
import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch, ref, shallowRef, computed } from 'vue';
|
||||||
|
import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { isTouchUsing } from '@/scripts/touch.js';
|
import { isTouchUsing } from '@/scripts/touch.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import type { Keymap } from '@/scripts/hotkey.js';
|
|
||||||
import { focusTrap } from '@/scripts/focus-trap.js';
|
import { focusTrap } from '@/scripts/focus-trap.js';
|
||||||
import { focusParent } from '@/scripts/focus.js';
|
import { focusParent } from '@/scripts/focus.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
function getFixedContainer(el: Element | null): Element | null {
|
function getFixedContainer(el: Element | null): Element | null {
|
||||||
if (el == null || el.tagName === 'BODY') return null;
|
if (el == null || el.tagName === 'BODY') return null;
|
||||||
|
@ -106,7 +106,7 @@ const zIndex = os.claimZIndex(props.zPriority);
|
||||||
const useSendAnime = ref(false);
|
const useSendAnime = ref(false);
|
||||||
const type = computed<ModalTypes>(() => {
|
const type = computed<ModalTypes>(() => {
|
||||||
if (props.preferType === 'auto') {
|
if (props.preferType === 'auto') {
|
||||||
if ((defaultStore.state.menuStyle === 'drawer') || (defaultStore.state.menuStyle === 'auto' && isTouchUsing && deviceKind === 'smartphone')) {
|
if ((prefer.s.menuStyle === 'drawer') || (prefer.s.menuStyle === 'auto' && isTouchUsing && deviceKind === 'smartphone')) {
|
||||||
return 'drawer';
|
return 'drawer';
|
||||||
} else {
|
} else {
|
||||||
return props.src != null ? 'popup' : 'dialog';
|
return props.src != null ? 'popup' : 'dialog';
|
||||||
|
@ -117,7 +117,7 @@ const type = computed<ModalTypes>(() => {
|
||||||
});
|
});
|
||||||
const isEnableBgTransparent = computed(() => props.transparentBg && (type.value === 'popup'));
|
const isEnableBgTransparent = computed(() => props.transparentBg && (type.value === 'popup'));
|
||||||
const transitionName = computed((() =>
|
const transitionName = computed((() =>
|
||||||
defaultStore.state.animation
|
prefer.s.animation
|
||||||
? useSendAnime.value
|
? useSendAnime.value
|
||||||
? 'send'
|
? 'send'
|
||||||
: type.value === 'drawer'
|
: type.value === 'drawer'
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
:class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover, [$style.skipRender]: defaultStore.state.skipNoteRender }]"
|
:class="[$style.root, { [$style.showActionsOnlyHover]: prefer.s.showNoteActionsOnlyHover, [$style.skipRender]: prefer.s.skipNoteRender }]"
|
||||||
:tabindex="isDeleted ? '-1' : '0'"
|
:tabindex="isDeleted ? '-1' : '0'"
|
||||||
>
|
>
|
||||||
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
|
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||||
|
@ -130,9 +130,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
||||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || prefer.s.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.footerButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown.prevent="clip()">
|
<button v-if="prefer.s.showClipButtonInNoteFooter" ref="clipButton" :class="$style.footerButton" class="_button" @mousedown.prevent="clip()">
|
||||||
<i class="ti ti-paperclip"></i>
|
<i class="ti ti-paperclip"></i>
|
||||||
</button>
|
</button>
|
||||||
<button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown.prevent="showMenu()">
|
<button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown.prevent="showMenu()">
|
||||||
|
@ -178,13 +178,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, ref, shallowRef, watch, provide } from 'vue';
|
import { computed, inject, onMounted, ref, shallowRef, watch, provide } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { isLink } from '@@/js/is-link.js';
|
import { isLink } from '@@/js/is-link.js';
|
||||||
import { shouldCollapsed } from '@@/js/collapsed.js';
|
import { shouldCollapsed } from '@@/js/collapsed.js';
|
||||||
import { host } from '@@/js/config.js';
|
import { host } from '@@/js/config.js';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
|
||||||
|
import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||||
import MkNoteHeader from '@/components/MkNoteHeader.vue';
|
import MkNoteHeader from '@/components/MkNoteHeader.vue';
|
||||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||||
|
@ -197,7 +199,6 @@ import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
|
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
|
@ -205,7 +206,7 @@ import number from '@/filters/number.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore, noteViewInterruptors } from '@/store.js';
|
import { noteViewInterruptors } from '@/store.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
@ -219,9 +220,9 @@ import { getNoteSummary } from '@/scripts/get-note-summary.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
import { isEnabledUrlPreview } from '@/instance.js';
|
||||||
import type { Keymap } from '@/scripts/hotkey.js';
|
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
import { focusPrev, focusNext } from '@/scripts/focus.js';
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -284,13 +285,13 @@ const collapsed = ref(appearNote.value.cw == null && isLong);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
|
const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
|
||||||
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords, true));
|
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords, true));
|
||||||
const showSoftWordMutedWord = computed(() => defaultStore.state.showSoftWordMutedWord);
|
const showSoftWordMutedWord = computed(() => prefer.s.showSoftWordMutedWord);
|
||||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
|
||||||
const renoteCollapsed = ref(
|
const renoteCollapsed = ref(
|
||||||
defaultStore.state.collapseRenotes && isRenote && (
|
prefer.s.collapseRenotes && isRenote && (
|
||||||
($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) || // `||` must be `||`! See https://github.com/misskey-dev/misskey/issues/13131
|
($i && ($i.id === note.value.userId || $i.id === appearNote.value.userId)) || // `||` must be `||`! See https://github.com/misskey-dev/misskey/issues/13131
|
||||||
(appearNote.value.myReaction != null)
|
(appearNote.value.myReaction != null)
|
||||||
),
|
),
|
||||||
|
@ -345,7 +346,7 @@ const keymap = {
|
||||||
},
|
},
|
||||||
'c': () => {
|
'c': () => {
|
||||||
if (renoteCollapsed.value) return;
|
if (renoteCollapsed.value) return;
|
||||||
if (!defaultStore.state.showClipButtonInNoteFooter) return;
|
if (!prefer.s.showClipButtonInNoteFooter) return;
|
||||||
clip();
|
clip();
|
||||||
},
|
},
|
||||||
'o': () => {
|
'o': () => {
|
||||||
|
@ -479,7 +480,7 @@ function react(): void {
|
||||||
reaction: '❤️',
|
reaction: '❤️',
|
||||||
});
|
});
|
||||||
const el = reactButton.value;
|
const el = reactButton.value;
|
||||||
if (el && defaultStore.state.animation) {
|
if (el && prefer.s.animation) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
@ -490,7 +491,7 @@ function react(): void {
|
||||||
} else {
|
} else {
|
||||||
blur();
|
blur();
|
||||||
reactionPicker.show(reactButton.value ?? null, note.value, async (reaction) => {
|
reactionPicker.show(reactButton.value ?? null, note.value, async (reaction) => {
|
||||||
if (defaultStore.state.confirmOnReact) {
|
if (prefer.s.confirmOnReact) {
|
||||||
const confirm = await os.confirm({
|
const confirm = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.tsx.reactAreYouSure({ emoji: reaction.replace('@.', '') }),
|
text: i18n.tsx.reactAreYouSure({ emoji: reaction.replace('@.', '') }),
|
||||||
|
@ -549,7 +550,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
if (ev.target && isLink(ev.target as HTMLElement)) return;
|
if (ev.target && isLink(ev.target as HTMLElement)) return;
|
||||||
if (window.getSelection()?.toString() !== '') return;
|
if (window.getSelection()?.toString() !== '') return;
|
||||||
|
|
||||||
if (defaultStore.state.useReactionPickerForContextMenu) {
|
if (prefer.s.useReactionPickerForContextMenu) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -146,9 +146,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
<i v-else-if="appearNote.myReaction != null" class="ti ti-minus" style="color: var(--MI_THEME-accent);"></i>
|
||||||
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
<i v-else-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
<i v-else class="ti ti-plus"></i>
|
<i v-else class="ti ti-plus"></i>
|
||||||
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || prefer.s.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
|
<button v-if="prefer.s.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
|
||||||
<i class="ti ti-paperclip"></i>
|
<i class="ti ti-paperclip"></i>
|
||||||
</button>
|
</button>
|
||||||
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
|
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
|
||||||
|
@ -215,6 +215,9 @@ import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { isLink } from '@@/js/is-link.js';
|
import { isLink } from '@@/js/is-link.js';
|
||||||
import { host } from '@@/js/config.js';
|
import { host } from '@@/js/config.js';
|
||||||
|
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
|
||||||
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
|
import type { Keymap } from '@/scripts/hotkey.js';
|
||||||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||||
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
||||||
|
@ -226,7 +229,6 @@ import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
|
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
import { checkWordMute } from '@/scripts/check-word-mute.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
|
@ -234,7 +236,7 @@ import number from '@/filters/number.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { defaultStore, noteViewInterruptors } from '@/store.js';
|
import { noteViewInterruptors } from '@/store.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
@ -248,12 +250,11 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
|
||||||
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
import MkReactionIcon from '@/components/MkReactionIcon.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { isEnabledUrlPreview } from '@/instance.js';
|
import { isEnabledUrlPreview } from '@/instance.js';
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
import type { Keymap } from '@/scripts/hotkey.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
@ -303,7 +304,7 @@ const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
||||||
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
||||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||||
const conversation = ref<Misskey.entities.Note[]>([]);
|
const conversation = ref<Misskey.entities.Note[]>([]);
|
||||||
const replies = ref<Misskey.entities.Note[]>([]);
|
const replies = ref<Misskey.entities.Note[]>([]);
|
||||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || appearNote.value.userId === $i?.id);
|
||||||
|
@ -319,7 +320,7 @@ const keymap = {
|
||||||
'q': () => renote(),
|
'q': () => renote(),
|
||||||
'm': () => showMenu(),
|
'm': () => showMenu(),
|
||||||
'c': () => {
|
'c': () => {
|
||||||
if (!defaultStore.state.showClipButtonInNoteFooter) return;
|
if (!prefer.s.showClipButtonInNoteFooter) return;
|
||||||
clip();
|
clip();
|
||||||
},
|
},
|
||||||
'o': () => galleryEl.value?.openGallery(),
|
'o': () => galleryEl.value?.openGallery(),
|
||||||
|
@ -442,7 +443,7 @@ function react(): void {
|
||||||
reaction: '❤️',
|
reaction: '❤️',
|
||||||
});
|
});
|
||||||
const el = reactButton.value;
|
const el = reactButton.value;
|
||||||
if (el && defaultStore.state.animation) {
|
if (el && prefer.s.animation) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
@ -453,7 +454,7 @@ function react(): void {
|
||||||
} else {
|
} else {
|
||||||
blur();
|
blur();
|
||||||
reactionPicker.show(reactButton.value ?? null, note.value, async (reaction) => {
|
reactionPicker.show(reactButton.value ?? null, note.value, async (reaction) => {
|
||||||
if (defaultStore.state.confirmOnReact) {
|
if (prefer.s.confirmOnReact) {
|
||||||
const confirm = await os.confirm({
|
const confirm = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.tsx.reactAreYouSure({ emoji: reaction.replace('@.', '') }),
|
text: i18n.tsx.reactAreYouSure({ emoji: reaction.replace('@.', '') }),
|
||||||
|
@ -497,7 +498,7 @@ function onContextmenu(ev: MouseEvent): void {
|
||||||
if (ev.target && isLink(ev.target as HTMLElement)) return;
|
if (ev.target && isLink(ev.target as HTMLElement)) return;
|
||||||
if (window.getSelection()?.toString() !== '') return;
|
if (window.getSelection()?.toString() !== '') return;
|
||||||
|
|
||||||
if (defaultStore.state.useReactionPickerForContextMenu) {
|
if (prefer.s.useReactionPickerForContextMenu) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,7 +40,6 @@ import * as Misskey from 'misskey-js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
|
|
@ -7,9 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template v-for="file in note.files">
|
<template v-for="file in note.files">
|
||||||
<div
|
<div
|
||||||
v-if="(((
|
v-if="(((
|
||||||
(defaultStore.state.nsfw === 'force' || file.isSensitive) &&
|
(prefer.s.nsfw === 'force' || file.isSensitive) &&
|
||||||
defaultStore.state.nsfw !== 'ignore'
|
prefer.s.nsfw !== 'ignore'
|
||||||
) || (defaultStore.state.dataSaver.media && file.type.startsWith('image/'))) &&
|
) || (prefer.s.dataSaver.media && file.type.startsWith('image/'))) &&
|
||||||
!showingFiles.has(file.id)
|
!showingFiles.has(file.id)
|
||||||
)"
|
)"
|
||||||
:class="[$style.filePreview, { [$style.square]: square }]"
|
:class="[$style.filePreview, { [$style.square]: square }]"
|
||||||
|
@ -18,15 +18,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkDriveFileThumbnail
|
<MkDriveFileThumbnail
|
||||||
:file="file"
|
:file="file"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
|
:highlightWhenSensitive="prefer.s.highlightSensitiveMedia"
|
||||||
:forceBlurhash="true"
|
:forceBlurhash="true"
|
||||||
:large="true"
|
:large="true"
|
||||||
:class="$style.file"
|
:class="$style.file"
|
||||||
/>
|
/>
|
||||||
<div :class="$style.sensitive">
|
<div :class="$style.sensitive">
|
||||||
<div>
|
<div>
|
||||||
<div v-if="file.isSensitive"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media && file.size ? ` (${bytes(file.size)})` : '' }}</div>
|
<div v-if="file.isSensitive"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media && file.size ? ` (${bytes(file.size)})` : '' }}</div>
|
||||||
<div v-else><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && file.size ? bytes(file.size) : i18n.ts.image }}</div>
|
<div v-else><i class="ti ti-photo"></i> {{ prefer.s.dataSaver.media && file.size ? bytes(file.size) : i18n.ts.image }}</div>
|
||||||
<div>{{ i18n.ts.clickToShow }}</div>
|
<div>{{ i18n.ts.clickToShow }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkDriveFileThumbnail
|
<MkDriveFileThumbnail
|
||||||
:file="file"
|
:file="file"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
|
:highlightWhenSensitive="prefer.s.highlightSensitiveMedia"
|
||||||
:large="true"
|
:large="true"
|
||||||
:class="$style.file"
|
:class="$style.file"
|
||||||
/>
|
/>
|
||||||
|
@ -45,10 +45,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
|
|
||||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||||
|
|
|
@ -25,17 +25,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, onActivated } from 'vue';
|
import { onUnmounted, onDeactivated, onMounted, computed, shallowRef, onActivated } from 'vue';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
import type { notificationTypes } from '@@/js/const.js';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import XNotification from '@/components/MkNotification.vue';
|
import XNotification from '@/components/MkNotification.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import type { notificationTypes } from '@@/js/const.js';
|
|
||||||
import { infoImageUrl } from '@/instance.js';
|
import { infoImageUrl } from '@/instance.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
excludeTypes?: typeof notificationTypes[number][];
|
excludeTypes?: typeof notificationTypes[number][];
|
||||||
|
@ -43,7 +43,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
const pagination = computed(() => defaultStore.reactiveState.useGroupedNotifications.value ? {
|
const pagination = computed(() => prefer.r.useGroupedNotifications.value ? {
|
||||||
endpoint: 'i/notifications-grouped' as const,
|
endpoint: 'i/notifications-grouped' as const,
|
||||||
limit: 20,
|
limit: 20,
|
||||||
params: computed(() => ({
|
params: computed(() => ({
|
||||||
|
|
|
@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
|
@ -44,15 +44,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, shallowRef, watch } from 'vue';
|
import { computed, isRef, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, ref, shallowRef, watch } from 'vue';
|
||||||
import type { ComputedRef } from 'vue';
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { useDocumentVisibility } from '@@/js/use-document-visibility.js';
|
import { useDocumentVisibility } from '@@/js/use-document-visibility.js';
|
||||||
import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@@/js/scroll.js';
|
import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@@/js/scroll.js';
|
||||||
import * as os from '@/os.js';
|
import type { ComputedRef } from 'vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import type { MisskeyEntity } from '@/types/date-separated-list.js';
|
import type { MisskeyEntity } from '@/types/date-separated-list.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const SECOND_FETCH_LIMIT = 30;
|
const SECOND_FETCH_LIMIT = 30;
|
||||||
const TOLERANCE = 16;
|
const TOLERANCE = 16;
|
||||||
|
@ -140,7 +139,7 @@ const empty = computed(() => items.value.size === 0);
|
||||||
const error = ref(false);
|
const error = ref(false);
|
||||||
const {
|
const {
|
||||||
enableInfiniteScroll,
|
enableInfiniteScroll,
|
||||||
} = defaultStore.reactiveState;
|
} = prefer.r;
|
||||||
|
|
||||||
const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value);
|
const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value);
|
||||||
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body);
|
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body);
|
||||||
|
|
|
@ -123,7 +123,7 @@ import { Autocomplete } from '@/scripts/autocomplete.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { selectFiles } from '@/scripts/select-file.js';
|
import { selectFiles } from '@/scripts/select-file.js';
|
||||||
import { defaultStore, notePostInterruptors, postFormActions } from '@/store.js';
|
import { store, notePostInterruptors, postFormActions } from '@/store.js';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
@ -135,6 +135,7 @@ import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
import { emojiPicker } from '@/scripts/emoji-picker.js';
|
||||||
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
|
@ -174,19 +175,18 @@ const text = ref(props.initialText ?? '');
|
||||||
const files = ref(props.initialFiles ?? []);
|
const files = ref(props.initialFiles ?? []);
|
||||||
const poll = ref<PollEditorModelValue | null>(null);
|
const poll = ref<PollEditorModelValue | null>(null);
|
||||||
const useCw = ref<boolean>(!!props.initialCw);
|
const useCw = ref<boolean>(!!props.initialCw);
|
||||||
const showPreview = ref(defaultStore.state.showPreview);
|
const showPreview = ref(store.state.showPreview);
|
||||||
watch(showPreview, () => defaultStore.set('showPreview', showPreview.value));
|
watch(showPreview, () => store.set('showPreview', showPreview.value));
|
||||||
const showAddMfmFunction = ref(defaultStore.state.enableQuickAddMfmFunction);
|
const showAddMfmFunction = ref(prefer.s.enableQuickAddMfmFunction);
|
||||||
watch(showAddMfmFunction, () => defaultStore.set('enableQuickAddMfmFunction', showAddMfmFunction.value));
|
watch(showAddMfmFunction, () => prefer.set('enableQuickAddMfmFunction', showAddMfmFunction.value));
|
||||||
const cw = ref<string | null>(props.initialCw ?? null);
|
const cw = ref<string | null>(props.initialCw ?? null);
|
||||||
const localOnly = ref(props.initialLocalOnly ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly));
|
const localOnly = ref(props.initialLocalOnly ?? (prefer.s.rememberNoteVisibility ? store.state.localOnly : prefer.s.defaultNoteLocalOnly));
|
||||||
const visibility = ref(props.initialVisibility ?? (defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility));
|
const visibility = ref(props.initialVisibility ?? (prefer.s.rememberNoteVisibility ? store.state.visibility : prefer.s.defaultNoteVisibility));
|
||||||
const visibleUsers = ref<Misskey.entities.UserDetailed[]>([]);
|
const visibleUsers = ref<Misskey.entities.UserDetailed[]>([]);
|
||||||
if (props.initialVisibleUsers) {
|
if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
||||||
}
|
}
|
||||||
const reactionAcceptance = ref(defaultStore.state.reactionAcceptance);
|
const reactionAcceptance = ref(store.state.reactionAcceptance);
|
||||||
const autocomplete = ref(null);
|
|
||||||
const draghover = ref(false);
|
const draghover = ref(false);
|
||||||
const quoteId = ref<string | null>(null);
|
const quoteId = ref<string | null>(null);
|
||||||
const hasNotSpecifiedMentions = ref(false);
|
const hasNotSpecifiedMentions = ref(false);
|
||||||
|
@ -268,8 +268,8 @@ const canPost = computed((): boolean => {
|
||||||
(!poll.value || poll.value.choices.length >= 2);
|
(!poll.value || poll.value.choices.length >= 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
const withHashtags = computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
|
const withHashtags = computed(store.makeGetterSetter('postFormWithHashtags'));
|
||||||
const hashtags = computed(defaultStore.makeGetterSetter('postFormHashtags'));
|
const hashtags = computed(store.makeGetterSetter('postFormHashtags'));
|
||||||
|
|
||||||
watch(text, () => {
|
watch(text, () => {
|
||||||
checkMissingMention();
|
checkMissingMention();
|
||||||
|
@ -357,7 +357,7 @@ if (props.specified) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep cw when reply
|
// keep cw when reply
|
||||||
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
|
if (prefer.s.keepCw && props.reply && props.reply.cw) {
|
||||||
useCw.value = true;
|
useCw.value = true;
|
||||||
cw.value = props.reply.cw;
|
cw.value = props.reply.cw;
|
||||||
}
|
}
|
||||||
|
@ -456,7 +456,7 @@ function replaceFile(file: Misskey.entities.DriveFile, newFile: Misskey.entities
|
||||||
function upload(file: File, name?: string): void {
|
function upload(file: File, name?: string): void {
|
||||||
if (props.mock) return;
|
if (props.mock) return;
|
||||||
|
|
||||||
uploadFile(file, defaultStore.state.uploadFolder, name).then(res => {
|
uploadFile(file, prefer.s.uploadFolder, name).then(res => {
|
||||||
files.value.push(res);
|
files.value.push(res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -477,8 +477,8 @@ function setVisibility() {
|
||||||
}, {
|
}, {
|
||||||
changeVisibility: v => {
|
changeVisibility: v => {
|
||||||
visibility.value = v;
|
visibility.value = v;
|
||||||
if (defaultStore.state.rememberNoteVisibility) {
|
if (prefer.s.rememberNoteVisibility) {
|
||||||
defaultStore.set('visibility', visibility.value);
|
store.set('visibility', visibility.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
|
@ -525,8 +525,8 @@ async function toggleLocalOnly() {
|
||||||
}
|
}
|
||||||
|
|
||||||
localOnly.value = !localOnly.value;
|
localOnly.value = !localOnly.value;
|
||||||
if (defaultStore.state.rememberNoteVisibility) {
|
if (prefer.s.rememberNoteVisibility) {
|
||||||
defaultStore.set('localOnly', localOnly.value);
|
store.set('localOnly', localOnly.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,6 +594,8 @@ function onCompositionEnd(ev: CompositionEvent) {
|
||||||
justEndedComposition.value = true;
|
justEndedComposition.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pastedFileName = 'yyyy-MM-dd HH-mm-ss [{{number}}]';
|
||||||
|
|
||||||
async function onPaste(ev: ClipboardEvent) {
|
async function onPaste(ev: ClipboardEvent) {
|
||||||
if (props.mock) return;
|
if (props.mock) return;
|
||||||
if (!ev.clipboardData) return;
|
if (!ev.clipboardData) return;
|
||||||
|
@ -604,7 +606,7 @@ async function onPaste(ev: ClipboardEvent) {
|
||||||
if (!file) continue;
|
if (!file) continue;
|
||||||
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), defaultStore.state.pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
|
const formatted = `${formatTimeString(new Date(file.lastModified), pastedFileName).replace(/{{number}}/g, `${i + 1}`)}${ext}`;
|
||||||
upload(file, formatted);
|
upload(file, formatted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -638,7 +640,7 @@ async function onPaste(ev: ClipboardEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = formatTimeString(new Date(), defaultStore.state.pastedFileName).replace(/{{number}}/g, '0');
|
const fileName = formatTimeString(new Date(), pastedFileName).replace(/{{number}}/g, '0');
|
||||||
const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' });
|
const file = new File([paste], `${fileName}.txt`, { type: 'text/plain' });
|
||||||
upload(file, `${fileName}.txt`);
|
upload(file, `${fileName}.txt`);
|
||||||
});
|
});
|
||||||
|
@ -751,7 +753,7 @@ async function post(ev?: MouseEvent) {
|
||||||
if (ev) {
|
if (ev) {
|
||||||
const el = (ev.currentTarget ?? ev.target) as HTMLElement | null;
|
const el = (ev.currentTarget ?? ev.target) as HTMLElement | null;
|
||||||
|
|
||||||
if (el && defaultStore.state.animation) {
|
if (el && prefer.s.animation) {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = rect.left + (el.offsetWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.offsetHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
|
|
@ -36,12 +36,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { defineAsyncComponent, inject } from 'vue';
|
import { defineAsyncComponent, inject } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { MenuItem } from '@/types/menu';
|
import type { MenuItem } from '@/types/menu';
|
||||||
import { defaultStore } from '@/store';
|
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard';
|
||||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | Keyboar
|
||||||
action: () => { detachAndDeleteMedia(file); },
|
action: () => { detachAndDeleteMedia(file); },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (prefer.s.devMode) {
|
||||||
menuItems.push({ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
|
|
94
packages/frontend/src/components/MkPreferenceContainer.vue
Normal file
94
packages/frontend/src/components/MkPreferenceContainer.vue
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="$style.root">
|
||||||
|
<div :class="$style.body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.menu">
|
||||||
|
<i v-if="isAccountOverrided" class="ti ti-user-cog" style="color: var(--MI_THEME-accent); opacity: 0.7;"></i>
|
||||||
|
<div :class="$style.buttons">
|
||||||
|
<button class="_button" style="color: var(--MI_THEME-fg)" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import type { PREF_DEF } from '@/preferences/def.js';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
import { profileManager } from '@/preferences.js';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
k: keyof typeof PREF_DEF;
|
||||||
|
}>(), {
|
||||||
|
});
|
||||||
|
|
||||||
|
const isAccountOverrided = ref(profileManager.isAccountOverrided(props.k));
|
||||||
|
|
||||||
|
function showMenu(ev: MouseEvent) {
|
||||||
|
const i = window.setInterval(() => {
|
||||||
|
isAccountOverrided.value = profileManager.isAccountOverrided(props.k);
|
||||||
|
}, 100);
|
||||||
|
os.popupMenu(profileManager.getPerPrefMenu(props.k), ev.currentTarget ?? ev.target, {
|
||||||
|
onClosing: () => {
|
||||||
|
window.clearInterval(i);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -8px;
|
||||||
|
left: -8px;
|
||||||
|
width: calc(100% + 16px);
|
||||||
|
height: calc(100% + 16px);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: light-dark(rgba(0, 0, 0, 0.02), rgba(255, 255, 255, 0.02));
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
.buttons {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-left: 8px;
|
||||||
|
border-left: solid 1px var(--MI_THEME-divider);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.buttons {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,11 +8,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
ref="buttonEl"
|
ref="buttonEl"
|
||||||
v-ripple="canToggle"
|
v-ripple="canToggle"
|
||||||
class="_button"
|
class="_button"
|
||||||
:class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.small]: defaultStore.state.reactionsDisplaySize === 'small', [$style.large]: defaultStore.state.reactionsDisplaySize === 'large' }]"
|
:class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.small]: prefer.s.reactionsDisplaySize === 'small', [$style.large]: prefer.s.reactionsDisplaySize === 'large' }]"
|
||||||
@click="toggleReaction()"
|
@click="toggleReaction()"
|
||||||
@contextmenu.prevent.stop="menu"
|
@contextmenu.prevent.stop="menu"
|
||||||
>
|
>
|
||||||
<MkReactionIcon :class="defaultStore.state.limitWidthOfReaction ? $style.limitWidth : ''" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
|
<MkReactionIcon :class="prefer.s.limitWidthOfReaction ? $style.limitWidth : ''" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
|
||||||
<span :class="$style.count">{{ count }}</span>
|
<span :class="$style.count">{{ count }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -30,11 +30,11 @@ import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import MkReactionEffect from '@/components/MkReactionEffect.vue';
|
import MkReactionEffect from '@/components/MkReactionEffect.vue';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
|
||||||
import { customEmojisMap } from '@/custom-emojis.js';
|
import { customEmojisMap } from '@/custom-emojis.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
reaction: string;
|
reaction: string;
|
||||||
|
@ -90,7 +90,7 @@ async function toggleReaction() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (defaultStore.state.confirmOnReact) {
|
if (prefer.s.confirmOnReact) {
|
||||||
const confirm = await os.confirm({
|
const confirm = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
text: i18n.tsx.reactAreYouSure({ emoji: props.reaction.replace('@.', '') }),
|
text: i18n.tsx.reactAreYouSure({ emoji: props.reaction.replace('@.', '') }),
|
||||||
|
@ -135,7 +135,7 @@ async function menu(ev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function anime() {
|
function anime() {
|
||||||
if (document.hidden || !defaultStore.state.animation || buttonEl.value == null) return;
|
if (document.hidden || !prefer.s.animation || buttonEl.value == null) return;
|
||||||
|
|
||||||
const rect = buttonEl.value.getBoundingClientRect();
|
const rect = buttonEl.value.getBoundingClientRect();
|
||||||
const x = rect.left + 16;
|
const x = rect.left + 16;
|
||||||
|
|
|
@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TransitionGroup
|
<TransitionGroup
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_x_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_x_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_x_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_x_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_x_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_x_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_x_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_x_leaveTo : ''"
|
||||||
:moveClass="defaultStore.state.animation ? $style.transition_x_move : ''"
|
:moveClass="prefer.s.animation ? $style.transition_x_move : ''"
|
||||||
tag="div" :class="$style.root"
|
tag="div" :class="$style.root"
|
||||||
>
|
>
|
||||||
<XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :isInitial="initialReactions.has(reaction)" :note="note" @reactionToggled="onMockToggleReaction"/>
|
<XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :isInitial="initialReactions.has(reaction)" :note="note" @reactionToggled="onMockToggleReaction"/>
|
||||||
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { inject, watch, ref } from 'vue';
|
import { inject, watch, ref } from 'vue';
|
||||||
import XReaction from '@/components/MkReactionsViewer.reaction.vue';
|
import XReaction from '@/components/MkReactionsViewer.reaction.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { onMounted, nextTick, shallowRef, ref } from 'vue';
|
import { onMounted, nextTick, shallowRef, ref } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
import { initChart } from '@/scripts/init-chart.js';
|
import { initChart } from '@/scripts/init-chart.js';
|
||||||
|
@ -75,7 +75,7 @@ async function renderChart() {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300';
|
const color = store.state.darkMode ? '#b4e900' : '#86b300';
|
||||||
|
|
||||||
const getYYYYMMDD = (date: Date) => {
|
const getYYYYMMDD = (date: Date) => {
|
||||||
const y = date.getFullYear().toString().padStart(2, '0');
|
const y = date.getFullYear().toString().padStart(2, '0');
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, shallowRef } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
|
@ -42,7 +42,7 @@ const getDate = (ymd: string) => {
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let raw = await misskeyApi('retention', { });
|
let raw = await misskeyApi('retention', { });
|
||||||
|
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
||||||
const color = accent.toHex();
|
const color = accent.toHex();
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-if="paginationQuery"
|
v-if="paginationQuery"
|
||||||
ref="tlComponent"
|
ref="tlComponent"
|
||||||
:pagination="paginationQuery"
|
:pagination="paginationQuery"
|
||||||
:noGap="!defaultStore.state.showGapBetweenNotesInTimeline"
|
:noGap="!prefer.s.showGapBetweenNotesInTimeline"
|
||||||
@queue="emit('queue', $event)"
|
@queue="emit('queue', $event)"
|
||||||
@status="prComponent?.setDisabled($event)"
|
@status="prComponent?.setDisabled($event)"
|
||||||
/>
|
/>
|
||||||
|
@ -20,14 +20,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed, watch, onUnmounted, provide, ref, shallowRef } from 'vue';
|
import { computed, watch, onUnmounted, provide, ref, shallowRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { BasicTimelineType } from '@/timelines.js';
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
|
import type { Paging } from '@/components/MkPagination.vue';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
import MkPullToRefresh from '@/components/MkPullToRefresh.vue';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import type { Paging } from '@/components/MkPagination.vue';
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role';
|
||||||
|
@ -239,7 +239,7 @@ function updatePaginationQuery() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshEndpointAndChannel() {
|
function refreshEndpointAndChannel() {
|
||||||
if (!defaultStore.state.disableStreamingTimeline) {
|
if (!prefer.s.disableStreamingTimeline) {
|
||||||
disconnectChannel();
|
disconnectChannel();
|
||||||
connectChannel();
|
connectChannel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_toast_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_toast_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toast_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_toast_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_toast_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_toast_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_toast_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_toast_leaveTo : ''"
|
||||||
appear @afterLeave="emit('closed')"
|
appear @afterLeave="emit('closed')"
|
||||||
>
|
>
|
||||||
<div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }">
|
<div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }">
|
||||||
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
message: string;
|
message: string;
|
||||||
|
|
|
@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_tooltip_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_tooltip_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_tooltip_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_tooltip_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_tooltip_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_tooltip_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_tooltip_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_tooltip_leaveTo : ''"
|
||||||
appear @afterLeave="emit('closed')"
|
appear @afterLeave="emit('closed')"
|
||||||
>
|
>
|
||||||
<div v-show="showing" ref="el" :class="$style.root" class="_acrylic _shadow" :style="{ zIndex, maxWidth: maxWidth + 'px' }">
|
<div v-show="showing" ref="el" :class="$style.root" class="_acrylic _shadow" :style="{ zIndex, maxWidth: maxWidth + 'px' }">
|
||||||
|
@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { nextTick, onMounted, onUnmounted, shallowRef } from 'vue';
|
import { nextTick, onMounted, onUnmounted, shallowRef } from 'vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { calcPopupPosition } from '@/scripts/popup-position.js';
|
import { calcPopupPosition } from '@/scripts/popup-position.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
showing: boolean;
|
showing: boolean;
|
||||||
|
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
sandbox="allow-popups allow-popups-to-escape-sandbox allow-scripts allow-same-origin"
|
sandbox="allow-popups allow-popups-to-escape-sandbox allow-scripts allow-same-origin"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
:style="{ position: 'relative', width: '100%', height: `${tweetHeight}px`, border: 0 }"
|
:style="{ position: 'relative', width: '100%', height: `${tweetHeight}px`, border: 0 }"
|
||||||
:src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&hideCard=false&hideThread=false&lang=en&theme=${defaultStore.state.darkMode ? 'dark' : 'light'}&id=${tweetId}`"
|
:src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&hideCard=false&hideThread=false&lang=en&theme=${store.state.darkMode ? 'dark' : 'light'}&id=${tweetId}`"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.action">
|
<div :class="$style.action">
|
||||||
|
@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<component :is="self ? 'MkA' : 'a'" :class="[$style.link, { [$style.compact]: compact }]" :[attr]="self ? url.substring(local.length) : url" rel="nofollow noopener" :target="target" :title="url">
|
<component :is="self ? 'MkA' : 'a'" :class="[$style.link, { [$style.compact]: compact }]" :[attr]="self ? url.substring(local.length) : url" rel="nofollow noopener" :target="target" :title="url">
|
||||||
<div v-if="thumbnail && !sensitive" :class="$style.thumbnail" :style="defaultStore.state.dataSaver.urlPreview ? '' : `background-image: url('${thumbnail}')`">
|
<div v-if="thumbnail && !sensitive" :class="$style.thumbnail" :style="prefer.s.dataSaver.urlPreview ? '' : `background-image: url('${thumbnail}')`">
|
||||||
</div>
|
</div>
|
||||||
<article :class="$style.body">
|
<article :class="$style.body">
|
||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
|
@ -92,7 +92,8 @@ import * as os from '@/os.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
|
import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
|
type SummalyResult = Awaited<ReturnType<typeof summaly>>;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.root" :style="{ zIndex, top: top + 'px', left: left + 'px' }">
|
<div :class="$style.root" :style="{ zIndex, top: top + 'px', left: left + 'px' }">
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" @afterLeave="emit('closed')">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" @afterLeave="emit('closed')">
|
||||||
<MkUrlPreview v-if="showing" class="_popup _shadow" :url="url" :showActions="false"/>
|
<MkUrlPreview v-if="showing" class="_popup _shadow" :url="url" :showActions="false"/>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
showing: boolean;
|
showing: boolean;
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_panel" :class="$style.root">
|
<div class="_panel" :class="$style.root">
|
||||||
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''"></div>
|
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${prefer.s.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''"></div>
|
||||||
<MkAvatar :class="$style.avatar" :user="user" indicator/>
|
<MkAvatar :class="$style.avatar" :user="user" indicator/>
|
||||||
<div :class="$style.title">
|
<div :class="$style.title">
|
||||||
<MkA :class="$style.name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
<MkA :class="$style.name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
||||||
|
@ -42,7 +42,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
user: Misskey.entities.UserDetailed;
|
user: Misskey.entities.UserDetailed;
|
||||||
|
|
|
@ -5,15 +5,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_popup_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_popup_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_popup_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_popup_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_popup_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_popup_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_popup_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_popup_leaveTo : ''"
|
||||||
appear @afterLeave="emit('closed')"
|
appear @afterLeave="emit('closed')"
|
||||||
>
|
>
|
||||||
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
|
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
|
||||||
<div v-if="user != null">
|
<div v-if="user != null">
|
||||||
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
|
<div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${prefer.s.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
|
||||||
<span v-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
|
<span v-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
|
||||||
</div>
|
</div>
|
||||||
<svg viewBox="0 0 128 128" :class="$style.avatarBack">
|
<svg viewBox="0 0 128 128" :class="$style.avatarBack">
|
||||||
|
@ -64,7 +64,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
|
|
|
@ -68,7 +68,7 @@ import MkInput from '@/components/MkInput.vue';
|
||||||
import FormSplit from '@/components/form/split.vue';
|
import FormSplit from '@/components/form/split.vue';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
@ -128,10 +128,10 @@ async function ok() {
|
||||||
dialogEl.value?.close();
|
dialogEl.value?.close();
|
||||||
|
|
||||||
// 最近使ったユーザー更新
|
// 最近使ったユーザー更新
|
||||||
let recents = defaultStore.state.recentlyUsedUsers;
|
let recents = store.state.recentlyUsedUsers;
|
||||||
recents = recents.filter(x => x !== selected.value?.id);
|
recents = recents.filter(x => x !== selected.value?.id);
|
||||||
recents.unshift(selected.value.id);
|
recents.unshift(selected.value.id);
|
||||||
defaultStore.set('recentlyUsedUsers', recents.splice(0, 16));
|
store.set('recentlyUsedUsers', recents.splice(0, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
|
@ -141,7 +141,7 @@ function cancel() {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
misskeyApi('users/show', {
|
misskeyApi('users/show', {
|
||||||
userIds: defaultStore.state.recentlyUsedUsers,
|
userIds: store.state.recentlyUsedUsers,
|
||||||
}).then(foundUsers => {
|
}).then(foundUsers => {
|
||||||
let _users = foundUsers;
|
let _users = foundUsers;
|
||||||
_users = _users.filter((u) => {
|
_users = _users.filter((u) => {
|
||||||
|
|
|
@ -139,7 +139,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { host } from '@@/js/config.js';
|
import { host } from '@@/js/config.js';
|
||||||
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
import MkPushNotificationAllowButton from '@/components/MkPushNotificationAllowButton.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -149,10 +149,10 @@ const emit = defineEmits<{
|
||||||
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const page = ref(defaultStore.state.accountSetupWizard);
|
const page = ref(store.state.accountSetupWizard);
|
||||||
|
|
||||||
watch(page, () => {
|
watch(page, () => {
|
||||||
defaultStore.set('accountSetupWizard', page.value);
|
store.set('accountSetupWizard', page.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function close(skip: boolean) {
|
async function close(skip: boolean) {
|
||||||
|
@ -165,11 +165,11 @@ async function close(skip: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.value?.close();
|
dialog.value?.close();
|
||||||
defaultStore.set('accountSetupWizard', -1);
|
store.set('accountSetupWizard', -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupComplete() {
|
function setupComplete() {
|
||||||
defaultStore.set('accountSetupWizard', -1);
|
store.set('accountSetupWizard', -1);
|
||||||
dialog.value?.close();
|
dialog.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ async function later(later: boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.value?.close();
|
dialog.value?.close();
|
||||||
defaultStore.set('accountSetupWizard', 0);
|
store.set('accountSetupWizard', 0);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { Chart } from 'chart.js';
|
||||||
import gradient from 'chartjs-plugin-gradient';
|
import gradient from 'chartjs-plugin-gradient';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { initChart } from '@/scripts/init-chart.js';
|
import { initChart } from '@/scripts/init-chart.js';
|
||||||
|
@ -59,7 +59,7 @@ async function renderChart() {
|
||||||
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(document.documentElement);
|
||||||
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
||||||
|
|
|
@ -5,10 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.transition_window_enterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.transition_window_enterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.transition_window_leaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.transition_window_leaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.transition_window_enterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.transition_window_enterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.transition_window_leaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.transition_window_leaveTo : ''"
|
||||||
appear
|
appear
|
||||||
@afterLeave="emit('closed')"
|
@afterLeave="emit('closed')"
|
||||||
>
|
>
|
||||||
|
@ -58,7 +58,7 @@ import type { MenuItem } from '@/types/menu.js';
|
||||||
import contains from '@/scripts/contains.js';
|
import contains from '@/scripts/contains.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
type WindowButton = {
|
type WindowButton = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="poamfof">
|
<div class="poamfof">
|
||||||
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
|
||||||
<div v-if="player.url && (player.url.startsWith('http://') || player.url.startsWith('https://'))" class="player">
|
<div v-if="player.url && (player.url.startsWith('http://') || player.url.startsWith('https://'))" class="player">
|
||||||
<iframe v-if="!fetching" :src="transformPlayerUrl(player.url)" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
<iframe v-if="!fetching" :src="transformPlayerUrl(player.url)" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,10 +25,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import MkWindow from '@/components/MkWindow.vue';
|
|
||||||
import { versatileLang } from '@@/js/intl-const.js';
|
import { versatileLang } from '@@/js/intl-const.js';
|
||||||
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
|
import { transformPlayerUrl } from '@/scripts/player-url-transform.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
url: string;
|
url: string;
|
||||||
|
|
|
@ -45,9 +45,10 @@ import { url as local, host } from '@@/js/config.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
type Ad = (typeof instance)['ads'][number];
|
type Ad = (typeof instance)['ads'][number];
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ const choseAd = (): Ad | null => {
|
||||||
return props.specify;
|
return props.specify;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allAds = instance.ads.map(ad => defaultStore.state.mutedAds.includes(ad.id) ? {
|
const allAds = instance.ads.map(ad => store.state.mutedAds.includes(ad.id) ? {
|
||||||
...ad,
|
...ad,
|
||||||
ratio: 0,
|
ratio: 0,
|
||||||
} : ad);
|
} : ad);
|
||||||
|
@ -107,12 +108,12 @@ const chosen = ref(choseAd());
|
||||||
|
|
||||||
const self = computed(() => chosen.value?.url.startsWith(local));
|
const self = computed(() => chosen.value?.url.startsWith(local));
|
||||||
|
|
||||||
const shouldHide = ref(!defaultStore.state.forceShowAds && $i && $i.policies.canHideAds && (props.specify == null));
|
const shouldHide = ref(!prefer.s.forceShowAds && $i && $i.policies.canHideAds && (props.specify == null));
|
||||||
|
|
||||||
function reduceFrequency(): void {
|
function reduceFrequency(): void {
|
||||||
if (chosen.value == null) return;
|
if (chosen.value == null) return;
|
||||||
if (defaultStore.state.mutedAds.includes(chosen.value.id)) return;
|
if (store.state.mutedAds.includes(chosen.value.id)) return;
|
||||||
defaultStore.push('mutedAds', chosen.value.id);
|
store.push('mutedAds', chosen.value.id);
|
||||||
os.success();
|
os.success();
|
||||||
chosen.value = choseAd();
|
chosen.value = choseAd();
|
||||||
showMenu.value = false;
|
showMenu.value = false;
|
||||||
|
|
|
@ -48,11 +48,10 @@ import MkA from './MkA.vue';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
import { acct, userPage } from '@/filters/user.js';
|
import { acct, userPage } from '@/filters/user.js';
|
||||||
import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue';
|
import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const animation = ref(defaultStore.state.animation);
|
const animation = ref(prefer.s.animation);
|
||||||
const squareAvatars = ref(defaultStore.state.squareAvatars);
|
const squareAvatars = ref(prefer.s.squareAvatars);
|
||||||
const useBlurEffect = ref(defaultStore.state.useBlurEffect);
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
user: Misskey.entities.User;
|
user: Misskey.entities.User;
|
||||||
|
@ -75,7 +74,7 @@ const emit = defineEmits<{
|
||||||
(ev: 'click', v: MouseEvent): void;
|
(ev: 'click', v: MouseEvent): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const showDecoration = props.forceShowDecoration || defaultStore.state.showAvatarDecorations;
|
const showDecoration = props.forceShowDecoration || prefer.s.showAvatarDecorations;
|
||||||
|
|
||||||
const bound = computed(() => props.link
|
const bound = computed(() => props.link
|
||||||
? { to: userPage(props.user), target: props.target }
|
? { to: userPage(props.user), target: props.target }
|
||||||
|
@ -83,7 +82,7 @@ const bound = computed(() => props.link
|
||||||
|
|
||||||
const url = computed(() => {
|
const url = computed(() => {
|
||||||
if (props.user.avatarUrl == null) return null;
|
if (props.user.avatarUrl == null) return null;
|
||||||
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return getStaticImageUrl(props.user.avatarUrl);
|
if (prefer.s.disableShowingAnimatedImages || prefer.s.dataSaver.avatar) return getStaticImageUrl(props.user.avatarUrl);
|
||||||
return props.user.avatarUrl;
|
return props.user.avatarUrl;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ function onClick(ev: MouseEvent): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDecorationUrl(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
function getDecorationUrl(decoration: Omit<Misskey.entities.UserDetailed['avatarDecorations'][number], 'id'>) {
|
||||||
if (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) return getStaticImageUrl(decoration.url);
|
if (prefer.s.disableShowingAnimatedImages || prefer.s.dataSaver.avatar) return getStaticImageUrl(decoration.url);
|
||||||
return decoration.url;
|
return decoration.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed, defineAsyncComponent, inject, ref } from 'vue';
|
import { computed, defineAsyncComponent, inject, ref } from 'vue';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import { customEmojisMap } from '@/custom-emojis.js';
|
import { customEmojisMap } from '@/custom-emojis.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||||
|
@ -37,6 +36,7 @@ import * as sound from '@/scripts/sound.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -77,7 +77,7 @@ const url = computed(() => {
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
return defaultStore.reactiveState.disableShowingAnimatedImages.value
|
return prefer.s.disableShowingAnimatedImages
|
||||||
? getStaticImageUrl(proxied)
|
? getStaticImageUrl(proxied)
|
||||||
: proxied;
|
: proxied;
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,12 +12,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed, inject } from 'vue';
|
import { computed, inject } from 'vue';
|
||||||
import { colorizeEmoji, getEmojiName } from '@@/js/emojilist.js';
|
import { colorizeEmoji, getEmojiName } from '@@/js/emojilist.js';
|
||||||
import { char2fluentEmojiFilePath, char2twemojiFilePath } from '@@/js/emoji-base.js';
|
import { char2fluentEmojiFilePath, char2twemojiFilePath } from '@@/js/emoji-base.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
emoji: string;
|
emoji: string;
|
||||||
|
@ -27,9 +27,9 @@ const props = defineProps<{
|
||||||
|
|
||||||
const react = inject<((name: string) => void) | null>('react', null);
|
const react = inject<((name: string) => void) | null>('react', null);
|
||||||
|
|
||||||
const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
|
const char2path = prefer.s.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
|
||||||
|
|
||||||
const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native');
|
const useOsNativeEmojis = computed(() => prefer.s.emojiStyle === 'native');
|
||||||
const url = computed(() => char2path(props.emoji));
|
const url = computed(() => char2path(props.emoji));
|
||||||
const colorizedNativeEmoji = computed(() => colorizeEmoji(props.emoji));
|
const colorizedNativeEmoji = computed(() => colorizeEmoji(props.emoji));
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
||||||
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
import { serverErrorImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
|
@ -4,11 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.spacer, defaultStore.reactiveState.darkMode.value ? $style.dark : $style.light]"></div>
|
<div :class="[$style.spacer, store.reactiveState.darkMode.value ? $style.dark : $style.light]"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { h, provide } from 'vue';
|
import { h } from 'vue';
|
||||||
import type { VNode, SetupContext } from 'vue';
|
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { host } from '@@/js/config.js';
|
import { host } from '@@/js/config.js';
|
||||||
|
import type { VNode, SetupContext } from 'vue';
|
||||||
|
import type { MkABehavior } from '@/components/global/MkA.vue';
|
||||||
import MkUrl from '@/components/global/MkUrl.vue';
|
import MkUrl from '@/components/global/MkUrl.vue';
|
||||||
import MkTime from '@/components/global/MkTime.vue';
|
import MkTime from '@/components/global/MkTime.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
@ -19,8 +20,7 @@ import MkCodeInline from '@/components/MkCodeInline.vue';
|
||||||
import MkGoogle from '@/components/MkGoogle.vue';
|
import MkGoogle from '@/components/MkGoogle.vue';
|
||||||
import MkSparkle from '@/components/MkSparkle.vue';
|
import MkSparkle from '@/components/MkSparkle.vue';
|
||||||
import MkA from '@/components/global/MkA.vue';
|
import MkA from '@/components/global/MkA.vue';
|
||||||
import type { MkABehavior } from '@/components/global/MkA.vue';
|
import { prefer } from '@/preferences.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
|
|
||||||
function safeParseFloat(str: unknown): number | null {
|
function safeParseFloat(str: unknown): number | null {
|
||||||
if (typeof str !== 'string' || str === '') return null;
|
if (typeof str !== 'string' || str === '') return null;
|
||||||
|
@ -81,7 +81,7 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
|
||||||
return c.match(/^[0-9a-f]{3,6}$/i) ? c : null;
|
return c.match(/^[0-9a-f]{3,6}$/i) ? c : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm;
|
const useAnim = prefer.s.advancedMfm && prefer.s.animatedMfm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gen Vue Elements from MFM AST
|
* Gen Vue Elements from MFM AST
|
||||||
|
@ -188,17 +188,17 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
|
||||||
}
|
}
|
||||||
case 'x2': {
|
case 'x2': {
|
||||||
return h('span', {
|
return h('span', {
|
||||||
class: defaultStore.state.advancedMfm ? 'mfm-x2' : '',
|
class: prefer.s.advancedMfm ? 'mfm-x2' : '',
|
||||||
}, genEl(token.children, scale * 2));
|
}, genEl(token.children, scale * 2));
|
||||||
}
|
}
|
||||||
case 'x3': {
|
case 'x3': {
|
||||||
return h('span', {
|
return h('span', {
|
||||||
class: defaultStore.state.advancedMfm ? 'mfm-x3' : '',
|
class: prefer.s.advancedMfm ? 'mfm-x3' : '',
|
||||||
}, genEl(token.children, scale * 3));
|
}, genEl(token.children, scale * 3));
|
||||||
}
|
}
|
||||||
case 'x4': {
|
case 'x4': {
|
||||||
return h('span', {
|
return h('span', {
|
||||||
class: defaultStore.state.advancedMfm ? 'mfm-x4' : '',
|
class: prefer.s.advancedMfm ? 'mfm-x4' : '',
|
||||||
}, genEl(token.children, scale * 4));
|
}, genEl(token.children, scale * 4));
|
||||||
}
|
}
|
||||||
case 'font': {
|
case 'font': {
|
||||||
|
@ -241,14 +241,14 @@ export default function (props: MfmProps, { emit }: { emit: SetupContext<MfmEven
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'position': {
|
case 'position': {
|
||||||
if (!defaultStore.state.advancedMfm) break;
|
if (!prefer.s.advancedMfm) break;
|
||||||
const x = safeParseFloat(token.props.args.x) ?? 0;
|
const x = safeParseFloat(token.props.args.x) ?? 0;
|
||||||
const y = safeParseFloat(token.props.args.y) ?? 0;
|
const y = safeParseFloat(token.props.args.y) ?? 0;
|
||||||
style = `transform: translateX(${x}em) translateY(${y}em);`;
|
style = `transform: translateX(${x}em) translateY(${y}em);`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'scale': {
|
case 'scale': {
|
||||||
if (!defaultStore.state.advancedMfm) {
|
if (!prefer.s.advancedMfm) {
|
||||||
style = '';
|
style = '';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.tabsInner">
|
<div :class="$style.tabsInner">
|
||||||
<button
|
<button
|
||||||
v-for="t in tabs" :ref="(el) => tabRefs[t.key] = (el as HTMLElement)" v-tooltip.noDelay="t.title"
|
v-for="t in tabs" :ref="(el) => tabRefs[t.key] = (el as HTMLElement)" v-tooltip.noDelay="t.title"
|
||||||
class="_button" :class="[$style.tab, { [$style.active]: t.key != null && t.key === props.tab, [$style.animate]: defaultStore.reactiveState.animation.value }]"
|
class="_button" :class="[$style.tab, { [$style.active]: t.key != null && t.key === props.tab, [$style.animate]: prefer.s.animation }]"
|
||||||
@mousedown="(ev) => onTabMousedown(t, ev)" @click="(ev) => onTabClick(t, ev)"
|
@mousedown="(ev) => onTabMousedown(t, ev)" @click="(ev) => onTabClick(t, ev)"
|
||||||
>
|
>
|
||||||
<div :class="$style.tabInner">
|
<div :class="$style.tabInner">
|
||||||
<i v-if="t.icon" :class="[$style.tabIcon, t.icon]"></i>
|
<i v-if="t.icon" :class="[$style.tabIcon, t.icon]"></i>
|
||||||
<div
|
<div
|
||||||
v-if="!t.iconOnly || (!defaultStore.reactiveState.animation.value && t.key === tab)"
|
v-if="!t.iconOnly || (!prefer.s.animation && t.key === tab)"
|
||||||
:class="$style.tabTitle"
|
:class="$style.tabTitle"
|
||||||
>
|
>
|
||||||
{{ t.title }}
|
{{ t.title }}
|
||||||
|
@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref="tabHighlightEl"
|
ref="tabHighlightEl"
|
||||||
:class="[$style.tabHighlight, { [$style.animate]: defaultStore.reactiveState.animation.value }]"
|
:class="[$style.tabHighlight, { [$style.animate]: prefer.s.animation }]"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -41,20 +41,20 @@ export type Tab = {
|
||||||
onClick?: (ev: MouseEvent) => void;
|
onClick?: (ev: MouseEvent) => void;
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
iconOnly?: false;
|
iconOnly?: false;
|
||||||
title: string;
|
title: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
iconOnly: true;
|
iconOnly: true;
|
||||||
icon: string;
|
icon: string;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue';
|
import { nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
tabs?: Tab[];
|
tabs?: Tab[];
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<KeepAlive
|
<KeepAlive
|
||||||
:max="defaultStore.state.numberOfPageCache"
|
:max="prefer.s.numberOfPageCache"
|
||||||
:exclude="pageCacheController"
|
:exclude="pageCacheController"
|
||||||
>
|
>
|
||||||
<Suspense :timeout="0">
|
<Suspense :timeout="0">
|
||||||
|
@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, onBeforeUnmount, provide, ref, shallowRef, computed, nextTick } from 'vue';
|
import { inject, onBeforeUnmount, provide, ref, shallowRef, computed, nextTick } from 'vue';
|
||||||
import type { IRouter, Resolved, RouteDef } from '@/nirax.js';
|
import type { IRouter, Resolved, RouteDef } from '@/nirax.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { globalEvents } from '@/events.js';
|
import { globalEvents } from '@/events.js';
|
||||||
import MkLoadingPage from '@/pages/_loading_.vue';
|
import MkLoadingPage from '@/pages/_loading_.vue';
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ const rootEl = useTemplateRef('root');
|
||||||
const rootElMutationObserver = new MutationObserver(() => {
|
const rootElMutationObserver = new MutationObserver(() => {
|
||||||
checkChildren();
|
checkChildren();
|
||||||
});
|
});
|
||||||
const injectedSearchMarkerId = inject<Ref<string | null>>('inAppSearchMarkerId');
|
const injectedSearchMarkerId = inject<Ref<string | null> | null>('inAppSearchMarkerId', null);
|
||||||
const searchMarkerId = computed(() => injectedSearchMarkerId?.value ?? window.location.hash.slice(1));
|
const searchMarkerId = computed(() => injectedSearchMarkerId?.value ?? window.location.hash.slice(1));
|
||||||
const highlighted = ref(props.markerId === searchMarkerId.value);
|
const highlighted = ref(props.markerId === searchMarkerId.value);
|
||||||
|
|
||||||
|
|
306
packages/frontend/src/deck.ts
Normal file
306
packages/frontend/src/deck.ts
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { throttle } from 'throttle-debounce';
|
||||||
|
import { notificationTypes } from 'misskey-js';
|
||||||
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
|
import type { SoundStore } from '@/preferences/def.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
|
type ColumnWidget = {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
data: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const columnTypes = [
|
||||||
|
'main',
|
||||||
|
'widgets',
|
||||||
|
'notifications',
|
||||||
|
'tl',
|
||||||
|
'antenna',
|
||||||
|
'list',
|
||||||
|
'channel',
|
||||||
|
'mentions',
|
||||||
|
'direct',
|
||||||
|
'roleTimeline',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type ColumnType = typeof columnTypes[number];
|
||||||
|
|
||||||
|
export type Column = {
|
||||||
|
id: string;
|
||||||
|
type: ColumnType;
|
||||||
|
name: string | null;
|
||||||
|
width: number;
|
||||||
|
widgets?: ColumnWidget[];
|
||||||
|
active?: boolean;
|
||||||
|
flexible?: boolean;
|
||||||
|
antennaId?: string;
|
||||||
|
listId?: string;
|
||||||
|
channelId?: string;
|
||||||
|
roleId?: string;
|
||||||
|
excludeTypes?: typeof notificationTypes[number][];
|
||||||
|
tl?: BasicTimelineType;
|
||||||
|
withRenotes?: boolean;
|
||||||
|
withReplies?: boolean;
|
||||||
|
withSensitive?: boolean;
|
||||||
|
onlyFiles?: boolean;
|
||||||
|
soundSetting?: SoundStore;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadDeck = async () => {
|
||||||
|
let deck;
|
||||||
|
|
||||||
|
try {
|
||||||
|
deck = await misskeyApi('i/registry/get', {
|
||||||
|
scope: ['client', 'deck', 'profiles'],
|
||||||
|
key: store.state['deck.profile'],
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'object' && err != null && 'code' in err && err.code === 'NO_SUCH_KEY') {
|
||||||
|
// 後方互換性のため
|
||||||
|
if (store.state['deck.profile'] === 'default') {
|
||||||
|
saveDeck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set('deck.columns', []);
|
||||||
|
store.set('deck.layout', []);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set('deck.columns', deck.columns);
|
||||||
|
store.set('deck.layout', deck.layout);
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function forceSaveDeck() {
|
||||||
|
await misskeyApi('i/registry/set', {
|
||||||
|
scope: ['client', 'deck', 'profiles'],
|
||||||
|
key: store.state['deck.profile'],
|
||||||
|
value: {
|
||||||
|
columns: store.reactiveState['deck.columns'].value,
|
||||||
|
layout: store.reactiveState['deck.layout'].value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: deckがloadされていない状態でsaveすると意図せず上書きが発生するので対策する
|
||||||
|
export const saveDeck = throttle(1000, () => {
|
||||||
|
forceSaveDeck();
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function getProfiles(): Promise<string[]> {
|
||||||
|
return await misskeyApi('i/registry/keys', {
|
||||||
|
scope: ['client', 'deck', 'profiles'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteProfile(key: string): Promise<void> {
|
||||||
|
return await misskeyApi('i/registry/remove', {
|
||||||
|
scope: ['client', 'deck', 'profiles'],
|
||||||
|
key: key,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addColumn(column: Column) {
|
||||||
|
if (column.name === undefined) column.name = null;
|
||||||
|
store.push('deck.columns', column);
|
||||||
|
store.push('deck.layout', [column.id]);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeColumn(id: Column['id']) {
|
||||||
|
store.set('deck.columns', store.state['deck.columns'].filter(c => c.id !== id));
|
||||||
|
store.set('deck.layout', store.state['deck.layout']
|
||||||
|
.map(ids => ids.filter(_id => _id !== id))
|
||||||
|
.filter(ids => ids.length > 0));
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swapColumn(a: Column['id'], b: Column['id']) {
|
||||||
|
const aX = store.state['deck.layout'].findIndex(ids => ids.indexOf(a) !== -1);
|
||||||
|
const aY = store.state['deck.layout'][aX].findIndex(id => id === a);
|
||||||
|
const bX = store.state['deck.layout'].findIndex(ids => ids.indexOf(b) !== -1);
|
||||||
|
const bY = store.state['deck.layout'][bX].findIndex(id => id === b);
|
||||||
|
const layout = deepClone(store.state['deck.layout']);
|
||||||
|
layout[aX][aY] = b;
|
||||||
|
layout[bX][bY] = a;
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swapLeftColumn(id: Column['id']) {
|
||||||
|
const layout = deepClone(store.state['deck.layout']);
|
||||||
|
store.state['deck.layout'].some((ids, i) => {
|
||||||
|
if (ids.includes(id)) {
|
||||||
|
const left = store.state['deck.layout'][i - 1];
|
||||||
|
if (left) {
|
||||||
|
layout[i - 1] = store.state['deck.layout'][i];
|
||||||
|
layout[i] = left;
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swapRightColumn(id: Column['id']) {
|
||||||
|
const layout = deepClone(store.state['deck.layout']);
|
||||||
|
store.state['deck.layout'].some((ids, i) => {
|
||||||
|
if (ids.includes(id)) {
|
||||||
|
const right = store.state['deck.layout'][i + 1];
|
||||||
|
if (right) {
|
||||||
|
layout[i + 1] = store.state['deck.layout'][i];
|
||||||
|
layout[i] = right;
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swapUpColumn(id: Column['id']) {
|
||||||
|
const layout = deepClone(store.state['deck.layout']);
|
||||||
|
const idsIndex = store.state['deck.layout'].findIndex(ids => ids.includes(id));
|
||||||
|
const ids = deepClone(store.state['deck.layout'][idsIndex]);
|
||||||
|
ids.some((x, i) => {
|
||||||
|
if (x === id) {
|
||||||
|
const up = ids[i - 1];
|
||||||
|
if (up) {
|
||||||
|
ids[i - 1] = id;
|
||||||
|
ids[i] = up;
|
||||||
|
|
||||||
|
layout[idsIndex] = ids;
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function swapDownColumn(id: Column['id']) {
|
||||||
|
const layout = deepClone(store.state['deck.layout']);
|
||||||
|
const idsIndex = store.state['deck.layout'].findIndex(ids => ids.includes(id));
|
||||||
|
const ids = deepClone(store.state['deck.layout'][idsIndex]);
|
||||||
|
ids.some((x, i) => {
|
||||||
|
if (x === id) {
|
||||||
|
const down = ids[i + 1];
|
||||||
|
if (down) {
|
||||||
|
ids[i + 1] = id;
|
||||||
|
ids[i] = down;
|
||||||
|
|
||||||
|
layout[idsIndex] = ids;
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stackLeftColumn(id: Column['id']) {
|
||||||
|
let layout = deepClone(store.state['deck.layout']);
|
||||||
|
const i = store.state['deck.layout'].findIndex(ids => ids.includes(id));
|
||||||
|
layout = layout.map(ids => ids.filter(_id => _id !== id));
|
||||||
|
layout[i - 1].push(id);
|
||||||
|
layout = layout.filter(ids => ids.length > 0);
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function popRightColumn(id: Column['id']) {
|
||||||
|
let layout = deepClone(store.state['deck.layout']);
|
||||||
|
const i = store.state['deck.layout'].findIndex(ids => ids.includes(id));
|
||||||
|
const affected = layout[i];
|
||||||
|
layout = layout.map(ids => ids.filter(_id => _id !== id));
|
||||||
|
layout.splice(i + 1, 0, [id]);
|
||||||
|
layout = layout.filter(ids => ids.length > 0);
|
||||||
|
store.set('deck.layout', layout);
|
||||||
|
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
for (const column of columns) {
|
||||||
|
if (affected.includes(column.id)) {
|
||||||
|
column.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addColumnWidget(id: Column['id'], widget: ColumnWidget) {
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
const columnIndex = store.state['deck.columns'].findIndex(c => c.id === id);
|
||||||
|
const column = deepClone(store.state['deck.columns'][columnIndex]);
|
||||||
|
if (column == null) return;
|
||||||
|
if (column.widgets == null) column.widgets = [];
|
||||||
|
column.widgets.unshift(widget);
|
||||||
|
columns[columnIndex] = column;
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeColumnWidget(id: Column['id'], widget: ColumnWidget) {
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
const columnIndex = store.state['deck.columns'].findIndex(c => c.id === id);
|
||||||
|
const column = deepClone(store.state['deck.columns'][columnIndex]);
|
||||||
|
if (column == null) return;
|
||||||
|
if (column.widgets == null) column.widgets = [];
|
||||||
|
column.widgets = column.widgets.filter(w => w.id !== widget.id);
|
||||||
|
columns[columnIndex] = column;
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setColumnWidgets(id: Column['id'], widgets: ColumnWidget[]) {
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
const columnIndex = store.state['deck.columns'].findIndex(c => c.id === id);
|
||||||
|
const column = deepClone(store.state['deck.columns'][columnIndex]);
|
||||||
|
if (column == null) return;
|
||||||
|
column.widgets = widgets;
|
||||||
|
columns[columnIndex] = column;
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateColumnWidget(id: Column['id'], widgetId: string, widgetData: any) {
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
const columnIndex = store.state['deck.columns'].findIndex(c => c.id === id);
|
||||||
|
const column = deepClone(store.state['deck.columns'][columnIndex]);
|
||||||
|
if (column == null) return;
|
||||||
|
if (column.widgets == null) column.widgets = [];
|
||||||
|
column.widgets = column.widgets.map(w => w.id === widgetId ? {
|
||||||
|
...w,
|
||||||
|
data: widgetData,
|
||||||
|
} : w);
|
||||||
|
columns[columnIndex] = column;
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
saveDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateColumn(id: Column['id'], column: Partial<Column>) {
|
||||||
|
const columns = deepClone(store.state['deck.columns']);
|
||||||
|
const columnIndex = store.state['deck.columns'].findIndex(c => c.id === id);
|
||||||
|
const currentColumn = deepClone(store.state['deck.columns'][columnIndex]);
|
||||||
|
if (currentColumn == null) return;
|
||||||
|
for (const [k, v] of Object.entries(column)) {
|
||||||
|
currentColumn[k] = v;
|
||||||
|
}
|
||||||
|
columns[columnIndex] = currentColumn;
|
||||||
|
store.set('deck.columns', columns);
|
||||||
|
saveDeck();
|
||||||
|
}
|
|
@ -4,11 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Directive } from 'vue';
|
import type { Directive } from 'vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mounted(el: HTMLElement, binding, vn) {
|
mounted(el: HTMLElement, binding, vn) {
|
||||||
if (!defaultStore.state.animation) return;
|
if (!prefer.s.animation) return;
|
||||||
|
|
||||||
const target = el.children[0];
|
const target = el.children[0];
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { popup } from '@/os.js';
|
import { popup } from '@/os.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mounted(el, binding, vn) {
|
mounted(el, binding, vn) {
|
||||||
// 明示的に false であればバインドしない
|
// 明示的に false であればバインドしない
|
||||||
if (binding.value === false) return;
|
if (binding.value === false) return;
|
||||||
if (!defaultStore.state.animation) return;
|
if (!prefer.s.animation) return;
|
||||||
|
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
|
|
|
@ -19,7 +19,6 @@ export type Keys = (
|
||||||
'drafts' |
|
'drafts' |
|
||||||
'hashtags' |
|
'hashtags' |
|
||||||
'wallpaper' |
|
'wallpaper' |
|
||||||
'theme' |
|
|
||||||
'colorScheme' |
|
'colorScheme' |
|
||||||
'useSystemFont' |
|
'useSystemFont' |
|
||||||
'fontSize' |
|
'fontSize' |
|
||||||
|
@ -28,13 +27,17 @@ export type Keys = (
|
||||||
'locale' |
|
'locale' |
|
||||||
'localeVersion' |
|
'localeVersion' |
|
||||||
'theme' |
|
'theme' |
|
||||||
|
'themeId' |
|
||||||
'customCss' |
|
'customCss' |
|
||||||
'message_drafts' |
|
'message_drafts' |
|
||||||
'scratchpad' |
|
'scratchpad' |
|
||||||
'debug' |
|
'debug' |
|
||||||
|
'preferences' |
|
||||||
|
'latestPreferencesUpdate' |
|
||||||
|
'hidePreferencesRestoreSuggestion' |
|
||||||
`miux:${string}` |
|
`miux:${string}` |
|
||||||
`ui:folder:${string}` |
|
`ui:folder:${string}` |
|
||||||
`themes:${string}` |
|
`themes:${string}` | // DEPRECATED
|
||||||
`aiscript:${string}` |
|
`aiscript:${string}` |
|
||||||
'lastEmojisFetchedAt' | // DEPRECATED, stored in indexeddb (13.9.0~)
|
'lastEmojisFetchedAt' | // DEPRECATED, stored in indexeddb (13.9.0~)
|
||||||
'emojis' | // DEPRECATED, stored in indexeddb (13.9.0~);
|
'emojis' | // DEPRECATED, stored in indexeddb (13.9.0~);
|
||||||
|
|
|
@ -6,15 +6,15 @@
|
||||||
// TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
|
// TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
|
||||||
|
|
||||||
import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue';
|
import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue';
|
||||||
import type { Component, Ref } from 'vue';
|
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import type { Component, Ref } from 'vue';
|
||||||
import type { ComponentProps as CP } from 'vue-component-type-helpers';
|
import type { ComponentProps as CP } from 'vue-component-type-helpers';
|
||||||
import type { Form, GetFormResultType } from '@/scripts/form.js';
|
import type { Form, GetFormResultType } from '@/scripts/form.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import type { PostFormProps } from '@/types/post-form.js';
|
import type { PostFormProps } from '@/types/post-form.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkPostFormDialog from '@/components/MkPostFormDialog.vue';
|
import MkPostFormDialog from '@/components/MkPostFormDialog.vue';
|
||||||
import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
|
import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
|
||||||
|
@ -626,7 +626,7 @@ export async function selectRole(params: {
|
||||||
}): Promise<
|
}): Promise<
|
||||||
{ canceled: true; result: undefined; } |
|
{ canceled: true; result: undefined; } |
|
||||||
{ canceled: false; result: Misskey.entities.Role[] }
|
{ canceled: false; result: Misskey.entities.Role[] }
|
||||||
> {
|
> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
||||||
done: roles => {
|
done: roles => {
|
||||||
|
@ -699,8 +699,8 @@ export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | n
|
||||||
|
|
||||||
export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
|
export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
|
||||||
if (
|
if (
|
||||||
defaultStore.state.contextMenu === 'native' ||
|
prefer.s.contextMenu === 'native' ||
|
||||||
(defaultStore.state.contextMenu === 'appWithShift' && !ev.shiftKey)
|
(prefer.s.contextMenu === 'appWithShift' && !ev.shiftKey)
|
||||||
) {
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkLoading v-if="!loaded"/>
|
<MkLoading v-if="!loaded"/>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div v-show="loaded" :class="$style.root">
|
<div v-show="loaded" :class="$style.root">
|
||||||
<img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/>
|
<img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
|
@ -27,15 +27,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { version } from '@@/js/config.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkLink from '@/components/MkLink.vue';
|
import MkLink from '@/components/MkLink.vue';
|
||||||
import { version } from '@@/js/config.js';
|
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { unisonReload } from '@/scripts/unison-reload.js';
|
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { serverErrorImageUrl } from '@/instance.js';
|
import { serverErrorImageUrl } from '@/instance.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -143,7 +143,7 @@ import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { physics } from '@/scripts/physics.js';
|
import { physics } from '@/scripts/physics.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
|
||||||
|
@ -406,7 +406,7 @@ const easterEggEngine = ref<{ stop: () => void } | null>(null);
|
||||||
const containerEl = shallowRef<HTMLElement>();
|
const containerEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
function iconLoaded() {
|
function iconLoaded() {
|
||||||
const emojis = defaultStore.state.reactions;
|
const emojis = store.state.reactions;
|
||||||
const containerWidth = containerEl.value.offsetWidth;
|
const containerWidth = containerEl.value.offsetWidth;
|
||||||
for (let i = 0; i < 32; i++) {
|
for (let i = 0; i < 32; i++) {
|
||||||
easterEggEmojis.value.push({
|
easterEggEmojis.value.push({
|
||||||
|
|
|
@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton link to="/admin/abuse-report-notification-recipient" primary>{{ i18n.ts.notificationSetting }}</MkButton>
|
<MkButton link to="/admin/abuse-report-notification-recipient" primary>{{ i18n.ts.notificationSetting }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkInfo v-if="!defaultStore.reactiveState.abusesTutorial.value" closable @close="closeTutorial()">
|
<MkInfo v-if="!store.reactiveState.abusesTutorial.value" closable @close="closeTutorial()">
|
||||||
{{ i18n.ts._abuseUserReport.resolveTutorial }}
|
{{ i18n.ts._abuseUserReport.resolveTutorial }}
|
||||||
</MkInfo>
|
</MkInfo>
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
|
||||||
const reports = shallowRef<InstanceType<typeof MkPagination>>();
|
const reports = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ function resolved(reportId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeTutorial() {
|
function closeTutorial() {
|
||||||
defaultStore.set('abusesTutorial', false);
|
store.set('abusesTutorial', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerActions = computed(() => []);
|
const headerActions = computed(() => []);
|
||||||
|
|
|
@ -78,6 +78,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { onMounted, ref, useCssModule } from 'vue';
|
import { onMounted, ref, useCssModule } from 'vue';
|
||||||
|
import type { RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
|
||||||
|
import type { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
||||||
|
import type { DroppedFile } from '@/scripts/file-drop.js';
|
||||||
|
import type { GridSetting } from '@/components/grid/grid.js';
|
||||||
|
import type { GridRow } from '@/components/grid/row.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import {
|
import {
|
||||||
emptyStrToEmptyArray,
|
emptyStrToEmptyArray,
|
||||||
|
@ -88,7 +93,6 @@ import MkGrid from '@/components/grid/MkGrid.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -99,11 +103,7 @@ import { extractDroppedItems, flattenDroppedFiles } from '@/scripts/file-drop.js
|
||||||
import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
|
import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
|
||||||
import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js';
|
import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js';
|
||||||
|
|
||||||
import type { RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import type { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
|
||||||
import type { DroppedFile } from '@/scripts/file-drop.js';
|
|
||||||
import type { GridSetting } from '@/components/grid/grid.js';
|
|
||||||
import type { GridRow } from '@/components/grid/row.js';
|
|
||||||
|
|
||||||
const MAXIMUM_EMOJI_REGISTER_COUNT = 100;
|
const MAXIMUM_EMOJI_REGISTER_COUNT = 100;
|
||||||
|
|
||||||
|
@ -244,8 +244,8 @@ function setupGrid(): GridSetting {
|
||||||
|
|
||||||
const uploadFolders = ref<FolderItem[]>([]);
|
const uploadFolders = ref<FolderItem[]>([]);
|
||||||
const gridItems = ref<GridItem[]>([]);
|
const gridItems = ref<GridItem[]>([]);
|
||||||
const selectedFolderId = ref(defaultStore.state.uploadFolder);
|
const selectedFolderId = ref(prefer.s.uploadFolder);
|
||||||
const keepOriginalUploading = ref(defaultStore.state.keepOriginalUploading);
|
const keepOriginalUploading = ref(prefer.s.keepOriginalUploading);
|
||||||
const directoryToCategory = ref<boolean>(false);
|
const directoryToCategory = ref<boolean>(false);
|
||||||
const registerButtonDisabled = ref<boolean>(false);
|
const registerButtonDisabled = ref<boolean>(false);
|
||||||
const requestLogs = ref<RequestLogItem[]>([]);
|
const requestLogs = ref<RequestLogItem[]>([]);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { onMounted, shallowRef, ref } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import gradient from 'chartjs-plugin-gradient';
|
import gradient from 'chartjs-plugin-gradient';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { initChart } from '@/scripts/init-chart.js';
|
import { initChart } from '@/scripts/init-chart.js';
|
||||||
|
@ -54,7 +54,7 @@ async function renderChart() {
|
||||||
|
|
||||||
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
const raw = await misskeyApi('charts/active-users', { limit: chartLimit, span: 'day' });
|
||||||
|
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const colorRead = '#3498db';
|
const colorRead = '#3498db';
|
||||||
const colorWrite = '#2ecc71';
|
const colorWrite = '#2ecc71';
|
||||||
|
|
|
@ -27,7 +27,7 @@ import isChromatic from 'chromatic';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
import { initChart } from '@/scripts/init-chart.js';
|
import { initChart } from '@/scripts/init-chart.js';
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
const raw = await misskeyApi('charts/ap-request', { limit: chartLimit, span: 'day' });
|
const raw = await misskeyApi('charts/ap-request', { limit: chartLimit, span: 'day' });
|
||||||
|
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
const succColor = '#87e000';
|
const succColor = '#87e000';
|
||||||
const failColor = '#ff4400';
|
const failColor = '#ff4400';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else :class="$style.instances">
|
<div v-else :class="$style.instances">
|
||||||
<MkA v-for="(instance, i) in instances" :key="instance.id" v-tooltip.mfm.noDelay="`${instance.name}\n${instance.host}\n${instance.softwareName} ${instance.softwareVersion}`" :to="`/instance-info/${instance.host}`" :class="$style.instance">
|
<MkA v-for="(instance, i) in instances" :key="instance.id" v-tooltip.mfm.noDelay="`${instance.name}\n${instance.host}\n${instance.softwareName} ${instance.softwareVersion}`" :to="`/instance-info/${instance.host}`" :class="$style.instance">
|
||||||
|
@ -18,11 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
|
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const instances = ref<Misskey.entities.FederationInstance[]>([]);
|
const instances = ref<Misskey.entities.FederationInstance[]>([]);
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else :class="$style.root" class="_panel">
|
<div v-else :class="$style.root" class="_panel">
|
||||||
<MkA v-for="user in moderators" :key="user.id" class="user" :to="`/admin/user/${user.id}`">
|
<MkA v-for="user in moderators" :key="user.id" class="user" :to="`/admin/user/${user.id}`">
|
||||||
|
@ -18,9 +18,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const moderators = ref<Misskey.entities.UserDetailed[] | null>(null);
|
const moderators = ref<Misskey.entities.UserDetailed[] | null>(null);
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, shallowRef } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
|
@ -67,7 +67,7 @@ const color =
|
||||||
'?' as never;
|
'?' as never;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl.value, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else :class="$style.root">
|
<div v-else :class="$style.root">
|
||||||
<div class="item _panel users">
|
<div class="item _panel users">
|
||||||
|
@ -68,7 +68,7 @@ import MkNumberDiff from '@/components/MkNumberDiff.vue';
|
||||||
import MkNumber from '@/components/MkNumber.vue';
|
import MkNumber from '@/components/MkNumber.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { customEmojis } from '@/custom-emojis.js';
|
import { customEmojis } from '@/custom-emojis.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||||
const usersComparedToThePrevDay = ref<number>();
|
const usersComparedToThePrevDay = ref<number>();
|
||||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else class="users">
|
<div v-else class="users">
|
||||||
<MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/admin/user/${user.id}`" class="user">
|
<MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/admin/user/${user.id}`" class="user">
|
||||||
|
@ -18,11 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const newUsers = ref<Misskey.entities.UserDetailed[] | null>(null);
|
const newUsers = ref<Misskey.entities.UserDetailed[] | null>(null);
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, shallowRef } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
|
||||||
import { chartVLine } from '@/scripts/chart-vline.js';
|
import { chartVLine } from '@/scripts/chart-vline.js';
|
||||||
import { alpha } from '@/scripts/color.js';
|
import { alpha } from '@/scripts/color.js';
|
||||||
|
@ -67,7 +67,7 @@ const color =
|
||||||
'?' as never;
|
'?' as never;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl.value, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
|
|
|
@ -8,10 +8,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="800">
|
<MkSpacer :contentMax="800">
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.fadeEnterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.fadeEnterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.fadeLeaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.fadeEnterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.fadeLeaveTo : ''"
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
<div v-if="announcement" :key="announcement.id" class="_panel" :class="$style.announcement">
|
<div v-if="announcement" :key="announcement.id" class="_panel" :class="$style.announcement">
|
||||||
|
@ -56,7 +56,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { $i, updateAccountPartial } from '@/account.js';
|
import { $i, updateAccountPartial } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
announcementId: string;
|
announcementId: string;
|
||||||
|
|
|
@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkInfo v-if="channel.isArchived" warn>{{ i18n.ts.thisChannelArchived }}</MkInfo>
|
<MkInfo v-if="channel.isArchived" warn>{{ i18n.ts.thisChannelArchived }}</MkInfo>
|
||||||
|
|
||||||
<!-- スマホ・タブレットの場合、キーボードが表示されると投稿が見づらくなるので、デスクトップ場合のみ自動でフォーカスを当てる -->
|
<!-- スマホ・タブレットの場合、キーボードが表示されると投稿が見づらくなるので、デスクトップ場合のみ自動でフォーカスを当てる -->
|
||||||
<MkPostForm v-if="$i && defaultStore.reactiveState.showFixedPostFormInChannel.value" :channel="channel" class="post-form _panel" fixed :autofocus="deviceKind === 'desktop'"/>
|
<MkPostForm v-if="$i && prefer.r.showFixedPostFormInChannel.value" :channel="channel" class="post-form _panel" fixed :autofocus="deviceKind === 'desktop'"/>
|
||||||
|
|
||||||
<MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/>
|
<MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -75,6 +75,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref } from 'vue';
|
import { computed, watch, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { url } from '@@/js/config.js';
|
||||||
|
import type { PageHeaderItem } from '@/types/page-header.js';
|
||||||
import MkPostForm from '@/components/MkPostForm.vue';
|
import MkPostForm from '@/components/MkPostForm.vue';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import XChannelFollowButton from '@/components/MkChannelFollowButton.vue';
|
import XChannelFollowButton from '@/components/MkChannelFollowButton.vue';
|
||||||
|
@ -85,16 +87,14 @@ import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
import { url } from '@@/js/config.js';
|
|
||||||
import { favoritedChannelsCache } from '@/cache.js';
|
import { favoritedChannelsCache } from '@/cache.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import type { PageHeaderItem } from '@/types/page-header.js';
|
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { notesSearchAvailable } from '@/scripts/check-permissions.js';
|
import { notesSearchAvailable } from '@/scripts/check-permissions.js';
|
||||||
|
|
|
@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref="containerEl" :class="[$style.gameContainer, { [$style.gameOver]: isGameOver && !replaying }]" @contextmenu.stop.prevent @click.stop.prevent="onClick" @touchmove.stop.prevent="onTouchmove" @touchend="onTouchend" @mousemove="onMousemove">
|
<div ref="containerEl" :class="[$style.gameContainer, { [$style.gameOver]: isGameOver && !replaying }]" @contextmenu.stop.prevent @click.stop.prevent="onClick" @touchmove.stop.prevent="onTouchmove" @touchend="onTouchend" @mousemove="onMousemove">
|
||||||
<img v-if="defaultStore.state.darkMode" src="/client-assets/drop-and-fusion/frame-dark.svg" :class="$style.mainFrameImg"/>
|
<img v-if="store.state.darkMode" src="/client-assets/drop-and-fusion/frame-dark.svg" :class="$style.mainFrameImg"/>
|
||||||
<img v-else src="/client-assets/drop-and-fusion/frame-light.svg" :class="$style.mainFrameImg"/>
|
<img v-else src="/client-assets/drop-and-fusion/frame-light.svg" :class="$style.mainFrameImg"/>
|
||||||
<canvas ref="canvasEl" :class="$style.canvas"/>
|
<canvas ref="canvasEl" :class="$style.canvas"/>
|
||||||
<Transition
|
<Transition
|
||||||
|
@ -195,6 +195,8 @@ import { computed, onDeactivated, onMounted, onUnmounted, ref, shallowRef, watch
|
||||||
import * as Matter from 'matter-js';
|
import * as Matter from 'matter-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { DropAndFusionGame } from 'misskey-bubble-game';
|
import { DropAndFusionGame } from 'misskey-bubble-game';
|
||||||
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
|
import { apiUrl } from '@@/js/config.js';
|
||||||
import type { Mono } from 'misskey-bubble-game';
|
import type { Mono } from 'misskey-bubble-game';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
|
@ -203,15 +205,14 @@ import MkNumber from '@/components/MkNumber.vue';
|
||||||
import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue';
|
import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
|
||||||
import { apiUrl } from '@@/js/config.js';
|
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import MkRange from '@/components/MkRange.vue';
|
import MkRange from '@/components/MkRange.vue';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
type FrontendMonoDefinition = {
|
type FrontendMonoDefinition = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -586,8 +587,8 @@ const showConfig = ref(false);
|
||||||
const replaying = ref(false);
|
const replaying = ref(false);
|
||||||
const replayPlaybackRate = ref(1);
|
const replayPlaybackRate = ref(1);
|
||||||
const currentFrame = ref(0);
|
const currentFrame = ref(0);
|
||||||
const bgmVolume = ref(defaultStore.state.dropAndFusion.bgmVolume);
|
const bgmVolume = ref(prefer.s['game.dropAndFusion'].bgmVolume);
|
||||||
const sfxVolume = ref(defaultStore.state.dropAndFusion.sfxVolume);
|
const sfxVolume = ref(prefer.s['game.dropAndFusion'].sfxVolume);
|
||||||
|
|
||||||
watch(replayPlaybackRate, (newValue) => {
|
watch(replayPlaybackRate, (newValue) => {
|
||||||
game.replayPlaybackRate = newValue;
|
game.replayPlaybackRate = newValue;
|
||||||
|
@ -623,7 +624,7 @@ function loadMonoTextures() {
|
||||||
if (renderer.textures[mono.img]) return;
|
if (renderer.textures[mono.img]) return;
|
||||||
|
|
||||||
let src = mono.img;
|
let src = mono.img;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
if (monoTextureUrls[mono.img]) {
|
if (monoTextureUrls[mono.img]) {
|
||||||
src = monoTextureUrls[mono.img];
|
src = monoTextureUrls[mono.img];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
@ -649,7 +650,6 @@ function loadMonoTextures() {
|
||||||
function getTextureImageUrl(mono: Mono) {
|
function getTextureImageUrl(mono: Mono) {
|
||||||
const def = monoDefinitions.value.find(x => x.id === mono.id)!;
|
const def = monoDefinitions.value.find(x => x.id === mono.id)!;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
if (monoTextureUrls[def.img]) {
|
if (monoTextureUrls[def.img]) {
|
||||||
return monoTextureUrls[def.img];
|
return monoTextureUrls[def.img];
|
||||||
|
|
||||||
|
@ -853,13 +853,13 @@ function exportLog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSettings<
|
function updateSettings<
|
||||||
K extends keyof typeof defaultStore.state.dropAndFusion,
|
K extends keyof typeof prefer.s['game.dropAndFusion'],
|
||||||
V extends typeof defaultStore.state.dropAndFusion[K],
|
V extends typeof prefer.s['game.dropAndFusion'][K],
|
||||||
>(key: K, value: V) {
|
>(key: K, value: V) {
|
||||||
const changes: { [P in K]?: V } = {};
|
const changes: { [P in K]?: V } = {};
|
||||||
changes[key] = value;
|
changes[key] = value;
|
||||||
defaultStore.set('dropAndFusion', {
|
prefer.set('game.dropAndFusion', {
|
||||||
...defaultStore.state.dropAndFusion,
|
...prefer.s['game.dropAndFusion'],
|
||||||
...changes,
|
...changes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -909,8 +909,8 @@ function getGameImageDriveFile() {
|
||||||
formData.append('name', `bubble-game-${Date.now()}.png`);
|
formData.append('name', `bubble-game-${Date.now()}.png`);
|
||||||
formData.append('isSensitive', 'false');
|
formData.append('isSensitive', 'false');
|
||||||
formData.append('i', $i.token);
|
formData.append('i', $i.token);
|
||||||
if (defaultStore.state.uploadFolder) {
|
if (prefer.s.uploadFolder) {
|
||||||
formData.append('folderId', defaultStore.state.uploadFolder);
|
formData.append('folderId', prefer.s.uploadFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.fetch(apiUrl + '/drive/files/create', {
|
window.fetch(apiUrl + '/drive/files/create', {
|
||||||
|
|
|
@ -7,9 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="700">
|
<MkSpacer :contentMax="700">
|
||||||
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
|
||||||
<div v-if="flash" :key="flash.id">
|
<div v-if="flash" :key="flash.id">
|
||||||
<Transition :name="defaultStore.state.animation ? 'zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? 'zoom' : ''" mode="out-in">
|
||||||
<div v-if="started" :class="$style.started">
|
<div v-if="started" :class="$style.started">
|
||||||
<div class="main _panel">
|
<div class="main _panel">
|
||||||
<MkAsUi v-if="root" :component="root" :components="components"/>
|
<MkAsUi v-if="root" :component="root" :components="components"/>
|
||||||
|
@ -79,7 +79,7 @@ import { registerAsUiLib } from '@/scripts/aiscript/ui.js';
|
||||||
import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
|
import { aiScriptReadline, createAiScriptEnv } from '@/scripts/aiscript/api.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkCode from '@/components/MkCode.vue';
|
import MkCode from '@/components/MkCode.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="1000" :marginMin="16" :marginMax="32">
|
<MkSpacer :contentMax="1000" :marginMin="16" :marginMax="32">
|
||||||
<div class="_root">
|
<div class="_root">
|
||||||
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
|
||||||
<div v-if="post" class="rkxwuolj">
|
<div v-if="post" class="rkxwuolj">
|
||||||
<div class="files">
|
<div class="files">
|
||||||
<div v-for="file in post.files" :key="file.id" class="file">
|
<div v-for="file in post.files" :key="file.id" class="file">
|
||||||
|
@ -65,6 +65,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref, defineAsyncComponent } from 'vue';
|
import { computed, watch, ref, defineAsyncComponent } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { url } from '@@/js/config.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
@ -72,15 +74,13 @@ import MkContainer from '@/components/MkContainer.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
|
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
|
||||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||||
import { url } from '@@/js/config.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -45,18 +45,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onActivated, onDeactivated, nextTick } from 'vue';
|
import { ref, computed, onActivated, onDeactivated, nextTick } from 'vue';
|
||||||
|
import type { Extension } from '@/components/MkExtensionInstaller.vue';
|
||||||
|
import type { AiScriptPluginMeta } from '@/plugin.js';
|
||||||
import MkLoading from '@/components/global/MkLoading.vue';
|
import MkLoading from '@/components/global/MkLoading.vue';
|
||||||
import MkExtensionInstaller from '@/components/MkExtensionInstaller.vue';
|
import MkExtensionInstaller from '@/components/MkExtensionInstaller.vue';
|
||||||
import type { Extension } from '@/components/MkExtensionInstaller.vue';
|
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkUrl from '@/components/global/MkUrl.vue';
|
import MkUrl from '@/components/global/MkUrl.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { parsePluginMeta, installPlugin } from '@/scripts/install-plugin.js';
|
import { parsePluginMeta, installPlugin } from '@/plugin.js';
|
||||||
import type { AiScriptPluginMeta } from '@/scripts/install-plugin.js';
|
import { parseThemeCode, installTheme } from '@/scripts/theme.js';
|
||||||
import { parseThemeCode, installTheme } from '@/scripts/install-theme.js';
|
|
||||||
import { unisonReload } from '@/scripts/unison-reload.js';
|
import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
|
@ -67,15 +67,15 @@ import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userListsCache } from '@/cache.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
enableInfiniteScroll,
|
enableInfiniteScroll,
|
||||||
} = defaultStore.reactiveState;
|
} = prefer.r;
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="800">
|
<MkSpacer :contentMax="800">
|
||||||
<div>
|
<div>
|
||||||
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
|
||||||
<div v-if="note">
|
<div v-if="note">
|
||||||
<div v-if="showNext" class="_margin">
|
<div v-if="showNext" class="_margin">
|
||||||
<MkNotes class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/>
|
<MkNotes class="" :pagination="showNext === 'channel' ? nextChannelPagination : nextUserPagination" :noGap="true" :disableAutoLoad="true"/>
|
||||||
|
@ -61,7 +61,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { dateString } from '@/filters/date.js';
|
import { dateString } from '@/filters/date.js';
|
||||||
import MkClipPreview from '@/components/MkClipPreview.vue';
|
import MkClipPreview from '@/components/MkClipPreview.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
import { serverContext, assertServerContext } from '@/server-context.js';
|
import { serverContext, assertServerContext } from '@/server-context.js';
|
||||||
|
|
|
@ -8,10 +8,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="800">
|
<MkSpacer :contentMax="800">
|
||||||
<Transition
|
<Transition
|
||||||
:enterActiveClass="defaultStore.state.animation ? $style.fadeEnterActive : ''"
|
:enterActiveClass="prefer.s.animation ? $style.fadeEnterActive : ''"
|
||||||
:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
|
:leaveActiveClass="prefer.s.animation ? $style.fadeLeaveActive : ''"
|
||||||
:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
|
:enterFromClass="prefer.s.animation ? $style.fadeEnterFrom : ''"
|
||||||
:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
|
:leaveToClass="prefer.s.animation ? $style.fadeLeaveTo : ''"
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
<div v-if="page" :key="page.id" class="_gaps">
|
<div v-if="page" :key="page.id" class="_gaps">
|
||||||
|
@ -100,11 +100,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, ref, defineAsyncComponent } from 'vue';
|
import { computed, watch, ref, defineAsyncComponent } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { url } from '@@/js/config.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import XPage from '@/components/page/page.vue';
|
import XPage from '@/components/page/page.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { url } from '@@/js/config.js';
|
|
||||||
import MkMediaImage from '@/components/MkMediaImage.vue';
|
import MkMediaImage from '@/components/MkMediaImage.vue';
|
||||||
import MkImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
import MkImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
|
||||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||||
|
@ -113,7 +114,7 @@ import MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkPagePreview from '@/components/MkPagePreview.vue';
|
import MkPagePreview from '@/components/MkPagePreview.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { pageViewInterruptors, defaultStore } from '@/store.js';
|
import { pageViewInterruptors } from '@/store.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
|
@ -121,7 +122,7 @@ import { instance } from '@/instance.js';
|
||||||
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
import { getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -8,49 +8,63 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<SearchMarker :keywords="['animation', 'motion', 'reduce']">
|
<SearchMarker :keywords="['animation', 'motion', 'reduce']">
|
||||||
<MkSwitch v-model="reduceAnimation">
|
<MkPreferenceContainer k="animation">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.reduceUiAnimation }}</SearchLabel></template>
|
<MkSwitch v-model="reduceAnimation">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.reduceUiAnimation }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
|
<SearchMarker :keywords="['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
|
||||||
<MkSwitch v-model="disableShowingAnimatedImages">
|
<MkPreferenceContainer k="disableShowingAnimatedImages">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.disableShowingAnimatedImages }}</SearchLabel></template>
|
<MkSwitch v-model="disableShowingAnimatedImages">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.disableShowingAnimatedImages }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['mfm', 'enable', 'show', 'animated']">
|
<SearchMarker :keywords="['mfm', 'enable', 'show', 'animated']">
|
||||||
<MkSwitch v-model="animatedMfm">
|
<MkPreferenceContainer k="animatedMfm">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.enableAnimatedMfm }}</SearchLabel></template>
|
<MkSwitch v-model="animatedMfm">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.enableAnimatedMfm }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['swipe', 'horizontal', 'tab']">
|
<SearchMarker :keywords="['swipe', 'horizontal', 'tab']">
|
||||||
<MkSwitch v-model="enableHorizontalSwipe">
|
<MkPreferenceContainer k="enableHorizontalSwipe">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.enableHorizontalSwipe }}</SearchLabel></template>
|
<MkSwitch v-model="enableHorizontalSwipe">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.enableHorizontalSwipe }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['keep', 'screen', 'display', 'on']">
|
<SearchMarker :keywords="['keep', 'screen', 'display', 'on']">
|
||||||
<MkSwitch v-model="keepScreenOn">
|
<MkPreferenceContainer k="keepScreenOn">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.keepScreenOn }}</SearchLabel></template>
|
<MkSwitch v-model="keepScreenOn">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.keepScreenOn }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['native', 'system', 'video', 'audio', 'player', 'media']">
|
<SearchMarker :keywords="['native', 'system', 'video', 'audio', 'player', 'media']">
|
||||||
<MkSwitch v-model="useNativeUIForVideoAudioPlayer">
|
<MkPreferenceContainer k="useNativeUiForVideoAudioPlayer">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</SearchLabel></template>
|
<MkSwitch v-model="useNativeUiForVideoAudioPlayer">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SearchMarker :keywords="['contextmenu', 'system', 'native']">
|
<SearchMarker :keywords="['contextmenu', 'system', 'native']">
|
||||||
<MkSelect v-model="contextMenu">
|
<MkPreferenceContainer k="contextMenu">
|
||||||
<template #label><SearchLabel>{{ i18n.ts._contextMenu.title }}</SearchLabel></template>
|
<MkSelect v-model="contextMenu">
|
||||||
<option value="app">{{ i18n.ts._contextMenu.app }}</option>
|
<template #label><SearchLabel>{{ i18n.ts._contextMenu.title }}</SearchLabel></template>
|
||||||
<option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
|
<option value="app">{{ i18n.ts._contextMenu.app }}</option>
|
||||||
<option value="native">{{ i18n.ts._contextMenu.native }}</option>
|
<option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
|
||||||
</MkSelect>
|
<option value="native">{{ i18n.ts._contextMenu.native }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
</div>
|
</div>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
@ -60,18 +74,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { reloadAsk } from '@/scripts/reload-ask.js';
|
import { reloadAsk } from '@/scripts/reload-ask.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||||
|
|
||||||
const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
|
const reduceAnimation = prefer.model('animation', v => !v, v => !v);
|
||||||
const animatedMfm = computed(defaultStore.makeGetterSetter('animatedMfm'));
|
const animatedMfm = prefer.model('animatedMfm');
|
||||||
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
|
const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages');
|
||||||
const keepScreenOn = computed(defaultStore.makeGetterSetter('keepScreenOn'));
|
const keepScreenOn = prefer.model('keepScreenOn');
|
||||||
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
|
const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe');
|
||||||
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
|
const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer');
|
||||||
const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu'));
|
const contextMenu = prefer.model('contextMenu');
|
||||||
|
|
||||||
watch([
|
watch([
|
||||||
keepScreenOn,
|
keepScreenOn,
|
||||||
|
|
|
@ -10,73 +10,85 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<SearchMarker :keywords="['blur']">
|
<SearchMarker :keywords="['blur']">
|
||||||
<MkSwitch v-model="useBlurEffect">
|
<MkPreferenceContainer k="useBlurEffect">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
|
<MkSwitch v-model="useBlurEffect">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['blur', 'modal']">
|
<SearchMarker :keywords="['blur', 'modal']">
|
||||||
<MkSwitch v-model="useBlurEffectForModal">
|
<MkPreferenceContainer k="useBlurEffectForModal">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template>
|
<MkSwitch v-model="useBlurEffectForModal">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail']">
|
<SearchMarker :keywords="['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail']">
|
||||||
<MkSwitch v-model="highlightSensitiveMedia">
|
<MkPreferenceContainer k="highlightSensitiveMedia">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.highlightSensitiveMedia }}</SearchLabel></template>
|
<MkSwitch v-model="highlightSensitiveMedia">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.highlightSensitiveMedia }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['avatar', 'icon', 'square']">
|
<SearchMarker :keywords="['avatar', 'icon', 'square']">
|
||||||
<MkSwitch v-model="squareAvatars">
|
<MkPreferenceContainer k="squareAvatars">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.squareAvatars }}</SearchLabel></template>
|
<MkSwitch v-model="squareAvatars">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.squareAvatars }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
|
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
|
||||||
<MkSwitch v-model="showAvatarDecorations">
|
<MkPreferenceContainer k="showAvatarDecorations">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.showAvatarDecorations }}</SearchLabel></template>
|
<MkSwitch v-model="showAvatarDecorations">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.showAvatarDecorations }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['note', 'timeline', 'gap']">
|
<SearchMarker :keywords="['note', 'timeline', 'gap']">
|
||||||
<MkSwitch v-model="showGapBetweenNotesInTimeline">
|
<MkPreferenceContainer k="showGapBetweenNotesInTimeline">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.showGapBetweenNotesInTimeline }}</SearchLabel></template>
|
<MkSwitch v-model="showGapBetweenNotesInTimeline">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.showGapBetweenNotesInTimeline }}</SearchLabel></template>
|
||||||
</SearchMarker>
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
<SearchMarker :keywords="['font', 'system', 'native']">
|
|
||||||
<MkSwitch v-model="useSystemFont">
|
|
||||||
<template #label><SearchLabel>{{ i18n.ts.useSystemFont }}</SearchLabel></template>
|
|
||||||
</MkSwitch>
|
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['effect', 'show']">
|
<SearchMarker :keywords="['effect', 'show']">
|
||||||
<MkSwitch v-model="enableSeasonalScreenEffect">
|
<MkPreferenceContainer k="enableSeasonalScreenEffect">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.seasonalScreenEffect }}</SearchLabel></template>
|
<MkSwitch v-model="enableSeasonalScreenEffect">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.seasonalScreenEffect }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SearchMarker :keywords="['menu', 'style', 'popup', 'drawer']">
|
<SearchMarker :keywords="['menu', 'style', 'popup', 'drawer']">
|
||||||
<MkSelect v-model="menuStyle">
|
<MkPreferenceContainer k="menuStyle">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.menuStyle }}</SearchLabel></template>
|
<MkSelect v-model="menuStyle">
|
||||||
<option value="auto">{{ i18n.ts.auto }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.menuStyle }}</SearchLabel></template>
|
||||||
<option value="popup">{{ i18n.ts.popup }}</option>
|
<option value="auto">{{ i18n.ts.auto }}</option>
|
||||||
<option value="drawer">{{ i18n.ts.drawer }}</option>
|
<option value="popup">{{ i18n.ts.popup }}</option>
|
||||||
</MkSelect>
|
<option value="drawer">{{ i18n.ts.drawer }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['emoji', 'style', 'native', 'system', 'fluent', 'twemoji']">
|
<SearchMarker :keywords="['emoji', 'style', 'native', 'system', 'fluent', 'twemoji']">
|
||||||
<div>
|
<MkPreferenceContainer k="emojiStyle">
|
||||||
<MkRadios v-model="emojiStyle">
|
<div>
|
||||||
<template #label><SearchLabel>{{ i18n.ts.emojiStyle }}</SearchLabel></template>
|
<MkRadios v-model="emojiStyle">
|
||||||
<option value="native">{{ i18n.ts.native }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.emojiStyle }}</SearchLabel></template>
|
||||||
<option value="fluentEmoji">Fluent Emoji</option>
|
<option value="native">{{ i18n.ts.native }}</option>
|
||||||
<option value="twemoji">Twemoji</option>
|
<option value="fluentEmoji">Fluent Emoji</option>
|
||||||
</MkRadios>
|
<option value="twemoji">Twemoji</option>
|
||||||
<div style="margin: 8px 0 0 0; font-size: 1.5em;"><Mfm :key="emojiStyle" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
|
</MkRadios>
|
||||||
</div>
|
<div style="margin: 8px 0 0 0; font-size: 1.5em;"><Mfm :key="emojiStyle" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
|
||||||
|
</div>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['font', 'size']">
|
<SearchMarker :keywords="['font', 'size']">
|
||||||
|
@ -88,6 +100,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<option value="3"><span style="font-size: 17px;">Aa</span></option>
|
<option value="3"><span style="font-size: 17px;">Aa</span></option>
|
||||||
</MkRadios>
|
</MkRadios>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
|
<SearchMarker :keywords="['font', 'system', 'native']">
|
||||||
|
<MkSwitch v-model="useSystemFont">
|
||||||
|
<template #label><SearchLabel>{{ i18n.ts.useSystemFont }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</SearchMarker>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
@ -97,46 +115,56 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display']">
|
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display']">
|
||||||
<MkRadios v-model="reactionsDisplaySize">
|
<MkPreferenceContainer k="reactionsDisplaySize">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.reactionsDisplaySize }}</SearchLabel></template>
|
<MkRadios v-model="reactionsDisplaySize">
|
||||||
<option value="small">{{ i18n.ts.small }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.reactionsDisplaySize }}</SearchLabel></template>
|
||||||
<option value="medium">{{ i18n.ts.medium }}</option>
|
<option value="small">{{ i18n.ts.small }}</option>
|
||||||
<option value="large">{{ i18n.ts.large }}</option>
|
<option value="medium">{{ i18n.ts.medium }}</option>
|
||||||
</MkRadios>
|
<option value="large">{{ i18n.ts.large }}</option>
|
||||||
|
</MkRadios>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display', 'width', 'limit']">
|
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display', 'width', 'limit']">
|
||||||
<MkSwitch v-model="limitWidthOfReaction">
|
<MkPreferenceContainer k="limitWidthOfReaction">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.limitWidthOfReaction }}</SearchLabel></template>
|
<MkSwitch v-model="limitWidthOfReaction">
|
||||||
</MkSwitch>
|
<template #label><SearchLabel>{{ i18n.ts.limitWidthOfReaction }}</SearchLabel></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height']">
|
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height']">
|
||||||
<MkRadios v-model="mediaListWithOneImageAppearance">
|
<MkPreferenceContainer k="mediaListWithOneImageAppearance">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.mediaListWithOneImageAppearance }}</SearchLabel></template>
|
<MkRadios v-model="mediaListWithOneImageAppearance">
|
||||||
<option value="expand">{{ i18n.ts.default }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.mediaListWithOneImageAppearance }}</SearchLabel></template>
|
||||||
<option value="16_9">{{ i18n.tsx.limitTo({ x: '16:9' }) }}</option>
|
<option value="expand">{{ i18n.ts.default }}</option>
|
||||||
<option value="1_1">{{ i18n.tsx.limitTo({ x: '1:1' }) }}</option>
|
<option value="16_9">{{ i18n.tsx.limitTo({ x: '16:9' }) }}</option>
|
||||||
<option value="2_3">{{ i18n.tsx.limitTo({ x: '2:3' }) }}</option>
|
<option value="1_1">{{ i18n.tsx.limitTo({ x: '1:1' }) }}</option>
|
||||||
</MkRadios>
|
<option value="2_3">{{ i18n.tsx.limitTo({ x: '2:3' }) }}</option>
|
||||||
|
</MkRadios>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
|
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
|
||||||
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
|
<MkPreferenceContainer k="instanceTicker">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.instanceTicker }}</SearchLabel></template>
|
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
|
||||||
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.instanceTicker }}</SearchLabel></template>
|
||||||
<option value="remote">{{ i18n.ts._instanceTicker.remote }}</option>
|
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
||||||
<option value="always">{{ i18n.ts._instanceTicker.always }}</option>
|
<option value="remote">{{ i18n.ts._instanceTicker.remote }}</option>
|
||||||
</MkSelect>
|
<option value="always">{{ i18n.ts._instanceTicker.always }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility']">
|
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility']">
|
||||||
<MkSelect v-model="nsfw">
|
<MkPreferenceContainer k="nsfw">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.displayOfSensitiveMedia }}</SearchLabel></template>
|
<MkSelect v-model="nsfw">
|
||||||
<option value="respect">{{ i18n.ts._displayOfSensitiveMedia.respect }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.displayOfSensitiveMedia }}</SearchLabel></template>
|
||||||
<option value="ignore">{{ i18n.ts._displayOfSensitiveMedia.ignore }}</option>
|
<option value="respect">{{ i18n.ts._displayOfSensitiveMedia.respect }}</option>
|
||||||
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
|
<option value="ignore">{{ i18n.ts._displayOfSensitiveMedia.ignore }}</option>
|
||||||
</MkSelect>
|
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
@ -148,21 +176,25 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<SearchMarker :keywords="['position']">
|
<SearchMarker :keywords="['position']">
|
||||||
<MkRadios v-model="notificationPosition">
|
<MkPreferenceContainer k="notificationPosition">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.position }}</SearchLabel></template>
|
<MkRadios v-model="notificationPosition">
|
||||||
<option value="leftTop"><i class="ti ti-align-box-left-top"></i> {{ i18n.ts.leftTop }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.position }}</SearchLabel></template>
|
||||||
<option value="rightTop"><i class="ti ti-align-box-right-top"></i> {{ i18n.ts.rightTop }}</option>
|
<option value="leftTop"><i class="ti ti-align-box-left-top"></i> {{ i18n.ts.leftTop }}</option>
|
||||||
<option value="leftBottom"><i class="ti ti-align-box-left-bottom"></i> {{ i18n.ts.leftBottom }}</option>
|
<option value="rightTop"><i class="ti ti-align-box-right-top"></i> {{ i18n.ts.rightTop }}</option>
|
||||||
<option value="rightBottom"><i class="ti ti-align-box-right-bottom"></i> {{ i18n.ts.rightBottom }}</option>
|
<option value="leftBottom"><i class="ti ti-align-box-left-bottom"></i> {{ i18n.ts.leftBottom }}</option>
|
||||||
</MkRadios>
|
<option value="rightBottom"><i class="ti ti-align-box-right-bottom"></i> {{ i18n.ts.rightBottom }}</option>
|
||||||
|
</MkRadios>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['stack', 'axis', 'direction']">
|
<SearchMarker :keywords="['stack', 'axis', 'direction']">
|
||||||
<MkRadios v-model="notificationStackAxis">
|
<MkPreferenceContainer k="notificationStackAxis">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.stackAxis }}</SearchLabel></template>
|
<MkRadios v-model="notificationStackAxis">
|
||||||
<option value="vertical"><i class="ti ti-carousel-vertical"></i> {{ i18n.ts.vertical }}</option>
|
<template #label><SearchLabel>{{ i18n.ts.stackAxis }}</SearchLabel></template>
|
||||||
<option value="horizontal"><i class="ti ti-carousel-horizontal"></i> {{ i18n.ts.horizontal }}</option>
|
<option value="vertical"><i class="ti ti-carousel-vertical"></i> {{ i18n.ts.vertical }}</option>
|
||||||
</MkRadios>
|
<option value="horizontal"><i class="ti ti-carousel-horizontal"></i> {{ i18n.ts.horizontal }}</option>
|
||||||
|
</MkRadios>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<MkButton @click="testNotification">{{ i18n.ts._notification.checkNotificationBehavior }}</MkButton>
|
<MkButton @click="testNotification">{{ i18n.ts._notification.checkNotificationBehavior }}</MkButton>
|
||||||
|
@ -183,7 +215,7 @@ import * as Misskey from 'misskey-js';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { reloadAsk } from '@/scripts/reload-ask.js';
|
import { reloadAsk } from '@/scripts/reload-ask.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
@ -194,26 +226,27 @@ import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||||
|
|
||||||
const fontSize = ref(miLocalStorage.getItem('fontSize'));
|
const fontSize = ref(miLocalStorage.getItem('fontSize'));
|
||||||
const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
|
const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
|
||||||
|
|
||||||
const showAvatarDecorations = computed(defaultStore.makeGetterSetter('showAvatarDecorations'));
|
const showAvatarDecorations = prefer.model('showAvatarDecorations');
|
||||||
const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle'));
|
const emojiStyle = prefer.model('emojiStyle');
|
||||||
const menuStyle = computed(defaultStore.makeGetterSetter('menuStyle'));
|
const menuStyle = prefer.model('menuStyle');
|
||||||
const useBlurEffectForModal = computed(defaultStore.makeGetterSetter('useBlurEffectForModal'));
|
const useBlurEffectForModal = prefer.model('useBlurEffectForModal');
|
||||||
const useBlurEffect = computed(defaultStore.makeGetterSetter('useBlurEffect'));
|
const useBlurEffect = prefer.model('useBlurEffect');
|
||||||
const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia'));
|
const highlightSensitiveMedia = prefer.model('highlightSensitiveMedia');
|
||||||
const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars'));
|
const squareAvatars = prefer.model('squareAvatars');
|
||||||
const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
|
const enableSeasonalScreenEffect = prefer.model('enableSeasonalScreenEffect');
|
||||||
const showGapBetweenNotesInTimeline = computed(defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'));
|
const showGapBetweenNotesInTimeline = prefer.model('showGapBetweenNotesInTimeline');
|
||||||
const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter('mediaListWithOneImageAppearance'));
|
const mediaListWithOneImageAppearance = prefer.model('mediaListWithOneImageAppearance');
|
||||||
const reactionsDisplaySize = computed(defaultStore.makeGetterSetter('reactionsDisplaySize'));
|
const reactionsDisplaySize = prefer.model('reactionsDisplaySize');
|
||||||
const limitWidthOfReaction = computed(defaultStore.makeGetterSetter('limitWidthOfReaction'));
|
const limitWidthOfReaction = prefer.model('limitWidthOfReaction');
|
||||||
const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition'));
|
const notificationPosition = prefer.model('notificationPosition');
|
||||||
const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis'));
|
const notificationStackAxis = prefer.model('notificationStackAxis');
|
||||||
const nsfw = computed(defaultStore.makeGetterSetter('nsfw'));
|
const nsfw = prefer.model('nsfw');
|
||||||
const instanceTicker = computed(defaultStore.makeGetterSetter('instanceTicker'));
|
const instanceTicker = prefer.model('instanceTicker');
|
||||||
|
|
||||||
watch(fontSize, () => {
|
watch(fontSize, () => {
|
||||||
if (fontSize.value == null) {
|
if (fontSize.value == null) {
|
||||||
|
|
|
@ -23,14 +23,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
import { deckStore } from '@/ui/deck/deck-store.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const navWindow = computed(deckStore.makeGetterSetter('navWindow'));
|
const navWindow = prefer.model('deck.navWindow');
|
||||||
const useSimpleUiForNonRootPages = computed(deckStore.makeGetterSetter('useSimpleUiForNonRootPages'));
|
const useSimpleUiForNonRootPages = prefer.model('deck.useSimpleUiForNonRootPages');
|
||||||
const alwaysShowMainColumn = computed(deckStore.makeGetterSetter('alwaysShowMainColumn'));
|
const alwaysShowMainColumn = prefer.model('deck.alwaysShowMainColumn');
|
||||||
const columnAlign = computed(deckStore.makeGetterSetter('columnAlign'));
|
const columnAlign = prefer.model('deck.columnAlign');
|
||||||
|
|
||||||
const headerActions = computed(() => []);
|
const headerActions = computed(() => []);
|
||||||
|
|
||||||
|
|
|
@ -50,17 +50,21 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</FormLink>
|
</FormLink>
|
||||||
|
|
||||||
<SearchMarker :keywords="['keep', 'original', 'raw', 'upload']">
|
<SearchMarker :keywords="['keep', 'original', 'raw', 'upload']">
|
||||||
<MkSwitch v-model="keepOriginalUploading">
|
<MkPreferenceContainer k="keepOriginalUploading">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.keepOriginalUploading }}</SearchLabel></template>
|
<MkSwitch v-model="keepOriginalUploading">
|
||||||
<template #caption><SearchKeyword>{{ i18n.ts.keepOriginalUploadingDescription }}</SearchKeyword></template>
|
<template #label><SearchLabel>{{ i18n.ts.keepOriginalUploading }}</SearchLabel></template>
|
||||||
</MkSwitch>
|
<template #caption><SearchKeyword>{{ i18n.ts.keepOriginalUploadingDescription }}</SearchKeyword></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['keep', 'original', 'filename']">
|
<SearchMarker :keywords="['keep', 'original', 'filename']">
|
||||||
<MkSwitch v-model="keepOriginalFilename">
|
<MkPreferenceContainer k="keepOriginalFilename">
|
||||||
<template #label><SearchLabel>{{ i18n.ts.keepOriginalFilename }}</SearchLabel></template>
|
<MkSwitch v-model="keepOriginalFilename">
|
||||||
<template #caption><SearchKeyword>{{ i18n.ts.keepOriginalFilenameDescription }}</SearchKeyword></template>
|
<template #label><SearchLabel>{{ i18n.ts.keepOriginalFilename }}</SearchLabel></template>
|
||||||
</MkSwitch>
|
<template #caption><SearchKeyword>{{ i18n.ts.keepOriginalFilenameDescription }}</SearchKeyword></template>
|
||||||
|
</MkSwitch>
|
||||||
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker :keywords="['always', 'default', 'mark', 'nsfw', 'sensitive', 'media', 'file']">
|
<SearchMarker :keywords="['always', 'default', 'mark', 'nsfw', 'sensitive', 'media', 'file']">
|
||||||
|
@ -93,11 +97,12 @@ import FormSplit from '@/components/form/split.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import bytes from '@/filters/bytes.js';
|
import bytes from '@/filters/bytes.js';
|
||||||
import { defaultStore } from '@/store.js';
|
|
||||||
import MkChart from '@/components/MkChart.vue';
|
import MkChart from '@/components/MkChart.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { signinRequired } from '@/account.js';
|
import { signinRequired } from '@/account.js';
|
||||||
|
import { prefer } from '@/preferences.js';
|
||||||
|
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
|
||||||
|
@ -120,8 +125,8 @@ const meterStyle = computed(() => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const keepOriginalUploading = computed(defaultStore.makeGetterSetter('keepOriginalUploading'));
|
const keepOriginalUploading = prefer.model('keepOriginalUploading');
|
||||||
const keepOriginalFilename = computed(defaultStore.makeGetterSetter('keepOriginalFilename'));
|
const keepOriginalFilename = prefer.model('keepOriginalFilename');
|
||||||
|
|
||||||
misskeyApi('drive').then(info => {
|
misskeyApi('drive').then(info => {
|
||||||
capacity.value = info.capacity;
|
capacity.value = info.capacity;
|
||||||
|
@ -129,9 +134,9 @@ misskeyApi('drive').then(info => {
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (defaultStore.state.uploadFolder) {
|
if (prefer.s.uploadFolder) {
|
||||||
misskeyApi('drive/folders/show', {
|
misskeyApi('drive/folders/show', {
|
||||||
folderId: defaultStore.state.uploadFolder,
|
folderId: prefer.s.uploadFolder,
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
uploadFolder.value = response;
|
uploadFolder.value = response;
|
||||||
});
|
});
|
||||||
|
@ -139,11 +144,11 @@ if (defaultStore.state.uploadFolder) {
|
||||||
|
|
||||||
function chooseUploadFolder() {
|
function chooseUploadFolder() {
|
||||||
os.selectDriveFolder(false).then(async folder => {
|
os.selectDriveFolder(false).then(async folder => {
|
||||||
defaultStore.set('uploadFolder', folder[0] ? folder[0].id : null);
|
prefer.set('uploadFolder', folder[0] ? folder[0].id : null);
|
||||||
os.success();
|
os.success();
|
||||||
if (defaultStore.state.uploadFolder) {
|
if (prefer.s.uploadFolder) {
|
||||||
uploadFolder.value = await misskeyApi('drive/folders/show', {
|
uploadFolder.value = await misskeyApi('drive/folders/show', {
|
||||||
folderId: defaultStore.state.uploadFolder,
|
folderId: prefer.s.uploadFolder,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
uploadFolder.value = null;
|
uploadFolder.value = null;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue