-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: created SVG document components
- Loading branch information
1 parent
66f37a5
commit 12c4ee8
Showing
17 changed files
with
474 additions
and
82 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
export const IssueIcon = () => ( | ||
<svg | ||
aria-hidden="true" | ||
height="16" | ||
viewBox="0 0 16 16" | ||
version="1.1" | ||
width="16" | ||
className="icon" | ||
> | ||
<path d="M8 9.5a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path> | ||
<path | ||
fillRule="evenodd" | ||
d="M8 0a8 8 0 100 16A8 8 0 008 0zM1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0z" | ||
></path> | ||
</svg> | ||
); | ||
|
||
export const PullRequestIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M12.7 10.1V5.3C12.7 4.3 12 2.7 10 2.7V1.3l-2.7 2 2.7 2V4c1.2 0 1.3 1 1.3 1.3v4.8c-1 0.3-1.7 1.2-1.6 2.2 0 1.3 1 2.3 2.3 2.4s2.3-1 2.3-2.4c0-1.1-0.7-1.9-1.6-2.2z m-0.7 3.2c-0.6 0-1-0.4-1-1s0.4-1 1-1 1 0.4 1 1-0.4 1-1 1zM6.3 3.7C6.3 2.4 5.3 1.3 4 1.3S1.7 2.4 1.7 3.7c0 1.1 0.7 1.9 1.6 2.2v4.2c-1 0.3-1.7 1.2-1.6 2.2C1.7 13.6 2.7 14.7 4 14.7s2.3-1 2.3-2.4c0-1.1-0.7-1.9-1.6-2.2V5.9C5.6 5.6 6.3 4.7 6.3 3.7z m-3.3 0C3 3.1 3.4 2.7 4 2.7s1 0.4 1 1S4.6 4.7 4 4.7s-1-0.4-1-1z m2 8.6c0 0.6-0.4 1-1 1s-1-0.4-1-1S3.4 11.3 4 11.3s1 0.4 1 1z" /> | ||
</svg> | ||
); | ||
|
||
export const MergeIcon = () => ( | ||
<svg | ||
viewBox="0 0 16 16" | ||
width="16" | ||
height="16" | ||
fill="currentColor" | ||
className="icon" | ||
> | ||
<path d="M1.7 12.3C1.7 13.6 2.7 14.7 4 14.7s2.3-1 2.3-2.4c0-1.1-0.7-1.9-1.6-2.2v-2.3c0.2 0.2 0.3 0.4 0.5 0.5 0.8 0.6 1.7 0.7 2.6 0.7 0.6 0 1.2-0.1 1.7-0.2a2.3 2.3 0 0 0 2.2 1.5c1.3 0 2.3-1 2.3-2.3s-1-2.3-2.3-2.3a2.3 2.3 0 0 0-2.3 1.8c-0.9 0.2-2.4 0.4-3.4-0.3-0.4-0.3-0.7-0.8-0.9-1.5C5.8 5.3 6.3 4.5 6.3 3.7 6.3 2.4 5.3 1.3 4 1.3S1.7 2.4 1.7 3.7c0 1.1 0.7 1.9 1.6 2.2v4.2c-1 0.3-1.7 1.2-1.6 2.2z m10-5.3c0.6 0 1 0.4 1 1s-0.4 1-1 1S10.7 8.6 10.7 8s0.4-1 1-1z m-6.7 5.3c0 0.6-0.4 1-1 1s-1-0.4-1-1S3.4 11.3 4 11.3s1 0.4 1 1z m-2-8.6C3 3.1 3.4 2.7 4 2.7s1 0.4 1 1S4.6 4.7 4 4.7s-1-0.4-1-1z" /> | ||
</svg> | ||
); | ||
|
||
export const CommitIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M11.3 7.3a3.3 3.3 0 0 0-6.6 0H1.3v1.4h3.4a3.3 3.3 0 0 0 6.6 0H14.7v-1.4h-3.4zM8 10c-1.1 0-2-0.9-2-2s0.9-2 2-2 2 0.9 2 2-0.9 2-2 2z" /> | ||
</svg> | ||
); | ||
|
||
export const RepositoryIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M12.3 2C13.3 2 14 2.7 14 3.7L14 12.3C14 13.3 13.3 14 12.3 14L3.7 14C2.7 14 2 13.3 2 12.3L2 3.7C2 2.8 2.7 2 3.6 2 3.6 2 6.5 2 12.3 2ZM3.7 2.7C3.1 2.7 2.7 3.1 2.7 3.7L2.7 12.3C2.7 12.9 3.1 13.3 3.7 13.3L12.3 13.3C12.9 13.3 13.3 12.9 13.3 12.3L13.3 3.7C13.3 3.1 12.9 2.7 12.3 2.7L3.7 2.7ZM6.6 9.5C6.7 9.6 6.7 9.8 6.5 9.9 6.4 10 6.2 10 6.1 9.9L4.7 8.2C4.6 8.1 4.6 7.9 4.7 7.8L6.1 6.1C6.2 6 6.4 6 6.5 6.1 6.7 6.2 6.7 6.4 6.6 6.5L5.4 8 6.6 9.5ZM9.4 6.5C9.3 6.4 9.3 6.2 9.5 6.1 9.6 6 9.8 6 9.9 6.1L11.3 7.8C11.4 7.9 11.4 8.1 11.3 8.2L9.9 9.9C9.8 10 9.6 10 9.5 9.9 9.3 9.8 9.3 9.6 9.4 9.5L10.6 8 9.4 6.5Z" /> | ||
</svg> | ||
); | ||
|
||
export const JavaScriptIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M2 2h12v12H2V2z m11 9.1c-0.1-0.5-0.4-1-1.5-1.4-0.4-0.2-0.8-0.3-0.9-0.6 0-0.2-0.1-0.3 0-0.3 0.1-0.3 0.5-0.4 0.8-0.4 0.2 0.1 0.4 0.2 0.4 0.5 0.5-0.3 0.5-0.3 0.9-0.6-0.1-0.2-0.2-0.3-0.3-0.4-0.3-0.4-0.7-0.5-1.4-0.5l-0.3 0.1c-0.3 0.1-0.7 0.3-0.9 0.5-0.6 0.6-0.4 1.8 0.3 2.2 0.7 0.5 1.7 0.6 1.8 1.1 0.1 0.6-0.4 0.8-1 0.7-0.4-0.1-0.6-0.3-0.9-0.6l-0.9 0.5c0.1 0.2 0.2 0.3 0.4 0.5 0.9 0.9 3 0.8 3.5-0.5 0 0 0.1-0.4 0-0.8l0 0z m-4.5-3.6h-1.1c0 1 0 1.9 0 2.9 0 0.6 0 1.2-0.1 1.4-0.2 0.3-0.6 0.3-0.8 0.2-0.2-0.1-0.3-0.2-0.4-0.4 0-0.1-0.1-0.1 0-0.1l-0.9 0.5c0.2 0.3 0.4 0.6 0.6 0.8 0.4 0.3 1 0.3 1.6 0.2 0.4-0.1 0.7-0.3 0.9-0.7 0.3-0.5 0.2-1 0.2-1.7 0-1 0-2.1 0-3.1l0 0z" /> | ||
</svg> | ||
); | ||
|
||
export const PythonIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M6.4 7.8h2.9s1.6 0 1.6-1.6V3.6S11.1 2 8 2C4.9 2 5.1 3.3 5.1 3.3l0 1.4h2.9v0.4H3.9s-2-0.2-1.9 2.9 1.7 3 1.7 2.9h1v-1.4s-0.1-1.7 1.7-1.7z m0-3.8a0.5 0.5 0 1 1 0-1.1 0.5 0.5 0 1 1 0 1.1z" /> | ||
<path d="M12.3 5h-1v1.4s0.1 1.7-1.7 1.8h-2.9s-1.6 0-1.6 1.5v2.7s-0.2 1.6 2.9 1.5c3 0 2.9-1.3 2.9-1.3l0-1.3h-2.9v-0.5h4.1s2 0.2 1.9-2.8-1.7-3-1.7-3z m-2.7 7a0.5 0.5 0 1 1 0 1 0.5 0.5 0 1 1 0-1z" /> | ||
</svg> | ||
); | ||
|
||
export const TypeScriptIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M0 0v16h16V0H0z m9.2 6.9H6.9v7.1h-1.2V6.9h-2.3v-1.1h5.8v1.1z m4.7 6.4c-0.8 1-3 1.1-4.3 0.3v-1.6c0.7 0.8 1.4 0.9 2 1 1.7 0.1 1.8-1.3 1.1-2-1-0.8-3.1-1.3-3.1-3.1 0-1.3 1-2.2 2.5-2.2 0.6 0 1.4 0 1.9 0.3v1.5c-1.2-1.1-3.7-0.8-3.1 0.8 0.5 1 2.4 1.1 3.3 2.7 0.3 0.9 0.1 1.7-0.3 2.3z" /> | ||
</svg> | ||
); | ||
|
||
export const ScoreIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M7.2 2.1a0.4 0.4 0 0 0-0.8-0.2l-0.7 3.7H2.8a0.4 0.4 0 1 0 0 0.8h2.7l-0.6 3.2H2a0.4 0.4 0 0 0 0 0.8h2.7l-0.7 3.5a0.4 0.4 0 1 0 0.8 0.2l0.7-3.7h4L8.8 13.9a0.4 0.4 0 0 0 0.8 0.2l0.7-3.7h2.9a0.4 0.4 0 0 0 0-0.8H10.5l0.7-3.2h2.8a0.4 0.4 0 1 0 0-0.8h-2.7l0.8-3.5a0.4 0.4 0 1 0-0.8-0.2l-0.8 3.7H6.5l0.7-3.5ZM6.3 6.4h4.1l-0.7 3.2H5.7l0.6-3.2Z" /> | ||
</svg> | ||
); | ||
|
||
export const StarIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M8 1l-2.3 4.6-5.1 0.7 3.7 3.6L3.5 15l4.5-2.4L12.6 15l-0.9-5.1 3.7-3.6-5.1-0.7Z" /> | ||
</svg> | ||
); | ||
|
||
export const CodeIcon = () => ( | ||
<svg viewBox="0 0 16 16" width="16" height="16" className="icon"> | ||
<path d="M5.1 12.4L0 8l5.1-4.4 0.8 1L2 8l3.9 3.4-0.8 1z m5.8 0l-0.8-1L14 8 10.1 4.6l0.8-1L16 8 10.9 12.4zM6.9 13.8L5.7 13.4 9.1 2.2 10.3 2.6 6.9 13.8z" /> | ||
</svg> | ||
); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import * as Icons from "@components/icons"; | ||
import { | ||
Document, | ||
DocumentTitle, | ||
List, | ||
ListItem, | ||
} from "@components/svgs/document"; | ||
import { ObjectEntries } from "@utils"; | ||
|
||
export const getUser = (result: any, platform: any) => { | ||
const langs = ObjectEntries(result.ranks.languages).map(([key, value]) => ({ | ||
lang: key, | ||
...value, | ||
})); | ||
|
||
const langItems = langs.map((lang, index) => ( | ||
<ListItem | ||
key={index} | ||
icon={<Icons.CodeIcon />} | ||
text={lang.lang as string} | ||
value={lang.score} | ||
/> | ||
)); | ||
|
||
return ( | ||
<Document width={210} height={200}> | ||
<DocumentTitle>Codewars</DocumentTitle> | ||
<List> | ||
<ListItem icon={<Icons.StarIcon />} text="Honor" value={result.honor} /> | ||
<ListItem | ||
icon={<Icons.ScoreIcon />} | ||
text="Overall Score" | ||
value={result.ranks.overall.score} | ||
/> | ||
{langItems} | ||
</List> | ||
</Document> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
import { ReactElement } from "react"; | ||
|
||
export const getDocumentStyle = () => { | ||
return `<style> | ||
svg{ border: 1px solid #ccc; border-radius: 10px; } | ||
.header { font: 600 18px 'Segoe UI', Ubuntu, Sans-Serif; fill: #2f80ed; animation: fadeInAnimation 0.8s ease-in-out forwards; } | ||
.stat { text-transform: capitalize; font: 600 14px 'Segoe UI', Ubuntu, "Helvetica Neue", Sans-Serif; fill: #434d58; } | ||
.stagger { opacity: 0; animation: fadeInAnimation 0.3s ease-in-out forwards; } | ||
.rank-text { font: 800 24px 'Segoe UI', Ubuntu, Sans-Serif; fill: #434d58; animation: scaleInAnimation 0.3s ease-in-out forwards; } | ||
.not_bold { font-weight: 400 } | ||
.bold { font-weight: 700 } | ||
.icon { fill: #4c71f2; display: block; } | ||
.rank-circle-rim { stroke: #2f80ed; fill: none; stroke-width: 6; opacity: 0.2; } | ||
.rank-circle { stroke: #2f80ed; stroke-dasharray: 250; fill: none; stroke-width: 6; stroke-linecap: round; opacity: 0.8; transform-origin: -10px 8px; transform: rotate(-90deg); animation: rankAnimation 1s forwards ease-in-out; } | ||
@supports(-moz-appearance: auto) { /* Selector detects Firefox */ .header { font-size: 15.5px; } } | ||
@supports(-moz-appearance: auto) { /* Selector detects Firefox */ .stat { font-size:12px; } } | ||
/* Animations */ | ||
@keyframes rankAnimation { from { stroke-dashoffset: 251.32741228718345; } to { stroke-dashoffset: 127.57536535528702; } } | ||
@keyframes scaleInAnimation { from { transform: translate(-5px, 5px) scale(0); } to { transform: translate(-5px, 5px) scale(1); } } | ||
@keyframes fadeInAnimation { from { opacity: 0; } to { opacity: 1; } } | ||
</style>`; | ||
}; | ||
|
||
type IDocument = { | ||
(props: { | ||
width: number; | ||
height: number; | ||
children: JSX.Element | JSX.Element[]; | ||
}): JSX.Element; | ||
}; | ||
|
||
type IDocumentHeader = { | ||
(props: { title: string; desc: string }): JSX.Element; | ||
}; | ||
|
||
type IDocumentTitle = { | ||
(props: { children: string }): JSX.Element; | ||
}; | ||
|
||
type IList = { | ||
(props: { children: any }): JSX.Element; | ||
}; | ||
|
||
export type IListItem = { | ||
(props: IItem): JSX.Element; | ||
}; | ||
|
||
type IItem = { | ||
icon: JSX.Element; | ||
url?: string; | ||
text: string; | ||
value?: string; | ||
index?: number; | ||
gap?: number; | ||
}; | ||
|
||
export const Document: IDocument = ({ width, height, children }) => { | ||
return ( | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
xmlnsXlink="http://www.w3.org/1999/xlink" | ||
width={width} | ||
height={height} | ||
> | ||
{getDocumentStyle()} | ||
|
||
{/* <DocumentHeader title={title} desc={desc} /> */} | ||
{/* <DocumentBackground /> */} | ||
{children} | ||
</svg> | ||
); | ||
}; | ||
|
||
export const DocumentTitle: IDocumentTitle = ({ children }) => { | ||
return ( | ||
<g data-testid="card-title" transform="translate(25, 35)"> | ||
<g transform="translate(0, 0)"> | ||
<text x="0" y="0" className="header" data-testid="header"> | ||
{children} | ||
</text> | ||
</g> | ||
</g> | ||
); | ||
}; | ||
|
||
export const DocumentHeader: IDocumentHeader = ({ title, desc }) => { | ||
return ( | ||
<> | ||
<title id="titleId">{title}</title> | ||
<desc id="descId">{desc}</desc> | ||
</> | ||
); | ||
}; | ||
|
||
export const DocumentBackground = () => { | ||
return ( | ||
<rect | ||
data-testid="card-bg" | ||
x="0.5" | ||
y="0.5" | ||
rx="4.5" | ||
width="500" | ||
height="120" | ||
stroke="#e4e2e2" | ||
fill="#fffefe" | ||
strokeOpacity="1" | ||
/> | ||
); | ||
}; | ||
|
||
export const List: IList = ({ children }) => { | ||
if (Array.isArray(children)) children = children.flat(); | ||
|
||
if (!Array.isArray(children)) children = [children]; | ||
|
||
const makeTitleShort = ( | ||
element: ReactElement<IItem, IListItem> | ||
): JSX.Element => { | ||
return { | ||
...element, | ||
props: { | ||
...element.props, | ||
value: | ||
element.props?.value && String(element.props.value).length > 45 | ||
? String(element.props.value).slice(0, 45) + "..." | ||
: String(element.props.value), | ||
}, | ||
}; | ||
}; | ||
|
||
const calculateGap = (elements: ReactElement<IItem, IListItem>[]) => { | ||
if (!children) { | ||
return []; | ||
} | ||
const gap = | ||
elements | ||
.map((child) => child.props.text.length * 6.7) | ||
.reduce((a, b) => Math.max(a, b), 0) + 45; | ||
return elements.map((child, index) => ({ | ||
...child, | ||
props: { ...child.props, index, gap: gap }, | ||
})); | ||
}; | ||
|
||
children = calculateGap(children.map(makeTitleShort)); | ||
|
||
return ( | ||
<g data-testid="main-card-body" transform="translate(0, 55)"> | ||
<svg x="0" y="0"> | ||
{children} | ||
</svg> | ||
</g> | ||
); | ||
}; | ||
|
||
export const ListItem: IListItem = ({ | ||
index = 0, | ||
gap = 0, | ||
icon, | ||
text, | ||
value, | ||
url, | ||
}) => { | ||
return ( | ||
<g transform={`translate(0, ${index * 25})`}> | ||
<g | ||
className="stagger" | ||
style={{ animationDelay: `${450 + 150 * index}ms` }} | ||
transform="translate(25, 0)" | ||
> | ||
<g className="item-info"> | ||
{icon} | ||
<text className="stat bold" x="25" y="12.5"> | ||
{text} | ||
</text> | ||
</g> | ||
|
||
{url ? ( | ||
<a href={url} target="_blank" rel="noopener noreferrer"> | ||
<text className="stat bold" x={gap} y="12.5"> | ||
{value} | ||
</text> | ||
</a> | ||
) : ( | ||
<text className="stat bold" x={gap} y="12.5"> | ||
{value} | ||
</text> | ||
)} | ||
</g> | ||
</g> | ||
); | ||
}; |
Oops, something went wrong.
12c4ee8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
devstats – ./
devstats-git-main-sametcodes.vercel.app
developerstats.vercel.app
devstats-zeta.vercel.app
0devstats.vercel.app
devstats-sametcodes.vercel.app