prepare for upstream release #39
7 changed files with 77 additions and 7 deletions
|
@ -58,6 +58,7 @@ PgroongaのCWサーチ (github.com/paricafe/misskey#d30db97b59d264450901c1dd8680
|
||||||
(Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663)
|
(Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663)
|
||||||
- Enhance: サイドバーを簡単に展開・折りたたみできるように ( #14981 )
|
- Enhance: サイドバーを簡単に展開・折りたたみできるように ( #14981 )
|
||||||
- Enhance: リノートメニューに「リノートの詳細」を追加
|
- Enhance: リノートメニューに「リノートの詳細」を追加
|
||||||
|
- Enhance: 非ログイン状態でMisskeyを開いた際のパフォーマンスを向上
|
||||||
- Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
|
- Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正
|
||||||
- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正
|
- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768)
|
||||||
|
|
|
@ -611,7 +611,7 @@ export class ClientServerService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region SSR (for crawlers)
|
//#region SSR
|
||||||
// User
|
// User
|
||||||
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
|
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
|
||||||
const { username, host } = Acct.parse(request.params.user);
|
const { username, host } = Acct.parse(request.params.user);
|
||||||
|
@ -636,11 +636,17 @@ export class ClientServerService {
|
||||||
reply.header('X-Robots-Tag', 'noimageai');
|
reply.header('X-Robots-Tag', 'noimageai');
|
||||||
reply.header('X-Robots-Tag', 'noai');
|
reply.header('X-Robots-Tag', 'noai');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _user = await this.userEntityService.pack(user);
|
||||||
|
|
||||||
return await reply.view('user', {
|
return await reply.view('user', {
|
||||||
user, profile, me,
|
user, profile, me,
|
||||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||||
sub: request.params.sub,
|
sub: request.params.sub,
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
user: _user,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
|
@ -693,6 +699,9 @@ export class ClientServerService {
|
||||||
// TODO: Let locale changeable by instance setting
|
// TODO: Let locale changeable by instance setting
|
||||||
summary: getNoteSummary(_note),
|
summary: getNoteSummary(_note),
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
note: _note,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -781,6 +790,9 @@ export class ClientServerService {
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _clip.user.avatarUrl,
|
avatarUrl: _clip.user.avatarUrl,
|
||||||
...await this.generateCommonPugData(this.meta),
|
...await this.generateCommonPugData(this.meta),
|
||||||
|
clientCtx: htmlSafeJsonStringify({
|
||||||
|
clip: _clip,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
|
|
@ -72,6 +72,9 @@ html
|
||||||
|
|
||||||
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
!= metaJson
|
!= metaJson
|
||||||
|
|
||||||
|
script(type='application/json' id='misskey_clientCtx' data-generated-at=now)
|
||||||
|
!= clientCtx
|
||||||
|
|
||||||
script(integrity=bootJS.integrity) !{bootJS.content}
|
script(integrity=bootJS.integrity) !{bootJS.content}
|
||||||
|
|
||||||
|
|
|
@ -33,25 +33,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, watch, provide, ref } from 'vue';
|
import { computed, watch, provide, ref } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { url } from '@@/js/config.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.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 { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { url } from '@@/js/config.js';
|
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { clipsCache } from '@/cache.js';
|
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';
|
import { getServerContext } from '@/server-context.js';
|
||||||
|
|
||||||
|
const CTX_CLIP = getServerContext('clip');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
clipId: string,
|
clipId: string,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const clip = ref<Misskey.entities.Clip | null>(null);
|
const clip = ref<Misskey.entities.Clip | null>(CTX_CLIP);
|
||||||
const favorited = ref(false);
|
const favorited = ref(false);
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: 'clips/notes' as const,
|
endpoint: 'clips/notes' as const,
|
||||||
|
@ -64,6 +67,11 @@ const pagination = {
|
||||||
const isOwned = computed<boolean | null>(() => $i && clip.value && ($i.id === clip.value.userId));
|
const isOwned = computed<boolean | null>(() => $i && clip.value && ($i.id === clip.value.userId));
|
||||||
|
|
||||||
watch(() => props.clipId, async () => {
|
watch(() => props.clipId, async () => {
|
||||||
|
if (CTX_CLIP && CTX_CLIP.id === props.clipId) {
|
||||||
|
clip.value = CTX_CLIP;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clip.value = await misskeyApi('clips/show', {
|
clip.value = await misskeyApi('clips/show', {
|
||||||
clipId: props.clipId,
|
clipId: props.clipId,
|
||||||
});
|
});
|
||||||
|
|
|
@ -62,13 +62,16 @@ import { dateString } from '@/filters/date.js';
|
||||||
import MkClipPreview from '@/components/MkClipPreview.vue';
|
import MkClipPreview from '@/components/MkClipPreview.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
import { pleaseLogin } from '@/scripts/please-login.js';
|
import { pleaseLogin } from '@/scripts/please-login.js';
|
||||||
|
import { getServerContext } from '@/server-context.js';
|
||||||
|
|
||||||
|
const CTX_NOTE = getServerContext('note');
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
noteId: string;
|
noteId: string;
|
||||||
initialTab?: string;
|
initialTab?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const note = ref<null | Misskey.entities.Note>();
|
const note = ref<null | Misskey.entities.Note>(CTX_NOTE);
|
||||||
const clips = ref<Misskey.entities.Clip[]>();
|
const clips = ref<Misskey.entities.Clip[]>();
|
||||||
const showPrev = ref<'user' | 'channel' | false>(false);
|
const showPrev = ref<'user' | 'channel' | false>(false);
|
||||||
const showNext = ref<'user' | 'channel' | false>(false);
|
const showNext = ref<'user' | 'channel' | false>(false);
|
||||||
|
@ -116,6 +119,12 @@ function fetchNote() {
|
||||||
showPrev.value = false;
|
showPrev.value = false;
|
||||||
showNext.value = false;
|
showNext.value = false;
|
||||||
note.value = null;
|
note.value = null;
|
||||||
|
|
||||||
|
if (CTX_NOTE && CTX_NOTE.id === props.noteId) {
|
||||||
|
note.value = CTX_NOTE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
misskeyApi('notes/show', {
|
misskeyApi('notes/show', {
|
||||||
noteId: props.noteId,
|
noteId: props.noteId,
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
|
|
|
@ -39,6 +39,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
|
import { getServerContext } from '@/server-context.js';
|
||||||
|
|
||||||
const XHome = defineAsyncComponent(() => import('./home.vue'));
|
const XHome = defineAsyncComponent(() => import('./home.vue'));
|
||||||
const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue'));
|
const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue'));
|
||||||
|
@ -52,6 +53,8 @@ const XFlashs = defineAsyncComponent(() => import('./flashs.vue'));
|
||||||
const XGallery = defineAsyncComponent(() => import('./gallery.vue'));
|
const XGallery = defineAsyncComponent(() => import('./gallery.vue'));
|
||||||
const XRaw = defineAsyncComponent(() => import('./raw.vue'));
|
const XRaw = defineAsyncComponent(() => import('./raw.vue'));
|
||||||
|
|
||||||
|
const CTX_USER = getServerContext('user');
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
acct: string;
|
acct: string;
|
||||||
page?: string;
|
page?: string;
|
||||||
|
@ -61,13 +64,24 @@ const props = withDefaults(defineProps<{
|
||||||
|
|
||||||
const tab = ref(props.page);
|
const tab = ref(props.page);
|
||||||
|
|
||||||
const user = ref<null | Misskey.entities.UserDetailed>(null);
|
const user = ref<null | Misskey.entities.UserDetailed>(CTX_USER);
|
||||||
const error = ref<any>(null);
|
const error = ref<any>(null);
|
||||||
|
|
||||||
function fetchUser(): void {
|
function fetchUser(): void {
|
||||||
if (props.acct == null) return;
|
if (props.acct == null) return;
|
||||||
|
|
||||||
|
const { username, host } = Misskey.acct.parse(props.acct);
|
||||||
|
|
||||||
|
if (CTX_USER && CTX_USER.username === username && CTX_USER.host === host) {
|
||||||
|
user.value = CTX_USER;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
user.value = null;
|
user.value = null;
|
||||||
misskeyApi('users/show', Misskey.acct.parse(props.acct)).then(u => {
|
misskeyApi('users/show', {
|
||||||
|
username,
|
||||||
|
host,
|
||||||
|
}).then(u => {
|
||||||
user.value = u;
|
user.value = u;
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
error.value = err;
|
error.value = err;
|
||||||
|
|
23
packages/frontend/src/server-context.ts
Normal file
23
packages/frontend/src/server-context.ts
Normal file
|
@ -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 a new issue