├── .dockerignore ├── .editorconfig ├── .eslintrc ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json └── settings.json ├── Dockerfile ├── LICENSE ├── README.md ├── README.zh-CN.md ├── cypress.config.ts ├── cypress ├── e2e │ └── basic.spec.ts └── tsconfig.json ├── index.html ├── locales ├── README.md ├── ar.yml ├── de.yml ├── en.yml ├── es.yml ├── fr.yml ├── id.yml ├── it.yml ├── ja.yml ├── ko.yml ├── pl.yml ├── pt-BR.yml ├── ru.yml ├── tr.yml ├── vi.yml └── zh-CN.yml ├── netlify.toml ├── package.json ├── pnpm-lock.yaml ├── public ├── _headers ├── favicon-dark.svg ├── favicon.svg ├── pwa-192x192.png ├── pwa-512x512.png └── safari-pinned-tab.svg ├── src ├── App.vue ├── auto-imports.d.ts ├── components.d.ts ├── components │ ├── Counter.vue │ ├── Footer.vue │ └── README.md ├── composables │ └── dark.ts ├── layouts │ ├── 404.vue │ ├── README.md │ ├── default.vue │ └── home.vue ├── main.ts ├── modules │ ├── README.md │ ├── i18n.ts │ ├── nprogress.ts │ ├── pinia.ts │ └── pwa.ts ├── pages │ ├── README.md │ ├── [...all].vue │ ├── about.md │ ├── hi │ │ ├── [name].vue │ │ └── static.vue │ ├── index.vue │ └── welcome.md ├── shims.d.ts ├── store │ └── user.ts ├── styles │ ├── main.css │ └── markdown.css └── types.ts ├── test ├── __snapshots__ │ └── component.test.ts.snap ├── basic.test.ts └── component.test.ts ├── tsconfig.json ├── typed-router.d.ts ├── unocss.config.ts └── vite.config.ts /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@antfu" 3 | } 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: antfu 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: pnpm/action-setup@v2 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: 16.x 21 | cache: pnpm 22 | 23 | - name: Install 24 | run: pnpm install 25 | 26 | - name: Lint 27 | run: pnpm run lint 28 | 29 | typecheck: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v3 33 | - uses: pnpm/action-setup@v2 34 | - uses: actions/setup-node@v3 35 | with: 36 | node-version: 16.x 37 | cache: pnpm 38 | 39 | - name: Install 40 | run: pnpm install 41 | 42 | - name: Typecheck 43 | run: pnpm run typecheck 44 | 45 | test: 46 | runs-on: ${{ matrix.os }} 47 | 48 | strategy: 49 | matrix: 50 | node-version: [14.x, 16.x] 51 | os: [ubuntu-latest] 52 | fail-fast: false 53 | 54 | steps: 55 | - uses: actions/checkout@v3 56 | - uses: pnpm/action-setup@v2 57 | - name: Use Node.js ${{ matrix.node-version }} 58 | uses: actions/setup-node@v3 59 | with: 60 | node-version: ${{ matrix.node-version }} 61 | registry-url: https://registry.npmjs.org/ 62 | cache: pnpm 63 | 64 | - run: pnpm install 65 | - run: pnpm run test:unit 66 | 67 | test-e2e: 68 | runs-on: ubuntu-latest 69 | steps: 70 | - uses: actions/checkout@v3 71 | - uses: actions/cache@v3 72 | with: 73 | path: | 74 | ~/.cache 75 | key: cypress-cache-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} 76 | 77 | - uses: pnpm/action-setup@v2 78 | 79 | - name: Use Node.js ${{ matrix.node-version }} 80 | uses: actions/setup-node@v3 81 | with: 82 | node-version: ${{ matrix.node-version }} 83 | registry-url: https://registry.npmjs.org/ 84 | cache: pnpm 85 | 86 | - run: pnpm install 87 | 88 | - name: Cypress PNPM Patch 89 | run: cp pnpm-lock.yaml package-lock.json 90 | 91 | - name: Cypress 92 | uses: cypress-io/github-action@v4 93 | with: 94 | install-command: echo 95 | build: pnpm run build 96 | start: npx vite --port 3333 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vite-ssg-dist 3 | .vite-ssg-temp 4 | *.local 5 | dist 6 | dist-ssr 7 | node_modules 8 | .idea/ 9 | *.log 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "antfu.iconify", 4 | "antfu.unocss", 5 | "antfu.vite", 6 | "antfu.goto-alias", 7 | "csstools.postcss", 8 | "dbaeumer.vscode-eslint", 9 | "vue.volar", 10 | "lokalise.i18n-ally", 11 | "streetsidesoftware.code-spell-checker" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Vitesse", 4 | "Vite", 5 | "unocss", 6 | "vitest", 7 | "vueuse", 8 | "pinia", 9 | "demi", 10 | "antfu", 11 | "iconify", 12 | "intlify", 13 | "vitejs", 14 | "unplugin", 15 | "pnpm" 16 | ], 17 | "i18n-ally.sourceLanguage": "en", 18 | "i18n-ally.keystyle": "nested", 19 | "i18n-ally.localesPaths": "locales", 20 | "i18n-ally.sortKeys": true, 21 | "prettier.enable": false, 22 | "editor.codeActionsOnSave": { 23 | "source.fixAll.eslint": true 24 | }, 25 | "files.associations": { 26 | "*.css": "postcss" 27 | }, 28 | "editor.formatOnSave": false, 29 | "typescript.preferences.autoImportFileExcludePatterns": ["vue-router"] 30 | } 31 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16-alpine as build-stage 2 | 3 | WORKDIR /app 4 | RUN corepack enable 5 | 6 | COPY .npmrc package.json pnpm-lock.yaml ./ 7 | RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store \ 8 | pnpm install --frozen-lockfile 9 | 10 | COPY . . 11 | RUN pnpm build 12 | 13 | FROM nginx:stable-alpine as production-stage 14 | 15 | COPY --from=build-stage /app/dist /usr/share/nginx/html 16 | EXPOSE 80 17 | 18 | CMD ["nginx", "-g", "daemon off;"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 Anthony Fu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Vitesse - Opinionated Vite Starter Template 3 |

4 | 5 |

6 | Mocking up web app with Vitesse(speed)
7 |

8 | 9 |
10 | 11 |

12 | Live Demo 13 |

14 | 15 |
16 | 17 |

18 | English | 简体中文 19 | 20 |

21 | 22 |
23 | 24 | 25 | ## Features 26 | 27 | - ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite 3](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [ESBuild](https://github.com/evanw/esbuild) - born with fastness 28 | 29 | - 🗂 [File based routing](./src/pages) 30 | 31 | - 📦 [Components auto importing](./src/components) 32 | 33 | - 🍍 [State Management via Pinia](https://pinia.vuejs.org/) 34 | 35 | - 📑 [Layout system](./src/layouts) 36 | 37 | - 📲 [PWA](https://github.com/antfu/vite-plugin-pwa) 38 | 39 | - 🎨 [UnoCSS](https://github.com/antfu/unocss) - the instant on-demand atomic CSS engine 40 | 41 | - 😃 [Use icons from any icon sets with classes](https://github.com/antfu/unocss/tree/main/packages/preset-icons) 42 | 43 | - 🌍 [I18n ready](./locales) 44 | 45 | - 🔎 [Component Preview](https://github.com/johnsoncodehk/vite-plugin-vue-component-preview) 46 | 47 | - 🗒 [Markdown Support](https://github.com/antfu/vite-plugin-vue-markdown) 48 | 49 | - 🔥 Use the [new ` 17 | 18 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /locales/README.md: -------------------------------------------------------------------------------- 1 | ## i18n 2 | 3 | This directory is to serve your locale translation files. YAML under this folder would be loaded automatically and register with their filenames as locale code. 4 | 5 | Check out [`vue-i18n`](https://github.com/intlify/vue-i18n-next) for more details. 6 | 7 | If you are using VS Code, [`i18n Ally`](https://github.com/lokalise/i18n-ally) is recommended to make the i18n experience better. 8 | -------------------------------------------------------------------------------- /locales/ar.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: حول 3 | back: رجوع 4 | go: تجربة 5 | home: الرئيسية 6 | toggle_dark: التغيير إلى الوضع المظلم 7 | toggle_langs: تغيير اللغة 8 | intro: 9 | desc: vite مثال لتطبيق 10 | dynamic-route: عرض لتوجيهات ديناميكية 11 | hi: مرحبا {name} 12 | aka: معروف أيضا تحت مسمى 13 | whats-your-name: ما إسمك؟ 14 | not-found: صفحة غير موجودة 15 | -------------------------------------------------------------------------------- /locales/de.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Über 3 | back: Zurück 4 | go: Los 5 | home: Startseite 6 | toggle_dark: Dunkelmodus umschalten 7 | toggle_langs: Sprachen ändern 8 | intro: 9 | desc: Vite Startvorlage mit Vorlieben 10 | dynamic-route: Demo einer dynamischen Route 11 | hi: Hi, {name}! 12 | aka: Auch bekannt als 13 | whats-your-name: Wie heißt du? 14 | not-found: Nicht gefunden 15 | -------------------------------------------------------------------------------- /locales/en.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: About 3 | back: Back 4 | go: GO 5 | home: Home 6 | toggle_dark: Toggle dark mode 7 | toggle_langs: Change languages 8 | intro: 9 | desc: Opinionated Vite Starter Template 10 | dynamic-route: Demo of dynamic route 11 | hi: Hi, {name}! 12 | aka: Also known as 13 | whats-your-name: What's your name? 14 | not-found: Not found 15 | -------------------------------------------------------------------------------- /locales/es.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Acerca de 3 | back: Atrás 4 | go: Ir 5 | home: Inicio 6 | toggle_dark: Alternar modo oscuro 7 | toggle_langs: Cambiar idiomas 8 | intro: 9 | desc: Plantilla de Inicio de Vite Dogmática 10 | dynamic-route: Demo de ruta dinámica 11 | hi: ¡Hola, {name}! 12 | aka: También conocido como 13 | whats-your-name: ¿Cómo te llamas? 14 | not-found: No se ha encontrado 15 | -------------------------------------------------------------------------------- /locales/fr.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: À propos 3 | back: Retour 4 | go: Essayer 5 | home: Accueil 6 | toggle_dark: Basculer en mode sombre 7 | toggle_langs: Changer de langue 8 | intro: 9 | desc: Exemple d'application Vite 10 | dynamic-route: Démo de route dynamique 11 | hi: Salut, {name}! 12 | aka: Aussi connu sous le nom de 13 | whats-your-name: Comment t'appelles-tu ? 14 | not-found: Page non trouvée 15 | -------------------------------------------------------------------------------- /locales/id.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Tentang 3 | back: Kembali 4 | go: Pergi 5 | home: Beranda 6 | toggle_dark: Ubah ke mode gelap 7 | toggle_langs: Ubah bahasa 8 | intro: 9 | desc: Template awal vite 10 | dynamic-route: Contoh rute dinamik 11 | hi: Halo, {name}! 12 | aka: Juga diketahui sebagai 13 | whats-your-name: Siapa nama anda? 14 | not-found: Tidak ditemukan 15 | -------------------------------------------------------------------------------- /locales/it.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Su di me 3 | back: Indietro 4 | go: Vai 5 | home: Home 6 | toggle_dark: Attiva/disattiva modalità scura 7 | toggle_langs: Cambia lingua 8 | intro: 9 | desc: Modello per una Applicazione Vite 10 | dynamic-route: Demo di rotta dinamica 11 | hi: Ciao, {name}! 12 | whats-your-name: Come ti chiami? 13 | not-found: Non trovato 14 | -------------------------------------------------------------------------------- /locales/ja.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: これは? 3 | back: 戻る 4 | go: 進む 5 | home: ホーム 6 | toggle_dark: ダークモード切り替え 7 | toggle_langs: 言語切り替え 8 | intro: 9 | desc: 固執された Vite スターターテンプレート 10 | dynamic-route: 動的ルートのデモ 11 | hi: こんにちは、{name}! 12 | whats-your-name: 君の名は。 13 | not-found: 見つかりませんでした 14 | -------------------------------------------------------------------------------- /locales/ko.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: 소개 3 | back: 뒤로가기 4 | go: 이동 5 | home: 홈 6 | toggle_dark: 다크모드 토글 7 | toggle_langs: 언어 변경 8 | intro: 9 | desc: Vite 애플리케이션 템플릿 10 | dynamic-route: 다이나믹 라우트 데모 11 | hi: 안녕, {name}! 12 | whats-your-name: 이름이 뭐예요? 13 | not-found: 찾을 수 없습니다 14 | -------------------------------------------------------------------------------- /locales/pl.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: O nas 3 | back: Wróć 4 | go: WEJDŹ 5 | home: Strona główna 6 | toggle_dark: Ustaw tryb nocny 7 | toggle_langs: Zmień język 8 | intro: 9 | desc: Opiniowany szablon startowy Vite 10 | dynamic-route: Demonstracja dynamicznego route 11 | hi: Cześć, {name}! 12 | aka: Znany też jako 13 | whats-your-name: Jak masz na imię? 14 | not-found: Nie znaleziono 15 | -------------------------------------------------------------------------------- /locales/pt-BR.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Sobre 3 | back: Voltar 4 | go: Ir 5 | home: Início 6 | toggle_dark: Alternar modo escuro 7 | toggle_langs: Mudar de idioma 8 | intro: 9 | desc: Modelo Opinativo de Partida de Vite 10 | dynamic-route: Demonstração de rota dinâmica 11 | hi: Olá, {name}! 12 | aka: Também conhecido como 13 | whats-your-name: Qual é o seu nome? 14 | not-found: Não encontrado 15 | -------------------------------------------------------------------------------- /locales/ru.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: О шаблоне 3 | back: Назад 4 | go: Перейти 5 | home: Главная 6 | toggle_dark: Включить темный режим 7 | toggle_langs: Сменить язык 8 | intro: 9 | desc: Самостоятельный начальный шаблон Vite 10 | dynamic-route: Демо динамического маршрута 11 | hi: Привет, {name}! 12 | whats-your-name: Как тебя зовут? 13 | not-found: Не найден 14 | -------------------------------------------------------------------------------- /locales/tr.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Hakkımda 3 | back: Geri 4 | go: İLERİ 5 | home: Anasayfa 6 | toggle_dark: Karanlık modu değiştir 7 | toggle_langs: Dilleri değiştir 8 | intro: 9 | desc: Görüşlü Vite Başlangıç Şablonu 10 | dynamic-route: Dinamik rota demosu 11 | hi: Merhaba, {name}! 12 | aka: Ayrıca şöyle bilinir 13 | whats-your-name: Adınız nedir? 14 | not-found: Bulunamadı 15 | -------------------------------------------------------------------------------- /locales/vi.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: Về 3 | back: Quay lại 4 | go: Đi 5 | home: Khởi đầu 6 | toggle_dark: Chuyển đổi chế độ tối 7 | toggle_langs: Thay đổi ngôn ngữ 8 | intro: 9 | desc: Ý kiến cá nhân Vite Template để bắt đầu 10 | dynamic-route: Bản giới thiệu về dynamic route 11 | hi: Hi, {name}! 12 | whats-your-name: Tên bạn là gì? 13 | not-found: Không tìm thấy 14 | -------------------------------------------------------------------------------- /locales/zh-CN.yml: -------------------------------------------------------------------------------- 1 | button: 2 | about: 关于 3 | back: 返回 4 | go: 确定 5 | home: 首页 6 | toggle_dark: 切换深色模式 7 | toggle_langs: 切换语言 8 | intro: 9 | desc: 固执己见的 Vite 项目模板 10 | dynamic-route: 动态路由演示 11 | hi: 你好,{name} 12 | aka: 也叫 13 | whats-your-name: 输入你的名字 14 | not-found: 未找到页面 15 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | # bypass npm auto install 3 | NPM_FLAGS = "--version" 4 | NODE_VERSION = "16" 5 | 6 | [build] 7 | publish = "dist" 8 | command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build" 9 | 10 | [[redirects]] 11 | from = "/*" 12 | to = "/index.html" 13 | status = 200 14 | 15 | [[headers]] 16 | for = "/manifest.webmanifest" 17 | [headers.values] 18 | Content-Type = "application/manifest+json" 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "private": true, 4 | "packageManager": "pnpm@7.8.0", 5 | "scripts": { 6 | "build": "vite-ssg build", 7 | "dev": "vite --port 3333 --open", 8 | "lint": "eslint .", 9 | "preview": "vite preview", 10 | "preview-https": "serve dist", 11 | "test": "vitest", 12 | "test:e2e": "cypress open", 13 | "test:unit": "vitest", 14 | "typecheck": "vue-tsc --noEmit", 15 | "up": "taze major -I" 16 | }, 17 | "dependencies": { 18 | "@unocss/reset": "^0.45.26", 19 | "@vueuse/core": "^9.3.0", 20 | "@vueuse/head": "^0.7.12", 21 | "nprogress": "^0.2.0", 22 | "pinia": "^2.0.22", 23 | "vue": "^3.2.40", 24 | "vue-demi": "^0.13.11", 25 | "vue-i18n": "^9.2.2", 26 | "vue-router": "^4.1.5" 27 | }, 28 | "devDependencies": { 29 | "@antfu/eslint-config": "^0.27.0", 30 | "@iconify-json/carbon": "^1.1.8", 31 | "@intlify/vite-plugin-vue-i18n": "^6.0.3", 32 | "@types/markdown-it-link-attributes": "^3.0.1", 33 | "@types/nprogress": "^0.2.0", 34 | "@vitejs/plugin-vue": "^3.1.0", 35 | "@vue/test-utils": "^2.1.0", 36 | "critters": "^0.0.16", 37 | "cross-env": "^7.0.3", 38 | "cypress": "^10.9.0", 39 | "eslint": "^8.24.0", 40 | "eslint-plugin-cypress": "^2.12.1", 41 | "https-localhost": "^4.7.1", 42 | "markdown-it-link-attributes": "^4.0.1", 43 | "markdown-it-shiki": "^0.5.1", 44 | "shiki": "^0.11.1", 45 | "taze": "^0.8.2", 46 | "typescript": "^4.8.4", 47 | "unocss": "^0.45.26", 48 | "unplugin-auto-import": "^0.11.2", 49 | "unplugin-vue-components": "^0.22.7", 50 | "unplugin-vue-router": "^0.2.3", 51 | "vite": "^3.1.4", 52 | "vite-plugin-inspect": "^0.7.4", 53 | "vite-plugin-pwa": "^0.13.1", 54 | "vite-plugin-vue-component-preview": "^0.3.3", 55 | "vite-plugin-vue-layouts": "^0.7.0", 56 | "vite-plugin-vue-markdown": "^0.22.1", 57 | "vite-ssg": "^0.20.2", 58 | "vite-ssg-sitemap": "^0.4.3", 59 | "vitest": "^0.23.4", 60 | "vue-tsc": "^0.40.13" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /public/_headers: -------------------------------------------------------------------------------- 1 | /assets/* 2 | cache-control: max-age=31536000 3 | cache-control: immutable 4 | -------------------------------------------------------------------------------- /public/favicon-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/pwa-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/posva/unplugin-vue-router-demo/781f60486710ba2b9db07d8ebf97ba3f7137d24e/public/pwa-192x192.png -------------------------------------------------------------------------------- /public/pwa-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/posva/unplugin-vue-router-demo/781f60486710ba2b9db07d8ebf97ba3f7137d24e/public/pwa-512x512.png -------------------------------------------------------------------------------- /public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /src/auto-imports.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by 'unplugin-auto-import' 2 | export {} 3 | declare global { 4 | const $$: typeof import('vue/macros')['$$'] 5 | const $: typeof import('vue/macros')['$'] 6 | const $computed: typeof import('vue/macros')['$computed'] 7 | const $customRef: typeof import('vue/macros')['$customRef'] 8 | const $ref: typeof import('vue/macros')['$ref'] 9 | const $shallowRef: typeof import('vue/macros')['$shallowRef'] 10 | const $toRef: typeof import('vue/macros')['$toRef'] 11 | const EffectScope: typeof import('vue')['EffectScope'] 12 | const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] 13 | const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] 14 | const computed: typeof import('vue')['computed'] 15 | const computedAsync: typeof import('@vueuse/core')['computedAsync'] 16 | const computedEager: typeof import('@vueuse/core')['computedEager'] 17 | const computedInject: typeof import('@vueuse/core')['computedInject'] 18 | const computedWithControl: typeof import('@vueuse/core')['computedWithControl'] 19 | const controlledComputed: typeof import('@vueuse/core')['controlledComputed'] 20 | const controlledRef: typeof import('@vueuse/core')['controlledRef'] 21 | const createApp: typeof import('vue')['createApp'] 22 | const createEventHook: typeof import('@vueuse/core')['createEventHook'] 23 | const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] 24 | const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] 25 | const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] 26 | const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] 27 | const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] 28 | const customRef: typeof import('vue')['customRef'] 29 | const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] 30 | const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch'] 31 | const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] 32 | const defineComponent: typeof import('vue')['defineComponent'] 33 | const defineLoader: typeof import('vue-router/auto')['defineLoader'] 34 | const definePage: typeof import('unplugin-vue-router/runtime')['_definePage'] 35 | const eagerComputed: typeof import('@vueuse/core')['eagerComputed'] 36 | const effectScope: typeof import('vue')['effectScope'] 37 | const extendRef: typeof import('@vueuse/core')['extendRef'] 38 | const getCurrentInstance: typeof import('vue')['getCurrentInstance'] 39 | const getCurrentScope: typeof import('vue')['getCurrentScope'] 40 | const h: typeof import('vue')['h'] 41 | const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] 42 | const inject: typeof import('vue')['inject'] 43 | const isDark: typeof import('./composables/dark')['isDark'] 44 | const isDefined: typeof import('@vueuse/core')['isDefined'] 45 | const isProxy: typeof import('vue')['isProxy'] 46 | const isReactive: typeof import('vue')['isReactive'] 47 | const isReadonly: typeof import('vue')['isReadonly'] 48 | const isRef: typeof import('vue')['isRef'] 49 | const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] 50 | const markRaw: typeof import('vue')['markRaw'] 51 | const nextTick: typeof import('vue')['nextTick'] 52 | const onActivated: typeof import('vue')['onActivated'] 53 | const onBeforeMount: typeof import('vue')['onBeforeMount'] 54 | const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] 55 | const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] 56 | const onClickOutside: typeof import('@vueuse/core')['onClickOutside'] 57 | const onDeactivated: typeof import('vue')['onDeactivated'] 58 | const onErrorCaptured: typeof import('vue')['onErrorCaptured'] 59 | const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke'] 60 | const onLongPress: typeof import('@vueuse/core')['onLongPress'] 61 | const onMounted: typeof import('vue')['onMounted'] 62 | const onRenderTracked: typeof import('vue')['onRenderTracked'] 63 | const onRenderTriggered: typeof import('vue')['onRenderTriggered'] 64 | const onScopeDispose: typeof import('vue')['onScopeDispose'] 65 | const onServerPrefetch: typeof import('vue')['onServerPrefetch'] 66 | const onStartTyping: typeof import('@vueuse/core')['onStartTyping'] 67 | const onUnmounted: typeof import('vue')['onUnmounted'] 68 | const onUpdated: typeof import('vue')['onUpdated'] 69 | const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] 70 | const preferredDark: typeof import('./composables/dark')['preferredDark'] 71 | const provide: typeof import('vue')['provide'] 72 | const reactify: typeof import('@vueuse/core')['reactify'] 73 | const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] 74 | const reactive: typeof import('vue')['reactive'] 75 | const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed'] 76 | const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit'] 77 | const reactivePick: typeof import('@vueuse/core')['reactivePick'] 78 | const readonly: typeof import('vue')['readonly'] 79 | const ref: typeof import('vue')['ref'] 80 | const refAutoReset: typeof import('@vueuse/core')['refAutoReset'] 81 | const refDebounced: typeof import('@vueuse/core')['refDebounced'] 82 | const refDefault: typeof import('@vueuse/core')['refDefault'] 83 | const refThrottled: typeof import('@vueuse/core')['refThrottled'] 84 | const refWithControl: typeof import('@vueuse/core')['refWithControl'] 85 | const resolveComponent: typeof import('vue')['resolveComponent'] 86 | const resolveRef: typeof import('@vueuse/core')['resolveRef'] 87 | const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] 88 | const shallowReactive: typeof import('vue')['shallowReactive'] 89 | const shallowReadonly: typeof import('vue')['shallowReadonly'] 90 | const shallowRef: typeof import('vue')['shallowRef'] 91 | const syncRef: typeof import('@vueuse/core')['syncRef'] 92 | const syncRefs: typeof import('@vueuse/core')['syncRefs'] 93 | const templateRef: typeof import('@vueuse/core')['templateRef'] 94 | const throttledRef: typeof import('@vueuse/core')['throttledRef'] 95 | const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] 96 | const toRaw: typeof import('vue')['toRaw'] 97 | const toReactive: typeof import('@vueuse/core')['toReactive'] 98 | const toRef: typeof import('vue')['toRef'] 99 | const toRefs: typeof import('vue')['toRefs'] 100 | const toggleDark: typeof import('./composables/dark')['toggleDark'] 101 | const triggerRef: typeof import('vue')['triggerRef'] 102 | const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] 103 | const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] 104 | const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted'] 105 | const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose'] 106 | const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted'] 107 | const unref: typeof import('vue')['unref'] 108 | const unrefElement: typeof import('@vueuse/core')['unrefElement'] 109 | const until: typeof import('@vueuse/core')['until'] 110 | const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] 111 | const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] 112 | const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] 113 | const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] 114 | const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] 115 | const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] 116 | const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] 117 | const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] 118 | const useArraySome: typeof import('@vueuse/core')['useArraySome'] 119 | const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] 120 | const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] 121 | const useAttrs: typeof import('vue')['useAttrs'] 122 | const useBase64: typeof import('@vueuse/core')['useBase64'] 123 | const useBattery: typeof import('@vueuse/core')['useBattery'] 124 | const useBluetooth: typeof import('@vueuse/core')['useBluetooth'] 125 | const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints'] 126 | const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] 127 | const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] 128 | const useCached: typeof import('@vueuse/core')['useCached'] 129 | const useClipboard: typeof import('@vueuse/core')['useClipboard'] 130 | const useCloned: typeof import('@vueuse/core')['useCloned'] 131 | const useColorMode: typeof import('@vueuse/core')['useColorMode'] 132 | const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] 133 | const useCounter: typeof import('@vueuse/core')['useCounter'] 134 | const useCssModule: typeof import('vue')['useCssModule'] 135 | const useCssVar: typeof import('@vueuse/core')['useCssVar'] 136 | const useCssVars: typeof import('vue')['useCssVars'] 137 | const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement'] 138 | const useCycleList: typeof import('@vueuse/core')['useCycleList'] 139 | const useDark: typeof import('@vueuse/core')['useDark'] 140 | const useDateFormat: typeof import('@vueuse/core')['useDateFormat'] 141 | const useDebounce: typeof import('@vueuse/core')['useDebounce'] 142 | const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn'] 143 | const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory'] 144 | const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion'] 145 | const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation'] 146 | const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio'] 147 | const useDevicesList: typeof import('@vueuse/core')['useDevicesList'] 148 | const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia'] 149 | const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility'] 150 | const useDraggable: typeof import('@vueuse/core')['useDraggable'] 151 | const useDropZone: typeof import('@vueuse/core')['useDropZone'] 152 | const useElementBounding: typeof import('@vueuse/core')['useElementBounding'] 153 | const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint'] 154 | const useElementHover: typeof import('@vueuse/core')['useElementHover'] 155 | const useElementSize: typeof import('@vueuse/core')['useElementSize'] 156 | const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility'] 157 | const useEventBus: typeof import('@vueuse/core')['useEventBus'] 158 | const useEventListener: typeof import('@vueuse/core')['useEventListener'] 159 | const useEventSource: typeof import('@vueuse/core')['useEventSource'] 160 | const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper'] 161 | const useFavicon: typeof import('@vueuse/core')['useFavicon'] 162 | const useFetch: typeof import('@vueuse/core')['useFetch'] 163 | const useFileDialog: typeof import('@vueuse/core')['useFileDialog'] 164 | const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess'] 165 | const useFocus: typeof import('@vueuse/core')['useFocus'] 166 | const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin'] 167 | const useFps: typeof import('@vueuse/core')['useFps'] 168 | const useFullscreen: typeof import('@vueuse/core')['useFullscreen'] 169 | const useGamepad: typeof import('@vueuse/core')['useGamepad'] 170 | const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] 171 | const useHead: typeof import('@vueuse/head')['useHead'] 172 | const useI18n: typeof import('vue-i18n')['useI18n'] 173 | const useIdle: typeof import('@vueuse/core')['useIdle'] 174 | const useImage: typeof import('@vueuse/core')['useImage'] 175 | const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] 176 | const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver'] 177 | const useInterval: typeof import('@vueuse/core')['useInterval'] 178 | const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn'] 179 | const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier'] 180 | const useLastChanged: typeof import('@vueuse/core')['useLastChanged'] 181 | const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage'] 182 | const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys'] 183 | const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory'] 184 | const useMediaControls: typeof import('@vueuse/core')['useMediaControls'] 185 | const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] 186 | const useMemoize: typeof import('@vueuse/core')['useMemoize'] 187 | const useMemory: typeof import('@vueuse/core')['useMemory'] 188 | const useMounted: typeof import('@vueuse/core')['useMounted'] 189 | const useMouse: typeof import('@vueuse/core')['useMouse'] 190 | const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement'] 191 | const useMousePressed: typeof import('@vueuse/core')['useMousePressed'] 192 | const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver'] 193 | const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage'] 194 | const useNetwork: typeof import('@vueuse/core')['useNetwork'] 195 | const useNow: typeof import('@vueuse/core')['useNow'] 196 | const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl'] 197 | const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] 198 | const useOnline: typeof import('@vueuse/core')['useOnline'] 199 | const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] 200 | const useParallax: typeof import('@vueuse/core')['useParallax'] 201 | const usePermission: typeof import('@vueuse/core')['usePermission'] 202 | const usePointer: typeof import('@vueuse/core')['usePointer'] 203 | const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] 204 | const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] 205 | const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] 206 | const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] 207 | const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] 208 | const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] 209 | const useRafFn: typeof import('@vueuse/core')['useRafFn'] 210 | const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] 211 | const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] 212 | const useRoute: typeof import('vue-router/auto')['useRoute'] 213 | const useRouter: typeof import('vue-router/auto')['useRouter'] 214 | const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation'] 215 | const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea'] 216 | const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] 217 | const useScroll: typeof import('@vueuse/core')['useScroll'] 218 | const useScrollLock: typeof import('@vueuse/core')['useScrollLock'] 219 | const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] 220 | const useShare: typeof import('@vueuse/core')['useShare'] 221 | const useSlots: typeof import('vue')['useSlots'] 222 | const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] 223 | const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] 224 | const useStepper: typeof import('@vueuse/core')['useStepper'] 225 | const useStorage: typeof import('@vueuse/core')['useStorage'] 226 | const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] 227 | const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] 228 | const useSupported: typeof import('@vueuse/core')['useSupported'] 229 | const useSwipe: typeof import('@vueuse/core')['useSwipe'] 230 | const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] 231 | const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] 232 | const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] 233 | const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] 234 | const useThrottle: typeof import('@vueuse/core')['useThrottle'] 235 | const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] 236 | const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] 237 | const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo'] 238 | const useTimeout: typeof import('@vueuse/core')['useTimeout'] 239 | const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn'] 240 | const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] 241 | const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] 242 | const useTitle: typeof import('@vueuse/core')['useTitle'] 243 | const useToNumber: typeof import('@vueuse/core')['useToNumber'] 244 | const useToString: typeof import('@vueuse/core')['useToString'] 245 | const useToggle: typeof import('@vueuse/core')['useToggle'] 246 | const useTransition: typeof import('@vueuse/core')['useTransition'] 247 | const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] 248 | const useUserMedia: typeof import('@vueuse/core')['useUserMedia'] 249 | const useUserStore: typeof import('./store/user')['useUserStore'] 250 | const useVModel: typeof import('@vueuse/core')['useVModel'] 251 | const useVModels: typeof import('@vueuse/core')['useVModels'] 252 | const useVibrate: typeof import('@vueuse/core')['useVibrate'] 253 | const useVirtualList: typeof import('@vueuse/core')['useVirtualList'] 254 | const useWakeLock: typeof import('@vueuse/core')['useWakeLock'] 255 | const useWebNotification: typeof import('@vueuse/core')['useWebNotification'] 256 | const useWebSocket: typeof import('@vueuse/core')['useWebSocket'] 257 | const useWebWorker: typeof import('@vueuse/core')['useWebWorker'] 258 | const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn'] 259 | const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus'] 260 | const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] 261 | const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] 262 | const watch: typeof import('vue')['watch'] 263 | const watchArray: typeof import('@vueuse/core')['watchArray'] 264 | const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] 265 | const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] 266 | const watchEffect: typeof import('vue')['watchEffect'] 267 | const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] 268 | const watchOnce: typeof import('@vueuse/core')['watchOnce'] 269 | const watchPausable: typeof import('@vueuse/core')['watchPausable'] 270 | const watchPostEffect: typeof import('vue')['watchPostEffect'] 271 | const watchSyncEffect: typeof import('vue')['watchSyncEffect'] 272 | const watchThrottled: typeof import('@vueuse/core')['watchThrottled'] 273 | const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable'] 274 | const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] 275 | const whenever: typeof import('@vueuse/core')['whenever'] 276 | } 277 | // for vue template auto import 278 | import { UnwrapRef } from 'vue' 279 | declare module '@vue/runtime-core' { 280 | interface ComponentCustomProperties { 281 | readonly $$: UnwrapRef 282 | readonly $: UnwrapRef 283 | readonly $computed: UnwrapRef 284 | readonly $customRef: UnwrapRef 285 | readonly $ref: UnwrapRef 286 | readonly $shallowRef: UnwrapRef 287 | readonly $toRef: UnwrapRef 288 | readonly EffectScope: UnwrapRef 289 | readonly asyncComputed: UnwrapRef 290 | readonly autoResetRef: UnwrapRef 291 | readonly computed: UnwrapRef 292 | readonly computedAsync: UnwrapRef 293 | readonly computedEager: UnwrapRef 294 | readonly computedInject: UnwrapRef 295 | readonly computedWithControl: UnwrapRef 296 | readonly controlledComputed: UnwrapRef 297 | readonly controlledRef: UnwrapRef 298 | readonly createApp: UnwrapRef 299 | readonly createEventHook: UnwrapRef 300 | readonly createGlobalState: UnwrapRef 301 | readonly createInjectionState: UnwrapRef 302 | readonly createReactiveFn: UnwrapRef 303 | readonly createSharedComposable: UnwrapRef 304 | readonly createUnrefFn: UnwrapRef 305 | readonly customRef: UnwrapRef 306 | readonly debouncedRef: UnwrapRef 307 | readonly debouncedWatch: UnwrapRef 308 | readonly defineAsyncComponent: UnwrapRef 309 | readonly defineComponent: UnwrapRef 310 | readonly defineLoader: UnwrapRef 311 | readonly definePage: UnwrapRef 312 | readonly eagerComputed: UnwrapRef 313 | readonly effectScope: UnwrapRef 314 | readonly extendRef: UnwrapRef 315 | readonly getCurrentInstance: UnwrapRef 316 | readonly getCurrentScope: UnwrapRef 317 | readonly h: UnwrapRef 318 | readonly ignorableWatch: UnwrapRef 319 | readonly inject: UnwrapRef 320 | readonly isDark: UnwrapRef 321 | readonly isDefined: UnwrapRef 322 | readonly isProxy: UnwrapRef 323 | readonly isReactive: UnwrapRef 324 | readonly isReadonly: UnwrapRef 325 | readonly isRef: UnwrapRef 326 | readonly makeDestructurable: UnwrapRef 327 | readonly markRaw: UnwrapRef 328 | readonly nextTick: UnwrapRef 329 | readonly onActivated: UnwrapRef 330 | readonly onBeforeMount: UnwrapRef 331 | readonly onBeforeUnmount: UnwrapRef 332 | readonly onBeforeUpdate: UnwrapRef 333 | readonly onClickOutside: UnwrapRef 334 | readonly onDeactivated: UnwrapRef 335 | readonly onErrorCaptured: UnwrapRef 336 | readonly onKeyStroke: UnwrapRef 337 | readonly onLongPress: UnwrapRef 338 | readonly onMounted: UnwrapRef 339 | readonly onRenderTracked: UnwrapRef 340 | readonly onRenderTriggered: UnwrapRef 341 | readonly onScopeDispose: UnwrapRef 342 | readonly onServerPrefetch: UnwrapRef 343 | readonly onStartTyping: UnwrapRef 344 | readonly onUnmounted: UnwrapRef 345 | readonly onUpdated: UnwrapRef 346 | readonly pausableWatch: UnwrapRef 347 | readonly preferredDark: UnwrapRef 348 | readonly provide: UnwrapRef 349 | readonly reactify: UnwrapRef 350 | readonly reactifyObject: UnwrapRef 351 | readonly reactive: UnwrapRef 352 | readonly reactiveComputed: UnwrapRef 353 | readonly reactiveOmit: UnwrapRef 354 | readonly reactivePick: UnwrapRef 355 | readonly readonly: UnwrapRef 356 | readonly ref: UnwrapRef 357 | readonly refAutoReset: UnwrapRef 358 | readonly refDebounced: UnwrapRef 359 | readonly refDefault: UnwrapRef 360 | readonly refThrottled: UnwrapRef 361 | readonly refWithControl: UnwrapRef 362 | readonly resolveComponent: UnwrapRef 363 | readonly resolveRef: UnwrapRef 364 | readonly resolveUnref: UnwrapRef 365 | readonly shallowReactive: UnwrapRef 366 | readonly shallowReadonly: UnwrapRef 367 | readonly shallowRef: UnwrapRef 368 | readonly syncRef: UnwrapRef 369 | readonly syncRefs: UnwrapRef 370 | readonly templateRef: UnwrapRef 371 | readonly throttledRef: UnwrapRef 372 | readonly throttledWatch: UnwrapRef 373 | readonly toRaw: UnwrapRef 374 | readonly toReactive: UnwrapRef 375 | readonly toRef: UnwrapRef 376 | readonly toRefs: UnwrapRef 377 | readonly toggleDark: UnwrapRef 378 | readonly triggerRef: UnwrapRef 379 | readonly tryOnBeforeMount: UnwrapRef 380 | readonly tryOnBeforeUnmount: UnwrapRef 381 | readonly tryOnMounted: UnwrapRef 382 | readonly tryOnScopeDispose: UnwrapRef 383 | readonly tryOnUnmounted: UnwrapRef 384 | readonly unref: UnwrapRef 385 | readonly unrefElement: UnwrapRef 386 | readonly until: UnwrapRef 387 | readonly useActiveElement: UnwrapRef 388 | readonly useArrayEvery: UnwrapRef 389 | readonly useArrayFilter: UnwrapRef 390 | readonly useArrayFind: UnwrapRef 391 | readonly useArrayFindIndex: UnwrapRef 392 | readonly useArrayJoin: UnwrapRef 393 | readonly useArrayMap: UnwrapRef 394 | readonly useArrayReduce: UnwrapRef 395 | readonly useArraySome: UnwrapRef 396 | readonly useAsyncQueue: UnwrapRef 397 | readonly useAsyncState: UnwrapRef 398 | readonly useAttrs: UnwrapRef 399 | readonly useBase64: UnwrapRef 400 | readonly useBattery: UnwrapRef 401 | readonly useBluetooth: UnwrapRef 402 | readonly useBreakpoints: UnwrapRef 403 | readonly useBroadcastChannel: UnwrapRef 404 | readonly useBrowserLocation: UnwrapRef 405 | readonly useCached: UnwrapRef 406 | readonly useClipboard: UnwrapRef 407 | readonly useCloned: UnwrapRef 408 | readonly useColorMode: UnwrapRef 409 | readonly useConfirmDialog: UnwrapRef 410 | readonly useCounter: UnwrapRef 411 | readonly useCssModule: UnwrapRef 412 | readonly useCssVar: UnwrapRef 413 | readonly useCssVars: UnwrapRef 414 | readonly useCurrentElement: UnwrapRef 415 | readonly useCycleList: UnwrapRef 416 | readonly useDark: UnwrapRef 417 | readonly useDateFormat: UnwrapRef 418 | readonly useDebounce: UnwrapRef 419 | readonly useDebounceFn: UnwrapRef 420 | readonly useDebouncedRefHistory: UnwrapRef 421 | readonly useDeviceMotion: UnwrapRef 422 | readonly useDeviceOrientation: UnwrapRef 423 | readonly useDevicePixelRatio: UnwrapRef 424 | readonly useDevicesList: UnwrapRef 425 | readonly useDisplayMedia: UnwrapRef 426 | readonly useDocumentVisibility: UnwrapRef 427 | readonly useDraggable: UnwrapRef 428 | readonly useDropZone: UnwrapRef 429 | readonly useElementBounding: UnwrapRef 430 | readonly useElementByPoint: UnwrapRef 431 | readonly useElementHover: UnwrapRef 432 | readonly useElementSize: UnwrapRef 433 | readonly useElementVisibility: UnwrapRef 434 | readonly useEventBus: UnwrapRef 435 | readonly useEventListener: UnwrapRef 436 | readonly useEventSource: UnwrapRef 437 | readonly useEyeDropper: UnwrapRef 438 | readonly useFavicon: UnwrapRef 439 | readonly useFetch: UnwrapRef 440 | readonly useFileDialog: UnwrapRef 441 | readonly useFileSystemAccess: UnwrapRef 442 | readonly useFocus: UnwrapRef 443 | readonly useFocusWithin: UnwrapRef 444 | readonly useFps: UnwrapRef 445 | readonly useFullscreen: UnwrapRef 446 | readonly useGamepad: UnwrapRef 447 | readonly useGeolocation: UnwrapRef 448 | readonly useHead: UnwrapRef 449 | readonly useI18n: UnwrapRef 450 | readonly useIdle: UnwrapRef 451 | readonly useImage: UnwrapRef 452 | readonly useInfiniteScroll: UnwrapRef 453 | readonly useIntersectionObserver: UnwrapRef 454 | readonly useInterval: UnwrapRef 455 | readonly useIntervalFn: UnwrapRef 456 | readonly useKeyModifier: UnwrapRef 457 | readonly useLastChanged: UnwrapRef 458 | readonly useLocalStorage: UnwrapRef 459 | readonly useMagicKeys: UnwrapRef 460 | readonly useManualRefHistory: UnwrapRef 461 | readonly useMediaControls: UnwrapRef 462 | readonly useMediaQuery: UnwrapRef 463 | readonly useMemoize: UnwrapRef 464 | readonly useMemory: UnwrapRef 465 | readonly useMounted: UnwrapRef 466 | readonly useMouse: UnwrapRef 467 | readonly useMouseInElement: UnwrapRef 468 | readonly useMousePressed: UnwrapRef 469 | readonly useMutationObserver: UnwrapRef 470 | readonly useNavigatorLanguage: UnwrapRef 471 | readonly useNetwork: UnwrapRef 472 | readonly useNow: UnwrapRef 473 | readonly useObjectUrl: UnwrapRef 474 | readonly useOffsetPagination: UnwrapRef 475 | readonly useOnline: UnwrapRef 476 | readonly usePageLeave: UnwrapRef 477 | readonly useParallax: UnwrapRef 478 | readonly usePermission: UnwrapRef 479 | readonly usePointer: UnwrapRef 480 | readonly usePointerSwipe: UnwrapRef 481 | readonly usePreferredColorScheme: UnwrapRef 482 | readonly usePreferredContrast: UnwrapRef 483 | readonly usePreferredDark: UnwrapRef 484 | readonly usePreferredLanguages: UnwrapRef 485 | readonly usePreferredReducedMotion: UnwrapRef 486 | readonly useRafFn: UnwrapRef 487 | readonly useRefHistory: UnwrapRef 488 | readonly useResizeObserver: UnwrapRef 489 | readonly useRoute: UnwrapRef 490 | readonly useRouter: UnwrapRef 491 | readonly useScreenOrientation: UnwrapRef 492 | readonly useScreenSafeArea: UnwrapRef 493 | readonly useScriptTag: UnwrapRef 494 | readonly useScroll: UnwrapRef 495 | readonly useScrollLock: UnwrapRef 496 | readonly useSessionStorage: UnwrapRef 497 | readonly useShare: UnwrapRef 498 | readonly useSlots: UnwrapRef 499 | readonly useSpeechRecognition: UnwrapRef 500 | readonly useSpeechSynthesis: UnwrapRef 501 | readonly useStepper: UnwrapRef 502 | readonly useStorage: UnwrapRef 503 | readonly useStorageAsync: UnwrapRef 504 | readonly useStyleTag: UnwrapRef 505 | readonly useSupported: UnwrapRef 506 | readonly useSwipe: UnwrapRef 507 | readonly useTemplateRefsList: UnwrapRef 508 | readonly useTextDirection: UnwrapRef 509 | readonly useTextSelection: UnwrapRef 510 | readonly useTextareaAutosize: UnwrapRef 511 | readonly useThrottle: UnwrapRef 512 | readonly useThrottleFn: UnwrapRef 513 | readonly useThrottledRefHistory: UnwrapRef 514 | readonly useTimeAgo: UnwrapRef 515 | readonly useTimeout: UnwrapRef 516 | readonly useTimeoutFn: UnwrapRef 517 | readonly useTimeoutPoll: UnwrapRef 518 | readonly useTimestamp: UnwrapRef 519 | readonly useTitle: UnwrapRef 520 | readonly useToNumber: UnwrapRef 521 | readonly useToString: UnwrapRef 522 | readonly useToggle: UnwrapRef 523 | readonly useTransition: UnwrapRef 524 | readonly useUrlSearchParams: UnwrapRef 525 | readonly useUserMedia: UnwrapRef 526 | readonly useUserStore: UnwrapRef 527 | readonly useVModel: UnwrapRef 528 | readonly useVModels: UnwrapRef 529 | readonly useVibrate: UnwrapRef 530 | readonly useVirtualList: UnwrapRef 531 | readonly useWakeLock: UnwrapRef 532 | readonly useWebNotification: UnwrapRef 533 | readonly useWebSocket: UnwrapRef 534 | readonly useWebWorker: UnwrapRef 535 | readonly useWebWorkerFn: UnwrapRef 536 | readonly useWindowFocus: UnwrapRef 537 | readonly useWindowScroll: UnwrapRef 538 | readonly useWindowSize: UnwrapRef 539 | readonly watch: UnwrapRef 540 | readonly watchArray: UnwrapRef 541 | readonly watchAtMost: UnwrapRef 542 | readonly watchDebounced: UnwrapRef 543 | readonly watchEffect: UnwrapRef 544 | readonly watchIgnorable: UnwrapRef 545 | readonly watchOnce: UnwrapRef 546 | readonly watchPausable: UnwrapRef 547 | readonly watchPostEffect: UnwrapRef 548 | readonly watchSyncEffect: UnwrapRef 549 | readonly watchThrottled: UnwrapRef 550 | readonly watchTriggerable: UnwrapRef 551 | readonly watchWithFilter: UnwrapRef 552 | readonly whenever: UnwrapRef 553 | } 554 | } 555 | -------------------------------------------------------------------------------- /src/components.d.ts: -------------------------------------------------------------------------------- 1 | // generated by unplugin-vue-components 2 | // We suggest you to commit this file into source control 3 | // Read more: https://github.com/vuejs/core/pull/3399 4 | import '@vue/runtime-core' 5 | 6 | export {} 7 | 8 | declare module '@vue/runtime-core' { 9 | export interface GlobalComponents { 10 | Counter: typeof import('./components/Counter.vue')['default'] 11 | Footer: typeof import('./components/Footer.vue')['default'] 12 | README: typeof import('./components/README.md')['default'] 13 | RouterLink: typeof import('vue-router')['RouterLink'] 14 | RouterView: typeof import('vue-router')['RouterView'] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Counter.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | -------------------------------------------------------------------------------- /src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | -------------------------------------------------------------------------------- /src/components/README.md: -------------------------------------------------------------------------------- 1 | ## Components 2 | 3 | Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components). 4 | 5 | 6 | ### Icons 7 | 8 | You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/). 9 | 10 | It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details. 11 | -------------------------------------------------------------------------------- /src/composables/dark.ts: -------------------------------------------------------------------------------- 1 | // these APIs are auto-imported from @vueuse/core 2 | export const isDark = useDark() 3 | export const toggleDark = useToggle(isDark) 4 | export const preferredDark = usePreferredDark() 5 | -------------------------------------------------------------------------------- /src/layouts/404.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 19 | -------------------------------------------------------------------------------- /src/layouts/README.md: -------------------------------------------------------------------------------- 1 | ## Layouts 2 | 3 | Vue components in this dir are used as layouts. 4 | 5 | By default, `default.vue` will be used unless an alternative is specified in the route meta. 6 | 7 | With [`vite-plugin-pages`](https://github.com/hannoeru/vite-plugin-pages) and [`vite-plugin-vue-layouts`](https://github.com/JohnCampionJr/vite-plugin-vue-layouts), you can specify the layout in the page's SFCs like this: 8 | 9 | ```html 10 | 11 | meta: 12 | layout: home 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /src/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/layouts/home.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { ViteSSG } from 'vite-ssg' 2 | import { setupLayouts } from 'virtual:generated-layouts' 3 | import Previewer from 'virtual:vue-component-preview' 4 | import { routes } from 'vue-router/auto/routes' 5 | import App from './App.vue' 6 | import type { UserModule } from './types' 7 | 8 | import '@unocss/reset/tailwind.css' 9 | import './styles/main.css' 10 | import 'uno.css' 11 | 12 | // https://github.com/antfu/vite-ssg 13 | export const createApp = ViteSSG( 14 | App, 15 | { 16 | routes: setupLayouts(routes), 17 | base: import.meta.env.BASE_URL, 18 | }, 19 | (ctx) => { 20 | // install all modules under `modules/` 21 | Object.values(import.meta.glob<{ install: UserModule }>('./modules/*.ts', { eager: true })) 22 | .forEach(i => i.install?.(ctx)) 23 | ctx.app.use(Previewer) 24 | }, 25 | ) 26 | -------------------------------------------------------------------------------- /src/modules/README.md: -------------------------------------------------------------------------------- 1 | ## Modules 2 | 3 | A custom user module system. Place a `.ts` file with the following template, it will be installed automatically. 4 | 5 | ```ts 6 | import { type UserModule } from '~/types' 7 | 8 | export const install: UserModule = ({ app, router, isClient }) => { 9 | // do something 10 | } 11 | ``` 12 | -------------------------------------------------------------------------------- /src/modules/i18n.ts: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n' 2 | import { type UserModule } from '~/types' 3 | 4 | // Import i18n resources 5 | // https://vitejs.dev/guide/features.html#glob-import 6 | // 7 | // Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite 8 | const messages = Object.fromEntries( 9 | Object.entries( 10 | import.meta.glob<{ default: any }>('../../locales/*.y(a)?ml', { eager: true })) 11 | .map(([key, value]) => { 12 | const yaml = key.endsWith('.yaml') 13 | return [key.slice(14, yaml ? -5 : -4), value.default] 14 | }), 15 | ) 16 | 17 | export const install: UserModule = ({ app }) => { 18 | const i18n = createI18n({ 19 | legacy: false, 20 | locale: 'en', 21 | messages, 22 | }) 23 | 24 | app.use(i18n) 25 | } 26 | -------------------------------------------------------------------------------- /src/modules/nprogress.ts: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress' 2 | import { type UserModule } from '~/types' 3 | 4 | export const install: UserModule = ({ isClient, router }) => { 5 | if (isClient) { 6 | router.beforeEach((to, from) => { 7 | if (to.path !== from.path) 8 | NProgress.start() 9 | }) 10 | router.afterEach(() => { NProgress.done() }) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/modules/pinia.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | import { type UserModule } from '~/types' 3 | 4 | // Setup Pinia 5 | // https://pinia.vuejs.org/ 6 | export const install: UserModule = ({ isClient, initialState, app }) => { 7 | const pinia = createPinia() 8 | app.use(pinia) 9 | // Refer to 10 | // https://github.com/antfu/vite-ssg/blob/main/README.md#state-serialization 11 | // for other serialization strategies. 12 | if (isClient) 13 | pinia.state.value = (initialState.pinia) || {} 14 | 15 | else 16 | initialState.pinia = pinia.state.value 17 | } 18 | -------------------------------------------------------------------------------- /src/modules/pwa.ts: -------------------------------------------------------------------------------- 1 | import { type UserModule } from '~/types' 2 | 3 | // https://github.com/antfu/vite-plugin-pwa#automatic-reload-when-new-content-available 4 | export const install: UserModule = ({ isClient, router }) => { 5 | if (!isClient) 6 | return 7 | 8 | router.isReady().then(async () => { 9 | const { registerSW } = await import('virtual:pwa-register') 10 | registerSW({ immediate: true }) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/README.md: -------------------------------------------------------------------------------- 1 | ## File-based Routing 2 | 3 | Routes will be auto-generated for Vue files in this dir with the same file structure. 4 | Check out [`vite-plugin-pages`](https://github.com/hannoeru/vite-plugin-pages) for more details. 5 | 6 | ### Path Aliasing 7 | 8 | `~/` is aliased to `./src/` folder. 9 | 10 | For example, instead of having 11 | 12 | ```ts 13 | import { isDark } from '../../../../composables' 14 | ``` 15 | 16 | now, you can use 17 | 18 | ```ts 19 | import { isDark } from '~/composables' 20 | ``` 21 | -------------------------------------------------------------------------------- /src/pages/[...all].vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | meta: 13 | layout: 404 14 | 15 | -------------------------------------------------------------------------------- /src/pages/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | --- 4 | 5 |
6 | 7 |
8 |

About

9 |
10 | 11 | [Vitesse](https://github.com/antfu/vitesse) is an opinionated [Vite](https://github.com/vitejs/vite) starter template made by [@antfu](https://github.com/antfu) for mocking apps swiftly. With **file-based routing**, **components auto importing**, **markdown support**, I18n, PWA and uses **UnoCSS** for styling and icons. 12 | 13 | ```js 14 | // syntax highlighting example 15 | function vitesse() { 16 | const foo = 'bar' 17 | console.log(foo) 18 | } 19 | ``` 20 | 21 | Check out the [GitHub repo](https://github.com/antfu/vitesse) for more details. 22 | -------------------------------------------------------------------------------- /src/pages/hi/[name].vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 54 | -------------------------------------------------------------------------------- /src/pages/hi/static.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/posva/unplugin-vue-router-demo/781f60486710ba2b9db07d8ebf97ba3f7137d24e/src/pages/hi/static.vue -------------------------------------------------------------------------------- /src/pages/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 58 | 59 | 60 | meta: 61 | layout: home 62 | 63 | -------------------------------------------------------------------------------- /src/pages/welcome.md: -------------------------------------------------------------------------------- 1 | # welcome to the website 2 | -------------------------------------------------------------------------------- /src/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Window { 2 | // extend the window 3 | } 4 | 5 | // with vite-plugin-vue-markdown, markdown files can be treated as Vue components 6 | declare module '*.md' { 7 | import { type DefineComponent } from 'vue' 8 | const component: DefineComponent<{}, {}, any> 9 | export default component 10 | } 11 | 12 | declare module '*.vue' { 13 | import { type DefineComponent } from 'vue' 14 | const component: DefineComponent<{}, {}, any> 15 | export default component 16 | } 17 | -------------------------------------------------------------------------------- /src/store/user.ts: -------------------------------------------------------------------------------- 1 | import { acceptHMRUpdate, defineStore } from 'pinia' 2 | 3 | export const useUserStore = defineStore('user', () => { 4 | /** 5 | * Current name of the user. 6 | */ 7 | const savedName = ref('') 8 | const previousNames = ref(new Set()) 9 | 10 | const usedNames = computed(() => Array.from(previousNames.value)) 11 | const otherNames = computed(() => usedNames.value.filter(name => name !== savedName.value)) 12 | 13 | /** 14 | * Changes the current name of the user and saves the one that was used 15 | * before. 16 | * 17 | * @param name - new name to set 18 | */ 19 | function setNewName(name: string) { 20 | if (savedName.value) 21 | previousNames.value.add(savedName.value) 22 | 23 | savedName.value = name 24 | } 25 | 26 | return { 27 | setNewName, 28 | otherNames, 29 | savedName, 30 | } 31 | }) 32 | 33 | if (import.meta.hot) 34 | import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot)) 35 | -------------------------------------------------------------------------------- /src/styles/main.css: -------------------------------------------------------------------------------- 1 | @import './markdown.css'; 2 | 3 | html, 4 | body, 5 | #app { 6 | height: 100%; 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | html.dark { 12 | background: #121212; 13 | color-scheme: dark; 14 | } 15 | 16 | #nprogress { 17 | pointer-events: none; 18 | } 19 | 20 | #nprogress .bar { 21 | background: rgb(13,148,136); 22 | opacity: 0.75; 23 | position: fixed; 24 | z-index: 1031; 25 | top: 0; 26 | left: 0; 27 | width: 100%; 28 | height: 2px; 29 | } 30 | -------------------------------------------------------------------------------- /src/styles/markdown.css: -------------------------------------------------------------------------------- 1 | .prose pre:not(.shiki) { 2 | padding: 0; 3 | } 4 | 5 | .prose .shiki { 6 | font-family: 'DM Mono', monospace; 7 | font-size: 1.2em; 8 | line-height: 1.4; 9 | } 10 | 11 | .prose img { 12 | width: 100%; 13 | } 14 | 15 | .shiki-light { 16 | background: #f8f8f8 !important; 17 | } 18 | .shiki-dark { 19 | background: #0e0e0e !important; 20 | } 21 | 22 | html.dark .shiki-light { 23 | display: none; 24 | } 25 | 26 | html:not(.dark) .shiki-dark { 27 | display: none; 28 | } 29 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { type ViteSSGContext } from 'vite-ssg' 2 | 3 | export type UserModule = (ctx: ViteSSGContext) => void 4 | -------------------------------------------------------------------------------- /test/__snapshots__/component.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1 2 | 3 | exports[`Counter.vue > should render 1`] = `"
10
"`; 4 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest' 2 | 3 | describe('tests', () => { 4 | it('should works', () => { 5 | expect(1 + 1).toEqual(2) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /test/component.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import { describe, expect, it } from 'vitest' 3 | import Counter from '../src/components/Counter.vue' 4 | 5 | describe('Counter.vue', () => { 6 | it('should render', () => { 7 | const wrapper = mount(Counter, { props: { initial: 10 } }) 8 | expect(wrapper.text()).toContain('10') 9 | expect(wrapper.html()).toMatchSnapshot() 10 | }) 11 | 12 | it('should be interactive', async () => { 13 | const wrapper = mount(Counter, { props: { initial: 0 } }) 14 | expect(wrapper.text()).toContain('0') 15 | 16 | expect(wrapper.find('.inc').exists()).toBe(true) 17 | 18 | expect(wrapper.find('.dec').exists()).toBe(true) 19 | 20 | await wrapper.get('.inc').trigger('click') 21 | 22 | expect(wrapper.text()).toContain('1') 23 | 24 | await wrapper.get('.dec').trigger('click') 25 | 26 | expect(wrapper.text()).toContain('0') 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "module": "ESNext", 5 | "target": "ESNext", 6 | "lib": ["DOM", "ESNext"], 7 | "strict": true, 8 | "esModuleInterop": true, 9 | "jsx": "preserve", 10 | "skipLibCheck": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "noUnusedLocals": true, 14 | "strictNullChecks": true, 15 | "allowJs": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "types": [ 18 | "vitest", 19 | "vite/client", 20 | "vue/ref-macros", 21 | "vite-plugin-vue-component-preview/client", 22 | "vite-plugin-vue-layouts/client", 23 | "vite-plugin-pwa/client", 24 | "./typed-router.d.ts" 25 | ], 26 | "paths": { 27 | "~/*": ["src/*"] 28 | } 29 | }, 30 | "exclude": ["dist", "node_modules", "cypress"] 31 | } 32 | -------------------------------------------------------------------------------- /typed-router.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️ 2 | // It's recommended to commit this file. 3 | // Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry. 4 | 5 | /// 6 | 7 | import type { 8 | // type safe route locations 9 | RouteLocationTypedList, 10 | RouteLocationResolvedTypedList, 11 | RouteLocationNormalizedTypedList, 12 | RouteLocationNormalizedLoadedTypedList, 13 | RouteLocationAsString, 14 | RouteLocationAsRelativeTypedList, 15 | RouteLocationAsPathTypedList, 16 | 17 | // helper types 18 | // route definitions 19 | RouteRecordInfo, 20 | ParamValue, 21 | ParamValueOneOrMore, 22 | ParamValueZeroOrMore, 23 | ParamValueZeroOrOne, 24 | 25 | // vue-router extensions 26 | _RouterTyped, 27 | RouterLinkTyped, 28 | NavigationGuard, 29 | UseLinkFnTyped, 30 | 31 | // data fetching 32 | _DataLoader, 33 | _DefineLoaderOptions, 34 | } from 'unplugin-vue-router' 35 | 36 | declare module 'vue-router/auto/routes' { 37 | export interface RouteNamedMap { 38 | '/': RouteRecordInfo<'/', '/', Record, Record>, 39 | '/[...all]': RouteRecordInfo<'/[...all]', '/:all(.*)', { all: ParamValue }, { all: ParamValue }>, 40 | '/about': RouteRecordInfo<'/about', '/about', Record, Record>, 41 | '/hi/[name]': RouteRecordInfo<'/hi/[name]', '/hi/:name', { name: ParamValue }, { name: ParamValue }>, 42 | '/hi/static': RouteRecordInfo<'/hi/static', '/hi/static', Record, Record>, 43 | '/README': RouteRecordInfo<'/README', '/README', Record, Record>, 44 | '/welcome': RouteRecordInfo<'/welcome', '/welcome', Record, Record>, 45 | } 46 | } 47 | 48 | declare module 'vue-router/auto' { 49 | import type { RouteNamedMap } from 'vue-router/auto/routes' 50 | 51 | export type RouterTyped = _RouterTyped 52 | 53 | /** 54 | * Type safe version of `RouteLocationNormalized` (the type of `to` and `from` in navigation guards). 55 | * Allows passing the name of the route to be passed as a generic. 56 | */ 57 | export type RouteLocationNormalized = RouteLocationNormalizedTypedList[Name] 58 | 59 | /** 60 | * Type safe version of `RouteLocationNormalizedLoaded` (the return type of `useRoute()`). 61 | * Allows passing the name of the route to be passed as a generic. 62 | */ 63 | export type RouteLocationNormalizedLoaded = RouteLocationNormalizedLoadedTypedList[Name] 64 | 65 | /** 66 | * Type safe version of `RouteLocationResolved` (the returned route of `router.resolve()`). 67 | * Allows passing the name of the route to be passed as a generic. 68 | */ 69 | export type RouteLocationResolved = RouteLocationResolvedTypedList[Name] 70 | 71 | /** 72 | * Type safe version of `RouteLocation` . Allows passing the name of the route to be passed as a generic. 73 | */ 74 | export type RouteLocation = RouteLocationTypedList[Name] 75 | 76 | /** 77 | * Type safe version of `RouteLocationRaw` . Allows passing the name of the route to be passed as a generic. 78 | */ 79 | export type RouteLocationRaw = 80 | | RouteLocationAsString 81 | | RouteLocationAsRelativeTypedList[Name] 82 | | RouteLocationAsPathTypedList[Name] 83 | 84 | /** 85 | * Generate a type safe params for a route location. Requires the name of the route to be passed as a generic. 86 | */ 87 | export type RouteParams = RouteNamedMap[Name]['params'] 88 | /** 89 | * Generate a type safe raw params for a route location. Requires the name of the route to be passed as a generic. 90 | */ 91 | export type RouteParamsRaw = RouteNamedMap[Name]['paramsRaw'] 92 | 93 | export function useRouter(): RouterTyped 94 | export function useRoute(name?: Name): RouteLocationNormalizedLoadedTypedList[Name] 95 | 96 | export const useLink: UseLinkFnTyped 97 | 98 | export function onBeforeRouteLeave(guard: NavigationGuard): void 99 | export function onBeforeRouteUpdate(guard: NavigationGuard): void 100 | 101 | // Experimental Data Fetching 102 | 103 | export function defineLoader< 104 | P extends Promise, 105 | Name extends keyof RouteNamedMap = keyof RouteNamedMap, 106 | isLazy extends boolean = false, 107 | >( 108 | name: Name, 109 | loader: (route: RouteLocationNormalizedLoaded) => P, 110 | options?: _DefineLoaderOptions, 111 | ): _DataLoader, isLazy> 112 | export function defineLoader< 113 | P extends Promise, 114 | isLazy extends boolean = false, 115 | >( 116 | loader: (route: RouteLocationNormalizedLoaded) => P, 117 | options?: _DefineLoaderOptions, 118 | ): _DataLoader, isLazy> 119 | 120 | export { 121 | _definePage as definePage, 122 | _HasDataLoaderMeta as HasDataLoaderMeta, 123 | _setupDataFetchingGuard as setupDataFetchingGuard, 124 | _stopDataFetchingScope as stopDataFetchingScope, 125 | } from 'unplugin-vue-router/runtime' 126 | } 127 | 128 | declare module 'vue-router' { 129 | import type { RouteNamedMap } from 'vue-router/auto/routes' 130 | 131 | export interface TypesConfig { 132 | beforeRouteUpdate: NavigationGuard 133 | beforeRouteLeave: NavigationGuard 134 | 135 | $route: RouteLocationNormalizedLoadedTypedList[keyof RouteNamedMap] 136 | $router: _RouterTyped 137 | 138 | RouterLink: RouterLinkTyped 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /unocss.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | presetAttributify, 4 | presetIcons, 5 | presetTypography, 6 | presetUno, 7 | presetWebFonts, 8 | transformerDirectives, 9 | transformerVariantGroup, 10 | } from 'unocss' 11 | 12 | export default defineConfig({ 13 | shortcuts: [ 14 | ['btn', 'px-4 py-1 rounded inline-block bg-teal-700 text-white cursor-pointer hover:bg-teal-800 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'], 15 | ['icon-btn', 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600'], 16 | ], 17 | presets: [ 18 | presetUno(), 19 | presetAttributify(), 20 | presetIcons({ 21 | scale: 1.2, 22 | warn: true, 23 | }), 24 | presetTypography(), 25 | presetWebFonts({ 26 | fonts: { 27 | sans: 'DM Sans', 28 | serif: 'DM Serif Display', 29 | mono: 'DM Mono', 30 | }, 31 | }), 32 | ], 33 | transformers: [ 34 | transformerDirectives(), 35 | transformerVariantGroup(), 36 | ], 37 | safelist: 'prose prose-sm m-auto text-left'.split(' '), 38 | }) 39 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { defineConfig } from 'vite' 3 | import Preview from 'vite-plugin-vue-component-preview' 4 | import Vue from '@vitejs/plugin-vue' 5 | import VueRouter from 'unplugin-vue-router/vite' 6 | import generateSitemap from 'vite-ssg-sitemap' 7 | import Layouts from 'vite-plugin-vue-layouts' 8 | import Components from 'unplugin-vue-components/vite' 9 | import AutoImport from 'unplugin-auto-import/vite' 10 | import Markdown from 'vite-plugin-vue-markdown' 11 | import { VitePWA } from 'vite-plugin-pwa' 12 | import VueI18n from '@intlify/vite-plugin-vue-i18n' 13 | import Inspect from 'vite-plugin-inspect' 14 | import LinkAttributes from 'markdown-it-link-attributes' 15 | import Unocss from 'unocss/vite' 16 | import Shiki from 'markdown-it-shiki' 17 | import { VueRouterAutoImports } from 'unplugin-vue-router' 18 | 19 | export default defineConfig({ 20 | resolve: { 21 | alias: { 22 | '~/': `${path.resolve(__dirname, 'src')}/`, 23 | }, 24 | }, 25 | 26 | plugins: [ 27 | Preview(), 28 | 29 | Vue({ 30 | include: [/\.vue$/, /\.md$/], 31 | reactivityTransform: true, 32 | }), 33 | 34 | VueRouter({ 35 | extensions: ['vue', 'md'], 36 | }), 37 | 38 | // https://github.com/JohnCampionJr/vite-plugin-vue-layouts 39 | Layouts(), 40 | 41 | // https://github.com/antfu/unplugin-auto-import 42 | AutoImport({ 43 | imports: [ 44 | 'vue', 45 | 'vue-i18n', 46 | 'vue/macros', 47 | '@vueuse/head', 48 | '@vueuse/core', 49 | VueRouterAutoImports, 50 | ], 51 | dts: 'src/auto-imports.d.ts', 52 | dirs: [ 53 | 'src/composables', 54 | 'src/store', 55 | ], 56 | vueTemplate: true, 57 | }), 58 | 59 | // https://github.com/antfu/unplugin-vue-components 60 | Components({ 61 | // allow auto load markdown components under `./src/components/` 62 | extensions: ['vue', 'md'], 63 | // allow auto import and register components used in markdown 64 | include: [/\.vue$/, /\.vue\?vue/, /\.md$/], 65 | dts: 'src/components.d.ts', 66 | }), 67 | 68 | // https://github.com/antfu/unocss 69 | // see unocss.config.ts for config 70 | Unocss(), 71 | 72 | // https://github.com/antfu/vite-plugin-vue-markdown 73 | // Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite 74 | Markdown({ 75 | wrapperClasses: 'prose prose-sm m-auto text-left', 76 | headEnabled: true, 77 | markdownItSetup(md) { 78 | // https://prismjs.com/ 79 | md.use(Shiki, { 80 | theme: { 81 | light: 'vitesse-light', 82 | dark: 'vitesse-dark', 83 | }, 84 | }) 85 | md.use(LinkAttributes, { 86 | matcher: (link: string) => /^https?:\/\//.test(link), 87 | attrs: { 88 | target: '_blank', 89 | rel: 'noopener', 90 | }, 91 | }) 92 | }, 93 | }), 94 | 95 | // https://github.com/antfu/vite-plugin-pwa 96 | VitePWA({ 97 | registerType: 'autoUpdate', 98 | includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'], 99 | manifest: { 100 | name: 'Vitesse', 101 | short_name: 'Vitesse', 102 | theme_color: '#ffffff', 103 | icons: [ 104 | { 105 | src: '/pwa-192x192.png', 106 | sizes: '192x192', 107 | type: 'image/png', 108 | }, 109 | { 110 | src: '/pwa-512x512.png', 111 | sizes: '512x512', 112 | type: 'image/png', 113 | }, 114 | { 115 | src: '/pwa-512x512.png', 116 | sizes: '512x512', 117 | type: 'image/png', 118 | purpose: 'any maskable', 119 | }, 120 | ], 121 | }, 122 | }), 123 | 124 | // https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n 125 | VueI18n({ 126 | runtimeOnly: true, 127 | compositionOnly: true, 128 | include: [path.resolve(__dirname, 'locales/**')], 129 | }), 130 | 131 | // https://github.com/antfu/vite-plugin-inspect 132 | // Visit http://localhost:3333/__inspect/ to see the inspector 133 | Inspect(), 134 | ], 135 | 136 | // https://github.com/vitest-dev/vitest 137 | test: { 138 | include: ['test/**/*.test.ts'], 139 | environment: 'jsdom', 140 | deps: { 141 | inline: ['@vue', '@vueuse', 'vue-demi'], 142 | }, 143 | }, 144 | 145 | // https://github.com/antfu/vite-ssg 146 | ssgOptions: { 147 | script: 'async', 148 | formatting: 'minify', 149 | onFinished() { generateSitemap() }, 150 | }, 151 | 152 | ssr: { 153 | // TODO: workaround until they support native ESM 154 | noExternal: ['workbox-window', /vue-i18n/], 155 | }, 156 | }) 157 | --------------------------------------------------------------------------------