UNPKG

@zo-bro-23/github-readme-stats-test

Version:

Dynamically generate stats for your GitHub readme

223 lines (199 loc) 5.15 kB
import { getAnimations } from "../getStyles.js"; import { encodeHTML, flexLayout } from "./utils.js"; class Card { /** * Creates a new card instance. * * @param {object} args Card arguments. * @param {number?=} args.width Card width. * @param {number?=} args.height Card height. * @param {number?=} args.border_radius Card border radius. * @param {string?=} args.customTitle Card custom title. * @param {string?=} args.defaultTitle Card default title. * @param {string?=} args.titlePrefixIcon Card title prefix icon. * @returns {Card} Card instance. */ constructor({ width = 100, height = 100, border_radius = 4.5, colors = {}, customTitle, defaultTitle = "", titlePrefixIcon, }) { this.width = width; this.height = height; this.hideBorder = false; this.hideTitle = false; this.border_radius = border_radius; // returns theme based colors with proper overrides and defaults this.colors = colors; this.title = customTitle !== undefined ? encodeHTML(customTitle) : encodeHTML(defaultTitle); this.css = ""; this.paddingX = 25; this.paddingY = 35; this.titlePrefixIcon = titlePrefixIcon; this.animations = true; this.a11yTitle = ""; this.a11yDesc = ""; } disableAnimations() { this.animations = false; } /** * @param {{title: string, desc: string}} prop */ setAccessibilityLabel({ title, desc }) { this.a11yTitle = title; this.a11yDesc = desc; } /** * @param {string} value */ setCSS(value) { this.css = value; } /** * @param {boolean} value */ setHideBorder(value) { this.hideBorder = value; } /** * @param {boolean} value */ setHideTitle(value) { this.hideTitle = value; if (value) { this.height -= 30; } } /** * @param {string} text */ setTitle(text) { this.title = text; } renderTitle() { const titleText = ` <text x="0" y="0" class="header" data-testid="header" >${this.title}</text> `; const prefixIcon = ` <svg class="icon" x="0" y="-13" viewBox="0 0 16 16" version="1.1" width="16" height="16" > ${this.titlePrefixIcon} </svg> `; return ` <g data-testid="card-title" transform="translate(${this.paddingX}, ${this.paddingY})" > ${flexLayout({ items: [this.titlePrefixIcon && prefixIcon, titleText], gap: 25, }).join("")} </g> `; } renderGradient() { if (typeof this.colors.bgColor !== "object") return ""; const gradients = this.colors.bgColor.slice(1); return typeof this.colors.bgColor === "object" ? ` <defs> <linearGradient id="gradient" gradientTransform="rotate(${this.colors.bgColor[0]})" gradientUnits="userSpaceOnUse" > ${gradients.map((grad, index) => { let offset = (index * 100) / (gradients.length - 1); return `<stop offset="${offset}%" stop-color="#${grad}" />`; })} </linearGradient> </defs> ` : ""; } /** * @param {string} body */ render(body) { return ` <svg width="${this.width}" height="${this.height}" viewBox="0 0 ${this.width} ${this.height}" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="descId" > <title id="titleId">${this.a11yTitle}</title> <desc id="descId">${this.a11yDesc}</desc> <style> .header { font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${this.colors.titleColor}; animation: fadeInAnimation 0.8s ease-in-out forwards; } @supports(-moz-appearance: auto) { /* Selector detects Firefox */ .header { font-size: 15.5px; } } ${this.css} ${process.env.NODE_ENV === "test" ? "" : getAnimations()} ${ this.animations === false ? `* { animation-duration: 0s !important; animation-delay: 0s !important; }` : "" } </style> ${this.renderGradient()} <rect data-testid="card-bg" x="0.5" y="0.5" rx="${this.border_radius}" height="99%" stroke="${this.colors.borderColor}" width="${this.width - 1}" fill="${ typeof this.colors.bgColor === "object" ? "url(#gradient)" : this.colors.bgColor }" stroke-opacity="${this.hideBorder ? 0 : 1}" /> ${this.hideTitle ? "" : this.renderTitle()} <g data-testid="main-card-body" transform="translate(0, ${ this.hideTitle ? this.paddingX : this.paddingY + 20 })" > ${body} </g> </svg> `; } } export { Card }; export default Card;