diff --git a/.eslintignore b/.eslintignore index fc58645..ea1f53a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules dist *.snap +docs/.vitepress/cache diff --git a/.gitignore b/.gitignore index 0738cb5..6e4468c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules .DS_Store -dist \ No newline at end of file +dist +docs/.vitepress/cache \ No newline at end of file diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..6bec259 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,45 @@ +import { defineConfig } from 'vitepress' +import Unfonts from '../../src/vite' + +export default defineConfig({ + base: '/unplugin-fonts/', + // site-level options + title: 'VitePress', + description: 'Just playing around.', + + themeConfig: { + // theme-level options + }, + + vite: { + plugins: [ + Unfonts({ + google: { + families: ['Crimson Pro', 'Open Sans', 'Material+Icons'], + }, + + custom: { + display: 'swap', + families: { + 'Dancing Script': './public/assets/fonts/DancingScript*', + }, + }, + + fontsource: { + families: [ + { + name: 'ABeeZee', + weights: [400], + styles: ['italic'], + }, + { + name: 'Truculenta', + weights: [400, 700], + subset: 'latin-ext', + }, + ], + }, + }), + ], + }, +}) diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 0000000..b86d644 --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,6 @@ + +:root { + /* --vp-font-family-base: "ABeeZee", sans-serif !important; */ + /* --vp-font-family-base: "Crimson Pro", sans-serif !important; */ + --vp-font-family-base: "Dancing Script", sans-serif !important; +} \ No newline at end of file diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..ba9c0f3 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,6 @@ +// @ts-expect-error - not typed in vitepress 60 +import DefaultTheme from 'vitepress/theme-without-fonts' +import './custom.css' +import 'unfonts.css' + +export default DefaultTheme diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..63e443b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,23 @@ +--- +layout: home + +hero: + name: VitePress + text: Just playing around. + tagline: My great project tagline + actions: + - theme: brand + text: Markdown Examples + link: /markdown-examples + - theme: alt + text: API Examples + link: /api-examples + +features: + - title: Feature A + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature B + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature C + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit +--- \ No newline at end of file diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..930f0a4 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,15 @@ +{ + "name": "docs", + "private": true, + "scripts": { + "dev": "vitepress dev", + "start": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview" + }, + "devDependencies": { + "unplugin-fonts": "workspace:*", + "vitepress": "^1.0.0-alpha.60" + } + +} diff --git a/docs/public/assets/fonts/DancingScript-Bold.ttf b/docs/public/assets/fonts/DancingScript-Bold.ttf new file mode 100644 index 0000000..49d8f3f Binary files /dev/null and b/docs/public/assets/fonts/DancingScript-Bold.ttf differ diff --git a/docs/public/assets/fonts/DancingScript-Medium.ttf b/docs/public/assets/fonts/DancingScript-Medium.ttf new file mode 100644 index 0000000..fdfd690 Binary files /dev/null and b/docs/public/assets/fonts/DancingScript-Medium.ttf differ diff --git a/docs/public/assets/fonts/DancingScript-Regular.ttf b/docs/public/assets/fonts/DancingScript-Regular.ttf new file mode 100644 index 0000000..b215107 Binary files /dev/null and b/docs/public/assets/fonts/DancingScript-Regular.ttf differ diff --git a/docs/public/assets/fonts/DancingScript-SemiBold.ttf b/docs/public/assets/fonts/DancingScript-SemiBold.ttf new file mode 100644 index 0000000..ce588e1 Binary files /dev/null and b/docs/public/assets/fonts/DancingScript-SemiBold.ttf differ diff --git a/examples/nuxt/nuxt.config.ts b/examples/nuxt/nuxt.config.ts index 30dcb7d..00389a2 100644 --- a/examples/nuxt/nuxt.config.ts +++ b/examples/nuxt/nuxt.config.ts @@ -15,5 +15,5 @@ export default defineNuxtConfig({ 'Dancing Script': './assets/fonts/DancingScript*', }, }, - } + }, }) diff --git a/examples/nuxt/tsconfig.json b/examples/nuxt/tsconfig.json index 28b66c5..a746f2a 100644 --- a/examples/nuxt/tsconfig.json +++ b/examples/nuxt/tsconfig.json @@ -1,4 +1,4 @@ { // https://nuxt.com/docs/guide/concepts/typescript "extends": "./.nuxt/tsconfig.json" -} \ No newline at end of file +} diff --git a/examples/vite/package.json b/examples/vite/package.json index 7943a85..d16b3b2 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -7,9 +7,9 @@ "preview": "vite preview" }, "devDependencies": { - "vite": "^4.2.0", - "unplugin-fonts": "workspace:*", "@fontsource/abeezee": "^4.5.10", - "@fontsource/truculenta": "^4.5.12" + "@fontsource/truculenta": "^4.5.12", + "unplugin-fonts": "workspace:*", + "vite": "^4.2.0" } } diff --git a/examples/vite/vite.config.ts b/examples/vite/vite.config.ts index d386c96..f639f74 100644 --- a/examples/vite/vite.config.ts +++ b/examples/vite/vite.config.ts @@ -11,7 +11,15 @@ export default defineConfig({ custom: { display: 'swap', families: { - 'Dancing Script': './assets/fonts/DancingScript*', + 'Dancing Script': { + src: './assets/fonts/DancingScript*', + transform(font) { + if (font.basename === 'DancingScript-Bold') + font.weight = 700 + + return font + }, + }, }, }, diff --git a/package.json b/package.json index d4a48ae..13b3da3 100644 --- a/package.json +++ b/package.json @@ -75,8 +75,11 @@ "build:fix": "esno scripts/postbuild.ts", "example:dev": "npm -C examples/vite run dev", "example:build": "npm -C examples/vite run build", + "docs:dev": "npm -C docs run dev", + "docs:build": "npm -C docs run build", "lint": "eslint .", - "lint:fix": "eslint --fix ." + "lint:fix": "eslint --fix .", + "test": "vitest" }, "peerDependencies": { "@nuxt/kit": "^3.0.0", @@ -97,6 +100,7 @@ "@types/node": "^18.15.3", "@typescript-eslint/eslint-plugin": "^5.55.0", "chalk": "^5.2.0", + "defu": "^6.1.2", "eslint": "^8.36.0", "eslint-plugin-eslint-comments": "^3.2.0", "esno": "^0.16.3", @@ -105,6 +109,7 @@ "tsup": "^6.6.3", "typescript": "^5.0.2", "vite": "^4.2.0", + "vitest": "^0.29.3", "webpack": "^5.76.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 092b502..406d8ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,7 @@ importers: '@types/node': ^18.15.3 '@typescript-eslint/eslint-plugin': ^5.55.0 chalk: ^5.2.0 + defu: ^6.1.2 eslint: ^8.36.0 eslint-plugin-eslint-comments: ^3.2.0 esno: ^0.16.3 @@ -19,6 +20,7 @@ importers: typescript: ^5.0.2 unplugin: ^1.3.1 vite: ^4.2.0 + vitest: ^0.29.3 webpack: ^5.76.2 dependencies: fast-glob: 3.2.12 @@ -29,6 +31,7 @@ importers: '@types/node': 18.15.3 '@typescript-eslint/eslint-plugin': 5.55.0_j4766f7ecgqbon3u7zlxn5zszu chalk: 5.2.0 + defu: 6.1.2 eslint: 8.36.0 eslint-plugin-eslint-comments: 3.2.0_eslint@8.36.0 esno: 0.16.3 @@ -37,8 +40,17 @@ importers: tsup: 6.6.3_typescript@5.0.2 typescript: 5.0.2 vite: 4.2.0_@types+node@18.15.3 + vitest: 0.29.3 webpack: 5.76.2 + docs: + specifiers: + unplugin-fonts: workspace:* + vitepress: ^1.0.0-alpha.60 + devDependencies: + unplugin-fonts: link:.. + vitepress: 1.0.0-alpha.60 + examples/astro: specifiers: astro: ^2.1.3 @@ -69,6 +81,116 @@ importers: packages: + /@algolia/autocomplete-core/1.7.4: + resolution: {integrity: sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==} + dependencies: + '@algolia/autocomplete-shared': 1.7.4 + dev: true + + /@algolia/autocomplete-preset-algolia/1.7.4_algoliasearch@4.15.0: + resolution: {integrity: sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==} + peerDependencies: + '@algolia/client-search': '>= 4.9.1 < 6' + algoliasearch: '>= 4.9.1 < 6' + dependencies: + '@algolia/autocomplete-shared': 1.7.4 + algoliasearch: 4.15.0 + dev: true + + /@algolia/autocomplete-shared/1.7.4: + resolution: {integrity: sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==} + dev: true + + /@algolia/cache-browser-local-storage/4.15.0: + resolution: {integrity: sha512-uxxFhTWh4JJDb2+FFSmNMfEQ8p9o2vjSpU7iW007QX3OvqljPPN68lk3bpZVaG8pwr5MU1DqpkZ71FcQdVTjgQ==} + dependencies: + '@algolia/cache-common': 4.15.0 + dev: true + + /@algolia/cache-common/4.15.0: + resolution: {integrity: sha512-Me3PbI4QurAM+3D+htIE0l1xt6+bl/18SG6Wc7bPQEZAtN7DTGz22HqhKNyLF2lR/cOfpaH7umXZlZEhIHf7gQ==} + dev: true + + /@algolia/cache-in-memory/4.15.0: + resolution: {integrity: sha512-B9mg1wd7CKMfpkbiTQ8KlcKkH6ut/goVaI6XmDCUczOOqeuZlV34tuEi7o3Xo1j66KWr/d9pMjjGYcoVPCVeOA==} + dependencies: + '@algolia/cache-common': 4.15.0 + dev: true + + /@algolia/client-account/4.15.0: + resolution: {integrity: sha512-8wqI33HRZy5ydfFt6F5vMhtkOiAUhVfSCYXx4U3Go5RALqWLgVUp6wzOo0mr1z08POCkHDpbQMQvyayb1CZ/kw==} + dependencies: + '@algolia/client-common': 4.15.0 + '@algolia/client-search': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + + /@algolia/client-analytics/4.15.0: + resolution: {integrity: sha512-jrPjEeNEIIQKeA1XCZXx3f3aybtwF7wjYlnfHbLARuZ9AuHzimOKjX0ZwqvMmvTsHivpcZ2rqY+j1E8HoH1ELA==} + dependencies: + '@algolia/client-common': 4.15.0 + '@algolia/client-search': 4.15.0 + '@algolia/requester-common': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + + /@algolia/client-common/4.15.0: + resolution: {integrity: sha512-PlsJMObZuYw4JlG5EhYv1PHDOv7n5mD5PzqFyoNfSOYaEPRZepa3W579ya29yOu3FZ0VGMNJmB7Q5v/+/fwvIw==} + dependencies: + '@algolia/requester-common': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + + /@algolia/client-personalization/4.15.0: + resolution: {integrity: sha512-Bf0bhRAiNL9LWurzyHRH8UBi4fDt3VbCNkInxVngKQT1uCZWXecwoPWGhcSSpdanBqFJA/1WBt+BWx7a50Bhlg==} + dependencies: + '@algolia/client-common': 4.15.0 + '@algolia/requester-common': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + + /@algolia/client-search/4.15.0: + resolution: {integrity: sha512-dTwZD4u53WdmexnMcoO2Qd/+YCP3ESXKOtD2MryQ1a9dHwB2Y3Qob0kyS1PG82idwM3enbznvscI9Sf4o9PUWQ==} + dependencies: + '@algolia/client-common': 4.15.0 + '@algolia/requester-common': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + + /@algolia/logger-common/4.15.0: + resolution: {integrity: sha512-D8OFwn/HpvQz66goIcjxOKsYBMuxiruxJ3cA/bnc0EiDvSA2P2z6bNQWgS5gbstuTZIJmbhr+53NyOxFkmMNAA==} + dev: true + + /@algolia/logger-console/4.15.0: + resolution: {integrity: sha512-pQOvVaRSEJQJRXKTnxEA6nN1hipSQadJJ4einw0nIlfMOGZh/kps1ybh8vRUlUGyfEuN/3dyFs0W3Ac7hIItlg==} + dependencies: + '@algolia/logger-common': 4.15.0 + dev: true + + /@algolia/requester-browser-xhr/4.15.0: + resolution: {integrity: sha512-va186EfALF+6msYZXaoBSxcnFCg3SoWJ+uv1yMyhQRJRe7cZSHWSVT3s40vmar90gxlBu80KMVwVlsvJhJv6ew==} + dependencies: + '@algolia/requester-common': 4.15.0 + dev: true + + /@algolia/requester-common/4.15.0: + resolution: {integrity: sha512-w0UUzxElbo4hrKg4QP/jiXDNbIJuAthxdlkos9nS8KAPK2XI3R9BlUjLz/ZVs4F9TDGI0mhjrNHhZ12KXcoyhg==} + dev: true + + /@algolia/requester-node-http/4.15.0: + resolution: {integrity: sha512-eeEOhFtgwKcgAlKAZpgBRZJ0ILSEBCXxZ9uwfVWPD24W1b6z08gVoTJ6J7lCeCnJmudg+tMElDnGzHkjup9CJA==} + dependencies: + '@algolia/requester-common': 4.15.0 + dev: true + + /@algolia/transporter/4.15.0: + resolution: {integrity: sha512-JoWR+ixG3EmA0UPntQFN/FV5TasYcYu93d5+oKzHFeZ6Z7rtW5Im9iy/Oh/ggk1AAN5fTdqKewtbBpdaYDbKsQ==} + dependencies: + '@algolia/cache-common': 4.15.0 + '@algolia/logger-common': 4.15.0 + '@algolia/requester-common': 4.15.0 + dev: true + /@ampproject/remapping/2.2.0: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} @@ -525,6 +647,44 @@ packages: mime: 3.0.0 dev: true + /@docsearch/css/3.3.3: + resolution: {integrity: sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==} + dev: true + + /@docsearch/js/3.3.3: + resolution: {integrity: sha512-2xAv2GFuHzzmG0SSZgf8wHX0qZX8n9Y1ZirKUk5Wrdc+vH9CL837x2hZIUdwcPZI9caBA+/CzxsS68O4waYjUQ==} + dependencies: + '@docsearch/react': 3.3.3 + preact: 10.13.1 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/react' + - react + - react-dom + dev: true + + /@docsearch/react/3.3.3: + resolution: {integrity: sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==} + peerDependencies: + '@types/react': '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0' + react-dom: '>= 16.8.0 < 19.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + react-dom: + optional: true + dependencies: + '@algolia/autocomplete-core': 1.7.4 + '@algolia/autocomplete-preset-algolia': 1.7.4_algoliasearch@4.15.0 + '@docsearch/css': 3.3.3 + algoliasearch: 4.15.0 + transitivePeerDependencies: + - '@algolia/client-search' + dev: true + /@emmetio/abbreviation/2.2.3: resolution: {integrity: sha512-87pltuCPt99aL+y9xS6GPZ+Wmmyhll2WXH73gG/xpGcQ84DRnptBsI2r0BeIQ0EB/SQTOe2ANPqFqj3Rj5FOGA==} dependencies: @@ -1516,6 +1676,16 @@ packages: '@babel/types': 7.21.3 dev: true + /@types/chai-subset/1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + dependencies: + '@types/chai': 4.3.4 + dev: true + + /@types/chai/4.3.4: + resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} + dev: true + /@types/debug/4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: @@ -1602,6 +1772,10 @@ packages: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: true + /@types/web-bluetooth/0.0.16: + resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + dev: true + /@types/yargs-parser/21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: true @@ -1850,6 +2024,48 @@ packages: vue: 3.2.47 dev: true + /@vitejs/plugin-vue/4.1.0_vite@4.2.0+vue@3.2.47: + resolution: {integrity: sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.2.0 + vue: 3.2.47 + dev: true + + /@vitest/expect/0.29.3: + resolution: {integrity: sha512-z/0JqBqqrdtrT/wzxNrWC76EpkOHdl+SvuNGxWulLaoluygntYyG5wJul5u/rQs5875zfFz/F+JaDf90SkLUIg==} + dependencies: + '@vitest/spy': 0.29.3 + '@vitest/utils': 0.29.3 + chai: 4.3.7 + dev: true + + /@vitest/runner/0.29.3: + resolution: {integrity: sha512-XLi8ctbvOWhUWmuvBUSIBf8POEDH4zCh6bOuVxm/KGfARpgmVF1ku+vVNvyq85va+7qXxtl+MFmzyXQ2xzhAvw==} + dependencies: + '@vitest/utils': 0.29.3 + p-limit: 4.0.0 + pathe: 1.1.0 + dev: true + + /@vitest/spy/0.29.3: + resolution: {integrity: sha512-LLpCb1oOCOZcBm0/Oxbr1DQTuKLRBsSIHyLYof7z4QVE8/v8NcZKdORjMUq645fcfX55+nLXwU/1AQ+c2rND+w==} + dependencies: + tinyspy: 1.1.1 + dev: true + + /@vitest/utils/0.29.3: + resolution: {integrity: sha512-hg4Ff8AM1GtUnLpUJlNMxrf9f4lZr/xRJjh3uJ0QFP+vjaW82HAxKrmeBmLnhc8Os2eRf+f+VBu4ts7TafPPkA==} + dependencies: + cli-truncate: 3.1.0 + diff: 5.1.0 + loupe: 2.3.6 + pretty-format: 27.5.1 + dev: true + /@vscode/emmet-helper/2.8.6: resolution: {integrity: sha512-IIB8jbiKy37zN8bAIHx59YmnIelY78CGHtThnibD/d3tQOKRY83bYVi9blwmZVUZh6l9nfkYH3tvReaiNxY9EQ==} dependencies: @@ -1972,6 +2188,31 @@ packages: resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==} dev: true + /@vueuse/core/9.13.0_vue@3.2.47: + resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0_vue@3.2.47 + vue-demi: 0.13.11_vue@3.2.47 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + + /@vueuse/metadata/9.13.0: + resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + dev: true + + /@vueuse/shared/9.13.0_vue@3.2.47: + resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + dependencies: + vue-demi: 0.13.11_vue@3.2.47 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: true + /@webassemblyjs/ast/1.11.1: resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} dependencies: @@ -2106,6 +2347,11 @@ packages: acorn: 8.8.2 dev: true + /acorn-walk/8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + /acorn/8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -2137,6 +2383,25 @@ packages: uri-js: 4.4.1 dev: true + /algoliasearch/4.15.0: + resolution: {integrity: sha512-+vgKQF5944dYsz9zhKk07JbOYeNdKisoD5GeG0woBL3nLzbn2a+nGwki60DXg7CXvaFXBcTXyJG4C+VaBVd44g==} + dependencies: + '@algolia/cache-browser-local-storage': 4.15.0 + '@algolia/cache-common': 4.15.0 + '@algolia/cache-in-memory': 4.15.0 + '@algolia/client-account': 4.15.0 + '@algolia/client-analytics': 4.15.0 + '@algolia/client-common': 4.15.0 + '@algolia/client-personalization': 4.15.0 + '@algolia/client-search': 4.15.0 + '@algolia/logger-common': 4.15.0 + '@algolia/logger-console': 4.15.0 + '@algolia/requester-browser-xhr': 4.15.0 + '@algolia/requester-common': 4.15.0 + '@algolia/requester-node-http': 4.15.0 + '@algolia/transporter': 4.15.0 + dev: true + /ansi-align/3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} dependencies: @@ -2167,6 +2432,10 @@ packages: engines: {node: '>=12'} dev: true + /ansi-sequence-parser/1.1.0: + resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==} + dev: true + /ansi-styles/3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -2181,6 +2450,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 + /ansi-styles/6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -2307,6 +2581,10 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /assertion-error/1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /astro/2.1.3: resolution: {integrity: sha512-5LFo/ixDXs84tgrSbzz0X5c7nzLfkag7w4tgOpBRL/DkveP83v+nSe3KjqwYLPL5vNY9UvryKHsfC0uu4TQz0g==} engines: {node: '>=16.12.0', npm: '>=6.14.0'} @@ -2448,6 +2726,10 @@ packages: readable-stream: 3.6.2 dev: true + /body-scroll-lock/4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + dev: true + /boolbase/1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true @@ -2600,6 +2882,19 @@ packages: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} 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/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2650,6 +2945,10 @@ packages: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true + /check-error/1.0.2: + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + dev: true + /chokidar/3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -2707,6 +3006,14 @@ packages: engines: {node: '>=6'} dev: true + /cli-truncate/3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + /cli-width/4.0.0: resolution: {integrity: sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==} engines: {node: '>= 12'} @@ -3028,6 +3335,13 @@ packages: character-entities: 2.0.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 @@ -4128,6 +4442,10 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-func-name/2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + dev: true + /get-intrinsic/1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: @@ -4776,6 +5094,11 @@ packages: engines: {node: '>=8'} dev: true + /is-fullwidth-code-point/4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -5208,6 +5531,12 @@ packages: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} 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/5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -6242,6 +6571,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/4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -6363,6 +6699,10 @@ packages: resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} dev: true + /pathval/1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + /perfect-debounce/0.1.3: resolution: {integrity: sha512-NOT9AcKiDGpnV/HBhI22Str++XWcErO/bALvHCuhv33owZW/CjH8KAFLZDCmu3727sihe0wTxpDhyGc6M8qacQ==} dev: true @@ -6760,6 +7100,10 @@ packages: source-map-js: 1.0.2 dev: true + /preact/10.13.1: + resolution: {integrity: sha512-KyoXVDU5OqTpG9LXlB3+y639JAGzl8JSBXLn1J9HTSB3gbKcuInga7bZnXLlxmK94ntTs1EFeZp0lrja2AuBYQ==} + dev: true + /preferred-pm/3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} engines: {node: '>=10'} @@ -6796,6 +7140,15 @@ packages: engines: {node: ^14.13.1 || >=16.0.0} dev: true + /pretty-format/27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + dev: true + /prismjs/1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} @@ -6862,6 +7215,10 @@ packages: flat: 5.0.2 dev: true + /react-is/17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: true + /read-cache/1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: @@ -7309,6 +7666,15 @@ packages: vscode-textmate: 6.0.0 dev: true + /shiki/0.14.1: + resolution: {integrity: sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==} + dependencies: + ansi-sequence-parser: 1.1.0 + jsonc-parser: 3.2.0 + vscode-oniguruma: 1.7.0 + vscode-textmate: 8.0.0 + dev: true + /side-channel/1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -7317,6 +7683,10 @@ packages: object-inspect: 1.12.3 dev: true + /siginfo/2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true @@ -7335,6 +7705,14 @@ packages: engines: {node: '>=12'} dev: true + /slice-ansi/5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + /smob/0.0.6: resolution: {integrity: sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw==} dev: true @@ -7408,6 +7786,10 @@ packages: deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' dev: true + /stackback/0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + /standard-as-callback/2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} dev: true @@ -7727,6 +8109,20 @@ packages: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} dev: true + /tinybench/2.4.0: + resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==} + dev: true + + /tinypool/0.3.1: + resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy/1.1.1: + resolution: {integrity: sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==} + engines: {node: '>=14.0.0'} + dev: true + /tmp/0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -7869,6 +8265,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.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} @@ -8232,6 +8633,27 @@ packages: - terser dev: true + /vite-node/0.29.3_@types+node@18.15.3: + resolution: {integrity: sha512-QYzYSA4Yt2IiduEjYbccfZQfxKp+T1Do8/HEpSX/G5WIECTFKJADwLs9c94aQH4o0A+UtCKU61lj1m5KvbxxQA==} + engines: {node: '>=v14.16.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.2.0 + pathe: 1.1.0 + picocolors: 1.0.0 + vite: 4.2.0_@types+node@18.15.3 + transitivePeerDependencies: + - '@types/node' + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite-plugin-checker/0.5.6_vite@4.1.4: resolution: {integrity: sha512-ftRyON0gORUHDxcDt2BErmsikKSkfvl1i2DoP6Jt2zDO9InfvM6tqO1RkXhSjkaXEhKPea6YOnhFaZxW3BzudQ==} engines: {node: '>=14.16'} @@ -8393,6 +8815,88 @@ packages: vite: 4.2.0 dev: true + /vitepress/1.0.0-alpha.60: + resolution: {integrity: sha512-GI5iLDkZRqGEPixbSloT+p6pbKcMh9ykRRxt8vf9AjV1gaPit6Stg/t9WNxTdIhKVCuQMexGs1605DNApSRK2A==} + hasBin: true + dependencies: + '@docsearch/css': 3.3.3 + '@docsearch/js': 3.3.3 + '@vitejs/plugin-vue': 4.1.0_vite@4.2.0+vue@3.2.47 + '@vue/devtools-api': 6.5.0 + '@vueuse/core': 9.13.0_vue@3.2.47 + body-scroll-lock: 4.0.0-beta.0 + shiki: 0.14.1 + vite: 4.2.0 + vue: 3.2.47 + transitivePeerDependencies: + - '@algolia/client-search' + - '@types/node' + - '@types/react' + - '@vue/composition-api' + - less + - react + - react-dom + - sass + - stylus + - sugarss + - terser + dev: true + + /vitest/0.29.3: + resolution: {integrity: sha512-muMsbXnZsrzDGiyqf/09BKQsGeUxxlyLeLK/sFFM4EXdURPQRv8y7dco32DXaRORYP0bvyN19C835dT23mL0ow==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.4 + '@types/chai-subset': 1.3.3 + '@types/node': 18.15.3 + '@vitest/expect': 0.29.3 + '@vitest/runner': 0.29.3 + '@vitest/spy': 0.29.3 + '@vitest/utils': 0.29.3 + acorn: 8.8.2 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.7 + debug: 4.3.4 + local-pkg: 0.4.3 + pathe: 1.1.0 + picocolors: 1.0.0 + source-map: 0.6.1 + std-env: 3.3.2 + strip-literal: 1.0.1 + tinybench: 2.4.0 + tinypool: 0.3.1 + tinyspy: 1.1.1 + vite: 4.2.0_@types+node@18.15.3 + vite-node: 0.29.3_@types+node@18.15.3 + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vscode-css-languageservice/6.2.4: resolution: {integrity: sha512-9UG0s3Ss8rbaaPZL1AkGzdjrGY8F+P+Ne9snsrvD9gxltDGhsn8C2dQpqQewHrMW37OvlqJoI8sUU2AWDb+qNw==} dependencies: @@ -8478,6 +8982,10 @@ packages: resolution: {integrity: sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==} dev: true + /vscode-textmate/8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} + dev: true + /vscode-uri/2.1.2: resolution: {integrity: sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==} dev: true @@ -8492,6 +9000,21 @@ packages: ufo: 1.1.1 dev: true + /vue-demi/0.13.11_vue@3.2.47: + resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.2.47 + dev: true + /vue-devtools-stub/0.1.0: resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} dev: true @@ -8651,6 +9174,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 + /wide-align/1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: @@ -8752,6 +9284,11 @@ packages: engines: {node: '>=10'} dev: true + /yocto-queue/1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true + /zhead/2.0.4: resolution: {integrity: sha512-V4R94t3ifk9AURym6OskbKcnowzgp5Z88tkoL/NF67vyryNxC62u6mx5F1Ux4oh4+YN7FFmKYEyWy6m5kfPH6g==} dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index fe455ac..d1cce72 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: + - docs - examples/* diff --git a/scripts/postbuild.ts b/scripts/postbuild.ts index d495f2e..5481f07 100644 --- a/scripts/postbuild.ts +++ b/scripts/postbuild.ts @@ -1,6 +1,6 @@ -import { basename, dirname, resolve } from 'path' -import { promises as fs } from 'fs' -import { fileURLToPath } from 'url' +import { basename, dirname, resolve } from 'node:path' +import { promises as fs } from 'node:fs' +import { fileURLToPath } from 'node:url' import fg from 'fast-glob' import chalk from 'chalk' diff --git a/src/astro.ts b/src/astro.ts index ca3a05d..cbeb2e6 100644 --- a/src/astro.ts +++ b/src/astro.ts @@ -7,9 +7,8 @@ export default function (options: Options) { name: 'unplugin-fonts', hooks: { 'astro:config:setup': async (astro: any) => { - if (options?.custom) { + if (options?.custom) options.custom.stripPrefix = 'public/' - } astro.config.vite.plugins ||= [] astro.config.vite.plugins.push(unplugin.vite(options)) @@ -17,7 +16,6 @@ export default function (options: Options) { // const links = getHeadLinkTags(options, astro.config.root.toString()) // const linksString: string[] = [] - // for (const link of links) { // linksString.push(` `${key}="${value}"`).join(' ')} />`) // } diff --git a/src/head.ts b/src/head.ts index 5bace70..2d9385e 100644 --- a/src/head.ts +++ b/src/head.ts @@ -1,4 +1,4 @@ import type { HtmlTagDescriptor } from 'vite' // exposed via virtual module -export const links: HtmlTagDescriptor[] = [] \ No newline at end of file +export const links: HtmlTagDescriptor[] = [] diff --git a/src/index.ts b/src/index.ts index f7b6826..1e64477 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,10 +5,10 @@ import { fontsourceVirtualModule } from './loaders/fontsource' import { customVirtualModule } from './loaders/custom' const virtualStylesId = 'unfonts.css' -const resolvedVirtualStylesId = '\0' + virtualStylesId +const resolvedVirtualStylesId = `\0${virtualStylesId}` const virtualModuleId = 'unplugin-fonts/head' -const resolvedVirtualModuleId = '\0' + virtualModuleId +const resolvedVirtualModuleId = `\0${virtualModuleId}` export default createUnplugin((userOptions) => { const options = userOptions || {} @@ -18,30 +18,25 @@ export default createUnplugin((userOptions) => { name: 'unplugin-fonts', enforce: 'pre', resolveId(id) { - if (id === virtualStylesId) { + if (id === virtualStylesId) return resolvedVirtualStylesId - } - - if (id === virtualModuleId) { + + if (id === virtualModuleId) return resolvedVirtualModuleId - } }, load(id) { - if (id === resolvedVirtualModuleId) { + if (id === resolvedVirtualModuleId) return `export const links = ${JSON.stringify(getHeadLinkTags(options, root))}` - } - + if (id === resolvedVirtualStylesId) { const source: string[] = [] - if (options.fontsource) { + if (options.fontsource) source.push(fontsourceVirtualModule(options.fontsource)) - } - if (options.custom) { + if (options.custom) source.push(customVirtualModule(options.custom, root)) - } return source.join('\n') } diff --git a/src/loaders/custom.ts b/src/loaders/custom.ts index e8f55c7..27ca59e 100644 --- a/src/loaders/custom.ts +++ b/src/loaders/custom.ts @@ -1,292 +1,238 @@ import type { HtmlTagDescriptor } from 'vite' import { sync as glob } from 'fast-glob' -import { resolve, join, relative } from 'pathe' - -interface CustomFontFace { - src: string[] - name: string - weight: number | string - style: string - display: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' - local?: string | string[] +import { basename as _basename, extname, join, relative } from 'pathe' +import type { CustomFontFace, CustomFontFamily, CustomFonts } from '../types' + +type ResolvedCustomFonts = Required> & { families: CustomFontFamily[] } + +function resolveUserOption(options: CustomFonts): ResolvedCustomFonts { + let { + families = [], + preload = true, + prefetch = false, + injectTo = 'head-prepend', + display = 'auto', + stripPrefix = 'public/', + } = options + + // --- Cast as array of `CustomFontFamily`. + if (!Array.isArray(families)) { + families = Object.entries(families) + .map(([name, family]) => (Array.isArray(family) || typeof family === 'string') + ? { name, src: family } + : { name, ...family }, + ) + } + + return { + families, + preload, + prefetch, + injectTo, + display, + stripPrefix, + } +} + +export function customVirtualModule(userOptions: CustomFonts, root: string) { + const options = resolveUserOption(userOptions) + + const css: string[] = [] + + for (const family of options.families) { + const faces = resolveFontFiles(family, options, root) + + // --- Generate CSS `@font-face` rules. + for (const face of faces) + css.push(generateFontCSS(face)) + } + + return css.join('\n') } -export interface CustomFontFamily { - /** - * Name of the font family. - * @example 'Comic Sans MS' - */ - name: string - /** - * Regex(es) of font files to import. The names of the files will - * predicate the `font-style` and `font-weight` values of the `@font-rule`'s. - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#common_weight_name_mapping - * - * @example - * A value of `./RobotoBoldItalic.*` will create this `@font-rule`: - * - * ```css - * font-face { - * font-family: 'Roboto'; - * src: url(./RobotoBoldItalic.ttf) format('truetype') - * url(./RobotoBoldItalic.woff) format('woff') - * url(./RobotoBoldItalic.woff2) format('woff2'); - * font-weight: bold; - * font-style: italic; - * font-display: auto; - * } - * ``` - */ - src: string | string[] - /** - * Local name of the font. Used to add `src: local()` to `@font-rule`. - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face#description - */ - local?: string | string[] +export function customLoader(userOptions: CustomFonts, root: string) { + const options = resolveUserOption(userOptions) + + const tags: HtmlTagDescriptor[] = [] + + // --- Iterate over font families and their faces. + for (const family of options.families) { + const faces = resolveFontFiles(family, options, root) + + // --- We can not do a prefetch and a preload for the same files. + if (options.preload && options.prefetch) { + console.warn('unplugin-fonts: Prefetch and a Preload options can not be used together.') + console.warn('unplugin-fonts: The prefetch stand for a lower priority for the resource (maybe we will need it in a future page) whereas preload is for the current page, so we can not have both.') + } + if (options.preload || options.prefetch) { + // --- Generate `` tags. + for (const face of faces) + tags.push(...createFontLinks(options, face)) + } + } + + return tags } -export interface CustomFonts { - /** - * Font families. - */ - families: CustomFontFamily[] | Record> - /** - * Defines the default `font-display` value used for the generated - * `@font-rule` classes. - * @see https://developer.mozilla.org/fr/docs/Web/CSS/@font-face/font-display - * @default 'auto' - */ - display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' - /** - * Using `` will trigger a request for the WebFont - * early in the critical rendering path, without having to wait for the - * CSSOM to be created. - * @see https://web.dev/optimize-webfont-loading/#preload-your-webfont-resources - * @default true - */ - preload?: boolean - - /** - * Using `` is intended for prefetching resources - * that will be used in the next navigation/page load - * (e.g. when you go to the next page) - * - * Note: this can not be used with `preload` - * @default false - */ - prefetch?: boolean - /** - * @default: 'head-prepend' - */ - injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' - - /** - * Remove the prefix from the front path - * @default: 'public/' - */ - stripPrefix?: string +function resolveFontFiles(family: CustomFontFamily, options: ResolvedCustomFonts, root: string) { + const sources = Array.isArray(family.src) ? family.src : [family.src] + const facesMap: Record = {} + + for (const source of sources) { + const results = glob(join(root, source), { absolute: true, cwd: root, onlyFiles: true }) + + for (const file of results) { + const ext = extname(file) + const basename = _basename(file, ext) + + let format = '' + switch (ext) { + case '.woff': + format = 'woff' + break + case '.woff2': + format = 'woff2' + break + case '.ttf': + format = 'truetype' + break + case '.otf': + format = 'opentype' + break + case '.svg': + format = 'svg' + break + default: + format = ext.replace('.', '') + } + + facesMap[basename] ||= { + source, + name: family.name, + basename, + weight: extractWeight(basename), + style: extractStyle(basename), + local: family.local, + display: options.display, + files: [], + } + facesMap[basename].files.push({ + src: file, + path: join('/', relative(root, file.replace(options.stripPrefix, ''))), + format, + ext, + }) + } + } + + const faces: CustomFontFace[] = [] + for (const face of Object.values(facesMap)) { + if (!family.transform) { + faces.push(face) + continue + } + + const transformed = family.transform(face) + if (transformed) + faces.push(transformed) + } + + return faces } -const resolveWeight = (weightOrSrc?: string | number) => { - if (typeof weightOrSrc === 'number') - return weightOrSrc - if (!weightOrSrc) +function extractWeight(filename?: string) { + if (!filename) return 400 - weightOrSrc = weightOrSrc.toLowerCase() - if (weightOrSrc.includes('thin')) + + filename = filename.toLowerCase() + + if (filename.includes('thin')) return 100 - if (weightOrSrc.includes('extralight')) + if (filename.includes('extralight')) return 200 - if (weightOrSrc.includes('ultralight')) + if (filename.includes('ultralight')) return 200 - if (weightOrSrc.includes('light')) + if (filename.includes('light')) return 300 - if (weightOrSrc.includes('normal')) + if (filename.includes('normal')) return 400 - if (weightOrSrc.includes('medium')) + if (filename.includes('medium')) return 500 - if (weightOrSrc.includes('semibold')) + if (filename.includes('semibold')) return 600 - if (weightOrSrc.includes('demibold')) + if (filename.includes('demibold')) return 600 - if (weightOrSrc.includes('extrabold')) + if (filename.includes('extrabold')) return 800 - if (weightOrSrc.includes('ultrabold')) + if (filename.includes('ultrabold')) return 800 - if (weightOrSrc.includes('bold')) + if (filename.includes('bold')) return 700 - if (weightOrSrc.includes('black')) + if (filename.includes('black')) return 900 - if (weightOrSrc.includes('heavy')) + if (filename.includes('heavy')) return 900 return 400 } -const resolveStyle = (styleOrSrc?: string) => { - if (!styleOrSrc) +function extractStyle(filename?: string) { + if (!filename) return 'normal' - styleOrSrc = styleOrSrc.toLowerCase() - if (styleOrSrc.includes('normal')) + + filename = filename.toLowerCase() + if (filename.includes('normal')) return 'normal' - if (styleOrSrc.includes('italic')) + + if (filename.includes('italic')) return 'italic' - if (styleOrSrc.includes('oblique')) + + if (filename.includes('oblique')) return 'oblique' + return 'normal' } -const createFontFaceCSS = ({ name, src, local, weight, style, display }: CustomFontFace) => { +function generateFontCSS(face: CustomFontFace) { // --- Format sources. - const srcs = (Array.isArray(src) ? src : [src]) - .filter(Boolean) - .map((url) => { - let format = url.split('.').pop() - if (format === 'ttf') - format = 'truetype' - if (format === 'otf') - format = 'opentype' - return `url('${join('/', url)}') format('${format}')` + const srcs = face.files + .map((file) => { + return `url('${file.path}') format('${file.format}')` }) .join(',\n\t\t') // --- Format local. - const locals = (Array.isArray(local) ? local : [local]) + const locals = (Array.isArray(face.local) ? face.local : [face.local]) .filter(Boolean) .map(x => `local('${x}')`) .join(', ') // --- Return CSS rule as string. - return `@font-face { - font-family: '${name}'; - src: ${[srcs, locals].filter(Boolean).join(',')}; - font-weight: ${weight}; - font-style: ${style}; - font-display: ${display}; -}` -} - -const createFontFaceLink = ( - prefetch = false, - injectTo: 'head' | 'body' | 'head-prepend' | 'body-prepend' = 'head-prepend', -) => (href: string) => { - return { - tag: 'link', - injectTo, - attrs: { - rel: prefetch ? 'prefetch' : 'preload', - as: 'font', - type: `font/${href.split('.').pop()}`, - href, - crossorigin: true, - }, - } -} - -function resolveFontfaceFiles({ src, root }: { - src: string | string[] - root: string -}) { - const facesGrouped: Record = {}; - - (Array.isArray(src) ? src : [src]) - .flatMap(x => { - return glob(join(root, x), { absolute: true, cwd: root, onlyFiles: true }) - }) - .filter(Boolean) - .forEach((src) => { - const srcNoExt = src.match(/(.*)\.(\w|\d)+$/)?.[1].toLowerCase() - if (srcNoExt) - facesGrouped[srcNoExt] = (facesGrouped[srcNoExt] ?? []).concat(src) - }) - - return Object.entries(facesGrouped).map(([srcNoExt, src]) => ({ - srcNoExt, src - })) -} - -export function customVirtualModule(options: CustomFonts, root: string) { - const css: string[] = [] - - /* eslint-disable prefer-const */ - let { - families = [], - display = 'auto', - stripPrefix = 'public/', - } = options - /* eslint-enable prefer-const */ - - // --- Cast as array of `CustomFontFamily`. - if (!Array.isArray(families)) { - families = Object.entries(families) - .map(([name, family]) => (Array.isArray(family) || typeof family === 'string') - ? { name, src: family } - : { name, ...family }, - ) - } - - for (const { name, src, local } of families) { - const faces = resolveFontfaceFiles({ src, root }) - .map((item) => ({ - name, - src: item.src.map(x => join('/', relative(root, x.replace(stripPrefix, '')))), - weight: resolveWeight(item.srcNoExt), - style: resolveStyle(item.srcNoExt), - display, - local, - })) - // --- Generate CSS `@font-face` rules. - for (const face of faces) css.push(createFontFaceCSS(face)) - } - - return css.join('\n\n') + return [ + '@font-face {', + ` font-family: '${face.name}';`, + ` src: ${[srcs, locals].filter(Boolean).join(',')};`, + ` font-weight: ${face.weight};`, + ` font-style: ${face.style};`, + ` font-display: ${face.display};`, + '}', + ].join('\n') } -export function customLoader(options: CustomFonts, root: string) { - const tags: HtmlTagDescriptor[] = [] - // const css: string[] = [] - - // --- Extract and defaults plugin options. - /* eslint-disable prefer-const */ - let { - families = [], - preload = true, - prefetch = false, - injectTo = 'head-prepend', - stripPrefix = 'public/', - } = options - /* eslint-enable prefer-const */ - - // --- Cast as array of `CustomFontFamily`. - if (!Array.isArray(families)) { - families = Object.entries(families) - .map(([name, family]) => (Array.isArray(family) || typeof family === 'string') - ? { name, src: family } - : { name, ...family }, - ) - } - - // --- Iterate over font families and their faces. - for (const { src } of families) { - const faces = resolveFontfaceFiles({ src, root }) - - const hrefs = faces - .flatMap(face => face.src) - .map(src => join('/', relative(root, src.replace(stripPrefix, '')))) - - // --- Generate `` tags. - // --- We can not do a prefetch and a preload for the same files. - if (preload && prefetch) { - console.warn('unplugin-fonts: Prefetch and a Preload options can not be used together.') - console.warn('unplugin-fonts: The prefetch stand for a lower priority for the resource (maybe we will need it in a future page) whereas preload is for the current page, so we can not have both.') - } - if (preload || prefetch) - tags.push(...hrefs.map(createFontFaceLink(prefetch, injectTo))) - - // // --- Generate CSS `@font-face` rules. - // for (const face of faces) css.push(createFontFaceCSS(face)) +function createFontLinks(options: ResolvedCustomFonts, face: CustomFontFace) { + const links: HtmlTagDescriptor[] = [] + + for (const file of face.files) { + links.push({ + tag: 'link', + injectTo: options.injectTo, + attrs: { + rel: options.prefetch ? 'prefetch' : 'preload', + as: 'font', + type: `font/${file.ext.replace('.', '')}`, + href: file.path, + crossorigin: true, + }, + }) } - - // --- Return tags and CSS. - return tags + return links } - diff --git a/src/loaders/fontsource.ts b/src/loaders/fontsource.ts index 30c679a..bd643b1 100644 --- a/src/loaders/fontsource.ts +++ b/src/loaders/fontsource.ts @@ -1,16 +1,4 @@ - -export interface FontsourceFontFamily { - name: string - variables?: ('variable' | 'variable-italic' | 'variable-full' | 'variable-full-italic')[] - weights: (100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900)[] - styles?: ('italic' | 'normal')[] - subset?: string -} -export interface FontsourceFonts { - families: (string | FontsourceFontFamily)[] - // text?: string - // display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' -} +import type { FontsourceFonts } from '../types' export function fontsourceVirtualModule(options?: FontsourceFonts) { const source: string[] = [] @@ -19,52 +7,53 @@ export function fontsourceVirtualModule(options?: FontsourceFonts) { families = [], } = options || {} - for(const family of families) { - if(typeof family === 'string') { - source.push(`@import "@fontsource/${family.toLowerCase()}";`) - } else { - const { - name, - variables, - weights, - styles, - subset - } = family - - const subsetPrefix = subset ? `${subset}-` : '' - - if (variables) { - if (weights) { - console.warn('unplugin-fonts: Variable fonts do not support weights. Ignoring weights.') - } + for (const family of families) { + if (!family) + continue - for (const variable of variables) { - source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${variable}.css";`) - } - } else if (weights) { - for (const weight of weights) { - if (styles) { - for (const style of styles) { - if (style === 'normal') { - source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${style}.css";`) - } else { - source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${weight}-${style}.css";`) - } - } - } else { - source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${weight}.css";`) + if (typeof family === 'string') { + source.push(`@import "@fontsource/${family.toLowerCase()}";`) + continue + } + const { + name, + variables, + weights, + styles, + subset, + } = family + + const subsetPrefix = subset ? `${subset}-` : '' + + if (variables) { + if (weights) + console.warn('unplugin-fonts: Variable fonts does not support weights. Ignoring weights.') + + for (const variable of variables) + source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${variable}.css";`) + } + else if (weights) { + for (const weight of weights) { + if (styles) { + for (const style of styles) { + if (style === 'normal') + source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${style}.css";`) + else + source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${weight}-${style}.css";`) } } - } else { - if (subset) { - source.push(`@import "@fontsource/${name.toLowerCase()}/${subset}.css";`) - } else { - source.push(`@import "@fontsource/${name.toLowerCase()}";`) + else { + source.push(`@import "@fontsource/${name.toLowerCase()}/${subsetPrefix}${weight}.css";`) } } - + } + else { + if (subset) + source.push(`@import "@fontsource/${name.toLowerCase()}/${subset}.css";`) + else + source.push(`@import "@fontsource/${name.toLowerCase()}";`) } } return source.join('\n') -} \ No newline at end of file +} diff --git a/src/loaders/google-fonts.ts b/src/loaders/google-fonts.ts index e9bdd57..9a48763 100644 --- a/src/loaders/google-fonts.ts +++ b/src/loaders/google-fonts.ts @@ -1,20 +1,5 @@ import type { HtmlTagDescriptor } from 'vite' - -export interface GoogleFontFamily { - name: string - styles?: string - defer?: boolean -} -export interface GoogleFonts { - families: (string | GoogleFontFamily)[] - text?: string - display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' - preconnect?: boolean - /** - * @default: 'head-prepend' - */ - injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' -} +import type { GoogleFonts } from '../types' const GoogleFontsBase = 'https://fonts.googleapis.com/css2' const GStaticBase = 'https://fonts.gstatic.com/' @@ -43,7 +28,7 @@ export function googleLoader({ continue } - if (!(family as GoogleFontFamily)) + if (!family) continue const { diff --git a/src/loaders/index.ts b/src/loaders/index.ts index 7f5837f..c13fe5b 100644 --- a/src/loaders/index.ts +++ b/src/loaders/index.ts @@ -1,18 +1,20 @@ -import { HtmlTagDescriptor } from 'vite' +import type { HtmlTagDescriptor } from 'vite' import type { Options } from '../types' import { customLoader } from './custom' import { typekitLoader } from './typekit' import { googleLoader } from './google-fonts' -export function getHeadLinkTags (resolvedOptions: Options, root: string) { +export function getHeadLinkTags(resolvedOptions: Options, root: string) { const tags: HtmlTagDescriptor[] = [] if (resolvedOptions.typekit) tags.push(...typekitLoader(resolvedOptions.typekit)) + if (resolvedOptions.google) tags.push(...googleLoader(resolvedOptions.google)) + if (resolvedOptions.custom) tags.push(...customLoader(resolvedOptions.custom, root)) return tags -} \ No newline at end of file +} diff --git a/src/loaders/typekit.ts b/src/loaders/typekit.ts index eeec414..79f17a6 100644 --- a/src/loaders/typekit.ts +++ b/src/loaders/typekit.ts @@ -1,13 +1,5 @@ import type { HtmlTagDescriptor } from 'vite' - -export interface TypeKitFonts { - id: string - defer?: boolean - /** - * default: 'head-prepend' - */ - injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' -} +import type { TypeKitFonts } from '../types' const TypekitFontBase = 'https://use.typekit.net/' @@ -49,4 +41,3 @@ export function typekitLoader({ return tags } - diff --git a/src/nuxt.ts b/src/nuxt.ts index 0663c5c..bb44067 100644 --- a/src/nuxt.ts +++ b/src/nuxt.ts @@ -1,4 +1,4 @@ -import { addVitePlugin, addWebpackPlugin, defineNuxtModule, addTemplate } from '@nuxt/kit' +import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from '@nuxt/kit' // Workaround for: // src/nuxt.ts(5,1): error TS2742: The inferred type of 'default' cannot be named without a reference to '.pnpm/@nuxt+schema@3.0.0_rollup@3.7.3/node_modules/@nuxt/schema'. This is likely not portable. A type annotation is necessary. import type {} from '@nuxt/schema' diff --git a/src/types.ts b/src/types.ts index f8ac812..9f5b69c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,11 +1,145 @@ -import type { CustomFonts } from './loaders/custom' -import type { FontsourceFonts } from './loaders/fontsource' -import type { GoogleFonts } from './loaders/google-fonts' -import type { TypeKitFonts } from './loaders/typekit' - export interface Options { custom?: CustomFonts fontsource?: FontsourceFonts google?: GoogleFonts typekit?: TypeKitFonts } + +export interface CustomFontFace { + source: string + name: string + basename: string + weight: number + style: string + display: string + local?: string | string[] + files: { + src: string + ext: string + path: string + format: string + }[] +} + +export interface CustomFontFamily { + /** + * Name of the font family. + * @example 'Comic Sans MS' + */ + name: string + + /** + * Regex(es) of font files to import. The names of the files will + * predicate the `font-style` and `font-weight` values of the `@font-rule`'s. + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#common_weight_name_mapping + * + * @example + * A value of `./RobotoBoldItalic.*` will create this `@font-rule`: + * + * ```css + * font-face { + * font-family: 'Roboto'; + * src: url(./RobotoBoldItalic.ttf) format('truetype') + * url(./RobotoBoldItalic.woff) format('woff') + * url(./RobotoBoldItalic.woff2) format('woff2'); + * font-weight: bold; + * font-style: italic; + * font-display: auto; + * } + * ``` + */ + src: string | string[] + /** + * Local name of the font. Used to add `src: local()` to `@font-rule`. + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face#description + */ + local?: string | string[] + + /** + * Allows to transform the generated config for any font face. + * + * @param font + * @returns + */ + transform?: (font: CustomFontFace) => CustomFontFace | null +} + +export interface CustomFonts { + /** + * Font families. + */ + families: CustomFontFamily[] | Record> + + /** + * Defines the default `font-display` value used for the generated + * `@font-rule` classes. + * @see https://developer.mozilla.org/fr/docs/Web/CSS/@font-face/font-display + * @default 'auto' + */ + display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' + + /** + * Using `` will trigger a request for the WebFont + * early in the critical rendering path, without having to wait for the + * CSSOM to be created. + * @see https://web.dev/optimize-webfont-loading/#preload-your-webfont-resources + * @default true + */ + preload?: boolean + + /** + * Using `` is intended for prefetching resources + * that will be used in the next navigation/page load + * (e.g. when you go to the next page) + * + * Note: this can not be used with `preload` + * @default false + */ + prefetch?: boolean + /** + * @default: 'head-prepend' + */ + injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' + + /** + * Remove the prefix from the front path + * @default: 'public/' + */ + stripPrefix?: string +} + +export interface FontsourceFontFamily { + name: string + variables?: ('variable' | 'variable-italic' | 'variable-full' | 'variable-full-italic')[] + weights: (100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900)[] + styles?: ('italic' | 'normal')[] + subset?: string +} +export interface FontsourceFonts { + families: (string | FontsourceFontFamily)[] +} + +export interface GoogleFontFamily { + name: string + styles?: string + defer?: boolean +} +export interface GoogleFonts { + families: (string | GoogleFontFamily)[] + text?: string + display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional' + preconnect?: boolean + /** + * @default: 'head-prepend' + */ + injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' +} + +export interface TypeKitFonts { + id: string + defer?: boolean + /** + * default: 'head-prepend' + */ + injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' +} diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 0000000..e2079b8 --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,7 @@ +import { describe, expect, it } from 'vitest' + +describe('index', () => { + it('hi vitest', () => { + expect(1).toBe(1) + }) +}) diff --git a/tsup.config.ts b/tsup.config.ts index c6495b2..0a63ae4 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -6,7 +6,7 @@ export default { 'src/astro/component.astro', ], loader: { - '.astro': 'copy' + '.astro': 'copy', }, clean: true, format: ['cjs', 'esm'],