Compare commits
4 Commits
69f64c79ca
...
c0c17b96e8
Author | SHA1 | Date |
---|---|---|
syuilo | c0c17b96e8 | |
鴇峰 朔華 | 4603ab67bb | |
syuilo | ec73511759 | |
syuilo | 9d36ad9052 |
|
@ -30,6 +30,7 @@
|
|||
(Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663)
|
||||
- Enhance: サイドバーを簡単に展開・折りたたみできるように ( #14981 )
|
||||
- Enhance: リノートメニューに「リノートの詳細」を追加
|
||||
- Enhance: 非ログイン状態でMisskeyを開いた際のパフォーマンスを向上
|
||||
- Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
|
||||
- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正
|
||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
|
||||
|
|
|
@ -559,7 +559,7 @@ export class ClientServerService {
|
|||
}
|
||||
});
|
||||
|
||||
//#region SSR (for crawlers)
|
||||
//#region SSR
|
||||
// User
|
||||
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
|
||||
const { username, host } = Acct.parse(request.params.user);
|
||||
|
@ -584,11 +584,17 @@ export class ClientServerService {
|
|||
reply.header('X-Robots-Tag', 'noimageai');
|
||||
reply.header('X-Robots-Tag', 'noai');
|
||||
}
|
||||
|
||||
const _user = await this.userEntityService.pack(user);
|
||||
|
||||
return await reply.view('user', {
|
||||
user, profile, me,
|
||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||
sub: request.params.sub,
|
||||
...await this.generateCommonPugData(this.meta),
|
||||
clientCtx: htmlSafeJsonStringify({
|
||||
user: _user,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
// リモートユーザーなので
|
||||
|
@ -641,6 +647,9 @@ export class ClientServerService {
|
|||
// TODO: Let locale changeable by instance setting
|
||||
summary: getNoteSummary(_note),
|
||||
...await this.generateCommonPugData(this.meta),
|
||||
clientCtx: htmlSafeJsonStringify({
|
||||
note: _note,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
return await renderBase(reply);
|
||||
|
@ -729,6 +738,9 @@ export class ClientServerService {
|
|||
profile,
|
||||
avatarUrl: _clip.user.avatarUrl,
|
||||
...await this.generateCommonPugData(this.meta),
|
||||
clientCtx: htmlSafeJsonStringify({
|
||||
clip: _clip,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
return await renderBase(reply);
|
||||
|
|
|
@ -74,6 +74,9 @@ html
|
|||
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||
!= metaJson
|
||||
|
||||
script(type='application/json' id='misskey_clientCtx' data-generated-at=now)
|
||||
!= clientCtx
|
||||
|
||||
script
|
||||
include ../boot.js
|
||||
|
||||
|
|
|
@ -25,17 +25,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import { computed, defineAsyncComponent, inject, ref } from 'vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { customEmojisMap } from '@/custom-emojis.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { misskeyApi, misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||
import * as sound from '@/scripts/sound.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
|
@ -125,9 +126,31 @@ function onClick(ev: MouseEvent) {
|
|||
},
|
||||
});
|
||||
|
||||
if ($i?.isModerator ?? $i?.isAdmin) {
|
||||
menuItems.push({
|
||||
text: i18n.ts.edit,
|
||||
icon: 'ti ti-pencil',
|
||||
action: async () => {
|
||||
await edit(props.name);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||
}
|
||||
}
|
||||
|
||||
async function edit(name: string) {
|
||||
const emoji = await misskeyApi('emoji', {
|
||||
name: name,
|
||||
});
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/pages/emoji-edit-dialog.vue')), {
|
||||
emoji: emoji,
|
||||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -46,12 +46,13 @@ import { isSupportShare } from '@/scripts/navigator.js';
|
|||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||
import { genEmbedCode } from '@/scripts/get-embed-code.js';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import { getServerContext } from '@/server-context.js';
|
||||
|
||||
const props = defineProps<{
|
||||
clipId: string,
|
||||
}>();
|
||||
|
||||
const clip = ref<Misskey.entities.Clip | null>(null);
|
||||
const clip = ref<Misskey.entities.Clip | null>(getServerContext('clip'));
|
||||
const favorited = ref(false);
|
||||
const pagination = {
|
||||
endpoint: 'clips/notes' as const,
|
||||
|
@ -64,6 +65,11 @@ const pagination = {
|
|||
const isOwned = computed<boolean | null>(() => $i && clip.value && ($i.id === clip.value.userId));
|
||||
|
||||
watch(() => props.clipId, async () => {
|
||||
if (getServerContext('clip') && getServerContext('clip').id === props.clipId) {
|
||||
clip.value = getServerContext('clip');
|
||||
return;
|
||||
}
|
||||
|
||||
clip.value = await misskeyApi('clips/show', {
|
||||
clipId: props.clipId,
|
||||
});
|
||||
|
|
|
@ -15,18 +15,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import type { MenuItem } from '@/types/menu.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApiGet } from '@/scripts/misskey-api.js';
|
||||
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkCustomEmojiDetailedDialog from '@/components/MkCustomEmojiDetailedDialog.vue';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const props = defineProps<{
|
||||
emoji: Misskey.entities.EmojiSimple;
|
||||
}>();
|
||||
|
||||
function menu(ev) {
|
||||
os.popupMenu([{
|
||||
const menuItems: MenuItem[] = [];
|
||||
menuItems.push({
|
||||
type: 'label',
|
||||
text: ':' + props.emoji.name + ':',
|
||||
}, {
|
||||
|
@ -48,8 +52,28 @@ function menu(ev) {
|
|||
closed: () => dispose(),
|
||||
});
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
});
|
||||
|
||||
if ($i?.isModerator ?? $i?.isAdmin) {
|
||||
menuItems.push({
|
||||
text: i18n.ts.edit,
|
||||
icon: 'ti ti-pencil',
|
||||
action: () => {
|
||||
edit(props.emoji);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
const edit = async (emoji) => {
|
||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/pages/emoji-edit-dialog.vue')), {
|
||||
emoji: emoji,
|
||||
}, {
|
||||
closed: () => dispose(),
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -62,13 +62,14 @@ import { dateString } from '@/filters/date.js';
|
|||
import MkClipPreview from '@/components/MkClipPreview.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||
import { getServerContext } from '@/server-context.js';
|
||||
|
||||
const props = defineProps<{
|
||||
noteId: string;
|
||||
initialTab?: string;
|
||||
}>();
|
||||
|
||||
const note = ref<null | Misskey.entities.Note>();
|
||||
const note = ref<null | Misskey.entities.Note>(getServerContext('note'));
|
||||
const clips = ref<Misskey.entities.Clip[]>();
|
||||
const showPrev = ref<'user' | 'channel' | false>(false);
|
||||
const showNext = ref<'user' | 'channel' | false>(false);
|
||||
|
@ -116,6 +117,12 @@ function fetchNote() {
|
|||
showPrev.value = false;
|
||||
showNext.value = false;
|
||||
note.value = null;
|
||||
|
||||
if (getServerContext('note') && getServerContext('note').id === props.noteId) {
|
||||
note.value = getServerContext('note');
|
||||
return;
|
||||
}
|
||||
|
||||
misskeyApi('notes/show', {
|
||||
noteId: props.noteId,
|
||||
}).then(res => {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const providedContextEl = document.getElementById('misskey_clientCtx');
|
||||
|
||||
export type ServerContext = {
|
||||
clip?: Misskey.entities.Clip;
|
||||
note?: Misskey.entities.Note;
|
||||
user?: Misskey.entities.UserLite;
|
||||
} | null;
|
||||
|
||||
export const serverContext: ServerContext = (providedContextEl && providedContextEl.textContent) ? JSON.parse(providedContextEl.textContent) : null;
|
||||
|
||||
export function getServerContext<K extends keyof NonNullable<ServerContext>>(entity: K): Required<Pick<NonNullable<ServerContext>, K>> | null {
|
||||
// contextは非ログイン状態の情報しかないためログイン時は利用できない
|
||||
if ($i) return null;
|
||||
|
||||
return serverContext ? (serverContext[entity] ?? null) : null;
|
||||
}
|
Loading…
Reference in New Issue