1use crate::{
2 BadgeParams, BadgeStyle, default_label_color, default_message_color, render_badge_svg,
3};
4
5pub struct NoLink;
6pub struct OneLink {
7 link: String,
8}
9pub struct TwoLink {
10 link: String,
11 extra_link: String,
12}
13
14pub struct CommonBadgeData {
16 label: String,
17 message: String,
18}
19
20impl CommonBadgeData {
21 fn new() -> Self {
22 Self {
23 label: String::new(),
24 message: String::new(),
25 }
26 }
27
28 fn set_label_internal(&mut self, label: &str) {
30 self.label = label.to_string();
31 }
32
33 fn set_message_internal(&mut self, message: &str) {
34 self.message = message.to_string();
35 }
36}
37
38pub struct SocialBadgeBuilder<State = NoLink> {
39 common_data: CommonBadgeData,
40 state: State,
41}
42
43impl<S> SocialBadgeBuilder<S> {
44 pub fn set_label(mut self, label: &str) -> Self {
45 self.common_data.set_label_internal(label);
46 self
47 }
48 pub fn set_message(mut self, message: &str) -> Self {
49 self.common_data.set_message_internal(message);
50 self
51 }
52}
53
54impl SocialBadgeBuilder<NoLink> {
55 pub fn new() -> Self {
56 Self {
57 common_data: CommonBadgeData::new(),
58 state: NoLink,
59 }
60 }
61 pub fn set_link(&mut self, link: &str) -> SocialBadgeBuilder<OneLink> {
63 SocialBadgeBuilder {
64 common_data: CommonBadgeData {
65 label: self.common_data.label.clone(),
66 message: self.common_data.message.clone(),
67 },
68 state: OneLink {
69 link: link.to_string(),
70 },
71 }
72 }
73 pub fn build(&self) -> String {
74 render_badge_svg(&BadgeParams {
75 style: BadgeStyle::Social,
76 label: Some(self.common_data.label.as_str()),
77 message: self.common_data.message.as_str(),
78 label_color: None,
79 message_color: &"",
80 link: None,
81 extra_link: None,
82 logo: None,
83 logo_color: None,
84 })
85 }
86}
87
88impl SocialBadgeBuilder<OneLink> {
89 pub fn set_extra_link(self, link: &str) -> SocialBadgeBuilder<TwoLink> {
90 SocialBadgeBuilder {
91 common_data: self.common_data,
92 state: TwoLink {
93 link: self.state.link,
94 extra_link: link.to_string(),
95 },
96 }
97 }
98 pub fn build(&self) -> String {
99 render_badge_svg(&BadgeParams {
100 style: BadgeStyle::Social,
101 label: Some(self.common_data.label.as_str()),
102 message: self.common_data.message.as_str(),
103 label_color: None,
104 message_color: &"",
105 link: Some(&self.state.link),
106 extra_link: None,
107 logo: None,
108 logo_color: None,
109 })
110 }
111}
112
113impl SocialBadgeBuilder<TwoLink> {
114 pub fn build(&self) -> String {
115 render_badge_svg(&BadgeParams {
116 style: BadgeStyle::Social,
117 label: Some(self.common_data.label.as_str()),
118 message: self.common_data.message.as_str(),
119 label_color: None,
120 message_color: &"",
121 link: Some(&self.state.link),
122 extra_link: Some(&self.state.extra_link),
123 logo: None,
124 logo_color: None,
125 })
126 }
127}
128
129pub struct ColorBadgeBuilder<State = NoLink> {
130 common_data: CommonBadgeData,
131 style: BadgeStyle,
132 label_color: String,
133 message_color: String,
134 state: State,
135}
136
137impl ColorBadgeBuilder<NoLink> {
138 pub fn new(style: BadgeStyle) -> Self {
139 Self {
140 style,
141 common_data: CommonBadgeData::new(),
142 label_color: String::from(default_label_color()),
143 message_color: String::from(default_message_color()),
144 state: NoLink,
145 }
146 }
147 pub fn set_link(self, link: &str) -> ColorBadgeBuilder<OneLink> {
148 ColorBadgeBuilder {
149 style: self.style,
150 common_data: self.common_data,
151 label_color: self.label_color,
152 message_color: self.message_color,
153 state: OneLink {
154 link: link.to_string(),
155 },
156 }
157 }
158}
159
160impl ColorBadgeBuilder<OneLink> {
161 pub fn set_extra_link(self, extra: &str) -> ColorBadgeBuilder<TwoLink> {
162 ColorBadgeBuilder {
163 style: self.style,
164 common_data: self.common_data,
165 label_color: self.label_color,
166 message_color: self.message_color,
167 state: TwoLink {
168 link: self.state.link,
169 extra_link: extra.to_string(),
170 },
171 }
172 }
173}
174
175impl<S> ColorBadgeBuilder<S> {
176 pub fn set_label_color(&mut self, color: &str) -> &mut Self {
177 self.label_color = color.to_string();
178 self
179 }
180 pub fn set_message_color(&mut self, color: &str) -> &mut Self {
181 self.message_color = color.to_string();
182 self
183 }
184
185 pub fn build(&self) -> String {
186 return render_badge_svg(&BadgeParams {
188 style: self.style,
189 label: Some(self.common_data.label.as_str()),
190 message: self.common_data.message.as_str(),
191 label_color: Some(self.label_color.as_str()),
192 message_color: self.message_color.as_str(),
193 link: None,
194 extra_link: None,
195 logo: None,
196 logo_color: None,
197 });
198 }
199}
200
201impl<S> ColorBadgeBuilder<S> {
202 pub fn set_label(mut self, label: &str) -> Self {
203 self.common_data.set_label_internal(label);
204 self
205 }
206 pub fn set_message(mut self, message: &str) -> Self {
207 self.common_data.set_message_internal(message);
208 self
209 }
210}
211
212pub struct Builder {}
213
214impl Builder {
215 pub fn social(self) -> SocialBadgeBuilder {
216 SocialBadgeBuilder::new()
217 }
218
219 pub fn flat(self) -> ColorBadgeBuilder {
220 ColorBadgeBuilder::new(BadgeStyle::Base(crate::BaseBadgeStyle::Flat))
221 }
222
223 pub fn flat_square(self) -> ColorBadgeBuilder {
224 ColorBadgeBuilder::new(BadgeStyle::Base(crate::BaseBadgeStyle::FlatSquare))
225 }
226
227 pub fn plastic(self) -> ColorBadgeBuilder {
228 ColorBadgeBuilder::new(BadgeStyle::Base(crate::BaseBadgeStyle::Plastic))
229 }
230}
231
232#[cfg(test)]
233
234mod tests {
235 use super::*;
236 #[test]
237 fn test_builder() {
238 let builder = Builder {};
239 let badge = builder
240 .flat()
241 .set_label("test")
242 .set_message("test")
243 .set_label_color("#000000")
244 .set_message_color("#FFFFFF")
245 .build();
246 assert_eq!(
247 badge,
248 r##"<svg xmlns="http://www.w3.org/2000/svg" width="62" height="20" role="img" aria-label="test: test"><title>test: test</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="62" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="31" height="20" fill="#000000"/><rect x="31" width="31" height="20" fill="#ffffff"/><rect width="62" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="165" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="210">test</text><text x="165" y="140" transform="scale(.1)" fill="#fff" textLength="210">test</text><text aria-hidden="true" x="455" y="150" fill="#ccc" fill-opacity=".3" transform="scale(.1)" textLength="210">test</text><text x="455" y="140" transform="scale(.1)" fill="#333" textLength="210">test</text></g></svg>"##
249 );
250 }
251 #[test]
252 fn test_builder_social_with_link() {
253 let builder = Builder {};
254 let badge = builder
255 .social()
256 .set_label("test")
257 .set_link("https://example.com")
258 .set_message("test")
259 .set_extra_link("https://example.com/extra")
260 .build();
261 assert_eq!(
262 badge,
263 r##"<svg xmlns="http://www.w3.org/2000/svg" width="67" height="20"><style>a:hover #llink{fill:url(#b);stroke:#ccc}a:hover #rlink{fill:#4183c4}</style><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fcfcfc" stop-opacity="0"/><stop offset="1" stop-opacity=".1"/></linearGradient><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#ccc" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><g stroke="#d5d5d5"><rect stroke="none" fill="#fcfcfc" x="0.5" y="0.5" width="33" height="19" rx="2"/><rect x="39.5" y="0.5" width="27" height="19" rx="2" fill="#fafafa"/><rect x="39" y="7.5" width="0.5" height="5" stroke="#fafafa"/><path d="M39.5 6.5 l-3 3v1 l3 3" stroke="d5d5d5" fill="#fafafa"/></g><g aria-hidden="false" fill="#333" text-anchor="middle" font-family="Helvetica Neue,Helvetica,Arial,sans-serif" text-rendering="geometricPrecision" font-weight="700" font-size="110px" line-height="14px"><a target="_blank" href="https://example.com"><text aria-hidden="true" x="165" y="150" fill="#fff" transform="scale(.1)" textLength="230">Test</text><text x="165" y="140" transform="scale(.1)" textLength="230">Test</text><rect id="llink" stroke="#d5d5d5" fill="url(#a)" x=".5" y=".5" width="33" height="19" rx="2"/></a><a target="_blank" href="https://example.com/extra"><rect width="28" x="39" height="20" fill="rgba(0,0,0,0)"/><text aria-hidden="true" x="525" y="150" fill="#fff" transform="scale(.1)" textLength="190">test</text><text id="rlink" x="525" y="140" transform="scale(.1)" textLength="190">test</text></a></g></svg>"##
264 )
265 }
266
267 #[test]
268 fn test_builder_plastic_with_link() {
269 let builder = Builder {};
270 let badge = builder
271 .plastic()
272 .set_label("test")
273 .set_link("https://example.com")
274 .set_message("test")
275 .build();
276 assert_eq!(
277 badge,
278 r##"<svg xmlns="http://www.w3.org/2000/svg" width="62" height="18" role="img" aria-label="test: test"><title>test: test</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#fff" stop-opacity=".7"/><stop offset=".1" stop-color="#aaa" stop-opacity=".1"/><stop offset=".9" stop-color="#000" stop-opacity=".3"/><stop offset="1" stop-color="#000" stop-opacity=".5"/></linearGradient><clipPath id="r"><rect width="62" height="18" rx="4" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="31" height="18" fill="#555"/><rect x="31" width="31" height="18" fill="#007ec6"/><rect width="62" height="18" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="165" y="140" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="210">test</text><text x="165" y="130" transform="scale(.1)" fill="#fff" textLength="210">test</text><text aria-hidden="true" x="455" y="140" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="210">test</text><text x="455" y="130" transform="scale(.1)" fill="#fff" textLength="210">test</text></g></svg>"##
279 );
280 }
281}