diff --git a/greenwood.config.js b/greenwood.config.js index 39e8acdc..e1a4eea3 100644 --- a/greenwood.config.js +++ b/greenwood.config.js @@ -1,9 +1,10 @@ import { greenwoodPluginImportRaw } from "@greenwood/plugin-import-raw"; import { greenwoodPluginCssModules } from "./plugin-css-modules.js"; +// import { greenwoodPluginPostCss } from "@greenwood/plugin-postcss"; export default { prerender: true, - plugins: [greenwoodPluginImportRaw(), greenwoodPluginCssModules()], + plugins: [greenwoodPluginCssModules(), greenwoodPluginImportRaw()], markdown: { plugins: ["@mapbox/rehype-prism"], }, diff --git a/package-lock.json b/package-lock.json index 5ce6f15e..df47b1b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@esm-bundle/chai": "^4.3.4-fix.0", "@greenwood/cli": "^0.30.0-alpha.4", "@greenwood/plugin-import-raw": "^0.30.0-alpha.4", + "@greenwood/plugin-postcss": "^0.30.0-alpha.4", "@ls-lint/ls-lint": "^1.10.0", "@mapbox/rehype-prism": "^0.9.0", "@storybook/addon-essentials": "^8.0.6", @@ -38,6 +39,7 @@ "lint-staged": "^15.2.2", "lit": "^3.1.2", "patch-package": "^8.0.0", + "postcss-import": "^16.1.0", "prettier": "^3.2.5", "rimraf": "^5.0.5", "storybook": "^8.0.6", @@ -2015,6 +2017,302 @@ "@csstools/css-tokenizer": "^2.2.4" } }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, "node_modules/@csstools/selector-specificity": { "version": "3.0.3", "dev": true, @@ -2225,6 +2523,37 @@ "@greenwood/cli": "^0.4.0" } }, + "node_modules/@greenwood/plugin-postcss": { + "version": "0.30.0-alpha.4", + "resolved": "https://registry.npmjs.org/@greenwood/plugin-postcss/-/plugin-postcss-0.30.0-alpha.4.tgz", + "integrity": "sha512-zXxSx2I1IOYT/PqtT5Si5actidRCgI4gfEWMYwzLHsMwziq4MqMtROvuVptuirC4TyvpqAQtg80Vi/k4oAb5Dw==", + "dev": true, + "dependencies": { + "postcss": "^8.3.11", + "postcss-import": "^13.0.0", + "postcss-preset-env": "^7.0.1" + }, + "peerDependencies": { + "@greenwood/cli": "^0.4.0" + } + }, + "node_modules/@greenwood/plugin-postcss/node_modules/postcss-import": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-13.0.0.tgz", + "integrity": "sha512-LPUbm3ytpYopwQQjqgUH4S3EM/Gb9QsaSPP/5vnoi+oKVy3/mIk2sc0Paqw7RL57GpScm9MdIMUypw2znWiBpg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "dev": true, @@ -2909,9 +3238,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", "cpu": [ "x64" ], @@ -5628,6 +5957,43 @@ "gulp-header": "^1.7.1" } }, + "node_modules/autoprefixer": { + "version": "10.4.19", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", + "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001599", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "dev": true, @@ -6995,6 +7361,24 @@ "node": ">=8" } }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, "node_modules/css-functions-list": { "version": "3.2.2", "dev": true, @@ -7003,25 +7387,74 @@ "node": ">=12 || >=16" } }, - "node_modules/css-tree": { - "version": "2.3.1", + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", "dev": true, - "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" } }, - "node_modules/css.escape": { - "version": "1.5.1", + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", "dev": true, - "license": "MIT" - }, - "node_modules/cssesc": { - "version": "3.0.0", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cssdb": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.11.2.tgz", + "integrity": "sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ] + }, + "node_modules/cssesc": { + "version": "3.0.0", "dev": true, "license": "MIT", "bin": { @@ -8493,6 +8926,19 @@ "node": ">= 0.6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fresh": { "version": "0.5.2", "dev": true, @@ -11778,6 +12224,15 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", "dev": true, @@ -12709,6 +13164,552 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", + "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, "node_modules/postcss-resolve-nested-selector": { "version": "0.1.1", "dev": true, @@ -12739,6 +13740,25 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, "node_modules/postcss-selector-parser": { "version": "6.0.16", "dev": true, @@ -13182,6 +14202,24 @@ "dev": true, "license": "MIT" }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-cache/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "dev": true, diff --git a/package.json b/package.json index 84fa25e4..0917b3b0 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@esm-bundle/chai": "^4.3.4-fix.0", "@greenwood/cli": "^0.30.0-alpha.4", "@greenwood/plugin-import-raw": "^0.30.0-alpha.4", + "@greenwood/plugin-postcss": "^0.30.0-alpha.4", "@ls-lint/ls-lint": "^1.10.0", "@mapbox/rehype-prism": "^0.9.0", "@storybook/addon-essentials": "^8.0.6", @@ -62,6 +63,7 @@ "lint-staged": "^15.2.2", "lit": "^3.1.2", "patch-package": "^8.0.0", + "postcss-import": "^16.1.0", "prettier": "^3.2.5", "rimraf": "^5.0.5", "storybook": "^8.0.6", diff --git a/patches/@greenwood+cli+0.30.0-alpha.4.patch b/patches/@greenwood+cli+0.30.0-alpha.4.patch new file mode 100644 index 00000000..ff330157 --- /dev/null +++ b/patches/@greenwood+cli+0.30.0-alpha.4.patch @@ -0,0 +1,358 @@ +diff --git a/node_modules/@greenwood/cli/src/config/rollup.config.js b/node_modules/@greenwood/cli/src/config/rollup.config.js +index 7771d11..5d48e0c 100644 +--- a/node_modules/@greenwood/cli/src/config/rollup.config.js ++++ b/node_modules/@greenwood/cli/src/config/rollup.config.js +@@ -12,7 +12,9 @@ function cleanRollupId(id) { + return id.replace('\x00', '').replace('?commonjs-proxy', ''); + } + +-function greenwoodResourceLoader (compilation) { ++function greenwoodResourceLoader (compilation, browser = false) { ++ // ConstructableStylesheets, JSON Modules ++ const externalizedResources = ['css', 'json']; + const resourcePlugins = compilation.config.plugins.filter((plugin) => { + return plugin.type === 'resource'; + }).map((plugin) => { +@@ -21,16 +23,29 @@ function greenwoodResourceLoader (compilation) { + + return { + name: 'greenwood-resource-loader', +- async resolveId(id) { +- const normalizedId = cleanRollupId(id); // idUrl.pathname; +- const { projectDirectory, userWorkspace } = compilation.context; +- +- if (normalizedId.startsWith('.') && !normalizedId.startsWith(projectDirectory.pathname)) { ++ async resolveId(id, importer) { ++ const normalizedId = cleanRollupId(id); ++ const { userWorkspace } = compilation.context; ++ ++ // check for non bare paths and resolve them to the user's workspace ++ // or Greenwood's scratch dir, like when bundling inline `) ++ ...customImports.filter(resource => resource.split(' ')[0].split('.').pop() === 'js') ++ .map((resource) => { ++ const [src, ...attributes] = resource.split(' '); ++ const attrs = attributes?.length > 0 ++ ? attributes.join(' ') ++ : ''; ++ ++ return ``; ++ }) + ].join('\n'); + + const finalBody = pageLayoutContents +diff --git a/node_modules/@greenwood/cli/src/lifecycles/bundle.js b/node_modules/@greenwood/cli/src/lifecycles/bundle.js +index 21636a9..f3b814b 100644 +--- a/node_modules/@greenwood/cli/src/lifecycles/bundle.js ++++ b/node_modules/@greenwood/cli/src/lifecycles/bundle.js +@@ -353,10 +353,12 @@ const bundleCompilation = async (compilation) => { + + console.info('bundling static assets...'); + ++ // need styles bundled first for usage with import attributes syncing in Rollup ++ await bundleStyleResources(compilation, optimizeResourcePlugins); ++ + await Promise.all([ + await bundleApiRoutes(compilation), +- await bundleScriptResources(compilation), +- await bundleStyleResources(compilation, optimizeResourcePlugins) ++ await bundleScriptResources(compilation) + ]); + + // bundleSsrPages depends on bundleScriptResources having run first +diff --git a/node_modules/@greenwood/cli/src/loader.js b/node_modules/@greenwood/cli/src/loader.js +index 657ab4e..792f43c 100644 +--- a/node_modules/@greenwood/cli/src/loader.js ++++ b/node_modules/@greenwood/cli/src/loader.js +@@ -7,6 +7,7 @@ const resourcePlugins = config.plugins + .filter(plugin => plugin.name !== 'plugin-node-modules:resource' && plugin.name !== 'plugin-user-workspace') + .map(plugin => plugin.provider({ + context: { ++ outputDir: new URL(`file://${process.cwd()}/public`), + projectDirectory: new URL(`file://${process.cwd()}/`), + scratchDir: new URL(`file://${process.cwd()}/.greenwood/`) + }, +diff --git a/node_modules/@greenwood/cli/src/plugins/resource/plugin-standard-css.js b/node_modules/@greenwood/cli/src/plugins/resource/plugin-standard-css.js +index b0cdbcb..d8409ea 100644 +--- a/node_modules/@greenwood/cli/src/plugins/resource/plugin-standard-css.js ++++ b/node_modules/@greenwood/cli/src/plugins/resource/plugin-standard-css.js +@@ -49,23 +49,26 @@ function bundleCss(body, url, compilation) { + barePath = barePath.replace('/', ''); + } + +- const locationUrl = barePath.startsWith('node_modules') ++ const locationUrl = barePath.indexOf('node_modules/') >= 0 + ? new URL(`./${barePath}`, projectDirectory) + : new URL(`./${barePath}`, userWorkspace); + + if (fs.existsSync(locationUrl)) { ++ const isDev = process.env.__GWD_COMMAND__ === 'develop'; // eslint-disable-line no-underscore-dangle + const hash = hashString(fs.readFileSync(locationUrl, 'utf-8')); + const ext = barePath.split('.').pop(); +- const hashedRoot = barePath.replace(`.${ext}`, `.${hash}.${ext}`); ++ const hashedRoot = isDev ? barePath : barePath.replace(`.${ext}`, `.${hash}.${ext}`); + +- fs.mkdirSync(new URL(`./${path.dirname(barePath)}/`, outputDir), { +- recursive: true +- }); ++ if (!isDev) { ++ fs.mkdirSync(new URL(`./${path.dirname(hashedRoot)}/`, outputDir), { ++ recursive: true ++ }); + +- fs.promises.copyFile( +- locationUrl, +- new URL(`./${hashedRoot}`, outputDir) +- ); ++ fs.promises.copyFile( ++ locationUrl, ++ new URL(`./${hashedRoot}`, outputDir) ++ ); ++ } + + optimizedCss += `url('${basePath}${hashedRoot}')`; + } else { +@@ -303,39 +306,25 @@ class StandardCssResource extends ResourceInterface { + }); + } + +- async shouldIntercept(url, request) { +- const { pathname, searchParams } = url; ++ async shouldIntercept(url) { ++ const { pathname } = url; + const ext = pathname.split('.').pop(); + +- return url.protocol === 'file:' && ext === this.extensions[0] && request.headers.get('Accept')?.indexOf('text/javascript') >= 0 && !searchParams.has('type'); ++ return url.protocol === 'file:' && ext === this.extensions[0]; + } + + async intercept(url, request, response) { +- const contents = (await response.text()).replace(/\r?\n|\r/g, ' ').replace(/\\/g, '\\\\'); +- const body = `const sheet = new CSSStyleSheet();sheet.replaceSync(\`${contents}\`);export default sheet;`; +- +- return new Response(body, { +- headers: { +- 'Content-Type': 'text/javascript' +- } +- }); +- } ++ let body = bundleCss(await response.text(), url, this.compilation); ++ let headers = {}; + +- async shouldOptimize(url, response) { +- const { protocol, pathname, searchParams } = url; +- const isValidCss = pathname.split('.').pop() === this.extensions[0] +- && protocol === 'file:' +- && response.headers.get('Content-Type').indexOf(this.contentType) >= 0 +- && searchParams.get('type') !== 'css'; ++ if (request.headers.get('Accept')?.indexOf('text/javascript') >= 0 && !url.searchParams.has('type')) { ++ const contents = body.replace(/\r?\n|\r/g, ' ').replace(/\\/g, '\\\\'); + +- return this.compilation.config.optimization !== 'none' && isValidCss; +- } +- +- async optimize(url, response) { +- const body = await response.text(); +- const optimizedBody = bundleCss(body, url, this.compilation); ++ body = `const sheet = new CSSStyleSheet();sheet.replaceSync(\`${contents}\`);export default sheet;`; ++ headers['Content-Type'] = 'text/javascript'; ++ } + +- return new Response(optimizedBody); ++ return new Response(body, { headers }); + } + } + diff --git a/patches/wc-compiler+0.14.0.patch b/patches/wc-compiler+0.14.0.patch index c3e43a7c..b8ff5220 100644 --- a/patches/wc-compiler+0.14.0.patch +++ b/patches/wc-compiler+0.14.0.patch @@ -1,8 +1,18 @@ diff --git a/node_modules/wc-compiler/src/dom-shim.js b/node_modules/wc-compiler/src/dom-shim.js -index be289a3..dd4692a 100644 +index be289a3..2c97d0e 100644 --- a/node_modules/wc-compiler/src/dom-shim.js +++ b/node_modules/wc-compiler/src/dom-shim.js -@@ -102,6 +102,9 @@ class ShadowRoot extends DocumentFragment { +@@ -83,6 +83,9 @@ class Document extends Node { + createDocumentFragment(html) { + return new DocumentFragment(html); + } ++ ++ querySelector() { } ++ querySelectorAll() { } + } + + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement +@@ -102,6 +105,9 @@ class ShadowRoot extends DocumentFragment { super(); this.mode = options.mode || 'closed'; this.adoptedStyleSheets = []; diff --git a/plugin-css-modules.js b/plugin-css-modules.js index 46080983..4d89785d 100644 --- a/plugin-css-modules.js +++ b/plugin-css-modules.js @@ -159,78 +159,104 @@ class CssModulesResource extends ResourceInterface { return new Request(matchedUrl); } - async shouldServe(url) { + // async shouldIntercept(url) { + // console.log('css modules intercept', { url }); + // const { pathname, protocol } = url; + // const mapKey = `${protocol}//${pathname}`; + // // // console.log(this.compilation.context.scratchDir) + // // // console.log(new URL('./__css-modules-map.json', this.compilation.context.scratchDir)); + // const cssModulesMap = getCssModulesMap(this.compilation); + // // console.log("shouldServer", { cssModulesMap, url }); + // return protocol === "file:" && pathname.endsWith(this.extensions[0]) && cssModulesMap[mapKey]; + // } + + // async intercept(url) { + // console.log('css modules intercept', { url }); + // const { pathname, protocol } = url; + // const mapKey = `${protocol}//${pathname}`; + // const cssModulesMap = getCssModulesMap(this.compilation); + // // console.log("@@@@@@", { url, cssModulesMap }); + // const cssModule = `export default ${JSON.stringify(cssModulesMap[mapKey].module)}`; + + // // console.log("@@@@@@", { cssModule }); + // return new Response(cssModule, { + // headers: { + // "Content-Type": this.contentType, + // }, + // }); + // } + + // this happens "first" as the HTML is returned, to find viable references to CSS Modules + // better way than just checking for /? + async shouldIntercept(url) { const { pathname, protocol } = url; const mapKey = `${protocol}//${pathname}`; - // // console.log(this.compilation.context.scratchDir) - // // console.log(new URL('./__css-modules-map.json', this.compilation.context.scratchDir)); const cssModulesMap = getCssModulesMap(this.compilation); - // console.log("shouldServer", { cssModulesMap, url }); - return protocol === "file:" && pathname.endsWith(this.extensions[0]) && cssModulesMap[mapKey]; + + return ( + url.pathname.endsWith("/") || + (protocol === "file:" && pathname.endsWith(this.extensions[0]) && cssModulesMap[mapKey]) + ); } - async serve(url) { + async intercept(url, request, response) { const { pathname, protocol } = url; const mapKey = `${protocol}//${pathname}`; const cssModulesMap = getCssModulesMap(this.compilation); - // console.log("@@@@@@", { url, cssModulesMap }); - const cssModule = `export default ${JSON.stringify(cssModulesMap[mapKey].module)}`; - - // console.log("@@@@@@", { cssModule }); - return new Response(cssModule, { - headers: { - "Content-Type": this.contentType, - }, - }); - } - - // this happens "first" as the HTML is returned, to find viable references to CSS Modules - // better way than just checking for /? - async shouldIntercept(url) { - return url.pathname.endsWith("/"); - } - async intercept(url, request, response) { - const body = await response.text(); - const dom = htmlparser.parse(body, { script: true }); - const scripts = dom.querySelectorAll("head script"); - const sheets = []; // TODO use a map here? - - for (const script of scripts) { - const type = script.getAttribute("type"); - const src = script.getAttribute("src"); - if (src && ["module", "module-shim"].includes(type)) { - // console.log("check this file for CSS Modules", src); - // await resolveForRelativeUrl(new URL(src, import.meta.url this.compilation.context.userWorkspace) - const scriptUrl = new URL( - `./${src.replace(/\.\.\//g, "").replace(/\.\//g, "")}`, - this.compilation.context.userWorkspace, - ); - walkAllImportsForCssModules(scriptUrl, sheets, this.compilation); + if (url.pathname.endsWith("/")) { + const body = await response.text(); + const dom = htmlparser.parse(body, { script: true }); + const scripts = dom.querySelectorAll("head script"); + const sheets = []; // TODO use a map here? + + for (const script of scripts) { + const type = script.getAttribute("type"); + const src = script.getAttribute("src"); + if (src && ["module", "module-shim"].includes(type)) { + // console.log("check this file for CSS Modules", src); + // await resolveForRelativeUrl(new URL(src, import.meta.url this.compilation.context.userWorkspace) + const scriptUrl = new URL( + `./${src.replace(/\.\.\//g, "").replace(/\.\//g, "")}`, + this.compilation.context.userWorkspace, + ); + walkAllImportsForCssModules(scriptUrl, sheets, this.compilation); + } } - } - const cssModulesMap = getCssModulesMap(this.compilation); - // console.log({ cssModulesMap }); - - // for(const cssModule of cssModulesMap) { - // // console.log({ cssModule }); - // } - Object.keys(cssModulesMap).forEach((key) => { - sheets.push(cssModulesMap[key].contents); - }); - - const newBody = body.replace( - "", - ` - - - `, - ); + const cssModulesMap = getCssModulesMap(this.compilation); + // console.log({ cssModulesMap }); + + // for(const cssModule of cssModulesMap) { + // // console.log({ cssModule }); + // } + Object.keys(cssModulesMap).forEach((key) => { + sheets.push(cssModulesMap[key].contents); + }); + + const newBody = body.replace( + "", + ` + + + `, + ); - return new Response(newBody); + return new Response(newBody); + } else if ( + url.pathname.endsWith("/") || + (protocol === "file:" && pathname.endsWith(this.extensions[0]) && cssModulesMap[mapKey]) + ) { + const cssModule = `export default ${JSON.stringify(cssModulesMap[mapKey].module)}`; + + return new Response(cssModule, { + headers: { + "Content-Type": this.contentType, + }, + }); + } } async shouldOptimize(url, response) { diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 00000000..0df4fd4a --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,3 @@ +module.exports = { + plugins: [require("postcss-import")], +}; diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 00000000..38ef7be9 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,5 @@ +// would like to get rid of this need, ideally +// https://github.com/ProjectEvergreen/greenwood/discussions/1238 +export default { + plugins: [(await import("postcss-import")).default], +}; diff --git a/src/assets/github.svg b/src/assets/github.svg index a69fbfcb..dc42fbd5 100644 --- a/src/assets/github.svg +++ b/src/assets/github.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/htmx.svg b/src/assets/htmx.svg new file mode 100644 index 00000000..4f5f653b --- /dev/null +++ b/src/assets/htmx.svg @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/modern-web.svg b/src/assets/modern-web.svg new file mode 100644 index 00000000..64e0b6a9 --- /dev/null +++ b/src/assets/modern-web.svg @@ -0,0 +1,104 @@ + + Tilted sphere with longitudinal stripes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/build-with-friends/build-with-friends.js b/src/components/build-with-friends/build-with-friends.js new file mode 100644 index 00000000..dd21aaf0 --- /dev/null +++ b/src/components/build-with-friends/build-with-friends.js @@ -0,0 +1,47 @@ +import styles from "./build-with-friends.module.css"; +import htmxIcon from "../../assets/htmx.svg?type=raw"; +import litIcon from "../../assets/lit.svg?type=raw"; +import storybookIcon from "../../assets/storybook.svg?type=raw"; +import tailwindIcon from "../../assets/tailwind-logo.svg?type=raw"; +import typescriptIcon from "../../assets/typescript.svg?type=raw"; +import wccIcon from "../../assets/wcc.svg?type=raw"; +import wtrIcon from "../../assets/modern-web.svg?type=raw"; + +export default class BuildWithFriends extends HTMLElement { + connectedCallback() { + this.innerHTML = ` + + Build With Friends + + Greenwood and Web Components work great with all of your favorite tools in the web ecosystem. + + + + ${litIcon} + + + ${storybookIcon} + + + ${tailwindIcon} + + + ${typescriptIcon} + + + ${htmxIcon} + + + ${wtrIcon} + Web Test Runner + + + ${wccIcon} + + + + `; + } +} + +customElements.define("app-build-with-friends", BuildWithFriends); diff --git a/src/components/build-with-friends/build-with-friends.module.css b/src/components/build-with-friends/build-with-friends.module.css new file mode 100644 index 00000000..9e2bac57 --- /dev/null +++ b/src/components/build-with-friends/build-with-friends.module.css @@ -0,0 +1,52 @@ +.container { + background-color: var(--color-gray); + border: var(--border-size-1) solid var(--color-black); + border-radius: var(--radius-5); + padding: var(--size-px-5) var(--size-px-5); + margin: 20px auto; +} + +.heading { + font-size: var(--font-size-5); + font-weight: var(--font-weight-9); +} + +.icons { + display: block; +} + +.icon { + display: block; + text-align: center; + background-color: var(--color-white); + border-radius: var(--radius-5); + padding: var(--size-fluid-1) var(--size-fluid-2); + margin: var(--size-fluid-1) var(--size-fluid-1) var(--size-fluid-1) 0; + line-height: 100%; +} + +.icon svg { + height: 50px; +} + +.icon span { + vertical-align: middle; + font-weight: var(--font-weight-9); +} + +@media (min-width: 600px) { + .icon { + display: inline-block; + vertical-align: middle; + } +} + +@media (min-width: 1440px) { + .icons { + max-width: 80%; + } + + .container { + padding: var(--size-px-10) var(--size-px-11); + } +} diff --git a/src/components/build-with-friends/build-with-friends.stories.js b/src/components/build-with-friends/build-with-friends.stories.js new file mode 100644 index 00000000..741390ee --- /dev/null +++ b/src/components/build-with-friends/build-with-friends.stories.js @@ -0,0 +1,9 @@ +import "./build-with-friends.js"; + +export default { + title: "Components/Build With Friends", +}; + +const Template = () => ""; + +export const Primary = Template.bind({}); diff --git a/src/components/footer/footer.js b/src/components/footer/footer.js index 5f39bc30..7f808f5e 100644 --- a/src/components/footer/footer.js +++ b/src/components/footer/footer.js @@ -1,7 +1,7 @@ import discordIcon from "../../assets/discord.svg?type=raw"; import githubIcon from "../../assets/github.svg?type=raw"; import twitterIcon from "../../assets/twitter-logo.svg?type=raw"; -import styles from "./footer.module.css"; +import styles from "./footer.module.css" with { type: "css" }; import greenwoodLogo from "../../assets/greenwood-logo-full.svg?type=raw"; export default class Footer extends HTMLElement { diff --git a/src/components/get-started/get-started.js b/src/components/get-started/get-started.js new file mode 100644 index 00000000..e6a19ac9 --- /dev/null +++ b/src/components/get-started/get-started.js @@ -0,0 +1,28 @@ +import styles from "./get-started.module.css"; + +export default class GetStarted extends HTMLElement { + connectedCallback() { + this.innerHTML = ` + + Get started in seconds 🚀 + + + $ npx @greenwood/init@latest + + + + + View in Stackblitz + + + + Get Started + + + + + `; + } +} + +customElements.define("app-get-started", GetStarted); diff --git a/src/components/get-started/get-started.module.css b/src/components/get-started/get-started.module.css new file mode 100644 index 00000000..74d72bb5 --- /dev/null +++ b/src/components/get-started/get-started.module.css @@ -0,0 +1,68 @@ +.container { + padding: 20px 0 160px; + border-radius: var(--radius-5); + color: var(--color-white); + background-color: var(--color-tertiary); + text-align: center; +} + +.heading { + font-size: var(--font-size-5); + font-weight: var(--font-weight-9); +} + +.snippet { + display: inline-block; + border-radius: var(--radius-4); + padding: 0 var(--size-4); + box-shadow: var(--shadow-4); + letter-spacing: var(--font-letterspacing-3); + background-color: var(--color-white); + color: var(--color-black); + margin: 10px 0; +} + +.snippet pre { + font-size: 16px; + text-align: center; + display: inline-block; +} + +.buttonBlitz { + display: inline-block; + cursor: pointer; + border-radius: var(--radius-3); + border: var(--border-size-1) solid var(--color-white); + background-color: transparent; + padding: var(--size-fluid-1) var(--size-fluid-2); + min-width: var(--size-px-13); + color: var(--color-black); + box-shadow: var(--shadow-2); +} + +.buttonStarted { + display: inline-block; + cursor: pointer; + border-radius: var(--radius-3); + padding: var(--size-fluid-1) var(--size-fluid-2); + background-color: var(--color-primary); + min-width: var(--size-px-13); + color: var(--color-white); + box-shadow: var(--shadow-4); + margin-top: var(--size-fluid-1); +} + +.linkStarted { + color: var(--color-white); + text-decoration: none; +} + +@media (min-width: 1024px) { + .container { + padding: var(--size-px-10) 0 var(--size-px-13) 0; + } + + .snippet { + max-width: 50%; + } +} diff --git a/src/components/get-started/get-started.stories.js b/src/components/get-started/get-started.stories.js new file mode 100644 index 00000000..76d2a82c --- /dev/null +++ b/src/components/get-started/get-started.stories.js @@ -0,0 +1,9 @@ +import "./get-started.js"; + +export default { + title: "Components/Get Started", +}; + +const Template = () => ""; + +export const Primary = Template.bind({}); diff --git a/src/components/header/header.js b/src/components/header/header.js index 6077b97f..07a6743a 100644 --- a/src/components/header/header.js +++ b/src/components/header/header.js @@ -4,6 +4,7 @@ import githubIcon from "../../assets/github.svg?type=raw"; import twitterIcon from "../../assets/twitter-logo.svg?type=raw"; import mobileMenuIcon from "../../assets/tile.svg?type=raw"; import greenwoodLogo from "../../assets/greenwood-logo-full.svg?type=raw"; +import data from "./header.json" with { type: "json" }; export default class Header extends HTMLElement { constructor() { @@ -73,6 +74,7 @@ export default class Header extends HTMLElement { + !!! ${data.message} !!! diff --git a/src/components/header/header.json b/src/components/header/header.json new file mode 100644 index 00000000..fc04a68a --- /dev/null +++ b/src/components/header/header.json @@ -0,0 +1,3 @@ +{ + "message": "Message from JSON import attributes" +} diff --git a/src/components/hero-banner/hero-banner.js b/src/components/hero-banner/hero-banner.js new file mode 100644 index 00000000..2192650d --- /dev/null +++ b/src/components/hero-banner/hero-banner.js @@ -0,0 +1,27 @@ +import styles from "./hero-banner.module.css"; + +export default class HeroBanner extends HTMLElement { + connectedCallback() { + this.innerHTML = ` + + The fullstack web is here + + Greenwood is your workbench for the web, embracing web standards from the ground up to empower your stack from front to back. + + + View in Stackblitz + + + + Get Started + + + + $ npx @greenwood/init@latest + + + `; + } +} + +customElements.define("app-hero-banner", HeroBanner); diff --git a/src/components/hero-banner/hero-banner.module.css b/src/components/hero-banner/hero-banner.module.css new file mode 100644 index 00000000..f3abf1ab --- /dev/null +++ b/src/components/hero-banner/hero-banner.module.css @@ -0,0 +1,75 @@ +.container { + text-align: left; + margin: 0; + padding: var(--size-px-2); +} + +.heading, +.headingEmphasis { + font-size: var(--font-size-8); + font-weight: var(--font-weight-9); + margin-block-start: 0; + margin-block-end: 0; +} + +.headingEmphasis { + text-decoration: underline; +} + +.headingSub { + font-size: var(--font-size-3); + letter-spacing: var(--font-letterspacing-2); +} + +.buttonBlitz { + display: inline-block; + cursor: pointer; + border-radius: var(--radius-3); + background-color: transparent; + padding: var(--size-fluid-1); + min-width: var(--size-px-13); + color: var(--color-black); + box-shadow: var(--shadow-2); +} + +.buttonStarted { + display: inline-block; + cursor: pointer; + border-radius: var(--radius-3); + padding: var(--size-fluid-1); + background-color: var(--color-primary); + min-width: var(--size-px-13); + color: var(--color-white); + box-shadow: var(--shadow-4); + margin-top: var(--size-fluid-1); +} + +.linkStarted { + color: var(--color-white); + text-decoration: none; +} + +.snippet { + display: block; + width: fit-content; + border-radius: var(--radius-4); + padding: 0 2px; + border: var(--radius-1) solid var(--color-primary); + box-shadow: var(--shadow-4); + margin: 5px 0; +} + +@media (min-width: 768px) { + .snippet { + display: inline-block; + letter-spacing: var(--font-letterspacing-3); + padding: 0 var(--size-4); + margin: 10px 0; + } +} + +@media (min-width: 1440px) { + .container { + max-width: 80%; + } +} diff --git a/src/components/hero-banner/hero-banner.stories.js b/src/components/hero-banner/hero-banner.stories.js new file mode 100644 index 00000000..ec7c7167 --- /dev/null +++ b/src/components/hero-banner/hero-banner.stories.js @@ -0,0 +1,9 @@ +import "./hero-banner.js"; + +export default { + title: "Components/Hero Banner", +}; + +const Template = () => ""; + +export const Primary = Template.bind({}); diff --git a/src/components/latest-post/latest-post.js b/src/components/latest-post/latest-post.js new file mode 100644 index 00000000..d0c50102 --- /dev/null +++ b/src/components/latest-post/latest-post.js @@ -0,0 +1,17 @@ +import styles from "./latest-post.module.css"; + +export default class LatestPost extends HTMLElement { + connectedCallback() { + const link = this.getAttribute("link"); + const title = this.getAttribute("title"); + + this.innerHTML = ` + + 🎉 New + ${title} → + + `; + } +} + +customElements.define("app-latest-post", LatestPost); diff --git a/src/components/latest-post/latest-post.module.css b/src/components/latest-post/latest-post.module.css new file mode 100644 index 00000000..17df04e3 --- /dev/null +++ b/src/components/latest-post/latest-post.module.css @@ -0,0 +1,19 @@ +.pill { + display: inline-block; + border-radius: var(--radius-4); + padding: var(--size-fluid-1); + border: var(--radius-1) solid var(--color-gray-background); + box-shadow: var(--shadow-2); + text-align: left; +} + +.new { + background-color: #c3ddba; + border-radius: var(--radius-4); + padding: var(--size-2); + margin-right: var(--size-fluid-1); +} + +.link { + line-height: 50px; +} diff --git a/src/components/latest-post/latest-post.spec.js b/src/components/latest-post/latest-post.spec.js new file mode 100644 index 00000000..1ef843ae --- /dev/null +++ b/src/components/latest-post/latest-post.spec.js @@ -0,0 +1,51 @@ +import { expect } from "@esm-bundle/chai"; +import "./latest-post.js"; + +describe("Components/Latest Post", () => { + const LINK = "/test/"; + const TITLE = "test title"; + let latestPost; + + before(async () => { + latestPost = document.createElement("app-latest-post"); + + latestPost.setAttribute("link", LINK); + latestPost.setAttribute("title", TITLE); + + document.body.appendChild(latestPost); + + await latestPost.updateComplete; + }); + + describe("Default Behavior", () => { + it("should not be null", () => { + expect(latestPost).not.equal(undefined); + expect(latestPost.querySelectorAll("div").length).equal(1); + }); + + describe("Link tag", () => { + let link; + + before(async () => { + link = document.querySelector("a"); + }); + + it("should have the expected href value", () => { + expect(link.getAttribute("href")).to.equal(LINK); + }); + + it("should have the expected title attribute", () => { + expect(link.getAttribute("title")).to.equal("Read our latest post"); + }); + + it("should have the expected title text", () => { + expect(link.textContent).to.equal(`${TITLE} →`); + }); + }); + }); + + after(() => { + latestPost.remove(); + latestPost = null; + }); +}); diff --git a/src/components/latest-post/latest-post.stories.js b/src/components/latest-post/latest-post.stories.js new file mode 100644 index 00000000..9ee43bbc --- /dev/null +++ b/src/components/latest-post/latest-post.stories.js @@ -0,0 +1,14 @@ +import "./latest-post.js"; + +export default { + title: "Components/Latest Post", +}; + +const Template = () => ` + +`; + +export const Primary = Template.bind({}); diff --git a/src/components/run-anywhere/platforms.json b/src/components/run-anywhere/platforms.json new file mode 100644 index 00000000..fe3bbf5d --- /dev/null +++ b/src/components/run-anywhere/platforms.json @@ -0,0 +1,22 @@ +[ + { + "name": "Vercel", + "icon": "/assets/vercel.svg", + "link": "#" + }, + { + "name": "Netlify", + "icon": "/assets/netlify.png", + "link": "#" + }, + { + "name": "NodeJS", + "icon": "/assets/node.png", + "link": "#" + }, + { + "name": "GitHub", + "icon": "/assets/github.svg", + "link": "#" + } +] diff --git a/src/components/run-anywhere/run-anywhere.js b/src/components/run-anywhere/run-anywhere.js new file mode 100644 index 00000000..0c38bc9c --- /dev/null +++ b/src/components/run-anywhere/run-anywhere.js @@ -0,0 +1,36 @@ +import platforms from "./platforms.json" with { type: "json" }; +import styles from "./run-anywhere.module.css"; + +export default class RunAnywhere extends HTMLElement { + connectedCallback() { + this.innerHTML = ` + + Run anywhere the web can run + + Greenwood helps you take your application further by embracing platforms that embrace web standards. + + + + ${platforms + .map((platform) => { + const { name, icon, link } = platform; + + return ` + + + + + + ${name} + + `; + }) + .join("")} + + + + `; + } +} + +customElements.define("app-run-anywhere", RunAnywhere); diff --git a/src/components/run-anywhere/run-anywhere.module.css b/src/components/run-anywhere/run-anywhere.module.css new file mode 100644 index 00000000..6173254f --- /dev/null +++ b/src/components/run-anywhere/run-anywhere.module.css @@ -0,0 +1,67 @@ +.container { + border-left: 2px solid var(--color-gray); + border-right: 2px solid var(--color-gray); + margin: 0 auto; + text-align: center; +} + +.iconContainer { + margin: 0 auto; +} + +.heading { + font-size: var(--font-size-5); + font-weight: var(--font-weight-9); +} + +.subHeading { + text-align: center; + margin: 0px auto 30px; + padding: 20px; +} + +.iconBox { + border-radius: var(--radius-3); + box-shadow: var(--shadow-2); + background-color: var(--color-white); + width: 150px; + line-height: 150px; + margin: 0 auto; + display: inline-block; +} + +.icon { + width: 100px; + display: inline-block; + vertical-align: middle; + line-height: 100%; +} + +.iconLink { + display: inline-block; + margin: var(--size-px-2) 0 var(--size-px-4); + border-radius: var(--radius-3); + border: 1px solid #bababa; + background-color: var(--gray-background); + color: var(--color-black); + padding: 10px 20px; + text-decoration: none; + line-height: 100%; +} + +@media (min-width: 768px) { + .platformBox { + display: inline-block; + } + + .iconLink { + display: block; + margin: 0 var(--size-px-6); + } +} + +@media (min-width: 1024px) { + .subHeading { + max-width: 70%; + } +} diff --git a/src/components/run-anywhere/run-anywhere.stories.js b/src/components/run-anywhere/run-anywhere.stories.js new file mode 100644 index 00000000..87cf7e72 --- /dev/null +++ b/src/components/run-anywhere/run-anywhere.stories.js @@ -0,0 +1,9 @@ +import "./run-anywhere.js"; + +export default { + title: "Components/Run Anywhere", +}; + +const Template = () => ""; + +export const Primary = Template.bind({}); diff --git a/src/components/walkthrough/walkthrough.css b/src/components/walkthrough/walkthrough.css new file mode 100644 index 00000000..2f56290e --- /dev/null +++ b/src/components/walkthrough/walkthrough.css @@ -0,0 +1,127 @@ +:host .walkthrough { + padding: 50px; + border-radius: var(--radius-5); + color: var(--color-white); + background-color: var(--color-secondary); +} + +.walkthrough em, +.walkthrough strong { + font-size: var(--font-size-1); +} + +.cards { + overflow-x: auto; +} + +.card { + display: inline-block; + border-radius: var(--radius-5); + cursor: pointer; + margin: var(--font-size-1) 0; + padding: 10px 20px; +} + +.card:hover { + border: 2px dotted var(--color-accent); +} + +.card:hover strong, +.active strong { + color: var(--color-white); + font-weight: bold; +} + +.active { + background-color: var(--color-accent); + color: var(--color-black); +} + +.snippet pre { + border-radius: var(--radius-3); +} + +h2 { + font-size: var(--font-size-fluid-3); + font-weight: bold; + margin: 0; +} + +h3 { + color: var(--color-gray); +} + +h4 { + font-size: var(--font-size-fluid-1); + font-weight: bold; + margin: 5px 0; + display: inline-block; +} + +nav { + overflow: auto; + white-space: nowrap; + border-bottom: 1px solid var(--color-accent); + padding: 0px; + margin-bottom: 5px; +} + +ul { + list-style-type: none; + display: inline-block; + width: fit-content; + padding: 0; + margin: 0; +} + +p { + margin: 0; + padding: 10px; + text-align: left; + font-size: var(--font-size-1); + min-height: 100px; + border-radius: var(--radius-2); +} + +img { + display: inline-block; + vertical-align: middle; +} + +@media (max-width: 760px) { + code[class*="language-"], + pre[class*="language-"], + .token { + font-size: 12px; + } +} + +@media (min-width: 760px) { + :host .walkthrough { + padding: 50px 100px; + } + + .snippet pre { + border-radius: var(--radius-1); + } + + .card { + padding: 20px; + margin-right: 20px; + } + + .card:hover { + padding: 18px; + } + + nav { + padding-bottom: 10px; + margin-bottom: 10px; + } +} + +@media (min-width: 1400px) { + p { + width: 60%; + } +} diff --git a/src/components/walkthrough/walkthrough.js b/src/components/walkthrough/walkthrough.js new file mode 100644 index 00000000..6aeb4026 --- /dev/null +++ b/src/components/walkthrough/walkthrough.js @@ -0,0 +1,110 @@ +import sheet from "./walkthrough.css" with { type: "css" }; +import theme from "../../styles/theme.css" with { type: "css" }; + +const template = document.createElement("template"); + +export default class Walkthrough extends HTMLElement { + constructor() { + super(); + this.index = 0; + this.cards = []; + } + + connectedCallback() { + this.cards = globalThis.document?.querySelectorAll(".walkthrough-card") || []; + + if (this.cards.length > 0) { + template.innerHTML = ` + + Go from zero to fullstack with web standards + Lorum Ipsum... + + + + ${Array.from(this.cards) + .map((card, idx) => { + const title = card.querySelector("span").innerHTML; + const text = card.querySelector("p").innerHTML; + const icon = card.querySelector("i").textContent; + const isActiveClass = idx === this.index ? " active" : ""; + + return ` + + + + ${title} + + + `; + }) + .join("")} + + + + ${this.cards[this.index].querySelector("p").innerHTML} + ${this.cards[this.index].querySelector("pre").outerHTML} + + `; + + // TODO if going with the above option, rename cards related classes + // if (this.cards.length > 0) { + // template.innerHTML = ` + // + // Go from Zero to Fullstack with web standards + // Lorum Ipsum... + + // + // + // ${Array.from(this.cards) + // .map((card, idx) => { + // const title = card.querySelector("span").innerHTML; + // const text = card.querySelector("p").innerHTML; + // const icon = card.querySelector("i").textContent; + // const isActiveClass = idx === this.index ? " active" : ""; + + // return ` + // + // + // + // ${title} + // + // ${text} + // + // `; + // }) + // .join("")} + // + + // ${this.cards[this.index].querySelector("pre").outerHTML} + // + // + // `; + + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + this.shadowRoot.adoptedStyleSheets = [theme, sheet]; + this.shadowRoot + .querySelectorAll(".card") + .forEach((item) => item.addEventListener("click", this.selectItem.bind(this))); + } else { + console.debug("no walkthrough content cards detected"); + } + } + + selectItem(event) { + const cards = this.shadowRoot.querySelectorAll(".card"); + const index = (this.index = event.currentTarget.dataset.idx); + + this.shadowRoot.querySelector(".snippet").innerHTML = + this.cards[this.index].querySelector("pre").outerHTML; + + this.shadowRoot.querySelector("p").innerHTML = + this.cards[this.index].querySelector("p").innerHTML; + + cards.forEach((card) => { + card.dataset.idx === index ? card.classList.add("active") : card.classList.remove("active"); + }); + } +} + +customElements.define("app-walkthrough", Walkthrough); diff --git a/src/components/why-greenwood/why-greenwood.js b/src/components/why-greenwood/why-greenwood.js new file mode 100644 index 00000000..caecddab --- /dev/null +++ b/src/components/why-greenwood/why-greenwood.js @@ -0,0 +1,35 @@ +import styles from "./why-greenwood.module.css"; +import placeholderIcon from "../../assets/api-routes.svg?type=raw"; + +export default class WhyGreenwood extends HTMLElement { + connectedCallback() { + this.innerHTML = ` + + Why Greenwood? + Greenwood lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + + + + ${placeholderIcon} Something 1 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Link + + + + ${placeholderIcon} Something 2 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Link + + + + ${placeholderIcon} Something 3 + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + Link + + + + `; + } +} + +customElements.define("app-why-greenwood", WhyGreenwood); diff --git a/src/components/why-greenwood/why-greenwood.module.css b/src/components/why-greenwood/why-greenwood.module.css new file mode 100644 index 00000000..b795fe54 --- /dev/null +++ b/src/components/why-greenwood/why-greenwood.module.css @@ -0,0 +1,64 @@ +.container { + background-color: var(--color-gray); + border: var(--border-size-1) solid var(--color-black); + border-radius: var(--radius-5); + text-align: center; + margin: 0 auto; + padding: 20px 20px; +} + +.heading { + font-size: var(--font-size-5); + font-weight: var(--font-weight-9); +} + +.subHeading { + margin: 10px auto 30px; +} + +.cardContainer { + background-color: var(--color-white); + border-radius: var(--radius-5); +} + +.card { + display: inline-block; + text-align: left; + margin: 10px 10px 10px; + padding: 20px; + border-radius: var(--radius-5); + background-color: var(--color-gray); +} + +.card h3 { + padding: 20px; + border-radius: var(--radius-5); + background-color: var(--color-gray-background); + line-height: 50px; +} + +.card svg { + vertical-align: middle; +} + +.card a { + display: inline-block; + margin-left: 40px; + width: 100px; + padding: 10px 0; + text-align: center; + border-radius: var(--radius-5); + border: var(--border-size-1) solid var(--color-black); +} + +@media (min-width: 1024px) { + .card { + display: inline-block; + margin: 20px 10px 20px 20px; + width: 29%; + } + + .subHeading { + width: 60%; + } +} diff --git a/src/components/why-greenwood/why-greenwood.stories.js b/src/components/why-greenwood/why-greenwood.stories.js new file mode 100644 index 00000000..6662928f --- /dev/null +++ b/src/components/why-greenwood/why-greenwood.stories.js @@ -0,0 +1,9 @@ +import "./why-greenwood.js"; + +export default { + title: "Components/Why Greenwood", +}; + +const Template = () => ""; + +export const Primary = Template.bind({}); diff --git a/src/pages/index.md b/src/pages/index.md index 57cf31da..f1188986 100644 --- a/src/pages/index.md +++ b/src/pages/index.md @@ -1,14 +1,170 @@ --- imports: + - ../components/latest-post/latest-post.js data-gwd-opt="static" type="module" + - ../components/hero-banner/hero-banner.js data-gwd-opt="static" type="module" + - ../components/walkthrough/walkthrough.js type="module" + - ../components/why-greenwood/why-greenwood.js data-gwd-opt="static" type="module" + - ../components/run-anywhere/run-anywhere.js data-gwd-opt="static" type="module" + - ../components/build-with-friends/build-with-friends.js data-gwd-opt="static" type="module" + - ../components/get-started/get-started.js data-gwd-opt="static" type="module" - ../styles/home.css --- -# Welcome to Greenwood! + + + + + + + + HTML First + html.svg + Greenwood is HTML first by design. Start from just an index.html file or leverage hybrid, file-system based routing to easily achieve static and dynamic pages side-by-side. + +```html + + + + My Site + + + + Welcome to our site! + + Feel free to browse around or + contact us + if you have any questions. + + + +``` + + + + + Server Rendering + build-ssg.svg + Yay SSR! Lorum... ```js -return new Response("Hello World", { - headers: { - "Content-Type": "text/html", - }, -}); +// pages/products.js +import "../components/card.js"; +import { getProducts } from "../services/products.js"; + +export default class ProductsPage extends HTMLElement { + async connectedCallback() { + const products = await getProducts(); + const html = products + .map((product) => { + const { title, thumbnail } = product; + + return ` + + + `; + }) + .join(""); + + this.innerHTML = ` + Product Catalog + ${html} + `; + } +} ``` + + + + + Web Components + web-components.svg + Yay Web Components! Lorum... + +```js +// components/card.js +import sheet from "./card.js" with { type: "css" }; + +export default class Card extends HTMLElement { + connectedCallback() { + if (!this.shadowRoot) { + const thumbnail = this.getAttribute("thumbnail"); + const title = this.getAttribute("title"); + const template = document.createElement("template"); + + template.innerHTML = ` + + ${title} + + + `; + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(template.content.cloneNode(true)); + } + + this.shadowRoot.adoptedStyleSheets = [sheet]; + } +} + +customElements.define("app-card", Card); +``` + + + + + API Routes + api-routes.svg + Yay API Routes! Lorum... + +```js +// api/search.js +import { renderFromHTML } from "wc-compiler"; +import { getProducts } from "../services/products.js"; + +export async function handler(request) { + const formData = await request.formData(); + const searchTerm = formData.has("term") ? formData.get("term") : ""; + const products = await getProducts(searchTerm); + let body = "No results found."; + + if (products.length > 0) { + const { html } = await renderFromHTML( + ` + ${products + .map((item, idx) => { + const { title, thumbnail } = item; + + return ` + + `; + }) + .join("")} + `, + [new URL("../components/card.js", import.meta.url)], + ); + + body = html; + } + + return new Response(body, { + headers: new Headers({ + "Content-Type": "text/html", + }), + }); +} +``` + + + + + + + + + + diff --git a/src/styles/home.css b/src/styles/home.css index 2b330484..a857f5f1 100644 --- a/src/styles/home.css +++ b/src/styles/home.css @@ -1,9 +1,32 @@ -h1 { - text-align: center; +app-latest-post, +app-hero-banner, +app-walkthrough { + display: block; + margin: var(--size-fluid-1) auto; } -pre { - margin: 0 auto !important; - width: 30%; - overflow: scroll; +.walkthrough-card { + display: none; +} + +app-get-started { + display: block; + padding-bottom: 160px; +} + +app-get-started { + display: block; + margin-bottom: -300px; +} + +@media (min-width: 768px) { + app-hero-banner, + app-latest-post { + width: 70%; + } + + app-run-anywhere { + display: block; + margin: 0 auto; + } } diff --git a/src/styles/theme.css b/src/styles/theme.css index 2dd48507..2a9de343 100644 --- a/src/styles/theme.css +++ b/src/styles/theme.css @@ -15,7 +15,8 @@ format("truetype"); } -:root { +:root, +:host { --color-primary: #016341; --color-secondary: #0e0f0c; --color-tertiary: #151818; @@ -33,7 +34,7 @@ * { font-family: var(--font-primary); - font-size: var(--size-px-3); + font-size: var(--font-size-3); box-sizing: border-box; }
Greenwood and Web Components work great with all of your favorite tools in the web ecosystem.
$ npx @greenwood/init@latest
!!! ${data.message} !!!
Greenwood is your workbench for the web, embracing web standards from the ground up to empower your stack from front to back.
Greenwood helps you take your application further by embracing platforms that embrace web standards.
${this.cards[this.index].querySelector("p").innerHTML}
${text}
Greenwood lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Greenwood is HTML first by design. Start from just an index.html file or leverage hybrid, file-system based routing to easily achieve static and dynamic pages side-by-side.
+ Feel free to browse around or + contact us + if you have any questions. +
Yay SSR! Lorum...
Yay Web Components! Lorum...
Yay API Routes! Lorum...