Skip to content

Commit

Permalink
Update badges to new design (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten authored Oct 3, 2023
1 parent 958c019 commit 9f9d2b8
Show file tree
Hide file tree
Showing 79 changed files with 321 additions and 379 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20
20
177 changes: 39 additions & 138 deletions build-scripts/create-badges.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
const anafanafo = require("anafanafo");
const path = require("path");
const fs = require("fs");
const redirects = require("../redirect.json");
const { optimize } = require("svgo");
const TextToSVG = require('text-to-svg');

const OUTPUT_DIR = path.resolve(__dirname, "../public/badges");

const fontFamily = 'font-family="Verdana,Geneva,DejaVu Sans,sans-serif"';

function escapeXml(s) {
if (s === undefined || typeof s !== "string") {
return undefined;
Expand All @@ -21,43 +19,8 @@ function escapeXml(s) {
}
}

function roundUpToOdd(val) {
return val % 2 === 0 ? val + 1 : val;
}

function preferredWidthOf(str, options) {
// Increase chances of pixel grid alignment.
return roundUpToOdd(anafanafo(str, options) | 0);
}

function renderLogo({
logo,
badgeHeight,
horizPadding,
logoWidth = 14,
logoPadding = 0,
}) {
if (!logo) {
return {
totalLogoWidth: 14 + logoPadding,
renderedLogo: `<path d="m15.727 5.0652c-0.29907 0-0.59814 0.11064-0.8246 0.33109l-7.685 7.4798c-0.057048 0.05573-0.11237 0.11719-0.16596 0.18521-0.053591 0.0672-0.10545 0.13932-0.15472 0.21635a3.6658 3.4756 0 0 0-0.47886 1.2465c-0.00259 0.01558-0.00778 0.03196-0.00865 0.04672-0.011237 0.08441-0.017287 0.16636-0.017287 0.24504v6.8151c0 0.62448 0.52467 1.1359 1.1669 1.1359h7.1777l-3.1601-3.0765a1.5463 1.4661 0 0 1-0.51689 0.08523c-0.87906 0-1.5947-0.69659-1.5947-1.5522 0-0.85558 0.71569-1.5522 1.5947-1.5522s1.5947 0.69659 1.5947 1.5522c0 0.1762-0.03199 0.34502-0.08817 0.50319l2.4608 2.3955v-8.7754a1.6423 1.5571 0 0 1-0.89461-1.3932c0-0.85476 0.71569-1.5514 1.5947-1.5514 0.87906 0 1.5947 0.69659 1.5947 1.5522 0 0.61136-0.36562 1.1391-0.89462 1.3924v6.1546l2.447-2.3823a1.6795 1.5923 0 0 1-0.07434-0.46959c0-0.8564 0.71569-1.553 1.5947-1.553 0.87906 0 1.5947 0.69659 1.5947 1.553 0 0.85558-0.71569 1.5522-1.5947 1.5522-0.19448 0-0.38032-0.03606-0.55146-0.09834l-3.416 3.3256v2.3373h7.4681c0.56184 0 1.0338-0.39091 1.1427-0.90721 0.01556-0.07375 0.0242-0.14997 0.0242-0.22783v-6.8151a2.0313 1.9259 0 0 0-0.01728-0.24422 3.6459 3.4567 0 0 0-0.4875-1.2932 2.7832 2.6389 0 0 0-0.15472-0.21717 2.0399 1.9341 0 0 0-0.16596-0.18439l-7.685-7.4806a1.1479 1.0883 0 0 0-0.8246-0.33191z"/>`,
};
} else {
const logoHeight = 14;
const y = (badgeHeight - logoHeight) / 2;
const x = horizPadding;
return {
totalLogoWidth: logoWidth + logoPadding,
renderedLogo: `<image x="${x}" y="${y}" width="${logoWidth}" height="${logoHeight}" xlink:href="${escapeXml(
logo
)}"/>`,
};
}
}

function createAccessibleText({ label, message }) {
const labelPrefix = label ? `${label}: ` : "";
return labelPrefix + message;
function createAccessibleText(message) {
return message + " My Home Assistant";
}

function renderAriaAttributes({ accessibleText }) {
Expand All @@ -68,125 +31,63 @@ function renderTitle({ accessibleText }) {
return `<title>${escapeXml(accessibleText)}</title>`;
}

function renderBadge({ leftWidth, rightWidth, height, accessibleText }, main) {
const width = leftWidth + rightWidth;

function renderBadge({ width, height, accessibleText }, main) {
return `
<svg
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="${width}"
height="${height}"
style="border-radius: 4px;"
width="${width / 2}"
height="${height / 2}"
viewBox="0 0 ${width} ${height}"
${renderAriaAttributes({ accessibleText })}
style="border-radius:24px"
>
${renderTitle({ accessibleText })}
${main}
</svg>`;
${renderTitle({ accessibleText })}
<rect width="${width}" height="${height}" rx="48" fill="#18BCF2"/>
${main}
<g style="transform: translate(${width - 497}px, 0);">
<rect x="344" y="16" width="137" height="64" rx="32" fill="#F2F4F9"/>
<path d="M394.419 37.0469V60.5H390.122V46.7969L384.716 60.5H380.559L375.216 46.9062V60.5H371.028V37.0469H375.216L382.638 55.4062L390.122 37.0469H394.419ZM403.784 37.0469L409.128 46.9375L414.472 37.0469H419.238L411.269 51.1875V60.5H406.878V51.1875L398.847 37.0469H403.784Z" fill="#18BCF2"/>
<g>
<path d="M457 60C457 61.65 455.65 63 454 63H430C428.35 63 427 61.65 427 60V51C427 49.35 427.95 47.05 429.12 45.88L439.88 35.12C441.05 33.95 442.96 33.95 444.12 35.12L454.88 45.88C456.05 47.05 457 49.35 457 51V60Z" fill="#18BCF2"/>
<path d="M442 45.5C443.105 45.5 444 44.6046 444 43.5C444 42.3954 443.105 41.5 442 41.5C440.895 41.5 440 42.3954 440 43.5C440 44.6046 440.895 45.5 442 45.5Z" fill="#F2F4F9" stroke="#F2F4F9"/>
<path d="M449.5 53.5C450.605 53.5 451.5 52.6046 451.5 51.5C451.5 50.3954 450.605 49.5 449.5 49.5C448.395 49.5 447.5 50.3954 447.5 51.5C447.5 52.6046 448.395 53.5 449.5 53.5Z" fill="#F2F4F9" stroke="#F2F4F9" stroke-miterlimit="10"/>
<path d="M434.5 57.5C435.605 57.5 436.5 56.6046 436.5 55.5C436.5 54.3954 435.605 53.5 434.5 53.5C433.395 53.5 432.5 54.3954 432.5 55.5C432.5 56.6046 433.395 57.5 434.5 57.5Z" fill="#F2F4F9" stroke="#F2F4F9" stroke-miterlimit="10"/>
<path d="M442 43.48V63L434.5 55.5" stroke="#F2F4F9" fill="none" stroke-width="2.25" stroke-miterlimit="10"/>
<path d="M449.5 51.46L442.09 58.87" stroke="#F2F4F9" fill="none" stroke-width="2.25" stroke-miterlimit="10"/>
</g>
</g>
</svg>`;
}

function myBadge({
label = "my",
message,
logo,
logoWidth,
logoPadding = 4,
color = "#03a9f4",
labelColor,
}) {
// For the Badge is styled in all caps. Convert to caps here so widths can
// be measured using the correct characters.
label = label.toUpperCase();
message = message.toUpperCase();
const height = 96;

let labelWidth = preferredWidthOf(label, { font: "10px Verdana" }) || 0;
let messageWidth =
preferredWidthOf(message, { font: "bold 10px Verdana" }) || 0;
const height = 28;
const hasLabel = label.length || labelColor;
if (labelColor == null) {
labelColor = "#555";
}
const horizPadding = 9;
const { totalLogoWidth, renderedLogo } = renderLogo({
logo,
badgeHeight: height,
horizPadding,
logoWidth,
logoPadding,
});

labelWidth += 10 + totalLogoWidth;
if (label.length) {
// Add 10 px of padding, plus approximately 1 px of letter spacing per
// character.
labelWidth += 10 + 2 * label.length;
} else {
if (hasLabel) {
labelWidth += 7;
} else {
labelWidth -= 7;
}
}

// Add 20 px of padding, plus approximately 1.5 px of letter spacing per
// character.
messageWidth += 20 + 1.5 * message.length;
const leftWidth = !hasLabel ? 0 : labelWidth - 1.5;
const rightWidth = !hasLabel ? messageWidth + labelWidth : messageWidth;

color = escapeXml(color);
labelColor = escapeXml(labelColor);

const accessibleText = createAccessibleText({ label, message });

function renderLabelText() {
const textColor = "#fff";
if (label === "MY") {
return `
<g style="stroke-width: .3; stroke: ${textColor};">
<path d="m 31.903106,15.269123 0.04782,0.872727 q 0,0.07173 -0.01195,0.263013 0,0.191283 -0.143462,0.3467 -0.131507,0.143462 -0.334745,0.143462 -0.191281,0 -0.298878,-0.01195 -0.394521,0 -0.394521,-0.3467 0,-0.286923 0.263014,-2.307346 0.263013,-2.032378 0.334744,-2.618181 0.07173,-0.585803 0.119551,-0.980323 0.05978,-0.406476 0.08368,-0.597758 0.02391,-0.1912835 0.07173,-0.3825665 0.04782,-0.191282 0.143462,-0.310834 0.179327,-0.2271482 0.693399,-0.2271482 0.860772,0.4303862 1.769365,2.4388537 0.645578,1.43462 0.860771,1.817186 0.215194,0.382564 0.418431,0.526027 L 37.91655,9.7338865 q 0.251059,-0.179327 0.382565,-0.179327 0.382566,0 0.585804,0.3467 0.203237,0.3467005 0.334744,0.8488165 0.143462,0.490162 0.239103,1.087921 0.107597,0.597757 0.179327,1.255291 0.08369,0.64558 0.155417,1.267248 0.167373,1.494396 0.251059,1.87696 0.09564,0.382566 0.09564,0.549939 0,0.155417 -0.107596,0.310834 -0.107596,0.14346 -0.298879,0.14346 -0.191283,0 -0.382565,-0.14346 -0.191284,-0.155418 -0.239104,-0.370611 -0.03587,-0.227148 -0.08368,-0.585804 -0.03587,-0.358654 -0.09564,-0.800995 -0.05978,-0.454296 -0.119551,-0.944458 -0.05978,-0.502117 -0.119552,-0.956413 -0.05978,-0.454296 -0.107597,-0.800996 -0.04782,-0.358655 -0.07173,-0.537982 0,-0.239104 -0.01195,-0.442342 -0.01195,-0.203237 -0.09564,-0.251058 -0.08368,-0.04782 -0.263014,0.119552 -0.167372,0.155416 -0.478206,0.645579 -0.669489,1.040099 -1.936737,3.502862 -0.167372,0.298879 -0.442341,0.131508 -0.32279,-0.179329 -0.549937,-0.920548 L 32.536731,10.21209 q -0.286924,0.573847 -0.526027,3.801741 -0.03587,0.394521 -0.04782,0.66949 -0.05978,0.298879 -0.05978,0.585802 z"/>
<path d="m 44.006573,21.772732 q -0.251058,0.561893 -0.597757,0.561893 -0.167373,0 -0.251059,-0.155418 -0.07173,-0.143461 0,-0.346699 0.263014,-1.11183 0.753175,-2.534494 0.502117,-1.422665 0.66949,-1.912827 -0.418431,-0.418431 -1.315068,-1.673722 -1.841096,-2.582316 -1.841096,-2.833374 0,-0.01195 0.01196,-0.02391 l 0.454293,-0.454296 q 0.944458,0.872727 2.462764,2.96488 0.382565,0.526028 0.609713,0.884683 0.251058,-0.502118 0.39452,-0.860773 0.143462,-0.37061 0.227149,-0.585803 0.09564,-0.227147 0.251058,-0.597758 0.406475,-0.992279 1.123786,-2.522539 0.107595,-0.04782 0.227148,-0.04782 0.298878,0 0.430386,0.155416 0.04782,0.05978 0.04782,0.143463 0,0.07173 -0.02391,0.143462 z"/>
<path d="m 31.140745,18.796586 h 10.004768 c 0.279767,0 0.570315,0.05509 0.570315,0.357096 0,0.301994 -0.290558,0.73578 -0.570315,0.733141 l -9.961222,-0.09401 c -0.279756,-0.0026 -0.39613,-0.14911 -0.39613,-0.451105 0,-0.301995 0.07281,-0.545119 0.352584,-0.545119 z"/>
</g>`;
}
const labelTextX = ((labelWidth + totalLogoWidth) / 2) * 10;
const labelTextLength = (labelWidth - (24 + totalLogoWidth)) * 10;
const escapedLabel = escapeXml(label);

const text = `<text fill="${textColor}" x="${labelTextX}" y="175" transform="scale(.1)" textLength="${labelTextLength}">${escapedLabel}</text>`;
return text;
}
const accessibleText = createAccessibleText(message);

function renderMessageText() {
const textColor = "#fff";

const text = `<text fill="${textColor}" x="${(leftWidth + messageWidth / 2) * 10
}" y="175" font-weight="bold" transform="scale(.1)" textLength="${(messageWidth - 24) * 10
}">${escapeXml(message)}</text>`;
message = message.toUpperCase();

return text;
}
const { metrics, svg } = renderMessagePath(message, { x: 40, y: 46.8, fontSize: 33.5, letterSpacing: .02, anchor: 'left middle', attributes: { fill: "white" } });

return renderBadge(
{
leftWidth,
rightWidth,
width: Math.round(metrics.width + 40 + 173),
accessibleText,
height,
},
` <g shape-rendering="crispEdges">
<rect width="${leftWidth}" height="${height}" fill="${labelColor}"/>
<rect x="${leftWidth}" width="${rightWidth}" height="${height}" fill="${color}"/>
</g>
<g fill="#fff" text-anchor="middle" ${fontFamily} text-rendering="geometricPrecision" font-size="100">
${renderedLogo}
${hasLabel ? renderLabelText() : ""}
${renderMessageText()}
</g>`
svg
);
}

function renderMessagePath(message, options) {
const textToSVG = TextToSVG.loadSync('build-scripts/fonts/Figtree-Bold.otf');
const svg = textToSVG.getPath(message, options);
const metrics = textToSVG.getMetrics(message, options);
return { metrics, svg };
}

if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
Expand All @@ -205,4 +106,4 @@ redirects.forEach((redirect) =>
writeBadge(redirect.redirect, redirect.badge || redirect.name)
);

writeBadge("homeassistant", "Home Assistant");
// writeBadge("homeassistant", "Home Assistant");
Binary file added build-scripts/fonts/Figtree-Bold.otf
Binary file not shown.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-typescript": "^11.1.4",
"anafanafo": "^2.0.0",
"gulp": "^4.0.2",
"pre-commit": "^1.2.2",
"prettier": "^3.0.3",
Expand All @@ -29,6 +28,7 @@
"rollup-plugin-terser": "^7.0.2",
"serve": "^14.2.1",
"svgo": "^3.0.2",
"text-to-svg": "^3.1.5",
"typescript": "^5.2.2"
},
"dependencies": {
Expand Down
14 changes: 0 additions & 14 deletions public/badges/add_matter_device-new.svg

This file was deleted.

Loading

0 comments on commit 9f9d2b8

Please sign in to comment.