From 1c29a829b1c6d2bdaacf898febbcc44b3f93aac1 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Tue, 7 May 2024 16:02:39 +0800 Subject: [PATCH] fix(plugin-redirect): fix direct modal, close #105 --- .../src/client/components/LanguageSwitch.ts | 166 ------------------ .../src/client/components/RedirectModal.ts | 158 +++++++++++++++++ plugins/plugin-redirect/src/client/config.ts | 6 +- ...nguage-switch.scss => redirect-modal.scss} | 0 4 files changed, 161 insertions(+), 169 deletions(-) delete mode 100644 plugins/plugin-redirect/src/client/components/LanguageSwitch.ts create mode 100644 plugins/plugin-redirect/src/client/components/RedirectModal.ts rename plugins/plugin-redirect/src/client/styles/{language-switch.scss => redirect-modal.scss} (100%) diff --git a/plugins/plugin-redirect/src/client/components/LanguageSwitch.ts b/plugins/plugin-redirect/src/client/components/LanguageSwitch.ts deleted file mode 100644 index 409fe335a8..0000000000 --- a/plugins/plugin-redirect/src/client/components/LanguageSwitch.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - usePreferredLanguages, - useScrollLock, - useSessionStorage, -} from '@vueuse/core' -import type { VNode } from 'vue' -import { - computed, - defineComponent, - h, - onBeforeUnmount, - onMounted, - ref, - TransitionGroup, - watch, -} from 'vue' -import { useRoute, useRouteLocale, useRouter } from 'vuepress/client' -import type { RedirectPluginLocaleConfig } from '../../shared/locales.js' -import { redirectLocaleConfig, redirectLocaleEntries } from '../define.js' - -import '../styles/language-switch.css' - -declare const __REDIRECT_LOCALES__: RedirectPluginLocaleConfig - -const redirectLocales = __REDIRECT_LOCALES__ -const { switchLocale } = redirectLocaleConfig - -interface LocaleInfo { - lang: string - localePath: string -} - -const REDIRECT_LOCALE_STORAGE = useSessionStorage>( - 'VUEPRESS_REDIRECT_LOCALES', - {}, -) - -export default defineComponent({ - name: 'LanguageSwitch', - - setup() { - const languages = usePreferredLanguages() - const route = useRoute() - const router = useRouter() - const routeLocale = useRouteLocale() - - const showModal = ref(false) - - const info = computed(() => { - if (redirectLocaleEntries.some(([key]) => routeLocale.value === key)) - for (const language of languages.value) - for (const [localePath, langs] of redirectLocaleEntries) - if (langs.includes(language)) { - if (localePath === routeLocale.value) return null - - return { - lang: language, - localePath, - } - } - - return null - }) - - const locale = computed(() => { - if (info.value) { - const { lang, localePath } = info.value - const locales = [ - redirectLocales[routeLocale.value], - redirectLocales[localePath], - ] - - return { - hint: locales.map(({ hint }) => hint.replace('$1', lang)), - switch: locales - .map(({ switch: switchText }) => switchText.replace('$1', lang)) - .join(' / '), - cancel: locales.map(({ cancel }) => cancel).join(' / '), - } - } - - return null - }) - - const targetRoute = computed(() => - info.value - ? route.path.replace(routeLocale.value, info.value.localePath) - : null, - ) - - const updateStatus = (): void => { - REDIRECT_LOCALE_STORAGE.value[routeLocale.value] = true - showModal.value = false - } - - onMounted(() => { - const isLocked = useScrollLock(document.body) - - if (!REDIRECT_LOCALE_STORAGE.value[routeLocale.value]) - if (info.value) - if (switchLocale === 'direct') router.replace(targetRoute.value!) - else if (switchLocale === 'modal') showModal.value = true - else showModal.value = false - else showModal.value = false - - watch( - showModal, - (value) => { - isLocked.value = value - }, - { immediate: true }, - ) - - onBeforeUnmount(() => { - isLocked.value = false - }) - }) - - return (): VNode | null => - showModal.value - ? h(TransitionGroup, { name: 'redirect-modal-fade' }, () => - showModal.value - ? h( - 'div', - { key: 'mask', class: 'redirect-modal-mask' }, - h( - 'div', - { - key: 'popup', - class: 'redirect-modal-wrapper', - }, - [ - h( - 'div', - { class: 'redirect-modal-content' }, - locale.value?.hint.map((text) => h('p', text)), - ), - h( - 'button', - { - type: 'button', - class: 'redirect-modal-action primary', - onClick: () => { - updateStatus() - router.replace(targetRoute.value!) - }, - }, - locale.value?.switch, - ), - h( - 'button', - { - type: 'button', - class: 'redirect-modal-action', - onClick: () => updateStatus(), - }, - locale.value?.cancel, - ), - ], - ), - ) - : null, - ) - : null - }, -}) diff --git a/plugins/plugin-redirect/src/client/components/RedirectModal.ts b/plugins/plugin-redirect/src/client/components/RedirectModal.ts new file mode 100644 index 0000000000..b67470016e --- /dev/null +++ b/plugins/plugin-redirect/src/client/components/RedirectModal.ts @@ -0,0 +1,158 @@ +import { + usePreferredLanguages, + useScrollLock, + useSessionStorage, +} from '@vueuse/core' +import type { VNode } from 'vue' +import { + computed, + defineComponent, + h, + nextTick, + onBeforeUnmount, + onMounted, + ref, + TransitionGroup, +} from 'vue' +import { useRoute, useRouteLocale, useRouter } from 'vuepress/client' +import type { RedirectPluginLocaleConfig } from '../../shared/locales.js' +import { redirectLocaleConfig, redirectLocaleEntries } from '../define.js' + +import '../styles/redirect-modal.css' + +declare const __REDIRECT_LOCALES__: RedirectPluginLocaleConfig + +const redirectLocales = __REDIRECT_LOCALES__ +const { switchLocale } = redirectLocaleConfig + +interface LocaleInfo { + lang: string + localePath: string +} + +const redirectStatusStorage = useSessionStorage>( + 'VUEPRESS_REDIRECT_LOCALES', + {}, +) + +export default defineComponent({ + name: 'RedirectModal', + + setup() { + const languages = usePreferredLanguages() + const route = useRoute() + const router = useRouter() + const routeLocale = useRouteLocale() + + const body = ref() + // lock body scroll when modal is displayed + const showModal = useScrollLock(body) + + const info = computed(() => { + if (redirectLocaleEntries.some(([key]) => routeLocale.value === key)) + for (const language of languages.value) + for (const [localePath, langs] of redirectLocaleEntries) + if (langs.includes(language)) { + if (localePath === routeLocale.value) return null + + return { + lang: language, + localePath, + } + } + + return null + }) + + const locale = computed(() => { + if (info.value) { + const { lang, localePath } = info.value + const locales = [ + redirectLocales[routeLocale.value], + redirectLocales[localePath], + ] + + return { + hint: locales.map(({ hint }) => hint.replace('$1', lang)), + switch: locales + .map(({ switch: switchText }) => switchText.replace('$1', lang)) + .join(' / '), + cancel: locales.map(({ cancel }) => cancel).join(' / '), + } + } + + return null + }) + + const redirect = (): void => { + if (info.value) + router.replace( + route.path.replace(routeLocale.value, info.value.localePath), + ) + } + + onMounted(async () => { + body.value = document.body + + await nextTick() + + if (!redirectStatusStorage.value[routeLocale.value]) { + if (switchLocale === 'direct') redirect() + else if (switchLocale === 'modal') showModal.value = true + } + }) + + onBeforeUnmount(() => { + showModal.value = false + }) + + return (): VNode | null => + h(TransitionGroup, { name: 'redirect-modal-fade' }, () => + showModal.value + ? h( + 'div', + { key: 'mask', class: 'redirect-modal-mask' }, + h( + 'div', + { + key: 'popup', + class: 'redirect-modal-wrapper', + }, + [ + h( + 'div', + { class: 'redirect-modal-content' }, + locale.value?.hint.map((text) => h('p', text)), + ), + h( + 'button', + { + type: 'button', + class: 'redirect-modal-action primary', + onClick: () => { + redirectStatusStorage.value[routeLocale.value] = true + showModal.value = false + redirect() + }, + }, + locale.value?.switch, + ), + h( + 'button', + { + type: 'button', + class: 'redirect-modal-action', + onClick: () => { + redirectStatusStorage.value[routeLocale.value] = true + showModal.value = false + }, + }, + locale.value?.cancel, + ), + ], + ), + ) + : null, + ) + }, +}) diff --git a/plugins/plugin-redirect/src/client/config.ts b/plugins/plugin-redirect/src/client/config.ts index 3beb39e044..1a6d1dbdd5 100644 --- a/plugins/plugin-redirect/src/client/config.ts +++ b/plugins/plugin-redirect/src/client/config.ts @@ -1,7 +1,7 @@ import type { ClientConfig } from 'vuepress/client' import { defineClientConfig } from 'vuepress/client' -import LanguageSwitch from './components/LanguageSwitch.js' -import { setupDevServerRedirect } from './composables/setupDevServerRedirect.js' +import RedirectModal from './components/RedirectModal.js' +import { setupDevServerRedirect } from './composables/index.js' import './styles/vars.css' @@ -11,5 +11,5 @@ export default defineClientConfig({ setup() { if (__VUEPRESS_DEV__) setupDevServerRedirect() }, - rootComponents: __REDIRECT_LOCALE_SWITCH__ ? [LanguageSwitch] : [], + rootComponents: __REDIRECT_LOCALE_SWITCH__ ? [RedirectModal] : [], }) as ClientConfig diff --git a/plugins/plugin-redirect/src/client/styles/language-switch.scss b/plugins/plugin-redirect/src/client/styles/redirect-modal.scss similarity index 100% rename from plugins/plugin-redirect/src/client/styles/language-switch.scss rename to plugins/plugin-redirect/src/client/styles/redirect-modal.scss