Compare commits

...

34 Commits

Author SHA1 Message Date
Eric Fennis
7bd41d9b48 Add vue to main readme 2021-02-22 20:33:43 +01:00
Eric Fennis
4024911219 Lucide Vue Package (#174)
* 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

* improvements package.json

* update tests

* update workflow
2021-02-22 20:26:38 +01:00
Eric Fennis
acea1b4116 Add radio receiver (#190) 2021-02-21 19:29:46 +01:00
Eric Fennis
ec3542dab8 Add tv-2 icon (#189) 2021-02-21 19:29:37 +01:00
Eric Fennis
51cf68c11f Add history icon (#188) 2021-02-21 19:29:26 +01:00
Yashu Mittal
0c460bc3dd add image-minus icon (#191)
* add image-minus icon

* refactor the icon
2021-02-18 08:40:21 +01:00
Yashu Mittal
7e91be9e38 add binary icon (#203) 2021-02-17 13:24:11 +01:00
Yashu Mittal
d042899a06 add regex icon (#213) 2021-02-17 13:18:42 +01:00
Eric Fennis
891115f6fd Add pencil icon (#129) 2021-02-17 13:04:50 +01:00
Yashu Mittal
8ce52d834d add inspect icon (#209) 2021-02-15 16:21:00 +01:00
Yashu Mittal
b6ea440d70 add option icon (#225) 2021-02-15 16:20:47 +01:00
Yashu Mittal
a3125d53cb change lucide domain url to lucide.dev (#228) 2021-02-15 16:20:30 +01:00
Eric Fennis
a7e8b3bcb7 Add contributors to icon overlay and add dot (#223)
* add contributers

* Add icon fetcher

* add contributing json

* Fix fetch call

* Add contributers to site

* Add caching for github api

* Fix build

* Move context provider

* Revert packages changes

* Fix mobile layout

* remove react-spring

* remove incorrect type prop
2021-02-12 20:38:47 +01:00
Eric Fennis
c4dfe6b8cb Update tags (#224)
* Add script to add more tags

* add tags

* update tags

* Fix tags
2021-02-12 16:07:57 +01:00
Yashu Mittal
90e86767d8 add bell plus & minus icon (#202)
* add bell plus & minus icon

* adjust 2px spacing in bell-minus icon
2021-02-12 15:52:02 +01:00
Eric Fennis
30f7be3fd4 Update README.md 2021-02-10 21:23:37 +01:00
John Letey
5d945372d4 Vercel Sponsorship (#221)
* feat: add Vercel sponsorship requirements

* chore: fix syntax error
2021-02-08 07:53:49 +01:00
Yashu Mittal
736b888608 add shield alert, check & close icon (#208)
* add shield alert, check & close icon

* Update icons/shield-close.svg

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2021-02-07 11:24:37 +01:00
Yashu Mittal
fc03912eef add wallet icon (#193)
* add wallet icon

* Update icons/wallet.svg

Co-authored-by: Alexandr Antonov <alexandr-post@yandex.ru>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2021-02-07 11:23:44 +01:00
Yashu Mittal
0864092670 add sigma icon (#197)
Co-authored-by: johnletey <johnletey@gmail.com>
2021-02-06 22:54:45 +01:00
Aishwarya Sharma
400f7871d2 Add icon podcast (#132)
* Add icon podcast

* update to svg with stroke width

* Update podcast.svg

* Update icons/podcast.svg
2021-02-06 22:46:06 +01:00
Yashu Mittal
0ce207bc2f add asterisk icon (#196) 2021-02-04 19:28:22 +01:00
Yashu Mittal
8c85053002 add alarm check, minus, plus icon (#198) 2021-02-04 19:27:41 +01:00
Yashu Mittal
a453c61aa5 decrease slash size by 1px border (#200) 2021-02-04 19:26:29 +01:00
Yashu Mittal
5ad6f5bba3 add webcam icon (#192)
* add webcam icon

* Update icons/webcam.svg

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2021-02-04 19:08:05 +01:00
Eric Fennis
68b91149f2 Add repeat 1 icon (#187) 2021-02-04 19:07:27 +01:00
Yashu Mittal
c50b8181a0 Add icon image-plus (#184)
* add icon image-add

* Rename to "image-plus"
2021-02-04 19:06:58 +01:00
Eric Fennis
1db690953b Merge branch 'master' of github.com:lucide-icons/lucide 2021-02-03 13:14:49 +01:00
Eric Fennis
cef1e1aafa test raw icons 2021-02-03 13:14:03 +01:00
Yashu Mittal
d29667ed99 add globe-2 icon (#178)
* add globe-2 icon

* Refactor & set border at 1px

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2021-02-02 21:10:25 +01:00
Yashu Mittal
d31c2a2f2a optimize icons using script (#195) 2021-02-02 21:09:33 +01:00
Yashu Mittal
e4a86687e2 Add git-branch-new icon (#182)
* Add git-branch-new icon

* rename icon to "git-branch-plus"

* Refactor git-branch-new icon

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2021-02-02 11:15:10 +01:00
Eric Fennis
2d9eee74c5 📦 Bump versions 2021-01-27 20:58:26 +01:00
Eric Fennis
0668f8aebe Fix auth token setting 2021-01-27 20:45:10 +01:00
81 changed files with 7023 additions and 452 deletions

View File

@@ -24,7 +24,7 @@ jobs:
clean: true clean: true
- name: Set Auth Token - name: Set Auth Token
run: yarn config set 'npmRegistries["//registry.npmjs.org"].npmAuthToken' ${{ secrets.NPM_TOKEN }} run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
# Build lucide # Build lucide
- name: Install Dependencies Lucide - name: Install Dependencies Lucide
@@ -33,6 +33,9 @@ jobs:
- name: Build lucide package - name: Build lucide package
run: yarn build run: yarn build
- name: Test lucide package
run: yarn test
# Build lucide-react # Build lucide-react
- name: Install Dependencies lucide-react - name: Install Dependencies lucide-react
run: yarn --pure-lockfile run: yarn --pure-lockfile
@@ -42,6 +45,23 @@ jobs:
run: yarn build run: yarn build
working-directory: packages/lucide-react 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 # Publish lucide
- name: Set package.json version lucide - name: Set package.json version lucide
run: yarn version --new-version ${{ steps.get_version.outputs.VERSION }} --no-git-tag-version run: yarn version --new-version ${{ steps.get_version.outputs.VERSION }} --no-git-tag-version
@@ -58,10 +78,20 @@ jobs:
run: yarn publish run: yarn publish
working-directory: packages/lucide-react 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: Commit package.json - name: Commit package.json
run: | run: |
git add package.json git add package.json
git add packages/lucide-react/package.json git add packages/lucide-react/package.json
git add packages/lucide-vue/package.json
git -c user.name="Lucide Bot" -c user.email="lucide-bot@users.noreply.github.com" \ 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 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 git remote set-url --push origin https://lucide-bot:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git

View File

@@ -5,3 +5,12 @@ node_modules
tests tests
scripts scripts
site site
src
build
babel.config.js
categories.json
jest.config.js
netlify.toml
rollup.config.js
rollup.plugins.js
tags.json

View File

@@ -1,4 +1,4 @@
<p align=center><img width="410" src="https://lucide.netlify.app/logo-text.svg" alt="Lucide Logo"></p> <p align=center><img width="410" src="https://lucide.dev/logo-text.svg" alt="Lucide Logo"></p>
# Lucide # Lucide
@@ -22,6 +22,7 @@ Lucide is a community-run fork of [Feather Icons](https://github.com/feathericon
* [Treeshake library](#treeshake-the-library-only-use-the-icons-you-use) * [Treeshake library](#treeshake-the-library-only-use-the-icons-you-use)
* [Custom binding](#custom-element-binding) * [Custom binding](#custom-element-binding)
* [React](#with-react) * [React](#with-react)
* [Vue](#with-vue)
* [Figma](#figma) * [Figma](#figma)
* [Contributing](#contributing) * [Contributing](#contributing)
* [Community](#community) * [Community](#community)
@@ -163,6 +164,20 @@ 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/blob/master/packages/lucide-react/README.md).
### With Vue
You can also use the Lucide library using the Vue package.
```sh
yarn add lucide-vue
# or
npm install lucide-vue
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/blob/master/packages/lucide-vue/README.md).
### Figma ### Figma
You can use the components from [this Figma file](https://www.figma.com/file/g0UipfQlRfGrntKPxZknM7/Featherity). You can use the components from [this Figma file](https://www.figma.com/file/g0UipfQlRfGrntKPxZknM7/Featherity).
@@ -180,3 +195,9 @@ Join the community on our [Discord](https://discord.gg/EH6nSts) server!
## License ## License
Lucide is licensed under the [ISC License](https://github.com/lucide-icons/lucide/blob/master/LICENSE). Lucide is licensed under the [ISC License](https://github.com/lucide-icons/lucide/blob/master/LICENSE).
<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>

18
icons/alarm-check.svg Normal file
View File

@@ -0,0 +1,18 @@
<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="M12 21a8 8 0 100-16 8 8 0 000 16z" />
<path d="M5 3L2 6" />
<path d="M22 6l-3-3" />
<path d="M6 19l-2 2" />
<path d="M18 19l2 2" />
<path d="M9 13l2 2 4-4" />
</svg>

After

Width:  |  Height:  |  Size: 388 B

18
icons/alarm-minus.svg Normal file
View File

@@ -0,0 +1,18 @@
<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="M12 21a8 8 0 100-16 8 8 0 000 16z" />
<path d="M5 3L2 6" />
<path d="M22 6l-3-3" />
<path d="M6 19l-2 2" />
<path d="M18 19l2 2" />
<path d="M8 13h8" />
</svg>

After

Width:  |  Height:  |  Size: 382 B

19
icons/alarm-plus.svg Normal file
View File

@@ -0,0 +1,19 @@
<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="M12 21a8 8 0 100-16 8 8 0 000 16z" />
<path d="M5 3L2 6" />
<path d="M22 6l-3-3" />
<path d="M6 19l-2 2" />
<path d="M18 19l2 2" />
<path d="M12 9v8" />
<path d="M8 13h8" />
</svg>

After

Width:  |  Height:  |  Size: 405 B

View File

@@ -9,5 +9,5 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="m9 3h6v11h4l-7 7-7-7h4z" /> <path d="M9 3h6v11h4l-7 7-7-7h4z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 247 B

View File

@@ -9,5 +9,5 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="m3 12 7-7v4h11v6h-11v4z" /> <path d="M3 12l7-7v4h11v6H10v4z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 246 B

View File

@@ -9,5 +9,5 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="m21 12-7-7v4h-11v6h11v4z" /> <path d="M21 12l-7-7v4H3v6h11v4z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 248 B

After

Width:  |  Height:  |  Size: 247 B

View File

@@ -9,5 +9,5 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="m9 21v-11h-4l7-7 7 7h-4v11z" /> <path d="M9 21V10H5l7-7 7 7h-4v11z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 249 B

15
icons/asterisk.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M12 6v12" />
<path d="M17.196 9L6.804 15" />
<path d="M6.804 9l10.392 6" />
</svg>

After

Width:  |  Height:  |  Size: 299 B

15
icons/bell-minus.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M13.73 21a2 2 0 01-3.46 0" />
<path d="M21 5h-6" />
<path d="M18.021 9C18.29 15.193 21 17 21 17H3s3-2 3-9a6 6 0 017-5.916" />
</svg>

After

Width:  |  Height:  |  Size: 349 B

View File

@@ -10,8 +10,8 @@
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="M13.73 21a2 2 0 01-3.46 0" /> <path d="M13.73 21a2 2 0 01-3.46 0" />
<path d="M18.63 13A17.89 17.89 0 0118 8" /> <path d="M18.63 13A17.888 17.888 0 0118 8" />
<path d="M6.26 6.26A5.86 5.86 0 006 8c0 7-3 9-3 9h14" /> <path d="M6.26 6.26A5.86 5.86 0 006 8c0 7-3 9-3 9h14" />
<path d="M18 8a6 6 0 00-9.33-5" /> <path d="M18 8a6 6 0 00-9.33-5" />
<line x1="1" y1="1" x2="23" y2="23" /> <path d="M2 2l20 20" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 419 B

16
icons/bell-plus.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18.387 12C19.198 15.799 21 17 21 17H3s3-2 3-9a6 6 0 017-5.916" />
<path d="M13.73 21a2 2 0 01-3.46 0" />
<path d="M18 2v6" />
<path d="M21 5h-6" />
</svg>

After

Width:  |  Height:  |  Size: 374 B

16
icons/binary.svg Normal file
View File

@@ -0,0 +1,16 @@
<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="M10 4H6v6h4V4z" />
<path d="M18 14h-4v6h4v-6z" />
<path d="M14 4h2v6m-2 0h4" />
<path d="M6 14h2v6m-2 0h4" />
</svg>

After

Width:  |  Height:  |  Size: 335 B

18
icons/git-branch-plus.svg Normal file
View File

@@ -0,0 +1,18 @@
<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="M6 3v12" />
<path d="M18 9a3 3 0 100-6 3 3 0 000 6z" />
<path d="M6 21a3 3 0 100-6 3 3 0 000 6z" />
<path d="M15 6a9 9 0 00-9 9" />
<path d="M18 15v6" />
<path d="M21 18h-6" />
</svg>

After

Width:  |  Height:  |  Size: 406 B

16
icons/globe-2.svg Normal file
View File

@@ -0,0 +1,16 @@
<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="M15 21v-4a2 2 0 012-2h4" />
<path d="M7 4v2a3 3 0 003 2h0a2 2 0 012 2 2 2 0 004 0 2 2 0 012-2h3" />
<path d="M3 11h2a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v4" />
<circle cx="12" cy="12" r="10" />
</svg>

After

Width:  |  Height:  |  Size: 420 B

15
icons/history.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M3 3v5h5" />
<path d="M3.05 13A9 9 0 106 5.3L3 8" />
<path d="M12 7v5l4 2" />
</svg>

After

Width:  |  Height:  |  Size: 301 B

16
icons/image-minus.svg Normal file
View File

@@ -0,0 +1,16 @@
<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 11v8a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h8" />
<path d="M8.5 10a1.5 1.5 0 100-3 1.5 1.5 0 000 3z" />
<path d="M21 15l-5-5L5 21" />
<path d="M22 5h-6" />
</svg>

After

Width:  |  Height:  |  Size: 388 B

17
icons/image-plus.svg Normal file
View File

@@ -0,0 +1,17 @@
<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 11v8a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h8" />
<path d="M8.5 10a1.5 1.5 0 100-3 1.5 1.5 0 000 3z" />
<path d="M21 15l-5-5L5 21" />
<path d="M19 2v6" />
<path d="M22 5h-6" />
</svg>

After

Width:  |  Height:  |  Size: 411 B

View File

@@ -9,5 +9,5 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="M18.1783 8C23.2739 8 23.2739 16 18.1783 16C13.0828 16 11.0446 8 5.43949 8C0.853503 8 0.853504 16 5.43949 16C11.0446 16 13.0828 8 18.1783 8Z" /> <path d="M18.178 8c5.096 0 5.096 8 0 8-5.095 0-7.133-8-12.739-8-4.585 0-4.585 8 0 8 5.606 0 7.644-8 12.74-8z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 323 B

15
icons/inspect.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M19 11V4a2 2 0 00-2-2H4a2 2 0 00-2 2v13a2 2 0 002 2h7" />
<path d="M12 12l4.166 10 1.48-4.355L22 16.166 12 12z" />
<path d="M18 18l3 3" />
</svg>

After

Width:  |  Height:  |  Size: 362 B

14
icons/option.svg Normal file
View File

@@ -0,0 +1,14 @@
<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="M3 3h6l6 18h6" />
<path d="M14 3h7" />
</svg>

After

Width:  |  Height:  |  Size: 260 B

14
icons/pencil.svg Normal file
View File

@@ -0,0 +1,14 @@
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<line x1="18" y1="2" x2="22" y2="6" />
<path d="M7.5 20.5L19 9l-4-4L3.5 16.5 2 22l5.5-1.5z" />
</svg>

After

Width:  |  Height:  |  Size: 307 B

16
icons/podcast.svg Normal file
View File

@@ -0,0 +1,16 @@
<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="11" r="1" />
<path d="M17.03 18.46a9 9 0 10-10.02.03" />
<path d="M16.06 13.91a5 5 0 10-7.97.2" />
<path d="M11.11 17a.9.9 0 111.78 0l-.52 4.67a.37.37 0 01-.74 0l-.52-4.68z" />
</svg>

After

Width:  |  Height:  |  Size: 413 B

16
icons/radio-receiver.svg Normal file
View File

@@ -0,0 +1,16 @@
<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="M5 16v2" />
<path d="M19 16v2" />
<rect x="2" y="8" width="20" height="8" rx="2" />
<path d="M18 12h0" />
</svg>

After

Width:  |  Height:  |  Size: 331 B

16
icons/regex.svg Normal file
View File

@@ -0,0 +1,16 @@
<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="M17 3v10" />
<path d="M12.67 5.5l8.66 5" />
<path d="M12.67 10.5l8.66-5" />
<path d="M9 17a2 2 0 00-2-2H5a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2v-2z" />
</svg>

After

Width:  |  Height:  |  Size: 380 B

17
icons/repeat-1.svg Normal file
View File

@@ -0,0 +1,17 @@
<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="M17 2l4 4-4 4" />
<path d="M3 11v-1a4 4 0 014-4h14" />
<path d="M7 22l-4-4 4-4" />
<path d="M21 13v1a4 4 0 01-4 4H3" />
<path d="M11 10h1v4" />
</svg>

After

Width:  |  Height:  |  Size: 371 B

View File

@@ -9,9 +9,9 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="M6 10H4C2.89543 10 2 9.10457 2 8V4C2 2.89543 2.89543 2 4 2H20C21.1046 2 22 2.89543 22 4V8C22 9.10457 21.1046 10 20 10H18" /> <path d="M6 10H4a2 2 0 01-2-2V4a2 2 0 012-2h16a2 2 0 012 2v4a2 2 0 01-2 2h-2" />
<path d="M6 14H4C2.89543 14 2 14.8954 2 16V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V16C22 14.8954 21.1046 14 20 14H18" /> <path d="M6 14H4a2 2 0 00-2 2v4a2 2 0 002 2h16a2 2 0 002-2v-4a2 2 0 00-2-2h-2" />
<path d="M6 6H6.01" /> <path d="M6 6h.01" />
<path d="M6 18H6.01" /> <path d="M6 18h.01" />
<path d="M13 6L9 12H15L11 18" /> <path d="M13 6l-4 6h6l-4 6" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 457 B

15
icons/shield-alert.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
<path d="M12 8v4" />
<path d="M12 16h.01" />
</svg>

After

Width:  |  Height:  |  Size: 316 B

14
icons/shield-check.svg Normal file
View File

@@ -0,0 +1,14 @@
<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="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
<path d="M9 12l2 2 4-4" />
</svg>

After

Width:  |  Height:  |  Size: 296 B

15
icons/shield-close.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
<line x1="9.5" y1="9" x2="14.5" y2="14" />
<line x1="14.5" y1="9" x2="9.5" y2="14" />
</svg>

After

Width:  |  Height:  |  Size: 357 B

13
icons/sigma.svg Normal file
View File

@@ -0,0 +1,13 @@
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 7V4H6l6 8-6 8h12v-3" />
</svg>

After

Width:  |  Height:  |  Size: 247 B

View File

@@ -1,8 +1,8 @@
<svg <svg
viewBox="0 0 24 24"
width="24" width="24"
height="24" height="24"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
stroke-width="2" stroke-width="2"
@@ -10,7 +10,7 @@
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="M7 20h10" /> <path d="M7 20h10" />
<path d="M10 20c5.5-2.5.8-6.4 3-10"/> <path d="M10 20c5.5-2.5.8-6.4 3-10" />
<path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z"/> <path d="M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z" />
<path d="M14.1 6a7 7 0 00-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z"/> <path d="M14.1 6a7 7 0 00-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 475 B

14
icons/tv-2.svg Normal file
View File

@@ -0,0 +1,14 @@
<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="M7 21h10" />
<rect x="2" y="3" width="20" height="14" rx="2" />
</svg>

After

Width:  |  Height:  |  Size: 285 B

15
icons/wallet.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="M20 12V8H6a2 2 0 01-2-2c0-1.1.9-2 2-2h12v4" />
<path d="M4 6v12c0 1.1.9 2 2 2h14v-4" />
<path d="M18 12a2 2 0 00-2 2c0 1.1.9 2 2 2h4v-4h-4z" />
</svg>

After

Width:  |  Height:  |  Size: 367 B

15
icons/webcam.svg Normal file
View File

@@ -0,0 +1,15 @@
<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="10" r="8" />
<circle cx="12" cy="10" r="3" />
<path d="M12 22v-4m-5 4h5-5zm10 0h-5 5z" />
</svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@@ -1,12 +1,13 @@
{ {
"name": "lucide", "name": "lucide",
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.", "description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
"version": "0.12.0", "version": "0.13.0",
"license": "ISC", "license": "ISC",
"homepage": "https://lucide.netlify.app", "homepage": "https://lucide.dev",
"repository": "github:lucide-icons/lucide", "bugs": "https://github.com/lucide-icons/lucide/issues",
"bugs": { "repository": {
"url": "https://github.com/lucide-icons/lucide/issues" "type": "git",
"url": "https://github.com/lucide-icons/lucide.git"
}, },
"amdName": "lucide", "amdName": "lucide",
"source": "build/lucide.js", "source": "build/lucide.js",
@@ -24,6 +25,7 @@
"build:es": "babel build -d dist/esm", "build:es": "babel build -d dist/esm",
"build:bundles": "rollup -c rollup.config.js", "build:bundles": "rollup -c rollup.config.js",
"optimize": "npx babel-node ./scripts/optimizeSvgs.js --presets @babel/env", "optimize": "npx babel-node ./scripts/optimizeSvgs.js --presets @babel/env",
"addtags": "npx babel-node ./scripts/addMissingKeysToTags.js --presets @babel/env",
"test": "jest" "test": "jest"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -0,0 +1,9 @@
stats
node_modules
tests
scripts
build
src
babel.config.js
jest.config.js
rollup.config.js

View File

@@ -15,7 +15,7 @@ npm install lucide-react
## How to use ## How to use
It's build with ESmodules so it's completely threeshakable. It's build with ESmodules so it's completely threeshakable.
Each icon can be imported as an react component. Each icon can be imported as a react component.
### Example ### Example
@@ -56,7 +56,7 @@ const App = () => {
It is possible to create one generic icon component to load icons. It is possible to create one generic icon component to load icons.
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers. > :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
#### Icon Component Example #### Icon Component Example

View File

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

View File

@@ -1,37 +1,41 @@
{ {
"name": "lucide-react", "name": "lucide-react",
"description": "Lucide React package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.", "description": "Lucide React package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
"version": "0.12.0", "version": "0.13.0",
"license": "ISC", "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-react"
},
"author": "Eric Fennis",
"amdName": "lucide-react", "amdName": "lucide-react",
"source": "build/lucide-react.js",
"main": "dist/cjs/lucide-react.js", "main": "dist/cjs/lucide-react.js",
"main:umd": "dist/umd/lucide-react.js", "main:umd": "dist/umd/lucide-react.js",
"module": "dist/esm/lucide-react.js", "module": "dist/esm/lucide-react.js",
"unpkg": "dist/umd/lucide-react.min.js", "unpkg": "dist/umd/lucide-react.min.js",
"repository": "github:lucide-icons/lucide",
"author": "Eric Fennis",
"scripts": { "scripts": {
"build": "yarn clean && yarn build:move && yarn build:icons && yarn build:es && yarn build:bundles", "build": "yarn clean && yarn build:move && yarn build:icons && yarn build:es && yarn build:bundles",
"clean": "rm -rf dist && rm -rf build", "clean": "rm -rf dist && rm -rf build",
"build:move": "cp -av src 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 --renderUniqueKey", "build:icons": "yarn --cwd ../../ build:icons --output=../packages/lucide-react/build --templateSrc=../packages/lucide-react/scripts/exportTemplate --camelizeAttrs --noDefaultAttrs --renderUniqueKey",
"build:es": "yarn --cwd ../../ babel packages/lucide-react/build -d packages/lucide-react/dist/esm", "build:es": "yarn --cwd ../../ babel packages/lucide-react/build -d packages/lucide-react/dist/esm",
"build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-react/rollup.config.js", "build:bundles": "yarn --cwd ../../ rollup -c packages/lucide-react/rollup.config.js",
"test": "jest" "test": "jest"
}, },
"dependencies": { "dependencies": {
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^17.0.1" "react": "^16.5.1"
}, },
"devDependencies": { "devDependencies": {
"babel-preset-react-app": "^10.0.0", "babel-preset-react-app": "^10.0.0",
"jest": "^26.6.3", "jest": "^26.6.3",
"lucide": "file:../..", "react-test-renderer": "^16.5.1"
"react-test-renderer": "^17.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react": "^17.0.1" "react": "^16.5.1"
} }
} }

View File

@@ -1,7 +1,8 @@
const plugins = require('lucide/rollup.plugins'); const plugins = require('../../rollup.plugins');
const pkg = require('./package.json'); const pkg = require('./package.json');
const outputFileName = pkg.name; const packageName = 'LucideReact';
const outputFileName = 'lucide-react';
const rootDir = 'packages/lucide-react'; // It runs from the root const rootDir = 'packages/lucide-react'; // It runs from the root
const outputDir = `${rootDir}/dist`; const outputDir = `${rootDir}/dist`;
const inputs = [`${rootDir}/build/lucide-react.js`]; const inputs = [`${rootDir}/build/lucide-react.js`];
@@ -31,7 +32,7 @@ const configs = bundles
plugins: plugins(pkg, minify), plugins: plugins(pkg, minify),
external: ['react', 'prop-types'], external: ['react', 'prop-types'],
output: { output: {
name: outputFileName, name: packageName,
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`, file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
format, format,
sourcemap: true, sourcemap: true,

View File

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

View File

@@ -11,7 +11,7 @@ export default (iconName, [tag, attrs, children]) => {
...attrs, ...attrs,
width: size, width: size,
height: size, height: size,
color, stroke: color,
strokeWidth, strokeWidth,
...rest, ...rest,
}, },

View File

@@ -0,0 +1,11 @@
export default {
xmlns: 'http://www.w3.org/2000/svg',
width: 24,
height: 24,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 2,
strokeLinecap: 'round',
strokeLinejoin: 'round',
};

View File

@@ -2,7 +2,6 @@
exports[`Using lucide icon components should adjust the size, stroke color and stroke width 1`] = ` exports[`Using lucide icon components should adjust the size, stroke color and stroke width 1`] = `
<svg <svg
color="currentColor"
fill="none" fill="none"
height={48} height={48}
stroke="red" stroke="red"
@@ -50,7 +49,6 @@ exports[`Using lucide icon components should adjust the size, stroke color and s
exports[`Using lucide icon components should render an component 1`] = ` exports[`Using lucide icon components should render an component 1`] = `
<svg <svg
color="currentColor"
fill="none" fill="none"
height={24} height={24}
stroke="currentColor" stroke="currentColor"

View File

@@ -3246,9 +3246,6 @@ lru-cache@^6.0.0:
dependencies: dependencies:
yallist "^4.0.0" yallist "^4.0.0"
"lucide@file:../..":
version "0.11.0"
make-dir@^3.0.0: make-dir@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -3661,7 +3658,7 @@ prompts@^2.0.1:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@^15.7.2: prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -3693,41 +3690,34 @@ qs@~6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1: react-is@^16.8.1, react-is@^16.8.6:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
react-is@^16.8.1:
version "16.13.1" version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-shallow-renderer@^16.13.1: react-is@^17.0.1:
version "16.14.1" version "17.0.1"
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg== integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
react-test-renderer@^16.5.1:
version "16.14.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.14.0.tgz#e98360087348e260c56d4fe2315e970480c228ae"
integrity sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==
dependencies: dependencies:
object-assign "^4.1.1" object-assign "^4.1.1"
react-is "^16.12.0 || ^17.0.0" prop-types "^15.6.2"
react-is "^16.8.6"
scheduler "^0.19.1"
react-test-renderer@^17.0.1: react@^16.5.1:
version "17.0.1" version "16.14.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3187e636c3063e6ae498aedf21ecf972721574c7" resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
integrity sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA== integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
dependencies:
object-assign "^4.1.1"
react-is "^17.0.1"
react-shallow-renderer "^16.13.1"
scheduler "^0.20.1"
react@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127"
integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==
dependencies: dependencies:
loose-envify "^1.1.0" loose-envify "^1.1.0"
object-assign "^4.1.1" object-assign "^4.1.1"
prop-types "^15.6.2"
read-pkg-up@^7.0.1: read-pkg-up@^7.0.1:
version "7.0.1" version "7.0.1"
@@ -3962,10 +3952,10 @@ saxes@^5.0.0:
dependencies: dependencies:
xmlchars "^2.2.0" xmlchars "^2.2.0"
scheduler@^0.20.1: scheduler@^0.19.1:
version "0.20.1" version "0.19.1"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw== integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
dependencies: dependencies:
loose-envify "^1.1.0" loose-envify "^1.1.0"
object-assign "^4.1.1" object-assign "^4.1.1"

View File

@@ -0,0 +1,9 @@
stats
node_modules
tests
scripts
build
src
babel.config.js
jest.config.js
rollup.config.js

View File

@@ -0,0 +1,103 @@
# Lucide Vue
Use the lucide icon library in you Vue app.
## Installation
```sh
yarn add lucide-vue
# or
npm install lucide-vue
```
## How to use
It's build with ESmodules so it's completely threeshakable.
Each icon can be imported as a vue component.
### Example
You can pass additional props to adjust the icon.
``` vue
<template>
<Camera
color="red"
:size="32"
/>
</template>
<script>
// Returns Vue component
import { Camera } from 'lucide-vue';
export default {
name: "My Component",
components: { Camera }
}
</script>
```
### Props
| name | type | default
| ------------ | -------- | --------
| `size` | *Number* | 24
| `color` | *String* | currentColor
| `strokeWidth`| *Number* | 2
| `defaultClass`| *String* | lucide-icon
### Custom props
You can also pass custom props that will be added in the svg as attributes.
``` vue
<template>
<Camera fill="red" />
</template>
```
### One generic icon component
It is possible to create one generic icon component to load icons.
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
#### Icon Component Example
``` vue
<template>
<component :is="icon" />
</template>
<script>
import * as icons from "lucide-vue";
export default {
props: {
name: {
type: String,
required: true,
},
},
computed: {
icon() {
return icons[this.name];
},
},
};
</script>
```
##### Then you can use it like this
``` vue
<template>
<div id="app">
<Icon name="Airplay" />
</div>
</template>
```

View File

@@ -0,0 +1,12 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
};

View File

@@ -0,0 +1,14 @@
module.exports = {
verbose: true,
roots: ['<rootDir>/src/', '<rootDir>/tests/'],
moduleFileExtensions: ['js'],
transform: {
'^.+\\.js$': 'babel-jest',
'^.+\\.vue$': 'vue-jest',
},
transformIgnorePatterns: [`/node_modules`],
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};

View File

@@ -0,0 +1,44 @@
{
"name": "lucide-vue",
"version": "0.13.0-beta.1",
"author": "Eric Fennis",
"description": "Lucide Vue Package",
"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-vue"
},
"amdName": "lucide-vue",
"source": "build/lucide-vue.js",
"main": "dist/cjs/lucide-vue.js",
"main:umd": "dist/umd/lucide-vue.js",
"module": "dist/esm/lucide-vue.js",
"unpkg": "dist/umd/lucide-vue.min.js",
"dependencies": {
"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: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"
},
"peerDependencies": {
"vue": "^2.6.12"
}
}

View File

@@ -0,0 +1,47 @@
const plugins = require('../../rollup.plugins');
const pkg = require('./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 bundles = [
{
format: 'umd',
inputs,
outputDir,
minify: true,
},
{
format: 'umd',
inputs,
outputDir,
},
{
format: 'cjs',
inputs,
outputDir,
},
];
const configs = bundles
.map(({ inputs, outputDir, format, minify }) =>
inputs.map(input => ({
input,
plugins: plugins(pkg, minify),
external: ['vue'],
output: {
name: packageName,
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
format,
sourcemap: true,
globals: {
vue: 'vue',
},
},
})),
)
.flat();
export default configs;

View File

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

View File

@@ -0,0 +1,47 @@
export default (iconName, [tag, defaultAttrs, children]) => ({
name: iconName,
functional: true,
props: {
color: {
type: String,
default: 'currentColor',
},
size: {
type: Number,
default: 24,
},
strokeWidth: {
type: Number,
default: 2,
},
defaultClass: {
type: String,
default: 'lucide-icon',
},
},
render(
createElement,
{
props: { color, size, strokeWidth, defaultClass },
data,
},
) {
return createElement(
tag,
{
// 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,
width: size,
height: size,
stroke: color,
'stroke-width': strokeWidth,
...data.attrs,
},
},
children.map(([childTag, childAttrs]) => createElement(childTag, { attrs: childAttrs })),
);
},
});

View File

@@ -0,0 +1,11 @@
export default {
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',
};

View File

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

View File

@@ -0,0 +1 @@
export * from './icons';

View File

@@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Using lucide icon components should add a class to the element 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" class="lucide-icon my-icon">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>
`;
exports[`Using lucide icon components should add a style attribute to the element 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" style="position: absolute" class="lucide-icon">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>
`;
exports[`Using lucide icon components should adjust the size, stroke color and stroke width 1`] = `
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="red" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" class="lucide-icon">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>
`;
exports[`Using lucide icon components should render an component 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" class="lucide-icon">
<circle cx="12" cy="12" r="10"></circle>
<path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
<line x1="9" y1="9" x2="9.01" y2="9"></line>
<line x1="15" y1="9" x2="15.01" y2="9"></line>
</svg>
`;

View File

@@ -0,0 +1,45 @@
import { mount } from '@vue/test-utils'
import { Smile } from '..'
describe('Using lucide icon components', () => {
it('should render an component', () => {
const wrapper = mount(Smile)
expect(wrapper).toMatchSnapshot();
});
it('should adjust the size, stroke color and stroke width', () => {
const wrapper = mount(Smile, {
propsData: {
size: 48,
stroke: 'red',
strokeWidth: 4
}
})
expect(wrapper).toMatchSnapshot();
});
it('should add a class to the element', () => {
const wrapper = mount(Smile, {
attrs: {
class: "my-icon"
}
})
expect(wrapper).toMatchSnapshot();
expect(String(wrapper.classes())).toBe(String(['lucide-icon', 'my-icon']))
});
it('should add a style attribute to the element', () => {
const wrapper = mount(Smile, {
attrs: {
style: 'position: absolute',
}
})
expect(wrapper).toMatchSnapshot();
expect(wrapper.attributes('style')).toContain('position: absolute')
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
import path from 'path';
import tags from '../tags.json';
import { readSvgDirectory, writeFile } from './helpers';
const ICONS_DIR = path.resolve(__dirname, '../icons');
console.log(`Read all tags`);
const svgFiles = readSvgDirectory(ICONS_DIR);
const iconNames = svgFiles.map(icon => icon.split('.')[0]);
const iconTags = iconNames
.map(iconName => ({
name: iconName,
tags: tags[iconName] || [],
}))
.sort((a, b) => {
const nameA = a.name;
const nameB = b.name;
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
const newTags = iconTags.reduce((acc, { name, tags }) => {
acc[name] = tags;
return acc;
}, {});
const tagsContent = JSON.stringify(newTags, null, 2);
writeFile(tagsContent, 'tags.json', path.resolve(__dirname, '..'));

View File

@@ -1,5 +1,6 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
// eslint-disable-next-line import/no-extraneous-dependencies
import getArgumentOptions from 'minimist'; import getArgumentOptions from 'minimist';
import renderIconsObject from './render/renderIconsObject'; import renderIconsObject from './render/renderIconsObject';

View File

@@ -38,13 +38,15 @@ export default (iconsObject, options) => {
]; ];
}); });
iconNodes[icon] = [ iconNodes[icon] = !options.noDefaultAttrs
'svg', ? [
{ 'svg',
...(options.camelizeAttrs ? camelizeAttrs(DEFAULT_ATTRS) : DEFAULT_ATTRS), {
}, ...(options.camelizeAttrs ? camelizeAttrs(DEFAULT_ATTRS) : DEFAULT_ATTRS),
children, },
]; children,
]
: children;
}); });
return iconNodes; return iconNodes;

View File

@@ -13,7 +13,7 @@
"dependencies": { "dependencies": {
"@chakra-ui/core": "^1.0.0-rc.8", "@chakra-ui/core": "^1.0.0-rc.8",
"downloadjs": "^1.4.7", "downloadjs": "^1.4.7",
"framer-motion": "^2.9.4", "framer-motion": "^3.3.0",
"fuse.js": "^6.0.4", "fuse.js": "^6.0.4",
"jszip": "^3.4.0", "jszip": "^3.4.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
@@ -23,7 +23,6 @@
"react": "^16.13.1", "react": "^16.13.1",
"react-color": "2.17.3", "react-color": "2.17.3",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-spring": "^8.0.27",
"react-svg-loader": "^3.0.3" "react-svg-loader": "^3.0.3"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" fill="white"/>
<svg class="icon-grid" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#dedede" stroke-width="0.1" xmlns="http://www.w3.org/2000/svg"><g><line x1="0" y1="1" x2="24" y2="1"></line><line x1="1" y1="0" x2="1" y2="24"></line></g><g><line x1="0" y1="2" x2="24" y2="2"></line><line x1="2" y1="0" x2="2" y2="24"></line></g><g><line x1="0" y1="3" x2="24" y2="3"></line><line x1="3" y1="0" x2="3" y2="24"></line></g><g><line x1="0" y1="4" x2="24" y2="4"></line><line x1="4" y1="0" x2="4" y2="24"></line></g><g><line x1="0" y1="5" x2="24" y2="5"></line><line x1="5" y1="0" x2="5" y2="24"></line></g><g><line x1="0" y1="6" x2="24" y2="6"></line><line x1="6" y1="0" x2="6" y2="24"></line></g><g><line x1="0" y1="7" x2="24" y2="7"></line><line x1="7" y1="0" x2="7" y2="24"></line></g><g><line x1="0" y1="8" x2="24" y2="8"></line><line x1="8" y1="0" x2="8" y2="24"></line></g><g><line x1="0" y1="9" x2="24" y2="9"></line><line x1="9" y1="0" x2="9" y2="24"></line></g><g><line x1="0" y1="10" x2="24" y2="10"></line><line x1="10" y1="0" x2="10" y2="24"></line></g><g><line x1="0" y1="11" x2="24" y2="11"></line><line x1="11" y1="0" x2="11" y2="24"></line></g><g><line x1="0" y1="12" x2="24" y2="12"></line><line x1="12" y1="0" x2="12" y2="24"></line></g><g><line x1="0" y1="13" x2="24" y2="13"></line><line x1="13" y1="0" x2="13" y2="24"></line></g><g><line x1="0" y1="14" x2="24" y2="14"></line><line x1="14" y1="0" x2="14" y2="24"></line></g><g><line x1="0" y1="15" x2="24" y2="15"></line><line x1="15" y1="0" x2="15" y2="24"></line></g><g><line x1="0" y1="16" x2="24" y2="16"></line><line x1="16" y1="0" x2="16" y2="24"></line></g><g><line x1="0" y1="17" x2="24" y2="17"></line><line x1="17" y1="0" x2="17" y2="24"></line></g><g><line x1="0" y1="18" x2="24" y2="18"></line><line x1="18" y1="0" x2="18" y2="24"></line></g><g><line x1="0" y1="19" x2="24" y2="19"></line><line x1="19" y1="0" x2="19" y2="24"></line></g><g><line x1="0" y1="20" x2="24" y2="20"></line><line x1="20" y1="0" x2="20" y2="24"></line></g><g><line x1="0" y1="21" x2="24" y2="21"></line><line x1="21" y1="0" x2="21" y2="24"></line></g><g><line x1="0" y1="22" x2="24" y2="22"></line><line x1="22" y1="0" x2="22" y2="24"></line></g><g><line x1="0" y1="23" x2="24" y2="23"></line><line x1="23" y1="0" x2="23" y2="24"></line></g></svg>
<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="M14 12C14 9.79086 12.2091 8 10 8C7.79086 8 6 9.79086 6 12C6 16.4183 9.58172 20 14 20C18.4183 20 22 16.4183 22 12C22 8.446 20.455 5.25285 18 3.05557" />
<path d="M10 12C10 14.2091 11.7909 16 14 16C16.2091 16 18 14.2091 18 12C18 7.58172 14.4183 4 10 4C5.58172 4 2 7.58172 2 12C2 15.5841 3.57127 18.8012 6.06253 21" stroke="#F56565" />
</svg>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

6
site/public/vercel.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,4 +1,4 @@
import {Button, Flex, Link, Stack, Text,} from "@chakra-ui/core"; import {Button, Flex, Link, WrapItem, Text, Wrap,} from "@chakra-ui/core";
import download from "downloadjs"; import download from "downloadjs";
import JSZip from "jszip"; import JSZip from "jszip";
import { Download, Github } from 'lucide-react'; import { Download, Github } from 'lucide-react';
@@ -30,15 +30,26 @@ const Header = ({ data }) => {
<Text fontSize="lg" as="p" textAlign="center" mb="8"> <Text fontSize="lg" as="p" textAlign="center" mb="8">
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>! 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> </Text>
<Stack isInline marginTop={3} marginBottom={10}> <Wrap
<Button isInline
leftIcon={<Download/>} marginTop={3}
size="lg" marginBottom={10}
onClick={downloadAllIcons} spacing="15px"
> justify="center"
Download all >
</Button> <WrapItem>
<Button
leftIcon={<Download/>}
size="lg"
onClick={downloadAllIcons}
>
Download all
</Button>
</WrapItem>
<WrapItem>
<IconCustomizerDrawer/> <IconCustomizerDrawer/>
</WrapItem>
<WrapItem>
<Button <Button
as="a" as="a"
leftIcon={<Github/>} leftIcon={<Github/>}
@@ -49,7 +60,8 @@ const Header = ({ data }) => {
> >
Github Github
</Button> </Button>
</Stack> </WrapItem>
</Wrap>
</Flex> </Flex>
) )
}; };

View File

@@ -1,41 +1,37 @@
import { useSpring, animated } from "react-spring"; import { Box, Text, IconButton, useColorMode, Flex, Slide, ButtonGroup, Button, useToast, Heading, Avatar, AvatarGroup, Link, Tooltip, useMediaQuery, useDisclosure } from "@chakra-ui/core";
import { Box, Text, IconButton, useColorMode, Flex, ButtonGroup, Button, useToast } from "@chakra-ui/core";
import theme from "../lib/theme"; import theme from "../lib/theme";
import download from 'downloadjs'; import download from 'downloadjs';
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import { X as Close } from 'lucide-react'; import { X as Close } from 'lucide-react';
import {useContext, useRef} from "react"; import {useContext, useEffect, useRef} from "react";
import {IconStyleContext} from "./CustomizeIconContext"; import {IconStyleContext} from "./CustomizeIconContext";
import {IconWrapper} from "./IconWrapper"; import {IconWrapper} from "./IconWrapper";
import ModifiedTooltip from "./ModifiedTooltip";
type IconDownload = { type IconDownload = {
src: string; src: string;
name: string; name: string;
}; };
const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => { const IconDetailOverlay = ({ open = true, close, icon }) => {
const toast = useToast(); const toast = useToast();
const { colorMode } = useColorMode(); const { colorMode } = useColorMode();
const { tags = [], name } = icon; const { tags = [], name } = icon;
const {color, strokeWidth, size} = useContext(IconStyleContext); const {color, strokeWidth, size} = useContext(IconStyleContext);
const iconRef = useRef<SVGSVGElement>(null); const iconRef = useRef<SVGSVGElement>(null);
const [isMobile] = useMediaQuery("(max-width: 560px)")
const { transform, opacity } = useSpring({ const { isOpen, onOpen, onClose } = useDisclosure()
opacity: isOpen ? 1 : 0,
transform: `translateY(${isOpen ? -120 : 0}%)`,
config: { mass: 5, tension: 500, friction: 80 },
});
const handleClose = () => { const handleClose = () => {
onClose(); onClose();
close();
}; };
const panelStyling = { useEffect(() => {
transform: transform.interpolate(t => t), if(open) {
opacity: opacity.interpolate(o => o), onOpen()
width: "100%", }
willChange: "transform" }, [open])
}
const iconStyling = (isLight) => ({ const iconStyling = (isLight) => ({
height: "25vw", height: "25vw",
@@ -88,6 +84,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
height={0} height={0}
key={name} key={name}
> >
<Slide direction="bottom" in={isOpen} style={{ zIndex: 10 }}>
<Flex <Flex
alignItems="center" alignItems="center"
justifyContent="space-between" justifyContent="space-between"
@@ -98,9 +95,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
w="full" w="full"
px={8} px={8}
> >
<animated.div
style={panelStyling}
>
<Box <Box
borderWidth="1px" borderWidth="1px"
rounded="lg" rounded="lg"
@@ -163,11 +158,25 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
</svg> </svg>
</Box> </Box>
</Flex> </Flex>
<Flex marginLeft={[0, 8]}> <Flex marginLeft={[0, 8]} w="100%">
<Box> <Box w="100%">
<Text fontSize="3xl" style={{ cursor: "pointer" }} mb={1}> <Flex
{icon.name} justify={isMobile ? 'center' : 'flex-start'}
</Text> marginTop={isMobile ? 10 : 0}
>
<Box
position="relative"
mb={1}
display="inline-block"
style={{ cursor: "pointer" }}
pr={6}
>
<Text fontSize="3xl">
{icon.name}
</Text>
{ icon?.contributors?.length ? ( <ModifiedTooltip/> ) : null}
</Box>
</Flex>
<Box mb={4}> <Box mb={4}>
{ tags?.length ? ( { tags?.length ? (
<Text <Text
@@ -187,23 +196,42 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
Edit Tags Edit Tags
</Button> */} </Button> */}
</Box> </Box>
<ButtonGroup spacing={4}> <Box overflowY="auto" w="100%" pt={1} pb={1}>
<Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}> <ButtonGroup spacing={4}>
Download SVG <Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
</Button> Download SVG
<Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}> </Button>
Copy SVG <Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
</Button> Copy SVG
<Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}> </Button>
Download PNG <Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
</Button> Download PNG
</ButtonGroup> </Button>
</ButtonGroup>
</Box>
{ icon?.contributors?.length ? (
<>
<Heading as="h5" size="sm" marginTop={4} marginBottom={2}>
Contributors:
</Heading>
<AvatarGroup size="md">
{ 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`} />
</Tooltip>
</Link>
)) }
</AvatarGroup>
</>
) : null }
</Box> </Box>
</Flex> </Flex>
</Flex> </Flex>
</Box> </Box>
</animated.div>
</Flex> </Flex>
</Slide>
</Box> </Box>
); );
}; };

View File

@@ -6,6 +6,7 @@ import {useContext, useMemo} from "react";
import {IconStyleContext} from "./CustomizeIconContext"; import {IconStyleContext} from "./CustomizeIconContext";
import {IconWrapper} from "./IconWrapper"; import {IconWrapper} from "./IconWrapper";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import ModifiedTooltip from './ModifiedTooltip';
const IconList = ({icons}) => { const IconList = ({icons}) => {
const router = useRouter() const router = useRouter()
@@ -17,13 +18,13 @@ const IconList = ({icons}) => {
return ( return (
<Grid <Grid
templateColumns={`repeat(auto-fill, minmax(160px, 1fr))`} templateColumns={`repeat(auto-fill, minmax(150px, 1fr))`}
gap={5} gap={5}
marginBottom="320px" marginBottom="320px"
> >
{ icons.map((icon) => { { icons.map((icon) => {
const actualIcon = icon.item ? icon.item : icon; const actualIcon = icon.item ? icon.item : icon;
const { name, content } = actualIcon; const { name, content, contributors } = actualIcon;
return ( return (
<Link <Link
@@ -42,6 +43,7 @@ const IconList = ({icons}) => {
borderWidth="1px" borderWidth="1px"
rounded="lg" rounded="lg"
padding={16} padding={16}
position="relative"
onClick={(event) => { onClick={(event) => {
if (event.shiftKey) { if (event.shiftKey) {
copy(actualIcon.src); copy(actualIcon.src);
@@ -63,6 +65,7 @@ const IconList = ({icons}) => {
key={name} key={name}
alignItems="center" alignItems="center"
> >
{ contributors?.length ? ( <ModifiedTooltip/> ) : null}
<Flex direction="column" align="center" justify="center"> <Flex direction="column" align="center" justify="center">
<IconWrapper <IconWrapper
content={content} content={content}

View File

@@ -38,7 +38,7 @@ const Layout = ({ children }) => {
maxW="1250px" maxW="1250px"
margin="0 auto" margin="0 auto"
w="full" w="full"
px={8} px={5}
> >
<Flex justifyContent="center" alignItems="center"> <Flex justifyContent="center" alignItems="center">
<NextLink href="/" passHref> <NextLink href="/" passHref>
@@ -77,9 +77,15 @@ const Layout = ({ children }) => {
</Flex> </Flex>
</Flex> </Flex>
</Flex> </Flex>
<Flex margin="0 auto" direction="column" maxW="1250px" px={8}> <Flex margin="0 auto" direction="column" maxW="1250px" px={5}>
{children} {children}
<Divider marginTop={4} marginBottom={8} /> <Divider marginBottom={8} />
<p style={{ alignSelf: "center" }}>
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
</a>
</p>
<br />
</Flex> </Flex>
</Box> </Box>
); );

View File

@@ -0,0 +1,31 @@
import { Box, Tooltip, useColorMode } from "@chakra-ui/core";
import theme from '../lib/theme';
const ModifiedTooltip = ({}) => {
const { colorMode } = useColorMode();
return (
<Tooltip
hasArrow
label="This is new or modified icon"
bg={colorMode === 'light' ? theme.colors.white : theme.colors.gray[700]}
color={colorMode === 'dark' ? theme.colors.white : null}
>
<Box
{
...{
position: 'absolute',
height: '8px',
width: '8px',
background: '#F56565',
top: '8px',
right: '8px',
borderRadius: '4px'
}
}
/>
</Tooltip>
)
}
export default ModifiedTooltip;

View File

@@ -0,0 +1,129 @@
import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
const IGNORE_COMMIT_MESSAGES = ['fork', 'optimize'];
function getContentHashOfFile(path) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('md4');
const stream = fs.createReadStream(path);
stream.on('error', err => reject(err));
stream.on('data', chunk => hash.update(chunk));
stream.on('end', () => resolve(hash.digest('hex')));
});
}
const fetchCommitsOfIcon = (name) =>
new Promise(async (resolve, reject) => {
try {
const headers = new Headers();
const username = 'ericfennis';
const password = process.env.GITHUB_API_KEY;
headers.set(
'Authorization',
`Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
);
const res = await fetch(
`https://api.github.com/repos/lucide-icons/lucide/commits?path=icons/${name}.svg`,
{
method: 'GET',
headers,
},
);
const data = await res.json();
resolve({
name,
commits: data,
});
} catch (error) {
reject(error);
}
});
export const filterCommits = (commits) =>
commits.filter(({ commit }) =>
!IGNORE_COMMIT_MESSAGES.some(ignoreItem =>
commit.message.toLowerCase().includes(ignoreItem),
))
.map(({ sha, author, commit }) => ({
author: author && author.login ? author.login : null,
commit: sha,
}));
const getIconHash = async (icon) => await getContentHashOfFile(path.join(process.cwd(), "../icons", `${icon}.svg`))
const iconCacheDir = path.join(process.cwd(),'.next/cache/github-api');
const iconCache = (hash) => path.join(iconCacheDir, `${hash}.json`);
export async function checkIconCache(icon) {
const hash = await getIconHash(icon);
const cachePath = iconCache(hash);
if(fs.existsSync( cachePath )) {
const iconCache = fs.readFileSync(cachePath, "utf8");
return JSON.parse(iconCache)
}
return false
}
async function writeIconCache(icon, content) {
const hash = await getIconHash(icon);
const iconCachePath = iconCache(hash);
if (!fs.existsSync(iconCacheDir)){
fs.mkdirSync(iconCacheDir);
}
fs.writeFileSync(iconCachePath, JSON.stringify(content), 'utf-8');
}
export async function getContributors(icon) {
try {
let iconCommits
const iconCache = await checkIconCache(icon);
if (iconCache) {
iconCommits = iconCache
} else {
const { commits } : any = await fetchCommitsOfIcon(icon);
writeIconCache(icon, commits)
iconCommits = commits
}
if (iconCommits && iconCommits.length) {
return filterCommits(iconCommits);
}
return [];
} catch (error) {
throw new Error(error);
}
}
export async function getAllContributors(icons) {
try {
const AllIconCommits = await Promise.all(icons.map(fetchCommitsOfIcon));
const filteredCommits = AllIconCommits.reduce((acc, { name, commits }) => {
if (commits && commits.length) {
acc[name] = filterCommits(commits)
}
return acc;
}, {});
return filteredCommits
} catch (error) {
console.error(error);
}
}

View File

@@ -2,6 +2,7 @@ import fs from "fs";
import path from "path"; import path from "path";
import cheerio from 'cheerio'; import cheerio from 'cheerio';
import tags from '../../../tags.json'; import tags from '../../../tags.json';
import { getContributors } from "./fetchAllContributors";
const directory = path.join(process.cwd(), "../icons"); const directory = path.join(process.cwd(), "../icons");
@@ -13,25 +14,26 @@ export function getAllNames() {
}); });
} }
export function getData(name) { export async function getData(name:string) {
const fullPath = path.join(directory, `${name}.svg`); const fullPath = path.join(directory, `${name}.svg`);
const fileContents = fs.readFileSync(fullPath, "utf8"); const fileContents = fs.readFileSync(fullPath, "utf8");
const $ = cheerio.load(fileContents); const $ = cheerio.load(fileContents);
const content = $("svg").html(); const content = $("svg").html();
const contributors = await getContributors(name);
return { return {
name, name,
tags: tags[name] || [], tags: tags[name] || [],
contributors,
src: fileContents, src: fileContents,
content: content content: content
}; };
} }
export function getAllData() { export async function getAllData() {
const names = getAllNames(); const names = getAllNames();
return names.map((name) => { return Promise.all(names.map((name) => getData(name)));
return getData(name);
});
} }

View File

@@ -2,6 +2,7 @@ import { ChakraProvider } from '@chakra-ui/core';
import customTheme from '../lib/theme'; import customTheme from '../lib/theme';
import '../assets/styling.css'; import '../assets/styling.css';
import Head from 'next/head'; import Head from 'next/head';
import { CustomizeIconContext } from "../components/CustomizeIconContext";
const App = ({ Component, pageProps }) => { const App = ({ Component, pageProps }) => {
return ( return (
@@ -10,7 +11,9 @@ const App = ({ Component, pageProps }) => {
<title>Lucide</title> <title>Lucide</title>
</Head> </Head>
<ChakraProvider theme={customTheme}> <ChakraProvider theme={customTheme}>
<Component {...pageProps} /> <CustomizeIconContext>
<Component {...pageProps} />
</CustomizeIconContext>
</ChakraProvider> </ChakraProvider>
</> </>
); );

View File

@@ -1,4 +1,3 @@
import { useEffect } from 'react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import IconDetailOverlay from '../../components/IconDetailOverlay' import IconDetailOverlay from '../../components/IconDetailOverlay'
import { getAllData, getData } from '../../lib/icons'; import { getAllData, getData } from '../../lib/icons';
@@ -29,7 +28,7 @@ const IconPage = ({ icon, data }) => {
<IconDetailOverlay <IconDetailOverlay
key={icon.name} key={icon.name}
icon={icon} icon={icon}
onClose={onClose} close={onClose}
/> />
<Header {...{data}}/> <Header {...{data}}/>
<IconOverview {...{data}}/> <IconOverview {...{data}}/>
@@ -39,15 +38,17 @@ const IconPage = ({ icon, data }) => {
export default IconPage export default IconPage
export function getStaticProps({ params: { iconName } }) { export async function getStaticProps({ params: { iconName } }) {
const data = getAllData(); const data = await getAllData();
const icon = getData(iconName); const icon = await getData(iconName);
return { props: { icon, data } } return { props: { icon, data } }
} }
export function getStaticPaths() { export async function getStaticPaths() {
const data = await getAllData();
return { return {
paths: getAllData().map(({name: iconName }) => ({ paths: data.map(({ name: iconName }) => ({
params: { iconName }, params: { iconName },
})), })),
fallback: false, fallback: false,

View File

@@ -5,7 +5,6 @@ import IconOverview from "../components/IconOverview";
import IconDetailOverlay from "../components/IconDetailOverlay"; import IconDetailOverlay from "../components/IconDetailOverlay";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Header from "../components/Header"; import Header from "../components/Header";
import {CustomizeIconContext} from "../components/CustomizeIconContext";
const IndexPage = ({ data }) => { const IndexPage = ({ data }) => {
const router = useRouter(); const router = useRouter();
@@ -13,21 +12,19 @@ const IndexPage = ({ data }) => {
return ( return (
<Layout> <Layout>
<CustomizeIconContext> <IconDetailOverlay
<IconDetailOverlay open={!!router.query.iconName}
isOpen={!!router.query.iconName} icon={getIcon(router.query.iconName)}
icon={getIcon(router.query.iconName)} close={() => router.push('/')}
onClose={() => router.push('/')} />
/> <Header {...{data}}/>
<Header {...{data}}/> <IconOverview {...{data}}/>
<IconOverview {...{data}}/>
</CustomizeIconContext>
</Layout> </Layout>
); );
}; };
export async function getStaticProps() { export async function getStaticProps() {
let data = getAllData(); let data = await getAllData();
return { return {
props: { props: {

View File

@@ -356,7 +356,7 @@
core-js-pure "^3.0.0" core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/runtime@7.12.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.9.2": "@babel/runtime@7.12.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.9.2":
version "7.12.5" version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
@@ -3774,25 +3774,23 @@ fragment-cache@^0.2.1:
dependencies: dependencies:
map-cache "^0.2.2" map-cache "^0.2.2"
framer-motion@^2.9.4: framer-motion@^3.3.0:
version "2.9.5" version "3.3.0"
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.9.5.tgz#bbb185325d531c57f494cf3f6cf7719fc2c225c7" resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-3.3.0.tgz#e355824369f03c8cd07a87ef59b7a8348c33fafd"
integrity sha512-epSX4Co1YbDv0mjfHouuY0q361TpHE7WQzCp/xMTilxy4kXd+Z23uJzPVorfzbm1a/9q1Yu8T5bndaw65NI4Tg== integrity sha512-bjUrwXfMJZ6D+HSMDiXbMGKmlWGnUux8HotWgORTZkdPTgKAndlRXjeC2ikCgNVo2ifmRvEla5ckP9JaZc7JKA==
dependencies: dependencies:
framesync "^4.1.0" framesync "^5.0.0"
hey-listen "^1.0.8" hey-listen "^1.0.8"
popmotion "9.0.0-rc.20" popmotion "^9.1.0"
style-value-types "^3.1.9" style-value-types "^4.0.1"
tslib "^1.10.0" tslib "^1.10.0"
optionalDependencies: optionalDependencies:
"@emotion/is-prop-valid" "^0.8.2" "@emotion/is-prop-valid" "^0.8.2"
framesync@^4.1.0: framesync@5.0.0, framesync@^5.0.0:
version "4.1.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a" resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.0.0.tgz#7de8caedf53ac441118e79680f1beb7391c328b6"
integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ== integrity sha512-wd8t+JsQGisluSv1twiEeDv0aNGpavGb9q7xgIk9fGbcIWkNXF/KVtrjnOrCwBWJuiXxlJfNkcvGudsI32FxYA==
dependencies:
hey-listen "^1.0.5"
from2@^2.1.0: from2@^2.1.0:
version "2.3.0" version "2.3.0"
@@ -4064,7 +4062,7 @@ he@1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hey-listen@^1.0.5, hey-listen@^1.0.8: hey-listen@^1.0.8:
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
@@ -6049,14 +6047,14 @@ pnp-webpack-plugin@1.6.4:
dependencies: dependencies:
ts-pnp "^1.1.6" ts-pnp "^1.1.6"
popmotion@9.0.0-rc.20: popmotion@^9.1.0:
version "9.0.0-rc.20" version "9.1.0"
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.20.tgz#f3550042ae31957b5416793ae8723200951ad39d" resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.1.0.tgz#4360d06bd18ce8baa8f9284ecec7d55344af6325"
integrity sha512-f98sny03WuA+c8ckBjNNXotJD4G2utG/I3Q23NU69OEafrXtxxSukAaJBxzbtxwDvz3vtZK69pu9ojdkMoBNTg== integrity sha512-+J7pzzBy5kk2qsP8ilowKs/CH+HoZa3kOGEBNCleCvsPXEF3nKHdfAR3SboMyPvdpIrofaT7ZIy/xWgz446Azw==
dependencies: dependencies:
framesync "^4.1.0" framesync "5.0.0"
hey-listen "^1.0.8" hey-listen "^1.0.8"
style-value-types "^3.1.9" style-value-types "^4.0.1"
tslib "^1.10.0" tslib "^1.10.0"
posix-character-classes@^0.1.0: posix-character-classes@^0.1.0:
@@ -6215,7 +6213,7 @@ prompts@^2.0.1:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -6421,14 +6419,6 @@ react-remove-scroll@2.4.0:
use-callback-ref "^1.2.3" use-callback-ref "^1.2.3"
use-sidecar "^1.0.1" use-sidecar "^1.0.1"
react-spring@^8.0.27:
version "8.0.27"
resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.27.tgz#97d4dee677f41e0b2adcb696f3839680a3aa356a"
integrity sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==
dependencies:
"@babel/runtime" "^7.3.1"
prop-types "^15.5.8"
react-style-singleton@^2.1.0: react-style-singleton@^2.1.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
@@ -7343,10 +7333,10 @@ style-loader@1.2.1:
loader-utils "^2.0.0" loader-utils "^2.0.0"
schema-utils "^2.6.6" schema-utils "^2.6.6"
style-value-types@^3.1.9: style-value-types@^4.0.1:
version "3.2.0" version "4.0.1"
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.2.0.tgz#eb89cab1340823fa7876f3e289d29d99c92111bb" resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-4.0.1.tgz#23f05dd03e8a850654defc22cf03ebac572aaa00"
integrity sha512-ih0mGsrYYmVvdDi++/66O6BaQPRPRMQHoZevNNdMMcPlP/cH28Rnfsqf1UEba/Bwfuw9T8BmIMwbGdzsPwQKrQ== integrity sha512-aOV/HHyynIyTmU27qfs0oAHhFde6BFIvV4+nMerE2MAPZMwYOeQk1/F3S6djxF2u4HdbiieCPs3ZzWsbNUoc9A==
dependencies: dependencies:
hey-listen "^1.0.8" hey-listen "^1.0.8"
tslib "^1.10.0" tslib "^1.10.0"

View File

@@ -0,0 +1,11 @@
export default {
xmlns: 'http://www.w3.org/2000/svg',
width: 24,
height: 24,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
strokeWidth: 2,
strokeLinecap: 'round',
strokeLinejoin: 'round',
};

1915
tags.json

File diff suppressed because it is too large Load Diff