+
-
+
-
+
?
+ >?
@@ -109,8 +72,7 @@ function useToggleFn(
title="About SFC"
href="/guide/scaling-up/sfc.html"
@click="closeSideBar"
- >?
+ >?
diff --git a/.vitepress/theme/components/preferences.ts b/.vitepress/theme/components/preferences.ts
deleted file mode 100644
index e67279e9d9..0000000000
--- a/.vitepress/theme/components/preferences.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { ref } from 'vue'
-import { AugmentedHeader } from '../../headerMdPlugin'
-
-const hasStorage = typeof localStorage !== 'undefined'
-const get = (key: string, defaultValue = false): boolean =>
- hasStorage
- ? JSON.parse(localStorage.getItem(key) || String(defaultValue))
- : defaultValue
-
-export const preferCompositionKey = 'vue-docs-prefer-composition'
-export const preferComposition = ref(get(preferCompositionKey))
-
-export const preferSFCKey = 'vue-docs-prefer-sfc'
-export const preferSFC = ref(get(preferSFCKey, true))
-
-export function filterHeadersByPreference(h: AugmentedHeader) {
- return preferComposition.value ? !h.optionsOnly : !h.compositionOnly
-}
diff --git a/.vitepress/theme/composables/usePlatform.ts b/.vitepress/theme/composables/usePlatform.ts
new file mode 100644
index 0000000000..d9947699a0
--- /dev/null
+++ b/.vitepress/theme/composables/usePlatform.ts
@@ -0,0 +1,9 @@
+export default function usePlatform() {
+ const isMac = /(Mac OS X)/i.test(globalThis.navigator?.userAgent)
+ const altKey = isMac ? 'Option' : 'Alt';
+
+ return {
+ isMac,
+ altKey
+ }
+}
\ No newline at end of file
diff --git a/.vitepress/theme/composables/usePreferences.ts b/.vitepress/theme/composables/usePreferences.ts
new file mode 100644
index 0000000000..32ec8a1b4d
--- /dev/null
+++ b/.vitepress/theme/composables/usePreferences.ts
@@ -0,0 +1,115 @@
+import { AugmentedHeader } from '.vitepress/headerMdPlugin'
+import { useRoute } from 'vitepress'
+import { computed, onMounted, onUnmounted, Ref, ref } from 'vue'
+
+import usePlatform from './usePlatform'
+
+const hasStorage = typeof localStorage !== 'undefined'
+const get = (key: string, defaultValue = false): boolean =>
+ hasStorage
+ ? JSON.parse(localStorage.getItem(key) || String(defaultValue))
+ : defaultValue
+
+const preferCompositionKey = 'vue-docs-prefer-composition'
+export const preferComposition = ref(get(preferCompositionKey))
+
+const preferSFCKey = 'vue-docs-prefer-sfc'
+export const preferSFC = ref(get(preferSFCKey, true))
+
+export function filterHeadersByPreference(h: AugmentedHeader) {
+ return preferComposition.value ? !h.optionsOnly : !h.compositionOnly
+}
+
+export default function usePreferences() {
+ const route = useRoute()
+ const showPreference = computed(() =>
+ /^\/(guide|tutorial|examples)\//.test(route.path)
+ )
+ const { altKey } = usePlatform()
+
+ const shortcutInfo = computed(() => `Ctrl+${altKey}+A: toggle API preference`)
+
+ const isOpen = ref(
+ typeof localStorage !== 'undefined' &&
+ !localStorage.getItem(preferCompositionKey)
+ )
+
+ const toggleOpen = () => {
+ isOpen.value = !isOpen.value
+ }
+
+ const toggleCompositionAPI = useToggleFn(
+ preferCompositionKey,
+ preferComposition,
+ 'prefer-composition'
+ )
+ const toggleSFC = useToggleFn(preferSFCKey, preferSFC, 'prefer-sfc')
+
+ function useToggleFn(
+ storageKey: string,
+ state: Ref
,
+ className: string
+ ) {
+ if (typeof localStorage === 'undefined') {
+ return () => {}
+ }
+ const classList = document.documentElement.classList
+ return (value = !state.value) => {
+ if ((state.value = value)) {
+ classList.add(className)
+ } else {
+ classList.remove(className)
+ }
+ localStorage.setItem(storageKey, String(state.value))
+ }
+ }
+
+ let closeTimeout: any
+ let hasInitiallyBeenOpenByKeyboard = false
+ const onPreferenceKeyupChange = (callback: Function) => {
+ clearTimeout(closeTimeout)
+ if (!isOpen.value) {
+ isOpen.value = true // Open preference to see what is changed.
+ hasInitiallyBeenOpenByKeyboard = true
+ setTimeout(() => {
+ // Defer the toggle a bit to be able to see the change
+ callback()
+ }, 100)
+ } else {
+ callback()
+ }
+ if (hasInitiallyBeenOpenByKeyboard) {
+ // Close automatically when it was initially opened by shortcut
+ closeTimeout = setTimeout(() => {
+ // Close after 5 seconds
+ isOpen.value = false
+ hasInitiallyBeenOpenByKeyboard = false
+ }, 5000)
+ }
+ }
+
+ const preferenceKeyupHandler = (e: KeyboardEvent) => {
+ if (e.altKey && e.ctrlKey && showPreference.value) {
+ if (e.keyCode === 65) {
+ // Ctrl+Alt+A + preference switch available
+ onPreferenceKeyupChange(toggleCompositionAPI)
+ }
+ }
+ }
+
+ onMounted(() => {
+ document.addEventListener('keyup', preferenceKeyupHandler)
+ })
+ onUnmounted(() => {
+ document.removeEventListener('keyup', preferenceKeyupHandler)
+ })
+
+ return {
+ isOpen,
+ shortcutInfo,
+ showPreference,
+ toggleOpen,
+ toggleCompositionAPI,
+ toggleSFC
+ }
+}
diff --git a/.vitepress/theme/index.ts b/.vitepress/theme/index.ts
index 171dd6a6ae..bffb6ea125 100644
--- a/.vitepress/theme/index.ts
+++ b/.vitepress/theme/index.ts
@@ -1,14 +1,14 @@
import './styles/index.css'
import { h, App } from 'vue'
import { VPTheme } from '@vue/theme'
-import PreferenceSwitch from './components/PreferenceSwitch.vue'
import {
preferComposition,
preferSFC,
filterHeadersByPreference
-} from './components/preferences'
+} from './composables/usePreferences'
import SponsorsAside from './components/SponsorsAside.vue'
import VueJobs from './components/VueJobs.vue'
+import PreferenceSwitch from './components/PreferenceSwitch.vue'
import VueSchoolLink from './components/VueSchoolLink.vue'
import Banner from './components/Banner.vue'
diff --git a/src/guide/introduction.md b/src/guide/introduction.md
index 891bb9a541..6bf6ab9cf9 100644
--- a/src/guide/introduction.md
+++ b/src/guide/introduction.md
@@ -213,7 +213,14 @@ If you are new to Vue, here's our general recommendation:
- Go with Composition API + Single-File Components if you plan to build full applications with Vue.
-You don't have to commit to only one style during the learning phase. The rest of the documentation will provide code samples in both styles where applicable, and you can toggle between them at any time using the **API Preference switches** at the top of the left sidebar.
+You don't have to commit to only one style during the learning phase. The rest of the documentation will provide code samples in both styles where applicable, and you can toggle between them at any time using the **API Preference switches** at the top of the left sidebar.
+
+
+
+> You can use following shortcut to switch between API Preferences: `Ctrl+{{altKey}}+A`
## Still Got Questions?