diff --git a/locales/index.d.ts b/locales/index.d.ts index 94d9657ac8..31fc8cdb1e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -533,7 +533,7 @@ export interface Locale { "deleteAll": string; "showFixedPostForm": string; "showFixedPostFormInChannel": string; - "newNoteRecived": string; + "goToTheHeadOfTimeline": string; "sounds": string; "sound": string; "listen": string; @@ -1103,6 +1103,7 @@ export interface Locale { "doYouAgree": string; "beSureToReadThisAsItIsImportant": string; "iHaveReadXCarefullyAndAgree": string; + "timelineBackTopBehavior": string; "dialog": string; "icon": string; "forYou": string; @@ -1672,6 +1673,10 @@ export interface Locale { "dialog": string; "quiet": string; }; + "_timelineBackTopBehavior": { + "newest": string; + "next": string; + }; "_channel": { "create": string; "edit": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index eb0590a724..a4a65588d0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -530,7 +530,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" -newNoteRecived: "新しいノートがあります" +goToTheHeadOfTimeline: "最新のノートに移動" sounds: "サウンド" sound: "サウンド" listen: "聴く" @@ -1100,6 +1100,7 @@ expired: "期限切れ" doYouAgree: "同意しますか?" beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。" +timelineBackTopBehavior: "タイムラインのスクロールが先頭に戻った時の挙動" dialog: "ダイアログ" icon: "アイコン" forYou: "あなたへ" @@ -1589,6 +1590,10 @@ _serverDisconnectedBehavior: dialog: "ダイアログで警告" quiet: "控えめに警告" +_timelineBackTopBehavior: + newest: "最新の投稿を表示" + next: "次の投稿を遡る" + _channel: create: "チャンネルを作成" edit: "チャンネルを編集" diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 98117521f0..000989ed21 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -68,6 +68,7 @@ "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", "typescript": "5.2.2", + "ua-parser-js": "2.0.0-alpha.2", "uuid": "9.0.1", "vanilla-tilt": "1.8.1", "vite": "4.4.9", diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue index e6690ed8a0..f6c8a008dc 100644 --- a/packages/frontend/src/components/MkDateSeparatedList.vue +++ b/packages/frontend/src/components/MkDateSeparatedList.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> + + diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index 865ebe2ef9..b0f5aafbfd 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -40,9 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.letsLookAtTimeline }}
-
- -
+
diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 5a4679f69f..8ed078e939 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -16,12 +16,18 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/nirax.ts b/packages/frontend/src/nirax.ts index 66ae39fa56..f2f45600bb 100644 --- a/packages/frontend/src/nirax.ts +++ b/packages/frontend/src/nirax.ts @@ -54,24 +54,30 @@ function parsePath(path: string): ParsedPath { return res; } +export type NiraxChangeEvent = { + beforePath: string; + path: string; + resolved: Resolved; + key: string; +}; + +export type NiraxExportEvent = { + path: string; + key: string; +}; + +export type NiraxPushEvent = { + beforePath: string; + path: string; + route: RouteDef | null; + props: Map | null; + key: string; +}; + export class Router extends EventEmitter<{ - change: (ctx: { - beforePath: string; - path: string; - resolved: Resolved; - key: string; - }) => void; - replace: (ctx: { - path: string; - key: string; - }) => void; - push: (ctx: { - beforePath: string; - path: string; - route: RouteDef | null; - props: Map | null; - key: string; - }) => void; + change: (ctx: NiraxChangeEvent) => void; + replace: (ctx: NiraxExportEvent) => void; + push: (ctx: NiraxExportEvent) => void; same: () => void; }> { private routes: RouteDef[]; @@ -276,29 +282,3 @@ export class Router extends EventEmitter<{ this.navigate(path, key); } } - -export function useScrollPositionManager(getScrollContainer: () => HTMLElement, router: Router) { - const scrollPosStore = new Map(); - - onMounted(() => { - const scrollContainer = getScrollContainer(); - - scrollContainer.addEventListener('scroll', () => { - scrollPosStore.set(router.getCurrentKey(), scrollContainer.scrollTop); - }, { passive: true }); - - router.addListener('change', ctx => { - const scrollPos = scrollPosStore.get(ctx.key) ?? 0; - scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); - if (scrollPos !== 0) { - window.setTimeout(() => { // 遷移直後はタイミングによってはコンポーネントが復元し切ってない可能性も考えられるため少し時間を空けて再度スクロール - scrollContainer.scroll({ top: scrollPos, behavior: 'instant' }); - }, 100); - } - }); - - router.addListener('same', () => { - scrollContainer.scroll({ top: 0, behavior: 'smooth' }); - }); - }); -} diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue index f410e78e06..6f754292c1 100644 --- a/packages/frontend/src/pages/antenna-timeline.vue +++ b/packages/frontend/src/pages/antenna-timeline.vue @@ -8,16 +8,13 @@ SPDX-License-Identifier: AGPL-3.0-only
-
-
- -
+
@@ -26,7 +23,6 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index d9cb81b5ef..c27fa53b19 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- +
@@ -105,7 +105,6 @@ import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; import { deviceKind } from '@/scripts/device-kind'; import { miLocalStorage } from '@/local-storage'; import { CURRENT_STICKY_BOTTOM } from '@/const'; -import { useScrollPositionManager } from '@/nirax'; const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); @@ -227,8 +226,6 @@ watch($$(navFooter), () => { }, { immediate: true, }); - -useScrollPositionManager(() => contents.value.rootEl, mainRouter); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6976a67bff..1c6b6f490b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -799,6 +799,9 @@ importers: typescript: specifier: 5.2.2 version: 5.2.2 + ua-parser-js: + specifier: 2.0.0-alpha.2 + version: 2.0.0-alpha.2 uuid: specifier: 9.0.1 version: 9.0.1 @@ -11846,6 +11849,7 @@ packages: /form-data@3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} + requiresBuild: true dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -18818,6 +18822,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + /ua-parser-js@2.0.0-alpha.2: + resolution: {integrity: sha512-Vz+BJN/EFC1OaUv0eu5kPyX7HEZIO7Dv29jIK7rMuKjUB1qqq+Is/XIpu5iV5XDvoNl62dM7ay8DtzYjBDI0WA==} + dev: false + /ufo@1.1.2: resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} dev: true