├── .nvmrc
├── .npmrc
├── src
├── composables
│ ├── index.ts
│ └── dark.ts
├── lib
│ └── index.ts
├── styles
│ └── main.css
├── App.vue
├── components
│ ├── icons
│ │ ├── README.md
│ │ └── CarbonIcon.vue
│ ├── README.md
│ ├── Counter.vue
│ └── Footer.vue
├── pages
│ ├── README.md
│ ├── hi
│ │ └── [name].vue
│ └── index.vue
└── main.ts
├── public
├── logo.webp
└── favicon.svg
├── eslint.config.js
├── test
└── basic.test.ts
├── .vscode
├── extensions.json
└── settings.json
├── .gitignore
├── netlify.toml
├── components.d.ts
├── tsconfig.json
├── index.html
├── unocss.config.ts
├── package.json
├── vite.config.ts
├── README.md
└── auto-imports.d.ts
/.nvmrc:
--------------------------------------------------------------------------------
1 | v20
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 |
--------------------------------------------------------------------------------
/src/composables/index.ts:
--------------------------------------------------------------------------------
1 | export * from './dark'
2 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export const isIE = 'ActiveXObject' in window
2 |
--------------------------------------------------------------------------------
/public/logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luvletterldl/the-last-naruto/HEAD/public/logo.webp
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import antfu from '@antfu/eslint-config'
2 |
3 | export default antfu({
4 | rules: {
5 | 'no-console': 0,
6 | },
7 | })
8 |
--------------------------------------------------------------------------------
/src/composables/dark.ts:
--------------------------------------------------------------------------------
1 | import { useDark, useToggle } from '@vueuse/core'
2 |
3 | export const isDark = useDark()
4 | export const toggleDark = useToggle(isDark)
5 |
--------------------------------------------------------------------------------
/src/styles/main.css:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #root {
4 | height: 100%;
5 | margin: 0;
6 | padding: 0;
7 | }
8 |
9 | html.dark {
10 | background: #121212;
11 | }
12 |
--------------------------------------------------------------------------------
/test/basic.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest'
2 |
3 | describe('hi', () => {
4 | it('should works', () => {
5 | expect(1 + 1).toEqual(2)
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/components/icons/README.md:
--------------------------------------------------------------------------------
1 | # Icon
2 |
3 | [icones](https://icones.js.org/)
4 |
5 | Cause IE11 not support mask. [caniuse](https://caniuse.com/?search=mask)
6 |
7 | If you want to use icons on IE11. You can refer to [CarbonIcon.vue](./CarbonIcon.vue) file.
8 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "antfu.iconify",
4 | "antfu.unocss",
5 | "antfu.goto-alias",
6 | "vue.volar",
7 | "dbaeumer.vscode-eslint"
8 | ],
9 | "unwantedRecommendations": [
10 | "octref.vetur"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | package-lock.json
11 | pnpm-lock.json
12 |
13 | node_modules
14 | dist
15 | dist-ssr
16 | *.local
17 |
18 | # Editor directories and files
19 | .vscode/*
20 | !.vscode/extensions.json
21 | .idea
22 | .DS_Store
23 | *.suo
24 | *.ntvs*
25 | *.njsproj
26 | *.sln
27 | *.sw?
28 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "dist"
3 | command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run build"
4 |
5 | [build.environment]
6 | # bypass npm auto install
7 | NPM_FLAGS = "--version"
8 | NODE_VERSION = "18"
9 |
10 | [[redirects]]
11 | from = "/*"
12 | to = "/index.html"
13 | status = 200
14 |
15 | [[headers]]
16 | for = "/manifest.webmanifest"
17 |
18 | [headers.values]
19 | Content-Type = "application/manifest+json"
20 |
--------------------------------------------------------------------------------
/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 | ### Icons
6 |
7 | You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/).
8 |
9 | It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details.
10 |
--------------------------------------------------------------------------------
/src/components/Counter.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 | {{ count }}
13 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/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/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import routes from 'virtual:generated-pages'
3 | import VueRouter from 'vue-router'
4 | import App from './App.vue'
5 |
6 | import '@unocss/reset/tailwind-compat.css'
7 | import '~/styles/main.css'
8 | import 'uno.css'
9 |
10 | Vue.config.productionTip = false
11 |
12 | export const router = new VueRouter({
13 | mode: 'history',
14 | base: import.meta.env.BASE_URL,
15 | routes,
16 | })
17 |
18 | Vue.use(VueRouter)
19 |
20 | new Vue({
21 | router,
22 | render: h => h(App),
23 | }).$mount('#app')
24 |
--------------------------------------------------------------------------------
/src/pages/hi/[name].vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
Hi, {{ props.name }}
11 |
12 | Dynamic route!
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
21 |
22 |
--------------------------------------------------------------------------------
/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // @ts-nocheck
3 | // Generated by unplugin-vue-components
4 | // Read more: https://github.com/vuejs/core/pull/3399
5 | export {}
6 |
7 | /* prettier-ignore */
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | CarbonIcon: typeof import('./src/components/icons/CarbonIcon.vue')['default']
11 | Counter: typeof import('./src/components/Counter.vue')['default']
12 | Footer: typeof import('./src/components/Footer.vue')['default']
13 | RouterLink: typeof import('vue-router')['RouterLink']
14 | RouterView: typeof import('vue-router')['RouterView']
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "incremental": false,
4 | "target": "ES6",
5 | "jsx": "preserve",
6 | "lib": ["esnext", "dom"],
7 | "useDefineForClassFields": true,
8 | "baseUrl": ".",
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "paths": {
12 | "~/*": ["src/*"]
13 | },
14 | "resolveJsonModule": true,
15 | "types": ["vite/client", "vite-plugin-pages/client"],
16 | "strict": true,
17 | "strictNullChecks": true,
18 | "noUnusedLocals": true,
19 | "sourceMap": true,
20 | "esModuleInterop": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "isolatedModules": true,
23 | "skipLibCheck": true
24 | },
25 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
26 | "vueCompilerOptions": {
27 | "target": 2.7
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | The Last Naruto
9 |
10 |
11 |
12 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/unocss.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | defineConfig,
3 | presetAttributify,
4 | presetIcons,
5 | presetUno,
6 | presetWebFonts,
7 | // transformerDirectives,
8 | // transformerVariantGroup,
9 | } from 'unocss'
10 |
11 | export default defineConfig({
12 | shortcuts: [
13 | [
14 | 'btn',
15 | 'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50',
16 | ],
17 | [
18 | 'icon-btn',
19 | 'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600 !outline-none',
20 | ],
21 | ],
22 | safelist: 'w-6 h-6 w-10 w-14 h-14 h-10 w-20 h-20'.split(' '),
23 | presets: [
24 | presetUno(),
25 | presetAttributify(),
26 | presetIcons({
27 | scale: 1.2,
28 | warn: true,
29 | }),
30 | presetWebFonts({
31 | fonts: {
32 | sans: 'DM Sans',
33 | serif: 'DM Serif Display',
34 | mono: 'DM Mono',
35 | },
36 | }),
37 | ],
38 | // transformers: [
39 | // transformerDirectives(),
40 | // transformerVariantGroup(),
41 | // ],
42 | })
43 |
--------------------------------------------------------------------------------
/src/components/icons/CarbonIcon.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "vetur.validation.script": false,
3 | "css.lint.unknownAtRules": "ignore",
4 | "scss.lint.unknownAtRules": "ignore",
5 | "less.lint.unknownAtRules": "ignore",
6 | // Enable the ESlint flat config support
7 | "eslint.experimental.useFlatConfig": true,
8 |
9 | // Disable the default formatter, use eslint instead
10 | "prettier.enable": false,
11 | "editor.formatOnSave": false,
12 |
13 | // Auto fix
14 | "editor.codeActionsOnSave": {
15 | "source.fixAll.eslint": "explicit",
16 | "source.organizeImports": "never"
17 | },
18 |
19 | // Silent the stylistic rules in you IDE, but still auto fix them
20 | "eslint.rules.customizations": [
21 | { "rule": "style/*", "severity": "off" },
22 | { "rule": "format/*", "severity": "off" },
23 | { "rule": "*-indent", "severity": "off" },
24 | { "rule": "*-spacing", "severity": "off" },
25 | { "rule": "*-spaces", "severity": "off" },
26 | { "rule": "*-order", "severity": "off" },
27 | { "rule": "*-dangle", "severity": "off" },
28 | { "rule": "*-newline", "severity": "off" },
29 | { "rule": "*quotes", "severity": "off" },
30 | { "rule": "*semi", "severity": "off" }
31 | ],
32 |
33 | // Enable eslint for all supported languages
34 | "eslint.validate": [
35 | "javascript",
36 | "javascriptreact",
37 | "typescript",
38 | "typescriptreact",
39 | "vue",
40 | "html",
41 | "markdown",
42 | "json",
43 | "jsonc",
44 | "yaml",
45 | "toml"
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "the-last-naruto",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "private": true,
6 | "packageManager": "pnpm@9.6.0",
7 | "scripts": {
8 | "dev": "vite --port 3456 --open",
9 | "build": "vite build",
10 | "lint": "eslint .",
11 | "format": "eslint . --fix",
12 | "typecheck": "vue-tsc --noEmit",
13 | "preview": "vite preview",
14 | "test": "vitest",
15 | "up": "taze major -I",
16 | "postinstall": "npx simple-git-hooks"
17 | },
18 | "dependencies": {
19 | "@vueuse/core": "^10.11.0",
20 | "vue": "2.7.16",
21 | "vue-router": "3.6.5"
22 | },
23 | "devDependencies": {
24 | "@antfu/eslint-config": "^2.24.1",
25 | "@iconify-json/carbon": "^1.1.37",
26 | "@unocss/reset": "^0.61.9",
27 | "@unocss/transformer-directives": "^0.61.9",
28 | "@unocss/transformer-variant-group": "^0.61.9",
29 | "@vitejs/plugin-legacy": "^5.4.1",
30 | "@vitejs/plugin-vue2": "^2.3.1",
31 | "@vue/test-utils": "^2.4.6",
32 | "eslint": "^9.8.0",
33 | "jsdom": "^24.1.1",
34 | "lightningcss": "^1.25.1",
35 | "lint-staged": "^15.2.8",
36 | "pnpm": "^9.6.0",
37 | "simple-git-hooks": "^2.11.1",
38 | "taze": "^0.16.3",
39 | "terser": "^5.31.3",
40 | "typescript": "^5.5.4",
41 | "unocss": "^0.61.9",
42 | "unplugin-auto-import": "^0.18.2",
43 | "unplugin-vue-components": "^0.27.3",
44 | "vite": "^5.3.5",
45 | "vite-plugin-pages": "^0.32.3",
46 | "vitest": "^2.0.5",
47 | "vue-demi": "^0.14.10",
48 | "vue-tsc": "^2.0.29"
49 | },
50 | "simple-git-hooks": {
51 | "pre-commit": "pnpm lint-staged"
52 | },
53 | "lint-staged": {
54 | "*": "eslint --fix"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import path from 'node:path'
4 | import { defineConfig } from 'vite'
5 | import Vue from '@vitejs/plugin-vue2'
6 | import Pages from 'vite-plugin-pages'
7 | import legacy from '@vitejs/plugin-legacy'
8 | import Components from 'unplugin-vue-components/vite'
9 | import AutoImport from 'unplugin-auto-import/vite'
10 | import Unocss from 'unocss/vite'
11 | import transformerDirective from '@unocss/transformer-directives'
12 | import transformerVariantGroup from '@unocss/transformer-variant-group'
13 |
14 | // https://vitejs.dev/config/
15 | export default defineConfig({
16 | resolve: {
17 | alias: {
18 | '~/': `${path.resolve(__dirname, 'src')}/`,
19 | },
20 | },
21 | css: {
22 | transformer: 'lightningcss',
23 | },
24 | plugins: [
25 | Vue(),
26 |
27 | // https://github.com/hannoeru/vite-plugin-pages
28 | Pages(),
29 |
30 | // https://github.com/antfu/unplugin-auto-import
31 | AutoImport({
32 | imports: ['vue', 'vue/macros', 'vue-router', '@vueuse/core'],
33 | dts: true,
34 | dirs: ['./src/composables'],
35 | vueTemplate: true,
36 | }),
37 |
38 | // https://github.com/antfu/vite-plugin-components
39 | Components({
40 | dts: true,
41 | }),
42 |
43 | legacy({
44 | targets: ['ie >= 11'],
45 | additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
46 | }),
47 | // https://github.com/antfu/unocss
48 | // see unocss.config.ts for config
49 | Unocss({
50 | transformers: [transformerVariantGroup(), transformerDirective()],
51 | }),
52 | ],
53 |
54 | // https://github.com/vitest-dev/vitest
55 | test: {
56 | environment: 'jsdom',
57 | },
58 | })
59 |
--------------------------------------------------------------------------------
/src/pages/index.vue:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
21 | 🔗
22 |
27 | 🔗
28 |
29 |
30 |
31 |
36 | The Last Naruto
37 |
38 |
39 |
40 | Vite + Vue2.7 Starter Template
41 |
42 |
43 |
44 |
45 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Last Naruto
2 |
3 | 
4 |
5 | [中文](https://juejin.cn/post/7122016953593495560)
6 |
7 | # Features
8 |
9 | - 👍 Support IE11 by [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy)
10 |
11 | - ⚡️ [Vue 2.7](https://github.com/vuejs/vue), [Vite 5](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [ESBuild](https://github.com/evanw/esbuild) - born with fastness
12 |
13 | - 🗂 [File based routing](./src/pages)
14 |
15 | - 📦 [Components auto importing](./src/components)
16 |
17 | - 🎨 [UnoCSS](https://github.com/antfu/unocss) - The instant on-demand atomic CSS engine.
18 |
19 | - 😃 Use icons from any icon sets in [Pure CSS](https://github.com/antfu/unocss/tree/main/packages/preset-icons)
20 | - IE11([partial support](./src/components/icons/README.md))
21 |
22 | - 🔥 Use the [new `