From 40d0e732b0a312899b598c77cded073011a5538e Mon Sep 17 00:00:00 2001 From: liv Date: Mon, 12 Jun 2023 15:23:21 +0200 Subject: [PATCH] feat: add funding page (#358) Co-authored-by: Sara Vieira --- .gitignore | 4 +- Cargo.lock | 24 +- Cargo.toml | 3 +- docs/src/SUMMARY.md | 1 + docs/src/configuration.md | 8 + oranda-css/css/components.css | 42 +++ oranda-css/css/themes/cupcake.css | 10 + oranda-css/css/themes/hacker.css | 8 + oranda-css/yarn.lock | 385 ++++++++++++++++---------- src/commands/dev.rs | 6 + src/config/mod.rs | 18 +- src/config/oranda_config.rs | 14 + src/data/funding.rs | 71 +++++ src/data/github/repo.rs | 5 + src/data/mod.rs | 2 + src/errors.rs | 14 + src/site/funding/icons.rs | 41 +++ src/site/funding/mod.rs | 155 +++++++++++ src/site/layout/header.rs | 14 +- src/site/mod.rs | 50 ++-- tests/build/fixtures/oranda_config.rs | 1 + 21 files changed, 705 insertions(+), 171 deletions(-) create mode 100644 src/data/funding.rs create mode 100644 src/site/funding/icons.rs create mode 100644 src/site/funding/mod.rs diff --git a/.gitignore b/.gitignore index 771d1283..d53fea87 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,13 @@ public/ oranda-debug.log # banish macos to the depths of hell .DS_Store -# banish jetbrains as well .idea/ # oranda-css oranda-css/dist +oranda-css/.yarn +# weirdo yarn feature that dumps files everywhere +oranda-css/.pnp* node_modules # nix diff --git a/Cargo.lock b/Cargo.lock index e2d1b294..5cf83172 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bincode" @@ -2141,6 +2141,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "serde_yaml", "syntect", "thiserror", "tokio", @@ -2815,6 +2816,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha2" version = "0.10.6" @@ -3546,6 +3560,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" + [[package]] name = "url" version = "2.3.1" diff --git a/Cargo.toml b/Cargo.toml index e38cdeb2..38bbe292 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ octolotl = "0.1.0" reqwest = { version = "0.11.13", features = ["blocking", "json"] } serde = { version = "1.0.144", features = ["derive"] } serde_json = { version = "1.0.85" } +serde_yaml = "0.9.21" syntect = "5.0" thiserror = "1.0.37" tokio = { version = "1.20.1", features = ["full"] } @@ -73,4 +74,4 @@ windows-archive = ".tar.gz" # The archive format to use for non-windows builds (defaults .tar.xz) unix-archive = ".tar.gz" # A namespace to use when publishing this package to the npm registry -npm-scope = "@axodotdev" +npm-scope = "@axodotdev" \ No newline at end of file diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 4a1ab70b..993763d2 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -17,3 +17,4 @@ - [`mdbook` support](./configuration/mdbook.md) - [Social](./configuration/social.md) - [Theming](./configuration/theme.md) + - [Funding](./configuration/funding.md) diff --git a/docs/src/configuration.md b/docs/src/configuration.md index ae6a0ef5..74c9245a 100644 --- a/docs/src/configuration.md +++ b/docs/src/configuration.md @@ -23,6 +23,7 @@ - [mdbook or md\_book](#mdbook-or-md_book) - [changelog](#changelog) - [styles](#styles) + - [funding](#funding) `oranda` is designed to work with no configuration- for projects with a @@ -170,3 +171,10 @@ Enable changelog generation. [More information](./configuration/changelog.md) ### styles [Configuration for custom styles or themes.](./configuration/theme.md) + +### funding + +> Added in __0.1.0__. + +Allows you to tweak or disable oranda's funding page. +[Read more here.](./configuration/funding.md) \ No newline at end of file diff --git a/oranda-css/css/components.css b/oranda-css/css/components.css index 90d9d9e5..565cb697 100644 --- a/oranda-css/css/components.css +++ b/oranda-css/css/components.css @@ -27,3 +27,45 @@ footer { .repo_banner > a { @apply flex justify-center gap-2 items-start hover:text-slate-50 text-slate-50 dark:text-axo-black dark:hover:text-axo-black h-[20px] hover:underline hover:underline-offset-1 dark:hover:decoration-axo-black hover:decoration-slate-50; } + +/* FUNDING */ + +.funding-wrapper { + @apply mt-8 flex flex-col items-center; +} + +.funding-list { + @apply my-12 w-full lg:grid grid-cols-2 gap-4; +} + +.funding-list li { + @apply m-0 mb-4; +} + +.funding-list li a { + @apply flex gap-2 items-center; +} + +.funding-list li a:hover button { + @apply text-slate-100 bg-axo-orange-dark border-axo-orange-dark; +} + +.funding-list .button { + @apply block w-auto group-hover:bg-green-500 mr-2; +} + +.preferred-funding-list { + @apply grid-cols-1; +} + +.preferred-funding-list li a { + @apply flex-col text-4xl; +} + +.preferred-funding-list svg { + @apply w-12 h-12; +} + +.preferred-funding-list .button { + @apply border-0; +} \ No newline at end of file diff --git a/oranda-css/css/themes/cupcake.css b/oranda-css/css/themes/cupcake.css index 6099eb4a..4aaf44ac 100644 --- a/oranda-css/css/themes/cupcake.css +++ b/oranda-css/css/themes/cupcake.css @@ -31,6 +31,16 @@ html.cupcake .button.primary:hover { background: var(--secondary-100); } +html.cupcake .button.secondary { + border: 1px solid var(--secondary); + color: var(--secondary-100); +} + +html.cupcake .button.secondary:hover { + background: var(--secondary); + color: var(--b2); +} + html.cupcake h1, html.cupcake h2, html.cupcake h3, diff --git a/oranda-css/css/themes/hacker.css b/oranda-css/css/themes/hacker.css index ab0feac8..485113b3 100644 --- a/oranda-css/css/themes/hacker.css +++ b/oranda-css/css/themes/hacker.css @@ -13,6 +13,10 @@ html.hacker body { --hacker-green: #20c20e; } +html.hacker .button.secondary { + @apply text-slate-300 border-orange-500 hover:bg-orange-500 hover:text-axo-black; +} + html.hacker h2, html.hacker h3, html.hacker h4, @@ -104,3 +108,7 @@ html.hacker .prereleases-toggle input:checked { html.hacker .releases-nav ul li a { @apply hover:decoration-orange-500; } + +html.hacker .funding-wrapper { + @apply items-start; +} diff --git a/oranda-css/yarn.lock b/oranda-css/yarn.lock index b676cf16..a5359395 100644 --- a/oranda-css/yarn.lock +++ b/oranda-css/yarn.lock @@ -5,6 +5,13 @@ __metadata: version: 6 cacheKey: 8 +"@alloc/quick-lru@npm:^5.2.0": + version: 5.2.0 + resolution: "@alloc/quick-lru@npm:5.2.0" + checksum: bdc35758b552bcf045733ac047fb7f9a07c4678b944c641adfbd41f798b4b91fffd0fdc0df2578d9b0afc7b4d636aa6e110ead5d6281a2adc1ab90efd7f057f8 + languageName: node + linkType: hard + "@gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" @@ -12,6 +19,55 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.2": + version: 0.3.3 + resolution: "@jridgewell/gen-mapping@npm:0.3.3" + dependencies: + "@jridgewell/set-array": ^1.0.1 + "@jridgewell/sourcemap-codec": ^1.4.10 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:3.1.0": + version: 3.1.0 + resolution: "@jridgewell/resolve-uri@npm:3.1.0" + checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.0.1": + version: 1.1.2 + resolution: "@jridgewell/set-array@npm:1.1.2" + checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:1.4.14": + version: 1.4.14 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" + checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.18 + resolution: "@jridgewell/trace-mapping@npm:0.3.18" + dependencies: + "@jridgewell/resolve-uri": 3.1.0 + "@jridgewell/sourcemap-codec": 1.4.14 + checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -71,11 +127,11 @@ __metadata: linkType: hard "@tailwindcss/line-clamp@npm:^0.4.2": - version: 0.4.2 - resolution: "@tailwindcss/line-clamp@npm:0.4.2" + version: 0.4.4 + resolution: "@tailwindcss/line-clamp@npm:0.4.4" peerDependencies: tailwindcss: ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" - checksum: 26b8135df24fff51c3d3790ae795bdc12bc4a7113fa22dcab80568ae6ee00710e2ed4154048958c472bb654061f0f1573b7ac5e004ae6222cbd5ac6fcf199478 + checksum: 3d2ad992aa9263fe9b5cdb23bcfca521a6ab00f65e0f7167be35d2cb46b1635af72889ff9f6d5b2febf5aa5a36e3128eaad8ed43e43af4512c74c74f1058c4c0 languageName: node linkType: hard @@ -107,33 +163,6 @@ __metadata: languageName: node linkType: hard -"acorn-node@npm:^1.8.2": - version: 1.8.2 - resolution: "acorn-node@npm:1.8.2" - dependencies: - acorn: ^7.0.0 - acorn-walk: ^7.0.0 - xtend: ^4.0.2 - checksum: 02e1564a1ccf8bd1fcefcd01235398af4a9effaf032c5397994ddd275590a72894cb3e26e4b82579ccdda1e48ade7486aef61e771ddae3563ca452b927f443d8 - languageName: node - linkType: hard - -"acorn-walk@npm:^7.0.0": - version: 7.2.0 - resolution: "acorn-walk@npm:7.2.0" - checksum: 9252158a79b9d92f1bc0dd6acc0fcfb87a67339e84bcc301bb33d6078936d27e35d606b4d35626d2962cd43c256d6f27717e70cbe15c04fff999ab0b2260b21f - languageName: node - linkType: hard - -"acorn@npm:^7.0.0": - version: 7.4.1 - resolution: "acorn@npm:7.4.1" - bin: - acorn: bin/acorn - checksum: 1860f23c2107c910c6177b7b7be71be350db9e1080d814493fae143ae37605189504152d1ba8743ba3178d0b37269ce1ffc42b101547fdc1827078f82671e407 - languageName: node - linkType: hard - "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -171,6 +200,13 @@ __metadata: languageName: node linkType: hard +"any-promise@npm:^1.0.0": + version: 1.3.0 + resolution: "any-promise@npm:1.3.0" + checksum: 0ee8a9bdbe882c90464d75d1f55cf027f5458650c4bd1f0467e65aec38ccccda07ca5844969ee77ed46d04e7dded3eaceb027e8d32f385688523fe305fa7e1de + languageName: node + linkType: hard + "anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -313,13 +349,6 @@ __metadata: languageName: node linkType: hard -"color-name@npm:^1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - "color-support@npm:^1.1.3": version: 1.1.3 resolution: "color-support@npm:1.1.3" @@ -329,6 +358,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^4.0.0": + version: 4.1.1 + resolution: "commander@npm:4.1.1" + checksum: d7b9913ff92cae20cb577a4ac6fcc121bd6223319e54a40f51a14740a681ad5c574fd29a57da478a5f234a6fa6c52cbf0b7c641353e03c648b1ae85ba670b977 + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -364,13 +400,6 @@ __metadata: languageName: node linkType: hard -"defined@npm:^1.0.0": - version: 1.0.1 - resolution: "defined@npm:1.0.1" - checksum: b1a852300bdb57f297289b55eafdd0c517afaa3ec8190e78fce91b9d8d0c0369d4505ecbdacfd3d98372e664f4a267d9bd793938d4a8c76209c9d9516fbe2101 - languageName: node - linkType: hard - "delegates@npm:^1.0.0": version: 1.0.0 resolution: "delegates@npm:1.0.0" @@ -385,19 +414,6 @@ __metadata: languageName: node linkType: hard -"detective@npm:^5.2.1": - version: 5.2.1 - resolution: "detective@npm:5.2.1" - dependencies: - acorn-node: ^1.8.2 - defined: ^1.0.0 - minimist: ^1.2.6 - bin: - detective: bin/detective.js - checksum: dc4601bbc6be850edb3c2dab7a0eaf5a6169a15ad201679c66d40ea1986df816eeaecd590047f15b0780285f3eeea13b82dca0d4c52a47e744a571e326a72dc9 - languageName: node - linkType: hard - "didyoumean@npm:^1.2.2": version: 1.2.2 resolution: "didyoumean@npm:1.2.2" @@ -549,6 +565,20 @@ __metadata: languageName: node linkType: hard +"glob@npm:7.1.6": + version: 7.1.6 + resolution: "glob@npm:7.1.6" + dependencies: + fs.realpath: ^1.0.0 + inflight: ^1.0.4 + inherits: 2 + minimatch: ^3.0.4 + once: ^1.3.0 + path-is-absolute: ^1.0.0 + checksum: 351d549dd90553b87c2d3f90ce11aed9e1093c74130440e7ae0592e11bbcd2ce7f0ebb8ba6bfe63aaf9b62166a7f4c80cb84490ae5d78408bb2572bf7d4ee0a6 + languageName: node + linkType: hard + "glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.2.3 resolution: "glob@npm:7.2.3" @@ -699,12 +729,12 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.9.0": - version: 2.11.0 - resolution: "is-core-module@npm:2.11.0" +"is-core-module@npm:^2.11.0": + version: 2.12.1 + resolution: "is-core-module@npm:2.12.1" dependencies: has: ^1.0.3 - checksum: f96fd490c6b48eb4f6d10ba815c6ef13f410b0ba6f7eb8577af51697de523e5f2cd9de1c441b51d27251bf0e4aebc936545e33a5d26d5d51f28d25698d4a8bab + checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 languageName: node linkType: hard @@ -752,13 +782,29 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:^2.0.5, lilconfig@npm:^2.0.6": +"jiti@npm:^1.18.2": + version: 1.18.2 + resolution: "jiti@npm:1.18.2" + bin: + jiti: bin/jiti.js + checksum: 46c41cd82d01c6efdee3fc0ae9b3e86ed37457192d6366f19157d863d64961b07982ab04e9d5879576a1af99cc4d132b0b73b336094f86a5ce9fb1029ec2d29f + languageName: node + linkType: hard + +"lilconfig@npm:^2.0.5, lilconfig@npm:^2.1.0": version: 2.1.0 resolution: "lilconfig@npm:2.1.0" checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 languageName: node linkType: hard +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 + languageName: node + linkType: hard + "lodash.castarray@npm:^4.4.0": version: 4.4.0 resolution: "lodash.castarray@npm:4.4.0" @@ -846,7 +892,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.1.1": +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -864,13 +910,6 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 - languageName: node - linkType: hard - "minipass-collect@npm:^1.0.2": version: 1.0.2 resolution: "minipass-collect@npm:1.0.2" @@ -971,12 +1010,23 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.4": - version: 3.3.4 - resolution: "nanoid@npm:3.3.4" +"mz@npm:^2.7.0": + version: 2.7.0 + resolution: "mz@npm:2.7.0" + dependencies: + any-promise: ^1.0.0 + object-assign: ^4.0.1 + thenify-all: ^1.0.0 + checksum: 8427de0ece99a07e9faed3c0c6778820d7543e3776f9a84d22cf0ec0a8eb65f6e9aee9c9d353ff9a105ff62d33a9463c6ca638974cc652ee8140cd1e35951c87 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.6": + version: 3.3.6 + resolution: "nanoid@npm:3.3.6" bin: nanoid: bin/nanoid.cjs - checksum: 2fddd6dee994b7676f008d3ffa4ab16035a754f4bb586c61df5a22cf8c8c94017aadd360368f47d653829e0569a92b129979152ff97af23a558331e47e37cd9c + checksum: 7d0eda657002738aa5206107bd0580aead6c95c460ef1bdd0b1a87a9c7ae6277ac2e9b945306aaa5b32c6dcb7feaf462d0f552e7f8b5718abfc6ead5c94a71b3 languageName: node linkType: hard @@ -1037,6 +1087,13 @@ __metadata: languageName: node linkType: hard +"object-assign@npm:^4.0.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f + languageName: node + linkType: hard + "object-hash@npm:^3.0.0": version: 3.0.0 resolution: "object-hash@npm:3.0.0" @@ -1108,20 +1165,27 @@ __metadata: languageName: node linkType: hard -"postcss-import@npm:^14.1.0": - version: 14.1.0 - resolution: "postcss-import@npm:14.1.0" +"pirates@npm:^4.0.1": + version: 4.0.5 + resolution: "pirates@npm:4.0.5" + checksum: c9994e61b85260bec6c4fc0307016340d9b0c4f4b6550a957afaaff0c9b1ad58fbbea5cfcf083860a25cb27a375442e2b0edf52e2e1e40e69934e08dcc52d227 + languageName: node + linkType: hard + +"postcss-import@npm:^15.1.0": + version: 15.1.0 + resolution: "postcss-import@npm:15.1.0" dependencies: postcss-value-parser: ^4.0.0 read-cache: ^1.0.0 resolve: ^1.1.7 peerDependencies: postcss: ^8.0.0 - checksum: cd45d406e90f67cdab9524352e573cc6b4462b790934a05954e929a6653ebd31288ceebc8ce3c3ed7117ae672d9ebbec57df0bceec0a56e9b259c2e71d47ca86 + checksum: 7bd04bd8f0235429009d0022cbf00faebc885de1d017f6d12ccb1b021265882efc9302006ba700af6cab24c46bfa2f3bc590be3f9aee89d064944f171b04e2a3 languageName: node linkType: hard -"postcss-js@npm:^4.0.0": +"postcss-js@npm:^4.0.1": version: 4.0.1 resolution: "postcss-js@npm:4.0.1" dependencies: @@ -1132,12 +1196,12 @@ __metadata: languageName: node linkType: hard -"postcss-load-config@npm:^3.1.4": - version: 3.1.4 - resolution: "postcss-load-config@npm:3.1.4" +"postcss-load-config@npm:^4.0.1": + version: 4.0.1 + resolution: "postcss-load-config@npm:4.0.1" dependencies: lilconfig: ^2.0.5 - yaml: ^1.10.2 + yaml: ^2.1.1 peerDependencies: postcss: ">=8.0.9" ts-node: ">=9.0.0" @@ -1146,22 +1210,22 @@ __metadata: optional: true ts-node: optional: true - checksum: 1c589504c2d90b1568aecae8238ab993c17dba2c44f848a8f13619ba556d26a1c09644d5e6361b5784e721e94af37b604992f9f3dc0483e687a0cc1cc5029a34 + checksum: b61f890499ed7dcda1e36c20a9582b17d745bad5e2b2c7bc96942465e406bc43ae03f270c08e60d1e29dab1ee50cb26970b5eb20c9aae30e066e20bd607ae4e4 languageName: node linkType: hard -"postcss-nested@npm:6.0.0": - version: 6.0.0 - resolution: "postcss-nested@npm:6.0.0" +"postcss-nested@npm:^6.0.1": + version: 6.0.1 + resolution: "postcss-nested@npm:6.0.1" dependencies: - postcss-selector-parser: ^6.0.10 + postcss-selector-parser: ^6.0.11 peerDependencies: postcss: ^8.2.14 - checksum: 2105dc52cd19747058f1a46862c9e454b5a365ac2e7135fc1015d67a8fe98ada2a8d9ee578e90f7a093bd55d3994dd913ba5ff1d5e945b4ed9a8a2992ecc8f10 + checksum: 7ddb0364cd797de01e38f644879189e0caeb7ea3f78628c933d91cc24f327c56d31269384454fc02ecaf503b44bfa8e08870a7c4cc56b23bc15640e1894523fa languageName: node linkType: hard -"postcss-selector-parser@npm:6.0.10, postcss-selector-parser@npm:^6.0.10": +"postcss-selector-parser@npm:6.0.10": version: 6.0.10 resolution: "postcss-selector-parser@npm:6.0.10" dependencies: @@ -1172,12 +1236,12 @@ __metadata: linkType: hard "postcss-selector-parser@npm:^6.0.11": - version: 6.0.11 - resolution: "postcss-selector-parser@npm:6.0.11" + version: 6.0.13 + resolution: "postcss-selector-parser@npm:6.0.13" dependencies: cssesc: ^3.0.0 util-deprecate: ^1.0.2 - checksum: 0b01aa9c2d2c8dbeb51e9b204796b678284be9823abc8d6d40a8b16d4149514e922c264a8ed4deb4d6dbced564b9be390f5942c058582d8656351516d6c49cde + checksum: f89163338a1ce3b8ece8e9055cd5a3165e79a15e1c408e18de5ad8f87796b61ec2d48a2902d179ae0c4b5de10fccd3a325a4e660596549b040bc5ad1b465f096 languageName: node linkType: hard @@ -1188,14 +1252,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.0.9": - version: 8.4.21 - resolution: "postcss@npm:8.4.21" +"postcss@npm:^8.4.23": + version: 8.4.24 + resolution: "postcss@npm:8.4.24" dependencies: - nanoid: ^3.3.4 + nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: e39ac60ccd1542d4f9d93d894048aac0d686b3bb38e927d8386005718e6793dbbb46930f0a523fe382f1bbd843c6d980aaea791252bf5e176180e5a4336d9679 + checksum: 814e2126dacfea313588eda09cc99a9b4c26ec55c059188aa7a916d20d26d483483106dc5ff9e560731b59f45c5bb91b945dfadc670aed875cc90ddbbf4e787d languageName: node linkType: hard @@ -1223,13 +1287,6 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^5.1.1": - version: 5.1.1 - resolution: "quick-lru@npm:5.1.1" - checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed - languageName: node - linkType: hard - "read-cache@npm:^1.0.0": version: 1.0.0 resolution: "read-cache@npm:1.0.0" @@ -1259,29 +1316,29 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.7, resolve@npm:^1.22.1": - version: 1.22.1 - resolution: "resolve@npm:1.22.1" +"resolve@npm:^1.1.7, resolve@npm:^1.22.2": + version: 1.22.2 + resolution: "resolve@npm:1.22.2" dependencies: - is-core-module: ^2.9.0 + is-core-module: ^2.11.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e + checksum: 7e5df75796ebd429445d102d5824482ee7e567f0070b2b45897b29bb4f613dcbc262e0257b8aeedb3089330ccaea0d6a0464df1a77b2992cf331dcda0f4cb549 languageName: node linkType: hard -"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.22.1#~builtin": - version: 1.22.1 - resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d" +"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.22.2#~builtin": + version: 1.22.2 + resolution: "resolve@patch:resolve@npm%3A1.22.2#~builtin::version=1.22.2&hash=c3c19d" dependencies: - is-core-module: ^2.9.0 + is-core-module: ^2.11.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b + checksum: 66cc788f13b8398de18eb4abb3aed90435c84bb8935953feafcf7231ba4cd191b2c10b4a87b1e9681afc34fb138c705f91f7330ff90bfa36f457e5584076a2b8 languageName: node linkType: hard @@ -1334,13 +1391,13 @@ __metadata: linkType: hard "semver@npm:^7.3.5": - version: 7.5.0 - resolution: "semver@npm:7.5.0" + version: 7.5.1 + resolution: "semver@npm:7.5.1" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b + checksum: d16dbedad53c65b086f79524b9ef766bf38670b2395bdad5c957f824dcc566b624988013564f4812bcace3f9d405355c3635e2007396a39d1bffc71cfec4a2fc languageName: node linkType: hard @@ -1431,6 +1488,24 @@ __metadata: languageName: node linkType: hard +"sucrase@npm:^3.32.0": + version: 3.32.0 + resolution: "sucrase@npm:3.32.0" + dependencies: + "@jridgewell/gen-mapping": ^0.3.2 + commander: ^4.0.0 + glob: 7.1.6 + lines-and-columns: ^1.1.6 + mz: ^2.7.0 + pirates: ^4.0.1 + ts-interface-checker: ^0.1.9 + bin: + sucrase: bin/sucrase + sucrase-node: bin/sucrase-node + checksum: 79f760aef513adcf22b882d43100296a8afa7f307acef3e8803304b763484cf138a3e2cebc498a6791110ab20c7b8deba097f6ce82f812ca8f1723e3440e5c95 + languageName: node + linkType: hard + "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" @@ -1439,44 +1514,42 @@ __metadata: linkType: hard "tailwindcss@npm:^3.2.7": - version: 3.2.7 - resolution: "tailwindcss@npm:3.2.7" + version: 3.3.2 + resolution: "tailwindcss@npm:3.3.2" dependencies: + "@alloc/quick-lru": ^5.2.0 arg: ^5.0.2 chokidar: ^3.5.3 - color-name: ^1.1.4 - detective: ^5.2.1 didyoumean: ^1.2.2 dlv: ^1.1.3 fast-glob: ^3.2.12 glob-parent: ^6.0.2 is-glob: ^4.0.3 - lilconfig: ^2.0.6 + jiti: ^1.18.2 + lilconfig: ^2.1.0 micromatch: ^4.0.5 normalize-path: ^3.0.0 object-hash: ^3.0.0 picocolors: ^1.0.0 - postcss: ^8.0.9 - postcss-import: ^14.1.0 - postcss-js: ^4.0.0 - postcss-load-config: ^3.1.4 - postcss-nested: 6.0.0 + postcss: ^8.4.23 + postcss-import: ^15.1.0 + postcss-js: ^4.0.1 + postcss-load-config: ^4.0.1 + postcss-nested: ^6.0.1 postcss-selector-parser: ^6.0.11 postcss-value-parser: ^4.2.0 - quick-lru: ^5.1.1 - resolve: ^1.22.1 - peerDependencies: - postcss: ^8.0.9 + resolve: ^1.22.2 + sucrase: ^3.32.0 bin: tailwind: lib/cli.js tailwindcss: lib/cli.js - checksum: 819446bf67acea1fc738f345d80f328b7bb6e6ef4b24070249a11219307045881cf97baed6258cbdcede7fa18886e9c9c41fd0fa087b3e987cf2948560a2f164 + checksum: 4897c70e671c885e151f57434d87ccb806f468a11900f028245b351ffbca5245ff0c10ca5dbb6eb4c7c4df3de8a15a05fe08c2aea4b152cb07bee9bb1d8a14a8 languageName: node linkType: hard "tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.14 - resolution: "tar@npm:6.1.14" + version: 6.1.15 + resolution: "tar@npm:6.1.15" dependencies: chownr: ^2.0.0 fs-minipass: ^2.0.0 @@ -1484,7 +1557,25 @@ __metadata: minizlib: ^2.1.1 mkdirp: ^1.0.3 yallist: ^4.0.0 - checksum: a1be0815a9bdc97dfca7c6c2d71d1b836f8ba9314684e2c412832f0f59cc226d4c13da303d6bc30925e82f634cc793f40da79ae72f3e96fb87c23d0f4efd5207 + checksum: f23832fceeba7578bf31907aac744ae21e74a66f4a17a9e94507acf460e48f6db598c7023882db33bab75b80e027c21f276d405e4a0322d58f51c7088d428268 + languageName: node + linkType: hard + +"thenify-all@npm:^1.0.0": + version: 1.6.0 + resolution: "thenify-all@npm:1.6.0" + dependencies: + thenify: ">= 3.1.0 < 4" + checksum: dba7cc8a23a154cdcb6acb7f51d61511c37a6b077ec5ab5da6e8b874272015937788402fd271fdfc5f187f8cb0948e38d0a42dcc89d554d731652ab458f5343e + languageName: node + linkType: hard + +"thenify@npm:>= 3.1.0 < 4": + version: 3.3.1 + resolution: "thenify@npm:3.3.1" + dependencies: + any-promise: ^1.0.0 + checksum: 84e1b804bfec49f3531215f17b4a6e50fd4397b5f7c1bccc427b9c656e1ecfb13ea79d899930184f78bc2f57285c54d9a50a590c8868f4f0cef5c1d9f898b05e languageName: node linkType: hard @@ -1497,6 +1588,13 @@ __metadata: languageName: node linkType: hard +"ts-interface-checker@npm:^0.1.9": + version: 0.1.13 + resolution: "ts-interface-checker@npm:0.1.13" + checksum: 20c29189c2dd6067a8775e07823ddf8d59a33e2ffc47a1bd59a5cb28bb0121a2969a816d5e77eda2ed85b18171aa5d1c4005a6b88ae8499ec7cc49f78571cb5e + languageName: node + linkType: hard + "unique-filename@npm:^2.0.0": version: 2.0.1 resolution: "unique-filename@npm:2.0.1" @@ -1549,13 +1647,6 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.2": - version: 4.0.2 - resolution: "xtend@npm:4.0.2" - checksum: ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a - languageName: node - linkType: hard - "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -1563,9 +1654,9 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.2": - version: 1.10.2 - resolution: "yaml@npm:1.10.2" - checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f +"yaml@npm:^2.1.1": + version: 2.3.1 + resolution: "yaml@npm:2.3.1" + checksum: 2c7bc9a7cd4c9f40d3b0b0a98e370781b68b8b7c4515720869aced2b00d92f5da1762b4ffa947f9e795d6cd6b19f410bd4d15fdd38aca7bd96df59bd9486fb54 languageName: node linkType: hard diff --git a/src/commands/dev.rs b/src/commands/dev.rs index 8d837596..012c15c0 100644 --- a/src/commands/dev.rs +++ b/src/commands/dev.rs @@ -72,6 +72,12 @@ impl Dev { paths_to_watch.append(&mut include_paths); } + // Watch for the funding.md page and the funding.yml file + if config.funding.is_some() { + paths_to_watch.push("funding.md".into()); + paths_to_watch.push(".github/FUNDING.yml".into()); + } + // Watch for additional pages, if we have any if config.additional_pages.is_some() { let mut additional_pages: Vec = diff --git a/src/config/mod.rs b/src/config/mod.rs index 95d9121c..89669f08 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -4,7 +4,7 @@ pub mod project; pub mod theme; use artifacts::Artifacts; -pub use oranda_config::{MdBookConfig, StyleConfig}; +pub use oranda_config::{FundingConfig, MdBookConfig, StyleConfig}; pub mod analytics; use crate::errors::*; use analytics::Analytics; @@ -38,6 +38,7 @@ pub struct Config { pub mdbook: Option, pub styles: StyleConfig, pub changelog: bool, + pub funding: Option, } impl Config { @@ -68,6 +69,7 @@ impl Config { cfg.apply_project_layer(project); cfg.apply_custom_layer(custom); cfg.find_mdbook(); + cfg.find_funding(); Ok(cfg) } @@ -109,6 +111,7 @@ impl Config { self.path_prefix.apply_opt(custom.path_prefix); self.changelog.apply_val(custom.changelog); self.mdbook.apply_bool_layer(custom.mdbook); + self.funding.apply_bool_layer(custom.funding); } } @@ -133,6 +136,18 @@ impl Config { } } } + + /// If we have a FUNDING.yml file, try to find it. If we fail, we disable funding support. + fn find_funding(&mut self) { + // Try and find the actual FUNDING.yml file first. + let funding_path = Utf8PathBuf::from(".github/FUNDING.yml"); + // We also want to enable funding if there's a funding.md file in the root, so check + // for that too. + let funding_doc_path = Utf8PathBuf::from("funding.md"); + if !funding_path.exists() && !funding_doc_path.exists() { + self.funding = None; + } + } } impl Default for Config { @@ -159,6 +174,7 @@ impl Default for Config { // Later stages can disable mdbook support by setting this to None mdbook: Some(MdBookConfig::default()), changelog: false, + funding: Some(FundingConfig::default()), } } } diff --git a/src/config/oranda_config.rs b/src/config/oranda_config.rs index fca7d1b6..53a53ef9 100644 --- a/src/config/oranda_config.rs +++ b/src/config/oranda_config.rs @@ -11,6 +11,7 @@ use crate::message::{Message, MessageType}; use crate::site::markdown::SyntaxTheme; use crate::config::artifacts::Artifacts; +use crate::data::funding::FundingType; use super::{ApplyLayer, ApplyOptExt}; @@ -76,6 +77,18 @@ impl StyleConfig { } } +/// Config for displaying funding information on your page +#[derive(Debug, Default, Deserialize)] +pub struct FundingConfig { + pub preferred_funding: Option, +} + +impl ApplyLayer for FundingConfig { + fn apply_layer(&mut self, layer: Self) { + self.preferred_funding.apply_opt(layer.preferred_funding); + } +} + #[derive(Debug, Deserialize)] pub struct OrandaConfig { pub description: Option, @@ -103,6 +116,7 @@ pub struct OrandaConfig { pub mdbook: Option>, pub changelog: Option, pub styles: Option, + pub funding: Option>, } impl OrandaConfig { diff --git a/src/data/funding.rs b/src/data/funding.rs new file mode 100644 index 00000000..425be377 --- /dev/null +++ b/src/data/funding.rs @@ -0,0 +1,71 @@ +use crate::config::Config; +use crate::errors::{OrandaError, Result}; +use crate::site::markdown::to_html; +use axoasset::LocalAsset; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +/// Funding data-struct. +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +pub struct Funding { + /// Contents of the FUNDING.yml file. + pub content: HashMap, + /// Content read from the optional Markdown file + pub docs_content: Option, +} + +/// An enumeration of different supported funding providers. Represents the "key" portion of a +/// funding.yml entry. +#[derive(Serialize, Deserialize, Clone, Debug, PartialOrd, PartialEq, Eq, Hash)] +#[serde(rename_all = "snake_case")] +pub enum FundingType { + Github, + Patreon, + OpenCollective, + KoFi, + Tidelift, + CommunityBridge, + Issuehunt, + Liberapay, + Custom, +} + +/// An enum expressing the different types of values that an entry in FUNDING.yml can have. +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(untagged)] +pub enum FundingContent { + One(String), + Multiple(Vec), +} + +impl Funding { + /// Creates a new Funding struct by attempting to read from the FUNDING.yml, and the docs file. + pub fn new(config: &Config) -> Result { + let mut funding = match LocalAsset::load_string(".github/FUNDING.yml") { + Ok(res) => { + let parsed_response = parse_response(res)?; + Self { + content: parsed_response, + docs_content: None, + } + } + Err(_) => Self::default(), + }; + if let Ok(res) = LocalAsset::load_string("funding.md") { + let html = to_html(&res, &config.styles.syntax_theme())?; + funding.docs_content = Some(html); + } + + Ok(funding) + } +} + +fn parse_response(contents: String) -> Result> { + let deserialized_map = serde_yaml::from_str(&contents); + match deserialized_map { + Ok(yaml) => Ok(yaml), + Err(e) => Err(OrandaError::GithubFundingParseError { + details: e.to_string(), + }), + } +} diff --git a/src/data/github/repo.rs b/src/data/github/repo.rs index 211753e6..26dd9f14 100644 --- a/src/data/github/repo.rs +++ b/src/data/github/repo.rs @@ -3,13 +3,18 @@ use crate::errors::*; use miette::{miette, IntoDiagnostic}; use url::Url; +/// Represents a GitHub repository that we can query things about. #[derive(Debug, Clone)] pub struct GithubRepo { + /// The repository owner. pub owner: String, + /// The repository name. pub name: String, } impl GithubRepo { + /// Constructs a new Github repository from a "owner/name" string. Notably, this does not check + /// whether the repo actually exists. pub fn from_url(repo_url: &str) -> Result { let binding = Url::parse(repo_url) diff --git a/src/data/mod.rs b/src/data/mod.rs index e02ce1b6..6d89c973 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -4,8 +4,10 @@ use crate::message::{Message, MessageType}; pub mod cargo_dist; use cargo_dist::DistRelease; +pub mod funding; pub mod github; mod release; + pub use release::Release; pub struct Context { diff --git a/src/errors.rs b/src/errors.rs index f0334685..28775293 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -141,6 +141,20 @@ pub enum OrandaError { #[diagnostic(help = "Make sure that oranda has privileges to set up file watchers!")] FilesystemWatchError(#[from] notify_debouncer_mini::notify::Error), + #[error("Failed to fetch your funding info from GitHub.")] + #[diagnostic(help = "Make sure that your funding file is located at `.github/FUNDING.yml`.")] + GithubFundingFetchError { + #[source] + details: reqwest::Error, + }, + + #[error("Error while parsing FUNDING.yml")] + #[diagnostic( + help = "Make sure your FUNDING.yml conforms to GitHub's format!", + url = "https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository" + )] + GithubFundingParseError { details: String }, + #[error("{0}")] Other(String), } diff --git a/src/site/funding/icons.rs b/src/site/funding/icons.rs new file mode 100644 index 00000000..5dc520bb --- /dev/null +++ b/src/site/funding/icons.rs @@ -0,0 +1,41 @@ +// axohtml does not support SVG (for now) :( + +use axohtml::{dom::UnsafeTextNode, unsafe_text}; + +const SVG_META: &str = + "role='img' viewBox='0 0 24 24' height='1em' width='1em' xmlns='http://www.w3.org/2000/svg'"; + +pub fn get_linux_icon() -> Box> { + unsafe_text!(format!("Linux Foundation", SVG_META)) +} + +pub fn get_web_icon() -> Box> { + unsafe_text!(format!(" + + + ", SVG_META)) +} + +pub fn get_github_icon() -> Box> { + unsafe_text!(format!("GitHub", SVG_META)) +} + +pub fn get_patreon_icon() -> Box> { + unsafe_text!(format!("Patreon", SVG_META)) +} + +pub fn get_open_collective_icon() -> Box> { + unsafe_text!(format!("Open Collective", SVG_META)) +} + +pub fn get_kofi_icon() -> Box> { + unsafe_text!(format!("Ko-fi", SVG_META)) +} + +pub fn get_tidelift_icon() -> Box> { + unsafe_text!(format!("", SVG_META)) +} + +pub fn get_liberapay_icon() -> Box> { + unsafe_text!(format!("Liberapay", SVG_META)) +} diff --git a/src/site/funding/mod.rs b/src/site/funding/mod.rs new file mode 100644 index 00000000..b8f13f0c --- /dev/null +++ b/src/site/funding/mod.rs @@ -0,0 +1,155 @@ +mod icons; + +use crate::config::Config; +use crate::data::funding::{Funding, FundingContent, FundingType}; +use crate::errors::Result; +use axohtml::dom::UnsafeTextNode; +use axohtml::elements::{div, li}; +use axohtml::types::SpacedList; +use axohtml::{html, text, unsafe_text}; +use std::collections::HashMap; + +/// Generate the standalone funding page. +pub fn page(config: &Config, funding: &Funding) -> Result { + let mut funding_items = funding.content.clone(); + // We've already made sure that we can unwrap on all of these `Option`s + let unwrapped_config = config.funding.as_ref().unwrap(); + let preferred_html = if unwrapped_config.preferred_funding.is_some() { + let preferred = unwrapped_config.preferred_funding.as_ref().unwrap(); + // Remove the preferred item from the rest of the list + funding_items.remove(preferred); + preferred_funding_section(preferred.clone(), funding.content.clone()) + } else { + None + }; + let regular_html = create_funding_list(funding_items); + Ok(html!( +
+

{text!("Help fund this project!")}

+ {preferred_html} + {unsafe_text!(funding.docs_content.clone().unwrap_or("".into()))} +
    + {regular_html} +
+
+ ) + .to_string()) +} + +fn preferred_funding_section( + preferred: FundingType, + funding: HashMap, +) -> Option>> { + if let Some(element) = funding.get(&preferred).cloned() { + let mut hashmap = HashMap::new(); + hashmap.insert(preferred, element); + Some(html!( +
+
    + {create_funding_list(hashmap)} +
+
)) + } else { + None + } +} + +#[allow(clippy::vec_box)] +fn create_funding_list(funding: HashMap) -> Vec>> { + let mut list_html = vec![]; + if let Some(github) = one_or_multiple(&funding.get(&FundingType::Github)) { + for link in github { + let gh_link = format!("https://github.com/sponsors/{}", link); + list_html + .extend(html!(
  • {create_link(&gh_link, icons::get_github_icon(), "GitHub")}
  • )) + } + } + + if let Some(FundingContent::One(patreon)) = &funding.get(&FundingType::Patreon) { + let patreon_link = format!("https://patreon.com/{}", patreon); + list_html.extend( + html!(
  • {create_link(&patreon_link, icons::get_patreon_icon(), "Patreon")}
  • ), + ) + } + + if let Some(FundingContent::One(open_collective)) = &funding.get(&FundingType::OpenCollective) { + let oc_link = format!("https://opencollective.com/{}", open_collective); + list_html.extend(html!(
  • {create_link(&oc_link, icons::get_open_collective_icon(), "Open Collective")}
  • )) + } + + if let Some(FundingContent::One(kofi)) = &funding.get(&FundingType::KoFi) { + let kofi_link = format!("https://ko-fi.com/{}", kofi); + list_html.extend(html!(
  • {create_link(&kofi_link, icons::get_kofi_icon(), "Ko-fi")}
  • )) + } + + if let Some(FundingContent::One(tidelift)) = &funding.get(&FundingType::Tidelift) { + let tidelift_link = format!("https://tidelift.com/subscription/pkg/{}", tidelift); + list_html.extend( + html!(
  • {create_link(&tidelift_link, icons::get_tidelift_icon(), "Tidelift")}
  • ), + ) + } + + if let Some(FundingContent::One(community_bridge)) = &funding.get(&FundingType::CommunityBridge) + { + let cb_link = format!( + "https://crowdfunding.lfx.linuxfoundation.org/projects/{}", + community_bridge + ); + list_html.extend( + html!(
  • {create_link(&cb_link, icons::get_linux_icon(), "LFX Mentorship")}
  • ), + ) + } + + if let Some(FundingContent::One(liberapay)) = &funding.get(&FundingType::Liberapay) { + let liberapay_link = format!("https://liberapay.com/{}", liberapay); + list_html.extend(html!(
  • {create_link(&liberapay_link, icons::get_liberapay_icon(), "Liberapay")}
  • )) + } + + if let Some(FundingContent::One(issuehunt)) = &funding.get(&FundingType::Issuehunt) { + let issuehunt_link = format!("https://issuehunt.com/r/{}", issuehunt); + // FIXME: Get an issuehunt icon from somewhere + list_html.extend( + html!(
  • {create_link(&issuehunt_link, icons::get_web_icon(), "IssueHunt")}
  • ), + ) + } + + if let Some(custom) = one_or_multiple(&funding.get(&FundingType::Custom)) { + for link in custom { + list_html.extend(html!(
  • {create_link(&link, icons::get_web_icon(), &link)}
  • )) + } + } + + list_html +} + +/// Handles either one or multiple funding items, and puts them into a Vec. +fn one_or_multiple(funding: &Option<&FundingContent>) -> Option> { + if funding.is_none() { + return None; + } + let mut vec = vec![]; + match funding.unwrap() { + FundingContent::One(item) => vec.push(item.to_owned()), + FundingContent::Multiple(items) => vec.extend(items.to_vec()), + } + + Some(vec) +} + +/// Creates a link element to be used in the funding page. +fn create_link( + link: &str, + icon: Box>, + site_name: &str, +) -> Box> { + let mut rels = SpacedList::new(); + rels.add("noopener"); + rels.add("noreferrer"); + let title = &format!("Support us on {}", site_name); + html!( + + {unsafe_text!(title)} + ) +} diff --git a/src/site/layout/header.rs b/src/site/layout/header.rs index c7633724..ab0bc05d 100644 --- a/src/site/layout/header.rs +++ b/src/site/layout/header.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::config::artifacts::Artifacts; -use crate::config::{Config, MdBookConfig}; +use crate::config::{Config, FundingConfig, MdBookConfig}; use crate::errors::*; use crate::message::{Message, MessageType}; use crate::site::{link, page}; @@ -34,6 +34,7 @@ fn nav( artifacts: &Artifacts, md_book: &Option, changelog: &bool, + funding: &Option, ) -> Result>> { Message::new(MessageType::Info, "Building nav...").print(); let mut html: Vec>> = if let Some(prefix) = &path_prefix { @@ -81,6 +82,16 @@ fn nav( html.extend(html!(
  • {text!("Docs")}
  • )); }; + if funding.is_some() { + Message::new(MessageType::Info, "Adding funding page...").print(); + let href = if let Some(prefix) = &path_prefix { + format!("/{}/{}/", prefix, "funding") + } else { + format!("/{}/", "funding") + }; + html.extend(html!(
  • {text!("Funding")}
  • )); + } + if *changelog { Message::new(MessageType::Info, "Adding changelog...").print(); let href = if let Some(prefix) = &path_prefix { @@ -118,6 +129,7 @@ pub fn create(config: &Config) -> Result>> { &config.artifacts, &config.mdbook, &config.changelog, + &config.funding, )?) } else { None diff --git a/src/site/mod.rs b/src/site/mod.rs index a0edc8d3..88bd6005 100644 --- a/src/site/mod.rs +++ b/src/site/mod.rs @@ -16,8 +16,11 @@ use layout::{css, javascript, Layout}; pub mod link; pub mod markdown; pub mod page; +use crate::data::funding::Funding; use page::Page; + pub mod changelog; +pub mod funding; pub mod mdbook; #[derive(Debug)] @@ -43,28 +46,39 @@ impl Site { if Self::needs_context(config) { match &config.repository { Some(repo_url) => { - let context = Context::new(repo_url, config.artifacts.cargo_dist())?; - if config.artifacts.has_some() { - index = Some(Page::index_with_artifacts(&context, &layout_template, config)?); - if context.latest_dist_release.is_some() - || config.artifacts.package_managers.is_some() - { - let body = artifacts::page(&context, config)?; - let artifacts_page = Page::new_from_contents( + let context = Context::new(repo_url, config.artifacts.cargo_dist())?; + if config.artifacts.has_some() { + index = Some(Page::index_with_artifacts(&context, &layout_template, config)?); + if context.latest_dist_release.is_some() + || config.artifacts.package_managers.is_some() + { + let body = artifacts::page(&context, config)?; + let artifacts_page = Page::new_from_contents( + body, + "artifacts.html", + &layout_template, + config, + ); + pages.push(artifacts_page); + } + } + if config.changelog { + let mut changelog_pages = Self::build_changelog_pages(&context, &layout_template, config)?; + pages.append(&mut changelog_pages); + } + if config.funding.is_some() { + let funding = Funding::new(config)?; + let body = funding::page(config, &funding)?; + let page = Page::new_from_contents( body, - "artifacts.html", + "funding.html", &layout_template, config, ); - pages.push(artifacts_page); + pages.push(page); } - } - if config.changelog { - let mut changelog_pages = Self::build_changelog_pages(&context, &layout_template, config)?; - pages.append(&mut changelog_pages); - } - }, - None => Err(OrandaError::Other("You have indicated you want to use features that require a repository context. Please add a \"repository\" key and value to your project (such as a package.json or Cargo.toml) or oranda config (oranda.json).".to_string()))? + }, + None => Err(OrandaError::Other("You have indicated you want to use features that require a repository context. Please add a \"repository\" key and value to your project (such as a package.json or Cargo.toml) or oranda config (oranda.json).".to_string()))? } } @@ -73,7 +87,7 @@ impl Site { } fn needs_context(config: &Config) -> bool { - config.artifacts.has_some() || config.changelog + config.artifacts.has_some() || config.changelog || config.funding.is_some() } fn build_additional_pages( diff --git a/tests/build/fixtures/oranda_config.rs b/tests/build/fixtures/oranda_config.rs index 9df2f2fe..b3a89dc5 100644 --- a/tests/build/fixtures/oranda_config.rs +++ b/tests/build/fixtures/oranda_config.rs @@ -26,6 +26,7 @@ pub fn no_artifacts(temp_dir: String) -> Config { ..Default::default() }, mdbook: None, + funding: None, ..Default::default() } }