init
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | __pycache__ | ||||||
							
								
								
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.python-version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | 3.12 | ||||||
							
								
								
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |     "python.testing.pytestArgs": [ | ||||||
|  |         "tests" | ||||||
|  |     ], | ||||||
|  |     "python.testing.unittestEnabled": false, | ||||||
|  |     "python.testing.pytestEnabled": true | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								api/api.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								api/api.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | from flask import Flask | ||||||
|  |  | ||||||
|  | app = Flask(__name__, static_folder="./web/dist/", static_url_path="") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @app.route("/") | ||||||
|  | def main(): | ||||||
|  |     return app.send_static_file("index.html") | ||||||
|  |  | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     app.run(debug=True) | ||||||
							
								
								
									
										0
									
								
								core/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								core/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										67
									
								
								core/objects/backup_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								core/objects/backup_object.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | """ | ||||||
|  | ******************************************** | ||||||
|  | * @Date: 2024 09 27 | ||||||
|  | * @Description: BackupObject备份对象 | ||||||
|  | ******************************************** | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import os | ||||||
|  | from typing import List, Union | ||||||
|  | from .tree_object import TreeObject | ||||||
|  | from .blob_object import BlobObject | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class BackupObject(ObjectBase): | ||||||
|  |     """ | ||||||
|  |     备份对象,负责管理存储对象(tree、blob)对象、备份信息、恢复等操作 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     backup_name: str | ||||||
|  |     backup_time_lately: str | ||||||
|  |     backup_time_create: str | ||||||
|  |     backup_size: int | ||||||
|  |     backup_version_number: int | ||||||
|  |     backup_tree: List[Union[TreeObject, BlobObject]] | ||||||
|  |     new_backup_flag: bool | ||||||
|  |  | ||||||
|  |     def __init__(self, backup_name: str, backup_base_path: str): | ||||||
|  |         self.backup_name = backup_name | ||||||
|  |  | ||||||
|  |         backup_path = os.path.join(backup_base_path, backup_name) | ||||||
|  |         if not os.path.exists(backup_path): | ||||||
|  |             self.new_backup_flag = True | ||||||
|  |         else: | ||||||
|  |             self.new_backup_flag = False | ||||||
|  |             pass #TODO 读取备份信息 | ||||||
|  |          | ||||||
|  |  | ||||||
|  |     def createNewBackup(self, backup_dirs: List[str]): | ||||||
|  |         """ | ||||||
|  |         创建新的备份 | ||||||
|  |  | ||||||
|  |         :return | ||||||
|  |         """ | ||||||
|  |         for backup_dir in backup_dirs: | ||||||
|  |             if os.path.isdir(backup_dir): | ||||||
|  |                 self.backup_tree.append(TreeObject(backup_dir)) | ||||||
|  |             else: | ||||||
|  |                 self.backup_tree.append(BlobObject(backup_dir)) | ||||||
|  |  | ||||||
|  |     def backup(self): | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     def recover(self, recover_path: str): | ||||||
|  |         """ | ||||||
|  |         恢复到指定备份 | ||||||
|  |  | ||||||
|  |         :return | ||||||
|  |         """ | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     def getBackupTree(self): | ||||||
|  |         """ | ||||||
|  |         获取备份树 | ||||||
|  |  | ||||||
|  |         :return | ||||||
|  |         """ | ||||||
|  |         pass | ||||||
							
								
								
									
										70
									
								
								core/objects/blob_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								core/objects/blob_object.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | """ | ||||||
|  | ******************************************** | ||||||
|  | * @Date: 2024 09 27 | ||||||
|  | * @Description: BlobObject存储对象 | ||||||
|  | ******************************************** | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import hashlib | ||||||
|  | import os | ||||||
|  | import zlib | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class BlobObject: | ||||||
|  |     object_id: str | ||||||
|  |     __buff_size: int = 8192 | ||||||
|  |  | ||||||
|  |     def __init__(self, file_path: str) -> None: | ||||||
|  |         self.file_path = file_path | ||||||
|  |         self.object_id = self.contentSha1() | ||||||
|  |  | ||||||
|  |     def writeBlob(self, base_path) -> None: | ||||||
|  |         Folder = base_path + "/" + self.__getFolderName() | ||||||
|  |         if not os.path.exists(Folder): | ||||||
|  |             os.makedirs(Folder) | ||||||
|  |         self.__compressFile( | ||||||
|  |             self.file_path, | ||||||
|  |             base_path + "/" + self.__getFolderName() + "/" + self.__getFileName(), | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     def __compressFile(self, file_path, save_path) -> None: | ||||||
|  |         compresser = zlib.compressobj(9) | ||||||
|  |         write_file = open(save_path, "wb") | ||||||
|  |         with open(file_path, "rb") as f: | ||||||
|  |             while True: | ||||||
|  |                 data = f.read(self.__buff_size) | ||||||
|  |                 if not data: | ||||||
|  |                     break | ||||||
|  |                 compressedData = compresser.compress(data) | ||||||
|  |                 write_file.write(compressedData) | ||||||
|  |             write_file.write(compresser.flush()) | ||||||
|  |             write_file.close() | ||||||
|  |  | ||||||
|  |     def __getFolderName(self) -> str: | ||||||
|  |         return self.object_id[:2] | ||||||
|  |  | ||||||
|  |     def __getFileName(self) -> str: | ||||||
|  |         return self.object_id[2:] | ||||||
|  |  | ||||||
|  |     def getBlobAbsPath(self) -> str: | ||||||
|  |         """ | ||||||
|  |         获取blob的绝对路径,此相对路径是基于存储路径的,不是相对当前文件的路径 | ||||||
|  |  | ||||||
|  |         :return 相对路径,格式为xx/xxxx... | ||||||
|  |         """ | ||||||
|  |         return self.__getFolderName() + "/" + self.__getFileName() | ||||||
|  |  | ||||||
|  |     def contentSha1(self) -> str: | ||||||
|  |         """ | ||||||
|  |         计算文件内容的sha1值 | ||||||
|  |  | ||||||
|  |         :return sha1的hex值 | ||||||
|  |         """ | ||||||
|  |         with open(self.file_path, "rb") as f: | ||||||
|  |             sha1 = hashlib.sha1() | ||||||
|  |             while True: | ||||||
|  |                 data = f.read(self.__buff_size) | ||||||
|  |                 if not data: | ||||||
|  |                     break | ||||||
|  |                 sha1.update(data) | ||||||
|  |             return sha1.hexdigest() | ||||||
							
								
								
									
										31
									
								
								core/objects/tree_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								core/objects/tree_object.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | """ | ||||||
|  | ******************************************** | ||||||
|  | * @Date: 2024 09 27 | ||||||
|  | * @Description: BackObject树对象,标记多个存储存储对象和树对象,为备份对象提供目标 | ||||||
|  | ******************************************** | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | from typing import Dict, List | ||||||
|  | from .blob_object import BlobObject | ||||||
|  | import os | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TreeObject: | ||||||
|  |     __children: List[BlobObject] = []  # 备份树节点列表,节点为BlobObject备份存储对象 | ||||||
|  |     __file_map: Dict[str, str] = {}  # 备份文件路径到blob对象的映射 | ||||||
|  |  | ||||||
|  |     def __init__(self, tree_path: str): | ||||||
|  |         self.tree_path = tree_path | ||||||
|  |         self.__loadChildren() | ||||||
|  |  | ||||||
|  |     def __loadChildren(self): | ||||||
|  |         for root, dirs, files in os.walk(self.tree_path): | ||||||
|  |             for name in files: | ||||||
|  |                 blob_path = os.path.join(root, name) | ||||||
|  |                 blob = BlobObject(blob_path) | ||||||
|  |                 self.__children.append(blob) | ||||||
|  |                 self.__file_map[blob_path] = blob.object_id | ||||||
|  |  | ||||||
|  |     def writeBlobs(self, base_path: str): | ||||||
|  |         for child in self.__children: | ||||||
|  |             child.writeBlob(base_path) | ||||||
							
								
								
									
										8
									
								
								core/plan/Plan.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								core/plan/Plan.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | class Plan: | ||||||
|  |     __priority_factor: float  # 优先级因子 | ||||||
|  |  | ||||||
|  |     def __init__(self): | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     def getPriorityFactor(self) -> float: | ||||||
|  |         return self.__priority_factor | ||||||
							
								
								
									
										15
									
								
								core/plan/PlanMinHeap.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								core/plan/PlanMinHeap.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | from typing import List | ||||||
|  | from .Plan import Plan | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class PlanPriorityMinHeap: | ||||||
|  |     """ | ||||||
|  |     计划优先小顶堆,按照优先级存储多个计划 | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     plans: List[Plan] | ||||||
|  |     def __init__(self): | ||||||
|  |         self.plans = [] | ||||||
|  |      | ||||||
|  |     def addPlan(self, plan: Plan): | ||||||
|  |         pass | ||||||
							
								
								
									
										0
									
								
								core/plan/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								core/plan/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								core/target/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								core/target/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										25
									
								
								core/target/targetBase.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								core/target/targetBase.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | """ | ||||||
|  | ******************************************** | ||||||
|  | * @Date: 2024 09 27 | ||||||
|  | * @Description: TargetBase存储后端的抽象类 | ||||||
|  | ******************************************** | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | from abc import ABC, abstractmethod | ||||||
|  | from core.objects.back_object import BackObject | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class TargetBase(ABC): | ||||||
|  |     @abstractmethod | ||||||
|  |     def test(self) -> bool: | ||||||
|  |         """ | ||||||
|  |         测试目标连通性 | ||||||
|  |  | ||||||
|  |         :param | ||||||
|  |         :return | ||||||
|  |         """ | ||||||
|  |         pass | ||||||
|  |  | ||||||
|  |     @abstractmethod | ||||||
|  |     def back(self, back_object: BackObject): | ||||||
|  |         pass | ||||||
							
								
								
									
										0
									
								
								core/timer/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								core/timer/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								docs/开发指南.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								docs/开发指南.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										11
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | [project] | ||||||
|  | name = "thousandhands" | ||||||
|  | version = "0.1.0" | ||||||
|  | description = "Add your description here" | ||||||
|  | readme = "README.md" | ||||||
|  | requires-python = ">=3.12" | ||||||
|  | dependencies = [ | ||||||
|  |     "flask>=3.0.3", | ||||||
|  |     "pytest>=8.3.3", | ||||||
|  | ] | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								script/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								script/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										4
									
								
								test.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | import pytest | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     pytest.main(["tests/", "-v"]) | ||||||
							
								
								
									
										0
									
								
								tests/core/objects/test_back_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/core/objects/test_back_object.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										17
									
								
								tests/core/objects/test_blob_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tests/core/objects/test_blob_object.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | from core.objects.blob_object import BlobObject | ||||||
|  | import hashlib | ||||||
|  | import tempfile | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Test_Blob: | ||||||
|  |  | ||||||
|  |     def test_newBlob(self): | ||||||
|  |         newBlob = BlobObject("README.md") | ||||||
|  |         assert ( | ||||||
|  |             newBlob.object_id | ||||||
|  |             == hashlib.sha1(open("README.md", "rb").read()).hexdigest() | ||||||
|  |         ) | ||||||
|  |     def test_writeBlob(self): | ||||||
|  |         newBlob = BlobObject("README.md") | ||||||
|  |         with tempfile.TemporaryDirectory() as tmpdirname: | ||||||
|  |             newBlob.writeBlob(tmpdirname) | ||||||
							
								
								
									
										0
									
								
								tests/core/objects/test_tree_object.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/core/objects/test_tree_object.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								utils/log.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								utils/log.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | import logging | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Logger: | ||||||
|  |     def __init__(self, name): | ||||||
|  |         self.logger = logging.getLogger(name) | ||||||
							
								
								
									
										156
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								uv.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | version = 1 | ||||||
|  | requires-python = ">=3.12" | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "blinker" | ||||||
|  | version = "1.8.2" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/1e/57/a6a1721eff09598fb01f3c7cda070c1b6a0f12d63c83236edf79a440abcc/blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83", size = 23161 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01", size = 9456 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "click" | ||||||
|  | version = "8.1.7" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "colorama", marker = "platform_system == 'Windows'" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "colorama" | ||||||
|  | version = "0.4.6" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "flask" | ||||||
|  | version = "3.0.3" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "blinker" }, | ||||||
|  |     { name = "click" }, | ||||||
|  |     { name = "itsdangerous" }, | ||||||
|  |     { name = "jinja2" }, | ||||||
|  |     { name = "werkzeug" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/41/e1/d104c83026f8d35dfd2c261df7d64738341067526406b40190bc063e829a/flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842", size = 676315 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", size = 101735 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "iniconfig" | ||||||
|  | version = "2.0.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "itsdangerous" | ||||||
|  | version = "2.2.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "jinja2" | ||||||
|  | version = "3.1.4" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "markupsafe" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "markupsafe" | ||||||
|  | version = "2.1.5" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "packaging" | ||||||
|  | version = "24.1" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "pluggy" | ||||||
|  | version = "1.5.0" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "pytest" | ||||||
|  | version = "8.3.3" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "colorama", marker = "sys_platform == 'win32'" }, | ||||||
|  |     { name = "iniconfig" }, | ||||||
|  |     { name = "packaging" }, | ||||||
|  |     { name = "pluggy" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "thousandhands" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = { virtual = "." } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "flask" }, | ||||||
|  |     { name = "pytest" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [package.metadata] | ||||||
|  | requires-dist = [ | ||||||
|  |     { name = "flask", specifier = ">=3.0.3" }, | ||||||
|  |     { name = "pytest", specifier = ">=8.3.3" }, | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | [[package]] | ||||||
|  | name = "werkzeug" | ||||||
|  | version = "3.0.4" | ||||||
|  | source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" } | ||||||
|  | dependencies = [ | ||||||
|  |     { name = "markupsafe" }, | ||||||
|  | ] | ||||||
|  | sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/0f/e2/6dbcaab07560909ff8f654d3a2e5a60552d937c909455211b1b36d7101dc/werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306", size = 803966 } | ||||||
|  | wheels = [ | ||||||
|  |     { url = "https://pypi.tuna.tsinghua.edu.cn/packages/4b/84/997bbf7c2bf2dc3f09565c6d0b4959fefe5355c18c4096cfd26d83e0785b/werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c", size = 227554 }, | ||||||
|  | ] | ||||||
							
								
								
									
										30
									
								
								web/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								web/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | # Logs | ||||||
|  | logs | ||||||
|  | *.log | ||||||
|  | npm-debug.log* | ||||||
|  | yarn-debug.log* | ||||||
|  | yarn-error.log* | ||||||
|  | pnpm-debug.log* | ||||||
|  | lerna-debug.log* | ||||||
|  |  | ||||||
|  | node_modules | ||||||
|  | .DS_Store | ||||||
|  | dist | ||||||
|  | dist-ssr | ||||||
|  | coverage | ||||||
|  | *.local | ||||||
|  |  | ||||||
|  | /cypress/videos/ | ||||||
|  | /cypress/screenshots/ | ||||||
|  |  | ||||||
|  | # Editor directories and files | ||||||
|  | .vscode/* | ||||||
|  | !.vscode/extensions.json | ||||||
|  | .idea | ||||||
|  | *.suo | ||||||
|  | *.ntvs* | ||||||
|  | *.njsproj | ||||||
|  | *.sln | ||||||
|  | *.sw? | ||||||
|  |  | ||||||
|  | *.tsbuildinfo | ||||||
							
								
								
									
										22
									
								
								web/.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								web/.prettierrc.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | module.exports = { | ||||||
|  |     printWidth: 200, //单行长度 | ||||||
|  |     tabWidth: 4, //缩进长度 | ||||||
|  |     useTabs: false, //使用空格代替tab缩进 | ||||||
|  |     semi: false, //句末使用分号 | ||||||
|  |     singleQuote: true, //使用单引号 | ||||||
|  |     quoteProps: 'as-needed', //仅在必需时为对象的key添加引号 | ||||||
|  |     jsxSingleQuote: true, // jsx中使用单引号 | ||||||
|  |     trailingComma: 'all', //多行时尽可能打印尾随逗号 | ||||||
|  |     bracketSpacing: true, //在对象前后添加空格-eg: { foo: bar } | ||||||
|  |     jsxBracketSameLine: true, //多属性html标签的‘>’折行放置 | ||||||
|  |     arrowParens: 'always', //单参数箭头函数参数周围使用圆括号-eg: (x) => x | ||||||
|  |     requirePragma: false, //无需顶部注释即可格式化 | ||||||
|  |     insertPragma: false, //在已被preitter格式化的文件顶部加上标注 | ||||||
|  |     proseWrap: 'preserve', //不知道怎么翻译 | ||||||
|  |     htmlWhitespaceSensitivity: 'ignore', //对HTML全局空白不敏感 | ||||||
|  |     vueIndentScriptAndStyle: false, //不对vue中的script及style标签缩进 | ||||||
|  |     endOfLine: 'lf', //结束行形式 | ||||||
|  |     embeddedLanguageFormatting: 'auto', //对引用代码进行格式化 | ||||||
|  |   }; | ||||||
|  |    | ||||||
|  |    | ||||||
							
								
								
									
										3
									
								
								web/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								web/.vscode/extensions.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |   "recommendations": ["Vue.volar"] | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								web/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								web/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | # web | ||||||
|  |  | ||||||
|  | This template should help get you started developing with Vue 3 in Vite. | ||||||
|  |  | ||||||
|  | ## Recommended IDE Setup | ||||||
|  |  | ||||||
|  | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). | ||||||
|  |  | ||||||
|  | ## Type Support for `.vue` Imports in TS | ||||||
|  |  | ||||||
|  | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. | ||||||
|  |  | ||||||
|  | ## Customize configuration | ||||||
|  |  | ||||||
|  | See [Vite Configuration Reference](https://vitejs.dev/config/). | ||||||
|  |  | ||||||
|  | ## Project Setup | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | bun install | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Compile and Hot-Reload for Development | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | bun dev | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Type-Check, Compile and Minify for Production | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | bun build | ||||||
|  | ``` | ||||||
							
								
								
									
										
											BIN
										
									
								
								web/bun.lockb
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/bun.lockb
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1
									
								
								web/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | /// <reference types="vite/client" /> | ||||||
							
								
								
									
										13
									
								
								web/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								web/index.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  |   <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <link rel="icon" href="/favicon.ico"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     <title>Vite App</title> | ||||||
|  |   </head> | ||||||
|  |   <body> | ||||||
|  |     <div id="app"></div> | ||||||
|  |     <script type="module" src="/src/main.ts"></script> | ||||||
|  |   </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										29
									
								
								web/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								web/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | { | ||||||
|  |   "name": "web", | ||||||
|  |   "version": "0.0.0", | ||||||
|  |   "private": true, | ||||||
|  |   "type": "module", | ||||||
|  |   "scripts": { | ||||||
|  |     "dev": "vite", | ||||||
|  |     "build": "run-p type-check \"build-only {@}\" --", | ||||||
|  |     "preview": "vite preview", | ||||||
|  |     "build-only": "vite build", | ||||||
|  |     "type-check": "vue-tsc --build --force" | ||||||
|  |   }, | ||||||
|  |   "dependencies": { | ||||||
|  |     "vue": "^3.4.29" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@tsconfig/node20": "^20.1.4", | ||||||
|  |     "@types/node": "^20.14.5", | ||||||
|  |     "@vitejs/plugin-vue": "^5.0.5", | ||||||
|  |     "@vue/tsconfig": "^0.5.1", | ||||||
|  |     "element-plus": "^2.8.4", | ||||||
|  |     "npm-run-all2": "^6.2.0", | ||||||
|  |     "typescript": "~5.4.0", | ||||||
|  |     "unplugin-auto-import": "^0.18.3", | ||||||
|  |     "unplugin-vue-components": "^0.27.4", | ||||||
|  |     "vite": "^5.3.1", | ||||||
|  |     "vue-tsc": "^2.0.21" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								web/public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.2 KiB | 
							
								
								
									
										21
									
								
								web/src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								web/src/App.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <script setup lang="ts"> | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <template> | ||||||
|  |   <header> | ||||||
|  |     <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> | ||||||
|  |  | ||||||
|  |     <div class="wrapper"> | ||||||
|  |       <HelloWorld msg="You did it!" /> | ||||||
|  |     </div> | ||||||
|  |   </header> | ||||||
|  |  | ||||||
|  |   <main> | ||||||
|  |     <TheWelcome /> | ||||||
|  |   </main> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  |  | ||||||
|  | </style> | ||||||
							
								
								
									
										86
									
								
								web/src/assets/base.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								web/src/assets/base.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | /* color palette from <https://github.com/vuejs/theme> */ | ||||||
|  | :root { | ||||||
|  |   --vt-c-white: #ffffff; | ||||||
|  |   --vt-c-white-soft: #f8f8f8; | ||||||
|  |   --vt-c-white-mute: #f2f2f2; | ||||||
|  |  | ||||||
|  |   --vt-c-black: #181818; | ||||||
|  |   --vt-c-black-soft: #222222; | ||||||
|  |   --vt-c-black-mute: #282828; | ||||||
|  |  | ||||||
|  |   --vt-c-indigo: #2c3e50; | ||||||
|  |  | ||||||
|  |   --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); | ||||||
|  |   --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); | ||||||
|  |   --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); | ||||||
|  |   --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); | ||||||
|  |  | ||||||
|  |   --vt-c-text-light-1: var(--vt-c-indigo); | ||||||
|  |   --vt-c-text-light-2: rgba(60, 60, 60, 0.66); | ||||||
|  |   --vt-c-text-dark-1: var(--vt-c-white); | ||||||
|  |   --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* semantic color variables for this project */ | ||||||
|  | :root { | ||||||
|  |   --color-background: var(--vt-c-white); | ||||||
|  |   --color-background-soft: var(--vt-c-white-soft); | ||||||
|  |   --color-background-mute: var(--vt-c-white-mute); | ||||||
|  |  | ||||||
|  |   --color-border: var(--vt-c-divider-light-2); | ||||||
|  |   --color-border-hover: var(--vt-c-divider-light-1); | ||||||
|  |  | ||||||
|  |   --color-heading: var(--vt-c-text-light-1); | ||||||
|  |   --color-text: var(--vt-c-text-light-1); | ||||||
|  |  | ||||||
|  |   --section-gap: 160px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (prefers-color-scheme: dark) { | ||||||
|  |   :root { | ||||||
|  |     --color-background: var(--vt-c-black); | ||||||
|  |     --color-background-soft: var(--vt-c-black-soft); | ||||||
|  |     --color-background-mute: var(--vt-c-black-mute); | ||||||
|  |  | ||||||
|  |     --color-border: var(--vt-c-divider-dark-2); | ||||||
|  |     --color-border-hover: var(--vt-c-divider-dark-1); | ||||||
|  |  | ||||||
|  |     --color-heading: var(--vt-c-text-dark-1); | ||||||
|  |     --color-text: var(--vt-c-text-dark-2); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | *, | ||||||
|  | *::before, | ||||||
|  | *::after { | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   margin: 0; | ||||||
|  |   font-weight: normal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | body { | ||||||
|  |   min-height: 100vh; | ||||||
|  |   color: var(--color-text); | ||||||
|  |   background: var(--color-background); | ||||||
|  |   transition: | ||||||
|  |     color 0.5s, | ||||||
|  |     background-color 0.5s; | ||||||
|  |   line-height: 1.6; | ||||||
|  |   font-family: | ||||||
|  |     Inter, | ||||||
|  |     -apple-system, | ||||||
|  |     BlinkMacSystemFont, | ||||||
|  |     'Segoe UI', | ||||||
|  |     Roboto, | ||||||
|  |     Oxygen, | ||||||
|  |     Ubuntu, | ||||||
|  |     Cantarell, | ||||||
|  |     'Fira Sans', | ||||||
|  |     'Droid Sans', | ||||||
|  |     'Helvetica Neue', | ||||||
|  |     sans-serif; | ||||||
|  |   font-size: 15px; | ||||||
|  |   text-rendering: optimizeLegibility; | ||||||
|  |   -webkit-font-smoothing: antialiased; | ||||||
|  |   -moz-osx-font-smoothing: grayscale; | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								web/src/assets/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								web/src/assets/logo.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg> | ||||||
| After Width: | Height: | Size: 276 B | 
							
								
								
									
										35
									
								
								web/src/assets/main.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								web/src/assets/main.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | @import './base.css'; | ||||||
|  |  | ||||||
|  | #app { | ||||||
|  |   max-width: 1280px; | ||||||
|  |   margin: 0 auto; | ||||||
|  |   padding: 2rem; | ||||||
|  |   font-weight: normal; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | a, | ||||||
|  | .green { | ||||||
|  |   text-decoration: none; | ||||||
|  |   color: hsla(160, 100%, 37%, 1); | ||||||
|  |   transition: 0.4s; | ||||||
|  |   padding: 3px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (hover: hover) { | ||||||
|  |   a:hover { | ||||||
|  |     background-color: hsla(160, 100%, 37%, 0.2); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (min-width: 1024px) { | ||||||
|  |   body { | ||||||
|  |     display: flex; | ||||||
|  |     place-items: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   #app { | ||||||
|  |     display: grid; | ||||||
|  |     grid-template-columns: 1fr 1fr; | ||||||
|  |     padding: 0 2rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								web/src/main.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								web/src/main.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | import './assets/main.css' | ||||||
|  |  | ||||||
|  | import { createApp } from 'vue' | ||||||
|  | import App from './App.vue' | ||||||
|  |  | ||||||
|  | createApp(App).mount('#app') | ||||||
							
								
								
									
										14
									
								
								web/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								web/tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | { | ||||||
|  |   "extends": "@vue/tsconfig/tsconfig.dom.json", | ||||||
|  |   "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], | ||||||
|  |   "exclude": ["src/**/__tests__/*"], | ||||||
|  |   "compilerOptions": { | ||||||
|  |     "composite": true, | ||||||
|  |     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", | ||||||
|  |  | ||||||
|  |     "baseUrl": ".", | ||||||
|  |     "paths": { | ||||||
|  |       "@/*": ["./src/*"] | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								web/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								web/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "files": [], | ||||||
|  |   "references": [ | ||||||
|  |     { | ||||||
|  |       "path": "./tsconfig.node.json" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "./tsconfig.app.json" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								web/tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  |   "extends": "@tsconfig/node20/tsconfig.json", | ||||||
|  |   "include": [ | ||||||
|  |     "vite.config.*", | ||||||
|  |     "vitest.config.*", | ||||||
|  |     "cypress.config.*", | ||||||
|  |     "nightwatch.conf.*", | ||||||
|  |     "playwright.config.*" | ||||||
|  |   ], | ||||||
|  |   "compilerOptions": { | ||||||
|  |     "composite": true, | ||||||
|  |     "noEmit": true, | ||||||
|  |     "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", | ||||||
|  |  | ||||||
|  |     "module": "ESNext", | ||||||
|  |     "moduleResolution": "Bundler", | ||||||
|  |     "types": ["node"] | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								web/vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								web/vite.config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | import { fileURLToPath, URL } from 'node:url' | ||||||
|  |  | ||||||
|  | import { defineConfig } from 'vite' | ||||||
|  | import vue from '@vitejs/plugin-vue' | ||||||
|  |  | ||||||
|  | // https://vitejs.dev/config/ | ||||||
|  | export default defineConfig({ | ||||||
|  |   plugins: [ | ||||||
|  |     vue(), | ||||||
|  |   ], | ||||||
|  |   resolve: { | ||||||
|  |     alias: { | ||||||
|  |       '@': fileURLToPath(new URL('./src', import.meta.url)) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
		Reference in New Issue
	
	Block a user