Lucide 0.15.0 (#272)

* add configs

* Add vue components

* Add documentation

* add alpha release version

* improve npm ignore files

* add tests

* Make style and class attrs work

* 📦 bump version

* Add Icon suffix for component names

* bump version

* Add icon component example

* remove space

* add new build strategy

* Write a better intro

* add other node design

* fix

* add new default template

* add tempalte

* improve code

* small improvements

* small improvements

* move files

* Connect lucide with lucide-react

* Add support for vue

* Add licenses to packages

* Fix tests

* refactor build scripts

* Minor code fixes

* update homepage readme

* Update footer text

* Add a better introduction to packages

* Split up in tempaltes

* Add new types build file

* Setup workflow file

* update readme

* update

* Fix build

* remove debug code

* Add check if svgs have duplicated children

* Add check if their are no children

* small fixes

* last fixes in the build

* Move script to packages folder

* Fix tests and add types for lucide

* Add rule to package.json

* add types in build

* add npm ignore

* update package.jsons
This commit is contained in:
Eric Fennis
2021-03-23 19:26:50 +01:00
committed by GitHub
parent 9d101a5275
commit b4e4f002f2
81 changed files with 5804 additions and 1655 deletions

View File

@@ -20,13 +20,9 @@ jobs:
- name: Install FontForge
run: sudo apt-get install zlib1g-dev fontforge
- name: Install NodeJS and Yarn
run: sudo apt-get install nodejs yarn
- name: Clone sfnt2woff-zopfli repo
run: git clone https://github.com/bramstein/sfnt2woff-zopfli.git sfnt2woff-zopfli
- name: Install and move sfnt2woff-zopfli
run: |
cd sfnt2woff-zopfli
@@ -36,7 +32,6 @@ jobs:
- name: Clone woff2
run: git clone --recursive https://github.com/google/woff2.git
- name: Install woff2
run: |
cd woff2
@@ -47,16 +42,14 @@ jobs:
run: sudo gem install fontcustom
- name: Install "outline-stroke"
run: sudo yarn add svg-outline-stroke svgson
run: sudo yarn add svg-outline-stroke -W
- name: "Outline SVG"
run: mkdir converted_icons && node scripts/outline_svg.js
- name: Build 'Lucide'
run: echo "Building Lucide font" && fontcustom compile ./converted_icons -h -n Lucide -o build -F
- name: Zip 'Lucide'
run: zip -r Lucide.zip build

View File

@@ -1,4 +1,4 @@
name: Release to NPM
name: Release Packages
on:
push:
@@ -6,94 +6,150 @@ on:
- 'v*'
jobs:
build-and-deploy:
pre-build:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
outputs:
VERSION: ${{ steps.get_version.outputs.VERSION }}
YARN_CACHE_DIR: ${{ steps.get_version.outputs.YARN_CACHE_DIR }}
steps:
- name: Get the version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/\v}
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=YARN_CACHE_DIR::$(yarn cache dir)"
lucide:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: pre-build
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
clean: true
node-version: '12.x'
- name: Set Auth Token
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ needs.pre-build.outputs.YARN_CACHE_DIR }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
# Build lucide
- name: Install Dependencies Lucide
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn --pure-lockfile
- name: Build lucide package
run: yarn build
- name: Set new version
run: yarn workspace lucide version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
- name: Test lucide package
run: yarn test
- name: Build
run: yarn workspace lucide build
# Build lucide-react
- name: Install Dependencies lucide-react
run: yarn --pure-lockfile
working-directory: packages/lucide-react
- name: Test
run: yarn workspace lucide test
- name: Build lucide-react
run: yarn build
working-directory: packages/lucide-react
- name: Test lucide-react
run: yarn test
working-directory: packages/lucide-react
# Build lucide-vue
- name: Install Dependencies lucide-vue
run: yarn --pure-lockfile
working-directory: packages/lucide-vue
- name: Build lucide-vue
run: yarn build
working-directory: packages/lucide-vue
- name: Test lucide-vue
run: yarn test
working-directory: packages/lucide-vue
# Publish lucide
- name: Set package.json version lucide
run: yarn version --new-version ${{ steps.get_version.outputs.VERSION }} --no-git-tag-version
- name: publish lucide
run: yarn publish
# Publish lucide-react
- name: Set package.json version lucide-react
run: yarn version --new-version ${{ steps.get_version.outputs.VERSION }} --no-git-tag-version
working-directory: packages/lucide-react
- name: publish lucide-react
run: yarn publish
working-directory: packages/lucide-react
# Publish lucide-vue
- name: Set package.json version lucide-vue
run: yarn version --new-version ${{ steps.get_version.outputs.VERSION }} --no-git-tag-version
working-directory: packages/lucide-vue
- name: publish lucide-vue
run: yarn publish
working-directory: packages/lucide-vue
- name: Publish
run: yarn workspace lucide publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit package.json
run: |
git add package.json
git add packages/lucide-react/package.json
git add packages/lucide-vue/package.json
git add packages/lucide/package.json
git -c user.name="Lucide Bot" -c user.email="lucide-bot@users.noreply.github.com" \
commit -m ":package: Bump version to ${{ steps.get_version.outputs.VERSION }}" --no-verify --quiet
git remote set-url --push origin https://lucide-bot:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git
commit -m ":package: Bump version lucide to ${{ needs.pre-build.outputs.VERSION }}" --no-verify --quiet
git remote set-url --push origin https://lucide-bot:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY.git
git push origin HEAD:master
lucide-react:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: pre-build
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '12.x'
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ needs.pre-build.outputs.YARN_CACHE_DIR }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn --pure-lockfile
- name: Set package.json version lucide
run: yarn workspace lucide-react version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
- name: Build
run: yarn workspace lucide-react build
- name: Test
run: yarn workspace lucide-react test
- name: Publish
run: yarn workspace lucide-react publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit package.json
run: |
git add packages/lucide-react/package.json
git -c user.name="Lucide Bot" -c user.email="lucide-bot@users.noreply.github.com" \
commit -m ":package: Bump version lucide-react to ${{ needs.pre-build.outputs.VERSION }}" --no-verify --quiet
git remote set-url --push origin https://lucide-bot:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY.git
git push origin HEAD:master
lucide-vue:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: pre-build
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '12.x'
- uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ needs.pre-build.outputs.YARN_CACHE_DIR }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
if: steps.yarn-cache.outputs.cache-hit != 'true'
run: yarn --pure-lockfile
- name: Set new version
run: yarn workspace lucide-vue version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
- name: Build
run: yarn workspace lucide-vue build
- name: Test
run: yarn workspace lucide-vue test
- name: Publish
run: yarn workspace lucide-vue publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit package.json
run: |
git add packages/lucide-vue/package.json
git -c user.name="Lucide Bot" -c user.email="lucide-bot@users.noreply.github.com" \
commit -m ":package: Bump version lucide-vue to ${{ needs.pre-build.outputs.VERSION }}" --no-verify --quiet
git remote set-url --push origin https://lucide-bot:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY.git
git push origin HEAD:master

3
.gitignore vendored
View File

@@ -4,10 +4,9 @@
node_modules
dist
build
/lib
sandbox
stash
coverage
stats
*.log
index.d.ts
packages/**/src/icons/*.js

160
README.md
View File

@@ -9,6 +9,15 @@
## What is Lucide?
Lucide is a community-run fork of [Feather Icons](https://github.com/feathericons/feather), open for anyone to contribute icons.
Started after growing disaffection of the moderation of the [Feather Icons](https://github.com/feathericons/feather) project, with over 300+ open issues and over 100+ open PRs, this project is no longer maintained. The owner of the project stopped merging icons and want to keep the project like it now is. Hundreds of developers/designer wasted their time trying to contribute, what a shame.
We're trying to expanding the icon set as much as possible while keeping it nice-looking, we do it as a community of devs and designers, join us!
### Why choose Lucide over Feather Icons
- Lucide already expended the icon set by 130+ in less then a year, so more icons to work with.
- Well maintained code base.
- Active community.
## Table of Contents
@@ -16,38 +25,14 @@ Lucide is a community-run fork of [Feather Icons](https://github.com/feathericon
* [Package managers](#package-managers)
* [CDN](#cdn)
* [Usage](#usage)
* [Unpkg](#with-unpkg)
* [ESModules](#with-esmodules)
* [Options](#additional-options)
* [Treeshake library](#treeshake-the-library-only-use-the-icons-you-use)
* [Custom binding](#custom-element-binding)
* [React](#with-react)
* [Vue](#with-vue)
* [Web](#web)
* [React](#react)
* [Vue](#vue)
* [Figma](#figma)
* [Contributing](#contributing)
* [Community](#community)
* [License](#license)
## Installation
### Package Managers
``` bash
npm install lucide
#or
yarn add lucide
```
### CDN
``` html
<!-- Development version -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<!-- Production version -->
<script src="https://unpkg.com/lucide@latest"></script>
```
## Usage
At its core, Lucide is a collection of [SVG](https://svgontheweb.com/#svg) files. This means that you can use Feather icons in all the same ways you can use SVGs (e.g. `img`, `background-image`, `inline`, `object`, `embed`, `iframe`). Here's a helpful article detailing the many ways SVGs can be used on the web: [SVG on the Web Implementation Options](https://svgontheweb.com/#implementation)
@@ -55,104 +40,23 @@ At its core, Lucide is a collection of [SVG](https://svgontheweb.com/#svg) files
The following are additional ways you can use Lucide.
With the Javascript library you can easily incorporate the icon you want in your webpage.
### With unpkg
### Web
Here is a complete example with unpkg
Implementation of the lucide icon library for web applications.
```html
<!DOCTYPE html>
<body>
<i icon-name="volume-2" class="my-class"></i>
<i icon-name="x"></i>
<i icon-name="menu"></i>
```sh
npm install lucide
<script src="https://unpkg.com/lucide@latest"></script>
<script>
lucide.createIcons();
</script>
</body>
#or
yarn add lucide
```
### With ESModules
For more details, see the [documentation](https://github.com/lucide-icons/lucide/blob/master/packages/lucide-react/README.md).
To reduce bundle size, lucide is built to be fully treeshakable.
The `createIcons` function will search for HTMLElements with the attribute `icon-name` and replace it with the svg from the given icon name.
### React
```html
<!-- Your HTML file -->
<i icon-name="menu"></i>
```
```js
import { createIcons, icons } from 'lucide';
// Caution, this will import all the icons and bundle them.
createIcons({icons});
// Recommended way, to include only the icons you need.
import { createIcons, Menu, ArrowRight, Globe } from 'lucide';
createIcons({
icons: {
Menu,
ArrowRight,
Globe,
},
});
```
#### Additional Options
In the `createIcons` function you can pass some extra parameters to adjust the `nameAttr` or add custom attributes like for example classes.
Here is a full example:
```js
import { createIcons } from 'lucide';
createIcons({
attrs: {
class: ['my-custom-class', 'icon'],
'stroke-width': 1,
stroke: '#333',
},
nameAttr: 'icon-name', // attribute for the icon name.
});
```
#### Treeshake the library, only use the icons you use
```js
import { createIcons, Menu, ArrowRight, Globe } from 'lucide';
createIcons({
icons: {
Menu,
ArrowRight,
Globe,
},
});
```
#### Custom Element binding
```js
import { createElement, Menu } from 'lucide';
const menuIcon = createElement(Menu); // Returns HTMLElement (svg)
// set custom attributes with browser native functions
menuIcon.setAttribute('stroke', '#333');
menuIcon.classList.add('my-icon-class');
// Append HTMLElement in webpage
const myApp = document.getElementById('app');
myApp.appendChild(menuIcon);
```
### With React
You can also use the Lucide library using the react package.
Implementation of the lucide icon library for react applications.
```sh
yarn add lucide-react
@@ -162,11 +66,11 @@ yarn add lucide-react
npm install lucide-react
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/blob/master/packages/lucide-react/README.md).
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-react#lucide-react).
### With Vue
### Vue
You can also use the Lucide library using the Vue package.
Implementation of the lucide icon library for vue applications.
```sh
yarn add lucide-vue
@@ -176,11 +80,15 @@ yarn add lucide-vue
npm install lucide-vue
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/blob/master/packages/lucide-vue/README.md).
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue#lucide-vue).
### Figma
You can use the components from [this Figma file](https://www.figma.com/file/g0UipfQlRfGrntKPxZknM7/Featherity).
The lucide figma plugin.
Visit [Figma community page](https://www.figma.com/community/plugin/939567362549682242/Lucide-Icons) to install the plugin.
<img width="420" src="https://www.figma.com/community/plugin/939567362549682242/thumbnail" alt="Figma Lucide Cover">
## Contributing
@@ -194,10 +102,10 @@ Join the community on our [Discord](https://discord.gg/EH6nSts) server!
## License
Lucide is licensed under the [ISC License](https://github.com/lucide-icons/lucide/blob/master/LICENSE).
Lucide is totally free for commercial use and personally use, this software is licensed under the [ISC License](https://github.com/lucide-icons/lucide/blob/master/LICENSE).
## Sponsors
<p align="center">
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
<img src="./site/public/vercel.svg" alt="Powered by Vercel" width="200" />
</a>
</p>

View File

@@ -1,13 +1,5 @@
module.exports = {
presets: [
[
'@babel/env',
{
loose: true,
modules: false,
},
],
],
presets: ['@babel/env'],
env: {
test: {
presets: ['@babel/env'],

View File

@@ -1 +1,15 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="2" y="6" width="20" height="12" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="2" y="6" width="20" height="12" rx="2" />
<circle cx="12" cy="12" r="2" />
<path d="M6 12h.01M18 12h.01" />
</svg>

Before

Width:  |  Height:  |  Size: 252 B

After

Width:  |  Height:  |  Size: 331 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 455 B

After

Width:  |  Height:  |  Size: 455 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 347 B

View File

@@ -11,6 +11,6 @@
>
<path d="M4 22h14a2 2 0 002-2V7.5L14.5 2H6a2 2 0 00-2 2v4" />
<path d="M14 2v6h6" />
<path d="M2 15l10-0" />
<path d="M2 15h10" />
<path d="M9 18l3-3-3-3" />
</svg>

Before

Width:  |  Height:  |  Size: 352 B

After

Width:  |  Height:  |  Size: 350 B

View File

@@ -11,6 +11,6 @@
>
<path d="M4 22h14a2 2 0 002-2V7.5L14.5 2H6a2 2 0 00-2 2v4" />
<path d="M14 2v6h6" />
<path d="M2 15l10-0" />
<path d="M2 15h10" />
<path d="M5 12l-3 3 3 3" />
</svg>

Before

Width:  |  Height:  |  Size: 353 B

After

Width:  |  Height:  |  Size: 351 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 347 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 321 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 341 B

View File

@@ -1,8 +1,8 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 282 B

View File

@@ -1,5 +0,0 @@
[build]
base = "site/"
publish = "build/"
command = "yarn deploy"
ignore = "git diff --quiet origin/master HEAD ../icons ../site"

View File

@@ -1,67 +1,50 @@
{
"name": "lucide",
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
"version": "0.14.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
"repository": {
"type": "git",
"url": "https://github.com/lucide-icons/lucide.git"
},
"amdName": "lucide",
"source": "build/lucide.js",
"main": "dist/cjs/lucide.js",
"main:umd": "dist/umd/lucide.js",
"module": "dist/esm/lucide.js",
"unpkg": "dist/umd/lucide.min.js",
"sideEffects": false,
"private": true,
"workspaces": [
"packages/*",
"site"
],
"scripts": {
"start": "babel-watch --watch src",
"clean": "rimraf dist && rimraf build && rimraf index.d.ts",
"build": "yarn clean && yarn build:move && yarn build:icons && yarn build:dts && yarn build:es && yarn build:bundles",
"build:move": "cp -av src build",
"build:icons": "npx babel-node ./scripts/buildIcons.js --presets @babel/env",
"build:dts": "npx babel-node ./scripts/buildDts.js --presets @babel/env",
"build:es": "babel build -d dist/esm",
"build:bundles": "rollup -c rollup.config.js",
"optimize": "npx babel-node ./scripts/optimizeSvgs.js --presets @babel/env",
"addtags": "npx babel-node ./scripts/addMissingKeysToTags.js --presets @babel/env",
"test": "jest"
"build": "yarn lucide build && yarn lucide-react build && yarn lucide-vue build",
"test": "yarn lucide build:icons && yarn lucide-react build:icons && yarn lucide-vue build:icons && jest",
"lucide": "yarn workspace lucide",
"lucide-react": "yarn workspace lucide-react",
"lucide-vue": "yarn workspace lucide-vue",
"build:icons": "babel-node ./scripts/buildIcons.js --presets @babel/env",
"optimize": "babel-node ./scripts/optimizeSvgs.js --presets @babel/env",
"addtags": "babel-node ./scripts/addMissingKeysToTags.js --presets @babel/env"
},
"devDependencies": {
"@ampproject/rollup-plugin-closure-compiler": "^0.25.2",
"@atomico/rollup-plugin-sizes": "^1.1.4",
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.1",
"@babel/node": "^7.10.5",
"@babel/node": "^7.13.10",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.0",
"@rollup/plugin-babel": "^5.0.0",
"babel-jest": "^26.3.0",
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.2.0",
"@rollup/plugin-replace": "^2.4.1",
"babel-jest": "^26.6.3",
"babel-plugin-add-import-extension": "^1.4.3",
"cheerio": "^1.0.0-rc.2",
"core-js": "3",
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.5.0",
"eslint-plugin-prettier": "^2.5.0",
"html-minifier": "^3.5.8",
"htmlparser2": "^4.1.0",
"husky": "^4.3.6",
"jest": "^26.4.2",
"lint-staged": "^10.5.3",
"minimist": "^1.2.5",
"prettier": "1.17.1",
"rollup": "^2.7.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-license": "^2.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-terser": "^5.2.0",
"rollup-plugin-visualizer": "^4.1.0",
"svgo": "^1.3.2"
"svgo": "^1.3.2",
"svgson": "^4.1.0"
},
"husky": {
"hooks": {

View File

@@ -2,6 +2,7 @@
"name": "lucide-figma",
"version": "0.13.0",
"license": "ISC",
"private": true,
"main": "build/ui.js",
"scripts": {
"build": "webpack --mode=production",

View File

@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2020, Lucide Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -1,6 +1,8 @@
# Lucide React
Use the lucide icon library in you react app.
Implementation of the lucide icon library for react applications.
> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
## Installation

View File

@@ -1,3 +1,6 @@
const mainConfig = require('../../babel.config');
module.exports = {
presets: ['react-app'],
env: mainConfig.env,
};

View File

@@ -1,54 +0,0 @@
const fs = require("fs")
const path = require("path")
const srcDirectory = path.join(__dirname, "dist")
// Declare type definitions
const typeDefinitions = `
/// <reference types="react" />
import { SVGAttributes } from 'react'
// Create interface extending SVGAttributes
export interface LucideProps extends Partial<React.SVGProps<SVGSVGElement>> {
color?: string
size?: string | number
stroke?: string | number
strokeWidth?: string | number
}
// Generated icons
`
// Write type definitions to file
fs.writeFileSync(
path.join(srcDirectory, "index.d.ts"),
typeDefinitions,
"utf-8",
)
const iconsFolder = "./build/icons"
fs.readdir(iconsFolder, (err, files) => {
files.forEach(file => {
const fileName = file.replace(".js", "")
// Convert fileName to component name
const componentName = fileName.split("-")
.map(word => word[0].toUpperCase() + word.substr(1, word.length))
.join("")
// Declare component type
const exportTypeString = `export declare const ${componentName}: (props: LucideProps) => JSX.Element;\n`
// Add component to the types file
fs.appendFileSync(
path.join(srcDirectory, "index.d.ts"),
exportTypeString,
"utf-8",
)
})
console.log("Generated index.d.ts file with", files.length, "icons")
})

View File

@@ -3,9 +3,6 @@ module.exports = {
roots: ['<rootDir>/src/', '<rootDir>/tests/'],
moduleFileExtensions: ['js'],
transformIgnorePatterns: [`/node_modules`],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
transform: {
'^.+\\.js$': 'babel-jest',
},

View File

@@ -16,14 +16,13 @@
"main:umd": "dist/umd/lucide-react.js",
"module": "dist/esm/lucide-react.js",
"unpkg": "dist/umd/lucide-react.min.js",
"typings": "dist/index.d.ts",
"typings": "dist/lucide-react.d.ts",
"scripts": {
"build": "yarn clean && yarn build:move && yarn build:icons && yarn build:es && yarn build:types && yarn build:bundles",
"clean": "rm -rf dist && rm -rf build",
"build:move": "cp -av src build",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-react/build --templateSrc=../packages/lucide-react/scripts/exportTemplate --camelizeAttrs --noDefaultAttrs --renderUniqueKey",
"build:types": "node build-types.js",
"build:es": "yarn --cwd ../../ babel packages/lucide-react/build -d packages/lucide-react/dist/esm",
"build": "yarn clean && yarn build:icons && yarn build:es && yarn build:types && yarn build:bundles",
"clean": "rm -rf dist && rm -rf ./src/icons/*.js",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-react/src --templateSrc=../packages/lucide-react/scripts/exportTemplate --renderUniqueKey",
"build:es": "yarn --cwd ../../ babel packages/lucide-react/src -d packages/lucide-react/dist/esm",
"build:types": "yarn --cwd ../../ babel-node packages/lucide-react/scripts/buildTypes.js",
"build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-react/rollup.config.js",
"test": "jest"
},

View File

@@ -1,11 +1,11 @@
const plugins = require('../../rollup.plugins');
const pkg = require('./package.json');
import plugins from '../../rollup.plugins';
import pkg from './package.json';
const packageName = 'LucideReact';
const outputFileName = 'lucide-react';
const rootDir = 'packages/lucide-react'; // It runs from the root
const outputDir = `${rootDir}/dist`;
const inputs = [`${rootDir}/build/lucide-react.js`];
const inputs = [`${rootDir}/src/lucide-react.js`];
const bundles = [
{
format: 'umd',
@@ -30,7 +30,7 @@ const configs = bundles
inputs.map(input => ({
input,
plugins: plugins(pkg, minify),
external: ['react', 'prop-types'],
external: ['react', 'prop-types', 'lucide'],
output: {
name: packageName,
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
@@ -39,6 +39,7 @@ const configs = bundles
globals: {
react: 'react',
'prop-types': 'PropTypes',
lucide: 'lucide',
},
},
})),

View File

@@ -0,0 +1,44 @@
import path from 'path';
import {
writeFile,
readSvgDirectory,
resetFile,
toPascalCase,
appendFile,
} from '../../../scripts/helpers';
const srcDirectory = path.join(__dirname, '../dist');
// Declare type definitions
const typeDefinitions = `\
/// <reference types="react" />
import { SVGAttributes } from 'react'
// Create interface extending SVGAttributes
export interface LucideProps extends Partial<React.SVGProps<SVGSVGElement>> {
color?: string
size?: string | number
stroke?: string | number
strokeWidth?: string | number
}
// Generated icons
`;
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const TYPES_FILE = 'lucide-react.d.ts';
resetFile(TYPES_FILE, srcDirectory);
writeFile(typeDefinitions, TYPES_FILE, srcDirectory);
const svgFiles = readSvgDirectory(ICONS_DIR);
svgFiles.forEach(svgFile => {
const iconName = path.basename(svgFile, '.svg');
const componentName = toPascalCase(iconName);
const exportTypeString = `export declare const ${componentName}: (props: LucideProps) => JSX.Element;\n`;
appendFile(exportTypeString, TYPES_FILE, srcDirectory);
});
console.log(`Generated ${TYPES_FILE} file with`, svgFiles.length, 'icons');

View File

@@ -1,8 +1,7 @@
export default ({ componentName, node }) => `
export default ({ componentName, children }) => `
import createReactComponent from '../createReactComponent';
import defaultAttributes from '../defaultAttributes';
const ${componentName} = createReactComponent('${componentName}', ['svg', defaultAttributes, ${node}]);
const ${componentName} = createReactComponent('${componentName}', ${JSON.stringify(children)});
export default ${componentName};
`;

View File

@@ -1,21 +1,22 @@
import { forwardRef, createElement } from 'react';
import PropTypes from 'prop-types';
import defaultAttributes from './defaultAttributes';
export default (iconName, [tag, attrs, children]) => {
export default (iconName, iconNode) => {
const Component = forwardRef(
({ color = 'currentColor', size = 24, strokeWidth = 2, ...rest }, ref) =>
createElement(
tag,
'svg',
{
ref,
...attrs,
...defaultAttributes,
width: size,
height: size,
stroke: color,
strokeWidth,
...rest,
},
children.map(([childTag, childAttrs]) => createElement(childTag, childAttrs)),
iconNode.map(([tag, attrs]) => createElement(tag, attrs)),
),
);

View File

@@ -0,0 +1 @@
Folder for generated icons

View File

@@ -1,5 +0,0 @@
/*
Icons exports.
Will be generated
*/

View File

@@ -1,6 +1,6 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { Grid } from '..'
import { Grid } from '../src/icons'
describe('Using lucide icon components', () => {
it('should render an component', () => {

View File

@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2020, Lucide Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -1,6 +1,8 @@
# Lucide Vue
Use the lucide icon library in you Vue app.
Implementation of the lucide icon library for Vue applications.
> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
## Installation

View File

@@ -7,7 +7,7 @@ module.exports = {
'^.+\\.vue$': 'vue-jest',
},
transformIgnorePatterns: [`/node_modules`],
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
snapshotSerializers: ['jest-serializer-vue'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},

View File

@@ -21,19 +21,16 @@
"vue": "^2.6.12"
},
"scripts": {
"build": "yarn clean && yarn build:move && yarn build:icons && yarn build:es && yarn build:bundles",
"clean": "rm -rf dist && rm -rf build",
"build:move": "cp -av src build",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-vue/build --templateSrc=../packages/lucide-vue/scripts/exportTemplate --noDefaultAttrs",
"build:es": "yarn --cwd ../../ babel packages/lucide-vue/build -d packages/lucide-vue/dist/esm",
"build": "yarn clean && yarn build:icons && yarn build:es && yarn build:bundles",
"clean": "rm -rf dist && rm -rf ./src/icons/*.js",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-vue/src --templateSrc=../packages/lucide-vue/scripts/exportTemplate",
"build:es": "yarn --cwd ../../ babel packages/lucide-vue/src -d packages/lucide-vue/dist/esm",
"build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-vue/rollup.config.js",
"test": "jest",
"test:watch": "jest --watchAll"
},
"devDependencies": {
"@vue/test-utils": "^1.1.2",
"babel-jest": "^26.6.3",
"jest": "^26.6.3",
"jest-serializer-vue": "^2.0.2",
"vue-jest": "^3.0.7",
"vue-template-compiler": "^2.6.12"

View File

@@ -1,11 +1,11 @@
const plugins = require('../../rollup.plugins');
const pkg = require('./package.json');
import plugins from '../../rollup.plugins';
import pkg from './package.json';
const packageName = 'LucideVue';
const outputFileName = 'lucide-vue';
const rootDir = 'packages/lucide-vue'; // It runs from the root
const outputDir = `${rootDir}/dist`;
const inputs = [`${rootDir}/build/lucide-vue.js`];
const inputs = [`${rootDir}/src/lucide-vue.js`];
const bundles = [
{
format: 'umd',

View File

@@ -1,8 +1,7 @@
export default ({ componentName, node }) => `
export default ({ componentName, children }) => `
import createVueComponent from '../createVueComponent';
import defaultAttributes from '../defaultAttributes';
const ${componentName} = createVueComponent('${componentName}Icon', ['svg', defaultAttributes, ${node}]);
const ${componentName} = createVueComponent('${componentName}Icon', ${JSON.stringify(children)});
export default ${componentName};
`;

View File

@@ -1,4 +1,6 @@
export default (iconName, [tag, defaultAttrs, children]) => ({
import defaultAttributes from './defaultAttributes';
export default (iconName, iconNode) => ({
name: iconName,
functional: true,
props: {
@@ -27,13 +29,13 @@ export default (iconName, [tag, defaultAttrs, children]) => ({
},
) {
return createElement(
tag,
'svg',
{
// eslint-disable-next-line prettier/prettier
class: [defaultClass, data.class, data.staticClass, data.attrs && data.attrs.class].filter(Boolean),
style: [data.style, data.staticStyle, data.attrs && data.attrs.style].filter(Boolean),
attrs: {
...defaultAttrs,
...defaultAttributes,
width: size,
height: size,
stroke: color,
@@ -41,7 +43,7 @@ export default (iconName, [tag, defaultAttrs, children]) => ({
...data.attrs,
},
},
children.map(([childTag, childAttrs]) => createElement(childTag, { attrs: childAttrs })),
iconNode.map(([tag, attrs]) => createElement(tag, { attrs })),
);
},
});

View File

@@ -0,0 +1 @@
Folder for generated icons

View File

@@ -1,5 +0,0 @@
/*
Icons exports.
Will be generated
*/

View File

@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import { Smile } from '..'
import { Smile } from '../src/icons'
describe('Using lucide icon components', () => {
it('should render an component', () => {

1
packages/lucide/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
src/icons/*.js

View File

@@ -0,0 +1,10 @@
stats
node_modules
tests
scripts
build
src
babel.config.js
jest.config.js
rollup.config.js
yarn.error.log

15
packages/lucide/LICENSE Normal file
View File

@@ -0,0 +1,15 @@
ISC License
Copyright (c) 2020, Lucide Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

120
packages/lucide/README.md Normal file
View File

@@ -0,0 +1,120 @@
# Lucide
Implementation of the lucide icon library for web applications.
## Installation
### Package Managers
``` bash
npm install lucide
#or
yarn add lucide
```
### CDN
``` html
<!-- Development version -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<!-- Production version -->
<script src="https://unpkg.com/lucide@latest"></script>
```
## Usage
### With unpkg
Here is a complete example with unpkg
```html
<!DOCTYPE html>
<body>
<i icon-name="volume-2" class="my-class"></i>
<i icon-name="x"></i>
<i icon-name="menu"></i>
<script src="https://unpkg.com/lucide@latest"></script>
<script>
lucide.createIcons();
</script>
</body>
```
### With ESModules
To reduce bundle size, lucide is built to be fully treeshakable.
The `createIcons` function will search for HTMLElements with the attribute `icon-name` and replace it with the svg from the given icon name.
```html
<!-- Your HTML file -->
<i icon-name="menu"></i>
```
```js
import { createIcons, icons } from 'lucide';
// Caution, this will import all the icons and bundle them.
createIcons({icons});
// Recommended way, to include only the icons you need.
import { createIcons, Menu, ArrowRight, Globe } from 'lucide';
createIcons({
icons: {
Menu,
ArrowRight,
Globe,
},
});
```
#### Additional Options
In the `createIcons` function you can pass some extra parameters to adjust the `nameAttr` or add custom attributes like for example classes.
Here is a full example:
```js
import { createIcons } from 'lucide';
createIcons({
attrs: {
class: ['my-custom-class', 'icon'],
'stroke-width': 1,
stroke: '#333',
},
nameAttr: 'icon-name', // attribute for the icon name.
});
```
#### Treeshake the library, only use the icons you use
```js
import { createIcons, Menu, ArrowRight, Globe } from 'lucide';
createIcons({
icons: {
Menu,
ArrowRight,
Globe,
},
});
```
#### Custom Element binding
```js
import { createElement, Menu } from 'lucide';
const menuIcon = createElement(Menu); // Returns HTMLElement (svg)
// set custom attributes with browser native functions
menuIcon.setAttribute('stroke', '#333');
menuIcon.classList.add('my-icon-class');
// Append HTMLElement in webpage
const myApp = document.getElementById('app');
myApp.appendChild(menuIcon);
```

View File

@@ -0,0 +1,14 @@
const mainConfig = require('../../babel.config');
module.exports = {
presets: [
[
'@babel/env',
{
loose: true,
modules: false,
},
],
],
env: mainConfig.env,
};

View File

@@ -5,9 +5,6 @@ module.exports = {
roots: ['<rootDir>/src/', '<rootDir>/tests/'],
moduleFileExtensions: ['js'],
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
transform: {
'^.+\\.js$': 'babel-jest',
},

View File

@@ -0,0 +1,30 @@
{
"name": "lucide",
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
"version": "0.14.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
"repository": {
"type": "git",
"url": "https://github.com/lucide-icons/lucide.git",
"directory": "packages/lucide"
},
"amdName": "lucide",
"source": "build/lucide.js",
"main": "dist/cjs/lucide.js",
"main:umd": "dist/umd/lucide.js",
"module": "dist/esm/lucide.js",
"unpkg": "dist/umd/lucide.min.js",
"typings": "dist/lucide.d.ts",
"sideEffects": false,
"scripts": {
"build": "yarn clean && yarn build:icons && yarn build:es && yarn build:types && yarn build:bundles",
"clean": "rm -rf dist && rm -rf ./src/icons/*.js",
"build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide/src",
"build:es": "babel src -d dist/esm",
"build:types": "yarn --cwd ../../ babel-node packages/lucide/scripts/buildTypes.js",
"build:bundles": "rollup -c rollup.config.js",
"test": "jest"
}
}

View File

@@ -1,9 +1,9 @@
const plugins = require('./rollup.plugins');
const pkg = require('./package.json');
import plugins from '../../rollup.plugins';
import pkg from './package.json';
const outputFileName = pkg.name;
const outputDir = 'dist';
const inputs = ['build/lucide.js'];
const inputs = ['src/lucide.js'];
const bundles = [
{
format: 'umd',
@@ -38,4 +38,4 @@ const configs = bundles
)
.flat();
module.exports = configs;
export default configs;

View File

@@ -0,0 +1,37 @@
import path from 'path';
import { readSvgDirectory, resetFile, appendFile, toPascalCase } from '../../../scripts/helpers';
const TARGET_DIR = path.join(__dirname, '../dist');
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const TYPES_FILE_NAME = 'lucide.d.ts';
// Generates header of d.ts file include some types and functions
const typeDefinitions = `\
export type IconName = string;
export type IconNode = readonly [tag: string, object:SVGProps<SVGSVGElement>, children:IconNode?];
export type IconsObj = { [IconName]: IconNode }
export interface Attributes extends Partial<Props<Element>> {}
export function createElement(icon: IconNode): SVGSVGElement;
export function createIcons({ icons: IconsObj, nameAttr: string = 'icon-name', attrs: Attributes = {} }): VoidFunction;
export declare const icons: IconsObj;
// Generated icons
`;
resetFile(TYPES_FILE_NAME, TARGET_DIR);
appendFile(typeDefinitions, TYPES_FILE_NAME, TARGET_DIR);
const svgFiles = readSvgDirectory(ICONS_DIR);
svgFiles.forEach(svgFile => {
const nameSvg = path.basename(svgFile, '.svg');
const namePascal = toPascalCase(nameSvg);
appendFile(`export declare const ${namePascal}: IconNode;\n`, TYPES_FILE_NAME, TARGET_DIR);
});
console.log(`Generated ${TYPES_FILE_NAME} file with`, svgFiles.length, 'icons');

View File

@@ -5,7 +5,7 @@ export default {
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 2,
strokeLinecap: 'round',
strokeLinejoin: 'round',
'stroke-width': 2,
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
};

View File

@@ -0,0 +1 @@
Folder for generated icons

View File

@@ -1,5 +1,5 @@
import replaceElement from './replaceElement';
import * as allIcons from './icons/index';
import * as allIcons from './icons';
/**
* Replaces all elements with matching nameAttr with the defined icons
@@ -34,4 +34,4 @@ export { default as createElement } from './createElement';
Icons exports.
*/
export { allIcons as icons };
export * from './icons/index';
export * from './icons';

View File

@@ -17,6 +17,7 @@ export const getAttrs = element =>
* @returns {Array}
*/
export const getClassNames = attrs => {
if (typeof attrs === 'string') return attrs;
if (!attrs || !attrs.class) return '';
if (attrs.class && typeof attrs.class === 'string') {
return attrs.class.split(' ');
@@ -38,6 +39,7 @@ export const combineClassNames = arrayOfClassnames => {
return classNameArray
.map(classItem => classItem.trim())
.filter(Boolean)
.filter((value, index, self) => self.indexOf(value) === index)
.join(' ');
};
@@ -63,23 +65,21 @@ export default (element, { nameAttr, icons, attrs }) => {
}
const elementAttrs = getAttrs(element);
const [tag, iconAttributes, children] = iconNode;
const [, iconAttrs] = iconNode;
const allAttrs = {
...iconAttrs,
const iconAttrs = {
...iconAttributes,
'icon-name': iconName,
...attrs,
};
iconNode[1] = { ...allAttrs };
const classNames = combineClassNames([iconAttrs, elementAttrs, attrs]);
const classNames = combineClassNames(['lucide', elementAttrs, attrs]);
if (classNames) {
iconNode[1].class = classNames;
iconAttrs.class = classNames;
}
const svgElement = createElement(iconNode);
const svgElement = createElement([tag, iconAttrs, children]);
return element.parentNode.replaceChild(svgElement, element);
};

View File

@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`createIcons should add custom attributes 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"black\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" icon-name=\\"volume-2\\" class=\\"lucide icon custom-class\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07\\"></path></svg>"`;
exports[`createIcons should read elements from DOM and replace it with icons 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" icon-name=\\"volume-2\\" class=\\"lucide\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07\\"></path></svg>"`;

View File

@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`combineClassNames should retuns a string of classNames 1`] = `"item1 item2 item3 item4 item5 item6 item7 item8 item9"`;
exports[`combineClassNames should retuns a string of classNames 1`] = `"item item1 item2 item3 item4 item5 item6 item7 item8 item9"`;

View File

@@ -1,15 +1,19 @@
import * as icons from './icons';
import * as icons from '../src/icons';
import { createIcons } from '../src/lucide';
import fs from 'fs';
import path from 'path';
import { minify } from 'html-minifier';
import { parseSync, stringify } from 'svgson';
const ICONS_DIR = path.resolve(__dirname, '../icons');
const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const getOriginalSvg = (iconName) => {
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
const svgParsed = parseSync(svgContent);
return minify(svgContent, { collapseWhitespace: true, keepClosingSlash: true, });
svgParsed.attributes['icon-name'] = iconName;
svgParsed.attributes['class'] = 'lucide';
return stringify(svgParsed, { selfClose: false });
};
describe('createIcons', () => {
@@ -19,6 +23,8 @@ describe('createIcons', () => {
createIcons({icons});
const svg = getOriginalSvg('volume-2');
expect(document.body.innerHTML).toBe(svg)
expect(document.body.innerHTML).toMatchSnapshot()
});
@@ -36,10 +42,10 @@ describe('createIcons', () => {
});
it('should add custom attributes', () => {
document.body.innerHTML = `<i icon-name="volume-2"></i>`;
document.body.innerHTML = `<i icon-name="volume-2" class="lucide"></i>`;
const attrs = {
class: 'icon custom-class',
class: 'lucide icon custom-class',
fill: 'black',
};
@@ -54,6 +60,8 @@ describe('createIcons', () => {
return acc;
},{})
expect(document.body.innerHTML).toMatchSnapshot();
expect(attributesAndValues).toEqual(expect.objectContaining(attrs));
});
});

View File

@@ -44,6 +44,7 @@ describe('getClassNames', () => {
describe('combineClassNames', () => {
it('should retuns a string of classNames', () => {
const arrayOfClassnames = [
'item',
{
class: ['item1','item2','item3']
},

View File

@@ -1,18 +1,20 @@
const babel = require('@rollup/plugin-babel').default;
const bundleSize = require('@atomico/rollup-plugin-sizes');
const compiler = require('@ampproject/rollup-plugin-closure-compiler');
const { terser } = require('rollup-plugin-terser');
const visualizer = require('rollup-plugin-visualizer');
const license = require('rollup-plugin-license');
const replace = require('rollup-plugin-replace');
const resolve = require('rollup-plugin-node-resolve');
const commonJS = require('rollup-plugin-commonjs');
/* eslint-disable import/no-extraneous-dependencies */
import babel from '@rollup/plugin-babel';
import bundleSize from '@atomico/rollup-plugin-sizes';
import compiler from '@ampproject/rollup-plugin-closure-compiler';
import { terser } from 'rollup-plugin-terser';
import visualizer from 'rollup-plugin-visualizer';
import license from 'rollup-plugin-license';
import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import commonJS from '@rollup/plugin-commonjs';
const plugins = (pkg, minify) =>
[
replace({
'icons = {}': 'icons = allIcons',
delimiters: ['', ''],
preventAssignment: false,
}),
babel({
babelHelpers: 'bundled',
@@ -34,4 +36,4 @@ const plugins = (pkg, minify) =>
}),
].filter(Boolean);
module.exports = plugins;
export default plugins;

View File

@@ -4,24 +4,28 @@ import path from 'path';
import prettier from 'prettier';
import { toPascalCase } from '../helpers';
export default function(iconNode, outputDirectory, template) {
const icons = Object.keys(iconNode);
export default function(iconNodes, outputDirectory, template, { showLog = true }) {
const icons = Object.keys(iconNodes);
const iconsDistDirectory = path.join(outputDirectory, `icons`);
if (!fs.existsSync(iconsDistDirectory)) {
fs.mkdirSync(iconsDistDirectory);
}
icons.forEach(icon => {
const location = path.join(iconsDistDirectory, `${icon}.js`);
const componentName = toPascalCase(icon);
icons.forEach(iconName => {
const location = path.join(iconsDistDirectory, `${iconName}.js`);
const componentName = toPascalCase(iconName);
const node = JSON.stringify(iconNode[icon]);
let { children } = iconNodes[iconName];
children = children.map(({name, attributes}) => ([name, attributes]))
const elementTemplate = template({ componentName, node });
const elementTemplate = template({ componentName, iconName, children });
fs.writeFileSync(location, prettier.format(elementTemplate, { parser: 'babel' }), 'utf-8');
fs.writeFileSync(location, prettier.format(elementTemplate, { singleQuote: true, trailingComma: 'all', parser: 'babel' }), 'utf-8');
if(showLog) {
console.log('Successfully built', componentName);
}
});
}

View File

@@ -1,35 +0,0 @@
import path from 'path';
import { readSvgDirectory, resetFile, appendFile, toPascalCase } from './helpers';
const ICONS_DIR = path.resolve(__dirname, '../icons');
const DTS_FILE_NAME = 'index.d.ts';
const DTS_FILE_ROOT = path.resolve(__dirname, '../');
resetFile(DTS_FILE_NAME, DTS_FILE_ROOT);
// Generates header of d.ts file include some types and functions
appendFile(
`
export type IconData = readonly [string, object, IconData?];
export type IconString = string;
export function createElement(ico: IconData): SVGSVGElement;
export declare const icons: { [key: string]: IconData };
// Generated icons
`,
DTS_FILE_NAME,
DTS_FILE_ROOT,
);
const svgFiles = readSvgDirectory(ICONS_DIR);
svgFiles.forEach(svgFile => {
const nameSvg = path.basename(svgFile, '.svg');
const namePascal = toPascalCase(nameSvg);
appendFile(`export declare const ${namePascal}: IconData;\n`, DTS_FILE_NAME, DTS_FILE_ROOT);
});
console.log(`Successfully generated '${DTS_FILE_NAME}'.`);

View File

@@ -1,15 +1,12 @@
import fs from 'fs';
import path from 'path';
// eslint-disable-next-line import/no-extraneous-dependencies
import getArgumentOptions from 'minimist';
import getArgumentOptions from 'minimist'; // eslint-disable-line import/no-extraneous-dependencies
import renderIconsObject from './render/renderIconsObject';
import renderIconNodes from './render/renderIconNodes';
import generateIconFiles from './build/generateIconFiles';
import generateExportsFile from './build/generateExportsFile';
import { readSvgDirectory } from './helpers';
/* eslint-disable import/no-dynamic-require */
import { readSvgDirectory } from './helpers';
const cliArguments = getArgumentOptions(process.argv.slice(2));
@@ -23,26 +20,14 @@ if (!fs.existsSync(OUTPUT_DIR)) {
const svgFiles = readSvgDirectory(ICONS_DIR);
const icons = renderIconsObject(svgFiles, ICONS_DIR);
const icons = renderIconsObject(svgFiles, ICONS_DIR, cliArguments.renderUniqueKey);
const iconVNodes = renderIconNodes(icons, cliArguments);
const defaultIconFileTemplate = ({ componentName, node }) => `
const ${componentName} = ${node};
export default ${componentName};
`;
const iconFileTemplate = cliArguments.templateSrc
? require(cliArguments.templateSrc).default
: defaultIconFileTemplate;
const defaultIconFileTemplate = './templates/defaultIconFileTemplate';
// eslint-disable-next-line import/no-dynamic-require
const iconFileTemplate = require(cliArguments.templateSrc || defaultIconFileTemplate).default;
// Generates iconsNodes files for each icon
generateIconFiles(iconVNodes, OUTPUT_DIR, iconFileTemplate);
generateIconFiles(icons, OUTPUT_DIR, iconFileTemplate, { showLog: !cliArguments.silent });
// Generates entry files for the compiler filled with icons exports
generateExportsFile(
path.join(SRC_DIR, 'icons/index.js'),
path.join(OUTPUT_DIR, 'icons'),
iconVNodes,
);
generateExportsFile(path.join(SRC_DIR, 'icons/index.js'), path.join(OUTPUT_DIR, 'icons'), icons);

View File

@@ -2,9 +2,10 @@ import fs from 'fs';
import path from 'path';
/**
* Converts string to PascalCase
* Converts string to CamelCase
*
* @param {string} string
* @returns {string} A camelized string
*/
export const toCamelCase = string =>
string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) =>
@@ -15,6 +16,7 @@ export const toCamelCase = string =>
* Converts string to PascalCase
*
* @param {string} string
* @returns {string} A pascalized string
*/
export const toPascalCase = string => {
const camelCase = toCamelCase(string);
@@ -23,9 +25,10 @@ export const toPascalCase = string => {
};
/**
* Converts string to PascalCase
* Converts string to KebabCase
*
* @param {string} string
* @returns {string} A kebabized string
*/
export const toKebabCase = string => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
@@ -42,6 +45,7 @@ export const resetFile = (fileName, outputDirectory) =>
* Reads the file contents.
*
* @param {string} path
* @returns {string} The contents of a file
*/
export const readFile = entry => fs.readFileSync(path.resolve(__dirname, '../', entry), 'utf-8');
@@ -69,6 +73,7 @@ export const writeFile = (content, fileName, outputDirectory) =>
* reads the icon directory
*
* @param {string} directory
* @returns {array} An array of file paths containig svgs
*/
export const readSvgDirectory = directory =>
fs.readdirSync(directory).filter(file => path.extname(file) === '.svg');
@@ -79,7 +84,8 @@ export const readSvgDirectory = directory =>
* @param {string} fileName
* @param {string} directory
*/
export const readSvg = (fileName, directory) => fs.readFileSync(path.join(directory, fileName));
export const readSvg = (fileName, directory) =>
fs.readFileSync(path.join(directory, fileName), 'utf-8');
/**
* writes content to a file
@@ -91,7 +97,13 @@ export const readSvg = (fileName, directory) => fs.readFileSync(path.join(direct
export const writeSvgFile = (fileName, outputDirectory, content) =>
fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8');
// This is a djb2 hashing function
/**
* djb2 hashing function
*
* @param {string} string
* @param {number} seed
* @returns {string} A hashed string of 6 characters
*/
export const hash = (string, seed = 5381) => {
let i = string.length;
@@ -103,3 +115,27 @@ export const hash = (string, seed = 5381) => {
// eslint-disable-next-line no-bitwise
return (seed >>> 0).toString(36).substr(0, 6);
};
/**
* Generate Hashed string based on name and attributes
*
* @param {object} seed
* @param {string} seed.name A name, for example an icon name
* @param {object} seed.attributes An object of SVGElement Attrbutes
* @returns {string} A hashed string of 6 characters
*/
export const generateHashedKey = ({ name, attributes }) => hash(JSON.stringify([name, attributes]));
/**
* Checks if array of items contains duplicated items
*
* @param {array} children an array of items
* @returns {Boolean} if items contains duplicated items.
*/
export const hasDuplicatedChildren = children => {
const hashedKeys = children.map(generateHashedKey);
return !hashedKeys.every(
(key, index) => index === hashedKeys.findIndex(childKey => childKey === key),
);
};

View File

@@ -1,6 +1,6 @@
const { promises: fs } = require("fs");
const outlineStroke = require("svg-outline-stroke");
const { parse, stringify } = require("svgson");
const { promises: fs } = require('fs');
const outlineStroke = require('svg-outline-stroke');
const { parse, stringify } = require('svgson');
const inputDir = `./icons/`;
const outputDir = `./converted_icons/`;
@@ -8,19 +8,16 @@ const outputDir = `./converted_icons/`;
async function init() {
try {
const files = await fs.readdir(inputDir);
for (let file of files) {
for (const file of files) {
const icon = await fs.readFile(`${inputDir}${file}`);
const scaled = await parse(icon.toString(), {
transformNode: transformForward
transformNode: transformForward,
});
const outlined = await outlineStroke(stringify(scaled));
const outlinedWithoutAttrs = await parse(outlined, {
transformNode: transformBackwards
transformNode: transformBackwards,
});
await fs.writeFile(
`${outputDir}${file}`,
stringify(outlinedWithoutAttrs)
);
await fs.writeFile(`${outputDir}${file}`, stringify(outlinedWithoutAttrs));
}
} catch (err) {
console.log(err);
@@ -30,25 +27,25 @@ async function init() {
init();
function transformForward(node) {
if (node.name === "svg") {
if (node.name === 'svg') {
return {
...node,
attributes: {
...node.attributes,
width: 960,
height: 960
}
height: 960,
},
};
}
return node;
}
function transformBackwards(node) {
if (node.name === "svg") {
if (node.name === 'svg') {
const { width, height, ...attributes } = node.attributes;
return {
...node,
attributes
attributes,
};
}
return node;

View File

@@ -1,30 +1,13 @@
/* eslint-disable import/no-extraneous-dependencies */
import Svgo from 'svgo';
import cheerio from 'cheerio';
import { format } from 'prettier';
import { parseSync, stringify } from 'svgson';
import DEFAULT_ATTRS from './default-attrs.json';
/**
* Process SVG string.
* @param {string} svg - An SVG string.
* @param {Promise<string>}
*/
function processSvg(svg) {
return (
optimize(svg)
.then(setAttrs)
.then(optimizedSvg => format(optimizedSvg, { parser: 'babel' }))
// remove semicolon inserted by prettier
// because prettier thinks it's formatting JSX not HTML
.then(svg => svg.replace(/;/g, ''))
);
}
/**
* Optimize SVG with `svgo`.
* @param {string} svg - An SVG string.
* @returns {Promise<string>}
* @returns {Promise<string>} An optimized svg
*/
function optimize(svg) {
const svgo = new Svgo({
@@ -42,14 +25,30 @@ function optimize(svg) {
/**
* Set default attibutes on SVG.
* @param {string} svg - An SVG string.
* @returns {string}
* @returns {string} An SVG string, included with the default attributes.
*/
function setAttrs(svg) {
const $ = cheerio.load(svg);
const contents = parseSync(svg);
Object.keys(DEFAULT_ATTRS).forEach(key => $('svg').attr(key, DEFAULT_ATTRS[key]));
contents.attributes = DEFAULT_ATTRS;
return $('body').html();
return stringify(contents);
}
/**
* Process SVG string.
* @param {string} svg An SVG string.
* @returns {Promise<string>} An optimized svg
*/
function processSvg(svg) {
return (
optimize(svg)
.then(setAttrs)
.then(optimizedSvg => format(optimizedSvg, { parser: 'babel' }))
// remove semicolon inserted by prettier
// because prettier thinks it's formatting JSX not HTML
.then(svg => svg.replace(/;/g, ''))
);
}
export default processSvg;

View File

@@ -1,53 +0,0 @@
/* eslint-disable import/no-extraneous-dependencies */
import { parseDOM } from 'htmlparser2';
import DEFAULT_ATTRS from './default-attrs.json';
import { toCamelCase, hash } from '../helpers';
const camelizeAttrs = attrs =>
Object.keys(attrs).reduce((newAttrs, attr) => {
const attrKey = toCamelCase(attr);
newAttrs[attrKey] = attrs[attr];
return newAttrs;
}, {});
export default (iconsObject, options) => {
const iconNodes = {};
Object.keys(iconsObject).forEach(icon => {
const svgString = iconsObject[icon];
const dom = parseDOM(svgString);
const children = dom.map(element => {
if (options.renderUniqueKey) {
const hashSource = {
name: element.name,
...element.attribs,
};
const uniqueKey = hash(JSON.stringify(hashSource));
element.attribs.key = uniqueKey;
}
return [
element.name,
{
...(options.camelizeAttrs ? camelizeAttrs(element.attribs) : element.attribs),
},
];
});
iconNodes[icon] = !options.noDefaultAttrs
? [
'svg',
{
...(options.camelizeAttrs ? camelizeAttrs(DEFAULT_ATTRS) : DEFAULT_ATTRS),
},
children,
]
: children;
});
return iconNodes;
};

View File

@@ -1,19 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */
import path from 'path';
import cheerio from 'cheerio';
import { minify } from 'html-minifier';
import { readSvg } from '../helpers';
/**
* Get contents between opening and closing `<svg>` tags.
* @param {string} svg
* @returns {string}
*/
function getSvgContents(svg) {
const $ = cheerio.load(svg);
return minify($('svg').html(), { collapseWhitespace: true });
}
import { basename } from 'path';
import { parseSync } from 'svgson';
import { generateHashedKey, readSvg, hasDuplicatedChildren } from '../helpers';
/**
* Build an object in the format: `{ <name>: <contents> }`.
@@ -21,12 +9,29 @@ function getSvgContents(svg) {
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
* @returns {Object}
*/
export default (svgFiles, iconsDirectory) =>
export default (svgFiles, iconsDirectory, renderUniqueKey = false) =>
svgFiles
.map(svgFile => {
const name = path.basename(svgFile, '.svg');
const name = basename(svgFile, '.svg');
const svg = readSvg(svgFile, iconsDirectory);
const contents = getSvgContents(svg);
const contents = parseSync(svg);
if (!(contents.children && contents.children.length)) {
throw new Error(`${name}.svg has no children!`);
}
if (hasDuplicatedChildren(contents.children)) {
throw new Error(`Duplicated children in ${name}.svg`);
}
if (renderUniqueKey) {
contents.children = contents.children.map(child => {
child.attributes.key = generateHashedKey(child);
return child;
});
}
return { name, contents };
})
.reduce((icons, icon) => {

View File

@@ -0,0 +1,11 @@
export default ({ componentName, children }) => `
import defaultAttributes from '../defaultAttributes';
const ${componentName} = [
'svg',
defaultAttributes,
${JSON.stringify(children)}
];
export default ${componentName};
`;

View File

@@ -14,12 +14,10 @@
"@chakra-ui/core": "^1.0.0-rc.8",
"downloadjs": "^1.4.7",
"framer-motion": "^3.3.0",
"fuse.js": "^6.0.4",
"jszip": "^3.4.0",
"lodash": "^4.17.20",
"lucide-react": "^0.11.0",
"lucide-react": "0.14.0",
"next": "^10.0.4",
"object-path": "0.11.5",
"react": "^16.13.1",
"react-color": "2.17.3",
"react-dom": "^16.13.1",

View File

@@ -1,4 +1,4 @@
import {Button, Flex, Link, WrapItem, Text, Wrap,} from "@chakra-ui/core";
import { Button, Flex, Link, WrapItem, Text, Wrap } from "@chakra-ui/core";
import download from "downloadjs";
import JSZip from "jszip";
import { Download, Github } from 'lucide-react';
@@ -31,7 +31,6 @@ const Header = ({ data }) => {
An open-source icon library, a fork of <Link href="https://github.com/feathericons/feather" isExternal>Feather Icons</Link>. <br/>We're expanding the icon set as much as possible while keeping it nice-looking - <Link href={repositoryUrl} isExternal>join us</Link>!
</Text>
<Wrap
isInline
marginTop={3}
marginBottom={10}
spacing="15px"

View File

@@ -218,7 +218,7 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
{ icon.contributors.map((commit, index) => (
<Link href={`https://github.com/${commit.author}`} isExternal key={`${index}_${commit.sha}`}>
<Tooltip label={commit.author} key={commit.sha}>
<Avatar name={commit.author} showBorder={false} src={`https://github.com/${commit.author}.png?size=88`} />
<Avatar name={commit.author} src={`https://github.com/${commit.author}.png?size=88`} />
</Tooltip>
</Link>
)) }

View File

@@ -1,5 +0,0 @@
/*
Icons exports.
Will be generated
*/

View File

@@ -1,3 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`createIcons should read elements from DOM and replace it with icons 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><polygon points=\\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\\"></polygon><path d=\\"M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07\\"></path></svg>"`;

View File

@@ -1,21 +0,0 @@
const Download = [
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
[
["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }],
["polyline", { points: "7 10 12 15 17 10" }],
["line", { x1: "12", y1: "15", x2: "12", y2: "3" }]
]
];
export default Download;

View File

@@ -1,27 +0,0 @@
const Globe = [
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
[
["circle", { cx: "12", cy: "12", r: "10" }],
["line", { x1: "2", y1: "12", x2: "22", y2: "12" }],
[
"path",
{
d:
"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"
}
]
]
];
export default Globe;

View File

@@ -1,6 +0,0 @@
export { default as Download } from './download';
export { default as Globe } from './globe';
export { default as Menu } from './menu';
export { default as Moon } from './moon';
export { default as Volume2 } from './volume-2';

View File

@@ -1,21 +0,0 @@
const Menu = [
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
[
["line", { x1: "3", y1: "12", x2: "21", y2: "12" }],
["line", { x1: "3", y1: "6", x2: "21", y2: "6" }],
["line", { x1: "3", y1: "18", x2: "21", y2: "18" }]
]
];
export default Menu;

View File

@@ -1,17 +0,0 @@
const Moon = [
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
[["path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }]]
];
export default Moon;

View File

@@ -1,23 +0,0 @@
const Volume2 = [
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
[
["polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }],
[
"path",
{ d: "M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" }
]
]
];
export default Volume2;

5992
yarn.lock

File diff suppressed because it is too large Load Diff