diff --git a/src/client/components/global/a.vue b/src/client/components/global/a.vue index 7ad62a731..d2544ecbe 100644 --- a/src/client/components/global/a.vue +++ b/src/client/components/global/a.vue @@ -9,7 +9,7 @@ import { defineComponent } from 'vue'; import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import * as os from '@client/os'; import copyToClipboard from '@client/scripts/copy-to-clipboard'; -import { router } from '@client/router'; +import { router, setNavigationInfo } from '@client/router'; import { url } from '@client/config'; import { popout } from '@client/scripts/popout'; import { ColdDeviceStorage } from '@client/store'; @@ -130,6 +130,10 @@ export default defineComponent({ if (this.$router.currentRoute.value.path === this.to) { window.scroll({ top: 0, behavior: 'smooth' }); } else { + setNavigationInfo({ + from: this.$router.currentRoute.value.path, + to: this.to + }); this.$router.push(this.to); } } diff --git a/src/client/router.ts b/src/client/router.ts index bf45c806e..bdb7755d5 100644 --- a/src/client/router.ts +++ b/src/client/router.ts @@ -1,4 +1,4 @@ -import { defineAsyncComponent, markRaw } from 'vue'; +import { defineAsyncComponent, markRaw, ref } from 'vue'; import { createRouter, createWebHistory } from 'vue-router'; import MkLoading from '@client/pages/_loading_.vue'; import MkError from '@client/pages/_error_.vue'; @@ -13,6 +13,16 @@ const page = (path: string) => defineAsyncComponent({ let indexScrollPos = 0; +export const navigationInfo = ref(null); +export function setNavigationInfo(info) { + navigationInfo.value = info; +} + +window.addEventListener('popstate', (event) => { + console.log('popstate'); + navigationInfo.value = null; +}); + export const router = createRouter({ history: createWebHistory(), routes: [ @@ -91,7 +101,7 @@ export const router = createRouter({ // 通常の使い方をすると scroll メソッドの behavior を設定できないため、自前で window.scroll するようにする scrollBehavior(to) { window._scroll = () => { // さらにHacky - if (to.name === 'index') { + if (location.pathname === '/') { window.scroll({ top: indexScrollPos, behavior: 'instant' }); const i = setInterval(() => { window.scroll({ top: indexScrollPos, behavior: 'instant' }); @@ -106,11 +116,11 @@ export const router = createRouter({ } }); -router.afterEach((to, from) => { - if (from.name === 'index') { +export function saveScrollPosition() { + if (navigationInfo.value?.from === '/') { indexScrollPos = window.scrollY; } -}); +} export function resolve(path: string) { const resolved = router.resolve(path); diff --git a/src/client/style.scss b/src/client/style.scss index eadf56bf3..0ba8d8b9b 100644 --- a/src/client/style.scss +++ b/src/client/style.scss @@ -322,6 +322,8 @@ hr { box-sizing: border-box; margin: var(--root-margin, 32px) auto; max-width: min(var(--baseContentWidth), calc(100% - (var(--root-margin, 32px) * 2))); + background: var(--bg); + min-height: 100%; @media (max-width: 500px) { --root-margin: 10px; diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue index c3dce0f32..ba1378d84 100644 --- a/src/client/ui/default.vue +++ b/src/client/ui/default.vue @@ -11,7 +11,7 @@
- + @@ -64,6 +64,7 @@ import XHeader from './_common_/header.vue'; import * as os from '@client/os'; import { sidebarDef } from '@client/sidebar'; import * as symbols from '@client/symbols'; +import { saveScrollPosition, navigationInfo } from '@client/router'; const DESKTOP_THRESHOLD = 1100; const MOBILE_THRESHOLD = 600; @@ -85,6 +86,7 @@ export default defineComponent({ isDesktop: window.innerWidth >= DESKTOP_THRESHOLD, widgetsShowing: false, fullView: false, + navigationInfo, wallpaper: localStorage.getItem('wallpaper') != null, faLayerGroup, faBars, faBell, faHome, faCircle, faPencilAlt, }; @@ -152,6 +154,10 @@ export default defineComponent({ this.$refs.drawerNav.show(); }, + saveScrollPosition() { + saveScrollPosition(); + }, + onTransition() { if (window._scroll) window._scroll(); }, @@ -215,6 +221,39 @@ export default defineComponent({ opacity: 0; } +.page-enter-active { + position: absolute; + top: 0; + z-index: 1; + width: 100%; + opacity: 1; + transform: translateX(0); + transition: transform 500ms cubic-bezier(0.23, 1, 0.32, 1), opacity 500ms cubic-bezier(0.23, 1, 0.32, 1); +} +.page-leave-active { + opacity: 1; + transform: translateX(0); + transition: transform 500ms cubic-bezier(0.23, 1, 0.32, 1), opacity 500ms cubic-bezier(0.23, 1, 0.32, 1); +} +.page-enter-from { + //opacity: 0; + transform: translateX(128px); + + /* iOSはoverflow: clipをサポートしていない */ + @supports (-webkit-touch-callout: none) { + transform: translateX(0); + } +} +.page-leave-active { + opacity: 0; + transform: translateX(-64px); + + /* iOSはoverflow: clipをサポートしていない */ + @supports (-webkit-touch-callout: none) { + transform: translateX(0); + } +} + .mk-app { $header-height: 50px; $ui-font-size: 1em; @@ -294,6 +333,7 @@ export default defineComponent({ } > .content { + position: relative; background: var(--bg); --stickyTop: #{$header-height}; }