Skip to content

Commit ef320cd

Browse files
committed
Initial commit
0 parents  commit ef320cd

File tree

9 files changed

+2934
-0
lines changed

9 files changed

+2934
-0
lines changed

.github/workflows/publish.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Publish on NPM
2+
on:
3+
schedule:
4+
- cron: "0 10 * * *"
5+
push:
6+
env:
7+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
8+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
9+
jobs:
10+
publish:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- uses: actions/setup-node@v2
15+
with:
16+
node-version: "14"
17+
- name: Install dependencies
18+
run: yarn
19+
- name: Run publish script
20+
run: yarn release

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
yarn-error.log
3+
tmp
4+
dist
5+
.env
6+
react-devicons.zip

babel.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
presets: ["@babel/preset-react", "babel-preset-minify"],
3+
plugins: ["@babel/plugin-transform-parameters"],
4+
};

index.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import degit from "degit";
2+
import fs from "fs";
3+
import fsAsync from "fs/promises";
4+
import { JSDOM } from "jsdom";
5+
import { exec } from "child_process";
6+
import svgtojsx from "svg-to-jsx";
7+
8+
interface ConfigEntry {
9+
name: string;
10+
tags: string[];
11+
versions: {
12+
svg: string[];
13+
font: string[];
14+
};
15+
color: string;
16+
aliases: {
17+
base: string;
18+
alias: string;
19+
}[];
20+
}
21+
22+
(async () => {
23+
const index: [string, string][] = [];
24+
25+
if (fs.existsSync(`${__dirname}/tmp`))
26+
fs.rmSync(`${__dirname}/tmp`, { recursive: true });
27+
if (fs.existsSync(`${__dirname}/dist`))
28+
fs.rmSync(`${__dirname}/dist`, { recursive: true });
29+
fsAsync.mkdir(`${__dirname}/tmp`);
30+
31+
await degit("https://github.com/devicons/devicon.git").clone(
32+
`${__dirname}/tmp/devicon`
33+
);
34+
35+
const deviconConfig: ConfigEntry[] = JSON.parse(
36+
(await fsAsync.readFile(`${__dirname}/tmp/devicon/devicon.json`)).toString()
37+
);
38+
39+
await fsAsync.mkdir(`${__dirname}/tmp/dist`);
40+
await fsAsync.copyFile(
41+
`${__dirname}/readme.md`,
42+
`${__dirname}/tmp/dist/readme.md`
43+
);
44+
await fsAsync.copyFile(
45+
`${__dirname}/package.json`,
46+
`${__dirname}/tmp/dist/package.json`
47+
);
48+
49+
await Promise.all(
50+
deviconConfig.map(async (entry) => {
51+
await fsAsync.mkdir(`${__dirname}/tmp/dist/${entry.name}`);
52+
await Promise.all(
53+
entry.versions.svg.map(async (version) => {
54+
const name = `${entry.name}-${version}`;
55+
const icon = await fsAsync.readFile(
56+
`${__dirname}/tmp/devicon/icons/${entry.name}/${name}.svg`
57+
);
58+
const { document } = new JSDOM(icon).window;
59+
const dir = `${__dirname}/tmp/dist/${entry.name}/${version}`;
60+
const reactName =
61+
name
62+
.split("-")
63+
.map((el) => el.charAt(0).toUpperCase() + el.slice(1))
64+
.join("") + "Icon";
65+
index.push([reactName, `./${entry.name}/${version}`]);
66+
await fsAsync.mkdir(dir);
67+
// await fsAsync.writeFile(
68+
// `${dir}/index.js`,
69+
// `export { default } from "./${reactName}"`
70+
// );
71+
const svg = document.getElementsByTagName("svg")[0];
72+
svg.removeAttribute("width");
73+
svg.removeAttribute("height");
74+
svg.removeAttribute("xmlns:xlink");
75+
const isPlain =
76+
version.includes("plain") ||
77+
version.includes("line") ||
78+
!!entry.aliases.find(
79+
(x) =>
80+
x.base == version &&
81+
(x.alias.includes("plain") || x.alias.includes("line"))
82+
);
83+
if (isPlain) {
84+
svg.removeAttribute("fill");
85+
const elements = svg.getElementsByTagName("*");
86+
for (let i = 0; i < elements.length; i++) {
87+
const element = elements[i] as SVGElement;
88+
element.removeAttribute("fill");
89+
element.style.removeProperty("fill");
90+
element.style.removeProperty("fill-rule");
91+
element.style.removeProperty("fill-opacity");
92+
}
93+
}
94+
await fsAsync.writeFile(
95+
`${dir}/index.js`,
96+
`const React = require("react");
97+
module.exports = function ${reactName}({size = "1em", ${
98+
isPlain ? `color = "${entry.color}",` : ""
99+
} ...props}){
100+
props = {
101+
...props,
102+
style: {
103+
...(props.style ? props.style : {}),
104+
width: size,
105+
height: size,${
106+
isPlain
107+
? `
108+
...(color ? { fill: color } : {} )`
109+
: ""
110+
}
111+
}
112+
}
113+
return (${(await svgtojsx(svg.outerHTML)).replace(
114+
"<svg",
115+
"<svg {...props}"
116+
)});
117+
}`
118+
);
119+
const definitions = `import React from "react";
120+
interface Props extends React.SVGProps<SVGElement> {
121+
size?: number | string;${
122+
isPlain
123+
? `
124+
color?: string;`
125+
: ""
126+
}
127+
}
128+
declare const ${reactName}: React.FunctionComponent<Props>;
129+
export default ${reactName};`;
130+
await fsAsync.writeFile(`${dir}/index.d.ts`, definitions);
131+
})
132+
);
133+
})
134+
);
135+
136+
await fsAsync.writeFile(
137+
`${__dirname}/tmp/dist/index.js`,
138+
index.map((e) => `const ${e[0]} = require("${e[1]}")`).join(";\n") +
139+
";\n" +
140+
`module.exports = {${index.map((e) => e[0]).join(",")}}`
141+
);
142+
await fsAsync.writeFile(
143+
`${__dirname}/tmp/dist/index.d.ts`,
144+
index.map((e) => `export { default as ${e[0]} } from "${e[1]}"`).join(";\n")
145+
);
146+
})();

package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "react-devicons",
3+
"license": "MIT",
4+
"scripts": {
5+
"build": "ts-node index.ts && babel tmp/dist --out-dir dist --copy-files",
6+
"release": "ts-node publish.ts"
7+
},
8+
"devDependencies": {
9+
"@babel/cli": "^7.13.14",
10+
"@babel/core": "^7.13.14",
11+
"@babel/plugin-syntax-jsx": "^7.12.13",
12+
"@babel/plugin-transform-parameters": "^7.13.0",
13+
"@babel/preset-react": "^7.13.13",
14+
"@octokit/core": "^3.3.2",
15+
"@types/degit": "^2.8.1",
16+
"@types/jsdom": "^16.2.9",
17+
"@types/node": "^14.14.37",
18+
"@types/react": "^17.0.3",
19+
"axios": "^0.21.1",
20+
"babel-preset-minify": "^0.5.1",
21+
"degit": "^2.8.0",
22+
"dotenv": "^8.2.0",
23+
"jsdom": "^16.5.2",
24+
"svg-to-jsx": "^1.0.3",
25+
"ts-node": "^9.1.1",
26+
"typescript": "^4.2.3"
27+
},
28+
"dependencies": {
29+
"react": "^17.0.2"
30+
}
31+
}

publish.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { Octokit } from "@octokit/core";
2+
import dotenv from "dotenv";
3+
import fsAsync from "fs/promises";
4+
import { exec as execCallback } from "child_process";
5+
import axios from "axios";
6+
7+
function exec(command: string) {
8+
return new Promise<void>((resolve) => {
9+
execCallback(command, () => {
10+
resolve();
11+
});
12+
});
13+
}
14+
15+
dotenv.config();
16+
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
17+
18+
(async () => {
19+
const deviconVersion = (
20+
await octokit.request("GET /repos/{owner}/{repo}/releases/latest", {
21+
owner: "devicons",
22+
repo: "devicon",
23+
})
24+
).data.tag_name.replace("v", "");
25+
const currentVersion = (
26+
await octokit.request("GET /repos/{owner}/{repo}/releases/latest", {
27+
owner: "maltejur",
28+
repo: "react-devicons",
29+
})
30+
).data.tag_name.replace("v", "");
31+
32+
await fsAsync.writeFile(
33+
".npmrc",
34+
`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`
35+
);
36+
37+
if (!deviconVersion.includes(currentVersion)) {
38+
console.log(
39+
`New version available (${currentVersion} -> ${deviconVersion})`
40+
);
41+
console.log(" - Building");
42+
await exec("yarn build");
43+
console.log(" - Publishing");
44+
await exec(
45+
`yarn publish dist --non-interactive --new-version ${deviconVersion}`
46+
);
47+
console.log(" - Creating github release");
48+
const release_id = (
49+
await octokit.request("POST /repos/{owner}/{repo}/releases", {
50+
owner: "maltejur",
51+
repo: "react-devicons",
52+
tag_name: `v${deviconVersion}`,
53+
})
54+
).data.id;
55+
await exec("zip react-devicons.zip dist -r");
56+
await axios({
57+
url: `https://uploads.github.com/repos/maltejur/react-devicons/releases/${release_id}/assets?name=react-devicons.zip`,
58+
data: Buffer.from(await fsAsync.readFile("./react-devicons.zip")),
59+
headers: {
60+
Authorization: `token ${process.env.GITHUB_TOKEN}`,
61+
"Content-Type": "application/zip",
62+
},
63+
});
64+
console.log("All done!");
65+
} else {
66+
console.log(`Version up to date (${deviconVersion})`);
67+
}
68+
})();

readme.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# react-devicons
2+
3+
React components for the svg icons of the [devicon](https://github.com/devicons/devicon) project.
4+
5+
## Installation
6+
7+
```js
8+
yarn add react-devicons
9+
// OR
10+
npm install --save react-devicons
11+
```
12+
13+
## Usage
14+
15+
```tsx
16+
import { GithubOriginalIcon, GithubOriginalWordmarkIcon } from "react-devicons";
17+
// OR
18+
import ReactOriginalIcon from "react-devicons/react/original";
19+
20+
<GithubOriginalWordmarkIcon />
21+
<GithubOriginalIcon size="2em" />
22+
<ReactOriginalIcon className="my-class" />
23+
```
24+
25+
### With color
26+
27+
Icons that are only one color can be recolored like this
28+
29+
```tsx
30+
import { DeviconPlainIcon } from "react-devicons";
31+
32+
<DeviconPlainIcon color="white" />;
33+
```

tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"jsx": "react",
4+
"moduleResolution": "Node",
5+
"allowSyntheticDefaultImports": true,
6+
"esModuleInterop": true
7+
}
8+
}

0 commit comments

Comments
 (0)