From 23a09c2b8dde86ede7180cfeabee399061759327 Mon Sep 17 00:00:00 2001 From: hdykokd Date: Tue, 11 Jul 2023 00:45:23 +0900 Subject: [PATCH] feat: tab icon --- .eslintrc | 42 ++- package.json | 4 +- pnpm-lock.yaml | 631 ++++++++++++++++++++++++++++++++++++++++++++ src/constants.ts | 28 ++ src/main.ts | 7 +- src/setting.ts | 187 ++++++++++++- src/type.ts | 8 - src/types.ts | 11 + src/util/setting.ts | 13 + src/util/view.ts | 44 +++ src/view.test.ts | 35 +++ src/view.ts | 69 +++-- styles.css | 5 +- vitest.config.ts | 7 + 14 files changed, 1027 insertions(+), 64 deletions(-) create mode 100644 src/constants.ts delete mode 100644 src/type.ts create mode 100644 src/types.ts create mode 100644 src/util/view.ts create mode 100644 src/view.test.ts create mode 100644 vitest.config.ts diff --git a/.eslintrc b/.eslintrc index 0807290..4b22229 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,23 +1,21 @@ { - "root": true, - "parser": "@typescript-eslint/parser", - "env": { "node": true }, - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" - ], - "parserOptions": { - "sourceType": "module" - }, - "rules": { - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], - "@typescript-eslint/ban-ts-comment": "off", - "no-prototype-builtins": "off", - "@typescript-eslint/no-empty-function": "off" - } - } \ No newline at end of file + "root": true, + "parser": "@typescript-eslint/parser", + "env": { "node": true }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { "args": "none", "varsIgnorePattern": "^_" }], + "@typescript-eslint/ban-ts-comment": "off", + "no-prototype-builtins": "off", + "@typescript-eslint/no-empty-function": "off" + } +} diff --git a/package.json b/package.json index a900fee..0d20ea2 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "node esbuild.config.mjs", "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", "lint": "npx eslint ./src", + "test": "vitest", "check-format": "npx prettier --check src", "format": "npx prettier --write src", "version": "node version-bump.mjs && git add manifest.json versions.json", @@ -26,7 +27,8 @@ "esbuild": "0.17.3", "obsidian": "latest", "tslib": "2.4.0", - "typescript": "4.7.4" + "typescript": "4.7.4", + "vitest": "^0.33.0" }, "packageManager": "pnpm@8.6.5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4841ff3..6c884a9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ devDependencies: typescript: specifier: 4.7.4 version: 4.7.4 + vitest: + specifier: ^0.33.0 + version: 0.33.0 packages: @@ -58,6 +61,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.18.11: + resolution: {integrity: sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.17.3: resolution: {integrity: sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==} engines: {node: '>=12'} @@ -67,6 +79,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.18.11: + resolution: {integrity: sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.17.3: resolution: {integrity: sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==} engines: {node: '>=12'} @@ -76,6 +97,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.18.11: + resolution: {integrity: sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.17.3: resolution: {integrity: sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==} engines: {node: '>=12'} @@ -85,6 +115,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.18.11: + resolution: {integrity: sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.17.3: resolution: {integrity: sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==} engines: {node: '>=12'} @@ -94,6 +133,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.18.11: + resolution: {integrity: sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.17.3: resolution: {integrity: sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==} engines: {node: '>=12'} @@ -103,6 +151,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.18.11: + resolution: {integrity: sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.17.3: resolution: {integrity: sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==} engines: {node: '>=12'} @@ -112,6 +169,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.18.11: + resolution: {integrity: sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.17.3: resolution: {integrity: sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==} engines: {node: '>=12'} @@ -121,6 +187,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.18.11: + resolution: {integrity: sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.17.3: resolution: {integrity: sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==} engines: {node: '>=12'} @@ -130,6 +205,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.18.11: + resolution: {integrity: sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.17.3: resolution: {integrity: sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==} engines: {node: '>=12'} @@ -139,6 +223,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.18.11: + resolution: {integrity: sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.17.3: resolution: {integrity: sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==} engines: {node: '>=12'} @@ -148,6 +241,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.18.11: + resolution: {integrity: sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.17.3: resolution: {integrity: sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==} engines: {node: '>=12'} @@ -157,6 +259,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.18.11: + resolution: {integrity: sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.17.3: resolution: {integrity: sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==} engines: {node: '>=12'} @@ -166,6 +277,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.18.11: + resolution: {integrity: sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.17.3: resolution: {integrity: sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==} engines: {node: '>=12'} @@ -175,6 +295,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.18.11: + resolution: {integrity: sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.17.3: resolution: {integrity: sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==} engines: {node: '>=12'} @@ -184,6 +313,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.18.11: + resolution: {integrity: sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.17.3: resolution: {integrity: sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==} engines: {node: '>=12'} @@ -193,6 +331,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.18.11: + resolution: {integrity: sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.17.3: resolution: {integrity: sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==} engines: {node: '>=12'} @@ -202,6 +349,15 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.18.11: + resolution: {integrity: sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.17.3: resolution: {integrity: sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==} engines: {node: '>=12'} @@ -211,6 +367,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.18.11: + resolution: {integrity: sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.17.3: resolution: {integrity: sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==} engines: {node: '>=12'} @@ -220,6 +385,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.18.11: + resolution: {integrity: sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.17.3: resolution: {integrity: sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==} engines: {node: '>=12'} @@ -229,6 +403,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.18.11: + resolution: {integrity: sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.17.3: resolution: {integrity: sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==} engines: {node: '>=12'} @@ -238,6 +421,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.18.11: + resolution: {integrity: sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.17.3: resolution: {integrity: sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==} engines: {node: '>=12'} @@ -247,6 +439,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.18.11: + resolution: {integrity: sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.44.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -304,6 +505,17 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@jest/schemas@29.6.0: + resolution: {integrity: sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.27.8 + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -325,6 +537,20 @@ packages: fastq: 1.15.0 dev: true + /@sinclair/typebox@0.27.8: + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + dev: true + + /@types/chai-subset@1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + dependencies: + '@types/chai': 4.3.5 + dev: true + + /@types/chai@4.3.5: + resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} + dev: true + /@types/codemirror@0.0.108: resolution: {integrity: sha512-3FGFcus0P7C2UOGCNUVENqObEb4SFk+S8Dnxq7K6aIsLVs/vDtlangl3PEO0ykaKXyK56swVF6Nho7VsA44uhw==} dependencies: @@ -475,6 +701,44 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@vitest/expect@0.33.0: + resolution: {integrity: sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==} + dependencies: + '@vitest/spy': 0.33.0 + '@vitest/utils': 0.33.0 + chai: 4.3.7 + dev: true + + /@vitest/runner@0.33.0: + resolution: {integrity: sha512-UPfACnmCB6HKRHTlcgCoBh6ppl6fDn+J/xR8dTufWiKt/74Y9bHci5CKB8tESSV82zKYtkBJo9whU3mNvfaisg==} + dependencies: + '@vitest/utils': 0.33.0 + p-limit: 4.0.0 + pathe: 1.1.1 + dev: true + + /@vitest/snapshot@0.33.0: + resolution: {integrity: sha512-tJjrl//qAHbyHajpFvr8Wsk8DIOODEebTu7pgBrP07iOepR5jYkLFiqLq2Ltxv+r0uptUb4izv1J8XBOwKkVYA==} + dependencies: + magic-string: 0.30.1 + pathe: 1.1.1 + pretty-format: 29.6.1 + dev: true + + /@vitest/spy@0.33.0: + resolution: {integrity: sha512-Kv+yZ4hnH1WdiAkPUQTpRxW8kGtH8VRTnus7ZTGovFYM1ZezJpvGtb9nPIjPnptHbsyIAxYZsEpVPYgtpjGnrg==} + dependencies: + tinyspy: 2.1.1 + dev: true + + /@vitest/utils@0.33.0: + resolution: {integrity: sha512-pF1w22ic965sv+EN6uoePkAOTkAPWM03Ri/jXNyMIKBb/XHLDPfhLvf/Fa9g0YECevAIz56oVYXhodLvLQ/awA==} + dependencies: + diff-sequences: 29.4.3 + loupe: 2.3.6 + pretty-format: 29.6.1 + dev: true + /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -483,6 +747,11 @@ packages: acorn: 8.10.0 dev: true + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + /acorn@8.10.0: resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} @@ -510,6 +779,11 @@ packages: color-convert: 2.0.1 dev: true + /ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true @@ -519,6 +793,10 @@ packages: engines: {node: '>=8'} dev: true + /assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -542,11 +820,29 @@ packages: engines: {node: '>=6'} dev: true + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} dev: true + /chai@4.3.7: + resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 4.1.3 + get-func-name: 2.0.0 + loupe: 2.3.6 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -555,6 +851,10 @@ packages: supports-color: 7.2.0 dev: true + /check-error@1.0.2: + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + dev: true + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -591,10 +891,22 @@ packages: ms: 2.1.2 dev: true + /deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 + dev: true + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /diff-sequences@29.4.3: + resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -639,6 +951,36 @@ packages: '@esbuild/win32-x64': 0.17.3 dev: true + /esbuild@0.18.11: + resolution: {integrity: sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.11 + '@esbuild/android-arm64': 0.18.11 + '@esbuild/android-x64': 0.18.11 + '@esbuild/darwin-arm64': 0.18.11 + '@esbuild/darwin-x64': 0.18.11 + '@esbuild/freebsd-arm64': 0.18.11 + '@esbuild/freebsd-x64': 0.18.11 + '@esbuild/linux-arm': 0.18.11 + '@esbuild/linux-arm64': 0.18.11 + '@esbuild/linux-ia32': 0.18.11 + '@esbuild/linux-loong64': 0.18.11 + '@esbuild/linux-mips64el': 0.18.11 + '@esbuild/linux-ppc64': 0.18.11 + '@esbuild/linux-riscv64': 0.18.11 + '@esbuild/linux-s390x': 0.18.11 + '@esbuild/linux-x64': 0.18.11 + '@esbuild/netbsd-x64': 0.18.11 + '@esbuild/openbsd-x64': 0.18.11 + '@esbuild/sunos-x64': 0.18.11 + '@esbuild/win32-arm64': 0.18.11 + '@esbuild/win32-ia32': 0.18.11 + '@esbuild/win32-x64': 0.18.11 + dev: true + /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -833,10 +1175,22 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true + /get-func-name@2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -960,6 +1314,10 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -968,6 +1326,11 @@ packages: type-check: 0.4.0 dev: true + /local-pkg@0.4.3: + resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + engines: {node: '>=14'} + dev: true + /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -979,6 +1342,12 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /loupe@2.3.6: + resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + dependencies: + get-func-name: 2.0.0 + dev: true + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -986,6 +1355,13 @@ packages: yallist: 4.0.0 dev: true + /magic-string@0.30.1: + resolution: {integrity: sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1005,6 +1381,15 @@ packages: brace-expansion: 1.1.11 dev: true + /mlly@1.4.0: + resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==} + dependencies: + acorn: 8.10.0 + pathe: 1.1.1 + pkg-types: 1.0.3 + ufo: 1.1.2 + dev: true + /moment@2.29.4: resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} dev: true @@ -1013,6 +1398,12 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -1054,6 +1445,13 @@ packages: yocto-queue: 0.1.0 dev: true + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -1088,16 +1486,54 @@ packages: engines: {node: '>=8'} dev: true + /pathe@1.1.1: + resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: true + + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} dev: true + /pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.4.0 + pathe: 1.1.1 + dev: true + + /postcss@8.4.25: + resolution: {integrity: sha512-7taJ/8t2av0Z+sQEvNzCkpDynl0tX3uJMCODi6nT3PfASC7dYCWV9aQ+uiCf+KBD4SEFcu+GvJdGdwzQ6OSjCw==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} dev: true + /pretty-format@29.6.1: + resolution: {integrity: sha512-7jRj+yXO0W7e4/tSJKoR7HRIHLPPjtNaUGG2xxKQnGvPNRkgWcQ0AZX6P4KBRJN4FcTBWb3sa7DVUJmocYuoog==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.6.0 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -1107,6 +1543,10 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: true + /regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -1129,6 +1569,14 @@ packages: glob: 7.2.3 dev: true + /rollup@3.26.2: + resolution: {integrity: sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -1155,11 +1603,28 @@ packages: engines: {node: '>=8'} dev: true + /siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} dev: true + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + + /std-env@3.3.3: + resolution: {integrity: sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==} + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1172,6 +1637,12 @@ packages: engines: {node: '>=8'} dev: true + /strip-literal@1.0.1: + resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} + dependencies: + acorn: 8.10.0 + dev: true + /style-mod@4.0.3: resolution: {integrity: sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==} dev: true @@ -1187,6 +1658,20 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /tinybench@2.5.0: + resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==} + dev: true + + /tinypool@0.6.0: + resolution: {integrity: sha512-FdswUUo5SxRizcBc6b1GSuLpLjisa8N8qMyYoP3rl+bym+QauhtJP5bvZY1ytt8krKGmMLYIRl36HBZfeAoqhQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy@2.1.1: + resolution: {integrity: sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==} + engines: {node: '>=14.0.0'} + dev: true + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1219,6 +1704,11 @@ packages: prelude-ls: 1.2.1 dev: true + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -1230,12 +1720,139 @@ packages: hasBin: true dev: true + /ufo@1.1.2: + resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.0 dev: true + /vite-node@0.33.0(@types/node@16.11.6): + resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==} + engines: {node: '>=v14.18.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.4.0 + pathe: 1.1.1 + picocolors: 1.0.0 + vite: 4.4.2(@types/node@16.11.6) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite@4.4.2(@types/node@16.11.6): + resolution: {integrity: sha512-zUcsJN+UvdSyHhYa277UHhiJ3iq4hUBwHavOpsNUGsTgjBeoBlK8eDt+iT09pBq0h9/knhG/SPrZiM7cGmg7NA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 16.11.6 + esbuild: 0.18.11 + postcss: 8.4.25 + rollup: 3.26.2 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vitest@0.33.0: + resolution: {integrity: sha512-1CxaugJ50xskkQ0e969R/hW47za4YXDUfWJDxip1hwbnhUjYolpfUn2AMOulqG/Dtd9WYAtkHmM/m3yKVrEejQ==} + engines: {node: '>=v14.18.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + playwright: '*' + safaridriver: '*' + webdriverio: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + dependencies: + '@types/chai': 4.3.5 + '@types/chai-subset': 1.3.3 + '@types/node': 16.11.6 + '@vitest/expect': 0.33.0 + '@vitest/runner': 0.33.0 + '@vitest/snapshot': 0.33.0 + '@vitest/spy': 0.33.0 + '@vitest/utils': 0.33.0 + acorn: 8.10.0 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.7 + debug: 4.3.4 + local-pkg: 0.4.3 + magic-string: 0.30.1 + pathe: 1.1.1 + picocolors: 1.0.0 + std-env: 3.3.3 + strip-literal: 1.0.1 + tinybench: 2.5.0 + tinypool: 0.6.0 + vite: 4.4.2(@types/node@16.11.6) + vite-node: 0.33.0(@types/node@16.11.6) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} dev: true @@ -1248,6 +1865,15 @@ packages: isexe: 2.0.0 dev: true + /why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true @@ -1260,3 +1886,8 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..de50550 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,28 @@ +export const DEFAULT_POSITION_OPTIONS = { + left: 'left', + right: 'right', +} as const; + +export const TAB_ICON_OPTIONS = { + TARGET: { + directory: 'directory', + title: 'title', + }, + CONDITION: { + startsWith: 'startsWith', + endsWith: 'endsWith', + includes: 'includes', + exact: 'exact', + regexp: 'regexp', + }, +} as const; + +export const DEFAULT_TAB_ICON_CONFIG = { + matchConfig: { + target: 'title', + condition: 'startsWith', + value: '', + }, + priority: 1, + icon: 'file', +}; diff --git a/src/main.ts b/src/main.ts index b0825da..ef6f628 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,11 +2,12 @@ import { Plugin } from 'obsidian'; import { log } from './util/message'; import { VerticalTabsViewSettings, DEFAULT_SETTINGS, VerticalTabsViewSettingTab } from './setting'; import { VerticalTabsViewView, VIEW_TYPE_VERTICAL_TABS } from './view'; -import { Leaf } from './type'; export default class VerticalTabsView extends Plugin { settings: VerticalTabsViewSettings; + private view: VerticalTabsViewView; + async onload() { log('loading...'); await this.loadSettings(); @@ -29,6 +30,7 @@ export default class VerticalTabsView extends Plugin { async saveSettings() { await this.saveData(this.settings); + this.view.updateView(); } addCommands() { @@ -43,7 +45,8 @@ export default class VerticalTabsView extends Plugin { registerViewExtension() { this.registerView(VIEW_TYPE_VERTICAL_TABS, (leaf) => { - return new VerticalTabsViewView(this, leaf as Leaf); + this.view = new VerticalTabsViewView(this.settings, leaf); + return this.view; }); } diff --git a/src/setting.ts b/src/setting.ts index 479dbda..433422f 100644 --- a/src/setting.ts +++ b/src/setting.ts @@ -1,11 +1,8 @@ -import { PluginSettingTab, App } from 'obsidian'; +import { PluginSettingTab, App, Setting, setIcon } from 'obsidian'; +import { DEFAULT_POSITION_OPTIONS, DEFAULT_TAB_ICON_CONFIG, TAB_ICON_OPTIONS } from './constants'; import VerticalTabsView from './main'; -import { createSelect, createToggle } from './util/setting'; - -export const DEFAULT_POSITION_OPTIONS = { - left: 'left', - right: 'right', -} as const; +import { TabIconConfig } from './types'; +import { createSelect, createText, createToggle } from './util/setting'; // eslint-disable-next-line export interface VerticalTabsViewSettings { @@ -13,6 +10,8 @@ export interface VerticalTabsViewSettings { showPinnedIcon: boolean; showPinIconIfNotPinned: boolean; showTabIcon: boolean; + defaultTabIcon: string; + tabIconConfigs: TabIconConfig[]; } export const DEFAULT_SETTINGS: VerticalTabsViewSettings = { @@ -20,6 +19,8 @@ export const DEFAULT_SETTINGS: VerticalTabsViewSettings = { showPinnedIcon: true, showPinIconIfNotPinned: true, showTabIcon: true, + defaultTabIcon: 'file', + tabIconConfigs: [], }; export class VerticalTabsViewSettingTab extends PluginSettingTab { @@ -34,8 +35,7 @@ export class VerticalTabsViewSettingTab extends PluginSettingTab { const { containerEl } = this; containerEl.empty(); - - containerEl.createEl('h2', { text: 'Vertical Tabs View' }); + containerEl.createEl('h1', { text: 'Vertical Tabs View' }); createSelect( containerEl, @@ -62,9 +62,178 @@ export class VerticalTabsViewSettingTab extends PluginSettingTab { this.plugin.saveSettings(); }, ); + + // tab icon createToggle(containerEl, 'Show tab icon', '', this.plugin.settings.showTabIcon, (value) => { this.plugin.settings.showTabIcon = value; this.plugin.saveSettings(); + this.display(); }); + + // tab icon per condition + if (this.plugin.settings.showTabIcon) { + // default icon + const { previewIconWrapper, previewIcon, previewIconText } = this.createPreviewIcon( + this.plugin.settings.defaultTabIcon, + ); + + const defaultTabIcon = createText( + containerEl, + 'Default tab icon', + 'If you clear this field, icon will be hidden by default.', + this.plugin.settings.defaultTabIcon, + (value) => { + this.plugin.settings.defaultTabIcon = value; + this.plugin.saveSettings(); + setIcon(previewIcon, value); + if (previewIcon.children.length === 0) { + // not found + previewIconText.innerText = 'Not found.'; + } else { + previewIconText.innerText = 'Preview: '; + } + }, + ); + defaultTabIcon.controlEl.prepend(previewIconWrapper); + + const h2 = containerEl.createEl('h2', { text: 'Icon Conditions' }); + h2.style.marginLeft = '1em'; + const p = containerEl.createEl('p', { text: 'Can override default icon' }); + p.style.marginLeft = '1em'; + const tabIconConfigs = containerEl.createEl('div'); + tabIconConfigs.style.marginLeft = '1em'; + + if (this.plugin.settings.tabIconConfigs.length === 0) { + this.plugin.settings.tabIconConfigs.push(structuredClone(DEFAULT_TAB_ICON_CONFIG)); + } + + this.plugin.settings.tabIconConfigs.forEach((c, i) => { + this.addTabIconConfig(tabIconConfigs, c, i); + }); + + const addBtn = new Setting(tabIconConfigs).addButton((button) => { + button.setButtonText('Add').onClick(async () => { + this.plugin.settings.tabIconConfigs.push(structuredClone(DEFAULT_TAB_ICON_CONFIG)); + this.display(); + }); + }); + addBtn.settingEl.style.border = 'none'; + } + } + + createPreviewIcon(defaultIcon: string) { + const previewIconWrapper = document.createElement('div'); + previewIconWrapper.style.display = 'flex'; + const previewIconText = document.createElement('div'); + previewIconText.innerText = 'Preview: '; + previewIconText.style.marginRight = '0.5em'; + const previewIcon = document.createElement('div'); + setIcon(previewIcon, defaultIcon); + if (previewIcon.children.length === 0) { + // not found + previewIconText.innerText = 'Icon not found'; + } else { + previewIconText.innerText = 'Preview: '; + } + previewIconWrapper.setChildrenInPlace([previewIconText, previewIcon]); + return { previewIconWrapper, previewIcon, previewIconText }; + } + + addTabIconConfig(parentEl: HTMLElement, config: TabIconConfigBase, index: number) { + const wrapperEl = parentEl.createEl('div'); + wrapperEl.style.border = '1px solid var(--background-modifier-border)'; + wrapperEl.style.padding = '1em'; + wrapperEl.style.marginBottom = '0.25em'; + + const matchConfigEl = wrapperEl.createEl('div'); + matchConfigEl.style.borderTop = '1px solid var(--background-modifier-border)'; + matchConfigEl.style.borderLeft = '1px solid var(--background-modifier-border)'; + matchConfigEl.style.borderBottom = '1px solid var(--background-modifier-border)'; + matchConfigEl.style.padding = '0.5em 1em'; + + // target + new Setting(matchConfigEl) + .addDropdown((dropdown) => { + dropdown + .setValue(config.matchConfig.target) + .addOptions(TAB_ICON_OPTIONS.TARGET) + .onChange(async (v: keyof typeof TAB_ICON_OPTIONS.TARGET) => { + config.matchConfig.target = v; + this.plugin.saveSettings(); + }); + }) + .setName('match target'); + + // condition + new Setting(matchConfigEl) + .addDropdown((dropdown) => { + dropdown + .setValue(config.matchConfig.condition) + .addOptions(TAB_ICON_OPTIONS.CONDITION) + .onChange(async (v: keyof typeof TAB_ICON_OPTIONS.CONDITION) => { + config.matchConfig.condition = v; + this.plugin.saveSettings(); + }); + }) + .setName('match condition'); + + // value + new Setting(matchConfigEl) + .addText((text) => { + text.setValue(config.matchConfig.value).onChange((v: string) => { + config.matchConfig.value = v; + this.plugin.saveSettings(); + }); + }) + .setName('match value') + .setDesc('For regexp, write like: /foo/i'); + + // priority + new Setting(matchConfigEl) + .addSlider((slider) => { + slider + .setLimits(1, 100, 1) + .setValue(config.priority) + .onChange((v) => { + config.priority = v; + this.plugin.saveSettings(); + }) + .setDynamicTooltip(); + }) + .setName('priority') + .setDesc('If there are multiple configs with the same priority, the one defined first will be prioritized.'); + + // icon + const { previewIconWrapper, previewIcon, previewIconText } = this.createPreviewIcon(config.icon); + const iconEl = new Setting(matchConfigEl) + .addText((text) => { + text.setValue(config.icon).onChange((v) => { + config.icon = v; + this.plugin.saveSettings(); + setIcon(previewIcon, v); + if (previewIcon.children.length === 0) { + // not found + previewIconText.innerText = 'Icon not found'; + } else { + previewIconText.innerText = 'Preview: '; + } + }); + }) + .setName('icon'); + + iconEl.controlEl.prepend(previewIconWrapper); + + // remove icon + const removeBtnWrapper = wrapperEl.createEl('div'); + removeBtnWrapper.style.display = 'flex'; + removeBtnWrapper.style.justifyContent = 'end'; + removeBtnWrapper.style.marginTop = '1em'; + const removeBtn = removeBtnWrapper.createEl('button'); + removeBtn.setText('Remove'); + removeBtn.onclick = () => { + this.plugin.settings.tabIconConfigs.splice(index, 1); + this.plugin.saveSettings(); + this.display(); + }; } } diff --git a/src/type.ts b/src/type.ts deleted file mode 100644 index 5e872aa..0000000 --- a/src/type.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { WorkspaceLeaf } from 'obsidian'; - -export type Leaf = WorkspaceLeaf & { - id: string; - pinned: boolean; - tabHeaderEl: HTMLElement; - tabHeaderInnerIconEl: HTMLElement; -}; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..de4598c --- /dev/null +++ b/src/types.ts @@ -0,0 +1,11 @@ +import { TAB_ICON_OPTIONS } from './constants'; + +export type TabIconConfig = { + matchConfig: { + target: keyof (typeof TAB_ICON_OPTIONS)['TARGET']; + condition: keyof (typeof TAB_ICON_OPTIONS)['CONDITION']; + value: string; + }; + priority: number; + icon: string; +}; diff --git a/src/util/setting.ts b/src/util/setting.ts index e0c8fbe..fc1f467 100644 --- a/src/util/setting.ts +++ b/src/util/setting.ts @@ -1,5 +1,18 @@ import { Setting } from 'obsidian'; +export const createText = ( + containerEl: HTMLElement, + name: string, + desc: string, + initialValue: string, + onChange: (value: string) => void, +) => { + return new Setting(containerEl) + .setName(name) + .setDesc(desc) + .addText((text) => text.setValue(initialValue).onChange(onChange)); +}; + export const createToggle = ( containerEl: HTMLElement, name: string, diff --git a/src/util/view.ts b/src/util/view.ts new file mode 100644 index 0000000..733b64e --- /dev/null +++ b/src/util/view.ts @@ -0,0 +1,44 @@ +import { TabIconConfig } from 'src/types'; + +export const getMatchedTabIconConfig = ( + configs: TabIconConfig[], + dirname: string, + title: string, + regexpCompileCache: Record, +) => { + const compileRegExp = (value: string) => { + if (regexpCompileCache[value]) return regexpCompileCache[value]; + const [_, cond, flags] = value.split('/'); + const regexp = new RegExp(cond, flags); + regexpCompileCache[value] = regexp; + return regexp; + }; + + const matchValue = (c: TabIconConfig, value: string) => { + if (c.matchConfig.condition === 'startsWith') { + if (value.startsWith(c.matchConfig.value)) return true; + } + if (c.matchConfig.condition === 'endsWith') { + if (value.endsWith(c.matchConfig.value)) return true; + } + if (c.matchConfig.condition === 'includes') { + if (value.includes(c.matchConfig.value)) return true; + } + if (c.matchConfig.condition === 'exact') { + if (value === c.matchConfig.value) return true; + } + if (c.matchConfig.condition === 'regexp') { + const regexp = compileRegExp(c.matchConfig.value); + if (regexp.test(value)) return true; + } + }; + + return configs.find((c) => { + if (c.matchConfig.target === 'directory') { + return matchValue(c, dirname); + } + if (c.matchConfig.target === 'title') { + return matchValue(c, title); + } + }); +}; diff --git a/src/view.test.ts b/src/view.test.ts new file mode 100644 index 0000000..0ac0af8 --- /dev/null +++ b/src/view.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { DEFAULT_TAB_ICON_CONFIG } from './constants'; +import { TabIconConfig } from './types'; +import { getMatchedTabIconConfig } from './util/view'; + +const generateConfig = (matchConfig: TabIconConfig['matchConfig']) => { + return { + ...DEFAULT_TAB_ICON_CONFIG, + matchConfig, + }; +}; + +describe('VerticalTabsViewView', () => { + describe('getMatchedTabIconConfig', () => { + const cases: [TabIconConfig, string, string][] = [ + [generateConfig({ target: 'directory', condition: 'startsWith', value: 'dir' }), 'dirname', 'title'], + [generateConfig({ target: 'directory', condition: 'endsWith', value: 'name' }), 'dirname', 'title'], + [generateConfig({ target: 'directory', condition: 'includes', value: 'ir' }), 'dirname', 'title'], + [generateConfig({ target: 'directory', condition: 'exact', value: 'dirname' }), 'dirname', 'title'], + [generateConfig({ target: 'directory', condition: 'regexp', value: '/^dirname$/i' }), 'dirname', 'title'], + [generateConfig({ target: 'title', condition: 'startsWith', value: 'tit' }), 'dirname', 'title'], + [generateConfig({ target: 'title', condition: 'endsWith', value: 'tle' }), 'dirname', 'title'], + [generateConfig({ target: 'title', condition: 'includes', value: 'itl' }), 'dirname', 'title'], + [generateConfig({ target: 'title', condition: 'exact', value: 'title' }), 'dirname', 'title'], + [generateConfig({ target: 'title', condition: 'regexp', value: '/^title$/i' }), 'dirname', 'title'], + ]; + cases.forEach(([config, dirname, title]) => { + const { target, condition, value } = config.matchConfig; + it(`${target} ${condition} ${value}`, () => { + const result = getMatchedTabIconConfig([config], dirname, title, {}); + expect(result).not.toBeUndefined(); + }); + }); + }); +}); diff --git a/src/view.ts b/src/view.ts index 0cdc682..25cea54 100644 --- a/src/view.ts +++ b/src/view.ts @@ -1,6 +1,7 @@ -import { ItemView, setIcon } from 'obsidian'; -import VerticalTabsView from './main'; -import { Leaf } from './type'; +import { ItemView, setIcon, WorkspaceLeaf } from 'obsidian'; +import { VerticalTabsViewSettings } from './setting'; +import { TabIconConfig } from './types'; +import { getMatchedTabIconConfig } from './util/view'; const VIEW_PREFIX = 'vertical-tabs-view'; const VIEW_CONTAINER_ID = VIEW_PREFIX + '-container'; @@ -9,11 +10,14 @@ const VIEW_CONTENT_ID = VIEW_PREFIX + '-content'; export const VIEW_TYPE_VERTICAL_TABS = 'view-type-vertical-tabs-view'; export class VerticalTabsViewView extends ItemView { - plugin: VerticalTabsView; + settings: VerticalTabsViewSettings; + regexCompileCache: Record = {}; + tabIconConfigs: TabIconConfig[]; - constructor(plugin: VerticalTabsView, leaf: Leaf) { + constructor(settings: VerticalTabsViewSettings, leaf: WorkspaceLeaf) { super(leaf); - this.plugin = plugin; + this.settings = settings; + this.tabIconConfigs = settings.tabIconConfigs.sort((a, b) => b.priority - a.priority); this.updateView(); @@ -58,6 +62,31 @@ export class VerticalTabsViewView extends ItemView { this.updateView(); } + getMatchedTabIconConfig(configs: TabIconConfig[], dirname: string, title: string) { + return getMatchedTabIconConfig(configs, dirname, title, this.regexCompileCache); + } + + createTabIcon( + leaf: WorkspaceLeaf & { tabHeaderInnerIconEl: HTMLElement }, + dirname: string, + title: string, + ): HTMLElement { + const icon = leaf.tabHeaderInnerIconEl.cloneNode(true) as HTMLElement; + icon.className = 'vertical-tabs-view-list-item-tab-icon vertical-tabs-view-list-item-icon'; + const matchedConfig = this.getMatchedTabIconConfig(this.tabIconConfigs, dirname, title); + if (matchedConfig) { + // override + setIcon(icon, matchedConfig.icon); + } else if (this.settings.defaultTabIcon) { + // set default + setIcon(icon, this.settings.defaultTabIcon); + } else if (leaf.getViewState().type === 'markdown') { + // remove + setIcon(icon, ''); + } + return icon; + } + updateView() { const el = document.querySelector(`#${VIEW_CONTENT_ID}`); if (!el) return; @@ -84,22 +113,21 @@ export class VerticalTabsViewView extends ItemView { const leaves = viewTypes .map((t: string) => this.app.workspace.getLeavesOfType(t)) .flat() - .filter((l: Leaf) => leavesInMain.includes(l.id)); + .filter((l: WorkspaceLeaf & { id: string }) => leavesInMain.includes(l.id)); const createPinIcon = (icon: 'pin' | 'pin-off', onClick: GlobalEventHandlers['onclick']) => { const pinBtn = document.createElement('div'); - pinBtn.className = `vertical-tabs-view-list-item-pin-btn vertical-tabs-view-list-item-pin-btn-${icon}`; + pinBtn.className = `.vertical-tabs-view-list-item-tab-icon vertical-tabs-view-list-item-pin-btn vertical-tabs-view-list-item-pin-btn-${icon}`; setIcon(pinBtn, icon); pinBtn.onclick = onClick; return pinBtn; }; const activeLeaf = this.app.workspace.getMostRecentLeaf(); - - leaves.forEach((leaf: Leaf) => { + leaves.forEach((leaf: WorkspaceLeaf & { id: string; pinned: boolean }) => { const listItem = document.createElement('li'); - listItem.className = 'vertical-tabs-view-list-item vertical-tabs-view-list-item-icon'; - if (activeLeaf && (activeLeaf as Leaf).id === leaf.id) { + listItem.className = 'vertical-tabs-view-list-item'; + if (activeLeaf && (activeLeaf as WorkspaceLeaf & { id: string }).id === leaf.id) { listItem.className += ' focused'; } listItem.onclick = () => { @@ -127,14 +155,9 @@ export class VerticalTabsViewView extends ItemView { // @ts-expect-error const file = leaf.view.file; - // tab icon - const icon = leaf.tabHeaderInnerIconEl.cloneNode(true) as HTMLElement; - icon.className = 'vertical-tabs-view-list-item-tab-icon vertical-tabs-view-list-item-icon'; - // dir const dirname = file ? file.parent.path : ''; if (dirname) { - setIcon(icon, 'file'); const dirnameEl = document.createElement('span'); dirnameEl.className = 'vertical-tabs-view-list-item-dirname'; dirnameEl.innerText = dirname; @@ -142,6 +165,7 @@ export class VerticalTabsViewView extends ItemView { } // title + // @ts-expect-error const title = leaf.tabHeaderEl.innerText; const titleEl = document.createElement('span'); titleEl.className = 'vertical-tabs-view-list-item-title'; @@ -149,18 +173,23 @@ export class VerticalTabsViewView extends ItemView { listItemNameContainer.appendChild(titleEl); listItemLeftContainer.setChildrenInPlace( - [closeBtn, this.plugin.settings.showTabIcon ? icon : null, listItemNameContainer].filter((v) => v) as Node[], + [ + closeBtn, + // @ts-expect-error + this.settings.showTabIcon ? this.createTabIcon(leaf, dirname, title) : null, + listItemNameContainer, + ].filter((v) => v) as Node[], ); // pin button const pinned = leaf.pinned; - if (this.plugin.settings.showPinnedIcon && pinned) { + if (this.settings.showPinnedIcon && pinned) { const pinnedBtn = createPinIcon('pin', () => { leaf.setPinned(false); }); listItemRightContainer.appendChild(pinnedBtn); } - if (this.plugin.settings.showPinIconIfNotPinned && !pinned) { + if (this.settings.showPinIconIfNotPinned && !pinned) { const pinnedBtn = createPinIcon('pin-off', () => { leaf.setPinned(true); }); diff --git a/styles.css b/styles.css index 058fa86..d4d5d64 100644 --- a/styles.css +++ b/styles.css @@ -39,7 +39,6 @@ ul.vertical-tabs-view-list { .vertical-tabs-view-list li .vertical-tabs-view-list-item-right-container { flex-shfrink: 0; - margin-top: 0.2em; } .vertical-tabs-view-list li:hover { @@ -70,8 +69,10 @@ ul.vertical-tabs-view-list { .vertical-tabs-view-list li .vertical-tabs-view-list-item-pin-btn { width: 2em; - height: 2em; margin-left: 0.5em; + margin-top: 0.5em; + --icon-size: var(--icon-xs); + --icon-stroke: var(--icon-xs-stroke-width); } .vertical-tabs-view-list li.focused { diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..d4cba47 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + optimizeDeps: { + exclude: ['obsidian'], + }, +});