display history of topic updates on topic details page
[websub-hub] / src / template / badge-svg.js
1 'use strict';
2
3 const th = require('./template-helper');
4
5
6 const ctxDefaults = {
7 charWidth: 7.2,
8 height: 20,
9 labelColor: '#444',
10 messageColor: '#f73',
11 color: '#fff',
12 fontFamily: 'DejaVu Sans,Verdana,Geneva,sans-serif',
13 };
14
15
16 function fixedRound(n, p = 2) {
17 return Number(n.toFixed(p));
18 }
19
20
21 /**
22 * image/svg+xml;charset=utf-8 formatted badge with subscriber count for a topic
23 * @param {Object} ctx - badge-specific context (not request context)
24 * @param {String} label
25 * @param {String} message
26 * @param {String} accessibleText
27 * @returns {String}
28 */
29 module.exports = (ctx, label, message, accessibleText) => {
30
31 ctx = Object.assign({}, ctxDefaults, ctx, {
32 label,
33 message,
34 accessibleText,
35 });
36 ctx.verticalMargin = fixedRound(ctx.height * 0.69);
37 ctx.labelWidth = fixedRound(ctx.label.length * ctx.charWidth);
38 ctx.messageWidth = fixedRound(ctx.message.length * ctx.charWidth);
39 ctx.width = ctx.labelWidth + ctx.messageWidth;
40 ctx.halfCharWidth = fixedRound(ctx.charWidth * 0.5);
41
42 /*
43 * This SVG content mostly replicates the output of the 'Plastic' badge
44 * renderer from https://github.com/badges/shields/tree/master/badge-maker which
45 * is under the http://creativecommons.org/publicdomain/zero/1.0/ license.
46 */
47 return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${ctx.width}" height="${ctx.height}" role="img" aria-label="${th.xmlEscape(ctx.accessibleText)}">
48 <title>${th.xmlEscape(ctx.accessibleText)}</title>
49 <linearGradient id="s" x2="0" y2="100%">
50 <stop offset="0" stop-color="#fff" stop-opacity=".7"/>
51 <stop offset=".1" stop-color="#aaa" stop-opacity=".1"/>
52 <stop offset=".9" stop-color="#000" stop-opacity=".3"/>
53 <stop offset="1" stop-color="#000" stop-opacity=".5"/>
54 </linearGradient>
55 <clipPath id="r">
56 <rect width="${ctx.width}" height="${ctx.height}" rx="4" fill="#fff"/>
57 </clipPath>
58 <g clip-path="url(#r)">
59 <rect width="${ctx.labelWidth}" height="${ctx.height}" fill="${ctx.labelColor}"/>
60 <rect x="${ctx.labelWidth}" width="${ctx.messageWidth}" height="${ctx.height}" fill="${ctx.messageColor}"/>
61 <rect width="${ctx.width}" height="${ctx.height}" fill="url(#s)"/>
62 </g>
63 <g fill="${ctx.color}" text-anchor="left" font-family="${ctx.fontFamily}" text-rendering="geometricPrecision" font-size="11" font-weight="bold">
64 <text x="${ctx.halfCharWidth}" y="${ctx.verticalMargin}">${th.xmlEscape(ctx.label)}</text>
65 <text x="${fixedRound(ctx.halfCharWidth + ctx.labelWidth)}" y="${ctx.verticalMargin}">${th.xmlEscape(ctx.message)}</text>
66 </g>
67 </svg>`;
68 };