Compare commits
5 Commits
2024.9.0-a
...
2024.9.0-a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6378dfbffc | ||
![]() |
cd247b99ee | ||
![]() |
0c6d1ec524 | ||
![]() |
e673c143a9 | ||
![]() |
7f7445ad7a |
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -12,6 +12,8 @@ on:
|
|||||||
- packages/frontend-embed/**
|
- packages/frontend-embed/**
|
||||||
- packages/sw/**
|
- packages/sw/**
|
||||||
- packages/misskey-js/**
|
- packages/misskey-js/**
|
||||||
|
- packages/misskey-bubble-game/**
|
||||||
|
- packages/misskey-reversi/**
|
||||||
- packages/shared/eslint.config.js
|
- packages/shared/eslint.config.js
|
||||||
- .github/workflows/lint.yml
|
- .github/workflows/lint.yml
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -22,6 +24,8 @@ on:
|
|||||||
- packages/frontend-embed/**
|
- packages/frontend-embed/**
|
||||||
- packages/sw/**
|
- packages/sw/**
|
||||||
- packages/misskey-js/**
|
- packages/misskey-js/**
|
||||||
|
- packages/misskey-bubble-game/**
|
||||||
|
- packages/misskey-reversi/**
|
||||||
- packages/shared/eslint.config.js
|
- packages/shared/eslint.config.js
|
||||||
- .github/workflows/lint.yml
|
- .github/workflows/lint.yml
|
||||||
jobs:
|
jobs:
|
||||||
@@ -53,6 +57,8 @@ jobs:
|
|||||||
- frontend-embed
|
- frontend-embed
|
||||||
- sw
|
- sw
|
||||||
- misskey-js
|
- misskey-js
|
||||||
|
- misskey-bubble-game
|
||||||
|
- misskey-reversi
|
||||||
env:
|
env:
|
||||||
eslint-cache-version: v1
|
eslint-cache-version: v1
|
||||||
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
- Enhance: ScratchpadにUIインスペクターを追加
|
- Enhance: ScratchpadにUIインスペクターを追加
|
||||||
- Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正
|
- Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正
|
||||||
- Fix: 月の違う同じ日はセパレータが表示されないのを修正
|
- Fix: 月の違う同じ日はセパレータが表示されないのを修正
|
||||||
|
- Fix: タッチ画面でレンジスライダーを操作するとツールチップが複数表示される問題を修正
|
||||||
|
(Cherry-picked from https://github.com/taiyme/misskey/pull/265)
|
||||||
- Fix: 縦横比が極端なカスタム絵文字を表示する際にレイアウトが崩れる箇所があるのを修正
|
- Fix: 縦横比が極端なカスタム絵文字を表示する際にレイアウトが崩れる箇所があるのを修正
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/725)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/725)
|
||||||
- Fix: 設定変更時のリロード確認ダイアログが複数個表示されることがある問題を修正
|
- Fix: 設定変更時のリロード確認ダイアログが複数個表示されることがある問題を修正
|
||||||
@@ -28,6 +30,8 @@
|
|||||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/26e0412fbb91447c37e8fb06ffb0487346063bb8)
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/26e0412fbb91447c37e8fb06ffb0487346063bb8)
|
||||||
- Fix: `Retry-After`ヘッダーが送信されなかった問題を修正
|
- Fix: `Retry-After`ヘッダーが送信されなかった問題を修正
|
||||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/8a982c61c01909e7540ff1be9f019df07c3f0624)
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/8a982c61c01909e7540ff1be9f019df07c3f0624)
|
||||||
|
- Fix: サーバーサイドのDOM解析完了時にリソースを開放するように
|
||||||
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/634)
|
||||||
|
|
||||||
## 2024.8.0
|
## 2024.8.0
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2024.9.0-alpha.6",
|
"version": "2024.9.0-alpha.7",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@@ -239,7 +239,7 @@ export class MfmService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { window } = new Window();
|
const { happyDOM, window } = new Window();
|
||||||
|
|
||||||
const doc = window.document;
|
const doc = window.document;
|
||||||
|
|
||||||
@@ -457,6 +457,10 @@ export class MfmService {
|
|||||||
|
|
||||||
appendChildren(nodes, body);
|
appendChildren(nodes, body);
|
||||||
|
|
||||||
return new XMLSerializer().serializeToString(body);
|
const serialized = new XMLSerializer().serializeToString(body);
|
||||||
|
|
||||||
|
happyDOM.close().catch(err => {});
|
||||||
|
|
||||||
|
return serialized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -207,7 +207,7 @@ export class ApRequestService {
|
|||||||
|
|
||||||
if ((contentType ?? '').split(';')[0].trimEnd().toLowerCase() === 'text/html' && _followAlternate === true) {
|
if ((contentType ?? '').split(';')[0].trimEnd().toLowerCase() === 'text/html' && _followAlternate === true) {
|
||||||
const html = await res.text();
|
const html = await res.text();
|
||||||
const window = new Window({
|
const { window, happyDOM } = new Window({
|
||||||
settings: {
|
settings: {
|
||||||
disableJavaScriptEvaluation: true,
|
disableJavaScriptEvaluation: true,
|
||||||
disableJavaScriptFileLoading: true,
|
disableJavaScriptFileLoading: true,
|
||||||
@@ -241,7 +241,7 @@ export class ApRequestService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// something went wrong parsing the HTML, ignore the whole thing
|
// something went wrong parsing the HTML, ignore the whole thing
|
||||||
} finally {
|
} finally {
|
||||||
window.close();
|
happyDOM.close().catch(err => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@@ -8,7 +8,7 @@ import * as Misskey from 'misskey-js';
|
|||||||
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js';
|
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { MenuButton } from '@/types/menu.js';
|
import type { MenuItem, MenuButton } from '@/types/menu.js';
|
||||||
import { del, get, set } from '@/scripts/idb-proxy.js';
|
import { del, get, set } from '@/scripts/idb-proxy.js';
|
||||||
import { apiUrl } from '@@/js/config.js';
|
import { apiUrl } from '@@/js/config.js';
|
||||||
import { waiting, popup, popupMenu, success, alert } from '@/os.js';
|
import { waiting, popup, popupMenu, success, alert } from '@/os.js';
|
||||||
@@ -288,14 +288,26 @@ export async function openAccountMenu(opts: {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
if (opts.withExtraOperation) {
|
if (opts.withExtraOperation) {
|
||||||
popupMenu([...[{
|
menuItems.push({
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
text: i18n.ts.profile,
|
text: i18n.ts.profile,
|
||||||
to: `/@${$i.username}`,
|
to: `/@${$i.username}`,
|
||||||
avatar: $i,
|
avatar: $i,
|
||||||
}, { type: 'divider' as const }, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, {
|
}, {
|
||||||
type: 'parent' as const,
|
type: 'divider',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.includeCurrentAccount) {
|
||||||
|
menuItems.push(createItem($i));
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push(...accountItemPromises);
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
|
type: 'parent',
|
||||||
icon: 'ti ti-plus',
|
icon: 'ti ti-plus',
|
||||||
text: i18n.ts.addAccount,
|
text: i18n.ts.addAccount,
|
||||||
children: [{
|
children: [{
|
||||||
@@ -306,19 +318,23 @@ export async function openAccountMenu(opts: {
|
|||||||
action: () => { createAccount(); },
|
action: () => { createAccount(); },
|
||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
icon: 'ti ti-users',
|
icon: 'ti ti-users',
|
||||||
text: i18n.ts.manageAccounts,
|
text: i18n.ts.manageAccounts,
|
||||||
to: '/settings/accounts',
|
to: '/settings/accounts',
|
||||||
}]], ev.currentTarget ?? ev.target, {
|
|
||||||
align: 'left',
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget ?? ev.target, {
|
if (opts.includeCurrentAccount) {
|
||||||
|
menuItems.push(createItem($i));
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push(...accountItemPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
popupMenu(menuItems, ev.currentTarget ?? ev.target, {
|
||||||
align: 'left',
|
align: 'left',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
(window as any).$i = $i;
|
(window as any).$i = $i;
|
||||||
|
@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
|
import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import { 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 { defaultStore } from '@/store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@@ -42,7 +42,7 @@ import { i18n } from '@/i18n.js';
|
|||||||
import { defaultStore } from '@/store.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
folder: Misskey.entities.DriveFolder;
|
folder: Misskey.entities.DriveFolder;
|
||||||
|
@@ -620,7 +620,9 @@ function fetchMoreFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMenu() {
|
function getMenu() {
|
||||||
const menu: MenuItem[] = [{
|
const menu: MenuItem[] = [];
|
||||||
|
|
||||||
|
menu.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.keepOriginalUploading,
|
text: i18n.ts.keepOriginalUploading,
|
||||||
ref: keepOriginal,
|
ref: keepOriginal,
|
||||||
@@ -638,19 +640,25 @@ function getMenu() {
|
|||||||
}, { type: 'divider' }, {
|
}, { type: 'divider' }, {
|
||||||
text: folder.value ? folder.value.name : i18n.ts.drive,
|
text: folder.value ? folder.value.name : i18n.ts.drive,
|
||||||
type: 'label',
|
type: 'label',
|
||||||
}, folder.value ? {
|
});
|
||||||
|
|
||||||
|
if (folder.value) {
|
||||||
|
menu.push({
|
||||||
text: i18n.ts.renameFolder,
|
text: i18n.ts.renameFolder,
|
||||||
icon: 'ti ti-forms',
|
icon: 'ti ti-forms',
|
||||||
action: () => { if (folder.value) renameFolder(folder.value); },
|
action: () => { if (folder.value) renameFolder(folder.value); },
|
||||||
} : undefined, folder.value ? {
|
}, {
|
||||||
text: i18n.ts.deleteFolder,
|
text: i18n.ts.deleteFolder,
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
action: () => { deleteFolder(folder.value as Misskey.entities.DriveFolder); },
|
action: () => { deleteFolder(folder.value as Misskey.entities.DriveFolder); },
|
||||||
} : undefined, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.push({
|
||||||
text: i18n.ts.createFolder,
|
text: i18n.ts.createFolder,
|
||||||
icon: 'ti ti-folder-plus',
|
icon: 'ti ti-folder-plus',
|
||||||
action: () => { createFolder(); },
|
action: () => { createFolder(); },
|
||||||
}];
|
});
|
||||||
|
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
@@ -172,9 +172,7 @@ async function show() {
|
|||||||
const menuShowing = ref(false);
|
const menuShowing = ref(false);
|
||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
let menu: MenuItem[] = [];
|
const menu: MenuItem[] = [
|
||||||
|
|
||||||
menu = [
|
|
||||||
// TODO: 再生キューに追加
|
// TODO: 再生キューに追加
|
||||||
{
|
{
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
@@ -222,7 +220,7 @@ function showMenu(ev: MouseEvent) {
|
|||||||
menu.push({
|
menu.push({
|
||||||
type: 'divider',
|
type: 'divider',
|
||||||
}, {
|
}, {
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
text: i18n.ts._fileViewer.title,
|
text: i18n.ts._fileViewer.title,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
to: `/my/drive/file/${props.audio.id}`,
|
to: `/my/drive/file/${props.audio.id}`,
|
||||||
|
@@ -60,6 +60,7 @@ 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 type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
image: Misskey.entities.DriveFile;
|
image: Misskey.entities.DriveFile;
|
||||||
@@ -111,27 +112,39 @@ watch(() => props.image, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.hide,
|
text: i18n.ts.hide,
|
||||||
icon: 'ti ti-eye-off',
|
icon: 'ti ti-eye-off',
|
||||||
action: () => {
|
action: () => {
|
||||||
hide.value = true;
|
hide.value = true;
|
||||||
},
|
},
|
||||||
}, ...(iAmModerator ? [{
|
});
|
||||||
|
|
||||||
|
if (iAmModerator) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.markAsSensitive,
|
text: i18n.ts.markAsSensitive,
|
||||||
icon: 'ti ti-eye-exclamation',
|
icon: 'ti ti-eye-exclamation',
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
|
os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true });
|
||||||
},
|
},
|
||||||
}] : []), ...($i?.id === props.image.userId ? [{
|
});
|
||||||
type: 'divider' as const,
|
}
|
||||||
|
|
||||||
|
if ($i?.id === props.image.userId) {
|
||||||
|
menuItems.push({
|
||||||
|
type: 'divider',
|
||||||
}, {
|
}, {
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
text: i18n.ts._fileViewer.title,
|
text: i18n.ts._fileViewer.title,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
to: `/my/drive/file/${props.image.id}`,
|
to: `/my/drive/file/${props.image.id}`,
|
||||||
}] : [])], ev.currentTarget ?? ev.target);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@@ -192,9 +192,7 @@ async function show() {
|
|||||||
const menuShowing = ref(false);
|
const menuShowing = ref(false);
|
||||||
|
|
||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
let menu: MenuItem[] = [];
|
const menu: MenuItem[] = [
|
||||||
|
|
||||||
menu = [
|
|
||||||
// TODO: 再生キューに追加
|
// TODO: 再生キューに追加
|
||||||
{
|
{
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
@@ -247,7 +245,7 @@ function showMenu(ev: MouseEvent) {
|
|||||||
menu.push({
|
menu.push({
|
||||||
type: 'divider',
|
type: 'divider',
|
||||||
}, {
|
}, {
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
text: i18n.ts._fileViewer.title,
|
text: i18n.ts._fileViewer.title,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
to: `/my/drive/file/${props.video.id}`,
|
to: `/my/drive/file/${props.video.id}`,
|
||||||
|
@@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, onUnmounted, provide, shallowRef, watch } from 'vue';
|
import { nextTick, onMounted, onUnmounted, provide, shallowRef, watch } from 'vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
items: MenuItem[];
|
items: MenuItem[];
|
||||||
|
@@ -193,7 +193,7 @@ import { deepClone } from '@/scripts/clone.js';
|
|||||||
import { useTooltip } from '@/scripts/use-tooltip.js';
|
import { useTooltip } from '@/scripts/use-tooltip.js';
|
||||||
import { claimAchievement } from '@/scripts/achievements.js';
|
import { claimAchievement } from '@/scripts/achievements.js';
|
||||||
import { getNoteSummary } from '@/scripts/get-note-summary.js';
|
import { getNoteSummary } from '@/scripts/get-note-summary.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.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 { shouldCollapsed } from '@@/js/collapsed.js';
|
import { shouldCollapsed } from '@@/js/collapsed.js';
|
||||||
|
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
import { ref, shallowRef } from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import MkModal from './MkModal.vue';
|
import MkModal from './MkModal.vue';
|
||||||
import MkMenu from './MkMenu.vue';
|
import MkMenu from './MkMenu.vue';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
items: MenuItem[];
|
items: MenuItem[];
|
||||||
|
@@ -26,6 +26,7 @@ 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 type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||||
|
|
||||||
@@ -136,7 +137,10 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
|||||||
if (menuShowing) return;
|
if (menuShowing) return;
|
||||||
|
|
||||||
const isImage = file.type.startsWith('image/');
|
const isImage = file.type.startsWith('image/');
|
||||||
os.popupMenu([{
|
|
||||||
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.renameFile,
|
text: i18n.ts.renameFile,
|
||||||
icon: 'ti ti-forms',
|
icon: 'ti ti-forms',
|
||||||
action: () => { rename(file); },
|
action: () => { rename(file); },
|
||||||
@@ -148,11 +152,17 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
|||||||
text: i18n.ts.describeFile,
|
text: i18n.ts.describeFile,
|
||||||
icon: 'ti ti-text-caption',
|
icon: 'ti ti-text-caption',
|
||||||
action: () => { describe(file); },
|
action: () => { describe(file); },
|
||||||
}, ...isImage ? [{
|
});
|
||||||
|
|
||||||
|
if (isImage) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.cropImage,
|
text: i18n.ts.cropImage,
|
||||||
icon: 'ti ti-crop',
|
icon: 'ti ti-crop',
|
||||||
action: () : void => { crop(file); },
|
action: () : void => { crop(file); },
|
||||||
}] : [], {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'divider',
|
type: 'divider',
|
||||||
}, {
|
}, {
|
||||||
text: i18n.ts.attachCancel,
|
text: i18n.ts.attachCancel,
|
||||||
@@ -163,7 +173,9 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
|||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => { detachAndDeleteMedia(file); },
|
action: () => { detachAndDeleteMedia(file); },
|
||||||
}], ev.currentTarget ?? ev.target).then(() => menuShowing = false);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target).then(() => menuShowing = false);
|
||||||
menuShowing = true;
|
menuShowing = true;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -5,7 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="timctyfi" :class="{ disabled, easing }">
|
<div class="timctyfi" :class="{ disabled, easing }">
|
||||||
<div class="label"><slot name="label"></slot></div>
|
<div class="label">
|
||||||
|
<slot name="label"></slot>
|
||||||
|
</div>
|
||||||
<div v-adaptive-border class="body">
|
<div v-adaptive-border class="body">
|
||||||
<div ref="containerEl" class="container">
|
<div ref="containerEl" class="container">
|
||||||
<div class="track">
|
<div class="track">
|
||||||
@@ -14,15 +16,25 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<div v-if="steps && showTicks" class="ticks">
|
<div v-if="steps && showTicks" class="ticks">
|
||||||
<div v-for="i in (steps + 1)" class="tick" :style="{ left: (((i - 1) / steps) * 100) + '%' }"></div>
|
<div v-for="i in (steps + 1)" class="tick" :style="{ left: (((i - 1) / steps) * 100) + '%' }"></div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="thumbEl" v-tooltip="textConverter(finalValue)" class="thumb" :style="{ left: thumbPosition + 'px' }" @mousedown="onMousedown" @touchstart="onMousedown"></div>
|
<div
|
||||||
|
ref="thumbEl"
|
||||||
|
class="thumb"
|
||||||
|
:style="{ left: thumbPosition + 'px' }"
|
||||||
|
@mouseenter.passive="onMouseenter"
|
||||||
|
@mousedown="onMousedown"
|
||||||
|
@touchstart="onMousedown"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="caption"><slot name="caption"></slot></div>
|
<div class="caption">
|
||||||
|
<slot name="caption"></slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch, shallowRef } from 'vue';
|
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
|
||||||
|
import { isTouchUsing } from '@/scripts/touch.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
@@ -101,12 +113,36 @@ const steps = computed(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tooltipForDragShowing = ref(false);
|
||||||
|
const tooltipForHoverShowing = ref(false);
|
||||||
|
|
||||||
|
function onMouseenter() {
|
||||||
|
if (isTouchUsing) return;
|
||||||
|
|
||||||
|
tooltipForHoverShowing.value = true;
|
||||||
|
|
||||||
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
|
||||||
|
showing: computed(() => tooltipForHoverShowing.value && !tooltipForDragShowing.value),
|
||||||
|
text: computed(() => {
|
||||||
|
return props.textConverter(finalValue.value);
|
||||||
|
}),
|
||||||
|
targetElement: thumbEl,
|
||||||
|
}, {
|
||||||
|
closed: () => dispose(),
|
||||||
|
});
|
||||||
|
|
||||||
|
thumbEl.value!.addEventListener('mouseleave', () => {
|
||||||
|
tooltipForHoverShowing.value = false;
|
||||||
|
}, { once: true, passive: true });
|
||||||
|
}
|
||||||
|
|
||||||
function onMousedown(ev: MouseEvent | TouchEvent) {
|
function onMousedown(ev: MouseEvent | TouchEvent) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
||||||
const tooltipShowing = ref(true);
|
tooltipForDragShowing.value = true;
|
||||||
|
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), {
|
||||||
showing: tooltipShowing,
|
showing: tooltipForDragShowing,
|
||||||
text: computed(() => {
|
text: computed(() => {
|
||||||
return props.textConverter(finalValue.value);
|
return props.textConverter(finalValue.value);
|
||||||
}),
|
}),
|
||||||
@@ -137,7 +173,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
|
|||||||
|
|
||||||
const onMouseup = () => {
|
const onMouseup = () => {
|
||||||
document.head.removeChild(style);
|
document.head.removeChild(style);
|
||||||
tooltipShowing.value = false;
|
tooltipForDragShowing.value = false;
|
||||||
window.removeEventListener('mousemove', onDrag);
|
window.removeEventListener('mousemove', onDrag);
|
||||||
window.removeEventListener('touchmove', onDrag);
|
window.removeEventListener('touchmove', onDrag);
|
||||||
window.removeEventListener('mouseup', onMouseup);
|
window.removeEventListener('mouseup', onMouseup);
|
||||||
|
@@ -46,7 +46,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { useInterval } from '@@/js/use-interval.js';
|
import { useInterval } from '@@/js/use-interval.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: string | null;
|
modelValue: string | null;
|
||||||
|
@@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
import { onBeforeUnmount, onMounted, provide, shallowRef, ref } from 'vue';
|
import { onBeforeUnmount, onMounted, provide, shallowRef, ref } from 'vue';
|
||||||
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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ 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 MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string;
|
name: string;
|
||||||
@@ -85,7 +86,9 @@ const errored = ref(url.value == null);
|
|||||||
|
|
||||||
function onClick(ev: MouseEvent) {
|
function onClick(ev: MouseEvent) {
|
||||||
if (props.menu) {
|
if (props.menu) {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'label',
|
type: 'label',
|
||||||
text: `:${props.name}:`,
|
text: `:${props.name}:`,
|
||||||
}, {
|
}, {
|
||||||
@@ -95,14 +98,20 @@ function onClick(ev: MouseEvent) {
|
|||||||
copyToClipboard(`:${props.name}:`);
|
copyToClipboard(`:${props.name}:`);
|
||||||
os.success();
|
os.success();
|
||||||
},
|
},
|
||||||
}, ...(props.menuReaction && react ? [{
|
});
|
||||||
|
|
||||||
|
if (props.menuReaction && react) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.doReaction,
|
text: i18n.ts.doReaction,
|
||||||
icon: 'ti ti-plus',
|
icon: 'ti ti-plus',
|
||||||
action: () => {
|
action: () => {
|
||||||
react(`:${props.name}:`);
|
react(`:${props.name}:`);
|
||||||
sound.playMisskeySfx('reaction');
|
sound.playMisskeySfx('reaction');
|
||||||
},
|
},
|
||||||
}] : []), {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.info,
|
text: i18n.ts.info,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
action: async () => {
|
action: async () => {
|
||||||
@@ -114,7 +123,9 @@ function onClick(ev: MouseEvent) {
|
|||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}], ev.currentTarget ?? ev.target);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -17,6 +17,7 @@ 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';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
emoji: string;
|
emoji: string;
|
||||||
@@ -39,7 +40,9 @@ function computeTitle(event: PointerEvent): void {
|
|||||||
|
|
||||||
function onClick(ev: MouseEvent) {
|
function onClick(ev: MouseEvent) {
|
||||||
if (props.menu) {
|
if (props.menu) {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'label',
|
type: 'label',
|
||||||
text: props.emoji,
|
text: props.emoji,
|
||||||
}, {
|
}, {
|
||||||
@@ -49,14 +52,20 @@ function onClick(ev: MouseEvent) {
|
|||||||
copyToClipboard(props.emoji);
|
copyToClipboard(props.emoji);
|
||||||
os.success();
|
os.success();
|
||||||
},
|
},
|
||||||
}, ...(props.menuReaction && react ? [{
|
});
|
||||||
|
|
||||||
|
if (props.menuReaction && react) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.doReaction,
|
text: i18n.ts.doReaction,
|
||||||
icon: 'ti ti-plus',
|
icon: 'ti ti-plus',
|
||||||
action: () => {
|
action: () => {
|
||||||
react(props.emoji);
|
react(props.emoji);
|
||||||
sound.playMisskeySfx('reaction');
|
sound.playMisskeySfx('reaction');
|
||||||
},
|
},
|
||||||
}] : [])], ev.currentTarget ?? ev.target);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -125,7 +125,7 @@ export const navbarItemDef = reactive({
|
|||||||
ui: {
|
ui: {
|
||||||
title: i18n.ts.switchUi,
|
title: i18n.ts.switchUi,
|
||||||
icon: 'ti ti-devices',
|
icon: 'ti ti-devices',
|
||||||
action: (ev) => {
|
action: (ev: MouseEvent) => {
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
text: i18n.ts.default,
|
text: i18n.ts.default,
|
||||||
active: ui === 'default' || ui === null,
|
active: ui === 'default' || ui === null,
|
||||||
|
@@ -22,7 +22,7 @@ import MkPasswordDialog from '@/components/MkPasswordDialog.vue';
|
|||||||
import MkEmojiPickerDialog from '@/components/MkEmojiPickerDialog.vue';
|
import MkEmojiPickerDialog from '@/components/MkEmojiPickerDialog.vue';
|
||||||
import MkPopupMenu from '@/components/MkPopupMenu.vue';
|
import MkPopupMenu from '@/components/MkPopupMenu.vue';
|
||||||
import MkContextMenu from '@/components/MkContextMenu.vue';
|
import MkContextMenu from '@/components/MkContextMenu.vue';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
|
||||||
|
@@ -45,6 +45,7 @@ import { clipsCache } from '@/cache.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 { genEmbedCode } from '@/scripts/get-embed-code.js';
|
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
clipId: string,
|
clipId: string,
|
||||||
@@ -131,7 +132,9 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{
|
|||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
handler: (ev: MouseEvent): void => {
|
handler: (ev: MouseEvent): void => {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-link',
|
icon: 'ti ti-link',
|
||||||
text: i18n.ts.copyUrl,
|
text: i18n.ts.copyUrl,
|
||||||
action: () => {
|
action: () => {
|
||||||
@@ -144,7 +147,10 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{
|
|||||||
action: () => {
|
action: () => {
|
||||||
genEmbedCode('clips', clip.value!.id);
|
genEmbedCode('clips', clip.value!.id);
|
||||||
},
|
},
|
||||||
}, ...(isSupportShare() ? [{
|
});
|
||||||
|
|
||||||
|
if (isSupportShare()) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
action: async () => {
|
action: async () => {
|
||||||
@@ -154,7 +160,10 @@ const headerActions = computed(() => clip.value && isOwned.value ? [{
|
|||||||
url: `${url}/clips/${clip.value!.id}`,
|
url: `${url}/clips/${clip.value!.id}`,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}] : [])], ev.currentTarget ?? ev.target);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
},
|
},
|
||||||
}] : []), {
|
}] : []), {
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
|
@@ -80,7 +80,7 @@ import { defaultStore } from '@/store.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 { MenuItem } from '@/types/menu';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -104,18 +104,23 @@ function fetchFlash() {
|
|||||||
function share(ev: MouseEvent) {
|
function share(ev: MouseEvent) {
|
||||||
if (!flash.value) return;
|
if (!flash.value) return;
|
||||||
|
|
||||||
os.popupMenu([
|
const menuItems: MenuItem[] = [];
|
||||||
{
|
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.shareWithNote,
|
text: i18n.ts.shareWithNote,
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
action: shareWithNote,
|
action: shareWithNote,
|
||||||
},
|
});
|
||||||
...(isSupportShare() ? [{
|
|
||||||
|
if (isSupportShare()) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
action: shareWithNavigator,
|
action: shareWithNavigator,
|
||||||
}] : []),
|
});
|
||||||
], ev.currentTarget ?? ev.target);
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
|
@@ -80,7 +80,7 @@ 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 { MenuItem } from '@/types/menu';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -171,18 +171,19 @@ function reportAbuse() {
|
|||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
if (!post.value) return;
|
if (!post.value) return;
|
||||||
|
|
||||||
const menu: MenuItem[] = [
|
const menuItems: MenuItem[] = [];
|
||||||
...($i && $i.id !== post.value.userId ? [
|
|
||||||
{
|
if ($i && $i.id !== post.value.userId) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-exclamation-circle',
|
icon: 'ti ti-exclamation-circle',
|
||||||
text: i18n.ts.reportAbuse,
|
text: i18n.ts.reportAbuse,
|
||||||
action: reportAbuse,
|
action: reportAbuse,
|
||||||
},
|
});
|
||||||
...($i.isModerator || $i.isAdmin ? [
|
|
||||||
{
|
if ($i.isModerator || $i.isAdmin) {
|
||||||
type: 'divider' as const,
|
menuItems.push({
|
||||||
},
|
type: 'divider',
|
||||||
{
|
}, {
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
text: i18n.ts.delete,
|
text: i18n.ts.delete,
|
||||||
danger: true,
|
danger: true,
|
||||||
@@ -194,12 +195,11 @@ function showMenu(ev: MouseEvent) {
|
|||||||
|
|
||||||
os.apiWithDialog('gallery/posts/delete', { postId: post.value.id });
|
os.apiWithDialog('gallery/posts/delete', { postId: post.value.id });
|
||||||
}),
|
}),
|
||||||
},
|
});
|
||||||
] : []),
|
}
|
||||||
] : []),
|
}
|
||||||
];
|
|
||||||
|
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.postId, fetchPost, { immediate: true });
|
watch(() => props.postId, fetchPost, { immediate: true });
|
||||||
|
@@ -134,12 +134,14 @@ async function removeUser(item, ev) {
|
|||||||
|
|
||||||
async function showMembershipMenu(item, ev) {
|
async function showMembershipMenu(item, ev) {
|
||||||
const withRepliesRef = ref(item.withReplies);
|
const withRepliesRef = ref(item.withReplies);
|
||||||
|
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRepliesToOthersInTimeline,
|
text: i18n.ts.showRepliesToOthersInTimeline,
|
||||||
icon: 'ti ti-messages',
|
icon: 'ti ti-messages',
|
||||||
ref: withRepliesRef,
|
ref: withRepliesRef,
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], ev.currentTarget ?? ev.target);
|
||||||
|
|
||||||
watch(withRepliesRef, withReplies => {
|
watch(withRepliesRef, withReplies => {
|
||||||
misskeyApi('users/lists/update-membership', {
|
misskeyApi('users/lists/update-membership', {
|
||||||
listId: list.value!.id,
|
listId: list.value!.id,
|
||||||
|
@@ -121,7 +121,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 { MenuItem } from '@/types/menu';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -165,18 +165,23 @@ function fetchPage() {
|
|||||||
function share(ev: MouseEvent) {
|
function share(ev: MouseEvent) {
|
||||||
if (!page.value) return;
|
if (!page.value) return;
|
||||||
|
|
||||||
os.popupMenu([
|
const menuItems: MenuItem[] = [];
|
||||||
{
|
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.shareWithNote,
|
text: i18n.ts.shareWithNote,
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
action: shareWithNote,
|
action: shareWithNote,
|
||||||
},
|
});
|
||||||
...(isSupportShare() ? [{
|
|
||||||
|
if (isSupportShare()) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
action: shareWithNavigator,
|
action: shareWithNavigator,
|
||||||
}] : []),
|
});
|
||||||
], ev.currentTarget ?? ev.target);
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
@@ -256,34 +261,43 @@ function reportAbuse() {
|
|||||||
function showMenu(ev: MouseEvent) {
|
function showMenu(ev: MouseEvent) {
|
||||||
if (!page.value) return;
|
if (!page.value) return;
|
||||||
|
|
||||||
const menu: MenuItem[] = [
|
const menuItems: MenuItem[] = [];
|
||||||
...($i && $i.id === page.value.userId ? [
|
|
||||||
{
|
if ($i && $i.id === page.value.userId) {
|
||||||
icon: 'ti ti-code',
|
menuItems.push({
|
||||||
text: i18n.ts._pages.viewSource,
|
icon: 'ti ti-pencil',
|
||||||
action: () => router.push(`/@${props.username}/pages/${props.pageName}/view-source`),
|
text: i18n.ts.editThisPage,
|
||||||
},
|
action: () => router.push(`/pages/edit/${page.value.id}`),
|
||||||
...($i.pinnedPageId === page.value.id ? [{
|
});
|
||||||
|
|
||||||
|
if ($i.pinnedPageId === page.value.id) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-pinned-off',
|
icon: 'ti ti-pinned-off',
|
||||||
text: i18n.ts.unpin,
|
text: i18n.ts.unpin,
|
||||||
action: () => pin(false),
|
action: () => pin(false),
|
||||||
}] : [{
|
});
|
||||||
|
} else {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-pin',
|
icon: 'ti ti-pin',
|
||||||
text: i18n.ts.pin,
|
text: i18n.ts.pin,
|
||||||
action: () => pin(true),
|
action: () => pin(true),
|
||||||
}]),
|
});
|
||||||
] : []),
|
}
|
||||||
...($i && $i.id !== page.value.userId ? [
|
} else if ($i && $i.id !== page.value.userId) {
|
||||||
{
|
menuItems.push({
|
||||||
|
icon: 'ti ti-code',
|
||||||
|
text: i18n.ts._pages.viewSource,
|
||||||
|
action: () => router.push(`/@${props.username}/pages/${props.pageName}/view-source`),
|
||||||
|
}, {
|
||||||
icon: 'ti ti-exclamation-circle',
|
icon: 'ti ti-exclamation-circle',
|
||||||
text: i18n.ts.reportAbuse,
|
text: i18n.ts.reportAbuse,
|
||||||
action: reportAbuse,
|
action: reportAbuse,
|
||||||
},
|
});
|
||||||
...($i.isModerator || $i.isAdmin ? [
|
|
||||||
{
|
if ($i.isModerator || $i.isAdmin) {
|
||||||
type: 'divider' as const,
|
menuItems.push({
|
||||||
},
|
type: 'divider',
|
||||||
{
|
}, {
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
text: i18n.ts.delete,
|
text: i18n.ts.delete,
|
||||||
danger: true,
|
danger: true,
|
||||||
@@ -295,12 +309,11 @@ function showMenu(ev: MouseEvent) {
|
|||||||
|
|
||||||
os.apiWithDialog('pages/delete', { pageId: page.value.id });
|
os.apiWithDialog('pages/delete', { pageId: page.value.id });
|
||||||
}),
|
}),
|
||||||
},
|
});
|
||||||
] : []),
|
}
|
||||||
] : []),
|
}
|
||||||
];
|
|
||||||
|
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => path.value, fetchPage, { immediate: true });
|
watch(() => path.value, fetchPage, { immediate: true });
|
||||||
|
@@ -121,7 +121,7 @@ import MkRadios from '@/components/MkRadios.vue';
|
|||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
|
|
||||||
const $i = signinRequired();
|
const $i = signinRequired();
|
||||||
|
@@ -50,7 +50,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
|||||||
import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
|
import { antennasCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { deepMerge } from '@/scripts/merge.js';
|
import { deepMerge } from '@/scripts/merge.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
||||||
import type { BasicTimelineType } from '@/timelines.js';
|
import type { BasicTimelineType } from '@/timelines.js';
|
||||||
@@ -189,7 +189,7 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
|
|||||||
}),
|
}),
|
||||||
(channels.length === 0 ? undefined : { type: 'divider' }),
|
(channels.length === 0 ? undefined : { type: 'divider' }),
|
||||||
{
|
{
|
||||||
type: 'link' as const,
|
type: 'link',
|
||||||
icon: 'ti ti-plus',
|
icon: 'ti ti-plus',
|
||||||
text: i18n.ts.createNew,
|
text: i18n.ts.createNew,
|
||||||
to: '/channels',
|
to: '/channels',
|
||||||
@@ -258,16 +258,24 @@ const headerActions = computed(() => {
|
|||||||
icon: 'ti ti-dots',
|
icon: 'ti ti-dots',
|
||||||
text: i18n.ts.options,
|
text: i18n.ts.options,
|
||||||
handler: (ev) => {
|
handler: (ev) => {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRenotes,
|
text: i18n.ts.showRenotes,
|
||||||
ref: withRenotes,
|
ref: withRenotes,
|
||||||
}, isBasicTimeline(src.value) && hasWithReplies(src.value) ? {
|
});
|
||||||
|
|
||||||
|
if (isBasicTimeline(src.value) && hasWithReplies(src.value)) {
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRepliesToOthersInTimeline,
|
text: i18n.ts.showRepliesToOthersInTimeline,
|
||||||
ref: withReplies,
|
ref: withReplies,
|
||||||
disabled: onlyFiles,
|
disabled: onlyFiles,
|
||||||
} : undefined, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.withSensitive,
|
text: i18n.ts.withSensitive,
|
||||||
ref: withSensitive,
|
ref: withSensitive,
|
||||||
@@ -276,7 +284,9 @@ const headerActions = computed(() => {
|
|||||||
text: i18n.ts.fileAttachedOnly,
|
text: i18n.ts.fileAttachedOnly,
|
||||||
ref: onlyFiles,
|
ref: onlyFiles,
|
||||||
disabled: isBasicTimeline(src.value) && hasWithReplies(src.value) ? withReplies : false,
|
disabled: isBasicTimeline(src.value) && hasWithReplies(src.value) ? withReplies : false,
|
||||||
}], ev.currentTarget ?? ev.target);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -9,7 +9,7 @@ import { i18n } from '@/i18n.js';
|
|||||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
function rename(file: Misskey.entities.DriveFile) {
|
function rename(file: Misskey.entities.DriveFile) {
|
||||||
@@ -87,8 +87,10 @@ async function deleteFile(file: Misskey.entities.DriveFile) {
|
|||||||
|
|
||||||
export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Misskey.entities.DriveFolder | null): MenuItem[] {
|
export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Misskey.entities.DriveFolder | null): MenuItem[] {
|
||||||
const isImage = file.type.startsWith('image/');
|
const isImage = file.type.startsWith('image/');
|
||||||
let menu;
|
|
||||||
menu = [{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
to: `/my/drive/file/${file.id}`,
|
to: `/my/drive/file/${file.id}`,
|
||||||
text: i18n.ts._fileViewer.title,
|
text: i18n.ts._fileViewer.title,
|
||||||
@@ -109,14 +111,20 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
|
|||||||
text: i18n.ts.describeFile,
|
text: i18n.ts.describeFile,
|
||||||
icon: 'ti ti-text-caption',
|
icon: 'ti ti-text-caption',
|
||||||
action: () => describe(file),
|
action: () => describe(file),
|
||||||
}, ...isImage ? [{
|
});
|
||||||
|
|
||||||
|
if (isImage) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts.cropImage,
|
text: i18n.ts.cropImage,
|
||||||
icon: 'ti ti-crop',
|
icon: 'ti ti-crop',
|
||||||
action: () => os.cropImage(file, {
|
action: () => os.cropImage(file, {
|
||||||
aspectRatio: NaN,
|
aspectRatio: NaN,
|
||||||
uploadFolder: folder ? folder.id : folder,
|
uploadFolder: folder ? folder.id : folder,
|
||||||
}),
|
}),
|
||||||
}] : [], { type: 'divider' }, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({ type: 'divider' }, {
|
||||||
text: i18n.ts.createNoteFromTheFile,
|
text: i18n.ts.createNoteFromTheFile,
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
action: () => os.post({
|
action: () => os.post({
|
||||||
@@ -138,17 +146,17 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
|
|||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => deleteFile(file),
|
action: () => deleteFile(file),
|
||||||
}];
|
});
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (defaultStore.state.devMode) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyFileId,
|
text: i18n.ts.copyFileId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(file.id);
|
copyToClipboard(file.id);
|
||||||
},
|
},
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
return menuItems;
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ import { defaultStore, noteActions } from '@/store.js';
|
|||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
||||||
import { clipsCache, favoritedChannelsCache } from '@/cache.js';
|
import { clipsCache, favoritedChannelsCache } from '@/cache.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
import { getAppearNote } from '@/scripts/get-appear-note.js';
|
||||||
@@ -99,11 +99,13 @@ export async function getNoteClipMenu(props: {
|
|||||||
const { canceled, result } = await os.form(i18n.ts.createNewClip, {
|
const { canceled, result } = await os.form(i18n.ts.createNewClip, {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
default: null,
|
||||||
label: i18n.ts.name,
|
label: i18n.ts.name,
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: false,
|
required: false,
|
||||||
|
default: null,
|
||||||
multiline: true,
|
multiline: true,
|
||||||
label: i18n.ts.description,
|
label: i18n.ts.description,
|
||||||
},
|
},
|
||||||
@@ -264,7 +266,7 @@ export function getNoteMenu(props: {
|
|||||||
title: i18n.ts.numberOfDays,
|
title: i18n.ts.numberOfDays,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (canceled) return;
|
if (canceled || days == null) return;
|
||||||
|
|
||||||
os.apiWithDialog('admin/promo/create', {
|
os.apiWithDialog('admin/promo/create', {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.id,
|
||||||
@@ -295,21 +297,23 @@ export function getNoteMenu(props: {
|
|||||||
props.translation.value = res;
|
props.translation.value = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
let menu: MenuItem[];
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
if ($i) {
|
if ($i) {
|
||||||
const statePromise = misskeyApi('notes/state', {
|
const statePromise = misskeyApi('notes/state', {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
menu = [
|
if (props.currentClip?.userId === $i.id) {
|
||||||
...(
|
menuItems.push({
|
||||||
props.currentClip?.userId === $i.id ? [{
|
|
||||||
icon: 'ti ti-backspace',
|
icon: 'ti ti-backspace',
|
||||||
text: i18n.ts.unclip,
|
text: i18n.ts.unclip,
|
||||||
danger: true,
|
danger: true,
|
||||||
action: unclip,
|
action: unclip,
|
||||||
}, { type: 'divider' }] : []
|
}, { type: 'divider' });
|
||||||
), {
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
text: i18n.ts.details,
|
text: i18n.ts.details,
|
||||||
action: openDetail,
|
action: openDetail,
|
||||||
@@ -317,26 +321,39 @@ export function getNoteMenu(props: {
|
|||||||
icon: 'ti ti-copy',
|
icon: 'ti ti-copy',
|
||||||
text: i18n.ts.copyContent,
|
text: i18n.ts.copyContent,
|
||||||
action: copyContent,
|
action: copyContent,
|
||||||
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink)
|
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink));
|
||||||
, (appearNote.url || appearNote.uri) ? {
|
|
||||||
|
if (appearNote.url || appearNote.uri) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-external-link',
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
||||||
},
|
},
|
||||||
} : getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode),
|
});
|
||||||
...(isSupportShare() ? [{
|
} else {
|
||||||
|
menuItems.push(getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSupportShare()) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
text: i18n.ts.share,
|
text: i18n.ts.share,
|
||||||
action: share,
|
action: share,
|
||||||
}] : []),
|
});
|
||||||
$i && $i.policies.canUseTranslator && instance.translatorAvailable ? {
|
}
|
||||||
|
|
||||||
|
if ($i.policies.canUseTranslator && instance.translatorAvailable) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-language-hiragana',
|
icon: 'ti ti-language-hiragana',
|
||||||
text: i18n.ts.translate,
|
text: i18n.ts.translate,
|
||||||
action: translate,
|
action: translate,
|
||||||
} : undefined,
|
});
|
||||||
{ type: 'divider' },
|
}
|
||||||
statePromise.then(state => state.isFavorited ? {
|
|
||||||
|
menuItems.push({ type: 'divider' });
|
||||||
|
|
||||||
|
menuItems.push(statePromise.then(state => state.isFavorited ? {
|
||||||
icon: 'ti ti-star-off',
|
icon: 'ti ti-star-off',
|
||||||
text: i18n.ts.unfavorite,
|
text: i18n.ts.unfavorite,
|
||||||
action: () => toggleFavorite(false),
|
action: () => toggleFavorite(false),
|
||||||
@@ -344,14 +361,16 @@ export function getNoteMenu(props: {
|
|||||||
icon: 'ti ti-star',
|
icon: 'ti ti-star',
|
||||||
text: i18n.ts.favorite,
|
text: i18n.ts.favorite,
|
||||||
action: () => toggleFavorite(true),
|
action: () => toggleFavorite(true),
|
||||||
}),
|
}));
|
||||||
{
|
|
||||||
type: 'parent' as const,
|
menuItems.push({
|
||||||
|
type: 'parent',
|
||||||
icon: 'ti ti-paperclip',
|
icon: 'ti ti-paperclip',
|
||||||
text: i18n.ts.clip,
|
text: i18n.ts.clip,
|
||||||
children: () => getNoteClipMenu(props),
|
children: () => getNoteClipMenu(props),
|
||||||
},
|
});
|
||||||
statePromise.then(state => state.isMutedThread ? {
|
|
||||||
|
menuItems.push(statePromise.then(state => state.isMutedThread ? {
|
||||||
icon: 'ti ti-message-off',
|
icon: 'ti ti-message-off',
|
||||||
text: i18n.ts.unmuteThread,
|
text: i18n.ts.unmuteThread,
|
||||||
action: () => toggleThreadMute(false),
|
action: () => toggleThreadMute(false),
|
||||||
@@ -359,18 +378,26 @@ export function getNoteMenu(props: {
|
|||||||
icon: 'ti ti-message-off',
|
icon: 'ti ti-message-off',
|
||||||
text: i18n.ts.muteThread,
|
text: i18n.ts.muteThread,
|
||||||
action: () => toggleThreadMute(true),
|
action: () => toggleThreadMute(true),
|
||||||
}),
|
}));
|
||||||
appearNote.userId === $i.id ? ($i.pinnedNoteIds ?? []).includes(appearNote.id) ? {
|
|
||||||
|
if (appearNote.userId === $i.id) {
|
||||||
|
if (($i.pinnedNoteIds ?? []).includes(appearNote.id)) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-pinned-off',
|
icon: 'ti ti-pinned-off',
|
||||||
text: i18n.ts.unpin,
|
text: i18n.ts.unpin,
|
||||||
action: () => togglePin(false),
|
action: () => togglePin(false),
|
||||||
} : {
|
});
|
||||||
|
} else {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-pin',
|
icon: 'ti ti-pin',
|
||||||
text: i18n.ts.pin,
|
text: i18n.ts.pin,
|
||||||
action: () => togglePin(true),
|
action: () => togglePin(true),
|
||||||
} : undefined,
|
});
|
||||||
{
|
}
|
||||||
type: 'parent' as const,
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
|
type: 'parent',
|
||||||
icon: 'ti ti-user',
|
icon: 'ti ti-user',
|
||||||
text: i18n.ts.user,
|
text: i18n.ts.user,
|
||||||
children: async () => {
|
children: async () => {
|
||||||
@@ -379,27 +406,17 @@ export function getNoteMenu(props: {
|
|||||||
cleanups.push(cleanup);
|
cleanups.push(cleanup);
|
||||||
return menu;
|
return menu;
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
/*
|
|
||||||
...($i.isModerator || $i.isAdmin ? [
|
if (appearNote.userId !== $i.id) {
|
||||||
{ type: 'divider' },
|
menuItems.push({ type: 'divider' });
|
||||||
{
|
menuItems.push(getAbuseNoteMenu(appearNote, i18n.ts.reportAbuse));
|
||||||
icon: 'ti ti-speakerphone',
|
}
|
||||||
text: i18n.ts.promote,
|
|
||||||
action: promote
|
if (appearNote.channel && (appearNote.channel.userId === $i.id || $i.isModerator || $i.isAdmin)) {
|
||||||
}]
|
menuItems.push({ type: 'divider' });
|
||||||
: []
|
menuItems.push({
|
||||||
),*/
|
type: 'parent',
|
||||||
...(appearNote.userId !== $i.id ? [
|
|
||||||
{ type: 'divider' },
|
|
||||||
appearNote.userId !== $i.id ? getAbuseNoteMenu(appearNote, i18n.ts.reportAbuse) : undefined,
|
|
||||||
]
|
|
||||||
: []
|
|
||||||
),
|
|
||||||
...(appearNote.channel && (appearNote.channel.userId === $i.id || $i.isModerator || $i.isAdmin) ? [
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
type: 'parent' as const,
|
|
||||||
icon: 'ti ti-device-tv',
|
icon: 'ti ti-device-tv',
|
||||||
text: i18n.ts.channel,
|
text: i18n.ts.channel,
|
||||||
children: async () => {
|
children: async () => {
|
||||||
@@ -428,28 +445,27 @@ export function getNoteMenu(props: {
|
|||||||
}
|
}
|
||||||
return channelChildMenu;
|
return channelChildMenu;
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
]
|
}
|
||||||
: []
|
|
||||||
),
|
if (appearNote.userId === $i.id || $i.isModerator || $i.isAdmin) {
|
||||||
...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [
|
menuItems.push({ type: 'divider' });
|
||||||
{ type: 'divider' },
|
if (appearNote.userId === $i.id) {
|
||||||
appearNote.userId === $i.id ? {
|
menuItems.push({
|
||||||
icon: 'ti ti-edit',
|
icon: 'ti ti-edit',
|
||||||
text: i18n.ts.deleteAndEdit,
|
text: i18n.ts.deleteAndEdit,
|
||||||
action: delEdit,
|
action: delEdit,
|
||||||
} : undefined,
|
});
|
||||||
{
|
}
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
text: i18n.ts.delete,
|
text: i18n.ts.delete,
|
||||||
danger: true,
|
danger: true,
|
||||||
action: del,
|
action: del,
|
||||||
}]
|
});
|
||||||
: []
|
}
|
||||||
)]
|
|
||||||
.filter(x => x !== undefined);
|
|
||||||
} else {
|
} else {
|
||||||
menu = [{
|
menuItems.push({
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
text: i18n.ts.details,
|
text: i18n.ts.details,
|
||||||
action: openDetail,
|
action: openDetail,
|
||||||
@@ -457,35 +473,42 @@ export function getNoteMenu(props: {
|
|||||||
icon: 'ti ti-copy',
|
icon: 'ti ti-copy',
|
||||||
text: i18n.ts.copyContent,
|
text: i18n.ts.copyContent,
|
||||||
action: copyContent,
|
action: copyContent,
|
||||||
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink),
|
}, getCopyNoteLinkMenu(appearNote, i18n.ts.copyLink));
|
||||||
(appearNote.url || appearNote.uri) ? {
|
|
||||||
|
if (appearNote.url || appearNote.uri) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-external-link',
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
action: () => {
|
action: () => {
|
||||||
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
|
||||||
},
|
},
|
||||||
} : getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode)]
|
});
|
||||||
.filter(x => x !== undefined);
|
} else {
|
||||||
|
menuItems.push(getNoteEmbedCodeMenu(appearNote, i18n.ts.genEmbedCode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noteActions.length > 0) {
|
if (noteActions.length > 0) {
|
||||||
menu = menu.concat([{ type: 'divider' }, ...noteActions.map(action => ({
|
menuItems.push({ type: 'divider' });
|
||||||
|
|
||||||
|
menuItems.push(...noteActions.map(action => ({
|
||||||
icon: 'ti ti-plug',
|
icon: 'ti ti-plug',
|
||||||
text: action.title,
|
text: action.title,
|
||||||
action: () => {
|
action: () => {
|
||||||
action.handler(appearNote);
|
action.handler(appearNote);
|
||||||
},
|
},
|
||||||
}))]);
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (defaultStore.state.devMode) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyNoteId,
|
text: i18n.ts.copyNoteId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(appearNote.id);
|
copyToClipboard(appearNote.id);
|
||||||
|
os.success();
|
||||||
},
|
},
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
@@ -496,7 +519,7 @@ export function getNoteMenu(props: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
menu,
|
menu: menuItems,
|
||||||
cleanup,
|
cleanup,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ import { IRouter } from '@/nirax.js';
|
|||||||
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
|
export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
|
||||||
const meId = $i ? $i.id : null;
|
const meId = $i ? $i.id : null;
|
||||||
@@ -148,56 +148,78 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let menu: MenuItem[] = [{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-at',
|
icon: 'ti ti-at',
|
||||||
text: i18n.ts.copyUsername,
|
text: i18n.ts.copyUsername,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(`@${user.username}@${user.host ?? host}`);
|
copyToClipboard(`@${user.username}@${user.host ?? host}`);
|
||||||
},
|
},
|
||||||
}, ...( notesSearchAvailable && (user.host == null || canSearchNonLocalNotes) ? [{
|
});
|
||||||
|
|
||||||
|
if (notesSearchAvailable && (user.host == null || canSearchNonLocalNotes)) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
text: i18n.ts.searchThisUsersNotes,
|
text: i18n.ts.searchThisUsersNotes,
|
||||||
action: () => {
|
action: () => {
|
||||||
router.push(`/search?username=${encodeURIComponent(user.username)}${user.host != null ? '&host=' + encodeURIComponent(user.host) : ''}`);
|
router.push(`/search?username=${encodeURIComponent(user.username)}${user.host != null ? '&host=' + encodeURIComponent(user.host) : ''}`);
|
||||||
},
|
},
|
||||||
}] : [])
|
});
|
||||||
, ...(iAmModerator ? [{
|
}
|
||||||
|
|
||||||
|
if (iAmModerator) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-user-exclamation',
|
icon: 'ti ti-user-exclamation',
|
||||||
text: i18n.ts.moderation,
|
text: i18n.ts.moderation,
|
||||||
action: () => {
|
action: () => {
|
||||||
router.push(`/admin/user/${user.id}`);
|
router.push(`/admin/user/${user.id}`);
|
||||||
},
|
},
|
||||||
}] : []), {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-rss',
|
icon: 'ti ti-rss',
|
||||||
text: i18n.ts.copyRSS,
|
text: i18n.ts.copyRSS,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(`${user.host ?? host}/@${user.username}.atom`);
|
copyToClipboard(`${user.host ?? host}/@${user.username}.atom`);
|
||||||
},
|
},
|
||||||
}, ...(user.host != null && user.url != null ? [{
|
});
|
||||||
|
|
||||||
|
if (user.host != null && user.url != null) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-external-link',
|
icon: 'ti ti-external-link',
|
||||||
text: i18n.ts.showOnRemote,
|
text: i18n.ts.showOnRemote,
|
||||||
action: () => {
|
action: () => {
|
||||||
if (user.url == null) return;
|
if (user.url == null) return;
|
||||||
window.open(user.url, '_blank', 'noopener');
|
window.open(user.url, '_blank', 'noopener');
|
||||||
},
|
},
|
||||||
}] : [{
|
});
|
||||||
|
} else {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-code',
|
icon: 'ti ti-code',
|
||||||
text: i18n.ts.genEmbedCode,
|
text: i18n.ts.genEmbedCode,
|
||||||
type: 'parent' as const,
|
type: 'parent',
|
||||||
children: [{
|
children: [{
|
||||||
text: i18n.ts.noteOfThisUser,
|
text: i18n.ts.noteOfThisUser,
|
||||||
action: () => {
|
action: () => {
|
||||||
genEmbedCode('user-timeline', user.id);
|
genEmbedCode('user-timeline', user.id);
|
||||||
},
|
},
|
||||||
}], // TODO: ユーザーカードの埋め込みなど
|
}], // TODO: ユーザーカードの埋め込みなど
|
||||||
}]), {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-share',
|
icon: 'ti ti-share',
|
||||||
text: i18n.ts.copyProfileUrl,
|
text: i18n.ts.copyProfileUrl,
|
||||||
action: () => {
|
action: () => {
|
||||||
const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`;
|
const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`;
|
||||||
copyToClipboard(`${url}/${canonical}`);
|
copyToClipboard(`${url}/${canonical}`);
|
||||||
},
|
},
|
||||||
}, ...($i ? [{
|
});
|
||||||
|
|
||||||
|
if ($i) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-mail',
|
icon: 'ti ti-mail',
|
||||||
text: i18n.ts.sendMessage,
|
text: i18n.ts.sendMessage,
|
||||||
action: () => {
|
action: () => {
|
||||||
@@ -207,9 +229,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
}, { type: 'divider' }, {
|
}, { type: 'divider' }, {
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.editMemo,
|
text: i18n.ts.editMemo,
|
||||||
action: () => {
|
action: editMemo,
|
||||||
editMemo();
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
type: 'parent',
|
type: 'parent',
|
||||||
icon: 'ti ti-list',
|
icon: 'ti ti-list',
|
||||||
@@ -217,21 +237,21 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
children: async () => {
|
children: async () => {
|
||||||
const lists = await userListsCache.fetch();
|
const lists = await userListsCache.fetch();
|
||||||
return lists.map(list => {
|
return lists.map(list => {
|
||||||
const isListed = ref(list.userIds.includes(user.id));
|
const isListed = ref(list.userIds?.includes(user.id) ?? false);
|
||||||
cleanups.push(watch(isListed, () => {
|
cleanups.push(watch(isListed, () => {
|
||||||
if (isListed.value) {
|
if (isListed.value) {
|
||||||
os.apiWithDialog('users/lists/push', {
|
os.apiWithDialog('users/lists/push', {
|
||||||
listId: list.id,
|
listId: list.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
list.userIds.push(user.id);
|
list.userIds?.push(user.id);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
os.apiWithDialog('users/lists/pull', {
|
os.apiWithDialog('users/lists/pull', {
|
||||||
listId: list.id,
|
listId: list.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
list.userIds.splice(list.userIds.indexOf(user.id), 1);
|
list.userIds?.splice(list.userIds?.indexOf(user.id), 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -270,11 +290,12 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
}] : [])] as any;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if ($i && meId !== user.id) {
|
if ($i && meId !== user.id) {
|
||||||
if (iAmModerator) {
|
if (iAmModerator) {
|
||||||
menu = menu.concat([{
|
menuItems.push({
|
||||||
type: 'parent',
|
type: 'parent',
|
||||||
icon: 'ti ti-badges',
|
icon: 'ti ti-badges',
|
||||||
text: i18n.ts.roles,
|
text: i18n.ts.roles,
|
||||||
@@ -312,13 +333,14 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// フォローしたとしても user.isFollowing はリアルタイム更新されないので不便なため
|
// フォローしたとしても user.isFollowing はリアルタイム更新されないので不便なため
|
||||||
//if (user.isFollowing) {
|
//if (user.isFollowing) {
|
||||||
const withRepliesRef = ref(user.withReplies);
|
const withRepliesRef = ref(user.withReplies ?? false);
|
||||||
menu = menu.concat([{
|
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
icon: 'ti ti-messages',
|
icon: 'ti ti-messages',
|
||||||
text: i18n.ts.showRepliesToOthersInTimeline,
|
text: i18n.ts.showRepliesToOthersInTimeline,
|
||||||
@@ -327,7 +349,8 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
icon: user.notify === 'none' ? 'ti ti-bell' : 'ti ti-bell-off',
|
icon: user.notify === 'none' ? 'ti ti-bell' : 'ti ti-bell-off',
|
||||||
text: user.notify === 'none' ? i18n.ts.notifyNotes : i18n.ts.unnotifyNotes,
|
text: user.notify === 'none' ? i18n.ts.notifyNotes : i18n.ts.unnotifyNotes,
|
||||||
action: toggleNotify,
|
action: toggleNotify,
|
||||||
}]);
|
});
|
||||||
|
|
||||||
watch(withRepliesRef, (withReplies) => {
|
watch(withRepliesRef, (withReplies) => {
|
||||||
misskeyApi('following/update', {
|
misskeyApi('following/update', {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@@ -338,7 +361,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
});
|
});
|
||||||
//}
|
//}
|
||||||
|
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: user.isMuted ? 'ti ti-eye' : 'ti ti-eye-off',
|
icon: user.isMuted ? 'ti ti-eye' : 'ti ti-eye-off',
|
||||||
text: user.isMuted ? i18n.ts.unmute : i18n.ts.mute,
|
text: user.isMuted ? i18n.ts.unmute : i18n.ts.mute,
|
||||||
action: toggleMute,
|
action: toggleMute,
|
||||||
@@ -350,70 +373,68 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
|
|||||||
icon: 'ti ti-ban',
|
icon: 'ti ti-ban',
|
||||||
text: user.isBlocking ? i18n.ts.unblock : i18n.ts.block,
|
text: user.isBlocking ? i18n.ts.unblock : i18n.ts.block,
|
||||||
action: toggleBlock,
|
action: toggleBlock,
|
||||||
}]);
|
});
|
||||||
|
|
||||||
if (user.isFollowed) {
|
if (user.isFollowed) {
|
||||||
menu = menu.concat([{
|
menuItems.push({
|
||||||
icon: 'ti ti-link-off',
|
icon: 'ti ti-link-off',
|
||||||
text: i18n.ts.breakFollow,
|
text: i18n.ts.breakFollow,
|
||||||
action: invalidateFollow,
|
action: invalidateFollow,
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-exclamation-circle',
|
icon: 'ti ti-exclamation-circle',
|
||||||
text: i18n.ts.reportAbuse,
|
text: i18n.ts.reportAbuse,
|
||||||
action: reportAbuse,
|
action: reportAbuse,
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.host !== null) {
|
if (user.host !== null) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-refresh',
|
icon: 'ti ti-refresh',
|
||||||
text: i18n.ts.updateRemoteUser,
|
text: i18n.ts.updateRemoteUser,
|
||||||
action: userInfoUpdate,
|
action: userInfoUpdate,
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultStore.state.devMode) {
|
if (defaultStore.state.devMode) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-id',
|
icon: 'ti ti-id',
|
||||||
text: i18n.ts.copyUserId,
|
text: i18n.ts.copyUserId,
|
||||||
action: () => {
|
action: () => {
|
||||||
copyToClipboard(user.id);
|
copyToClipboard(user.id);
|
||||||
},
|
},
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($i && meId === user.id) {
|
if ($i && meId === user.id) {
|
||||||
menu = menu.concat([{ type: 'divider' }, {
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.editProfile,
|
text: i18n.ts.editProfile,
|
||||||
action: () => {
|
action: () => {
|
||||||
router.push('/settings/profile');
|
router.push('/settings/profile');
|
||||||
},
|
},
|
||||||
}]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userActions.length > 0) {
|
if (userActions.length > 0) {
|
||||||
menu = menu.concat([{ type: 'divider' }, ...userActions.map(action => ({
|
menuItems.push({ type: 'divider' }, ...userActions.map(action => ({
|
||||||
icon: 'ti ti-plug',
|
icon: 'ti ti-plug',
|
||||||
text: action.title,
|
text: action.title,
|
||||||
action: () => {
|
action: () => {
|
||||||
action.handler(user);
|
action.handler(user);
|
||||||
},
|
},
|
||||||
}))]);
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanup = () => {
|
return {
|
||||||
|
menu: menuItems,
|
||||||
|
cleanup: () => {
|
||||||
if (_DEV_) console.log('user menu cleanup', cleanups);
|
if (_DEV_) console.log('user menu cleanup', cleanups);
|
||||||
for (const cl of cleanups) {
|
for (const cl of cleanups) {
|
||||||
cl();
|
cl();
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
|
||||||
return {
|
|
||||||
menu,
|
|
||||||
cleanup,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,9 @@ function toolsMenuItems(): MenuItem[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function openInstanceMenu(ev: MouseEvent) {
|
export function openInstanceMenu(ev: MouseEvent) {
|
||||||
os.popupMenu([{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
text: instance.name ?? host,
|
text: instance.name ?? host,
|
||||||
type: 'label',
|
type: 'label',
|
||||||
}, {
|
}, {
|
||||||
@@ -69,12 +71,18 @@ export function openInstanceMenu(ev: MouseEvent) {
|
|||||||
text: i18n.ts.ads,
|
text: i18n.ts.ads,
|
||||||
icon: 'ti ti-ad',
|
icon: 'ti ti-ad',
|
||||||
to: '/ads',
|
to: '/ads',
|
||||||
}, ($i && ($i.isAdmin || $i.policies.canInvite) && instance.disableRegistration) ? {
|
});
|
||||||
|
|
||||||
|
if ($i && ($i.isAdmin || $i.policies.canInvite) && instance.disableRegistration) {
|
||||||
|
menuItems.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
to: '/invite',
|
to: '/invite',
|
||||||
text: i18n.ts.invite,
|
text: i18n.ts.invite,
|
||||||
icon: 'ti ti-user-plus',
|
icon: 'ti ti-user-plus',
|
||||||
} : undefined, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'parent',
|
type: 'parent',
|
||||||
text: i18n.ts.tools,
|
text: i18n.ts.tools,
|
||||||
icon: 'ti ti-tool',
|
icon: 'ti ti-tool',
|
||||||
@@ -84,31 +92,52 @@ export function openInstanceMenu(ev: MouseEvent) {
|
|||||||
text: i18n.ts.inquiry,
|
text: i18n.ts.inquiry,
|
||||||
icon: 'ti ti-help-circle',
|
icon: 'ti ti-help-circle',
|
||||||
to: '/contact',
|
to: '/contact',
|
||||||
}, (instance.impressumUrl) ? {
|
});
|
||||||
|
|
||||||
|
if (instance.impressumUrl) {
|
||||||
|
menuItems.push({
|
||||||
type: 'a',
|
type: 'a',
|
||||||
text: i18n.ts.impressum,
|
text: i18n.ts.impressum,
|
||||||
icon: 'ti ti-file-invoice',
|
icon: 'ti ti-file-invoice',
|
||||||
href: instance.impressumUrl,
|
href: instance.impressumUrl,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
} : undefined, (instance.tosUrl) ? {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance.tosUrl) {
|
||||||
|
menuItems.push({
|
||||||
type: 'a',
|
type: 'a',
|
||||||
text: i18n.ts.termsOfService,
|
text: i18n.ts.termsOfService,
|
||||||
icon: 'ti ti-notebook',
|
icon: 'ti ti-notebook',
|
||||||
href: instance.tosUrl,
|
href: instance.tosUrl,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
} : undefined, (instance.privacyPolicyUrl) ? {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance.privacyPolicyUrl) {
|
||||||
|
menuItems.push({
|
||||||
type: 'a',
|
type: 'a',
|
||||||
text: i18n.ts.privacyPolicy,
|
text: i18n.ts.privacyPolicy,
|
||||||
icon: 'ti ti-shield-lock',
|
icon: 'ti ti-shield-lock',
|
||||||
href: instance.privacyPolicyUrl,
|
href: instance.privacyPolicyUrl,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) {
|
||||||
|
menuItems.push({ type: 'divider' });
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'a',
|
type: 'a',
|
||||||
text: i18n.ts.document,
|
text: i18n.ts.document,
|
||||||
icon: 'ti ti-bulb',
|
icon: 'ti ti-bulb',
|
||||||
href: 'https://misskey-hub.net/docs/for-users/',
|
href: 'https://misskey-hub.net/docs/for-users/',
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
}, ($i) ? {
|
});
|
||||||
|
|
||||||
|
if ($i) {
|
||||||
|
menuItems.push({
|
||||||
text: i18n.ts._initialTutorial.launchTutorial,
|
text: i18n.ts._initialTutorial.launchTutorial,
|
||||||
icon: 'ti ti-presentation',
|
icon: 'ti ti-presentation',
|
||||||
action: () => {
|
action: () => {
|
||||||
@@ -116,11 +145,16 @@ export function openInstanceMenu(ev: MouseEvent) {
|
|||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
} : undefined, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
text: i18n.ts.aboutMisskey,
|
text: i18n.ts.aboutMisskey,
|
||||||
to: '/about-misskey',
|
to: '/about-misskey',
|
||||||
}], ev.currentTarget ?? ev.target, {
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target, {
|
||||||
align: 'left',
|
align: 'left',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -118,7 +118,7 @@ import XMentionsColumn from '@/ui/deck/mentions-column.vue';
|
|||||||
import XDirectColumn from '@/ui/deck/direct-column.vue';
|
import XDirectColumn from '@/ui/deck/direct-column.vue';
|
||||||
import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue';
|
import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue';
|
||||||
import { mainRouter } from '@/router/main.js';
|
import { mainRouter } from '@/router/main.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
|
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
|
||||||
const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue'));
|
const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue'));
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ import MkTimeline from '@/components/MkTimeline.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { antennasCache } from '@/cache.js';
|
import { antennasCache } from '@/cache.js';
|
||||||
import { SoundStore } from '@/store.js';
|
import { SoundStore } from '@/store.js';
|
||||||
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
@@ -29,7 +29,7 @@ import * as os from '@/os.js';
|
|||||||
import { favoritedChannelsCache } from '@/cache.js';
|
import { favoritedChannelsCache } from '@/cache.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { SoundStore } from '@/store.js';
|
import { SoundStore } from '@/store.js';
|
||||||
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
@@ -46,7 +46,7 @@ import { onBeforeUnmount, onMounted, provide, watch, shallowRef, ref, computed }
|
|||||||
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store.js';
|
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
provide('shouldHeaderThin', true);
|
provide('shouldHeaderThin', true);
|
||||||
provide('shouldOmitHeaderTitle', true);
|
provide('shouldOmitHeaderTitle', true);
|
||||||
@@ -104,7 +104,27 @@ function toggleActive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMenu() {
|
function getMenu() {
|
||||||
let items: MenuItem[] = [{
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
if (props.menu) {
|
||||||
|
menuItems.push(...props.menu, {
|
||||||
|
type: 'divider',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.refresher) {
|
||||||
|
menuItems.push({
|
||||||
|
icon: 'ti ti-refresh',
|
||||||
|
text: i18n.ts.reload,
|
||||||
|
action: () => {
|
||||||
|
if (props.refresher) {
|
||||||
|
props.refresher();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-settings',
|
icon: 'ti ti-settings',
|
||||||
text: i18n.ts._deck.configureColumn,
|
text: i18n.ts._deck.configureColumn,
|
||||||
action: async () => {
|
action: async () => {
|
||||||
@@ -129,11 +149,11 @@ function getMenu() {
|
|||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
updateColumn(props.column.id, result);
|
updateColumn(props.column.id, result);
|
||||||
},
|
},
|
||||||
}, {
|
});
|
||||||
type: 'parent',
|
|
||||||
text: i18n.ts.move + '...',
|
const moveToMenuItems: MenuItem[] = [];
|
||||||
icon: 'ti ti-arrows-move',
|
|
||||||
children: [{
|
moveToMenuItems.push({
|
||||||
icon: 'ti ti-arrow-left',
|
icon: 'ti ti-arrow-left',
|
||||||
text: i18n.ts._deck.swapLeft,
|
text: i18n.ts._deck.swapLeft,
|
||||||
action: () => {
|
action: () => {
|
||||||
@@ -145,58 +165,57 @@ function getMenu() {
|
|||||||
action: () => {
|
action: () => {
|
||||||
swapRightColumn(props.column.id);
|
swapRightColumn(props.column.id);
|
||||||
},
|
},
|
||||||
}, props.isStacked ? {
|
});
|
||||||
|
|
||||||
|
if (props.isStacked) {
|
||||||
|
moveToMenuItems.push({
|
||||||
icon: 'ti ti-arrow-up',
|
icon: 'ti ti-arrow-up',
|
||||||
text: i18n.ts._deck.swapUp,
|
text: i18n.ts._deck.swapUp,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapUpColumn(props.column.id);
|
swapUpColumn(props.column.id);
|
||||||
},
|
},
|
||||||
} : undefined, props.isStacked ? {
|
}, {
|
||||||
icon: 'ti ti-arrow-down',
|
icon: 'ti ti-arrow-down',
|
||||||
text: i18n.ts._deck.swapDown,
|
text: i18n.ts._deck.swapDown,
|
||||||
action: () => {
|
action: () => {
|
||||||
swapDownColumn(props.column.id);
|
swapDownColumn(props.column.id);
|
||||||
},
|
},
|
||||||
} : undefined],
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
|
type: 'parent',
|
||||||
|
text: i18n.ts.move + '...',
|
||||||
|
icon: 'ti ti-arrows-move',
|
||||||
|
children: moveToMenuItems,
|
||||||
}, {
|
}, {
|
||||||
icon: 'ti ti-stack-2',
|
icon: 'ti ti-stack-2',
|
||||||
text: i18n.ts._deck.stackLeft,
|
text: i18n.ts._deck.stackLeft,
|
||||||
action: () => {
|
action: () => {
|
||||||
stackLeftColumn(props.column.id);
|
stackLeftColumn(props.column.id);
|
||||||
},
|
},
|
||||||
}, props.isStacked ? {
|
});
|
||||||
|
|
||||||
|
if (props.isStacked) {
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-window-maximize',
|
icon: 'ti ti-window-maximize',
|
||||||
text: i18n.ts._deck.popRight,
|
text: i18n.ts._deck.popRight,
|
||||||
action: () => {
|
action: () => {
|
||||||
popRightColumn(props.column.id);
|
popRightColumn(props.column.id);
|
||||||
},
|
},
|
||||||
} : undefined, { type: 'divider' }, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({ type: 'divider' }, {
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
text: i18n.ts.remove,
|
text: i18n.ts.remove,
|
||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
removeColumn(props.column.id);
|
removeColumn(props.column.id);
|
||||||
},
|
},
|
||||||
}];
|
});
|
||||||
|
|
||||||
if (props.menu) {
|
return menuItems;
|
||||||
items.unshift({ type: 'divider' });
|
|
||||||
items = props.menu.concat(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.refresher) {
|
|
||||||
items = [{
|
|
||||||
icon: 'ti ti-refresh',
|
|
||||||
text: i18n.ts.reload,
|
|
||||||
action: () => {
|
|
||||||
if (props.refresher) {
|
|
||||||
props.refresher();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, ...items];
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSettingsMenu(ev: MouseEvent) {
|
function showSettingsMenu(ev: MouseEvent) {
|
||||||
|
@@ -22,7 +22,7 @@ import MkTimeline from '@/components/MkTimeline.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { SoundStore } from '@/store.js';
|
import { SoundStore } from '@/store.js';
|
||||||
import { userListsCache } from '@/cache.js';
|
import { userListsCache } from '@/cache.js';
|
||||||
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
@@ -21,7 +21,7 @@ import MkTimeline from '@/components/MkTimeline.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 { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import { SoundStore } from '@/store.js';
|
import { SoundStore } from '@/store.js';
|
||||||
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
@@ -113,7 +113,10 @@ function onNote() {
|
|||||||
sound.playMisskeySfxFile(soundSetting.value);
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = computed<MenuItem[]>(() => [{
|
const menu = computed<MenuItem[]>(() => {
|
||||||
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.timeline,
|
text: i18n.ts.timeline,
|
||||||
action: setType,
|
action: setType,
|
||||||
@@ -125,17 +128,26 @@ const menu = computed<MenuItem[]>(() => [{
|
|||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRenotes,
|
text: i18n.ts.showRenotes,
|
||||||
ref: withRenotes,
|
ref: withRenotes,
|
||||||
}, hasWithReplies(props.column.tl) ? {
|
});
|
||||||
|
|
||||||
|
if (hasWithReplies(props.column.tl)) {
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRepliesToOthersInTimeline,
|
text: i18n.ts.showRepliesToOthersInTimeline,
|
||||||
ref: withReplies,
|
ref: withReplies,
|
||||||
disabled: onlyFiles,
|
disabled: onlyFiles,
|
||||||
} : undefined, {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItems.push({
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.fileAttachedOnly,
|
text: i18n.ts.fileAttachedOnly,
|
||||||
ref: onlyFiles,
|
ref: onlyFiles,
|
||||||
disabled: hasWithReplies(props.column.tl) ? withReplies : false,
|
disabled: hasWithReplies(props.column.tl) ? withReplies : false,
|
||||||
}]);
|
});
|
||||||
|
|
||||||
|
return menuItems;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
@@ -40,6 +40,7 @@ import MkContainer from '@/components/MkContainer.vue';
|
|||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { availableBasicTimelines, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
import { availableBasicTimelines, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
|
||||||
const name = 'timeline';
|
const name = 'timeline';
|
||||||
|
|
||||||
@@ -109,11 +110,26 @@ const choose = async (ev) => {
|
|||||||
setSrc('list');
|
setSrc('list');
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
os.popupMenu([...availableBasicTimelines().map(tl => ({
|
|
||||||
|
const menuItems: MenuItem[] = [];
|
||||||
|
|
||||||
|
menuItems.push(...availableBasicTimelines().map(tl => ({
|
||||||
text: i18n.ts._timelines[tl],
|
text: i18n.ts._timelines[tl],
|
||||||
icon: basicTimelineIconClass(tl),
|
icon: basicTimelineIconClass(tl),
|
||||||
action: () => { setSrc(tl); },
|
action: () => { setSrc(tl); },
|
||||||
})), antennaItems.length > 0 ? { type: 'divider' } : undefined, ...antennaItems, listItems.length > 0 ? { type: 'divider' } : undefined, ...listItems], ev.currentTarget ?? ev.target).then(() => {
|
})));
|
||||||
|
|
||||||
|
if (antennaItems.length > 0) {
|
||||||
|
menuItems.push({ type: 'divider' });
|
||||||
|
menuItems.push(...antennaItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listItems.length > 0) {
|
||||||
|
menuItems.push({ type: 'divider' });
|
||||||
|
menuItems.push(...listItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target).then(() => {
|
||||||
menuOpened.value = false;
|
menuOpened.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -1,32 +1,32 @@
|
|||||||
import * as esbuild from "esbuild";
|
import fs from 'node:fs';
|
||||||
import { build } from "esbuild";
|
import { fileURLToPath } from 'node:url';
|
||||||
import { globSync } from "glob";
|
import { dirname } from 'node:path';
|
||||||
import { execa } from "execa";
|
import * as esbuild from 'esbuild';
|
||||||
import fs from "node:fs";
|
import { build } from 'esbuild';
|
||||||
import { fileURLToPath } from "node:url";
|
import { globSync } from 'glob';
|
||||||
import { dirname } from "node:path";
|
import { execa } from 'execa';
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||||
|
|
||||||
const entryPoints = globSync("./src/**/**.{ts,tsx}");
|
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||||
|
|
||||||
/** @type {import('esbuild').BuildOptions} */
|
/** @type {import('esbuild').BuildOptions} */
|
||||||
const options = {
|
const options = {
|
||||||
entryPoints,
|
entryPoints,
|
||||||
minify: process.env.NODE_ENV === 'production',
|
minify: process.env.NODE_ENV === 'production',
|
||||||
outdir: "./built",
|
outdir: './built',
|
||||||
target: "es2022",
|
target: 'es2022',
|
||||||
platform: "browser",
|
platform: 'browser',
|
||||||
format: "esm",
|
format: 'esm',
|
||||||
sourcemap: 'linked',
|
sourcemap: 'linked',
|
||||||
};
|
};
|
||||||
|
|
||||||
// built配下をすべて削除する
|
// built配下をすべて削除する
|
||||||
fs.rmSync('./built', { recursive: true, force: true });
|
fs.rmSync('./built', { recursive: true, force: true });
|
||||||
|
|
||||||
if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
|
if (process.argv.map(arg => arg.toLowerCase()).includes('--watch')) {
|
||||||
await watchSrc();
|
await watchSrc();
|
||||||
} else {
|
} else {
|
||||||
await buildSrc();
|
await buildSrc();
|
||||||
@@ -36,7 +36,7 @@ async function buildSrc() {
|
|||||||
console.log(`[${_package.name}] start building...`);
|
console.log(`[${_package.name}] start building...`);
|
||||||
|
|
||||||
await build(options)
|
await build(options)
|
||||||
.then(it => {
|
.then(() => {
|
||||||
console.log(`[${_package.name}] build succeeded.`);
|
console.log(`[${_package.name}] build succeeded.`);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -65,7 +65,7 @@ function buildDts() {
|
|||||||
{
|
{
|
||||||
stdout: process.stdout,
|
stdout: process.stdout,
|
||||||
stderr: process.stderr,
|
stderr: process.stderr,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ async function watchSrc() {
|
|||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
console.log(`[${_package.name}] start watching...`)
|
console.log(`[${_package.name}] start watching...`);
|
||||||
|
|
||||||
const context = await esbuild.context({ ...options, plugins });
|
const context = await esbuild.context({ ...options, plugins });
|
||||||
await context.watch();
|
await context.watch();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import tsParser from '@typescript-eslint/parser';
|
import tsParser from '@typescript-eslint/parser';
|
||||||
import sharedConfig from '../shared/eslint.config.js';
|
import sharedConfig from '../shared/eslint.config.js';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default [
|
export default [
|
||||||
...sharedConfig,
|
...sharedConfig,
|
||||||
{
|
{
|
||||||
|
@@ -199,13 +199,12 @@ export class DropAndFusionGame extends EventEmitter<{
|
|||||||
};
|
};
|
||||||
if (mono.shape === 'circle') {
|
if (mono.shape === 'circle') {
|
||||||
return Matter.Bodies.circle(x, y, mono.sizeX / 2, options);
|
return Matter.Bodies.circle(x, y, mono.sizeX / 2, options);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
||||||
} else if (mono.shape === 'rectangle') {
|
} else if (mono.shape === 'rectangle') {
|
||||||
return Matter.Bodies.rectangle(x, y, mono.sizeX, mono.sizeY, options);
|
return Matter.Bodies.rectangle(x, y, mono.sizeX, mono.sizeY, options);
|
||||||
} else if (mono.shape === 'custom') {
|
} else if (mono.shape === 'custom' && mono.vertices != null && mono.verticesSize != null) { //eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
||||||
return Matter.Bodies.fromVertices(x, y, mono.vertices!.map(i => i.map(j => ({
|
return Matter.Bodies.fromVertices(x, y, mono.vertices.map(i => i.map(j => ({
|
||||||
x: (j.x / mono.verticesSize!) * mono.sizeX,
|
x: (j.x / mono.verticesSize!) * mono.sizeX, //eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
y: (j.y / mono.verticesSize!) * mono.sizeY,
|
y: (j.y / mono.verticesSize!) * mono.sizeY, //eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
}))), options);
|
}))), options);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('unrecognized shape');
|
throw new Error('unrecognized shape');
|
||||||
@@ -227,7 +226,12 @@ export class DropAndFusionGame extends EventEmitter<{
|
|||||||
this.gameOverReadyBodyIds = this.gameOverReadyBodyIds.filter(x => x !== bodyA.id && x !== bodyB.id);
|
this.gameOverReadyBodyIds = this.gameOverReadyBodyIds.filter(x => x !== bodyA.id && x !== bodyB.id);
|
||||||
Matter.Composite.remove(this.engine.world, [bodyA, bodyB]);
|
Matter.Composite.remove(this.engine.world, [bodyA, bodyB]);
|
||||||
|
|
||||||
const currentMono = this.monoDefinitions.find(y => y.id === bodyA.label)!;
|
const currentMono = this.monoDefinitions.find(y => y.id === bodyA.label);
|
||||||
|
|
||||||
|
if (currentMono == null) {
|
||||||
|
throw new Error('Current Mono Not Found');
|
||||||
|
}
|
||||||
|
|
||||||
const nextMono = this.monoDefinitions.find(x => x.level === currentMono.level + 1) ?? null;
|
const nextMono = this.monoDefinitions.find(x => x.level === currentMono.level + 1) ?? null;
|
||||||
|
|
||||||
if (nextMono) {
|
if (nextMono) {
|
||||||
@@ -362,14 +366,18 @@ export class DropAndFusionGame extends EventEmitter<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getActiveMonos() {
|
public getActiveMonos() {
|
||||||
return this.engine.world.bodies.map(x => this.monoDefinitions.find((mono) => mono.id === x.label)!).filter(x => x !== undefined);
|
return this.engine.world.bodies
|
||||||
|
.map(x => this.monoDefinitions.find((mono) => mono.id === x.label))
|
||||||
|
.filter(x => x !== undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
public drop(_x: number) {
|
public drop(_x: number) {
|
||||||
if (this.isGameOver) return;
|
if (this.isGameOver) return;
|
||||||
if (this.frame - this.latestDroppedAt < this.DROP_COOLTIME) return;
|
if (this.frame - this.latestDroppedAt < this.DROP_COOLTIME) return;
|
||||||
|
|
||||||
const head = this.stock.shift()!;
|
const head = this.stock.shift();
|
||||||
|
if (!head) return;
|
||||||
|
|
||||||
this.stock.push({
|
this.stock.push({
|
||||||
id: this.rng().toString(),
|
id: this.rng().toString(),
|
||||||
mono: this.monoDefinitions.filter(x => x.dropCandidate)[Math.floor(this.rng() * this.monoDefinitions.filter(x => x.dropCandidate).length)],
|
mono: this.monoDefinitions.filter(x => x.dropCandidate)[Math.floor(this.rng() * this.monoDefinitions.filter(x => x.dropCandidate).length)],
|
||||||
@@ -411,13 +419,15 @@ export class DropAndFusionGame extends EventEmitter<{
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.holding) {
|
if (this.holding) {
|
||||||
const head = this.stock.shift()!;
|
const head = this.stock.shift();
|
||||||
|
if (!head) return;
|
||||||
this.stock.unshift(this.holding);
|
this.stock.unshift(this.holding);
|
||||||
this.holding = head;
|
this.holding = head;
|
||||||
this.emit('changeHolding', this.holding);
|
this.emit('changeHolding', this.holding);
|
||||||
this.emit('changeStock', this.stock);
|
this.emit('changeStock', this.stock);
|
||||||
} else {
|
} else {
|
||||||
const head = this.stock.shift()!;
|
const head = this.stock.shift();
|
||||||
|
if (!head) return;
|
||||||
this.holding = head;
|
this.holding = head;
|
||||||
this.stock.push({
|
this.stock.push({
|
||||||
id: this.rng().toString(),
|
id: this.rng().toString(),
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"name": "misskey-js",
|
"name": "misskey-js",
|
||||||
"version": "2024.9.0-alpha.6",
|
"version": "2024.9.0-alpha.7",
|
||||||
"description": "Misskey SDK for JavaScript",
|
"description": "Misskey SDK for JavaScript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
|
@@ -1,32 +1,32 @@
|
|||||||
import * as esbuild from "esbuild";
|
import fs from 'node:fs';
|
||||||
import { build } from "esbuild";
|
import { fileURLToPath } from 'node:url';
|
||||||
import { globSync } from "glob";
|
import { dirname } from 'node:path';
|
||||||
import { execa } from "execa";
|
import * as esbuild from 'esbuild';
|
||||||
import fs from "node:fs";
|
import { build } from 'esbuild';
|
||||||
import { fileURLToPath } from "node:url";
|
import { globSync } from 'glob';
|
||||||
import { dirname } from "node:path";
|
import { execa } from 'execa';
|
||||||
|
|
||||||
const _filename = fileURLToPath(import.meta.url);
|
const _filename = fileURLToPath(import.meta.url);
|
||||||
const _dirname = dirname(_filename);
|
const _dirname = dirname(_filename);
|
||||||
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8'));
|
||||||
|
|
||||||
const entryPoints = globSync("./src/**/**.{ts,tsx}");
|
const entryPoints = globSync('./src/**/**.{ts,tsx}');
|
||||||
|
|
||||||
/** @type {import('esbuild').BuildOptions} */
|
/** @type {import('esbuild').BuildOptions} */
|
||||||
const options = {
|
const options = {
|
||||||
entryPoints,
|
entryPoints,
|
||||||
minify: process.env.NODE_ENV === 'production',
|
minify: process.env.NODE_ENV === 'production',
|
||||||
outdir: "./built",
|
outdir: './built',
|
||||||
target: "es2022",
|
target: 'es2022',
|
||||||
platform: "browser",
|
platform: 'browser',
|
||||||
format: "esm",
|
format: 'esm',
|
||||||
sourcemap: 'linked',
|
sourcemap: 'linked',
|
||||||
};
|
};
|
||||||
|
|
||||||
// built配下をすべて削除する
|
// built配下をすべて削除する
|
||||||
fs.rmSync('./built', { recursive: true, force: true });
|
fs.rmSync('./built', { recursive: true, force: true });
|
||||||
|
|
||||||
if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) {
|
if (process.argv.map(arg => arg.toLowerCase()).includes('--watch')) {
|
||||||
await watchSrc();
|
await watchSrc();
|
||||||
} else {
|
} else {
|
||||||
await buildSrc();
|
await buildSrc();
|
||||||
@@ -36,7 +36,7 @@ async function buildSrc() {
|
|||||||
console.log(`[${_package.name}] start building...`);
|
console.log(`[${_package.name}] start building...`);
|
||||||
|
|
||||||
await build(options)
|
await build(options)
|
||||||
.then(it => {
|
.then(() => {
|
||||||
console.log(`[${_package.name}] build succeeded.`);
|
console.log(`[${_package.name}] build succeeded.`);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -65,7 +65,7 @@ function buildDts() {
|
|||||||
{
|
{
|
||||||
stdout: process.stdout,
|
stdout: process.stdout,
|
||||||
stderr: process.stderr,
|
stderr: process.stderr,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ async function watchSrc() {
|
|||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
console.log(`[${_package.name}] start watching...`)
|
console.log(`[${_package.name}] start watching...`);
|
||||||
|
|
||||||
const context = await esbuild.context({ ...options, plugins });
|
const context = await esbuild.context({ ...options, plugins });
|
||||||
await context.watch();
|
await context.watch();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import tsParser from '@typescript-eslint/parser';
|
import tsParser from '@typescript-eslint/parser';
|
||||||
import sharedConfig from '../shared/eslint.config.js';
|
import sharedConfig from '../shared/eslint.config.js';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default [
|
export default [
|
||||||
...sharedConfig,
|
...sharedConfig,
|
||||||
{
|
{
|
||||||
|
@@ -53,9 +53,13 @@ export class Game {
|
|||||||
|
|
||||||
//#region Options
|
//#region Options
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||||
if (this.opts.isLlotheo == null) this.opts.isLlotheo = false;
|
if (this.opts.isLlotheo == null) this.opts.isLlotheo = false;
|
||||||
if (this.opts.canPutEverywhere == null) this.opts.canPutEverywhere = false;
|
if (this.opts.canPutEverywhere == null) this.opts.canPutEverywhere = false;
|
||||||
if (this.opts.loopedBoard == null) this.opts.loopedBoard = false;
|
if (this.opts.loopedBoard == null) this.opts.loopedBoard = false;
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Parse map data
|
//#region Parse map data
|
||||||
@@ -123,12 +127,13 @@ export class Game {
|
|||||||
// ターン計算
|
// ターン計算
|
||||||
this.turn =
|
this.turn =
|
||||||
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
|
this.canPutSomewhere(!this.prevColor) ? !this.prevColor :
|
||||||
this.canPutSomewhere(this.prevColor!) ? this.prevColor :
|
this.canPutSomewhere(this.prevColor!) ? this.prevColor : //eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
null;
|
null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public undo() {
|
public undo() {
|
||||||
const undo = this.logs.pop()!;
|
const undo = this.logs.pop();
|
||||||
|
if (undo == null) return;
|
||||||
this.prevColor = undo.color;
|
this.prevColor = undo.color;
|
||||||
this.prevPos = undo.pos;
|
this.prevPos = undo.pos;
|
||||||
this.board[undo.pos] = null;
|
this.board[undo.pos] = null;
|
||||||
@@ -183,7 +188,7 @@ export class Game {
|
|||||||
|
|
||||||
const found: number[] = []; // 挟めるかもしれない相手の石を入れておく配列
|
const found: number[] = []; // 挟めるかもしれない相手の石を入れておく配列
|
||||||
let [x, y] = this.posToXy(initPos);
|
let [x, y] = this.posToXy(initPos);
|
||||||
while (true) {
|
while (true) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
||||||
[x, y] = nextPos(x, y);
|
[x, y] = nextPos(x, y);
|
||||||
|
|
||||||
// 座標が指し示す位置がボード外に出たとき
|
// 座標が指し示す位置がボード外に出たとき
|
||||||
|
Reference in New Issue
Block a user