Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95a7d8648f | ||
|
|
b07eb8c00d | ||
|
|
40cb396a6c | ||
|
|
87ab0bfb62 | ||
|
|
c4f50417d5 | ||
|
|
0ca1b98689 | ||
|
|
7ce35bac34 | ||
|
|
7bd41d9b48 | ||
|
|
5ec34cb249 | ||
|
|
4024911219 | ||
|
|
acea1b4116 | ||
|
|
ec3542dab8 | ||
|
|
51cf68c11f | ||
|
|
0c460bc3dd | ||
|
|
7e91be9e38 | ||
|
|
d042899a06 | ||
|
|
891115f6fd | ||
|
|
8ce52d834d | ||
|
|
b6ea440d70 | ||
|
|
a3125d53cb | ||
|
|
a7e8b3bcb7 | ||
|
|
c4dfe6b8cb | ||
|
|
90e86767d8 | ||
|
|
30f7be3fd4 | ||
|
|
313b46ecc1 | ||
|
|
367f89ef1f | ||
|
|
32ba19d591 | ||
|
|
5d945372d4 | ||
|
|
736b888608 | ||
|
|
fc03912eef | ||
|
|
0864092670 | ||
|
|
400f7871d2 | ||
|
|
0ce207bc2f | ||
|
|
8c85053002 | ||
|
|
a453c61aa5 | ||
|
|
5ad6f5bba3 | ||
|
|
68b91149f2 | ||
|
|
c50b8181a0 | ||
|
|
1db690953b | ||
|
|
cef1e1aafa | ||
|
|
d29667ed99 | ||
|
|
d31c2a2f2a | ||
|
|
e4a86687e2 | ||
|
|
2d9eee74c5 | ||
|
|
0668f8aebe |
32
.github/workflows/release.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
clean: true
|
||||
|
||||
- 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
|
||||
- name: Install Dependencies Lucide
|
||||
@@ -33,6 +33,9 @@ jobs:
|
||||
- name: Build lucide package
|
||||
run: yarn build
|
||||
|
||||
- name: Test lucide package
|
||||
run: yarn test
|
||||
|
||||
# Build lucide-react
|
||||
- name: Install Dependencies lucide-react
|
||||
run: yarn --pure-lockfile
|
||||
@@ -42,6 +45,23 @@ jobs:
|
||||
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
|
||||
@@ -58,10 +78,20 @@ jobs:
|
||||
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: Commit package.json
|
||||
run: |
|
||||
git add 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" \
|
||||
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
|
||||
|
||||
@@ -5,3 +5,12 @@ node_modules
|
||||
tests
|
||||
scripts
|
||||
site
|
||||
src
|
||||
build
|
||||
babel.config.js
|
||||
categories.json
|
||||
jest.config.js
|
||||
netlify.toml
|
||||
rollup.config.js
|
||||
rollup.plugins.js
|
||||
tags.json
|
||||
|
||||
23
README.md
@@ -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
|
||||
|
||||
@@ -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)
|
||||
* [Custom binding](#custom-element-binding)
|
||||
* [React](#with-react)
|
||||
* [Vue](#with-vue)
|
||||
* [Figma](#figma)
|
||||
* [Contributing](#contributing)
|
||||
* [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).
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
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
@@ -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
@@ -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
@@ -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 |
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m9 3h6v11h4l-7 7-7-7h4z" />
|
||||
<path d="M9 3h6v11h4l-7 7-7-7h4z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 247 B |
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m3 12 7-7v4h11v6h-11v4z" />
|
||||
<path d="M3 12l7-7v4h11v6H10v4z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 246 B |
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m21 12-7-7v4h-11v6h11v4z" />
|
||||
<path d="M21 12l-7-7v4H3v6h11v4z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 247 B |
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="m9 21v-11h-4l7-7 7 7h-4v11z" />
|
||||
<path d="M9 21V10H5l7-7 7 7h-4v11z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 251 B After Width: | Height: | Size: 249 B |
15
icons/asterisk.svg
Normal 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
@@ -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 |
@@ -10,8 +10,8 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<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="M18 8a6 6 0 00-9.33-5" />
|
||||
<line x1="1" y1="1" x2="23" y2="23" />
|
||||
<path d="M2 2l20 20" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 432 B After Width: | Height: | Size: 419 B |
16
icons/bell-plus.svg
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 |
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="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>
|
||||
|
||||
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 323 B |
15
icons/inspect.svg
Normal 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 |
@@ -9,10 +9,10 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="5" y1="8" x2="11" y2="14" />
|
||||
<path d="M5 8l6 6" />
|
||||
<path d="M4 14l6-6 2-3" />
|
||||
<line x1="2" y1="5" x2="14" y2="5" />
|
||||
<line x1="7" y1="2" x2="8" y2="2" />
|
||||
<path d="M22 21l-5-10-5 10" />
|
||||
<line x1="14" y1="17" x2="20" y2="17" />
|
||||
<path d="M2 5h12" />
|
||||
<path d="M7 2h1" />
|
||||
<path d="M22 22l-5-10-5 10" />
|
||||
<path d="M14 18h6" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 363 B |
14
icons/option.svg
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 |
@@ -9,9 +9,9 @@
|
||||
stroke-linecap="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 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 6H6.01" />
|
||||
<path d="M6 18H6.01" />
|
||||
<path d="M13 6L9 12H15L11 18" />
|
||||
<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 14H4a2 2 0 00-2 2v4a2 2 0 002 2h16a2 2 0 002-2v-4a2 2 0 00-2-2h-2" />
|
||||
<path d="M6 6h.01" />
|
||||
<path d="M6 18h.01" />
|
||||
<path d="M13 6l-4 6h6l-4 6" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 573 B After Width: | Height: | Size: 457 B |
15
icons/shield-alert.svg
Normal 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
@@ -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
@@ -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
@@ -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 |
@@ -1,8 +1,8 @@
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
@@ -10,7 +10,7 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M7 20h10" />
|
||||
<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="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="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="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>
|
||||
|
||||
|
Before Width: | Height: | Size: 472 B After Width: | Height: | Size: 475 B |
14
icons/tv-2.svg
Normal 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
@@ -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
@@ -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 |
12
package.json
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "lucide",
|
||||
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
||||
"version": "0.12.0",
|
||||
"version": "0.14.0",
|
||||
"license": "ISC",
|
||||
"homepage": "https://lucide.netlify.app",
|
||||
"repository": "github:lucide-icons/lucide",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lucide-icons/lucide/issues"
|
||||
"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",
|
||||
@@ -24,6 +25,7 @@
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
25
packages/lucide-figma/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Lucide Figma plugin
|
||||
|
||||
A Figma plugin for using Lucide Icons
|
||||
|
||||
## Local development
|
||||
|
||||
1. Install the dependencies
|
||||
|
||||
```sh
|
||||
yarn
|
||||
```
|
||||
|
||||
2. Build the plugin
|
||||
|
||||
```sh
|
||||
yarn watch
|
||||
```
|
||||
|
||||
3. Open the [Figma desktop app](https://www.figma.com/downloads/)
|
||||
|
||||
4. Go to `Menu > Plugins > Development > New Plugin...`
|
||||
|
||||
5. Choose `lucide/packages/lucide-figma/manifest.json`
|
||||
|
||||
6. Run the plugin by going to `Menu > Plugins > Development > Lucide Icons`
|
||||
BIN
packages/lucide-figma/cover.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
675
packages/lucide-figma/figma.d.ts
vendored
Normal file
@@ -0,0 +1,675 @@
|
||||
// Global variable with Figma's plugin API.
|
||||
declare const figma: PluginAPI
|
||||
declare const __html__: string
|
||||
|
||||
interface PluginAPI {
|
||||
readonly currentPage: PageNode
|
||||
|
||||
// Root of the current Figma document.
|
||||
readonly root: DocumentNode
|
||||
|
||||
// API for accessing viewport information.
|
||||
readonly viewport: ViewportAPI
|
||||
|
||||
// call this once your plugin is finished executing.
|
||||
closePlugin(): void
|
||||
|
||||
// Command that the user chose through menu when launching the plugin.
|
||||
readonly command: string
|
||||
|
||||
// Finds a node by its id. If not found, returns null.
|
||||
getNodeById(id: string): BaseNode | null
|
||||
|
||||
// Finds a style by its id. If not found, returns null.
|
||||
getStyleById(id: string): BaseStyle | null
|
||||
|
||||
// Access browser APIs and/or show UI to the user.
|
||||
showUI(html: string, options?: ShowUIOptions): void
|
||||
readonly ui: UIAPI
|
||||
|
||||
// Lets you store persistent data on the user's local machine
|
||||
readonly clientStorage: ClientStorageAPI
|
||||
|
||||
// This value is returned when a property is in a "mixed" state.
|
||||
// In order to check if a property is in a mixed state, always
|
||||
// compare directly to this value. I.e.
|
||||
// `if (node.cornerRadius === figma.mixed) { ... }`
|
||||
mixed: symbol
|
||||
|
||||
// Creates new nodes. Nodes will start off inserted
|
||||
// into the current page.
|
||||
// To move them elsewhere use `appendChild` or `insertChild`
|
||||
createRectangle(): RectangleNode
|
||||
createLine(): LineNode
|
||||
createEllipse(): EllipseNode
|
||||
createPolygon(): PolygonNode
|
||||
createStar(): StarNode
|
||||
createVector(): VectorNode
|
||||
createText(): TextNode
|
||||
createBooleanOperation(): BooleanOperationNode
|
||||
createFrame(): FrameNode
|
||||
createComponent(): ComponentNode
|
||||
createPage(): PageNode
|
||||
createSlice(): SliceNode
|
||||
|
||||
// Creates styles. A style's id can be assigned to
|
||||
// node properties like textStyleId, fillStyleId, etc.
|
||||
createPaintStyle(): PaintStyle
|
||||
createTextStyle(): TextStyle
|
||||
createEffectStyle(): EffectStyle
|
||||
createGridStyle(): GridStyle
|
||||
|
||||
// These let you insert stuff from the team library if you have the key
|
||||
importComponentByKeyAsync(key: string): Promise<ComponentNode>
|
||||
importStyleByKeyAsync(key: string): Promise<BaseStyle>
|
||||
|
||||
// Return all fonts currently supported for use with the "fontName" property
|
||||
listAvailableFontsAsync(): Promise<Font[]>
|
||||
|
||||
// You must await the promise returned here before being able to use "fontName"
|
||||
loadFontAsync(fontName: FontName): Promise<void>
|
||||
|
||||
// Creates node from an SVG string.
|
||||
createNodeFromSvg(svg: string): FrameNode
|
||||
|
||||
// Creates an Image object using the provided file contents.
|
||||
createImage(data: Uint8Array): Image
|
||||
|
||||
// Groups every node in `nodes` under a new group.
|
||||
group(nodes: ReadonlyArray<BaseNode>, parent: BaseNode & ChildrenMixin, index?: number): FrameNode
|
||||
|
||||
// Flattens every node in `nodes` into a single vector network.
|
||||
flatten(nodes: ReadonlyArray<BaseNode>, parent?: BaseNode & ChildrenMixin, index?: number): VectorNode
|
||||
}
|
||||
|
||||
interface ClientStorageAPI {
|
||||
// This stores information in the browser, not on the server. It's similar to localStorage, but is
|
||||
// asynchronous, and allows storing objects, arrays, strings, numbers, booleans, null, undefined and Uint8Arrays.
|
||||
getAsync(key: string): Promise<any | undefined>
|
||||
setAsync(key: string, value: any): Promise<void>
|
||||
}
|
||||
|
||||
type ShowUIOptions = {
|
||||
visible?: boolean, // defaults to true
|
||||
width?: number, // defaults to 300
|
||||
height?: number, // defaults to 200
|
||||
}
|
||||
|
||||
interface UIAPI {
|
||||
show(): void
|
||||
hide(): void
|
||||
resize(width: number, height: number): void
|
||||
close(): void
|
||||
|
||||
// Sends a message to the iframe.
|
||||
postMessage(pluginMessage: any): void
|
||||
|
||||
// Registers a callback for messages sent by the iframe.
|
||||
onmessage: ((pluginMessage: any) => void) | undefined
|
||||
}
|
||||
|
||||
interface ViewportAPI {
|
||||
center: { x: number, y: number }
|
||||
|
||||
// 1.0 means 100% zoom, 0.5 means 50% zoom.
|
||||
zoom: number
|
||||
|
||||
// Adjust the viewport such that it shows the provided nodes.
|
||||
scrollAndZoomIntoView(nodes: ReadonlyArray<BaseNode>)
|
||||
}
|
||||
|
||||
// manifest.json format
|
||||
interface ManifestJson {
|
||||
// Name of the plugin.
|
||||
name: string
|
||||
|
||||
// Version of the runtime that the plugin uses, e.g. '0.5.0'.
|
||||
version: string
|
||||
|
||||
// The file name that contains the plugin code.
|
||||
script: string
|
||||
|
||||
// The file name that contains the html code made available in script.
|
||||
html?: string
|
||||
|
||||
// Shell command to be executed before the contents of the `html` and `script` files are read.
|
||||
build?: string
|
||||
|
||||
// Menu items to show up in UI.
|
||||
menu?: ManifestMenuItem[]
|
||||
}
|
||||
|
||||
type ManifestMenuItem =
|
||||
// Clickable menu item.
|
||||
{ name: string, command: string } |
|
||||
// Separator
|
||||
{ separator: true } |
|
||||
// Submenu
|
||||
{ name: string, menu: ManifestMenuItem[] }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Values
|
||||
|
||||
// These are the top two rows of a 3x3 matrix. This is enough to represent
|
||||
// translation, rotation, and skew.
|
||||
type Transform = [
|
||||
[number, number, number],
|
||||
[number, number, number]
|
||||
]
|
||||
|
||||
interface Vector {
|
||||
readonly x: number
|
||||
readonly y: number
|
||||
}
|
||||
|
||||
interface RGB {
|
||||
readonly r: number
|
||||
readonly g: number
|
||||
readonly b: number
|
||||
}
|
||||
|
||||
interface RGBA {
|
||||
readonly r: number
|
||||
readonly g: number
|
||||
readonly b: number
|
||||
readonly a: number
|
||||
}
|
||||
|
||||
interface FontName {
|
||||
readonly family: string
|
||||
readonly style: string
|
||||
}
|
||||
|
||||
interface ArcData {
|
||||
readonly startingAngle: number
|
||||
readonly endingAngle: number
|
||||
readonly innerRadius: number
|
||||
}
|
||||
|
||||
interface ShadowEffect {
|
||||
readonly type: "DROP_SHADOW" | "INNER_SHADOW"
|
||||
readonly color: RGBA
|
||||
readonly offset: Vector
|
||||
readonly radius: number
|
||||
readonly visible: boolean
|
||||
readonly blendMode: BlendMode
|
||||
}
|
||||
|
||||
interface BlurEffect {
|
||||
readonly type: "LAYER_BLUR" | "BACKGROUND_BLUR"
|
||||
readonly radius: number
|
||||
readonly visible: boolean
|
||||
}
|
||||
|
||||
type Effect = ShadowEffect | BlurEffect
|
||||
|
||||
type ConstraintType = "MIN" | "CENTER" | "MAX" | "STRETCH" | "SCALE"
|
||||
|
||||
interface Constraints {
|
||||
readonly horizontal: ConstraintType
|
||||
readonly vertical: ConstraintType
|
||||
}
|
||||
|
||||
interface ColorStop {
|
||||
readonly position: number
|
||||
readonly color: RGBA
|
||||
}
|
||||
|
||||
interface SolidPaint {
|
||||
readonly type: "SOLID"
|
||||
readonly color: RGB
|
||||
|
||||
readonly visible?: boolean
|
||||
readonly opacity?: number
|
||||
}
|
||||
|
||||
interface GradientPaint {
|
||||
readonly type: "GRADIENT_LINEAR" | "GRADIENT_RADIAL" | "GRADIENT_ANGULAR" | "GRADIENT_DIAMOND"
|
||||
readonly gradientTransform: Transform
|
||||
readonly gradientStops: ReadonlyArray<ColorStop>
|
||||
|
||||
readonly visible?: boolean
|
||||
readonly opacity?: number
|
||||
}
|
||||
|
||||
interface ImagePaint {
|
||||
readonly type: "IMAGE"
|
||||
readonly scaleMode: "FILL" | "FIT" | "CROP" | "TILE"
|
||||
readonly image: Image | null
|
||||
readonly imageTransform?: Transform // setting for "CROP"
|
||||
readonly scalingFactor?: number // setting for "TILE"
|
||||
|
||||
readonly visible?: boolean
|
||||
readonly opacity?: number
|
||||
}
|
||||
|
||||
type Paint = SolidPaint | GradientPaint | ImagePaint
|
||||
|
||||
interface Guide {
|
||||
readonly axis: "X" | "Y"
|
||||
readonly offset: number
|
||||
}
|
||||
|
||||
interface RowsColsLayoutGrid {
|
||||
readonly pattern: "ROWS" | "COLUMNS"
|
||||
readonly alignment: "MIN" | "STRETCH" | "CENTER"
|
||||
readonly gutterSize: number
|
||||
|
||||
readonly count: number // Infinity when "Auto" is set in the UI
|
||||
readonly sectionSize?: number // Not set for alignment: "STRETCH"
|
||||
readonly offset?: number // Not set for alignment: "CENTER"
|
||||
|
||||
readonly visible?: boolean
|
||||
readonly color?: RGBA
|
||||
}
|
||||
|
||||
interface GridLayoutGrid {
|
||||
readonly pattern: "GRID"
|
||||
readonly sectionSize: number
|
||||
|
||||
readonly visible?: boolean
|
||||
readonly color?: RGBA
|
||||
}
|
||||
|
||||
type LayoutGrid = RowsColsLayoutGrid | GridLayoutGrid
|
||||
|
||||
interface ExportSettingsImage {
|
||||
format: "JPG" | "PNG"
|
||||
contentsOnly?: boolean // defaults to true
|
||||
suffix?: string
|
||||
constraint?: { // defaults to unscaled ({ type: "SCALE", value: 1 })
|
||||
type: "SCALE" | "WIDTH" | "HEIGHT"
|
||||
value: number
|
||||
}
|
||||
}
|
||||
|
||||
interface ExportSettingsSVG {
|
||||
format: "SVG"
|
||||
contentsOnly?: boolean // defaults to true
|
||||
suffix?: string
|
||||
svgOutlineText?: boolean // defaults to true
|
||||
svgIdAttribute?: boolean // defaults to false
|
||||
svgSimplifyStroke?: boolean // defaults to true
|
||||
}
|
||||
|
||||
interface ExportSettingsPDF {
|
||||
format: "PDF"
|
||||
contentsOnly?: boolean // defaults to true
|
||||
suffix?: string
|
||||
}
|
||||
|
||||
type ExportSettings = ExportSettingsImage | ExportSettingsSVG | ExportSettingsPDF
|
||||
|
||||
type WindingRule = "NONZERO" | "EVENODD"
|
||||
|
||||
interface VectorVertex {
|
||||
readonly x: number
|
||||
readonly y: number
|
||||
readonly strokeCap?: StrokeCap
|
||||
readonly strokeJoin?: StrokeJoin
|
||||
readonly cornerRadius?: number
|
||||
readonly handleMirroring?: HandleMirroring
|
||||
}
|
||||
|
||||
interface VectorSegment {
|
||||
readonly start: number
|
||||
readonly end: number
|
||||
readonly tangentStart?: Vector // Defaults to { x: 0, y: 0 }
|
||||
readonly tangentEnd?: Vector // Defaults to { x: 0, y: 0 }
|
||||
}
|
||||
|
||||
interface VectorRegion {
|
||||
readonly windingRule: WindingRule
|
||||
readonly loops: ReadonlyArray<ReadonlyArray<number>>
|
||||
}
|
||||
|
||||
interface VectorNetwork {
|
||||
readonly vertices: ReadonlyArray<VectorVertex>
|
||||
readonly segments: ReadonlyArray<VectorSegment>
|
||||
readonly regions?: ReadonlyArray<VectorRegion> // Defaults to []
|
||||
}
|
||||
|
||||
interface VectorPath {
|
||||
// Similar to the svg fill-rule
|
||||
// "NONE" means an open path won't have a fill
|
||||
readonly windingRule: WindingRule | "NONE"
|
||||
readonly data: string
|
||||
}
|
||||
|
||||
type VectorPaths = ReadonlyArray<VectorPath>
|
||||
|
||||
interface NumberWithUnits {
|
||||
readonly value: number
|
||||
readonly units: "PIXELS" | "PERCENT"
|
||||
}
|
||||
|
||||
type BlendMode =
|
||||
"PASS_THROUGH" |
|
||||
"NORMAL" |
|
||||
"DARKEN" |
|
||||
"MULTIPLY" |
|
||||
"LINEAR_BURN" |
|
||||
"COLOR_BURN" |
|
||||
"LIGHTEN" |
|
||||
"SCREEN" |
|
||||
"LINEAR_DODGE" |
|
||||
"COLOR_DODGE" |
|
||||
"OVERLAY" |
|
||||
"SOFT_LIGHT" |
|
||||
"HARD_LIGHT" |
|
||||
"DIFFERENCE" |
|
||||
"EXCLUSION" |
|
||||
"HUE" |
|
||||
"SATURATION" |
|
||||
"COLOR" |
|
||||
"LUMINOSITY"
|
||||
|
||||
interface Font {
|
||||
fontName: FontName
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Mixins
|
||||
|
||||
interface BaseNodeMixin {
|
||||
readonly id: string
|
||||
readonly parent: (BaseNode & ChildrenMixin) | null
|
||||
name: string
|
||||
visible: boolean
|
||||
locked: boolean
|
||||
removed: boolean
|
||||
toString(): string
|
||||
remove(): void
|
||||
|
||||
// Attach custom data to a node. Only your plugin will be able to read this.
|
||||
getPluginData(key: string): string
|
||||
setPluginData(key: string, value: string): void
|
||||
|
||||
// Attach custom data to a node. All plugins will be able to read this.
|
||||
// Namespace is a string that must be at least 3 alphanumeric characters, and should
|
||||
// be a name related to your plugin. This is a mandatory argument to avoid multiple
|
||||
// multiple plugins adding keys like "data" and colliding with each other. Other
|
||||
// plugins will still be able to read shared plugin data as long as they know the
|
||||
// namespace you use.
|
||||
getSharedPluginData(namespace: string, key: string): string
|
||||
setSharedPluginData(namespace: string, key: string, value: string): void
|
||||
}
|
||||
|
||||
interface ChildrenMixin {
|
||||
// Sorted back-to-front. I.e. the top-most child is last in this array.
|
||||
readonly children: ReadonlyArray<BaseNode>
|
||||
|
||||
// Adds to the end of the .children array. I.e. visually on top of all other
|
||||
// children.
|
||||
appendChild(child: BaseNode): void
|
||||
|
||||
insertChild(index: number, child: BaseNode): void
|
||||
findAll(callback?: (node: BaseNode) => boolean): ReadonlyArray<BaseNode>
|
||||
findOne(callback: (node: BaseNode) => boolean): BaseNode | null
|
||||
}
|
||||
|
||||
interface LayoutMixin {
|
||||
readonly absoluteTransform: Transform
|
||||
relativeTransform: Transform
|
||||
x: number // The same as "relativeTransform[0][2]"
|
||||
y: number // The same as "relativeTransform[1][2]"
|
||||
rotation: number // The angle of the x axis of "relativeTransform" in degrees. Returns values from -180 to 180.
|
||||
|
||||
readonly size: Vector
|
||||
readonly width: number // The same as "size.x"
|
||||
readonly height: number // The same as "size.y"
|
||||
|
||||
// Resizes the node. If children of the node has constraints, it applies those constraints
|
||||
// width and height must be >= 0.01
|
||||
resize(width: number, height: number): void
|
||||
|
||||
// Resizes the node. Children of the node are never resized, even if those children have
|
||||
// constraints. width and height must be >= 0.01
|
||||
resizeWithoutConstraints(width: number, height: number): void
|
||||
|
||||
constraints: Constraints
|
||||
}
|
||||
|
||||
interface BlendMixin {
|
||||
opacity: number
|
||||
blendMode: BlendMode
|
||||
isMask: boolean
|
||||
effects: ReadonlyArray<Effect>
|
||||
effectStyleId: string
|
||||
}
|
||||
|
||||
interface FrameMixin {
|
||||
backgrounds: ReadonlyArray<Paint>
|
||||
layoutGrids: ReadonlyArray<LayoutGrid>
|
||||
clipsContent: boolean
|
||||
guides: ReadonlyArray<Guide>
|
||||
gridStyleId: string
|
||||
backgroundStyleId: string
|
||||
}
|
||||
|
||||
type StrokeCap = "NONE" | "ROUND" | "SQUARE" | "ARROW_LINES" | "ARROW_EQUILATERAL"
|
||||
type StrokeJoin = "MITER" | "BEVEL" | "ROUND"
|
||||
type HandleMirroring = "NONE" | "ANGLE" | "ANGLE_AND_LENGTH"
|
||||
|
||||
interface GeometryMixin {
|
||||
fills: ReadonlyArray<Paint> | symbol // This can return figma.mixed on TEXT nodes
|
||||
strokes: ReadonlyArray<Paint>
|
||||
strokeWeight: number
|
||||
strokeAlign: "CENTER" | "INSIDE" | "OUTSIDE"
|
||||
strokeCap: StrokeCap | symbol // This can return figma.mixed on VECTOR nodes if vertices have different strokeCap values
|
||||
strokeJoin: StrokeJoin | symbol // This can return figma.mixed on VECTOR nodes if vertices have different strokeJoin values
|
||||
dashPattern: ReadonlyArray<number>
|
||||
fillStyleId: string | symbol // This can return figma.mixed on TEXT nodes
|
||||
strokeStyleId: string
|
||||
}
|
||||
|
||||
interface CornerMixin {
|
||||
// This can return figma.mixed on VECTOR nodes if vertices have different cornerRadius values,
|
||||
// and on RECTANGLE nodes if node.topLeftRadius etc has different values
|
||||
cornerRadius: number | symbol
|
||||
|
||||
cornerSmoothing: number
|
||||
}
|
||||
|
||||
interface ExportMixin {
|
||||
exportSettings: ExportSettings[]
|
||||
exportAsync(settings?: ExportSettings): Promise<Uint8Array> // Defaults to PNG format
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Nodes
|
||||
|
||||
interface DocumentNode extends BaseNodeMixin, ChildrenMixin {
|
||||
readonly type: "DOCUMENT"
|
||||
clone(): DocumentNode // Note: this always throws an error
|
||||
}
|
||||
|
||||
interface PageNode extends BaseNodeMixin, ChildrenMixin, ExportMixin {
|
||||
readonly type: "PAGE"
|
||||
clone(): PageNode // cloned node starts off inserted into current page
|
||||
|
||||
guides: ReadonlyArray<Guide>
|
||||
selection: ReadonlyArray<BaseNode>
|
||||
}
|
||||
|
||||
interface FrameNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "FRAME" | "GROUP"
|
||||
clone(): FrameNode // cloned node starts off inserted into current page
|
||||
}
|
||||
|
||||
interface SliceNode extends BaseNodeMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "SLICE"
|
||||
clone(): SliceNode // cloned node starts off inserted into current page
|
||||
}
|
||||
|
||||
interface RectangleNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "RECTANGLE"
|
||||
clone(): RectangleNode // cloned node starts off inserted into current page
|
||||
topLeftRadius: number
|
||||
topRightRadius: number
|
||||
bottomLeftRadius: number
|
||||
bottomRightRadius: number
|
||||
}
|
||||
|
||||
interface LineNode extends BaseNodeMixin, BlendMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "LINE"
|
||||
clone(): LineNode // cloned node starts off inserted into current page
|
||||
}
|
||||
|
||||
interface EllipseNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "ELLIPSE"
|
||||
clone(): EllipseNode // cloned node starts off inserted into current page
|
||||
arcData: ArcData
|
||||
}
|
||||
|
||||
interface PolygonNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "POLYGON"
|
||||
clone(): PolygonNode // cloned node starts off inserted into current page
|
||||
pointCount: number
|
||||
}
|
||||
|
||||
interface StarNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "STAR"
|
||||
clone(): StarNode // cloned node starts off inserted into current page
|
||||
pointCount: number
|
||||
|
||||
// This is a percentage value from 0 to 1
|
||||
innerRadius: number
|
||||
}
|
||||
|
||||
interface VectorNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "VECTOR"
|
||||
clone(): VectorNode // cloned node starts off inserted into current page
|
||||
vectorNetwork: VectorNetwork
|
||||
vectorPaths: VectorPaths
|
||||
handleMirroring: HandleMirroring | symbol // This can return figma.mixed if vertices have different handleMirroring values
|
||||
}
|
||||
|
||||
interface TextNode extends BaseNodeMixin, BlendMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "TEXT"
|
||||
clone(): TextNode // cloned node starts off inserted into current page
|
||||
characters: string
|
||||
textAlignHorizontal: "LEFT" | "CENTER" | "RIGHT" | "JUSTIFIED"
|
||||
textAlignVertical: "TOP" | "CENTER" | "BOTTOM"
|
||||
textAutoResize: "NONE" | "WIDTH_AND_HEIGHT" | "HEIGHT"
|
||||
paragraphIndent: number
|
||||
paragraphSpacing: number
|
||||
autoRename: boolean
|
||||
|
||||
// These properties can all return figma.mixed if the text has multiple values for the property
|
||||
textStyleId: string | symbol
|
||||
fontSize: number | symbol
|
||||
fontName: FontName | symbol
|
||||
textCase: "ORIGINAL" | "UPPER" | "LOWER" | "TITLE" | symbol
|
||||
textDecoration: "NONE" | "UNDERLINE" | "STRIKETHROUGH" | symbol
|
||||
letterSpacing: NumberWithUnits | symbol
|
||||
lineHeight: NumberWithUnits | symbol
|
||||
}
|
||||
|
||||
interface ComponentNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "COMPONENT"
|
||||
clone(): ComponentNode // cloned node starts off inserted into current page
|
||||
|
||||
createInstance(): InstanceNode // instance starts off inserted into current page
|
||||
description: string
|
||||
readonly remote: boolean
|
||||
readonly key: string // The key to use with "importComponentByKeyAsync"
|
||||
}
|
||||
|
||||
interface InstanceNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "INSTANCE"
|
||||
clone(): InstanceNode // cloned node starts off inserted into current page
|
||||
masterComponent: ComponentNode
|
||||
}
|
||||
|
||||
interface BooleanOperationNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||
readonly type: "BOOLEAN_OPERATION"
|
||||
clone(): BooleanOperationNode // cloned node starts off inserted into current page
|
||||
booleanOperation: "UNION" | "INTERSECT" | "SUBTRACT" | "EXCLUDE"
|
||||
}
|
||||
|
||||
type BaseNode =
|
||||
DocumentNode |
|
||||
PageNode |
|
||||
SliceNode |
|
||||
FrameNode |
|
||||
ComponentNode |
|
||||
InstanceNode |
|
||||
BooleanOperationNode |
|
||||
VectorNode |
|
||||
StarNode |
|
||||
LineNode |
|
||||
EllipseNode |
|
||||
PolygonNode |
|
||||
RectangleNode |
|
||||
TextNode
|
||||
|
||||
type NodeType =
|
||||
"DOCUMENT" |
|
||||
"PAGE" |
|
||||
"SLICE" |
|
||||
"FRAME" |
|
||||
"GROUP" |
|
||||
"COMPONENT" |
|
||||
"INSTANCE" |
|
||||
"BOOLEAN_OPERATION" |
|
||||
"VECTOR" |
|
||||
"STAR" |
|
||||
"LINE" |
|
||||
"ELLIPSE" |
|
||||
"POLYGON" |
|
||||
"RECTANGLE" |
|
||||
"TEXT"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Styles
|
||||
type StyleType = "PAINT" | "TEXT" | "EFFECT" | "GRID"
|
||||
|
||||
interface BaseStyle {
|
||||
// The string to uniquely identify a style by
|
||||
readonly id: string
|
||||
readonly type: StyleType
|
||||
name: string // Note: setting this also sets "autoRename" to false on TextNodes
|
||||
description: string
|
||||
remote: boolean
|
||||
readonly key: string // The key to use with "importStyleByKeyAsync"
|
||||
remove(): void
|
||||
}
|
||||
|
||||
interface PaintStyle extends BaseStyle {
|
||||
type: "PAINT"
|
||||
paints: ReadonlyArray<Paint>
|
||||
}
|
||||
|
||||
interface TextStyle extends BaseStyle {
|
||||
type: "TEXT"
|
||||
fontSize: number
|
||||
textDecoration: "NONE" | "UNDERLINE" | "STRIKETHROUGH"
|
||||
fontName: FontName
|
||||
letterSpacing: NumberWithUnits
|
||||
lineHeight: NumberWithUnits
|
||||
paragraphIndent: number
|
||||
paragraphSpacing: number
|
||||
textCase: "ORIGINAL" | "UPPER" | "LOWER" | "TITLE"
|
||||
}
|
||||
|
||||
interface EffectStyle extends BaseStyle {
|
||||
type: "EFFECT"
|
||||
effects: ReadonlyArray<Paint>
|
||||
}
|
||||
|
||||
interface GridStyle extends BaseStyle {
|
||||
type: "GRID"
|
||||
layoutGrids: ReadonlyArray<LayoutGrid>
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Other
|
||||
|
||||
interface Image {
|
||||
// Returns a unique hash for the image
|
||||
readonly hash: string
|
||||
|
||||
// The contents of the image file
|
||||
getBytesAsync(): Promise<Uint8Array>
|
||||
}
|
||||
BIN
packages/lucide-figma/icon.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
7
packages/lucide-figma/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Lucide Icons",
|
||||
"id": "939567362549682242",
|
||||
"api": "1.0.0",
|
||||
"ui": "build/ui.html",
|
||||
"main": "build/main.js"
|
||||
}
|
||||
26
packages/lucide-figma/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "lucide-figma",
|
||||
"version": "0.13.0",
|
||||
"license": "ISC",
|
||||
"main": "build/ui.js",
|
||||
"scripts": {
|
||||
"build": "webpack --mode=production",
|
||||
"watch": "webpack --mode=development --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/core": "^10.0.14",
|
||||
"@types/react": "^16.8.23",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"css-loader": "^3.0.0",
|
||||
"html-webpack-inline-source-plugin": "^0.0.10",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"lucide-react": "^0.13.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"style-loader": "^0.23.1",
|
||||
"ts-loader": "^6.0.4",
|
||||
"typescript": "^3.5.2",
|
||||
"webpack": "^4.35.2",
|
||||
"webpack-cli": "^3.3.5"
|
||||
}
|
||||
}
|
||||
44
packages/lucide-figma/src/components/icon-button.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { jsx } from '@emotion/core'
|
||||
import theme from '../theme'
|
||||
import { renderToString } from 'react-dom/server'
|
||||
import { FC } from 'react';
|
||||
|
||||
interface IconButtonProps {
|
||||
name: string,
|
||||
component: FC,
|
||||
}
|
||||
|
||||
function IconButton({ name, component: IconComponent }: IconButtonProps) {
|
||||
const onIconclick = () => {
|
||||
const svg = renderToString(<IconComponent/>);
|
||||
|
||||
parent.postMessage({ pluginMessage: { name, svg }}, '*')
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
key={name}
|
||||
aria-label={name}
|
||||
onClick={onIconclick}
|
||||
css={{
|
||||
padding: theme.space[2],
|
||||
color: '#333',
|
||||
background: 'transparent',
|
||||
border: 0,
|
||||
borderRadius: theme.radii[1],
|
||||
appearance: 'none',
|
||||
outline: 0,
|
||||
'&:hover': {
|
||||
background: 'rgba(0, 0, 0, 0.06)',
|
||||
},
|
||||
'&:focus, &:active': {
|
||||
boxShadow: `inset 0 0 0 2px ${theme.colors.blue}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<IconComponent />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconButton
|
||||
24
packages/lucide-figma/src/components/search-icon.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createElement, forwardRef } from 'react'
|
||||
|
||||
const SearchIcon = forwardRef((props: any, ref) => createElement(
|
||||
'svg',
|
||||
{
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: 32,
|
||||
height: 32,
|
||||
clipRule: 'evenodd',
|
||||
fillRule: 'evenodd',
|
||||
ref,
|
||||
...props,
|
||||
},
|
||||
[
|
||||
createElement(
|
||||
'path', {
|
||||
d: 'm20 15c0 2.7614-2.2386 5-5 5s-5-2.2386-5-5 2.2386-5 5-5 5 2.2386 5 5zm-1.1256 4.5815c-1.0453.8849-2.3975 1.4185-3.8744 1.4185-3.3137 0-6-2.6863-6-6s2.6863-6 6-6 6 2.6863 6 6c0 1.4769-.5336 2.8291-1.4185 3.8744l4.2721 4.272-.7072.7072z',
|
||||
key: 'path'
|
||||
}
|
||||
)
|
||||
]
|
||||
))
|
||||
|
||||
export default SearchIcon
|
||||
43
packages/lucide-figma/src/components/search-input.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { jsx } from '@emotion/core'
|
||||
import theme from '../theme'
|
||||
import SearchIcon from './search-icon'
|
||||
interface SearchInputProps extends React.HTMLProps<HTMLDivElement> {
|
||||
value: string,
|
||||
iconCount: number,
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
||||
function SearchInput({ value, onChange, iconCount, ...props }: SearchInputProps) {
|
||||
return (
|
||||
<div css={{ position: 'relative' }} {...props}>
|
||||
<div
|
||||
css={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
padding: theme.space[1],
|
||||
}}
|
||||
>
|
||||
<SearchIcon fill="#333" />
|
||||
</div>
|
||||
<input
|
||||
autoFocus
|
||||
type="search"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder={`Search ${iconCount} icons`}
|
||||
css={{
|
||||
width: '100%',
|
||||
height: 40,
|
||||
padding: `0 ${theme.space[4]} 0 36px`,
|
||||
fontFamily: 'inherit',
|
||||
fontSize: theme.fontSizes[0],
|
||||
border: 0,
|
||||
outline: 0,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SearchInput
|
||||
21
packages/lucide-figma/src/helpers/naming.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
/**
|
||||
* Converts string to camelcase
|
||||
*
|
||||
* @param {string} string
|
||||
*/
|
||||
export const toCamelCase = (string: string) =>
|
||||
string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) =>
|
||||
p2 ? p2.toUpperCase() : p1.toLowerCase(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts string to PascalCase
|
||||
*
|
||||
* @param {string} string
|
||||
*/
|
||||
export const toPascalCase = (string: string) => {
|
||||
const camelCase = toCamelCase(string);
|
||||
|
||||
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||
};
|
||||
9
packages/lucide-figma/src/main.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
figma.showUI(__html__, { width: 300, height: 400 })
|
||||
|
||||
figma.ui.onmessage = ({name, svg}) => {
|
||||
const icon = figma.createNodeFromSvg(svg)
|
||||
icon.name = name
|
||||
icon.x = figma.viewport.center.x
|
||||
icon.y = figma.viewport.center.y
|
||||
figma.currentPage.selection = [icon]
|
||||
}
|
||||
8
packages/lucide-figma/src/theme.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export default {
|
||||
space: [0, 4, 8, 12, 16],
|
||||
fontSizes: [12, 14, 16],
|
||||
colors: {
|
||||
blue: '#18a0fb',
|
||||
},
|
||||
radii: [0, 2],
|
||||
}
|
||||
4
packages/lucide-figma/src/types/lucide-react.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module 'lucide-react';
|
||||
declare module 'lucide';
|
||||
declare module 'lucide/icons';
|
||||
declare module 'lucide/build/icons';
|
||||
10
packages/lucide-figma/src/ui.css
Normal file
@@ -0,0 +1,10 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('https://rsms.me/inter/font-files/Inter-Regular.woff2?v=3.9')
|
||||
format('woff2'),
|
||||
url('https://rsms.me/inter/font-files/Inter-Regular.woff?v=3.9')
|
||||
format('woff');
|
||||
}
|
||||
1
packages/lucide-figma/src/ui.html
Normal file
@@ -0,0 +1 @@
|
||||
<div id="root"></div>
|
||||
82
packages/lucide-figma/src/ui.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Global, jsx } from '@emotion/core'
|
||||
import { version } from '../package.json'
|
||||
import React, { useMemo } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import IconButton from './components/icon-button'
|
||||
import SearchInput from './components/search-input'
|
||||
import theme from './theme'
|
||||
import './ui.css'
|
||||
import tags from '../../../tags.json'
|
||||
import * as iconComponents from 'lucide-react'
|
||||
import { toPascalCase } from './helpers/naming';
|
||||
import useSearch from '../../../site/src/lib/useSearch';
|
||||
|
||||
declare var ICONS: [];
|
||||
|
||||
function App() {
|
||||
const [query, setQuery] = React.useState('')
|
||||
const icons = ICONS.map(name => {
|
||||
const componentName = toPascalCase(name);
|
||||
return {
|
||||
name,
|
||||
tags: tags[name] || [],
|
||||
component: iconComponents[componentName] || null
|
||||
}
|
||||
}).filter(({component}) => !!component)
|
||||
|
||||
const searchResults = useMemo(() => useSearch(icons, query), [icons, query])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Global
|
||||
styles={{ body: { margin: 0, fontFamily: 'Inter, sans-serif' } }}
|
||||
/>
|
||||
<SearchInput
|
||||
value={query}
|
||||
iconCount={icons.length}
|
||||
onChange={event => setQuery(event.target.value)}
|
||||
css={{
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
borderBottom: '1px solid #e5e5e5',
|
||||
backfaceVisibility: 'hidden'
|
||||
}}
|
||||
/>
|
||||
<div css={{ padding: theme.space[2] }}>
|
||||
<div
|
||||
css={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(6, 1fr)',
|
||||
gridGap: theme.space[1],
|
||||
}}
|
||||
>
|
||||
{searchResults.map(({name, component: Icon} :any) => (
|
||||
<IconButton
|
||||
name={name}
|
||||
key={name}
|
||||
component={Icon}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
css={{
|
||||
marginTop: theme.space[2],
|
||||
padding: theme.space[2],
|
||||
fontSize: theme.fontSizes[0],
|
||||
color: 'rgba(0, 0, 0, 0.5)',
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href="https://lucide.dev"
|
||||
target="_blank"
|
||||
css={{ color: 'inherit' }}
|
||||
>
|
||||
Lucide v{version}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
12
packages/lucide-figma/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"lib": ["dom", "esnext"],
|
||||
"jsx": "react",
|
||||
"jsxFactory": "jsx",
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
}
|
||||
48
packages/lucide-figma/webpack.config.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = (env, argv) => ({
|
||||
// This is necessary because Figma's 'eval' works differently than normal eval
|
||||
devtool: argv.mode === 'production' ? false : 'inline-source-map',
|
||||
entry: {
|
||||
ui: './src/ui.tsx',
|
||||
main: './src/main.ts',
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
ICONS: JSON.stringify(
|
||||
fs.readdirSync(path.join(process.cwd(), '../../icons')).map(name => name.split('.')[0]),
|
||||
),
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/ui.html',
|
||||
filename: 'ui.html',
|
||||
inlineSource: '.(js)$',
|
||||
chunks: ['ui'],
|
||||
}),
|
||||
new HtmlWebpackInlineSourcePlugin(),
|
||||
],
|
||||
});
|
||||
3599
packages/lucide-figma/yarn.lock
Normal file
9
packages/lucide-react/.npmignore
Normal file
@@ -0,0 +1,9 @@
|
||||
stats
|
||||
node_modules
|
||||
tests
|
||||
scripts
|
||||
build
|
||||
src
|
||||
babel.config.js
|
||||
jest.config.js
|
||||
rollup.config.js
|
||||
@@ -15,7 +15,7 @@ npm install lucide-react
|
||||
## How to use
|
||||
|
||||
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
|
||||
|
||||
@@ -56,7 +56,7 @@ const App = () => {
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// module.exports = require('../../babel.config');
|
||||
module.exports = {
|
||||
presets: ['react-app'],
|
||||
};
|
||||
|
||||
@@ -1,37 +1,41 @@
|
||||
{
|
||||
"name": "lucide-react",
|
||||
"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.14.1",
|
||||
"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",
|
||||
"source": "build/lucide-react.js",
|
||||
"main": "dist/cjs/lucide-react.js",
|
||||
"main:umd": "dist/umd/lucide-react.js",
|
||||
"module": "dist/esm/lucide-react.js",
|
||||
"unpkg": "dist/umd/lucide-react.min.js",
|
||||
"repository": "github:lucide-icons/lucide",
|
||||
"author": "Eric Fennis",
|
||||
"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-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:bundles": "yarn --cwd ../../ rollup -c packages/lucide-react/rollup.config.js",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.1"
|
||||
"react": "^16.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-react-app": "^10.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"lucide": "file:../..",
|
||||
"react-test-renderer": "^17.0.1"
|
||||
"react-test-renderer": "^16.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.1"
|
||||
"react": "^16.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const plugins = require('lucide/rollup.plugins');
|
||||
const plugins = require('../../rollup.plugins');
|
||||
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 outputDir = `${rootDir}/dist`;
|
||||
const inputs = [`${rootDir}/build/lucide-react.js`];
|
||||
@@ -31,7 +32,7 @@ const configs = bundles
|
||||
plugins: plugins(pkg, minify),
|
||||
external: ['react', 'prop-types'],
|
||||
output: {
|
||||
name: outputFileName,
|
||||
name: packageName,
|
||||
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
|
||||
format,
|
||||
sourcemap: true,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export default ({ componentName, node }) => `
|
||||
import createReactComponent from '../createReactComponent';
|
||||
import defaultAttributes from '../defaultAttributes';
|
||||
|
||||
const ${componentName} = createReactComponent('${componentName}', ${node});
|
||||
const ${componentName} = createReactComponent('${componentName}', ['svg', defaultAttributes, ${node}]);
|
||||
|
||||
export default ${componentName};
|
||||
`;
|
||||
|
||||
@@ -11,7 +11,7 @@ export default (iconName, [tag, attrs, children]) => {
|
||||
...attrs,
|
||||
width: size,
|
||||
height: size,
|
||||
color,
|
||||
stroke: color,
|
||||
strokeWidth,
|
||||
...rest,
|
||||
},
|
||||
@@ -22,7 +22,7 @@ export default (iconName, [tag, attrs, children]) => {
|
||||
Component.propTypes = {
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
strokeWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
};
|
||||
|
||||
Component.displayName = `${iconName}`;
|
||||
|
||||
11
packages/lucide-react/src/defaultAttributes.js
Normal 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',
|
||||
};
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
exports[`Using lucide icon components should adjust the size, stroke color and stroke width 1`] = `
|
||||
<svg
|
||||
color="currentColor"
|
||||
fill="none"
|
||||
height={48}
|
||||
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`] = `
|
||||
<svg
|
||||
color="currentColor"
|
||||
fill="none"
|
||||
height={24}
|
||||
stroke="currentColor"
|
||||
|
||||
@@ -3246,9 +3246,6 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
"lucide@file:../..":
|
||||
version "0.11.0"
|
||||
|
||||
make-dir@^3.0.0:
|
||||
version "3.1.0"
|
||||
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"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.7.2:
|
||||
prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
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"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1:
|
||||
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:
|
||||
react-is@^16.8.1, react-is@^16.8.6:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-shallow-renderer@^16.13.1:
|
||||
version "16.14.1"
|
||||
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124"
|
||||
integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==
|
||||
react-is@^17.0.1:
|
||||
version "17.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
|
||||
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:
|
||||
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:
|
||||
version "17.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3187e636c3063e6ae498aedf21ecf972721574c7"
|
||||
integrity sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA==
|
||||
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==
|
||||
react@^16.5.1:
|
||||
version "16.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d"
|
||||
integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
read-pkg-up@^7.0.1:
|
||||
version "7.0.1"
|
||||
@@ -3962,10 +3952,10 @@ saxes@^5.0.0:
|
||||
dependencies:
|
||||
xmlchars "^2.2.0"
|
||||
|
||||
scheduler@^0.20.1:
|
||||
version "0.20.1"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c"
|
||||
integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==
|
||||
scheduler@^0.19.1:
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
|
||||
integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
9
packages/lucide-vue/.npmignore
Normal file
@@ -0,0 +1,9 @@
|
||||
stats
|
||||
node_modules
|
||||
tests
|
||||
scripts
|
||||
build
|
||||
src
|
||||
babel.config.js
|
||||
jest.config.js
|
||||
rollup.config.js
|
||||
103
packages/lucide-vue/README.md
Normal 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>
|
||||
```
|
||||
12
packages/lucide-vue/babel.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
node: 'current',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
14
packages/lucide-vue/jest.config.js
Normal 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',
|
||||
},
|
||||
};
|
||||
44
packages/lucide-vue/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "lucide-vue",
|
||||
"version": "0.14.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
47
packages/lucide-vue/rollup.config.js
Normal 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;
|
||||
8
packages/lucide-vue/scripts/exportTemplate.js
Normal 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};
|
||||
`;
|
||||
47
packages/lucide-vue/src/createVueComponent.js
Normal 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 })),
|
||||
);
|
||||
},
|
||||
});
|
||||
11
packages/lucide-vue/src/defaultAttributes.js
Normal 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',
|
||||
};
|
||||
5
packages/lucide-vue/src/icons/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
Icons exports.
|
||||
|
||||
Will be generated
|
||||
*/
|
||||
1
packages/lucide-vue/src/lucide-vue.js
Normal file
@@ -0,0 +1 @@
|
||||
export * from './icons';
|
||||
@@ -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>
|
||||
`;
|
||||
45
packages/lucide-vue/tests/lucide-vue.spec.js
Normal 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')
|
||||
});
|
||||
});
|
||||
4028
packages/lucide-vue/yarn.lock
Normal file
41
scripts/addMissingKeysToTags.js
Normal 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, '..'));
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import getArgumentOptions from 'minimist';
|
||||
|
||||
import renderIconsObject from './render/renderIconsObject';
|
||||
|
||||
@@ -22,6 +22,13 @@ export const toPascalCase = string => {
|
||||
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts string to PascalCase
|
||||
*
|
||||
* @param {string} string
|
||||
*/
|
||||
export const toKebabCase = string => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
|
||||
/**
|
||||
* Resets the file contents.
|
||||
*
|
||||
|
||||
@@ -38,13 +38,15 @@ export default (iconsObject, options) => {
|
||||
];
|
||||
});
|
||||
|
||||
iconNodes[icon] = [
|
||||
'svg',
|
||||
{
|
||||
...(options.camelizeAttrs ? camelizeAttrs(DEFAULT_ATTRS) : DEFAULT_ATTRS),
|
||||
},
|
||||
children,
|
||||
];
|
||||
iconNodes[icon] = !options.noDefaultAttrs
|
||||
? [
|
||||
'svg',
|
||||
{
|
||||
...(options.camelizeAttrs ? camelizeAttrs(DEFAULT_ATTRS) : DEFAULT_ATTRS),
|
||||
},
|
||||
children,
|
||||
]
|
||||
: children;
|
||||
});
|
||||
|
||||
return iconNodes;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"dependencies": {
|
||||
"@chakra-ui/core": "^1.0.0-rc.8",
|
||||
"downloadjs": "^1.4.7",
|
||||
"framer-motion": "^2.9.4",
|
||||
"framer-motion": "^3.3.0",
|
||||
"fuse.js": "^6.0.4",
|
||||
"jszip": "^3.4.0",
|
||||
"lodash": "^4.17.20",
|
||||
@@ -23,7 +23,6 @@
|
||||
"react": "^16.13.1",
|
||||
"react-color": "2.17.3",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-svg-loader": "^3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
18
site/public/icons-raw/lucide.svg
Normal 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
|
After Width: | Height: | Size: 5.2 KiB |
@@ -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 JSZip from "jszip";
|
||||
import { Download, Github } from 'lucide-react';
|
||||
@@ -30,15 +30,26 @@ const Header = ({ data }) => {
|
||||
<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>!
|
||||
</Text>
|
||||
<Stack isInline marginTop={3} marginBottom={10}>
|
||||
<Button
|
||||
leftIcon={<Download/>}
|
||||
size="lg"
|
||||
onClick={downloadAllIcons}
|
||||
>
|
||||
Download all
|
||||
</Button>
|
||||
<Wrap
|
||||
isInline
|
||||
marginTop={3}
|
||||
marginBottom={10}
|
||||
spacing="15px"
|
||||
justify="center"
|
||||
>
|
||||
<WrapItem>
|
||||
<Button
|
||||
leftIcon={<Download/>}
|
||||
size="lg"
|
||||
onClick={downloadAllIcons}
|
||||
>
|
||||
Download all
|
||||
</Button>
|
||||
</WrapItem>
|
||||
<WrapItem>
|
||||
<IconCustomizerDrawer/>
|
||||
</WrapItem>
|
||||
<WrapItem>
|
||||
<Button
|
||||
as="a"
|
||||
leftIcon={<Github/>}
|
||||
@@ -49,7 +60,8 @@ const Header = ({ data }) => {
|
||||
>
|
||||
Github
|
||||
</Button>
|
||||
</Stack>
|
||||
</WrapItem>
|
||||
</Wrap>
|
||||
</Flex>
|
||||
)
|
||||
};
|
||||
|
||||
@@ -1,41 +1,37 @@
|
||||
import { useSpring, animated } from "react-spring";
|
||||
import { Box, Text, IconButton, useColorMode, Flex, ButtonGroup, Button, useToast } from "@chakra-ui/core";
|
||||
import { Box, Text, IconButton, useColorMode, Flex, Slide, ButtonGroup, Button, useToast, Heading, Avatar, AvatarGroup, Link, Tooltip, useMediaQuery, useDisclosure } from "@chakra-ui/core";
|
||||
import theme from "../lib/theme";
|
||||
import download from 'downloadjs';
|
||||
import copy from "copy-to-clipboard";
|
||||
import { X as Close } from 'lucide-react';
|
||||
import {useContext, useRef} from "react";
|
||||
import {useContext, useEffect, useRef} from "react";
|
||||
import {IconStyleContext} from "./CustomizeIconContext";
|
||||
import {IconWrapper} from "./IconWrapper";
|
||||
import ModifiedTooltip from "./ModifiedTooltip";
|
||||
|
||||
type IconDownload = {
|
||||
src: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
||||
const IconDetailOverlay = ({ open = true, close, icon }) => {
|
||||
const toast = useToast();
|
||||
const { colorMode } = useColorMode();
|
||||
const { tags = [], name } = icon;
|
||||
const {color, strokeWidth, size} = useContext(IconStyleContext);
|
||||
const iconRef = useRef<SVGSVGElement>(null);
|
||||
|
||||
const { transform, opacity } = useSpring({
|
||||
opacity: isOpen ? 1 : 0,
|
||||
transform: `translateY(${isOpen ? -120 : 0}%)`,
|
||||
config: { mass: 5, tension: 500, friction: 80 },
|
||||
});
|
||||
const [isMobile] = useMediaQuery("(max-width: 560px)")
|
||||
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
close();
|
||||
};
|
||||
|
||||
const panelStyling = {
|
||||
transform: transform.interpolate(t => t),
|
||||
opacity: opacity.interpolate(o => o),
|
||||
width: "100%",
|
||||
willChange: "transform"
|
||||
}
|
||||
useEffect(() => {
|
||||
if(open) {
|
||||
onOpen()
|
||||
}
|
||||
}, [open])
|
||||
|
||||
const iconStyling = (isLight) => ({
|
||||
height: "25vw",
|
||||
@@ -88,6 +84,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
||||
height={0}
|
||||
key={name}
|
||||
>
|
||||
<Slide direction="bottom" in={isOpen} style={{ zIndex: 10 }}>
|
||||
<Flex
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
@@ -98,9 +95,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
||||
w="full"
|
||||
px={8}
|
||||
>
|
||||
<animated.div
|
||||
style={panelStyling}
|
||||
>
|
||||
|
||||
<Box
|
||||
borderWidth="1px"
|
||||
rounded="lg"
|
||||
@@ -163,11 +158,25 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
||||
</svg>
|
||||
</Box>
|
||||
</Flex>
|
||||
<Flex marginLeft={[0, 8]}>
|
||||
<Box>
|
||||
<Text fontSize="3xl" style={{ cursor: "pointer" }} mb={1}>
|
||||
{icon.name}
|
||||
</Text>
|
||||
<Flex marginLeft={[0, 8]} w="100%">
|
||||
<Box w="100%">
|
||||
<Flex
|
||||
justify={isMobile ? 'center' : 'flex-start'}
|
||||
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}>
|
||||
{ tags?.length ? (
|
||||
<Text
|
||||
@@ -187,23 +196,42 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
||||
Edit Tags
|
||||
</Button> */}
|
||||
</Box>
|
||||
<ButtonGroup spacing={4}>
|
||||
<Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Download SVG
|
||||
</Button>
|
||||
<Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Copy SVG
|
||||
</Button>
|
||||
<Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Download PNG
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<Box overflowY="auto" w="100%" pt={1} pb={1}>
|
||||
<ButtonGroup spacing={4}>
|
||||
<Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Download SVG
|
||||
</Button>
|
||||
<Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Copy SVG
|
||||
</Button>
|
||||
<Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||
Download PNG
|
||||
</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>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
</animated.div>
|
||||
|
||||
</Flex>
|
||||
</Slide>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import {useContext, useMemo} from "react";
|
||||
import {IconStyleContext} from "./CustomizeIconContext";
|
||||
import {IconWrapper} from "./IconWrapper";
|
||||
import { useRouter } from "next/router";
|
||||
import ModifiedTooltip from './ModifiedTooltip';
|
||||
|
||||
const IconList = ({icons}) => {
|
||||
const router = useRouter()
|
||||
@@ -17,13 +18,13 @@ const IconList = ({icons}) => {
|
||||
|
||||
return (
|
||||
<Grid
|
||||
templateColumns={`repeat(auto-fill, minmax(160px, 1fr))`}
|
||||
templateColumns={`repeat(auto-fill, minmax(150px, 1fr))`}
|
||||
gap={5}
|
||||
marginBottom="320px"
|
||||
>
|
||||
{ icons.map((icon) => {
|
||||
const actualIcon = icon.item ? icon.item : icon;
|
||||
const { name, content } = actualIcon;
|
||||
const { name, content, contributors } = actualIcon;
|
||||
|
||||
return (
|
||||
<Link
|
||||
@@ -42,6 +43,7 @@ const IconList = ({icons}) => {
|
||||
borderWidth="1px"
|
||||
rounded="lg"
|
||||
padding={16}
|
||||
position="relative"
|
||||
onClick={(event) => {
|
||||
if (event.shiftKey) {
|
||||
copy(actualIcon.src);
|
||||
@@ -63,6 +65,7 @@ const IconList = ({icons}) => {
|
||||
key={name}
|
||||
alignItems="center"
|
||||
>
|
||||
{ contributors?.length ? ( <ModifiedTooltip/> ) : null}
|
||||
<Flex direction="column" align="center" justify="center">
|
||||
<IconWrapper
|
||||
content={content}
|
||||
|
||||
@@ -38,7 +38,7 @@ const Layout = ({ children }) => {
|
||||
maxW="1250px"
|
||||
margin="0 auto"
|
||||
w="full"
|
||||
px={8}
|
||||
px={5}
|
||||
>
|
||||
<Flex justifyContent="center" alignItems="center">
|
||||
<NextLink href="/" passHref>
|
||||
@@ -77,9 +77,15 @@ const Layout = ({ children }) => {
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex margin="0 auto" direction="column" maxW="1250px" px={8}>
|
||||
<Flex margin="0 auto" direction="column" maxW="1250px" px={5}>
|
||||
{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>
|
||||
</Box>
|
||||
);
|
||||
|
||||
31
site/src/components/ModifiedTooltip.tsx
Normal 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;
|
||||
129
site/src/lib/fetchAllContributors.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import cheerio from 'cheerio';
|
||||
import tags from '../../../tags.json';
|
||||
import { getContributors } from "./fetchAllContributors";
|
||||
|
||||
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 fileContents = fs.readFileSync(fullPath, "utf8");
|
||||
|
||||
const $ = cheerio.load(fileContents);
|
||||
const content = $("svg").html();
|
||||
|
||||
const contributors = await getContributors(name);
|
||||
|
||||
return {
|
||||
name,
|
||||
tags: tags[name] || [],
|
||||
contributors,
|
||||
src: fileContents,
|
||||
content: content
|
||||
};
|
||||
}
|
||||
|
||||
export function getAllData() {
|
||||
export async function getAllData() {
|
||||
const names = getAllNames();
|
||||
|
||||
return names.map((name) => {
|
||||
return getData(name);
|
||||
});
|
||||
return Promise.all(names.map((name) => getData(name)));
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useDebounce } from './useDebounce';
|
||||
interface Icon {
|
||||
name: string;
|
||||
tags: string[],
|
||||
}
|
||||
|
||||
function useSearch(icons: Array<any>, query:string) {
|
||||
function useSearch(icons: Icon[], query:string) {
|
||||
if(!query) return icons;
|
||||
|
||||
const searchString = query.toLowerCase()
|
||||
|
||||
return icons.filter(({ name, tags }) => {
|
||||
const icon = { name, tags };
|
||||
|
||||
return Object.keys(icon).some(
|
||||
key => String(icon[key])
|
||||
.toLowerCase()
|
||||
.includes(searchString)
|
||||
return icons.filter(({ name, tags }: Icon) => [name, ...tags].some(
|
||||
(item:string) => item
|
||||
.toLowerCase()
|
||||
.includes(searchString)
|
||||
)
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
export default useSearch;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ChakraProvider } from '@chakra-ui/core';
|
||||
import customTheme from '../lib/theme';
|
||||
import '../assets/styling.css';
|
||||
import Head from 'next/head';
|
||||
import { CustomizeIconContext } from "../components/CustomizeIconContext";
|
||||
|
||||
const App = ({ Component, pageProps }) => {
|
||||
return (
|
||||
@@ -10,7 +11,9 @@ const App = ({ Component, pageProps }) => {
|
||||
<title>Lucide</title>
|
||||
</Head>
|
||||
<ChakraProvider theme={customTheme}>
|
||||
<Component {...pageProps} />
|
||||
<CustomizeIconContext>
|
||||
<Component {...pageProps} />
|
||||
</CustomizeIconContext>
|
||||
</ChakraProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import IconDetailOverlay from '../../components/IconDetailOverlay'
|
||||
import { getAllData, getData } from '../../lib/icons';
|
||||
@@ -29,7 +28,7 @@ const IconPage = ({ icon, data }) => {
|
||||
<IconDetailOverlay
|
||||
key={icon.name}
|
||||
icon={icon}
|
||||
onClose={onClose}
|
||||
close={onClose}
|
||||
/>
|
||||
<Header {...{data}}/>
|
||||
<IconOverview {...{data}}/>
|
||||
@@ -39,15 +38,17 @@ const IconPage = ({ icon, data }) => {
|
||||
|
||||
export default IconPage
|
||||
|
||||
export function getStaticProps({ params: { iconName } }) {
|
||||
const data = getAllData();
|
||||
const icon = getData(iconName);
|
||||
export async function getStaticProps({ params: { iconName } }) {
|
||||
const data = await getAllData();
|
||||
const icon = await getData(iconName);
|
||||
return { props: { icon, data } }
|
||||
}
|
||||
|
||||
export function getStaticPaths() {
|
||||
export async function getStaticPaths() {
|
||||
const data = await getAllData();
|
||||
|
||||
return {
|
||||
paths: getAllData().map(({name: iconName }) => ({
|
||||
paths: data.map(({ name: iconName }) => ({
|
||||
params: { iconName },
|
||||
})),
|
||||
fallback: false,
|
||||
|
||||
@@ -5,7 +5,6 @@ import IconOverview from "../components/IconOverview";
|
||||
import IconDetailOverlay from "../components/IconDetailOverlay";
|
||||
import { useRouter } from "next/router";
|
||||
import Header from "../components/Header";
|
||||
import {CustomizeIconContext} from "../components/CustomizeIconContext";
|
||||
|
||||
const IndexPage = ({ data }) => {
|
||||
const router = useRouter();
|
||||
@@ -13,21 +12,19 @@ const IndexPage = ({ data }) => {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<CustomizeIconContext>
|
||||
<IconDetailOverlay
|
||||
isOpen={!!router.query.iconName}
|
||||
icon={getIcon(router.query.iconName)}
|
||||
onClose={() => router.push('/')}
|
||||
/>
|
||||
<Header {...{data}}/>
|
||||
<IconOverview {...{data}}/>
|
||||
</CustomizeIconContext>
|
||||
<IconDetailOverlay
|
||||
open={!!router.query.iconName}
|
||||
icon={getIcon(router.query.iconName)}
|
||||
close={() => router.push('/')}
|
||||
/>
|
||||
<Header {...{data}}/>
|
||||
<IconOverview {...{data}}/>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export async function getStaticProps() {
|
||||
let data = getAllData();
|
||||
let data = await getAllData();
|
||||
|
||||
return {
|
||||
props: {
|
||||
|
||||