Skip to content

Commit 9e1d7fe

Browse files
committed
feat: error handling; css to assets
1 parent abba7c7 commit 9e1d7fe

24 files changed

+474
-254
lines changed

Cargo.lock

Lines changed: 294 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ base64 = "0.22.1"
1010
cached = { version = "0.55.1", features = ["default", "async"] }
1111
chrono = { version = "0.4.40", features = ["serde"] }
1212
maud = { version = "0.27.0", features = ["axum"] }
13+
mime_guess = "2.0.5"
1314
phf = { version = "0.11.3", features = ["macros"] }
14-
reqwest = { version = "0.12.12", features = ["json", "rustls-tls"], default-features = false }
15+
reqwest = { version = "0.12.13", features = ["json", "rustls-tls"], default-features = false }
16+
rust-embed = { version = "8.6.0", features = ["axum"] }
1517
semver = "1.0.26"
1618
serde = { version = "1.0.219", features = ["derive"] }
1719
serde_json = "1.0.140"
@@ -31,6 +33,9 @@ rusttype = "0.9.3"
3133
[lints.rust]
3234
dead_code = "allow"
3335

36+
[lints.clippy]
37+
unused_imports = "deny"
38+
3439
[profile.release]
3540
strip = true
3641

assets/favicon.svg

Lines changed: 3 additions & 0 deletions
Loading

assets/main.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@media (min-width: 1024px) {
2+
.container {
3+
max-width: 950px !important;
4+
}
5+
}
6+
7+
html { scroll-behavior: smooth; }
8+
.absolute { position: absolute; }
9+
.relative { position: relative; }
10+
.flex { display: flex; }
11+
.flex-row { flex-direction: row; }
12+
.flex-col { flex-direction: column; }
13+
.flex-wrap { flex-wrap: wrap; }
14+
.items-center { align-items: center; }
15+
.w-1\/2 { width: 50%; }
16+
.w-1\/4 { width: 25%; }
17+
.gap-2 { gap: 0.5rem; }
18+
.py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; }
19+
.pr-2 { padding-right: 0.5rem; }
20+
.text-center { text-align: center; }
21+
.no-underline { text-decoration: none; }
22+
.heading { position: relative; }
23+
.heading a { position: absolute; transform: translateX(-100%); left: 0; padding-right: 0.5rem; opacity: 0; text-decoration: none; }
24+
.heading:hover a { opacity: 0.25; }
25+
.heading:hover a:hover { opacity: 1 !important; }
26+
.h20 { height: 20px; }

readme.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# badges.ws
22

3+
<img src="assets/favicon.svg" align="right" width="128" />
4+
5+
[<img src="https://badges.ws/github/license/vladkens/badges" />](https://github.com/vladkens/badges/blob/main/LICENSE)
6+
[<img src="https://badges.ws/badge/Powered_by_Fly.io-24175B?logo=flydotio&logoColor=fff" />](https://fly.io)
7+
[<img src="https://badges.ws/badge/-/buy%20me%20a%20coffee/ff813f?icon=buymeacoffee&label" alt="donate" />](https://buymeacoffee.com/vladkens)
8+
39
Badges.ws is a modern, Rust-based badge generation service inspired by [Shields.io](https://github.com/badges/shields) and [Badgen.net](https://github.com/badgen/badgen.net). It offers a simpler, more efficient codebase with up-to-date integrations, self-hosting capabilities, and low memory consumption. Additionally, it incorporates API-level data caching on top of control-cache headers.
410

511
## Why Badges.ws?

src/apis/amo.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use axum::{
2-
extract::{Path, Query},
3-
response::IntoResponse,
4-
};
1+
use axum::extract::{Path, Query};
52
use serde::{Deserialize, Serialize};
63

74
use super::get_client;
8-
use crate::badgelib::{Badge, DlPeriod};
9-
use crate::server::{Dict, Rep, Res};
5+
use crate::server::{Dict, Res};
6+
use crate::{
7+
badgelib::{Badge, DlPeriod},
8+
server::BadgeRep,
9+
};
1010

1111
#[derive(Debug)]
1212
struct Data {
@@ -39,10 +39,7 @@ pub(crate) enum Kind {
3939
Weekly,
4040
}
4141

42-
pub async fn handler(
43-
Path((kind, name)): Path<(Kind, String)>,
44-
Query(qs): Query<Dict>,
45-
) -> Rep<impl IntoResponse> {
42+
pub async fn handler(Path((kind, name)): Path<(Kind, String)>, Query(qs): Query<Dict>) -> BadgeRep {
4643
let rs = get_data(&name).await?;
4744
match kind {
4845
Kind::Version => Ok(Badge::for_version(&qs, "mozilla add-on", &rs.version)?),

src/apis/crates.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use axum::{
2-
extract::{Path, Query},
3-
response::IntoResponse,
4-
};
1+
use axum::extract::{Path, Query};
52
use serde::{Deserialize, Serialize};
63

74
use super::get_client;
85
use crate::badgelib::{Badge, DlPeriod};
9-
use crate::server::{Dict, Rep, Res};
6+
use crate::server::{BadgeRep, Dict, Res};
107

118
#[derive(Debug)]
129
struct CrateData {
@@ -53,10 +50,7 @@ pub(crate) enum Kind {
5350
Total,
5451
}
5552

56-
pub async fn handler(
57-
Path((kind, name)): Path<(Kind, String)>,
58-
Query(qs): Query<Dict>,
59-
) -> Rep<impl IntoResponse> {
53+
pub async fn handler(Path((kind, name)): Path<(Kind, String)>, Query(qs): Query<Dict>) -> BadgeRep {
6054
let rs = get_data(&name).await?;
6155
match kind {
6256
Kind::Version => Ok(Badge::for_version(&qs, "crates.io", &rs.version)?),

src/apis/cws.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use axum::{
2-
extract::{Path, Query},
3-
response::IntoResponse,
4-
};
1+
use axum::extract::{Path, Query};
52
use serde::{Deserialize, Serialize};
63

74
use super::get_client;
85
use crate::badgelib::{Badge, Color, utils::render_stars};
9-
use crate::server::{Dict, Rep, Res};
6+
use crate::server::{BadgeRep, Dict, Res};
107

118
#[derive(Debug)]
129
struct Data {
@@ -48,10 +45,7 @@ pub(crate) enum Kind {
4845
Stars,
4946
}
5047

51-
pub async fn handler(
52-
Path((kind, name)): Path<(Kind, String)>,
53-
Query(qs): Query<Dict>,
54-
) -> Rep<impl IntoResponse> {
48+
pub async fn handler(Path((kind, name)): Path<(Kind, String)>, Query(qs): Query<Dict>) -> BadgeRep {
5549
let rs = get_data(&name).await?;
5650
match kind {
5751
Kind::Version => Ok(Badge::for_version(&qs, "chrome web store", &rs.version)?),

src/apis/dart_pub.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
use axum::{
2-
extract::{Path, Query},
3-
response::IntoResponse,
4-
};
1+
use axum::extract::{Path, Query};
52
use serde::{Deserialize, Serialize};
63

74
use super::get_client;
85
use crate::badgelib::{Badge, DlPeriod};
9-
use crate::server::{Dict, Rep, Res};
6+
use crate::server::{BadgeRep, Dict, Res};
107

118
#[derive(Debug)]
129
struct Data {
@@ -66,10 +63,7 @@ pub(crate) enum Kind {
6663
Monthly,
6764
}
6865

69-
pub async fn handler(
70-
Path((kind, name)): Path<(Kind, String)>,
71-
Query(qs): Query<Dict>,
72-
) -> Rep<impl IntoResponse> {
66+
pub async fn handler(Path((kind, name)): Path<(Kind, String)>, Query(qs): Query<Dict>) -> BadgeRep {
7367
match kind {
7468
Kind::Version => Ok(Badge::for_version(&qs, "pub", &get_data(&name).await?.version)?),
7569
Kind::License => Ok(Badge::for_license(&qs, &get_score(&name).await?.license)?),

src/apis/fixed.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
use axum::{
2-
extract::{Path, Query},
3-
response::IntoResponse,
4-
};
1+
use axum::extract::{Path, Query};
52

63
use crate::badgelib::{Badge, Color};
7-
use crate::server::{Dict, Rep};
4+
use crate::server::{BadgeRep, Dict};
85

9-
pub async fn handler1(Query(qs): Query<Dict>) -> Rep<impl IntoResponse> {
6+
pub async fn handler1(Query(qs): Query<Dict>) -> BadgeRep {
107
Ok(Badge::from_qs(&qs)?)
118
}
129

13-
pub async fn handler2(
14-
Path(config): Path<String>,
15-
Query(qs): Query<Dict>,
16-
) -> Rep<impl IntoResponse> {
10+
pub async fn handler2(Path(config): Path<String>, Query(qs): Query<Dict>) -> BadgeRep {
1711
// Label, message and color separated by a dash -. For example: `label-message-color`
1812
// Message and color only, separated by a dash -. For example: `just%20the%20message-8A2BE2`
1913
// Rules:
@@ -53,7 +47,7 @@ pub async fn handler2(
5347
pub async fn handler3(
5448
Path((label, value, color)): Path<(String, String, Color)>,
5549
Query(qs): Query<Dict>,
56-
) -> Rep<impl IntoResponse> {
50+
) -> BadgeRep {
5751
let label = qs.get("label").unwrap_or(&label);
5852
let value = qs.get("value").unwrap_or(&value);
5953
let color = qs.get("color").map_or(color, |x| Color::from_str(x).unwrap_or_default());

0 commit comments

Comments
 (0)