mirror of
https://github.com/deps-rs/deps.rs.git
synced 2024-11-22 10:26:30 +00:00
modernize badge package
This commit is contained in:
parent
0d3e0ac0f5
commit
3e3e9eea9d
5 changed files with 925 additions and 566 deletions
1404
Cargo.lock
generated
1404
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,12 @@ name = "shiny-robots"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Sam Rijs <srijs@airpost.net>"]
|
authors = ["Sam Rijs <srijs@airpost.net>"]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
".",
|
||||||
|
"./libs/badge",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cadence = "0.13.1"
|
cadence = "0.13.1"
|
||||||
failure = "0.1.1"
|
failure = "0.1.1"
|
||||||
|
|
1
libs/badge/.gitignore
vendored
Normal file
1
libs/badge/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/test.svg
|
|
@ -6,11 +6,12 @@ authors = ["Onur Aslan <onur@onur.im>"]
|
||||||
license-file = "LICENSE"
|
license-file = "LICENSE"
|
||||||
repository = "https://github.com/onur/docs.rs"
|
repository = "https://github.com/onur/docs.rs"
|
||||||
documentation = "https://docs.rs/badge"
|
documentation = "https://docs.rs/badge"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "badge.rs"
|
path = "badge.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.9.0"
|
base64 = "0.12"
|
||||||
lazy_static = "1.0.0"
|
once_cell = "1"
|
||||||
rusttype = "0.5.0"
|
rusttype = "0.9"
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
//! Simple badge generator
|
//! Simple badge generator
|
||||||
|
|
||||||
extern crate base64;
|
|
||||||
#[macro_use] extern crate lazy_static;
|
|
||||||
extern crate rusttype;
|
|
||||||
|
|
||||||
|
|
||||||
use base64::display::Base64Display;
|
use base64::display::Base64Display;
|
||||||
use rusttype::{Font, FontCollection, Scale, point, Point, PositionedGlyph};
|
use once_cell::sync::Lazy;
|
||||||
|
use rusttype::{point, Font, Point, PositionedGlyph, Scale};
|
||||||
|
|
||||||
|
const FONT_DATA: &'static [u8] =
|
||||||
const FONT_DATA: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/DejaVuSans.ttf"));
|
||||||
"/DejaVuSans.ttf"));
|
|
||||||
const FONT_SIZE: f32 = 11.;
|
const FONT_SIZE: f32 = 11.;
|
||||||
|
const SCALE: Scale = Scale {
|
||||||
|
x: FONT_SIZE,
|
||||||
|
y: FONT_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct BadgeOptions {
|
pub struct BadgeOptions {
|
||||||
/// Subject will be displayed on the left side of badge
|
/// Subject will be displayed on the left side of badge
|
||||||
|
@ -23,7 +21,6 @@ pub struct BadgeOptions {
|
||||||
pub color: String,
|
pub color: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Default for BadgeOptions {
|
impl Default for BadgeOptions {
|
||||||
fn default() -> BadgeOptions {
|
fn default() -> BadgeOptions {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
|
@ -34,54 +31,47 @@ impl Default for BadgeOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct BadgeStaticData {
|
struct BadgeStaticData {
|
||||||
font: Font<'static>,
|
font: Font<'static>,
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
offset: Point<f32>
|
offset: Point<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DATA: Lazy<BadgeStaticData> = Lazy::new(|| {
|
||||||
|
let font = Font::try_from_bytes(FONT_DATA).expect("failed to parse font collection");
|
||||||
|
|
||||||
lazy_static! {
|
let v_metrics = font.v_metrics(SCALE);
|
||||||
static ref DATA: BadgeStaticData = {
|
let offset = point(0.0, v_metrics.ascent);
|
||||||
let collection = FontCollection::from_bytes(FONT_DATA)
|
|
||||||
.expect("failed to parse font collection");
|
|
||||||
let font = collection.into_font()
|
|
||||||
.expect("failed to load font data");
|
|
||||||
let scale = Scale {
|
|
||||||
x: FONT_SIZE,
|
|
||||||
y: FONT_SIZE,
|
|
||||||
};
|
|
||||||
let v_metrics = font.v_metrics(scale);
|
|
||||||
let offset = point(0.0, v_metrics.ascent);
|
|
||||||
|
|
||||||
BadgeStaticData { font, scale, offset }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
BadgeStaticData {
|
||||||
|
font,
|
||||||
|
scale: SCALE.clone(),
|
||||||
|
offset,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
pub struct Badge {
|
pub struct Badge {
|
||||||
options: BadgeOptions
|
options: BadgeOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Badge {
|
impl Badge {
|
||||||
pub fn new(options: BadgeOptions) -> Badge {
|
pub fn new(options: BadgeOptions) -> Badge {
|
||||||
Badge { options }
|
Badge { options }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn to_svg_data_uri(&self) -> String {
|
pub fn to_svg_data_uri(&self) -> String {
|
||||||
format!("data:image/svg+xml;base64,{}",
|
format!(
|
||||||
Base64Display::standard(self.to_svg().as_bytes()))
|
"data:image/svg+xml;base64,{}",
|
||||||
|
Base64Display::with_config(self.to_svg().as_bytes(), base64::STANDARD)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn to_svg(&self) -> String {
|
pub fn to_svg(&self) -> String {
|
||||||
let left_width = self.calculate_width(&self.options.subject) + 6;
|
let left_width = self.calculate_width(&self.options.subject) + 6;
|
||||||
let right_width = self.calculate_width(&self.options.status) + 6;
|
let right_width = self.calculate_width(&self.options.status) + 6;
|
||||||
|
|
||||||
let svg = format!(r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="20">
|
let svg = format!(
|
||||||
|
r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="20">
|
||||||
<linearGradient id="smooth" x2="0" y2="100%">
|
<linearGradient id="smooth" x2="0" y2="100%">
|
||||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||||
<stop offset="1" stop-opacity=".1"/>
|
<stop offset="1" stop-opacity=".1"/>
|
||||||
|
@ -118,16 +108,17 @@ impl Badge {
|
||||||
left_width + (right_width / 2),
|
left_width + (right_width / 2),
|
||||||
self.options.status,
|
self.options.status,
|
||||||
left_width + (right_width / 2),
|
left_width + (right_width / 2),
|
||||||
self.options.status);
|
self.options.status
|
||||||
|
);
|
||||||
|
|
||||||
svg
|
svg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn calculate_width(&self, text: &str) -> u32 {
|
fn calculate_width(&self, text: &str) -> u32 {
|
||||||
let glyphs: Vec<PositionedGlyph> =
|
let glyphs: Vec<PositionedGlyph> =
|
||||||
DATA.font.layout(text, DATA.scale, DATA.offset).collect();
|
DATA.font.layout(text, DATA.scale, DATA.offset).collect();
|
||||||
let width = glyphs.iter()
|
let width = glyphs
|
||||||
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.filter_map(|g| {
|
.filter_map(|g| {
|
||||||
g.pixel_bounding_box()
|
g.pixel_bounding_box()
|
||||||
|
@ -139,8 +130,6 @@ impl Badge {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in a new issue