├── .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 | 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 | 2 | 8 | 9 | 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 | 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 | 22 | -------------------------------------------------------------------------------- /src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 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 | 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 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Last Naruto 2 | 3 | ![The Last Naruto Logo](./public/logo.webp) 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 `