@@ -0,0 +1,9 @@ | |||
root = true | |||
[*] | |||
charset = utf-8 | |||
indent_style = space | |||
indent_size = 2 | |||
end_of_line = lf | |||
insert_final_newline = true | |||
trim_trailing_whitespace = true |
@@ -0,0 +1,3 @@ | |||
{ | |||
"extends": "@antfu" | |||
} |
@@ -0,0 +1 @@ | |||
github: antfu |
@@ -0,0 +1,44 @@ | |||
name: CI | |||
on: | |||
push: | |||
branches: | |||
- main | |||
pull_request: | |||
branches: | |||
- main | |||
jobs: | |||
lint: | |||
runs-on: ubuntu-latest | |||
steps: | |||
- uses: actions/checkout@v3 | |||
- uses: pnpm/action-setup@v2 | |||
- uses: actions/setup-node@v3 | |||
with: | |||
node-version: 16.x | |||
cache: pnpm | |||
- name: Install | |||
run: pnpm install | |||
- name: Lint | |||
run: pnpm run lint | |||
typecheck: | |||
runs-on: ubuntu-latest | |||
steps: | |||
- uses: actions/checkout@v3 | |||
- uses: pnpm/action-setup@v2 | |||
- uses: actions/setup-node@v3 | |||
with: | |||
node-version: 16.x | |||
cache: pnpm | |||
- name: Install | |||
run: pnpm install | |||
- name: Typecheck | |||
run: pnpm run typecheck | |||
@@ -0,0 +1,12 @@ | |||
.DS_Store | |||
.vite-ssg-dist | |||
.vite-ssg-temp | |||
*.local | |||
dist | |||
dist-ssr | |||
node_modules | |||
.idea/ | |||
*.log | |||
*.spec | |||
__pycache__ | |||
.vscode |
@@ -0,0 +1,2 @@ | |||
shamefully-hoist=true | |||
strict-peer-dependencies=false |
@@ -0,0 +1,13 @@ | |||
{ | |||
"recommendations": [ | |||
"antfu.iconify", | |||
"antfu.unocss", | |||
"antfu.vite", | |||
"antfu.goto-alias", | |||
"csstools.postcss", | |||
"dbaeumer.vscode-eslint", | |||
"vue.volar", | |||
"lokalise.i18n-ally", | |||
"streetsidesoftware.code-spell-checker" | |||
] | |||
} |
@@ -0,0 +1,28 @@ | |||
{ | |||
"cSpell.words": [ | |||
"demi", | |||
"iconify", | |||
"intlify", | |||
"pinia", | |||
"pnpm", | |||
"pywebview", | |||
"unocss", | |||
"unplugin", | |||
"Vite", | |||
"vitejs", | |||
"Vitesse", | |||
"vueuse" | |||
], | |||
"i18n-ally.sourceLanguage": "en", | |||
"i18n-ally.keystyle": "nested", | |||
"i18n-ally.localesPaths": "locales", | |||
"i18n-ally.sortKeys": true, | |||
"prettier.enable": false, | |||
"editor.codeActionsOnSave": { | |||
"source.fixAll.eslint": true | |||
}, | |||
"files.associations": { | |||
"*.css": "postcss" | |||
}, | |||
"editor.formatOnSave": false | |||
} |
@@ -0,0 +1,21 @@ | |||
MIT License | |||
Copyright (c) 2020-2021 Anthony Fu | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. |
@@ -0,0 +1,241 @@ | |||
<h1 align='center'>Vitesse-Python</h1> | |||
<p align='center'> | |||
Mocking up web app with <b>Vitesse</b><sup><em>(speed)</em></sup><br> | |||
</p> | |||
<br> | |||
<br> | |||
<p align='center'> | |||
<b>简体中文</b> | <a href="">English</a> | |||
<!-- Contributors: Thanks for getting interested, however we DON'T accept new transitions to the README, thanks. --> | |||
</p> | |||
<br> | |||
## Introduction | |||
### 👀 `Vitesse-Python` | |||
- Vitesse-Python 帮助您构建 windows 平台客户端的应用,不再受pyqt的困扰。 | |||
- Vitesse-Python 的视图层采用 HTML+JS+CSS,业务层采用本地 Python。 | |||
- Vitesse-Python 采用了 Vite 的开发模式,支持热更新,开发体验更佳。 | |||
- Vitesse-Python 采用了 PyInstaller 打包,支持 windows 平台,打包体积更小。 | |||
- Vitesse-Python 采用了 pywebview 作为渲染引擎,支持 windows 平台,渲染速度更快。 | |||
- Vitesse-Python 采用了 Vue3、Vitesse 作为前端框架,代码编写更优雅从容。 | |||
### 📦 适用场景 | |||
- 对软件的用户界面有一定美感要求 | |||
- 需要用到 Python 中的人工智能等模块 | |||
- 考虑搭建本地应用,使用本机计算和存储资源 | |||
- 对软件功能要求比较高,需要自己开发 | |||
### 👨💻 适用人群 | |||
- 熟悉 Vue3 和 Python 编程的程序员。 | |||
- 熟悉 HTML、CSS、JS 的前端工程师。 | |||
- 熟悉 Python 的数据分析师。 | |||
- 熟悉 Python 的机器学习工程师。 | |||
- 熟悉 Python 的人工智能工程师。 | |||
- 熟悉 Python 的软件工程师。 | |||
## Features | |||
- ⚡️ [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 | |||
- 🗂 [File based routing](./src/pages) | |||
- 📦 [Components auto importing](./src/components) | |||
- 🍍 [State Management via Pinia](https://pinia.vuejs.org/) | |||
- 📑 [Layout system](./src/layouts) | |||
- 📲 [PWA](https://github.com/antfu/vite-plugin-pwa) | |||
- 🎨 [UnoCSS](https://github.com/antfu/unocss) - the instant on-demand atomic CSS engine | |||
- 😃 [Use icons from any icon sets with classes](https://github.com/antfu/unocss/tree/main/packages/preset-icons) | |||
- 🌍 [I18n ready](./locales) | |||
- 🔎 [Component Preview](https://github.com/johnsoncodehk/vite-plugin-vue-component-preview) | |||
- 🗒 [Markdown Support](https://github.com/antfu/vite-plugin-vue-markdown) | |||
- 🔥 Use the [new `<script setup>` syntax](https://github.com/vuejs/rfcs/pull/227) | |||
- 🤙🏻 [Reactivity Transform](https://vuejs.org/guide/extras/reactivity-transform.html) enabled | |||
- 📥 [APIs auto importing](https://github.com/antfu/unplugin-auto-import) - use Composition API and others directly | |||
- 🖨 Static-site generation (SSG) via [vite-ssg](https://github.com/antfu/vite-ssg) | |||
- 🦔 Critical CSS via [critters](https://github.com/GoogleChromeLabs/critters) | |||
- 🦾 TypeScript, of course | |||
- ☁️ Deploy on Netlify, zero-config | |||
- 🎉 <strong>[Pywebview](https://pywebview.flowrl.com/) inside </strong> | |||
<br> | |||
## Try it now! | |||
> Vitesse-Python requires Node >=14.18 & Python >=3.7 | |||
```bash | |||
### GitHub Template | |||
[Create a repo from this template on GitHub](https://github.com/MarleneJiang/vitesse-python). | |||
### Clone to local | |||
If you prefer to do it manually with the cleaner git history | |||
```bash | |||
git clone https://github.com/MarleneJiang/vitesse-python.git | |||
cd vitesse-python | |||
pnpm inits # If you don't have pnpm installed, run: npm install -g pnpm | |||
``` | |||
## Usage | |||
### 开发前端 | |||
```bash | |||
pnpm dev | |||
``` | |||
### 开发软件 | |||
```bash | |||
pnpm dev:app | |||
``` | |||
### 整体开发 | |||
```bash | |||
pnpm start | |||
``` | |||
### 预打包,带console,方便输出日志信息 | |||
```bash | |||
pnpm pre | |||
``` | |||
### 预打包,带console,生成文件夹,仅win系统 | |||
```bash | |||
pnpm pre:folder | |||
``` | |||
### 正式打包,仅win系统 | |||
```bash | |||
pnpm build | |||
``` | |||
### 正式打包,生成文件夹,仅win系统 | |||
```bash | |||
pnpm build:folder | |||
``` | |||
## 高级用法 | |||
### 客户端引擎介绍 | |||
`Vitesse-Python` 基于 [pywebview](https://pywebview.flowrl.com) 构建客户端。而 pywebview 构架构建客户端的原理是利用本地电脑自带的浏览器引擎驱动,模拟生成客户端。本质上还是网页,或者说是一个浏览器,但是感官上和本地客户端没有差别。 | |||
那么,基于 pywebview 构架构建客户端的成败或质量,就与本地电脑的浏览器引擎息息相关了。 | |||
##### windows 系统 | |||
在 windows 系统上,大体上分为两类客户端引擎:正常模式和兼容模式。`Vitesse-Python` 仅支持正常模式。 | |||
- 正常模式 | |||
正常模式下,按照 edgechromium ,edgehtml, mshtml 的客户端引擎依次检索。如果本地电脑 edge 浏览器支持这些引擎,则客户端可以正常启动。否则,请安装对应的 [EdgeWebView2Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) 浏览器引擎。 | |||
- 兼容模式 | |||
如果本地电脑 edge 浏览器不支持这些引擎,同时也不想下载 [EdgeWebView2Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) ,那么就可以使用兼容模式。兼容模式的原理就是利用 [CEFPython](https://github.com/cztomczak/cefpython),嵌入 Chromium 的 Web 浏览器控件。也就是只要本地电脑安装了谷歌浏览器 V66 版及其以上版本,即可正常启动客户端。缺点就是生成的安装包体积会增加大约 60M 左右。 | |||
### 构建客户端 API | |||
构建客户端的主程序是在 app 文件夹下的 main.py。 | |||
main.py 里面主要是依靠 webview.create_window 和 webview.start 这两个 API 来构建客户端。其他的一些 API,可以直接查看 [pywebview 官网](https://pywebview.flowrl.com/guide/api.html) 了解详情。 | |||
#### webview.create_window | |||
``` | |||
webview.create_window(title, url='', html='', js_api=None, width=800, height=600, \ | |||
x=None, y=None, resizable=True, fullscreen=False, \ | |||
min_size=(200, 100), hidden=False, frameless=False, \ | |||
minimized=False, on_top=False, confirm_close=False, \ | |||
background_color='#FFF') | |||
``` | |||
创建一个新的 pywebview 窗口,并返回其实例。在开始 GUI 循环之前,窗口不会显示。 | |||
- **title** 窗口标题 | |||
- **url** 要加载的 URL。如果 URL 没有协议前缀,则将其解析为相对于应用程序入口点的路径。或者,可以传递 WSGI 服务器对象来启动本地 Web 服务器。 | |||
- **html** 要加载的 HTML 代码。如果同时指定了 URL 和 HTML,HTML 优先。 | |||
- **js_api** 将 python 对象暴露到当前 pywebview 窗口的 DOM 中。js_api 对象的方法可以通过调用 window.pywebview.api.<methodname>(<parameters>)从 Javascript 执行。请注意,调用 Javascript 函数会收到一个包含 python 函数的返回值。只有基本的 Python 对象(如 int、str、dict......)才能返回 Javascript。 | |||
- **width** 窗户宽度。默认值为 800px。 | |||
- **height** 窗户高度。默认值为 600px。 | |||
- **x** 窗口 x 坐标。默认值居中。 | |||
- **y** 窗口 y 坐标。默认值居中。 | |||
- **resizable** 是否可以调整窗口大小。默认值为 True | |||
- **fullscreen** 从全屏模式开始。默认为 False | |||
- **min_size** 指定最小窗口大小的(宽度、高度)元组。默认值为 200x100 | |||
- **hidden** 默认情况下创建一个隐藏的窗口。默认为 False | |||
- **frameless** 创建一个无框窗口。默认值为 False。 | |||
- **minimized** 以最小化模式启动 | |||
- **on_top** 将窗口设置为始终位于其他窗口的顶部。默认值为 False。 | |||
- **confirm_close** 是否显示窗口关闭确认对话框。默认为 False | |||
- **background_color** 加载 WebView 之前显示的窗口的背景颜色。指定为十六进制颜色。默认值为白色。 | |||
- **transparent** 创建一个透明的窗口。Windows 不支持。默认值为 False。请注意,此设置不会隐藏或使窗口铬透明。将窗口 chrome setframeless 隐藏为 True。 | |||
#### webview.start | |||
``` | |||
webview.start(func=None, args=None, localization={}, gui=None, debug=False, http_server=False) | |||
``` | |||
启动 GUI 循环并显示之前创建的窗口。此函数必须从主线程调用。 | |||
- **func** 启动 GUI 循环时调用的函数。 | |||
- **args** 函数参数。可以是单个值,也可以是元组值。 | |||
- **localization** 带有本地化字符串的词典。默认字符串及其键在 localization.py 中定义 | |||
- **gui** 强制使用特定的 GUI。允许的值是 cef、qt 或 gtk,具体取决于平台。 | |||
- **debug** 启用调试模式。 | |||
- **http_server** 启用内置 HTTP 服务器。如果启用,本地文件将使用随机端口上的本地 HTTP 服务器提供服务。对于每个窗口,都会生成一个单独的 HTTP 服务器。对于非本地 URL,此选项将被忽略。 | |||
### 域间通信 | |||
#### 从 Python 调用 Javascript | |||
window.evaluate_js(code, callback=None)允许您使用同步返回的最后一个值执行任意 Javascript 代码。如果提供了回调函数,则解析 promise,并调用回调函数,结果作为参数。Javascript 类型转换为 Python 类型,例如 JS 对象到 Python 字典,数组到列表,未定义为 None。由于实现限制,字符串“null”将被计算为 None。另外,evaluate_js 返回的值限制为 900 个字符内。 | |||
#### 从 Javascript 调用 Python | |||
从 Javascript 调用 Python 函数可以通过两种不同的方法完成。 | |||
- 通过将 Python 类的实例暴露给 create_window 的 js_api。该类的所有可调用方法都将以 pywebview.api.method_name 的形式公开到 JS 域中。方法名称不得以下划线开头。 | |||
- 通过将函数传递给窗口对象的 expose(func)这将以 pywebview.api.func_name 的形式将一个或多个函数公开到 JS 域。与 JS API 不同,expose 也允许在运行时公开函数。如果 JS API 和以这种方式公开的函数之间存在名称冲突,则后者优先。 | |||
## THX | |||
- [vue-pywebview-pyinstaller](https://github.com/pangao1990/vue-pywebview-pyinstaller) |
@@ -0,0 +1,9 @@ | |||
class API: | |||
'''本地API,供前端JS调用''' | |||
window = None | |||
def getOwner(self): | |||
self.window.evaluate_js('getPythonData()') | |||
return '我是Python' |
@@ -0,0 +1,3 @@ | |||
pywebview==3.7.2 | |||
pyinstaller==5.6.2 | |||
tinyaes==1.0.4 |
@@ -0,0 +1,10 @@ | |||
import platform | |||
class Config: | |||
'''配置文件''' | |||
appName = 'Vitesse-Python' # 应用名称 | |||
appVersion = "1.0.0" # 应用版本号 | |||
appSystem = platform.system() # 本机系统类型 |
@@ -0,0 +1,45 @@ | |||
import os | |||
import sys | |||
import webview | |||
import argparse | |||
from api.api import API | |||
from config.config import Config | |||
# 前端页面目录 | |||
if sys.flags.dev_mode: | |||
MAIN_DIR = os.path.join("..", "dist") # 开发环境 | |||
DEBUG = True | |||
else: | |||
MAIN_DIR = os.path.join(".", "web") # 生产环境 | |||
DEBUG = False | |||
def WebViewApp(port,dev=False): | |||
api = API() # 本地接口 | |||
cfg = Config() # 配置文件 | |||
if(dev): | |||
window = webview.create_window(cfg.appName, 'http://localhost:'+str(port)+'/',js_api=api) | |||
webview.start(debug=DEBUG, http_server=True) # 启动窗口 | |||
else: | |||
template = os.path.join(MAIN_DIR, "index.html") # 设置页面,可以指向远程或本地 | |||
window = webview.create_window(title=cfg.appName, url=template, js_api=api) # 创建窗口 | |||
api.window=window # 本地接口 | |||
webview.start(debug=DEBUG, http_server=True) # 启动窗口 | |||
if __name__ == "__main__": | |||
parser = argparse.ArgumentParser() | |||
parser.add_argument( | |||
'--dev', | |||
type=str, | |||
default='False', | |||
help="开发模式") | |||
parser.add_argument( | |||
'--port', | |||
type=str, | |||
default='3333', | |||
help="端口号") | |||
args = parser.parse_args() | |||
WebViewApp(args.port,args.dev=='True') |
@@ -0,0 +1,141 @@ | |||
import sys | |||
import os | |||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))# | |||
from config.config import Config | |||
cfg = Config() | |||
buildPath = 'build' # 存放最终打包成app的相对路径 | |||
console = False # 是否展示终端 | |||
mainName = 'main.py' # 主程序 main.py | |||
cryptoKey = '0123456789123456' # 对Python字节码加密 | |||
appName = cfg.appName # 项目名称 | |||
version = cfg.appVersion # 版本号 | |||
# spec配置文件 前半部分通用格式 | |||
def specFirstPart(): | |||
return f''' | |||
# -*- mode: python ; coding: utf-8 -*- | |||
import json | |||
import os | |||
import sys | |||
import PyInstaller.config | |||
# 存放最终打包成app的相对路径 | |||
buildPath = '{buildPath}' | |||
PyInstaller.config.CONF['distpath'] = buildPath | |||
# 存放打包成app的中间文件的相对路径 | |||
cachePath = os.path.join(buildPath, 'cache') | |||
if not os.path.exists(cachePath): | |||
os.makedirs(cachePath) | |||
PyInstaller.config.CONF['workpath'] = cachePath | |||
# icon相对路径 | |||
icoPath = os.path.join('..', '..', 'public', 'logo.ico') | |||
# 项目名称 | |||
appName = '{appName}' | |||
# 版本号 | |||
version = '{version}' | |||
# 对Python字节码加密 | |||
block_cipher = pyi_crypto.PyiBlockCipher(key='{cryptoKey}') | |||
a = Analysis(['../{mainName}'], | |||
pathex=[], | |||
binaries=[], | |||
datas=[('../../dist', 'web')], | |||
hiddenimports=[], | |||
hookspath=[], | |||
hooksconfig={{}}, | |||
runtime_hooks=[], | |||
excludes=[], | |||
win_no_prefer_redirects=False, | |||
win_private_assemblies=False, | |||
cipher=block_cipher, | |||
noarchive=False) | |||
pyz = PYZ(a.pure, a.zipped_data, | |||
cipher=block_cipher) | |||
''' | |||
# 打包为一个exe文件 | |||
def specPackagePartEXE(): | |||
return f''' | |||
exe = EXE(pyz, | |||
a.scripts, | |||
a.binaries, | |||
a.zipfiles, | |||
a.datas, | |||
[], | |||
name=appName, | |||
debug=False, | |||
bootloader_ignore_signals=False, | |||
strip=False, | |||
upx=True, | |||
upx_exclude=[], | |||
runtime_tmpdir=None, | |||
console={console}, | |||
disable_windowed_traceback=False, | |||
target_arch=None, | |||
codesign_identity=None, | |||
entitlements_file=None, | |||
icon=icoPath) | |||
''' | |||
# 以文件夹形式存在 | |||
def specUnpackagePartEXE(): | |||
return f''' | |||
exe = EXE(pyz, | |||
a.scripts, | |||
[], | |||
exclude_binaries=True, | |||
name=appName, | |||
debug=False, | |||
bootloader_ignore_signals=False, | |||
strip=False, | |||
upx=True, | |||
console={console}, | |||
disable_windowed_traceback=False, | |||
target_arch=None, | |||
codesign_identity=None, | |||
entitlements_file=None, | |||
icon=icoPath) | |||
coll = COLLECT(exe, | |||
a.binaries, | |||
a.zipfiles, | |||
a.datas, | |||
strip=False, | |||
upx=True, | |||
upx_exclude=[], | |||
name=appName) | |||
''' | |||
# 生成 spec 配置文件 | |||
specDir = os.path.dirname(__file__) | |||
# windows.spec | |||
with open(os.path.join(specDir, 'windows.spec'), 'w+', encoding='utf-8') as f: | |||
f.write(specFirstPart() + specPackagePartEXE()) | |||
# windows-folder.spec | |||
with open(os.path.join(specDir, 'windows-folder.spec'), 'w+', encoding='utf-8') as f: | |||
f.write(specFirstPart() + specUnpackagePartEXE()) | |||
console = True # 是否展示终端 | |||
# windows-pre.spec 带终端 | |||
with open(os.path.join(specDir, 'windows-pre.spec'), 'w+', encoding='utf-8') as f: | |||
f.write(specFirstPart() + specPackagePartEXE()) | |||
# windows-folder-pre.spec | |||
with open(os.path.join(specDir, 'windows-folder-pre.spec'), 'w+', encoding='utf-8') as f: | |||
f.write(specFirstPart() + specUnpackagePartEXE()) |
@@ -0,0 +1,22 @@ | |||
<!DOCTYPE html> | |||
<html lang="en"> | |||
<head> | |||
<meta charset="UTF-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |||
<link rel="apple-touch-icon" href="/pwa-192x192.png"> | |||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#00aba9"> | |||
<meta name="msapplication-TileColor" content="#00aba9"> | |||
<script> | |||
(function () { | |||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches | |||
const setting = localStorage.getItem('vueuse-color-scheme') || 'auto' | |||
if (setting === 'dark' || (prefersDark && setting !== 'light')) | |||
document.documentElement.classList.toggle('dark', true) | |||
})() | |||
</script> | |||
</head> | |||
<body class="font-sans"> | |||
<div id="app"></div> | |||
<script type="module" src="/src/main.ts"></script> | |||
</body> | |||
</html> |
@@ -0,0 +1,7 @@ | |||
## i18n | |||
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. | |||
Check out [`vue-i18n`](https://github.com/intlify/vue-i18n-next) for more details. | |||
If you are using VS Code, [`i18n Ally`](https://github.com/lokalise/i18n-ally) is recommended to make the i18n experience better. |
@@ -0,0 +1,14 @@ | |||
button: | |||
about: About | |||
back: Back | |||
go: GO | |||
home: Home | |||
toggle_dark: Toggle dark mode | |||
toggle_langs: Change languages | |||
intro: | |||
desc: Opinionated Vite Starter Template | |||
dynamic-route: Demo of dynamic route | |||
hi: Hi, {name}! | |||
aka: Also known as | |||
whats-your-name: What's your name? | |||
not-found: Not found |
@@ -0,0 +1,14 @@ | |||
button: | |||
about: 关于 | |||
back: 返回 | |||
go: 确定 | |||
home: 首页 | |||
toggle_dark: 切换深色模式 | |||
toggle_langs: 切换语言 | |||
intro: | |||
desc: 固执己见的 Vite 项目模板 | |||
dynamic-route: 动态路由演示 | |||
hi: 你好,{name} | |||
aka: 也叫 | |||
whats-your-name: 输入你的名字 | |||
not-found: 未找到页面 |
@@ -0,0 +1,16 @@ | |||
[build.environment] | |||
NODE_VERSION = "16" | |||
[build] | |||
publish = "dist" | |||
command = "pnpm run build" | |||
[[redirects]] | |||
from = "/*" | |||
to = "/index.html" | |||
status = 200 | |||
[[headers]] | |||
for = "/manifest.webmanifest" | |||
[headers.values] | |||
Content-Type = "application/manifest+json" |
@@ -0,0 +1,88 @@ | |||
{ | |||
"name": "vitesse-python", | |||
"type": "module", | |||
"private": true, | |||
"packageManager": "pnpm@7.8.0", | |||
"description": "基于vitesse,pywebview的python桌面应用", | |||
"author": "Marlene <1677568218@qq.com>", | |||
"scripts": { | |||
"dev": "vite --port 3333 --open ", | |||
"dev:app": "python app\\main.py --port 3333 --dev 'True'", | |||
"lint": "eslint .", | |||
"preview": "vite preview", | |||
"preview-https": "serve dist", | |||
"typecheck": "vue-tsc --noEmit", | |||
"up": "taze major -I", | |||
"inits": "pnpm install && run-script-os", | |||
"inits:windows": "python app\\spec\\getSpec.py && pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r .\\app\\assets\\requirements.txt", | |||
"start": "vite build && run-script-os", | |||
"start:windows": "python -X dev .\\app\\main.py", | |||
"pre": "shx rm -rf build && vite build && run-script-os", | |||
"pre:windows": "pyinstaller --clean .\\app\\spec\\windows-pre.spec", | |||
"pre:folder": "shx rm -rf build && vite build && pyinstaller --clean .\\app\\spec\\windows-folder-pre.spec", | |||
"build": "shx rm -rf build && vite build && run-script-os", | |||
"build:windows": "pyinstaller -w --clean .\\app\\spec\\windows.spec", | |||
"build:folder": "shx rm -rf build && vite build && pyinstaller --clean .\\app\\spec\\windows-folder.spec" | |||
}, | |||
"dependencies": { | |||
"@unocss/reset": "^0.46.5", | |||
"@vueuse/core": "^9.5.0", | |||
"@vueuse/head": "^1.0.18", | |||
"nprogress": "^0.2.0", | |||
"pinia": "^2.0.25", | |||
"run-script-os": "^1.1.6", | |||
"shx": "^0.3.4", | |||
"vue": "^3.2.45", | |||
"vue-demi": "^0.13.11", | |||
"vue-i18n": "^9.2.2", | |||
"vue-router": "^4.1.6" | |||
}, | |||
"devDependencies": { | |||
"@antfu/eslint-config": "^0.31.0", | |||
"@iconify-json/carbon": "^1.1.11", | |||
"@intlify/vite-plugin-vue-i18n": "^6.0.3", | |||
"@types/markdown-it-link-attributes": "^3.0.1", | |||
"@types/nprogress": "^0.2.0", | |||
"@vitejs/plugin-vue": "^3.2.0", | |||
"@vue-macros/volar": "^0.5.4", | |||
"@vue/test-utils": "^2.2.4", | |||
"critters": "^0.0.16", | |||
"cross-env": "^7.0.3", | |||
"eslint": "^8.28.0", | |||
"https-localhost": "^4.7.1", | |||
"markdown-it-link-attributes": "^4.0.1", | |||
"markdown-it-shiki": "^0.6.1", | |||
"pnpm": "^7.17.0", | |||
"shiki": "^0.11.1", | |||
"taze": "^0.8.4", | |||
"typescript": "^4.9.3", | |||
"unocss": "^0.46.5", | |||
"unplugin-auto-import": "^0.11.5", | |||
"unplugin-vue-components": "^0.22.11", | |||
"unplugin-vue-macros": "^1.0.0", | |||
"vite": "^3.2.4", | |||
"vite-plugin-inspect": "^0.7.9", | |||
"vite-plugin-pages": "^0.27.1", | |||
"vite-plugin-pwa": "^0.13.3", | |||
"vite-plugin-vue-component-preview": "^0.3.3", | |||
"vite-plugin-vue-layouts": "^0.7.0", | |||
"vite-plugin-vue-markdown": "^0.22.1", | |||
"vite-ssg": "^0.22.0", | |||
"vite-ssg-sitemap": "^0.4.3", | |||
"vue-tsc": "^1.0.9" | |||
}, | |||
"version": "1.0.0", | |||
"main": "index.js", | |||
"repository": { | |||
"type": "git", | |||
"url": "git+https://github.com/MarleneJiang/vitesse-python.git" | |||
}, | |||
"keywords": [ | |||
"qt5" | |||
], | |||
"license": "MIT", | |||
"bugs": { | |||
"url": "https://github.com/MarleneJiang/vitesse-python/issues" | |||
}, | |||
"homepage": "https://github.com/MarleneJiang/vitesse-python#readme" | |||
} |
@@ -0,0 +1,3 @@ | |||
/assets/* | |||
cache-control: max-age=31536000 | |||
cache-control: immutable |
@@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none"> | |||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.562 26L17.17 8.928l2.366-3.888L17.828 4L16 7.005L14.17 4l-1.708 1.04l2.366 3.888L4.438 26H2v2h28v-2zM16 10.85L25.22 26H17v-8h-2v8H6.78z" fill="white" /> | |||
</svg> |
@@ -0,0 +1,3 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none"> | |||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.562 26L17.17 8.928l2.366-3.888L17.828 4L16 7.005L14.17 4l-1.708 1.04l2.366 3.888L4.438 26H2v2h28v-2zM16 10.85L25.22 26H17v-8h-2v8H6.78z" fill="#222" /> | |||
</svg> |
@@ -0,0 +1,41 @@ | |||
<?xml version="1.0" standalone="no"?> | |||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" | |||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> | |||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" | |||
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000" | |||
preserveAspectRatio="xMidYMid meet"> | |||
<metadata> | |||
Created by potrace 1.11, written by Peter Selinger 2001-2013 | |||
</metadata> | |||
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)" | |||
fill="#000000" stroke="none"> | |||
<path d="M2916 6015 c-93 -57 -173 -108 -178 -113 -6 -6 7 -36 33 -78 23 -38 | |||
86 -141 139 -229 54 -88 135 -221 180 -295 46 -74 94 -155 108 -180 14 -25 29 | |||
-52 35 -60 7 -12 -9 -45 -62 -130 -39 -63 -85 -140 -103 -170 -18 -30 -117 | |||
-194 -222 -365 -104 -170 -199 -326 -210 -346 -12 -19 -61 -102 -111 -183 -49 | |||
-81 -101 -166 -115 -189 -14 -23 -39 -64 -55 -90 -17 -27 -77 -126 -134 -220 | |||
-57 -95 -127 -210 -156 -257 -194 -315 -325 -533 -325 -541 0 -5 -4 -9 -10 -9 | |||
-5 0 -10 -4 -10 -9 0 -5 -55 -98 -121 -207 -247 -404 -403 -660 -416 -684 -8 | |||
-14 -58 -97 -112 -185 l-98 -160 -189 -2 c-104 -1 -225 -2 -269 -2 l-80 -1 1 | |||
-210 c0 -116 4 -213 8 -218 11 -11 6107 -9 6114 2 8 13 8 406 0 419 -4 7 -88 | |||
10 -265 9 l-259 -2 -50 77 c-27 43 -54 87 -60 98 -6 11 -62 103 -124 205 -62 | |||
102 -120 197 -129 212 -9 16 -85 142 -170 280 -85 139 -160 262 -165 273 -6 | |||
11 -13 22 -16 25 -3 3 -30 46 -59 95 -30 50 -102 169 -161 265 -59 96 -240 | |||
393 -402 660 -163 267 -371 609 -463 760 -92 151 -194 318 -225 370 -31 52 | |||
-101 167 -155 255 l-97 160 27 50 c16 27 32 55 36 61 5 5 38 59 74 120 36 60 | |||
69 116 74 124 5 8 75 122 155 253 81 131 144 242 141 247 -4 7 -114 76 -183 | |||
115 -10 6 -52 32 -95 58 -42 27 -81 46 -87 42 -8 -5 -94 -140 -140 -219 -19 | |||
-33 -221 -365 -246 -404 -15 -22 -18 -18 -111 135 -52 87 -123 203 -157 258 | |||
-67 108 -67 110 -111 184 -16 28 -34 51 -40 50 -5 0 -86 -47 -179 -104z m739 | |||
-1642 c319 -526 519 -854 637 -1046 43 -70 78 -130 78 -133 0 -2 5 -10 10 -17 | |||
6 -7 69 -109 140 -227 72 -118 134 -222 139 -230 5 -8 55 -89 111 -180 56 -91 | |||
105 -172 110 -180 9 -14 52 -84 270 -445 54 -88 135 -221 180 -295 46 -74 91 | |||
-148 100 -165 9 -16 31 -53 48 -81 18 -28 32 -54 32 -57 0 -3 -403 -6 -895 -5 | |||
l-895 0 0 81 c-1 45 -1 439 -1 875 l0 792 -37 1 c-57 1 -344 1 -374 0 l-27 -1 | |||
0 -832 c0 -458 0 -852 0 -875 l-1 -42 -895 1 c-492 0 -895 3 -895 5 0 9 115 | |||
198 122 201 5 2 8 7 8 12 0 5 23 46 51 92 28 46 78 128 112 183 33 55 70 116 | |||
82 135 12 19 132 215 265 435 133 220 266 438 295 485 65 105 206 338 220 362 | |||
6 10 172 284 370 608 198 325 387 635 420 690 33 55 62 100 65 100 3 0 73 | |||
-111 155 -247z"/> | |||
</g> | |||
</svg> |
@@ -0,0 +1,26 @@ | |||
<script setup lang="ts"> | |||
// https://github.com/vueuse/head | |||
// you can use this to manipulate the document head in any components, | |||
// they will be rendered correctly in the html results with vite-ssg | |||
useHead({ | |||
title: 'Vitesse', | |||
meta: [ | |||
{ name: 'description', content: 'Opinionated Vite Starter Template' }, | |||
{ | |||
name: 'theme-color', | |||
content: computed(() => isDark.value ? '#00aba9' : '#ffffff'), | |||
}, | |||
], | |||
link: [ | |||
{ | |||
rel: 'icon', | |||
type: 'image/svg+xml', | |||
href: computed(() => preferredDark.value ? '/favicon-dark.svg' : '/favicon.svg'), | |||
}, | |||
], | |||
}) | |||
</script> | |||
<template> | |||
<RouterView /> | |||
</template> |
@@ -0,0 +1,560 @@ | |||
// Generated by 'unplugin-auto-import' | |||
export {} | |||
declare global { | |||
const $$: typeof import('vue/macros')['$$'] | |||
const $: typeof import('vue/macros')['$'] | |||
const $computed: typeof import('vue/macros')['$computed'] | |||
const $customRef: typeof import('vue/macros')['$customRef'] | |||
const $ref: typeof import('vue/macros')['$ref'] | |||
const $shallowRef: typeof import('vue/macros')['$shallowRef'] | |||
const $toRef: typeof import('vue/macros')['$toRef'] | |||
const EffectScope: typeof import('vue')['EffectScope'] | |||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] | |||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] | |||
const computed: typeof import('vue')['computed'] | |||
const computedAsync: typeof import('@vueuse/core')['computedAsync'] | |||
const computedEager: typeof import('@vueuse/core')['computedEager'] | |||
const computedInject: typeof import('@vueuse/core')['computedInject'] | |||
const computedWithControl: typeof import('@vueuse/core')['computedWithControl'] | |||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed'] | |||
const controlledRef: typeof import('@vueuse/core')['controlledRef'] | |||
const createApp: typeof import('vue')['createApp'] | |||
const createEventHook: typeof import('@vueuse/core')['createEventHook'] | |||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState'] | |||
const createInjectionState: typeof import('@vueuse/core')['createInjectionState'] | |||
const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn'] | |||
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable'] | |||
const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn'] | |||
const customRef: typeof import('vue')['customRef'] | |||
const debouncedRef: typeof import('@vueuse/core')['debouncedRef'] | |||
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch'] | |||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] | |||
const defineComponent: typeof import('vue')['defineComponent'] | |||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed'] | |||
const effectScope: typeof import('vue')['effectScope'] | |||
const extendRef: typeof import('@vueuse/core')['extendRef'] | |||
const getCurrentInstance: typeof import('vue')['getCurrentInstance'] | |||
const getCurrentScope: typeof import('vue')['getCurrentScope'] | |||
const h: typeof import('vue')['h'] | |||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] | |||
const inject: typeof import('vue')['inject'] | |||
const isDark: typeof import('./composables/dark')['isDark'] | |||
const isDefined: typeof import('@vueuse/core')['isDefined'] | |||
const isProxy: typeof import('vue')['isProxy'] | |||
const isReactive: typeof import('vue')['isReactive'] | |||
const isReadonly: typeof import('vue')['isReadonly'] | |||
const isRef: typeof import('vue')['isRef'] | |||
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable'] | |||
const markRaw: typeof import('vue')['markRaw'] | |||
const nextTick: typeof import('vue')['nextTick'] | |||
const onActivated: typeof import('vue')['onActivated'] | |||
const onBeforeMount: typeof import('vue')['onBeforeMount'] | |||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] | |||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] | |||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] | |||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] | |||
const onClickOutside: typeof import('@vueuse/core')['onClickOutside'] | |||
const onDeactivated: typeof import('vue')['onDeactivated'] | |||
const onErrorCaptured: typeof import('vue')['onErrorCaptured'] | |||
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke'] | |||
const onLongPress: typeof import('@vueuse/core')['onLongPress'] | |||
const onMounted: typeof import('vue')['onMounted'] | |||
const onRenderTracked: typeof import('vue')['onRenderTracked'] | |||
const onRenderTriggered: typeof import('vue')['onRenderTriggered'] | |||
const onScopeDispose: typeof import('vue')['onScopeDispose'] | |||
const onServerPrefetch: typeof import('vue')['onServerPrefetch'] | |||
const onStartTyping: typeof import('@vueuse/core')['onStartTyping'] | |||
const onUnmounted: typeof import('vue')['onUnmounted'] | |||
const onUpdated: typeof import('vue')['onUpdated'] | |||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch'] | |||
const preferredDark: typeof import('./composables/dark')['preferredDark'] | |||
const provide: typeof import('vue')['provide'] | |||
const reactify: typeof import('@vueuse/core')['reactify'] | |||
const reactifyObject: typeof import('@vueuse/core')['reactifyObject'] | |||
const reactive: typeof import('vue')['reactive'] | |||
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed'] | |||
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit'] | |||
const reactivePick: typeof import('@vueuse/core')['reactivePick'] | |||
const readonly: typeof import('vue')['readonly'] | |||
const ref: typeof import('vue')['ref'] | |||
const refAutoReset: typeof import('@vueuse/core')['refAutoReset'] | |||
const refDebounced: typeof import('@vueuse/core')['refDebounced'] | |||
const refDefault: typeof import('@vueuse/core')['refDefault'] | |||
const refThrottled: typeof import('@vueuse/core')['refThrottled'] | |||
const refWithControl: typeof import('@vueuse/core')['refWithControl'] | |||
const resolveComponent: typeof import('vue')['resolveComponent'] | |||
const resolveDirective: typeof import('vue')['resolveDirective'] | |||
const resolveRef: typeof import('@vueuse/core')['resolveRef'] | |||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] | |||
const shallowReactive: typeof import('vue')['shallowReactive'] | |||
const shallowReadonly: typeof import('vue')['shallowReadonly'] | |||
const shallowRef: typeof import('vue')['shallowRef'] | |||
const syncRef: typeof import('@vueuse/core')['syncRef'] | |||
const syncRefs: typeof import('@vueuse/core')['syncRefs'] | |||
const templateRef: typeof import('@vueuse/core')['templateRef'] | |||
const throttledRef: typeof import('@vueuse/core')['throttledRef'] | |||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch'] | |||
const toRaw: typeof import('vue')['toRaw'] | |||
const toReactive: typeof import('@vueuse/core')['toReactive'] | |||
const toRef: typeof import('vue')['toRef'] | |||
const toRefs: typeof import('vue')['toRefs'] | |||
const toggleDark: typeof import('./composables/dark')['toggleDark'] | |||
const triggerRef: typeof import('vue')['triggerRef'] | |||
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount'] | |||
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount'] | |||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted'] | |||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose'] | |||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted'] | |||
const unref: typeof import('vue')['unref'] | |||
const unrefElement: typeof import('@vueuse/core')['unrefElement'] | |||
const until: typeof import('@vueuse/core')['until'] | |||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement'] | |||
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery'] | |||
const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter'] | |||
const useArrayFind: typeof import('@vueuse/core')['useArrayFind'] | |||
const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex'] | |||
const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin'] | |||
const useArrayMap: typeof import('@vueuse/core')['useArrayMap'] | |||
const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce'] | |||
const useArraySome: typeof import('@vueuse/core')['useArraySome'] | |||
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue'] | |||
const useAsyncState: typeof import('@vueuse/core')['useAsyncState'] | |||
const useAttrs: typeof import('vue')['useAttrs'] | |||
const useBase64: typeof import('@vueuse/core')['useBase64'] | |||
const useBattery: typeof import('@vueuse/core')['useBattery'] | |||
const useBluetooth: typeof import('@vueuse/core')['useBluetooth'] | |||
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints'] | |||
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel'] | |||
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation'] | |||
const useCached: typeof import('@vueuse/core')['useCached'] | |||
const useClipboard: typeof import('@vueuse/core')['useClipboard'] | |||
const useCloned: typeof import('@vueuse/core')['useCloned'] | |||
const useColorMode: typeof import('@vueuse/core')['useColorMode'] | |||
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog'] | |||
const useCounter: typeof import('@vueuse/core')['useCounter'] | |||
const useCssModule: typeof import('vue')['useCssModule'] | |||
const useCssVar: typeof import('@vueuse/core')['useCssVar'] | |||
const useCssVars: typeof import('vue')['useCssVars'] | |||
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement'] | |||
const useCycleList: typeof import('@vueuse/core')['useCycleList'] | |||
const useDark: typeof import('@vueuse/core')['useDark'] | |||
const useDateFormat: typeof import('@vueuse/core')['useDateFormat'] | |||
const useDebounce: typeof import('@vueuse/core')['useDebounce'] | |||
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn'] | |||
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory'] | |||
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion'] | |||
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation'] | |||
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio'] | |||
const useDevicesList: typeof import('@vueuse/core')['useDevicesList'] | |||
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia'] | |||
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility'] | |||
const useDraggable: typeof import('@vueuse/core')['useDraggable'] | |||
const useDropZone: typeof import('@vueuse/core')['useDropZone'] | |||
const useElementBounding: typeof import('@vueuse/core')['useElementBounding'] | |||
const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint'] | |||
const useElementHover: typeof import('@vueuse/core')['useElementHover'] | |||
const useElementSize: typeof import('@vueuse/core')['useElementSize'] | |||
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility'] | |||
const useEventBus: typeof import('@vueuse/core')['useEventBus'] | |||
const useEventListener: typeof import('@vueuse/core')['useEventListener'] | |||
const useEventSource: typeof import('@vueuse/core')['useEventSource'] | |||
const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper'] | |||
const useFavicon: typeof import('@vueuse/core')['useFavicon'] | |||
const useFetch: typeof import('@vueuse/core')['useFetch'] | |||
const useFileDialog: typeof import('@vueuse/core')['useFileDialog'] | |||
const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess'] | |||
const useFocus: typeof import('@vueuse/core')['useFocus'] | |||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin'] | |||
const useFps: typeof import('@vueuse/core')['useFps'] | |||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen'] | |||
const useGamepad: typeof import('@vueuse/core')['useGamepad'] | |||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation'] | |||
const useHead: typeof import('@vueuse/head')['useHead'] | |||
const useI18n: typeof import('vue-i18n')['useI18n'] | |||
const useIdle: typeof import('@vueuse/core')['useIdle'] | |||
const useImage: typeof import('@vueuse/core')['useImage'] | |||
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll'] | |||
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver'] | |||
const useInterval: typeof import('@vueuse/core')['useInterval'] | |||
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn'] | |||
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier'] | |||
const useLastChanged: typeof import('@vueuse/core')['useLastChanged'] | |||
const useLink: typeof import('vue-router')['useLink'] | |||
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage'] | |||
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys'] | |||
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory'] | |||
const useMediaControls: typeof import('@vueuse/core')['useMediaControls'] | |||
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery'] | |||
const useMemoize: typeof import('@vueuse/core')['useMemoize'] | |||
const useMemory: typeof import('@vueuse/core')['useMemory'] | |||
const useMounted: typeof import('@vueuse/core')['useMounted'] | |||
const useMouse: typeof import('@vueuse/core')['useMouse'] | |||
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement'] | |||
const useMousePressed: typeof import('@vueuse/core')['useMousePressed'] | |||
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver'] | |||
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage'] | |||
const useNetwork: typeof import('@vueuse/core')['useNetwork'] | |||
const useNow: typeof import('@vueuse/core')['useNow'] | |||
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl'] | |||
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination'] | |||
const useOnline: typeof import('@vueuse/core')['useOnline'] | |||
const usePageLeave: typeof import('@vueuse/core')['usePageLeave'] | |||
const useParallax: typeof import('@vueuse/core')['useParallax'] | |||
const usePermission: typeof import('@vueuse/core')['usePermission'] | |||
const usePointer: typeof import('@vueuse/core')['usePointer'] | |||
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe'] | |||
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme'] | |||
const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast'] | |||
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark'] | |||
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages'] | |||
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion'] | |||
const useRafFn: typeof import('@vueuse/core')['useRafFn'] | |||
const useRefHistory: typeof import('@vueuse/core')['useRefHistory'] | |||
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver'] | |||
const useRoute: typeof import('vue-router')['useRoute'] | |||
const useRouter: typeof import('vue-router')['useRouter'] | |||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation'] | |||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea'] | |||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag'] | |||
const useScroll: typeof import('@vueuse/core')['useScroll'] | |||
const useScrollLock: typeof import('@vueuse/core')['useScrollLock'] | |||
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage'] | |||
const useShare: typeof import('@vueuse/core')['useShare'] | |||
const useSlots: typeof import('vue')['useSlots'] | |||
const useSorted: typeof import('@vueuse/core')['useSorted'] | |||
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition'] | |||
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis'] | |||
const useStepper: typeof import('@vueuse/core')['useStepper'] | |||
const useStorage: typeof import('@vueuse/core')['useStorage'] | |||
const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync'] | |||
const useStyleTag: typeof import('@vueuse/core')['useStyleTag'] | |||
const useSupported: typeof import('@vueuse/core')['useSupported'] | |||
const useSwipe: typeof import('@vueuse/core')['useSwipe'] | |||
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList'] | |||
const useTextDirection: typeof import('@vueuse/core')['useTextDirection'] | |||
const useTextSelection: typeof import('@vueuse/core')['useTextSelection'] | |||
const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize'] | |||
const useThrottle: typeof import('@vueuse/core')['useThrottle'] | |||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn'] | |||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory'] | |||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo'] | |||
const useTimeout: typeof import('@vueuse/core')['useTimeout'] | |||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn'] | |||
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll'] | |||
const useTimestamp: typeof import('@vueuse/core')['useTimestamp'] | |||
const useTitle: typeof import('@vueuse/core')['useTitle'] | |||
const useToNumber: typeof import('@vueuse/core')['useToNumber'] | |||
const useToString: typeof import('@vueuse/core')['useToString'] | |||
const useToggle: typeof import('@vueuse/core')['useToggle'] | |||
const useTransition: typeof import('@vueuse/core')['useTransition'] | |||
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams'] | |||
const useUserMedia: typeof import('@vueuse/core')['useUserMedia'] | |||
const useUserStore: typeof import('./store/user')['useUserStore'] | |||
const useVModel: typeof import('@vueuse/core')['useVModel'] | |||
const useVModels: typeof import('@vueuse/core')['useVModels'] | |||
const useVibrate: typeof import('@vueuse/core')['useVibrate'] | |||
const useVirtualList: typeof import('@vueuse/core')['useVirtualList'] | |||
const useWakeLock: typeof import('@vueuse/core')['useWakeLock'] | |||
const useWebNotification: typeof import('@vueuse/core')['useWebNotification'] | |||
const useWebSocket: typeof import('@vueuse/core')['useWebSocket'] | |||
const useWebWorker: typeof import('@vueuse/core')['useWebWorker'] | |||
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn'] | |||
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus'] | |||
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll'] | |||
const useWindowSize: typeof import('@vueuse/core')['useWindowSize'] | |||
const watch: typeof import('vue')['watch'] | |||
const watchArray: typeof import('@vueuse/core')['watchArray'] | |||
const watchAtMost: typeof import('@vueuse/core')['watchAtMost'] | |||
const watchDebounced: typeof import('@vueuse/core')['watchDebounced'] | |||
const watchEffect: typeof import('vue')['watchEffect'] | |||
const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable'] | |||
const watchOnce: typeof import('@vueuse/core')['watchOnce'] | |||
const watchPausable: typeof import('@vueuse/core')['watchPausable'] | |||
const watchPostEffect: typeof import('vue')['watchPostEffect'] | |||
const watchSyncEffect: typeof import('vue')['watchSyncEffect'] | |||
const watchThrottled: typeof import('@vueuse/core')['watchThrottled'] | |||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable'] | |||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] | |||
const whenever: typeof import('@vueuse/core')['whenever'] | |||
} | |||
// for vue template auto import | |||
import { UnwrapRef } from 'vue' | |||
declare module 'vue' { | |||
interface ComponentCustomProperties { | |||
readonly $$: UnwrapRef<typeof import('vue/macros')['$$']> | |||
readonly $: UnwrapRef<typeof import('vue/macros')['$']> | |||
readonly $computed: UnwrapRef<typeof import('vue/macros')['$computed']> | |||
readonly $customRef: UnwrapRef<typeof import('vue/macros')['$customRef']> | |||
readonly $ref: UnwrapRef<typeof import('vue/macros')['$ref']> | |||
readonly $shallowRef: UnwrapRef<typeof import('vue/macros')['$shallowRef']> | |||
readonly $toRef: UnwrapRef<typeof import('vue/macros')['$toRef']> | |||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> | |||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']> | |||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']> | |||
readonly computed: UnwrapRef<typeof import('vue')['computed']> | |||
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']> | |||
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']> | |||
readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']> | |||
readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']> | |||
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']> | |||
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']> | |||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']> | |||
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']> | |||
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']> | |||
readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']> | |||
readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']> | |||
readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']> | |||
readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']> | |||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']> | |||
readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']> | |||
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']> | |||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']> | |||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']> | |||
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']> | |||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']> | |||
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']> | |||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']> | |||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']> | |||
readonly h: UnwrapRef<typeof import('vue')['h']> | |||
readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']> | |||
readonly inject: UnwrapRef<typeof import('vue')['inject']> | |||
readonly isDark: UnwrapRef<typeof import('./composables/dark')['isDark']> | |||
readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']> | |||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']> | |||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']> | |||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']> | |||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']> | |||
readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']> | |||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']> | |||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']> | |||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']> | |||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']> | |||
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']> | |||
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']> | |||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']> | |||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']> | |||
readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']> | |||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']> | |||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']> | |||
readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']> | |||
readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']> | |||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']> | |||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']> | |||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']> | |||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']> | |||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']> | |||
readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']> | |||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']> | |||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']> | |||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']> | |||
readonly preferredDark: UnwrapRef<typeof import('./composables/dark')['preferredDark']> | |||
readonly provide: UnwrapRef<typeof import('vue')['provide']> | |||
readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']> | |||
readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']> | |||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']> | |||
readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']> | |||
readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']> | |||
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']> | |||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']> | |||
readonly ref: UnwrapRef<typeof import('vue')['ref']> | |||
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']> | |||
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']> | |||
readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']> | |||
readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']> | |||
readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']> | |||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']> | |||
readonly resolveDirective: UnwrapRef<typeof import('vue')['resolveDirective']> | |||
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']> | |||
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']> | |||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']> | |||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']> | |||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']> | |||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']> | |||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']> | |||
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']> | |||
readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']> | |||
readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']> | |||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']> | |||
readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']> | |||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']> | |||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']> | |||
readonly toggleDark: UnwrapRef<typeof import('./composables/dark')['toggleDark']> | |||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']> | |||
readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']> | |||
readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']> | |||
readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']> | |||
readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']> | |||
readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']> | |||
readonly unref: UnwrapRef<typeof import('vue')['unref']> | |||
readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']> | |||
readonly until: UnwrapRef<typeof import('@vueuse/core')['until']> | |||
readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']> | |||
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']> | |||
readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']> | |||
readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']> | |||
readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']> | |||
readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']> | |||
readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']> | |||
readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']> | |||
readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']> | |||
readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']> | |||
readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']> | |||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']> | |||
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']> | |||
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']> | |||
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']> | |||
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']> | |||
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']> | |||
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']> | |||
readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']> | |||
readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']> | |||
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']> | |||
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']> | |||
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']> | |||
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']> | |||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']> | |||
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']> | |||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']> | |||
readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']> | |||
readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']> | |||
readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']> | |||
readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']> | |||
readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']> | |||
readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']> | |||
readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']> | |||
readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']> | |||
readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']> | |||
readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']> | |||
readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']> | |||
readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']> | |||
readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']> | |||
readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']> | |||
readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']> | |||
readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']> | |||
readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']> | |||
readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']> | |||
readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']> | |||
readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']> | |||
readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']> | |||
readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']> | |||
readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']> | |||
readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']> | |||
readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']> | |||
readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']> | |||
readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']> | |||
readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']> | |||
readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']> | |||
readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']> | |||
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']> | |||
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']> | |||
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']> | |||
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']> | |||
readonly useHead: UnwrapRef<typeof import('@vueuse/head')['useHead']> | |||
readonly useI18n: UnwrapRef<typeof import('vue-i18n')['useI18n']> | |||
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']> | |||
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']> | |||
readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']> | |||
readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']> | |||
readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']> | |||
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']> | |||
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']> | |||
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']> | |||
readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']> | |||
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']> | |||
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']> | |||
readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']> | |||
readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']> | |||
readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']> | |||
readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']> | |||
readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']> | |||
readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']> | |||
readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']> | |||
readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']> | |||
readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']> | |||
readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']> | |||
readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']> | |||
readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']> | |||
readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']> | |||
readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']> | |||
readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']> | |||
readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']> | |||
readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']> | |||
readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']> | |||
readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']> | |||
readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']> | |||
readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']> | |||
readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']> | |||
readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']> | |||
readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']> | |||
readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']> | |||
readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']> | |||
readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']> | |||
readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']> | |||
readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']> | |||
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']> | |||
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']> | |||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']> | |||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']> | |||
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']> | |||
readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']> | |||
readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']> | |||
readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']> | |||
readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']> | |||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']> | |||
readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']> | |||
readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']> | |||
readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']> | |||
readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']> | |||
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']> | |||
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']> | |||
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']> | |||
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']> | |||
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']> | |||
readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']> | |||
readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']> | |||
readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']> | |||
readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']> | |||
readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']> | |||
readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']> | |||
readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']> | |||
readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']> | |||
readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']> | |||
readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']> | |||
readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']> | |||
readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']> | |||
readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']> | |||
readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']> | |||
readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']> | |||
readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']> | |||
readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']> | |||
readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']> | |||
readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']> | |||
readonly useUserStore: UnwrapRef<typeof import('./store/user')['useUserStore']> | |||
readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']> | |||
readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']> | |||
readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']> | |||
readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']> | |||
readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']> | |||
readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']> | |||
readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']> | |||
readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']> | |||
readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']> | |||
readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']> | |||
readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']> | |||
readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']> | |||
readonly watch: UnwrapRef<typeof import('vue')['watch']> | |||
readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']> | |||
readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']> | |||
readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']> | |||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']> | |||
readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']> | |||
readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']> | |||
readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']> | |||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']> | |||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']> | |||
readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']> | |||
readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']> | |||
readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']> | |||
readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']> | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
// generated by unplugin-vue-components | |||
// We suggest you to commit this file into source control | |||
// Read more: https://github.com/vuejs/core/pull/3399 | |||
import '@vue/runtime-core' | |||
export {} | |||
declare module '@vue/runtime-core' { | |||
export interface GlobalComponents { | |||
Counter: typeof import('./components/Counter.vue')['default'] | |||
Footer: typeof import('./components/Footer.vue')['default'] | |||
Input: typeof import('./components/Input.vue')['default'] | |||
README: typeof import('./components/README.md')['default'] | |||
RouterLink: typeof import('vue-router')['RouterLink'] | |||
RouterView: typeof import('vue-router')['RouterView'] | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
<script setup lang="ts"> | |||
const props = defineProps<{ | |||
initial: number | |||
}>() | |||
const { count, inc, dec } = useCounter(props.initial) | |||
</script> | |||
<template> | |||
<div> | |||
{{ count }} | |||
<button class="inc" @click="inc()"> | |||
+ | |||
</button> | |||
<button class="dec" @click="dec()"> | |||
- | |||
</button> | |||
</div> | |||
</template> |
@@ -0,0 +1,33 @@ | |||
<script setup lang="ts"> | |||
const { t, availableLocales, locale } = useI18n() | |||
const toggleLocales = () => { | |||
// change to some real logic | |||
const locales = availableLocales | |||
locale.value = locales[(locales.indexOf(locale.value) + 1) % locales.length] | |||
} | |||
</script> | |||
<template> | |||
<nav text-xl mt-6> | |||
<RouterLink class="icon-btn mx-2" to="/" :title="t('button.home')"> | |||
<div i-carbon-campsite /> | |||
</RouterLink> | |||
<button class="icon-btn mx-2 !outline-none" :title="t('button.toggle_dark')" @click="toggleDark()"> | |||
<div i="carbon-sun dark:carbon-moon" /> | |||
</button> | |||
<a class="icon-btn mx-2" :title="t('button.toggle_langs')" @click="toggleLocales()"> | |||
<div i-carbon-language /> | |||
</a> | |||
<RouterLink class="icon-btn mx-2" to="/about" :title="t('button.about')"> | |||
<div i-carbon-dicom-overlay /> | |||
</RouterLink> | |||
<a class="icon-btn mx-2" rel="noreferrer" href="https://github.com/antfu/vitesse" target="_blank" title="GitHub"> | |||
<div i-carbon-logo-github /> | |||
</a> | |||
</nav> | |||
</template> |
@@ -0,0 +1,20 @@ | |||
<script setup lang="ts"> | |||
const { modelValue } = defineModel<{ | |||
modelValue: string | |||
}>() | |||
</script> | |||
<template> | |||
<input | |||
id="input" | |||
v-model="modelValue" | |||
type="text" | |||
v-bind="$attrs" | |||
p="x-4 y-2" | |||
w="250px" | |||
text="center" | |||
bg="transparent" | |||
border="~ rounded gray-200 dark:gray-700" | |||
outline="none active:none" | |||
> | |||
</template> |
@@ -0,0 +1,10 @@ | |||
## Components | |||
Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components). | |||
### Icons | |||
You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/). | |||
It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details. |
@@ -0,0 +1,4 @@ | |||
// these APIs are auto-imported from @vueuse/core | |||
export const isDark = useDark() | |||
export const toggleDark = useToggle(isDark) | |||
export const preferredDark = usePreferredDark() |
@@ -0,0 +1,19 @@ | |||
<script setup lang="ts"> | |||
const router = useRouter() | |||
const { t } = useI18n() | |||
router.currentRoute.value.path === '/index.html' && router.push('/') // redirect to home page & fix pywebview issue | |||
</script> | |||
<template> | |||
<main p="x4 y10" text="center teal-700 dark:gray-200"> | |||
<div text-4xl> | |||
<div i-carbon-warning inline-block /> | |||
</div> | |||
<RouterView /> | |||
<div> | |||
<button btn text-sm m="3 t8" @click="router.back"> | |||
{{ t('button.back') }} | |||
</button> | |||
</div> | |||
</main> | |||
</template> |
@@ -0,0 +1,14 @@ | |||
## Layouts | |||
Vue components in this dir are used as layouts. | |||
By default, `default.vue` will be used unless an alternative is specified in the route meta. | |||
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: | |||
```html | |||
<route lang="yaml"> | |||
meta: | |||
layout: home | |||
</route> | |||
``` |
@@ -0,0 +1,9 @@ | |||
<template> | |||
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200"> | |||
<RouterView /> | |||
<Footer /> | |||
<div class="mt-5 mx-auto text-center opacity-75 dark:opacity-50 text-sm"> | |||
[Default Layout] | |||
</div> | |||
</main> | |||
</template> |
@@ -0,0 +1,9 @@ | |||
<template> | |||
<main class="px-4 py-10 text-center text-gray-700 dark:text-gray-200"> | |||
<RouterView /> | |||
<Footer /> | |||
<div class="mt-5 mx-auto text-center opacity-75 dark:opacity-50 text-sm"> | |||
[Home Layout] | |||
</div> | |||
</main> | |||
</template> |
@@ -0,0 +1,24 @@ | |||
import { ViteSSG } from 'vite-ssg' | |||
import { setupLayouts } from 'virtual:generated-layouts' | |||
import Previewer from 'virtual:vue-component-preview' | |||
import App from './App.vue' | |||
import type { UserModule } from './types' | |||
import generatedRoutes from '~pages' | |||
import '@unocss/reset/tailwind.css' | |||
import './styles/main.css' | |||
import 'uno.css' | |||
const routes = setupLayouts(generatedRoutes) | |||
// https://github.com/antfu/vite-ssg | |||
export const createApp = ViteSSG( | |||
App, | |||
{ routes, base: import.meta.env.BASE_URL }, | |||
(ctx) => { | |||
// install all modules under `modules/` | |||
Object.values(import.meta.glob<{ install: UserModule }>('./modules/*.ts', { eager: true })) | |||
.forEach(i => i.install?.(ctx)) | |||
ctx.app.use(Previewer) | |||
}, | |||
) |
@@ -0,0 +1,11 @@ | |||
## Modules | |||
A custom user module system. Place a `.ts` file with the following template, it will be installed automatically. | |||
```ts | |||
import { type UserModule } from '~/types' | |||
export const install: UserModule = ({ app, router, isClient }) => { | |||
// do something | |||
} | |||
``` |
@@ -0,0 +1,25 @@ | |||
import { createI18n } from 'vue-i18n' | |||
import { type UserModule } from '~/types' | |||
// Import i18n resources | |||
// https://vitejs.dev/guide/features.html#glob-import | |||
// | |||
// Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite | |||
const messages = Object.fromEntries( | |||
Object.entries( | |||
import.meta.glob<{ default: any }>('../../locales/*.y(a)?ml', { eager: true })) | |||
.map(([key, value]) => { | |||
const yaml = key.endsWith('.yaml') | |||
return [key.slice(14, yaml ? -5 : -4), value.default] | |||
}), | |||
) | |||
export const install: UserModule = ({ app }) => { | |||
const i18n = createI18n({ | |||
legacy: false, | |||
locale: 'en', | |||
messages, | |||
}) | |||
app.use(i18n) | |||
} |
@@ -0,0 +1,14 @@ | |||
import NProgress from 'nprogress' | |||
import { type UserModule } from '~/types' | |||
export const install: UserModule = ({ isClient, router }) => { | |||
if (isClient) { | |||
router.beforeEach((to, from) => { | |||
if (to.path !== from.path) | |||
NProgress.start() | |||
}) | |||
router.afterEach(() => { | |||
NProgress.done() | |||
}) | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
import { createPinia } from 'pinia' | |||
import { type UserModule } from '~/types' | |||
// Setup Pinia | |||
// https://pinia.vuejs.org/ | |||
export const install: UserModule = ({ isClient, initialState, app }) => { | |||
const pinia = createPinia() | |||
app.use(pinia) | |||
// Refer to | |||
// https://github.com/antfu/vite-ssg/blob/main/README.md#state-serialization | |||
// for other serialization strategies. | |||
if (isClient) | |||
pinia.state.value = (initialState.pinia) || {} | |||
else | |||
initialState.pinia = pinia.state.value | |||
} |
@@ -0,0 +1,12 @@ | |||
import { type UserModule } from '~/types' | |||
// https://github.com/antfu/vite-plugin-pwa#automatic-reload-when-new-content-available | |||
export const install: UserModule = ({ isClient, router }) => { | |||
if (!isClient) | |||
return | |||
router.isReady().then(async () => { | |||
const { registerSW } = await import('virtual:pwa-register') | |||
registerSW({ immediate: true }) | |||
}) | |||
} |
@@ -0,0 +1,20 @@ | |||
## File-based Routing | |||
Routes will be auto-generated for Vue files in this dir with the same file structure. | |||
Check out [`vite-plugin-pages`](https://github.com/hannoeru/vite-plugin-pages) for more details. | |||
### Path Aliasing | |||
`~/` is aliased to `./src/` folder. | |||
For example, instead of having | |||
```ts | |||
import { isDark } from '../../../../composables' | |||
``` | |||
now, you can use | |||
```ts | |||
import { isDark } from '~/composables' | |||
``` |
@@ -0,0 +1,14 @@ | |||
<script setup lang="ts"> | |||
const { t } = useI18n() | |||
</script> | |||
<template> | |||
<div> | |||
{{ t('not-found') }} | |||
</div> | |||
</template> | |||
<route lang="yaml"> | |||
meta: | |||
layout: 404 | |||
</route> |
@@ -0,0 +1,21 @@ | |||
--- | |||
title: About | |||
--- | |||
<div class="text-center"> | |||
<!-- You can use Vue components inside markdown --> | |||
<div i-carbon-dicom-overlay class="text-4xl -mb-6 m-auto" /> | |||
<h3>About</h3> | |||
</div> | |||
[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. | |||
```js | |||
// syntax highlighting example | |||
function vitesse() { | |||
const foo = 'bar' | |||
console.log(foo) | |||
} | |||
``` | |||
Check out the [GitHub repo](https://github.com/antfu/vitesse) for more details. |
@@ -0,0 +1,47 @@ | |||
<script setup lang="ts"> | |||
const props = defineProps<{ name: string }>() | |||
const router = useRouter() | |||
const user = useUserStore() | |||
const { t } = useI18n() | |||
watchEffect(() => { | |||
user.setNewName(props.name) | |||
}) | |||
</script> | |||
<template> | |||
<div> | |||
<div text-4xl> | |||
<div i-carbon-pedestrian inline-block /> | |||
</div> | |||
<p> | |||
{{ t('intro.hi', { name: props.name }) }} | |||
</p> | |||
<p text-sm opacity-75> | |||
<em>{{ t('intro.dynamic-route') }}</em> | |||
</p> | |||
<template v-if="user.otherNames.length"> | |||
<p text-sm mt-4> | |||
<span opacity-75>{{ t('intro.aka') }}:</span> | |||
<ul> | |||
<li v-for="otherName in user.otherNames" :key="otherName"> | |||
<router-link :to="`/hi/${otherName}`" replace> | |||
{{ otherName }} | |||
</router-link> | |||
</li> | |||
</ul> | |||
</p> | |||
</template> | |||
<div> | |||
<button | |||
btn m="3 t6" text-sm | |||
@click="router.back()" | |||
> | |||
{{ t('button.back') }} | |||
</button> | |||
</div> | |||
</div> | |||
</template> |
@@ -0,0 +1,73 @@ | |||
<script setup lang="ts"> | |||
defineOptions({ | |||
name: 'IndexPage', | |||
}) | |||
const user = useUserStore() | |||
const name = $ref(user.savedName) | |||
const router = useRouter() | |||
const go = () => { | |||
if (name) | |||
router.push(`/hi/${encodeURIComponent(name)}`) | |||
} | |||
const pythonName = ref('') | |||
const getOwner = async () => { | |||
pythonName.value = await window.pywebview.api.getOwner() // 前端调用Python暴露的方法 | |||
} | |||
getOwner() | |||
const pythonData = ref('') | |||
const getPythonData = () => { | |||
pythonData.value = 'Python调用了此方法' | |||
} | |||
window.getPythonData = getPythonData // 暴露方法给Python调用 | |||
const { t } = useI18n() | |||
</script> | |||
<template> | |||
<div> | |||
<div text-4xl> | |||
<div i-carbon-campsite inline-block /> | |||
</div> | |||
<p> | |||
<a rel="noreferrer" href="https://github.com/antfu/vitesse" target="_blank"> | |||
Vitesse | |||
</a> | |||
</p> | |||
<p> | |||
<em text-sm opacity-75>{{ t('intro.desc') }}</em> | |||
</p> | |||
<div py-4 /> | |||
<div>{{ pythonData }}</div> | |||
<div py-4 /> | |||
<Input | |||
v-model="name" | |||
placeholder="What's your name?" | |||
autocomplete="false" | |||
:value="pythonName" | |||
@keydown.enter="go" | |||
/> | |||
<label class="hidden" for="input">{{ t('intro.whats-your-name') }}</label> | |||
<div> | |||
<button | |||
btn m-3 text-sm | |||
:disabled="!name" | |||
@click="go" | |||
> | |||
{{ t('button.go') }} | |||
</button> | |||
</div> | |||
</div> | |||
</template> | |||
<route lang="yaml"> | |||
meta: | |||
layout: home | |||
</route> |
@@ -0,0 +1,16 @@ | |||
declare interface Window { | |||
// extend the window | |||
} | |||
// with vite-plugin-vue-markdown, markdown files can be treated as Vue components | |||
declare module '*.md' { | |||
import { type DefineComponent } from 'vue' | |||
const component: DefineComponent<{}, {}, any> | |||
export default component | |||
} | |||
declare module '*.vue' { | |||
import { type DefineComponent } from 'vue' | |||
const component: DefineComponent<{}, {}, any> | |||
export default component | |||
} |
@@ -0,0 +1,34 @@ | |||
import { acceptHMRUpdate, defineStore } from 'pinia' | |||
export const useUserStore = defineStore('user', () => { | |||
/** | |||
* Current name of the user. | |||
*/ | |||
const savedName = ref('') | |||
const previousNames = ref(new Set<string>()) | |||
const usedNames = computed(() => Array.from(previousNames.value)) | |||
const otherNames = computed(() => usedNames.value.filter(name => name !== savedName.value)) | |||
/** | |||
* Changes the current name of the user and saves the one that was used | |||
* before. | |||
* | |||
* @param name - new name to set | |||
*/ | |||
function setNewName(name: string) { | |||
if (savedName.value) | |||
previousNames.value.add(savedName.value) | |||
savedName.value = name | |||
} | |||
return { | |||
setNewName, | |||
otherNames, | |||
savedName, | |||
} | |||
}) | |||
if (import.meta.hot) | |||
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot)) |
@@ -0,0 +1,29 @@ | |||
@import './markdown.css'; | |||
html, | |||
body, | |||
#app { | |||
height: 100%; | |||
margin: 0; | |||
padding: 0; | |||
} | |||
html.dark { | |||
background: #121212; | |||
color-scheme: dark; | |||
} | |||
#nprogress { | |||
pointer-events: none; | |||
} | |||
#nprogress .bar { | |||
background: rgb(13,148,136); | |||
opacity: 0.75; | |||
position: fixed; | |||
z-index: 1031; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 2px; | |||
} |
@@ -0,0 +1,28 @@ | |||
.prose pre:not(.shiki) { | |||
padding: 0; | |||
} | |||
.prose .shiki { | |||
font-family: 'DM Mono', monospace; | |||
font-size: 1.2em; | |||
line-height: 1.4; | |||
} | |||
.prose img { | |||
width: 100%; | |||
} | |||
.shiki-light { | |||
background: #f8f8f8 !important; | |||
} | |||
.shiki-dark { | |||
background: #0e0e0e !important; | |||
} | |||
html.dark .shiki-light { | |||
display: none; | |||
} | |||
html:not(.dark) .shiki-dark { | |||
display: none; | |||
} |
@@ -0,0 +1,3 @@ | |||
import { type ViteSSGContext } from 'vite-ssg' | |||
export type UserModule = (ctx: ViteSSGContext) => void |
@@ -0,0 +1,37 @@ | |||
{ | |||
"compilerOptions": { | |||
"baseUrl": ".", | |||
"module": "ESNext", | |||
"target": "ESNext", | |||
"lib": ["DOM", "ESNext"], | |||
"strict": true, | |||
"esModuleInterop": true, | |||
"jsx": "preserve", | |||
"skipLibCheck": true, | |||
"moduleResolution": "node", | |||
"resolveJsonModule": true, | |||
"noUnusedLocals": true, | |||
"strictNullChecks": true, | |||
"allowJs": true, | |||
"forceConsistentCasingInFileNames": true, | |||
"types": [ | |||
"vite/client", | |||
"vue/ref-macros", | |||
"vite-plugin-pages/client", | |||
"vite-plugin-vue-component-preview/client", | |||
"vite-plugin-vue-layouts/client", | |||
"vite-plugin-pwa/client", | |||
"unplugin-vue-macros/macros-global" | |||
], | |||
"paths": { | |||
"~/*": ["src/*"] | |||
} | |||
}, | |||
"vueCompilerOptions": { | |||
"plugins": [ | |||
"@vue-macros/volar/define-model", | |||
"@vue-macros/volar/define-slots" | |||
] | |||
}, | |||
"exclude": ["dist", "node_modules"] | |||
} |
@@ -0,0 +1,38 @@ | |||
import { | |||
defineConfig, | |||
presetAttributify, | |||
presetIcons, | |||
presetTypography, | |||
presetUno, | |||
presetWebFonts, | |||
transformerDirectives, | |||
transformerVariantGroup, | |||
} from 'unocss' | |||
export default defineConfig({ | |||
shortcuts: [ | |||
['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'], | |||
['icon-btn', 'inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600'], | |||
], | |||
presets: [ | |||
presetUno(), | |||
presetAttributify(), | |||
presetIcons({ | |||
scale: 1.2, | |||
warn: true, | |||
}), | |||
presetTypography(), | |||
presetWebFonts({ | |||
fonts: { | |||
sans: 'DM Sans', | |||
serif: 'DM Serif Display', | |||
mono: 'DM Mono', | |||
}, | |||
}), | |||
], | |||
transformers: [ | |||
transformerDirectives(), | |||
transformerVariantGroup(), | |||
], | |||
safelist: 'prose prose-sm m-auto text-left'.split(' '), | |||
}) |
@@ -0,0 +1,152 @@ | |||
import path from 'path' | |||
import { defineConfig } from 'vite' | |||
import Preview from 'vite-plugin-vue-component-preview' | |||
import Vue from '@vitejs/plugin-vue' | |||
import Pages from 'vite-plugin-pages' | |||
import generateSitemap from 'vite-ssg-sitemap' | |||
import Layouts from 'vite-plugin-vue-layouts' | |||
import Components from 'unplugin-vue-components/vite' | |||
import AutoImport from 'unplugin-auto-import/vite' | |||
import Markdown from 'vite-plugin-vue-markdown' | |||
import { VitePWA } from 'vite-plugin-pwa' | |||
import VueI18n from '@intlify/vite-plugin-vue-i18n' | |||
import Inspect from 'vite-plugin-inspect' | |||
import LinkAttributes from 'markdown-it-link-attributes' | |||
import Unocss from 'unocss/vite' | |||
import Shiki from 'markdown-it-shiki' | |||
import VueMacros from 'unplugin-vue-macros/vite' | |||
export default defineConfig({ | |||
resolve: { | |||
alias: { | |||
'~/': `${path.resolve(__dirname, 'src')}/`, | |||
}, | |||
}, | |||
plugins: [ | |||
Preview(), | |||
VueMacros({ | |||
plugins: { | |||
vue: Vue({ | |||
include: [/\.vue$/, /\.md$/], | |||
reactivityTransform: true, | |||
}), | |||
}, | |||
}), | |||
// https://github.com/hannoeru/vite-plugin-pages | |||
Pages({ | |||
extensions: ['vue', 'md'], | |||
}), | |||
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts | |||
Layouts(), | |||
// https://github.com/antfu/unplugin-auto-import | |||
AutoImport({ | |||
imports: [ | |||
'vue', | |||
'vue-router', | |||
'vue-i18n', | |||
'vue/macros', | |||
'@vueuse/head', | |||
'@vueuse/core', | |||
], | |||
dts: 'src/auto-imports.d.ts', | |||
dirs: [ | |||
'src/composables', | |||
'src/store', | |||
], | |||
vueTemplate: true, | |||
}), | |||
// https://github.com/antfu/unplugin-vue-components | |||
Components({ | |||
// allow auto load markdown components under `./src/components/` | |||
extensions: ['vue', 'md'], | |||
// allow auto import and register components used in markdown | |||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/], | |||
dts: 'src/components.d.ts', | |||
}), | |||
// https://github.com/antfu/unocss | |||
// see unocss.config.ts for config | |||
Unocss(), | |||
// https://github.com/antfu/vite-plugin-vue-markdown | |||
// Don't need this? Try vitesse-lite: https://github.com/antfu/vitesse-lite | |||
Markdown({ | |||
wrapperClasses: 'prose prose-sm m-auto text-left', | |||
headEnabled: true, | |||
markdownItSetup(md) { | |||
// https://prismjs.com/ | |||
md.use(Shiki, { | |||
theme: { | |||
light: 'vitesse-light', | |||
dark: 'vitesse-dark', | |||
}, | |||
}) | |||
md.use(LinkAttributes, { | |||
matcher: (link: string) => /^https?:\/\//.test(link), | |||
attrs: { | |||
target: '_blank', | |||
rel: 'noopener', | |||
}, | |||
}) | |||
}, | |||
}), | |||
// https://github.com/antfu/vite-plugin-pwa | |||
VitePWA({ | |||
registerType: 'autoUpdate', | |||
includeAssets: ['favicon.svg', 'safari-pinned-tab.svg'], | |||
manifest: { | |||
name: 'Vitesse', | |||
short_name: 'Vitesse', | |||
theme_color: '#ffffff', | |||
icons: [ | |||
{ | |||
src: '/pwa-192x192.png', | |||
sizes: '192x192', | |||
type: 'image/png', | |||
}, | |||
{ | |||
src: '/pwa-512x512.png', | |||
sizes: '512x512', | |||
type: 'image/png', | |||
}, | |||
{ | |||
src: '/pwa-512x512.png', | |||
sizes: '512x512', | |||
type: 'image/png', | |||
purpose: 'any maskable', | |||
}, | |||
], | |||
}, | |||
}), | |||
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n | |||
VueI18n({ | |||
runtimeOnly: true, | |||
compositionOnly: true, | |||
include: [path.resolve(__dirname, 'locales/**')], | |||
}), | |||
// https://github.com/antfu/vite-plugin-inspect | |||
// Visit http://localhost:3333/__inspect/ to see the inspector | |||
Inspect(), | |||
], | |||
// https://github.com/antfu/vite-ssg | |||
ssgOptions: { | |||
script: 'async', | |||
formatting: 'minify', | |||
onFinished() { generateSitemap() }, | |||
}, | |||
ssr: { | |||
// TODO: workaround until they support native ESM | |||
noExternal: ['workbox-window', /vue-i18n/], | |||
}, | |||
}) |