Skip to content

Commit

Permalink
feat: manually generate card
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioRibera committed Mar 23, 2024
1 parent 1ae2a58 commit 2ad2177
Show file tree
Hide file tree
Showing 9 changed files with 886 additions and 187 deletions.
Binary file modified bun.lockb
Binary file not shown.
56 changes: 43 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"license": "ISC",
"devDependencies": {
"node-fetch": "^3.3.2",
"typescript": "^5.2.2"
"emoji-name-map": "^1.2.8",
"word-wrap": "^1.2.5"
}
}
270 changes: 270 additions & 0 deletions scripts/card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
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.
* @param {object?=} args.colors Card colors arguments.
* @param {string} args.colors.titleColor Card title color.
* @param {string} args.colors.textColor Card text color.
* @param {string} args.colors.iconColor Card icon color.
* @param {string|Array} args.colors.bgColor Card background color.
* @param {string} args.colors.borderColor Card border color.
* @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(defaultTitle)
: encodeHTML(customTitle);

this.css = "";

this.paddingX = 25;
this.paddingY = 35;
this.titlePrefixIcon = titlePrefixIcon;
this.animations = true;
this.a11yTitle = "";
this.a11yDesc = "";
}

/**
* @returns {void}
*/
disableAnimations() {
this.animations = false;
}

/**
* @param {Object} props The props object.
* @param {string} props.title Accessibility title.
* @param {string} props.desc Accessibility description.
* @returns {void}
*/
setAccessibilityLabel({ title, desc }) {
this.a11yTitle = title;
this.a11yDesc = desc;
}

/**
* @param {string} value The CSS to add to the card.
* @returns {void}
*/
setCSS(value) {
this.css = value;
}

/**
* @param {boolean} value Whether to hide the border or not.
* @returns {void}
*/
setHideBorder(value) {
this.hideBorder = value;
}

/**
* @param {boolean} value Whether to hide the title or not.
* @returns {void}
*/
setHideTitle(value) {
this.hideTitle = value;
if (value) {
this.height -= 30;
}
}

/**
* @param {string} text The title to set.
* @returns {void}
*/
setTitle(text) {
this.title = text;
}

/**
* @returns {string} The rendered card title.
*/
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>
`;
}

/**
* @returns {string} The rendered card gradient.
*/
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>
`
: "";
}

/**
* Retrieves css animations for a card.
*
* @returns {string} Animation css.
*/
getAnimations = () => {
return `
/* Animations */
@keyframes scaleInAnimation {
from {
transform: translate(-5px, 5px) scale(0);
}
to {
transform: translate(-5px, 5px) scale(1);
}
}
@keyframes fadeInAnimation {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
`;
};

/**
* @param {string} body The inner body of the card.
* @returns {string} The rendered card.
*/
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" ? "" : this.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;
27 changes: 27 additions & 0 deletions scripts/fetch-repo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import fetch from "node-fetch"

const fetchRepo = async (username, reponame) => {
let res = await fetch(`https://api.github.com/repos/${username}/${reponame}`);
let data = await res.json()

if (!data) {
throw new Error("Not found");
}

if (!data.html_url || data.private) {
throw new Error("User Repository Not found");
}

return {
name: data.name,
nameWithOwner: data.full_name,
description: data.description,
primaryLanguage: data.language,
isArchived: data.archived,
isTemplate: data.is_template,
starCount: data.stargazers_count,
forkCount: data.forks,
}
};

export default fetchRepo;
Loading

0 comments on commit 2ad2177

Please sign in to comment.