Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 53 additions & 58 deletions generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,39 @@ const fs = require('fs')
const path = require('path')
const axios = require('axios')

// Base url for icons
const iconURL = 'https://fonts.google.com/metadata/icons'
// This is the number of icons each thread will be downloading
const DOWNLOAD_CHUNK_SIZE = 500
const GOOGLE_FONTS_URL = 'https://fonts.google.com/metadata/icons'
const ICON_FAMILIES = [
{ id: 'materialicons', namePostfix: '' },
Comment thread
stplasim marked this conversation as resolved.
Outdated
{ id: 'materialiconsoutlined', namePostfix: 'Outlined' },
{ id: 'materialiconsround', namePostfix: 'Round' },
{ id: 'materialiconssharp', namePostfix: 'Sharp' },
{ id: 'materialiconstwotone', namePostfix: 'TwoTone' },
]

function setup() {
function generateIconPropsFile() {
Comment thread
stplasim marked this conversation as resolved.
Outdated
const typesFile = `
import React from 'react'
export interface IconProps extends React.SVGProps<SVGSVGElement> {
title?: string
}
`

// Create types file
fs.writeFileSync(path.join(__dirname, 'src', 'types.ts'), typesFile)
}

/**
* Format name.
* Covert from snake case to camel case and prevent numbers at the beginning
*
* @param string - String to format
* @returns {string} - Formatted string
*/
function formatName(string) {
function formatName(string, familyName) {
Comment thread
stplasim marked this conversation as resolved.
Outdated
const formattedString = string
.replace(/_/g, ' ')
.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
})
.replace(/ /g, '')
return 'Icon' + formattedString

return 'Icon' + formattedString + familyName
}

/**
* Component template for functional react icon component
*
* @param name - Component name
* @param svg - Icon SVG
* @returns {string} - Component
*/
function componentTemplate(name, svg) {
return `
import React from 'react'
Expand All @@ -54,34 +48,12 @@ function componentTemplate(name, svg) {
`
}

/**
* Generate React Icon components
*
* @param icon - Icon object
*/
function generateComponent(icon) {
icon.forEach(async (c) => {
const name = formatName(c.name)
const svg = await getSVGFile(c.name, c.version)

fs.writeFileSync(
path.join(__dirname, 'src', `${name}.tsx`),
componentTemplate(name, svg)
async function getSVGFile(icon, familyId, version) {
const svg = await axios
.get(
`https://fonts.gstatic.com/s/i/${familyId}/${icon}/v${version}/24px.svg`
)
})
}

/**
* Get SVG data form google static fonts api
*
* @param icon - Icon name
* @param version - Icon Version
* @returns {Promise<any>} - SVG Data
*/
async function getSVGFile(icon, version) {
const svg = await axios.get(
`https://fonts.gstatic.com/s/i/materialicons/${icon}/v${version}/24px.svg`
)
.catch((err) => console.log(err))

return svg.data
.replace('height="24"', '')
Expand All @@ -93,23 +65,46 @@ async function getSVGFile(icon, version) {
.replace('>', '>{props.title && <title>{props.title}</title>}')
.replace(/style="enableBackground:(.*?);?"/g, 'enableBackground="$1"')
.replace(/style="fill:(.*?);?"/g, 'fill="$1"')
.replace(/xmlns:xlink/g, 'xmlnsXlink')
.replace(/xlink:href/g, 'xlinkHref')
}

async function generateComponent(icons) {
for (let i = 0; i < icons.length; i++) {
const icon = icons[i]

for (let j = 0; j < ICON_FAMILIES.length; j++) {
const family = ICON_FAMILIES[j]

const name = formatName(icon.name, family.namePostfix)
Comment thread
stplasim marked this conversation as resolved.
Outdated
const svg = await getSVGFile(icon.name, family.id, icon.version)

console.log(`Downloading ${name} (${i + 1}/${icons.length})`)

await fs.writeFileSync(
path.join(__dirname, 'src', `${name}.tsx`),
componentTemplate(name, svg)
)
}
}
}

/**
* Main function
*/
;(async () => {
// Setup source folder
setup()
generateIconPropsFile()

const res = await axios.get(GOOGLE_FONTS_URL)

// Get icon information from google fonts
const res = await axios.get(iconURL)
// remove )]}' from the response
Comment thread
stplasim marked this conversation as resolved.
Outdated
const data = res.data.substring(4)

// Parse response from json to js object
const icons = await JSON.parse(data)

// Generate icon components and Index
await generateComponent(icons.icons)
const iconChunks = new Array(
Math.ceil(icons.icons.length / DOWNLOAD_CHUNK_SIZE)
)
.fill()
.map(() => icons.icons.splice(0, DOWNLOAD_CHUNK_SIZE))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you do the split up into multiple chunks? I don't really see any benefit here how you handle it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have cleaned it up


for (let i = 0; i < iconChunks.length; i++) {
generateComponent(iconChunks[i])
}
})()
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
},
"scripts": {
"build": "tsc",
"generate": "rm -rf src/* && node generator.js",
"clear": "rm -rf src/*",
"generate": "node generator.js",
"lint": "eslint --ext js,ts,tsx src ./generator.js",
"lint:fix": "npm run lint -- --fix",
"typecheck": "tsc --noEmit",
Expand Down
12 changes: 10 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,21 @@ import IconCached from '@aboutbits/react-material-icons/dist/IconCached'

const MyCommponent = () => {
return (
<IconCached />
);
<IconCached/>
);
}
```

SVG related parameters like height and width can be passed as props.

To import the different variants of an icon you can add the variants as a postfix:

- `Icon10k` > Default filled
- `Icon10kOutlined` > Outlined
- `Icon10kRound` > Rounded
- `Icon10kSharp` > Sharp
- `Icon10kTwoTone` > Tow tone

## Generate Components

To generate the components, simply run the following command:
Expand Down