<script setup>
import HelloWorld from '@/components/HelloWorld.vue'
-import ColorSchemeSwitch from '@/components/ColorSchemeSwitch.vue'
</script>
<template>
<div class="wrapper">
<HelloWorld msg="You did it!" />
- <ColorSchemeSwitch />
<div id="nav">
<router-link to="/">Home</router-link>
--section-gap: 160px;
}
-[data-color-scheme='dark'] {
- --color-background: var(--vt-c-black);
- --color-background-soft: var(--vt-c-black-soft);
- --color-background-mute: var(--vt-c-black-mute);
+@media (prefers-color-scheme: dark) {
+ :root {
+ --color-background: var(--vt-c-black);
+ --color-background-soft: var(--vt-c-black-soft);
+ --color-background-mute: var(--vt-c-black-mute);
- --color-border: var(--vt-c-divider-dark-2);
- --color-border-hover: var(--vt-c-divider-dark-1);
+ --color-border: var(--vt-c-divider-dark-2);
+ --color-border-hover: var(--vt-c-divider-dark-1);
- --color-heading: var(--vt-c-text-dark-1);
- --color-text: var(--vt-c-text-dark-2);
+ --color-heading: var(--vt-c-text-dark-1);
+ --color-text: var(--vt-c-text-dark-2);
+ }
}
*,
+++ /dev/null
-<script setup>
-import IconMoon from './icons/IconMoon.vue'
-import IconSun from './icons/IconSun.vue'
-
-import { watchEffect } from 'vue'
-import useColorScheme from '@/composables/useColorScheme'
-
-const { isDark, toggle } = useColorScheme()
-watchEffect(() => {
- if (isDark.value) {
- window.document.body.setAttribute('data-color-scheme', 'dark')
- } else {
- window.document.body.setAttribute('data-color-scheme', 'light')
- }
-})
-</script>
-
-<template>
- <label class="color-scheme-switch-wrapper">
- <span class="text">Color Scheme:</span>
-
- <button class="color-scheme-switch" @click="toggle">
- <div class="color-scheme-switch-check">
- <div class="color-scheme-switch-icon">
- <IconSun class="color-scheme-switch-svg is-sun" title="light" />
- <IconMoon class="color-scheme-switch-svg is-moon" title="dark" />
- </div>
- </div>
- </button>
- </label>
-</template>
-
-<style>
-.color-scheme-switch-wrapper {
- background-color: var(--color-background-soft);
- border-radius: 8px;
-
- display: flex;
- justify-content: space-between;
-
- margin-top: 2em;
- padding: 12px 14px 12px 16px;
- line-height: 22px;
-
- cursor: pointer;
-}
-
-.color-scheme-switch-wrapper .text {
- font-weight: 500;
- font-size: 12px;
-}
-
-.color-scheme-switch {
- position: relative;
- margin-left: 1em;
-
- border-radius: 11px;
- width: 40px;
- height: 22px;
- flex-shrink: 0;
- border: 1px solid var(--color-border);
- background-color: var(--color-background-mute);
- transition: border-color 0.25s, background-color 0.25s;
-
- cursor: pointer;
-}
-
-.color-scheme-switch:hover {
- border-color: var(--color-border-hover);
-}
-
-.color-scheme-switch-check {
- position: absolute;
- top: 1px;
- left: 1px;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- background-color: var(--color-background);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
- transition: background-color 0.25s, transform 0.25s;
-}
-
-[data-color-scheme='dark'] .color-scheme-switch-check {
- transform: translateX(18px);
-}
-
-.color-scheme-switch-icon {
- position: relative;
- width: 18px;
- height: 18px;
- border-radius: 50%;
- overflow: hidden;
-}
-
-.color-scheme-switch-svg {
- position: absolute;
- top: 3px;
- left: 3px;
- width: 12px;
- height: 12px;
- color: var(--color-heading);
-}
-
-.color-scheme-switch-svg.is-sun {
- opacity: 1;
-}
-.color-scheme-switch-svg.is-moon {
- opacity: 0;
-}
-
-[data-color-scheme='dark'] .color-scheme-switch-svg.is-sun {
- opacity: 0;
-}
-[data-color-scheme='dark'] .color-scheme-switch-svg.is-moon {
- opacity: 1;
-}
-
-[data-color-scheme='dark'] .color-scheme-switch-svg {
- transition: opacity 0.25s;
-}
-
-@media (min-width: 1024px) {
- .color-scheme-switch-wrapper {
- justify-content: left;
- border: none;
- background-color: inherit;
- padding: 0;
- margin-top: 1.2em;
- }
-
- .color-scheme-switch-wrapper .text {
- font-size: 1.2rem;
- font-weight: normal;
- }
-}
-</style>
--- /dev/null
+<script setup>
+import WelcomeItem from './WelcomeItem.vue'
+import DocumentationIcon from './icons/IconDocumentation.vue'
+import ToolingIcon from './icons/IconTooling.vue'
+import EcosystemIcon from './icons/IconEcosystem.vue'
+import CommunityIcon from './icons/IconCommunity.vue'
+import SupportIcon from './icons/IconSupport.vue'
+</script>
+
+<template>
+ <WelcomeItem>
+ <template #icon>
+ <DocumentationIcon />
+ </template>
+ <template #heading>Documentation</template>
+
+ Widely regarded as one of the best, Vue’s
+ <a target="_blank" href="https://v3.vuejs.org/">official documentation</a>
+ will provide you with all information you need to get started. Whether you’re already a Vue
+ veteran or just trying the framework out, great chances are you’ll find the answer to your next
+ question there.
+ </WelcomeItem>
+
+ <WelcomeItem>
+ <template #icon>
+ <ToolingIcon />
+ </template>
+ <template #heading>Tooling</template>
+
+ This project is served and bundled with
+ <a href="https://vitejs.dev/guide/features.html" target="_blank">Vite</a>. The recommended IDE
+ setup is <a href="https://code.visualstudio.com/" target="_blank">VSCode</a> +
+ <a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>. If you need to test
+ your components and web pages, check out
+ <a href="https://www.cypress.io/" target="_blank">Cypress</a> and
+ <a href="https://docs.cypress.io/guides/component-testing/introduction" target="_blank"
+ >Cypress Component Testing</a
+ >.
+
+ <br />
+
+ More instructions are available in <code>README.md</code>.
+ </WelcomeItem>
+
+ <WelcomeItem>
+ <template #icon>
+ <EcosystemIcon />
+ </template>
+ <template #heading>Ecosystem</template>
+
+ Get official tools and libraries for your project:
+ <a target="_blank" href="https://next.vuex.vuejs.org/">Vuex</a>,
+ <a target="_blank" href="https://next.router.vuejs.org/">Vue Router</a>,
+ <a target="_blank" href="https://next.vue-test-utils.vuejs.org/">Vue Test Utils</a>, and
+ <a target="_blank" href="https://github.com/vuejs/devtools">Vue Dev Tools</a>. If you need more
+ resources, we suggest paying
+ <a target="_blank" href="https://github.com/vuejs/awesome-vue">Awesome Vue</a>
+ a visit.
+ </WelcomeItem>
+
+ <WelcomeItem>
+ <template #icon>
+ <CommunityIcon />
+ </template>
+ <template #heading>Community</template>
+
+ Got stuck? Ask your question on
+ <a target="_blank" href="https://chat.vuejs.org">Vue Land</a>, our official Discord server, or
+ <a target="_blank" href="https://stackoverflow.com/questions/tagged/vue.js">StackOverflow</a>.
+ You should also subscribe to
+ <a target="_blank" href="https://news.vuejs.org">our mailing list</a> for latest news in the Vue
+ world.
+ </WelcomeItem>
+
+ <WelcomeItem>
+ <template #icon>
+ <SupportIcon />
+ </template>
+ <template #heading>Support Vue</template>
+
+ As an independent project, Vue relies on community backing for its sustainability. You can help
+ us by
+ <a target="_blank" href="https://vuejs.org/support-vuejs/">becoming a sponsor</a>.
+ </WelcomeItem>
+</template>
+++ /dev/null
-import { mount } from '@cypress/vue'
-
-import ColorSchemeSwitch from '../ColorSchemeSwitch.vue'
-
-describe('ColorSchemeSwitch', () => {
- beforeEach(() => {
- cy.stub(window, 'matchMedia')
- .withArgs('(prefers-color-scheme: light)')
- .returns({
- matches: false,
- addEventListener: () => {},
- removeEventListener: () => {},
- })
- .withArgs('(prefers-color-scheme: dark)')
- .returns({
- matches: true,
- addEventListener: () => {},
- removeEventListener: () => {},
- })
- })
-
- it('use the preferred color scheme by default', () => {
- mount(ColorSchemeSwitch)
-
- cy.get('body').should('have.attr', 'data-color-scheme', 'dark')
- })
-
- it('toggles the color scheme affter user clicks toggle', () => {
- mount(ColorSchemeSwitch)
-
- cy.get('.color-scheme-switch').click()
- cy.get('body').should('have.attr', 'data-color-scheme', 'light')
- })
-})
+++ /dev/null
-<script setup lang="ts">
-defineProps<{ title: string }>()
-</script>
-
-<template>
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="currentColor"
- >
- <title>{{ title }}</title>
- <path
- d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"
- />
- </svg>
-</template>
+++ /dev/null
-<script setup lang="ts">
-defineProps<{ title: string }>()
-</script>
-
-<template>
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="24"
- height="24"
- viewBox="0 0 24 24"
- fill="currentColor"
- >
- <title>{{ title }}</title>
- <path
- d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"
- />
- <path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z" />
- <path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z" />
- <path
- d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"
- />
- <path
- d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"
- />
- <path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z" />
- <path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z" />
- <path
- d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"
- />
- <path
- d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"
- />
- </svg>
-</template>
+++ /dev/null
-import { defineComponent, h, createVNode } from 'vue'
-import { mount } from '@cypress/vue'
-
-import useMediaQuery from '../useMediaQuery'
-
-const Wrapper = defineComponent({
- props: {
- query: {
- type: String,
- required: true
- }
- },
- setup(props) {
- const matches = useMediaQuery(props.query)
- return () => h('div', { id: 'result' }, matches.value.toString() )
- }
-})
-
-describe('useMediaQuery', () => {
- it('should correctly reflect the match result of a media query', () => {
- mount(Wrapper, {
- props: {
- query: '(min-width: 800px)'
- }
- })
-
- cy.viewport(1000, 660)
- cy.get('#result').should('include.text', 'true')
-
- cy.viewport(660, 660)
- cy.get('#result').should('include.text', 'false')
- })
-})
+++ /dev/null
-import { ref, computed } from 'vue'
-import useMediaQuery from './useMediaQuery'
-
-// Its value should be consistent when called multiple times.
-// So we put it outside the composable function
-const isUserToggledDark = ref()
-
-export default function useColorScheme() {
- const isDefaultDark = useMediaQuery('(prefers-color-scheme: dark)')
-
- const isDark = computed(() => {
- if (typeof isUserToggledDark.value !== 'undefined') {
- return isUserToggledDark.value
- } else {
- return isDefaultDark.value
- }
- })
-
- const toggle = () => {
- if (typeof isUserToggledDark.value !== 'undefined') {
- isUserToggledDark.value = !isUserToggledDark.value
- } else {
- isUserToggledDark.value = !isDefaultDark.value
- }
- }
-
- return {
- toggle,
- isDark
- }
-}
+++ /dev/null
-import { ref, onUnmounted } from 'vue'
-
-export default function useMediaQuery(query) {
- const mediaQueryList = window.matchMedia(query)
- const matches = ref(mediaQueryList.matches)
-
- const handler = (event) => {
- matches.value = event.matches
- }
-
- // Safari < 14 does not support this
- if (mediaQueryList.addEventListener) {
- mediaQueryList.addEventListener('change', handler)
- } else {
- mediaQueryList.addListener(handler)
- }
-
- onUnmounted(() => {
- // Safari < 14 does not support this
- if (mediaQueryList.removeEventListener) {
- mediaQueryList.removeEventListener('change', handler)
- } else {
- mediaQueryList.removeListener(handler)
- }
- })
-
- return matches
-}
-<script setup>
-import IntroductionItem from '@/components/IntroductionItem.vue'
-
-import DocumentationIcon from '@/components/icons/IconDocumentation.vue'
-import ToolingIcon from '@/components/icons/IconTooling.vue'
-import EcosystemIcon from '@/components/icons/IconEcosystem.vue'
-import CommunityIcon from '@/components/icons/IconCommunity.vue'
-import SupportIcon from '@/components/icons/IconSupport.vue'
+<script setup lang="ts">
+import Welcome from '@/components/Welcome.vue'
</script>
<template>
<main>
- <IntroductionItem>
- <template #icon>
- <DocumentationIcon />
- </template>
- <template #heading>Documentation</template>
-
- Widely regarded as one of the best, Vue’s
- <a target="_blank" href="https://v3.vuejs.org/">official documentation</a>
- will provide you with all information you need to get started. Whether you’re already a Vue
- veteran or just trying the framework out, great chances are you’ll find the answer to your
- next question there.
- </IntroductionItem>
-
- <IntroductionItem>
- <template #icon>
- <ToolingIcon />
- </template>
- <template #heading>Tooling</template>
-
- This project is served and bundled with
- <a href="https://vitejs.dev/guide/features.html" target="_blank">Vite</a>. The recommended IDE
- setup is <a href="https://code.visualstudio.com/" target="_blank">VSCode</a> +
- <a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>. If you need to
- test your components and web pages, check out
- <a href="https://www.cypress.io/" target="_blank">Cypress</a> and
- <a href="https://docs.cypress.io/guides/component-testing/introduction" target="_blank"
- >Cypress Component Testing</a
- >.
-
- <br />
-
- More instructions are available in <code>README.md</code>.
- </IntroductionItem>
-
- <IntroductionItem>
- <template #icon>
- <EcosystemIcon />
- </template>
- <template #heading>Ecosystem</template>
-
- Get official tools and libraries for your project:
- <a target="_blank" href="https://next.vuex.vuejs.org/">Vuex</a>,
- <a target="_blank" href="https://next.router.vuejs.org/">Vue Router</a>,
- <a target="_blank" href="https://next.vue-test-utils.vuejs.org/">Vue Test Utils</a>, and
- <a target="_blank" href="https://github.com/vuejs/devtools">Vue Dev Tools</a>. If you need
- more resources, we suggest paying
- <a target="_blank" href="https://github.com/vuejs/awesome-vue">Awesome Vue</a>
- a visit.
- </IntroductionItem>
-
- <IntroductionItem>
- <template #icon>
- <CommunityIcon />
- </template>
- <template #heading>Community</template>
-
- Got stuck? Ask your question on
- <a target="_blank" href="https://chat.vuejs.org">Vue Land</a>, our official Discord server, or
- <a target="_blank" href="https://stackoverflow.com/questions/tagged/vue.js">StackOverflow</a>.
- You should also subscribe to
- <a target="_blank" href="https://news.vuejs.org">our mailing list</a> for latest news in the
- Vue world.
- </IntroductionItem>
-
- <IntroductionItem>
- <template #icon>
- <SupportIcon />
- </template>
- <template #heading>Support Vue</template>
-
- As an independent project, Vue relies on community backing for its sustainability. You can
- help us by
- <a target="_blank" href="https://vuejs.org/support-vuejs/">becoming a sponsor</a>.
- </IntroductionItem>
+ <Welcome />
</main>
</template>