Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
maltejur committed Apr 11, 2021
0 parents commit ef320cd
Show file tree
Hide file tree
Showing 9 changed files with 2,934 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Publish on NPM
on:
schedule:
- cron: "0 10 * * *"
push:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: "14"
- name: Install dependencies
run: yarn
- name: Run publish script
run: yarn release
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
yarn-error.log
tmp
dist
.env
react-devicons.zip
4 changes: 4 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
presets: ["@babel/preset-react", "babel-preset-minify"],
plugins: ["@babel/plugin-transform-parameters"],
};
146 changes: 146 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import degit from "degit";
import fs from "fs";
import fsAsync from "fs/promises";
import { JSDOM } from "jsdom";
import { exec } from "child_process";
import svgtojsx from "svg-to-jsx";

interface ConfigEntry {
name: string;
tags: string[];
versions: {
svg: string[];
font: string[];
};
color: string;
aliases: {
base: string;
alias: string;
}[];
}

(async () => {
const index: [string, string][] = [];

if (fs.existsSync(`${__dirname}/tmp`))
fs.rmSync(`${__dirname}/tmp`, { recursive: true });
if (fs.existsSync(`${__dirname}/dist`))
fs.rmSync(`${__dirname}/dist`, { recursive: true });
fsAsync.mkdir(`${__dirname}/tmp`);

await degit("https://github.com/devicons/devicon.git").clone(
`${__dirname}/tmp/devicon`
);

const deviconConfig: ConfigEntry[] = JSON.parse(
(await fsAsync.readFile(`${__dirname}/tmp/devicon/devicon.json`)).toString()
);

await fsAsync.mkdir(`${__dirname}/tmp/dist`);
await fsAsync.copyFile(
`${__dirname}/readme.md`,
`${__dirname}/tmp/dist/readme.md`
);
await fsAsync.copyFile(
`${__dirname}/package.json`,
`${__dirname}/tmp/dist/package.json`
);

await Promise.all(
deviconConfig.map(async (entry) => {
await fsAsync.mkdir(`${__dirname}/tmp/dist/${entry.name}`);
await Promise.all(
entry.versions.svg.map(async (version) => {
const name = `${entry.name}-${version}`;
const icon = await fsAsync.readFile(
`${__dirname}/tmp/devicon/icons/${entry.name}/${name}.svg`
);
const { document } = new JSDOM(icon).window;
const dir = `${__dirname}/tmp/dist/${entry.name}/${version}`;
const reactName =
name
.split("-")
.map((el) => el.charAt(0).toUpperCase() + el.slice(1))
.join("") + "Icon";
index.push([reactName, `./${entry.name}/${version}`]);
await fsAsync.mkdir(dir);
// await fsAsync.writeFile(
// `${dir}/index.js`,
// `export { default } from "./${reactName}"`
// );
const svg = document.getElementsByTagName("svg")[0];
svg.removeAttribute("width");
svg.removeAttribute("height");
svg.removeAttribute("xmlns:xlink");
const isPlain =
version.includes("plain") ||
version.includes("line") ||
!!entry.aliases.find(
(x) =>
x.base == version &&
(x.alias.includes("plain") || x.alias.includes("line"))
);
if (isPlain) {
svg.removeAttribute("fill");
const elements = svg.getElementsByTagName("*");
for (let i = 0; i < elements.length; i++) {
const element = elements[i] as SVGElement;
element.removeAttribute("fill");
element.style.removeProperty("fill");
element.style.removeProperty("fill-rule");
element.style.removeProperty("fill-opacity");
}
}
await fsAsync.writeFile(
`${dir}/index.js`,
`const React = require("react");
module.exports = function ${reactName}({size = "1em", ${
isPlain ? `color = "${entry.color}",` : ""
} ...props}){
props = {
...props,
style: {
...(props.style ? props.style : {}),
width: size,
height: size,${
isPlain
? `
...(color ? { fill: color } : {} )`
: ""
}
}
}
return (${(await svgtojsx(svg.outerHTML)).replace(
"<svg",
"<svg {...props}"
)});
}`
);
const definitions = `import React from "react";
interface Props extends React.SVGProps<SVGElement> {
size?: number | string;${
isPlain
? `
color?: string;`
: ""
}
}
declare const ${reactName}: React.FunctionComponent<Props>;
export default ${reactName};`;
await fsAsync.writeFile(`${dir}/index.d.ts`, definitions);
})
);
})
);

await fsAsync.writeFile(
`${__dirname}/tmp/dist/index.js`,
index.map((e) => `const ${e[0]} = require("${e[1]}")`).join(";\n") +
";\n" +
`module.exports = {${index.map((e) => e[0]).join(",")}}`
);
await fsAsync.writeFile(
`${__dirname}/tmp/dist/index.d.ts`,
index.map((e) => `export { default as ${e[0]} } from "${e[1]}"`).join(";\n")
);
})();
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "react-devicons",
"license": "MIT",
"scripts": {
"build": "ts-node index.ts && babel tmp/dist --out-dir dist --copy-files",
"release": "ts-node publish.ts"
},
"devDependencies": {
"@babel/cli": "^7.13.14",
"@babel/core": "^7.13.14",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/plugin-transform-parameters": "^7.13.0",
"@babel/preset-react": "^7.13.13",
"@octokit/core": "^3.3.2",
"@types/degit": "^2.8.1",
"@types/jsdom": "^16.2.9",
"@types/node": "^14.14.37",
"@types/react": "^17.0.3",
"axios": "^0.21.1",
"babel-preset-minify": "^0.5.1",
"degit": "^2.8.0",
"dotenv": "^8.2.0",
"jsdom": "^16.5.2",
"svg-to-jsx": "^1.0.3",
"ts-node": "^9.1.1",
"typescript": "^4.2.3"
},
"dependencies": {
"react": "^17.0.2"
}
}
68 changes: 68 additions & 0 deletions publish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Octokit } from "@octokit/core";
import dotenv from "dotenv";
import fsAsync from "fs/promises";
import { exec as execCallback } from "child_process";
import axios from "axios";

function exec(command: string) {
return new Promise<void>((resolve) => {
execCallback(command, () => {
resolve();
});
});
}

dotenv.config();
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

(async () => {
const deviconVersion = (
await octokit.request("GET /repos/{owner}/{repo}/releases/latest", {
owner: "devicons",
repo: "devicon",
})
).data.tag_name.replace("v", "");
const currentVersion = (
await octokit.request("GET /repos/{owner}/{repo}/releases/latest", {
owner: "maltejur",
repo: "react-devicons",
})
).data.tag_name.replace("v", "");

await fsAsync.writeFile(
".npmrc",
`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`
);

if (!deviconVersion.includes(currentVersion)) {
console.log(
`New version available (${currentVersion} -> ${deviconVersion})`
);
console.log(" - Building");
await exec("yarn build");
console.log(" - Publishing");
await exec(
`yarn publish dist --non-interactive --new-version ${deviconVersion}`
);
console.log(" - Creating github release");
const release_id = (
await octokit.request("POST /repos/{owner}/{repo}/releases", {
owner: "maltejur",
repo: "react-devicons",
tag_name: `v${deviconVersion}`,
})
).data.id;
await exec("zip react-devicons.zip dist -r");
await axios({
url: `https://uploads.github.com/repos/maltejur/react-devicons/releases/${release_id}/assets?name=react-devicons.zip`,
data: Buffer.from(await fsAsync.readFile("./react-devicons.zip")),
headers: {
Authorization: `token ${process.env.GITHUB_TOKEN}`,
"Content-Type": "application/zip",
},
});
console.log("All done!");
} else {
console.log(`Version up to date (${deviconVersion})`);
}
})();
33 changes: 33 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# react-devicons

React components for the svg icons of the [devicon](https://github.com/devicons/devicon) project.

## Installation

```js
yarn add react-devicons
// OR
npm install --save react-devicons
```

## Usage

```tsx
import { GithubOriginalIcon, GithubOriginalWordmarkIcon } from "react-devicons";
// OR
import ReactOriginalIcon from "react-devicons/react/original";

<GithubOriginalWordmarkIcon />
<GithubOriginalIcon size="2em" />
<ReactOriginalIcon className="my-class" />
```

### With color

Icons that are only one color can be recolored like this

```tsx
import { DeviconPlainIcon } from "react-devicons";

<DeviconPlainIcon color="white" />;
```
8 changes: 8 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"jsx": "react",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}
Loading

0 comments on commit ef320cd

Please sign in to comment.