mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-17 10:47:41 +01:00
Compare commits
134 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dff42fe326 | ||
|
|
c1f642e20f | ||
|
|
cf9565b69c | ||
|
|
4cc4468d2f | ||
|
|
fd9ab8f17a | ||
|
|
c9101f0f39 | ||
|
|
614ef1a1d5 | ||
|
|
1a441812ac | ||
|
|
4a33e90c65 | ||
|
|
062a64a078 | ||
|
|
95a1ea7255 | ||
|
|
a0a5bc8fc2 | ||
|
|
698eded89b | ||
|
|
a70b713572 | ||
|
|
34530ad805 | ||
|
|
f73aed151a | ||
|
|
2bd7748562 | ||
|
|
da8a6c5a1b | ||
|
|
5736028dfa | ||
|
|
45d2063340 | ||
|
|
f71d3ffd1d | ||
|
|
b8c3a5fa0b | ||
|
|
a4076db69b | ||
|
|
55cb681461 | ||
|
|
09d9bb747d | ||
|
|
42f9cdceca | ||
|
|
c652723b32 | ||
|
|
a44328d8be | ||
|
|
376568239f | ||
|
|
92d05b5fca | ||
|
|
27b5b7eaad | ||
|
|
4de1355e54 | ||
|
|
c8d94bf3e1 | ||
|
|
a128d1c3c1 | ||
|
|
e145cb05e2 | ||
|
|
759ff562fd | ||
|
|
ae2899a09e | ||
|
|
8b7ea73aa3 | ||
|
|
1bdeae5364 | ||
|
|
0e307087f6 | ||
|
|
a46114b3e7 | ||
|
|
fcafe0e7b7 | ||
|
|
5312982b8f | ||
|
|
3a13fab009 | ||
|
|
30a69ee670 | ||
|
|
5f442122ab | ||
|
|
e78d910a83 | ||
|
|
ccc8dc2b34 | ||
|
|
96bcca0e08 | ||
|
|
d95b14a70b | ||
|
|
a852a43ef4 | ||
|
|
4953a95e36 | ||
|
|
cad1b95b69 | ||
|
|
92f3fb0f90 | ||
|
|
6e8895d075 | ||
|
|
a1b2ce5b7b | ||
|
|
4a54e87e84 | ||
|
|
d8bdbff9c6 | ||
|
|
70cffa8dd2 | ||
|
|
8cff59627b | ||
|
|
b684a0083b | ||
|
|
9fb4b0b161 | ||
|
|
9ec40ae506 | ||
|
|
890514de6c | ||
|
|
9463b2e445 | ||
|
|
0221022e24 | ||
|
|
751f7cb1e3 | ||
|
|
4c90b84236 | ||
|
|
01be733532 | ||
|
|
4ffa38e013 | ||
|
|
0a38dccdae | ||
|
|
3391b5b717 | ||
|
|
5c145f4e72 | ||
|
|
74429a8e92 | ||
|
|
1e99499dc8 | ||
|
|
724a43e3f0 | ||
|
|
fb79059fca | ||
|
|
9a54838538 | ||
|
|
c7438c0c10 | ||
|
|
667ae303f8 | ||
|
|
dc1d17181f | ||
|
|
26abdb904d | ||
|
|
cf0264745e | ||
|
|
510a5ec3b9 | ||
|
|
e1bc19be4e | ||
|
|
062894e113 | ||
|
|
eaa99b35f6 | ||
|
|
7c22ccfab4 | ||
|
|
e0e171db81 | ||
|
|
3b11552e5e | ||
|
|
d8b455b614 | ||
|
|
79eecc89f6 | ||
|
|
b943430a08 | ||
|
|
cebb0ee84b | ||
|
|
210c56807e | ||
|
|
c2a8f31176 | ||
|
|
a3f70d5b8b | ||
|
|
c97c6ed9e4 | ||
|
|
e9d69c6948 | ||
|
|
270c935cd4 | ||
|
|
b7377d21eb | ||
|
|
7ccf155ad4 | ||
|
|
c696d1e907 | ||
|
|
a8cf24e75a | ||
|
|
4e2773bd2d | ||
|
|
7c8f898893 | ||
|
|
c3951d36c7 | ||
|
|
f958310d91 | ||
|
|
d00cbebcc4 | ||
|
|
3619dfa7f2 | ||
|
|
c844bc668f | ||
|
|
32dec05e0b | ||
|
|
5394d7fceb | ||
|
|
8dea4c7b7f | ||
|
|
b8a595275d | ||
|
|
a7b3ecde63 | ||
|
|
8bcfc225ce | ||
|
|
1d608db223 | ||
|
|
c1cb5d9bc2 | ||
|
|
66f51474cd | ||
|
|
af0b16bc10 | ||
|
|
46d6c3c119 | ||
|
|
d3b8510602 | ||
|
|
97e0f30627 | ||
|
|
24676ddc8e | ||
|
|
92689a3328 | ||
|
|
b578269ecb | ||
|
|
d041a2b02a | ||
|
|
0253326b17 | ||
|
|
275c2cbc69 | ||
|
|
4bd6a273db | ||
|
|
34155d48e7 | ||
|
|
82db590192 | ||
|
|
70be55b78f |
49
.github/ISSUE_TEMPLATE/01_icon_request.yml
vendored
Normal file
49
.github/ISSUE_TEMPLATE/01_icon_request.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Icon request
|
||||
description: Suggest a new icon for this project
|
||||
labels: ['🙌 icon request']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before submitting an icon request check if it has already been requested. If there is an open request, please add a 👍.
|
||||
|
||||
**Important note**: No new brand logos are allowed, see https://github.com/lucide-icons/lucide/issues/670.
|
||||
Existing brand icons will also be phased out. For brand icons, consider using https://simpleicons.org, which offers purpose-built SVGs that are also on a 24×24px grid.
|
||||
- type: input
|
||||
id: name
|
||||
attributes:
|
||||
label: Icon name
|
||||
description: What should this icon depict? For multiple icons, provide a comma-separated list.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: use-cases
|
||||
attributes:
|
||||
label: Use cases
|
||||
description: Why do you need this icon? Include at least two real-life use cases per requested icon, avoiding generic descriptions like "it's a car icon".
|
||||
placeholder: e.g. I need a star icon to use in my rating system.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: design-ideas
|
||||
attributes:
|
||||
label: Design ideas
|
||||
description: What should this icon look like? Provide simple, minimalistic icon examples from other sets or your own drafts to help us visualize your request.
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please review the following checklist before submitting your request.
|
||||
options:
|
||||
- label: I have searched if someone has submitted a similar issue before and there weren't any. (Please make sure to also search closed issues, as this issue might already have been resolved.)
|
||||
required: true
|
||||
- label: I have searched existing icons to make sure it does not already exist and I didn't find any.
|
||||
required: true
|
||||
- label: I am not requesting a brand logo and the art is not protected by copyright.
|
||||
required: true
|
||||
- label: I am not requesting an icon that includes religious, political imagery or hate symbols.
|
||||
required: true
|
||||
- label: I have provided appropriate use cases for the icon(s) requested.
|
||||
required: true
|
||||
90
.github/ISSUE_TEMPLATE/02_bug_report.yml
vendored
Normal file
90
.github/ISSUE_TEMPLATE/02_bug_report.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: ['🐛 bug']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting an issue, please search to see if someone has filed a similar issue before. If there is already an open issue, please add a 👍 and/or leave a comment with additional information.
|
||||
- type: checkboxes
|
||||
id: packages
|
||||
attributes:
|
||||
label: Package
|
||||
description: Which Lucide packages are affected? You may select more than one.
|
||||
options:
|
||||
- label: lucide
|
||||
- label: lucide-angular
|
||||
- label: lucide-flutter
|
||||
- label: lucide-preact
|
||||
- label: lucide-react
|
||||
- label: lucide-react-native
|
||||
- label: lucide-solid
|
||||
- label: lucide-svelte
|
||||
- label: lucide-vue
|
||||
- label: lucide-vue-next
|
||||
- label: Figma plugin
|
||||
- label: source/main
|
||||
- label: other/not relevant
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of Lucide are you running?
|
||||
placeholder: e.g. 0.289.1
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: browsers
|
||||
attributes:
|
||||
label: Browser
|
||||
description: In which browser(s) are you experiencing the issue? You may select more than one.
|
||||
options:
|
||||
- label: Chrome/Chromium
|
||||
- label: Firefox
|
||||
- label: Safari
|
||||
- label: Edge
|
||||
- label: iOS Safari
|
||||
- label: Opera
|
||||
- label: Other/not relevant
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: operating-systems
|
||||
attributes:
|
||||
label: Operating system
|
||||
description: In which operating systems a you experiencing the issue? You may select more than one.
|
||||
options:
|
||||
- label: Windows
|
||||
- label: Linux
|
||||
- label: macOS
|
||||
- label: Other/not relevant
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Try to describe in detail the problem you're running into and provide additional context about your working environment if necessary.
|
||||
placeholder: e.g. When I do X, Y happens instead of Z
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please provide a detailed guide on how this issue can be reproduced or a live example with a working reproduction on Codesandbox, JSFiddle or similar.
|
||||
placeholder: |
|
||||
1. Import `check` icon
|
||||
2. Add to a React component/view
|
||||
3. Run the react app
|
||||
4. Notice that the `check` isn't rendering correctly which seems a encoding problem
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please review the following checklist before submitting your issue.
|
||||
options:
|
||||
- label: I have searched if someone has submitted a similar issue before and there weren't any. (Please make sure to also search closed issues, as this issue might already have been resolved.)
|
||||
required: true
|
||||
62
.github/ISSUE_TEMPLATE/03_bug_report_site.yml
vendored
Normal file
62
.github/ISSUE_TEMPLATE/03_bug_report_site.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: lucide.dev bug report
|
||||
description: Help us improve the Lucide site
|
||||
labels: ['🐛 bug', '🌍 site']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting an issue, please search to see if someone has filed a similar issue before. If there is already an open issue, please add a 👍 and/or leave a comment with additional information.
|
||||
- type: checkboxes
|
||||
id: browsers
|
||||
attributes:
|
||||
label: Browser
|
||||
description: In which browser(s) are you experiencing the issue? You may select more than one.
|
||||
options:
|
||||
- label: Chrome/Chromium
|
||||
- label: Firefox
|
||||
- label: Safari
|
||||
- label: Edge
|
||||
- label: iOS Safari
|
||||
- label: Opera
|
||||
- label: Other/not relevant
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: operating-systems
|
||||
attributes:
|
||||
label: Operating system
|
||||
description: In which operating systems are you experiencing the issue? You may select more than one.
|
||||
options:
|
||||
- label: Windows
|
||||
- label: Linux
|
||||
- label: macOS
|
||||
- label: Other/not relevant
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Try to describe in detail the problem you're running into and provide additional context about your working environment if necessary.
|
||||
placeholder: e.g. When I do X, Y happens instead of Z
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: stepsToReproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please provide a detailed guide on how this issue can be reproduced.
|
||||
placeholder: |
|
||||
1. I click on an icon
|
||||
2. I click on `Copy SVG` in the drawer
|
||||
3. I paste from the clipboard
|
||||
4. A base64 encoded data URI is inserted.
|
||||
...
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please review the following checklist before submitting your issue.
|
||||
options:
|
||||
- label: I have searched if someone has submitted a similar issue before and there weren't any. (Please make sure to also search closed issues, as this issue might already have been resolved.)
|
||||
required: true
|
||||
53
.github/ISSUE_TEMPLATE/04_feature_request.yml
vendored
Normal file
53
.github/ISSUE_TEMPLATE/04_feature_request.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Feature request
|
||||
description: Share with us your ideas on how Lucide could be improved upon.
|
||||
labels: ['💡 idea']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before submitting a new feature request, please search to see if someone has filed a similar request before. If there is already an open issue, please add a 👍 and/or leave a comment with additional information.
|
||||
- type: checkboxes
|
||||
id: packages
|
||||
attributes:
|
||||
label: Package
|
||||
description: Which Lucide project do you wish this feature were added to? You may select more than one.
|
||||
options:
|
||||
- label: lucide
|
||||
- label: lucide-angular
|
||||
- label: lucide-flutter
|
||||
- label: lucide-preact
|
||||
- label: lucide-react
|
||||
- label: lucide-react-native
|
||||
- label: lucide-solid
|
||||
- label: lucide-svelte
|
||||
- label: lucide-vue
|
||||
- label: lucide-vue-next
|
||||
- label: Figma plugin
|
||||
- label: all JS packages
|
||||
- label: site
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Try to describe in detail the feature you wish existed.
|
||||
placeholder: e.g. I want to be able to set extra CSS classes on icon components.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: use-cases
|
||||
attributes:
|
||||
label: Use cases
|
||||
description: Why do you need this feature? Provide real-life use cases as to why this feature will be useful for others.
|
||||
placeholder: e.g. I could use the extra classes to add animation or global custom styling to some icons.
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please check the following items before submitting your issue.
|
||||
options:
|
||||
- label: I have searched the existing issues to make sure this bug has not already been reported.
|
||||
required: true
|
||||
68
.github/ISSUE_TEMPLATE/bug_report.md
vendored
68
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,68 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
labels: "🐛 bug"
|
||||
---
|
||||
|
||||
<!--
|
||||
Before reporting an issue, please search to see if someone has filed a similar issue before. If there is already an open issue, please add a 👍 and/or leave a comment with additional information.
|
||||
-->
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Version:
|
||||
* Are you running from source/main:
|
||||
* Are you using a released build:
|
||||
* Operating system:
|
||||
* Bits:
|
||||
|
||||
## Step to reproduce
|
||||
|
||||
*(Type here)*
|
||||
|
||||
### Actual behavior
|
||||
|
||||
## Any message or error
|
||||
|
||||
*(Type here)*
|
||||
|
||||
## Resources
|
||||
|
||||
* Links
|
||||
* Screenshots
|
||||
|
||||
|
||||
Here is what a great bug report would look like:
|
||||
|
||||
```
|
||||
## Prerequisites
|
||||
|
||||
Version: Release v3.1.0
|
||||
Running from: Import using webpack
|
||||
Operating system: Mac OSX
|
||||
Bits: 64 bits
|
||||
|
||||
## Step to reproduce
|
||||
|
||||
- Import `check` icon
|
||||
- Add to a React component/view
|
||||
- Run the react app
|
||||
- Notice that the `check` isn't rendering correctly which seems a encoding problem
|
||||
|
||||
### Actual behavior:
|
||||
|
||||
- Import `check` icon
|
||||
- Add to a React component/view
|
||||
- Run the react app
|
||||
- Check is displayed with correct encoding (e.g UTF-8)
|
||||
|
||||
## Any message or error
|
||||
|
||||
No console output
|
||||
...
|
||||
|
||||
## Resources
|
||||
|
||||
No resources
|
||||
...
|
||||
```
|
||||
18
.github/ISSUE_TEMPLATE/icon_request.md
vendored
18
.github/ISSUE_TEMPLATE/icon_request.md
vendored
@@ -1,18 +0,0 @@
|
||||
---
|
||||
name: Icon request
|
||||
about: Suggest an new icon for this project
|
||||
labels: "🙌 icon request"
|
||||
---
|
||||
|
||||
<!--
|
||||
Before creating an icon request, please search to see if someone has requested the icon already. If there is an open request, please add a 👍.
|
||||
A note about brand logos and related material : We follow the decision from Feather Icons (https://github.com/feathericons/feather/issues/763) to deprecate icons relating to brands.
|
||||
You will find some in the set, but we won't add any new ones. https://simpleicons.org has 24x24 SVG icons for this purpose.
|
||||
|
||||
-->
|
||||
|
||||
## Icon Request
|
||||
|
||||
* Icon name:
|
||||
* Use case:
|
||||
* _Screenshots_ of similar icons:
|
||||
15
.github/PULL_REQUEST_TEMPLATE/new-icon.md
vendored
15
.github/PULL_REQUEST_TEMPLATE/new-icon.md
vendored
@@ -1,15 +0,0 @@
|
||||
---
|
||||
name: New icon
|
||||
about: Add a new icon to the library
|
||||
labels: "🎨 <icon"
|
||||
---
|
||||
|
||||
<!-- Thanks for submitting an icon! Please make sure you read the icon design guide
|
||||
at https://github.com/lucide-icons/lucide/blob/main/docs/icon-design-guide.md beforehand,
|
||||
and please fill everything below. -->
|
||||
|
||||
- **Name of the icon** : <!-- `icon` -->
|
||||
- **Tags (alternative names for this icon)** (add them in as a separate json file using the same icon name) :
|
||||
- **What is the purpose of this icon?** : <!-- Shows that one can click it to... / Is used to denote or label... -->
|
||||
- **100% scale preview** : <!-- upload an image -->
|
||||
- **Have you considered alternative possibilities** for its naming or design? :
|
||||
8
.github/actions/build-and-test.yml
vendored
8
.github/actions/build-and-test.yml
vendored
@@ -24,15 +24,15 @@ runs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-lucide-preact-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-lucide-preact-pnpm-store-
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter lucide-preact
|
||||
|
||||
8
.github/actions/check-icons.yml
vendored
8
.github/actions/check-icons.yml
vendored
@@ -24,15 +24,15 @@ runs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-lucide-preact-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-lucide-preact-pnpm-store-
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter .
|
||||
|
||||
62
.github/labeler.yml
vendored
Normal file
62
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# For changed dependencies
|
||||
📦 dependencies:
|
||||
- pnpm-lock.yaml
|
||||
|
||||
# For changes in documentation
|
||||
📖 documentation:
|
||||
- docs/*.md
|
||||
- docs/**/*.md
|
||||
|
||||
# For changes in the site, but not markdown files
|
||||
🌍 site:
|
||||
- 'docs/**'
|
||||
|
||||
# For changes in the metadata
|
||||
🫧 metadata:
|
||||
- 'icons/*.json'
|
||||
- categories/*
|
||||
|
||||
# For changes or added icons
|
||||
🎨 icon:
|
||||
- 'icons/*.svg'
|
||||
|
||||
# For changes in the lucide package
|
||||
🧳 lucide package:
|
||||
- 'packages/lucide/*'
|
||||
|
||||
# For changes in the lucide React package
|
||||
⚛️ react package:
|
||||
- 'packages/lucide-react/*'
|
||||
|
||||
# For changes in the lucide React Native package
|
||||
⚛️ react native package:
|
||||
- 'packages/lucide-react-native/*'
|
||||
|
||||
# For changes in the lucide vue packages
|
||||
💎 vue package:
|
||||
- 'packages/lucide-vue/*'
|
||||
- 'packages/lucide-vue-next/*'
|
||||
|
||||
# For changes in the lucide angular package
|
||||
🅰️ angular package:
|
||||
- 'packages/lucide-angular/*'
|
||||
|
||||
# For changes in the lucide preact package
|
||||
⚛️ preact package:
|
||||
- 'packages/lucide-preact/*'
|
||||
|
||||
# For changes in the lucide svelte package
|
||||
🧣 svelte package:
|
||||
- 'packages/lucide-svelte/*'
|
||||
|
||||
# For changes in the lucide solid package
|
||||
🪝 solid package:
|
||||
- 'packages/lucide-solid/*'
|
||||
|
||||
# For changes in the lucide static package
|
||||
🪨 static package:
|
||||
- 'packages/lucide-static/*'
|
||||
|
||||
# For changes in the lucide flutter package
|
||||
🏹 flutter package:
|
||||
- 'packages/lucide-flutter/*'
|
||||
55
.github/pull_request_template.md
vendored
Normal file
55
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<!-- Thank you for contributing! -->
|
||||
|
||||
<!-- Insert `closes #issueNumber` here if merging this PR will resolve an existing issue -->
|
||||
|
||||
## What is the purpose of this pull request?
|
||||
<!-- Please choose one of the following, and put an "x" next to it. -->
|
||||
- [ ] New Icon
|
||||
- [ ] Bug fix
|
||||
- [ ] New Feature
|
||||
- [ ] Documentation update
|
||||
- [ ] Other:
|
||||
|
||||
### Description
|
||||
<!-- Please insert your description here and provide info about the "what" this PR is contribution -->
|
||||
|
||||
### Icon use case <!-- ONLY for new icons, remove this part if not icon PR -->
|
||||
<!-- What is the purpose of this icon? For each icon added, please insert at least two real life use cases (the more the better). Text like "it's a car icon" is not accepted. -->
|
||||
|
||||
### Alternative icon designs <!-- ONLY for new icons, remove this part if not icon PR -->
|
||||
<!-- If you have any alternative icon designs, please attach them here. -->
|
||||
|
||||
## Icon Design Checklist <!-- ONLY for new icons, remove this part if not icon PR -->
|
||||
|
||||
### Concept <!-- ONLY for new icons -->
|
||||
<!-- All of these requirements must be fulfilled. -->
|
||||
- [ ] I have provided valid use cases for each icon.
|
||||
- [ ] I have not added any a brand or logo icon.
|
||||
- [ ] I have not used any hate symbols.
|
||||
- [ ] I have not included any religious or political imagery.
|
||||
|
||||
### Author, credits & license<!-- ONLY for new icons. -->
|
||||
<!-- Please choose one of the following, and put an "x" next to it. -->
|
||||
- [ ] The icons are solely my own creation.
|
||||
- [ ] The icons were originally created in #<issueNumber> by @<githubUser>
|
||||
- [ ] I've based them on the following Lucide icons: <!-- provide the list of icons -->
|
||||
- [ ] I've based them on the following design: <!-- provide source URL and license permitting use -->
|
||||
|
||||
### Naming <!-- ONLY for new icons -->
|
||||
<!-- All of these requirements must be fulfilled. -->
|
||||
- [ ] I've read and followed the [naming conventions](https://lucide.dev/guide/design/icon-design-guide#naming-conventions)
|
||||
- [ ] I've named icons by what they are rather than their use case.
|
||||
- [ ] I've provided meta JSON files in `icons/[iconName].json`.
|
||||
|
||||
### Design <!-- ONLY for new icons -->
|
||||
<!-- All of these requirements must be fulfilled. -->
|
||||
- [ ] I've read and followed the [icon design guidelines](https://lucide.dev/guide/design/icon-design-guide)
|
||||
- [ ] I've made sure that the icons look sharp on low DPI displays.
|
||||
- [ ] I've made sure that the icons look consistent with the icon set in size, optical volume and density.
|
||||
- [ ] I've made sure that the icons are visually centered.
|
||||
- [ ] I've correctly optimized all icons to two points of precision.
|
||||
|
||||
## Before Submitting <!-- For every PR! -->
|
||||
<!-- All of these requirements must be fulfilled. -->
|
||||
- [ ] I've read the [Contribution Guidelines](https://github.com/lucide-icons/lucide/blob/main/CONTRIBUTING.md).
|
||||
- [ ] I've checked if there was an existing PR that solves the same issue.
|
||||
32
.github/workflows/ci.yml
vendored
32
.github/workflows/ci.yml
vendored
@@ -10,8 +10,9 @@ on:
|
||||
jobs:
|
||||
create-release:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
VERSION: ${{ steps.new-version.outputs.NEW_VERSION }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -29,12 +30,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
@@ -47,7 +48,7 @@ jobs:
|
||||
|
||||
- name: Get latest tag
|
||||
id: latest-tag
|
||||
run: echo "::set-output name=LATEST_TAG::$(git describe --tags `git rev-list --tags --max-count=1`)"
|
||||
run: echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -57,17 +58,18 @@ jobs:
|
||||
|
||||
- name: Create new version
|
||||
id: new-version
|
||||
run: echo "::set-output name=NEW_VERSION::$(.github/workflows/version-up.sh --minor)"
|
||||
run: echo "NEW_VERSION=$(.github/workflows/version-up.sh --minor)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create change log
|
||||
id: change-log
|
||||
run: |
|
||||
CHANGE_LOG=$(pnpm run generate:changelog --old-tag=${{ steps.latest-tag.outputs.LATEST_TAG }})
|
||||
CHANGE_LOG="${CHANGE_LOG//'%'/'%25'}"
|
||||
CHANGE_LOG="${CHANGE_LOG//$'\n'/'%0A'}"
|
||||
CHANGE_LOG="${CHANGE_LOG//$'\r'/'%0D'}"
|
||||
CHANGE_LOG=$(tail -n +5 <<< $CHANGE_LOG)
|
||||
echo $CHANGE_LOG
|
||||
echo "::set-output name=CHANGE_LOG::$CHANGE_LOG"
|
||||
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
|
||||
echo "CHANGE_LOG<<$EOF" >> $GITHUB_OUTPUT
|
||||
echo "$CHANGE_LOG" >> $GITHUB_OUTPUT
|
||||
echo "$EOF" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -76,11 +78,17 @@ jobs:
|
||||
echo '${{ steps.new-version.outputs.NEW_VERSION }}'
|
||||
echo '${{ steps.change-log.outputs.CHANGE_LOG }}'
|
||||
|
||||
- name: Release
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CREATE_RELEASE_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.new-version.outputs.NEW_VERSION }}
|
||||
name: New icons ${{ steps.new-version.outputs.NEW_VERSION }}
|
||||
body: ${{ steps.change-log.outputs.CHANGE_LOG }}
|
||||
|
||||
start-release:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
needs: create-release
|
||||
uses: './.github/workflows/release.yml'
|
||||
secrets: inherit
|
||||
with:
|
||||
version: ${{ needs.create-release.outputs.VERSION }}
|
||||
|
||||
12
.github/workflows/labeler.yml
vendored
Normal file
12
.github/workflows/labeler.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: "Pull Request Labeler"
|
||||
on:
|
||||
- pull_request_target
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
5
.github/workflows/lucide-angular.yml
vendored
5
.github/workflows/lucide-angular.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-angular/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
18
.github/workflows/lucide-font.yml
vendored
18
.github/workflows/lucide-font.yml
vendored
@@ -4,12 +4,12 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- icons/**
|
||||
- tools/build-font/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-font:
|
||||
runs-on: ubuntu-latest
|
||||
container: ericfennis/lucide-font:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
@@ -26,15 +26,15 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-lucide-font-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-lucide-font-pnpm-store-
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter outline-svg
|
||||
@@ -42,11 +42,11 @@ jobs:
|
||||
- name: Outline svg Icons
|
||||
run: pnpm build:outline-icons
|
||||
|
||||
- name: Create directory
|
||||
run: mkdir lucide-font
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter build-font
|
||||
|
||||
- name: Build font
|
||||
run: fontcustom compile "./outlined" -h -n "lucide" -o ./lucide-font -F
|
||||
- name: Create font in ./lucide-font
|
||||
run: pnpm build:font
|
||||
|
||||
- name: "Upload to Artifacts"
|
||||
uses: actions/upload-artifact@v1
|
||||
|
||||
5
.github/workflows/lucide-preact.yml
vendored
5
.github/workflows/lucide-preact.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-preact/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-react-native.yml
vendored
5
.github/workflows/lucide-react-native.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-react-native/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
6
.github/workflows/lucide-react.yml
vendored
6
.github/workflows/lucide-react.yml
vendored
@@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-react/**
|
||||
- tools/build-icons/**
|
||||
- scripts/generateNextJSAliases.mjs
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +27,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-solid.yml
vendored
5
.github/workflows/lucide-solid.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-solid/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-static.yml
vendored
5
.github/workflows/lucide-static.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-static/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-svelte.yml
vendored
5
.github/workflows/lucide-svelte.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-svelte/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-vue-next.yml
vendored
5
.github/workflows/lucide-vue-next.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-vue-next/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide-vue.yml
vendored
5
.github/workflows/lucide-vue.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide-vue/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
5
.github/workflows/lucide.yml
vendored
5
.github/workflows/lucide.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/lucide/**
|
||||
- tools/build-icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
@@ -25,12 +26,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
18
.github/workflows/pull-request.yml
vendored
18
.github/workflows/pull-request.yml
vendored
@@ -22,6 +22,20 @@ jobs:
|
||||
uses: tj-actions/changed-files@v35
|
||||
with:
|
||||
files: icons/*.svg
|
||||
- name: Generate 24px dpi preview
|
||||
id: generate-24px-dpi-preview
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/dpi/24/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate cohesion check random
|
||||
id: generate-cohesion-check-random
|
||||
run: |
|
||||
@@ -134,6 +148,10 @@ jobs:
|
||||
${{ steps.generate-3px-stroke-width.outputs.body }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>DPI Preview (24px)</summary>
|
||||
${{ steps.generate-24px-dpi-preview.outputs.body }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Icon X-rays</summary>
|
||||
${{ steps.generate-x-rays.outputs.body }}
|
||||
</details>
|
||||
|
||||
640
.github/workflows/release.yml
vendored
640
.github/workflows/release.yml
vendored
@@ -5,6 +5,13 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
description: Version
|
||||
type: string
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
@@ -12,8 +19,8 @@ on:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
pre-build:
|
||||
if: github.repository == 'lucide-icons/lucide' && contains('["locness3","ericfennis", "johnletey", "karsa-mistmere"]', github.actor)
|
||||
pre-release:
|
||||
if: github.repository == 'lucide-icons/lucide' && contains('["ericfennis", "karsa-mistmere"]', github.actor)
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
VERSION: ${{ steps.get_version.outputs.VERSION }}
|
||||
@@ -23,19 +30,32 @@ jobs:
|
||||
id: get_version
|
||||
run: |
|
||||
echo $VERSION_REF
|
||||
echo ::set-output name=VERSION::${VERSION_REF/refs\/tags\/\v}
|
||||
echo "VERSION=${VERSION_REF/refs\/tags\/\v}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
VERSION_REF: ${{ github.event.inputs.version || github.ref }}
|
||||
VERSION_REF: ${{ inputs.version || github.event.inputs.version || github.ref }}
|
||||
|
||||
lucide:
|
||||
release:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
needs: pre-release
|
||||
strategy:
|
||||
matrix:
|
||||
package: [
|
||||
'lucide',
|
||||
'lucide-react',
|
||||
'lucide-react-native',
|
||||
'lucide-vue',
|
||||
'lucide-vue-next',
|
||||
'lucide-angular',
|
||||
'lucide-preact',
|
||||
'lucide-solid',
|
||||
'lucide-svelte',
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
@@ -47,484 +67,38 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ inputs.NPM_TOKEN || secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set new version
|
||||
run: pnpm --filter lucide version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
run: pnpm --filter ${{ matrix.package }} version --new-version ${{ needs.pre-release.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide build
|
||||
run: pnpm --filter ${{ matrix.package }} build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide test
|
||||
run: pnpm --filter ${{ matrix.package }} test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-package-json
|
||||
path: packages/lucide/package.json
|
||||
|
||||
lucide-react:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-react version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-react build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-react test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-react publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-react-package-json
|
||||
path: packages/lucide-react/package.json
|
||||
|
||||
lucide-react-native:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-react-native version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-react-native build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-react-native test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-react-native publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-react-native-package-json
|
||||
path: packages/lucide-react-native/package.json
|
||||
|
||||
lucide-vue:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set new version
|
||||
run: pnpm --filter lucide-vue version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-vue build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-vue test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-vue publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-vue-package-json
|
||||
path: packages/lucide-vue/package.json
|
||||
|
||||
lucide-vue-next:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set new version
|
||||
run: pnpm --filter lucide-vue-next version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-vue-next build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-vue-next test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-vue-next publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-vue-next-package-json
|
||||
path: packages/lucide-vue-next/package.json
|
||||
|
||||
lucide-angular:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-angular version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-angular build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-angular test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-angular publish --no-git-checks --ignore-scripts
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-angular-package-json
|
||||
path: packages/lucide-angular/package.json
|
||||
|
||||
lucide-preact:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-preact version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-preact build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-preact test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-preact publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-preact-package-json
|
||||
path: packages/lucide-preact/package.json
|
||||
|
||||
lucide-solid:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-solid version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-solid build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-solid test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-solid publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-solid-package-json
|
||||
path: packages/lucide-solid/package.json
|
||||
|
||||
lucide-svelte:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set package.json version lucide
|
||||
run: pnpm --filter lucide-svelte version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-svelte build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-svelte test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-svelte publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-svelte-package-json
|
||||
path: packages/lucide-svelte/package.json
|
||||
run: pnpm --filter ${{ matrix.package }} publish --no-git-checks --ignore-scripts
|
||||
|
||||
lucide-static:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pre-build, lucide-font]
|
||||
needs: [pre-release, lucide-font]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
@@ -543,24 +117,24 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Set Auth Token
|
||||
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Set new version
|
||||
run: pnpm --filter lucide-static version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
|
||||
run: pnpm --filter lucide-static version --new-version ${{ needs.pre-release.outputs.VERSION }} --no-git-tag-version
|
||||
|
||||
- name: Move Font
|
||||
run: cp -r lucide-font packages/lucide-static/font
|
||||
@@ -571,16 +145,10 @@ jobs:
|
||||
- name: Publish
|
||||
run: pnpm --filter lucide-static publish --no-git-checks
|
||||
|
||||
- name: Upload package.json
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-static-package-json
|
||||
path: packages/lucide-static/package.json
|
||||
|
||||
lucide-font:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-build
|
||||
needs: pre-release
|
||||
container: ericfennis/lucide-font:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -598,12 +166,12 @@ jobs:
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
@@ -626,130 +194,26 @@ jobs:
|
||||
name: lucide-font
|
||||
path: lucide-font
|
||||
|
||||
lucide-flutter:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pre-build, lucide-font]
|
||||
container:
|
||||
image: cirrusci/flutter:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.pub-cache
|
||||
key: ${{ runner.os }}-pub-${{ hashFiles('~/.pub-cache') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pub-
|
||||
|
||||
- name: Setup credentials
|
||||
run: |
|
||||
mkdir -p ~/.pub-cache
|
||||
cat <<EOF > ~/.pub-cache/credentials.json
|
||||
{
|
||||
"accessToken": "${{ secrets.GOOGLE_OAUTH_ACCESS_TOKEN }}",
|
||||
"refreshToken": "${{ secrets.GOOGLE_OAUTH_REFRESH_TOKEN }}",
|
||||
"idToken": "${{ secrets.GOOGLE_OAUTH_ID_TOKEN }}",
|
||||
"tokenEndpoint":"https://accounts.google.com/o/oauth2/token",
|
||||
"scopes": [ "openid", "https://www.googleapis.com/auth/userinfo.email" ],
|
||||
"expiration": 1629835569218
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Get packages
|
||||
run: flutter pub get
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: List lucide-font folder
|
||||
run: ls lucide-font
|
||||
|
||||
- name: Copy assets from lucide-font directory
|
||||
run: |
|
||||
mkdir packages/lucide-flutter/assets
|
||||
cp lucide-font/lucide.ttf packages/lucide-flutter/assets/lucide.ttf
|
||||
cp lucide-font/lucide-preview.html packages/lucide-flutter/assets/lucide-preview.html
|
||||
|
||||
- name: Generate exports file
|
||||
run: |
|
||||
dart tool/generate_fonts.dart assets/lucide-preview.html
|
||||
flutter format .
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: Test
|
||||
run: flutter test
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: Copy License
|
||||
run: cp ../../LICENSE ./LICENSE
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: Update yaml
|
||||
run: sed -E 's/(version:)[^\n]*/\1 ${{ needs.pre-build.outputs.VERSION }}/;' pubspec.yaml > pubspec && mv pubspec pubspec.yaml
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: Flutter publish
|
||||
run: flutter pub publish -f
|
||||
working-directory: packages/lucide-flutter
|
||||
|
||||
- name: Upload pubspec.yaml
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lucide-flutter-pubspec-yaml
|
||||
path: packages/lucide-flutter/pubspec.yaml
|
||||
|
||||
post-release:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
[
|
||||
pre-build,
|
||||
lucide,
|
||||
lucide-react,
|
||||
lucide-react-native,
|
||||
lucide-vue,
|
||||
lucide-vue-next,
|
||||
lucide-angular,
|
||||
lucide-svelte,
|
||||
lucide-preact,
|
||||
lucide-flutter,
|
||||
lucide-font,
|
||||
]
|
||||
needs: [
|
||||
pre-release,
|
||||
lucide-font,
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
|
||||
- name: Commit package files
|
||||
run: |
|
||||
mv lucide-package-json/package.json packages/lucide/package.json
|
||||
mv lucide-react-package-json/package.json packages/lucide-react/package.json
|
||||
mv lucide-react-native-package-json/package.json packages/lucide-react-native/package.json
|
||||
mv lucide-vue-package-json/package.json packages/lucide-vue/package.json
|
||||
mv lucide-preact-package-json/package.json packages/lucide-preact/package.json
|
||||
mv lucide-svelte-package-json/package.json packages/lucide-svelte/package.json
|
||||
mv lucide-vue-next-package-json/package.json packages/lucide-vue-next/package.json
|
||||
mv lucide-angular-package-json/package.json packages/lucide-angular/package.json
|
||||
mv lucide-flutter-pubspec-yaml/pubspec.yaml packages/lucide-flutter/pubspec.yaml
|
||||
|
||||
- name: Commit package.jsons
|
||||
run: |
|
||||
git add packages/*/package.json packages/lucide-flutter/pubspec.yaml
|
||||
git -c user.name="Lucide Bot" -c user.email="lucide-bot@users.noreply.github.com" \
|
||||
commit -m ":package: Bump lucide package versions to ${{ needs.pre-build.outputs.VERSION }}" --no-verify --quiet
|
||||
git remote set-url --push origin https://lucide-bot:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY.git
|
||||
git push origin HEAD:main
|
||||
|
||||
- name: Zip font and icons
|
||||
run: |
|
||||
zip -r lucide-font-${{ needs.pre-build.outputs.VERSION }}.zip lucide-font
|
||||
zip -r lucide-icons-${{ needs.pre-build.outputs.VERSION }}.zip icons
|
||||
zip -r lucide-font-${{ needs.pre-release.outputs.VERSION }}.zip lucide-font
|
||||
zip -r lucide-icons-${{ needs.pre-release.outputs.VERSION }}.zip icons
|
||||
|
||||
- name: Release zip and fonts
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CREATE_RELEASE_TOKEN }}
|
||||
with:
|
||||
tag_name: v${{ needs.pre-build.outputs.VERSION }}
|
||||
tag_name: ${{ needs.pre-release.outputs.VERSION }}
|
||||
files: |
|
||||
lucide-font-${{ needs.pre-build.outputs.VERSION }}.zip
|
||||
lucide-icons-${{ needs.pre-build.outputs.VERSION }}.zip
|
||||
lucide-font-${{ needs.pre-release.outputs.VERSION }}.zip
|
||||
lucide-icons-${{ needs.pre-release.outputs.VERSION }}.zip
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -17,6 +17,10 @@ packages/**/src/icons/*.js
|
||||
packages/**/src/icons/*.ts
|
||||
packages/**/src/icons/*.tsx
|
||||
packages/**/src/aliases.ts
|
||||
packages/**/src/dynamicIconImports.ts
|
||||
packages/**/dynamicIconImports.js
|
||||
packages/**/dynamicIconImports.d.ts
|
||||
packages/**/dynamicIconImports.js.map
|
||||
packages/**/LICENSE
|
||||
categories.json
|
||||
tags.json
|
||||
@@ -30,6 +34,7 @@ docs/.vitepress/data/iconNodes
|
||||
docs/.vitepress/data/iconMetaData.ts
|
||||
docs/.vitepress/data/releaseMetaData.json
|
||||
docs/.vitepress/data/releaseMetaData
|
||||
docs/.vitepress/data/iconDetails
|
||||
docs/.vitepress/data/relatedIcons.json
|
||||
docs/.vercel
|
||||
docs/.nitro
|
||||
|
||||
95
.vscode/svg.code-snippets
vendored
Normal file
95
.vscode/svg.code-snippets
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"Lucide SVG": {
|
||||
"scope": "xml",
|
||||
"description": "Base SVG with Lucide attributes.",
|
||||
"prefix": [
|
||||
"svg",
|
||||
"lucide"
|
||||
],
|
||||
"body": [
|
||||
"<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\"",
|
||||
">",
|
||||
" $0",
|
||||
"</svg>"
|
||||
]
|
||||
},
|
||||
"Rectangle": {
|
||||
"scope": "xml",
|
||||
"description": "SVG `rect`angle, with Lucide defaults.",
|
||||
"prefix": [
|
||||
"rect",
|
||||
"<rect"
|
||||
],
|
||||
"body": "<rect width=\"${1:20}\" height=\"${2:12}\" x=\"${3:2}\" y=\"${4:6}\" rx=\"${5|2,1|}\"/>"
|
||||
},
|
||||
"Square": {
|
||||
"scope": "xml",
|
||||
"description": "SVG square `rect`angle, with Lucide defaults.",
|
||||
"prefix": [
|
||||
"square",
|
||||
"rect",
|
||||
"<rect",
|
||||
"tile"
|
||||
],
|
||||
"body": "<rect width=\"${1:18}\" height=\"$1\" x=\"${2:3}\" y=\"${3:$2}\" rx=\"${4|2,1|}\" />"
|
||||
},
|
||||
"Circle": {
|
||||
"scope": "xml",
|
||||
"description": "SVG `circle`, with Lucide defaults.",
|
||||
"prefix": [
|
||||
"circle",
|
||||
"<circle"
|
||||
],
|
||||
"body": "<circle cx=\"${2:12}\" cy=\"${3:$2}\" r=\"${1|10,2,.5|}\" />"
|
||||
},
|
||||
"Ellipse": {
|
||||
"scope": "xml",
|
||||
"description": "SVG `ellipse`.",
|
||||
"prefix": [
|
||||
"ellipse",
|
||||
"<ellipse"
|
||||
],
|
||||
"body": "<ellipse cx=\"${3:12}\" cy=\"${4:$3}\" rx=\"${1:10}\" ry=\"${2:$1}\" />"
|
||||
},
|
||||
"Path": {
|
||||
"scope": "xml",
|
||||
"description": "SVG custom `path`.",
|
||||
"prefix": [
|
||||
"path",
|
||||
"<path",
|
||||
"polyline",
|
||||
"<polyline",
|
||||
"polygon",
|
||||
"<polygon"
|
||||
],
|
||||
"body": "<path d=\"${1|M,m|}$0\" />"
|
||||
},
|
||||
"Line": {
|
||||
"scope": "xml",
|
||||
"description": "SVG `path`, preffered to `line` in Lucide.",
|
||||
"prefix": [
|
||||
"line",
|
||||
"<line",
|
||||
"minus"
|
||||
],
|
||||
"body": "<path d=\"M${3:5} ${4:12}${1|h,v|}${2:14}\" />"
|
||||
},
|
||||
"Dot": {
|
||||
"scope": "xml",
|
||||
"description": "SVG small dot, within the Lucide guidelines.",
|
||||
"prefix": [
|
||||
"dot",
|
||||
"."
|
||||
],
|
||||
"body": "<path d=\"M ${1:12} ${2:$1}h.01\" />"
|
||||
}
|
||||
}
|
||||
@@ -166,8 +166,8 @@ For more details, see the [documentation](https://github.com/lucide-icons/lucide
|
||||
### Static (svg sprite, font, icons ..)
|
||||
|
||||
Assets:
|
||||
[Font Files](https://github.com/lucide-icons/lucide/releases/tag/latest)
|
||||
[SVG Files](https://github.com/lucide-icons/lucide/releases/tag/latest)
|
||||
[Font Files](https://github.com/lucide-icons/lucide/releases/latest)
|
||||
[SVG Files](https://github.com/lucide-icons/lucide/releases/latest)
|
||||
[SVG Sprite](https://cdn.jsdelivr.net/npm/lucide-static@latest/sprite.svg)
|
||||
|
||||
NPM package
|
||||
@@ -285,6 +285,9 @@ Thank you to all the people who contributed to Lucide!
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
||||
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
|
||||
<img src="./site/public/vercel.svg" alt="Powered by Vercel" width="200" />
|
||||
<img src="docs/public/vercel.svg" alt="Powered by Vercel" width="200" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.digitalocean.com/?refcode=b0877a2caebd&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"><img src="docs/public/digitalocean.svg" width="200" alt="DigitalOcean Referral Badge" /></a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Transportation",
|
||||
"icon": "train"
|
||||
"icon": "train-front"
|
||||
}
|
||||
11
docs/.vitepress/api/categories/index.get.ts
Normal file
11
docs/.vitepress/api/categories/index.get.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { eventHandler, setResponseHeader } from 'h3'
|
||||
import iconMetaData from '../../data/iconMetaData'
|
||||
|
||||
export default eventHandler((event) => {
|
||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(iconMetaData).map(([name, { categories }]) => [ name, categories ])
|
||||
)
|
||||
})
|
||||
@@ -1,41 +1,44 @@
|
||||
import { eventHandler, setResponseHeader, defaultContentType } from 'h3'
|
||||
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
|
||||
import { createElement } from 'react'
|
||||
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
|
||||
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
|
||||
import { createElement } from 'react';
|
||||
import SvgPreview from '../../lib/SvgPreview/index.tsx';
|
||||
import iconNodes from '../../data/iconNodes'
|
||||
import createLucideIcon from 'lucide-react/src/createLucideIcon'
|
||||
import iconNodes from '../../data/iconNodes';
|
||||
import createLucideIcon from 'lucide-react/src/createLucideIcon';
|
||||
import Backdrop from '../../lib/SvgPreview/Backdrop.tsx';
|
||||
|
||||
export default eventHandler((event) => {
|
||||
const { params } = event.context
|
||||
const { params } = event.context;
|
||||
|
||||
const [name, svgData] = params.data.split('/');
|
||||
const data = svgData.slice(0, -4);
|
||||
const pathData = params.data.split('/');
|
||||
const data = pathData.at(-1).slice(0, -4);
|
||||
const [name] = pathData;
|
||||
|
||||
const src = Buffer.from(data, 'base64').toString('utf8');
|
||||
|
||||
const children = []
|
||||
const children = [];
|
||||
|
||||
if (name in iconNodes) {
|
||||
const iconNode = iconNodes[name]
|
||||
// If the icon already exists, it uses the existing icon as the backdrop.
|
||||
// If the icon does not exist but an icon exists that starts with the same group name, that icon
|
||||
// is used as the backdrop
|
||||
const backdropName =
|
||||
name in iconNodes ? name : name.split('-')[0] in iconNodes ? name.split('-')[0] : null;
|
||||
if (backdropName) {
|
||||
const iconNode = iconNodes[backdropName];
|
||||
|
||||
const LucideIcon = createLucideIcon(name, iconNode)
|
||||
const svg = renderToStaticMarkup(createElement(LucideIcon))
|
||||
const LucideIcon = createLucideIcon(backdropName, iconNode);
|
||||
const svg = renderToStaticMarkup(createElement(LucideIcon));
|
||||
const backdropString = svg.replace(/<svg[^>]*>|<\/svg>/g, '');
|
||||
|
||||
children.push(createElement(Backdrop, { backdropString, src }))
|
||||
children.push(createElement(Backdrop, { backdropString, src }));
|
||||
}
|
||||
|
||||
const svg = Buffer.from(
|
||||
// We can't use jsx here, is not supported here by nitro.
|
||||
renderToString(createElement(SvgPreview, {src, showGrid: true}, children)).replace(
|
||||
/>/,
|
||||
'><style>@media screen and (prefers-color-scheme: dark) { svg { stroke: #fff } }</style>'
|
||||
)
|
||||
renderToString(createElement(SvgPreview, { src, showGrid: true }, children))
|
||||
).toString('utf8');
|
||||
|
||||
defaultContentType(event, 'image/svg+xml')
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
||||
defaultContentType(event, 'image/svg+xml');
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
|
||||
|
||||
return svg
|
||||
})
|
||||
return svg;
|
||||
});
|
||||
|
||||
73
docs/.vitepress/api/gh-icon/dpi/[...data].get.ts
Normal file
73
docs/.vitepress/api/gh-icon/dpi/[...data].get.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
|
||||
import { Resvg, initWasm } from '@resvg/resvg-wasm';
|
||||
import wasm from './loadWasm';
|
||||
|
||||
var initializedResvg = initWasm(wasm);
|
||||
|
||||
export default eventHandler(async (event) => {
|
||||
const { params = {} } = event.context;
|
||||
await initializedResvg;
|
||||
|
||||
const imageSize = 96;
|
||||
const [iconSizeString, svgData] = params.data.split('/');
|
||||
const iconSize = parseInt(iconSizeString, 10);
|
||||
const data = svgData.slice(0, -4);
|
||||
|
||||
const src = Buffer.from(data, 'base64').toString('utf8');
|
||||
const svg = (src.includes('<svg') ? src : `<svg>${src}</svg>`)
|
||||
.replace(/(\r\n|\n|\r)/gm, '')
|
||||
.replace(
|
||||
/<svg[^>]*/,
|
||||
`<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="${iconSize}"
|
||||
height="${iconSize}"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#fff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
`
|
||||
);
|
||||
|
||||
const resvg = new Resvg(svg, { background: '#000' });
|
||||
const pngData = resvg.render();
|
||||
const pngBuffer = Buffer.from(pngData.asPng());
|
||||
|
||||
defaultContentType(event, 'image/svg+xml');
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
|
||||
|
||||
return `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="${imageSize}" height="${imageSize}" viewBox="0 0 ${imageSize} ${imageSize}">
|
||||
<style>
|
||||
@media screen and (prefers-color-scheme: light) {
|
||||
#fallback-background { fill: transparent; }
|
||||
}
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
#fallback-background { fill: transparent; }
|
||||
rect { fill: #fff; }
|
||||
}
|
||||
</style>
|
||||
<mask id="mask">
|
||||
<image
|
||||
width="${imageSize}"
|
||||
height="${imageSize}"
|
||||
href="data:image/png;base64,${pngBuffer.toString('base64')}"
|
||||
image-rendering="pixelated"
|
||||
/>
|
||||
</mask>
|
||||
<rect
|
||||
id="fallback-background"
|
||||
width="${imageSize}"
|
||||
height="${imageSize}" ry="${imageSize / 24}"
|
||||
fill="#fff"
|
||||
/>
|
||||
<rect
|
||||
width="${imageSize}"
|
||||
height="${imageSize}"
|
||||
fill="#000"
|
||||
mask="url(#mask)"
|
||||
/>
|
||||
</svg>`;
|
||||
});
|
||||
15
docs/.vitepress/api/gh-icon/dpi/loadWasm.ts
Normal file
15
docs/.vitepress/api/gh-icon/dpi/loadWasm.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import fs from 'fs';
|
||||
import module from 'node:module';
|
||||
/* WASM_IMPORT */
|
||||
|
||||
let wasm;
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const require = module.createRequire(import.meta.url);
|
||||
|
||||
wasm = fs.readFileSync(require.resolve('@resvg/resvg-wasm/index_bg.wasm'));
|
||||
} else {
|
||||
wasm = resvg_wasm;
|
||||
}
|
||||
|
||||
export default wasm;
|
||||
@@ -22,10 +22,19 @@ export default eventHandler((event) => {
|
||||
|
||||
const svg = Buffer.from(
|
||||
// We can't use jsx here, is not supported here by nitro.
|
||||
renderToString(createElement(Icon, { strokeWidth })).replace(
|
||||
/>/,
|
||||
'><style>@media screen and (prefers-color-scheme: dark) { svg { stroke: #fff } }</style>'
|
||||
)
|
||||
renderToString(createElement(Icon, { strokeWidth }))
|
||||
.replace(/fill\="none"/, 'fill="#fff"')
|
||||
.replace(
|
||||
/>/,
|
||||
`><style>
|
||||
@media screen and (prefers-color-scheme: light) {
|
||||
svg { fill: transparent !important; }
|
||||
}
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
svg { stroke: #fff; fill: transparent !important; }
|
||||
}
|
||||
</style>`
|
||||
)
|
||||
).toString('utf8');
|
||||
|
||||
defaultContentType(event, 'image/svg+xml')
|
||||
|
||||
@@ -8,6 +8,7 @@ export default eventHandler((event) => {
|
||||
const withUniqueKeys = query.withUniqueKeys === 'true'
|
||||
|
||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
||||
|
||||
if (withUniqueKeys) {
|
||||
return iconNodes
|
||||
|
||||
@@ -38,6 +38,7 @@ export default eventHandler((event) => {
|
||||
|
||||
defaultContentType(event, 'image/svg+xml')
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
||||
|
||||
return svg
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import iconMetaData from '../../data/iconMetaData'
|
||||
|
||||
export default eventHandler((event) => {
|
||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(iconMetaData).map(([name, { tags }]) => [ name, tags ])
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { createWriteStream } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { SitemapStream } from 'sitemap'
|
||||
import sidebar from './sidebar';
|
||||
|
||||
const links = []
|
||||
|
||||
|
||||
const title = "Lucide";
|
||||
const socialTitle = "Lucide Icons";
|
||||
const description = "Beautiful & consistent icon toolkit made by the community."
|
||||
@@ -19,6 +12,7 @@ export default defineConfig({
|
||||
description,
|
||||
cleanUrls: true,
|
||||
outDir: '.vercel/output/static',
|
||||
srcExclude: ['**/README.md'],
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: [
|
||||
@@ -35,11 +29,11 @@ export default defineConfig({
|
||||
)
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
head: [
|
||||
[ 'script', {
|
||||
src: 'https://plausible.io/js/script.js',
|
||||
src: 'https://analytics.lucide.dev/js/script.js',
|
||||
'data-domain': 'lucide.dev',
|
||||
defer: ''
|
||||
}],
|
||||
@@ -125,36 +119,7 @@ export default defineConfig({
|
||||
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
|
||||
},
|
||||
},
|
||||
transformHtml: (_, id, { pageData }) => {
|
||||
if (/[\\/]404\.html$/.test(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (pageData.relativePath === 'index.md') {
|
||||
console.log('Home!');
|
||||
}
|
||||
|
||||
if (pageData.relativePath.startsWith('icons/')) {
|
||||
links.push({
|
||||
url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
|
||||
lastmod: pageData?.params?.changedRelease?.date
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
links.push({
|
||||
url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
|
||||
lastmod: pageData.lastUpdated
|
||||
})
|
||||
},
|
||||
buildEnd: async ({ outDir }) => {
|
||||
const sitemap = new SitemapStream({
|
||||
hostname: 'https://lucide.dev/'
|
||||
})
|
||||
const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml'))
|
||||
sitemap.pipe(writeStream)
|
||||
links.forEach((link) => sitemap.write(link))
|
||||
sitemap.end()
|
||||
await new Promise((r) => writeStream.on('finish', r))
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://lucide.dev/'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getPaths, assert } from './utils';
|
||||
|
||||
const Grid = ({
|
||||
radius,
|
||||
fill,
|
||||
fill = '#fff',
|
||||
...props
|
||||
}: {
|
||||
strokeWidth: number;
|
||||
@@ -12,6 +12,7 @@ const Grid = ({
|
||||
} & PathProps<'stroke', 'strokeWidth'>) => (
|
||||
<g className="svg-preview-grid-group" strokeLinecap="butt" {...props}>
|
||||
<rect
|
||||
className="svg-preview-grid-rect"
|
||||
width={24 - props.strokeWidth}
|
||||
height={24 - props.strokeWidth}
|
||||
x={props.strokeWidth / 2}
|
||||
@@ -207,7 +208,12 @@ const SvgPreview = React.forwardRef<
|
||||
>(({ src, children, showGrid = false, ...props }, ref) => {
|
||||
const paths = typeof src === 'string' ? getPaths(src) : src;
|
||||
|
||||
const darkModeCss = `@media screen and (prefers-color-scheme: dark) {
|
||||
const darkModeCss = `@media screen and (prefers-color-scheme: light) {
|
||||
.svg-preview-grid-rect { fill: none }
|
||||
}
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
.svg-preview-grid-rect { fill: none }
|
||||
.svg
|
||||
.svg-preview-grid-group,
|
||||
.svg-preview-radii-group,
|
||||
.svg-preview-shadow-mask-group,
|
||||
|
||||
@@ -24,7 +24,7 @@ const getIconCodes = (): CodeExampleType => {
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<i data-lucide-name="Name"></i>
|
||||
code: `<i data-lucide="Name"></i>
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -8,14 +8,6 @@ const DATE_OF_FORK = '2020-06-08T16:39:52+0100';
|
||||
|
||||
const directory = path.join(process.cwd(), "../icons");
|
||||
|
||||
export function getAllNames() {
|
||||
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json');
|
||||
|
||||
return fileNames
|
||||
.filter((fileName) => fs.existsSync(directory + '/' + path.basename(fileName, '.json') + '.svg'))
|
||||
.map((fileName) => path.basename(fileName, '.json'));
|
||||
}
|
||||
|
||||
export interface GetDataOptions {
|
||||
withChildKeys?: boolean
|
||||
}
|
||||
@@ -49,7 +41,7 @@ export async function getData(name: string) {
|
||||
}
|
||||
|
||||
export async function getAllData(): Promise<{ name: string, iconNode: IconNodeWithKeys}[]> {
|
||||
const names = getAllNames();
|
||||
const names = Object.keys(iconNodes);
|
||||
|
||||
return Promise.all(names.map((name) => getData(name)));
|
||||
}
|
||||
|
||||
@@ -10,26 +10,49 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
{ text: 'Comparison', link: '/guide/comparison' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Basics',
|
||||
items: [
|
||||
{
|
||||
text: 'Color',
|
||||
link: '/guide/basics/color'
|
||||
},
|
||||
{
|
||||
text: 'Sizing',
|
||||
link: '/guide/basics/sizing'
|
||||
},
|
||||
{
|
||||
text: 'Stroke width',
|
||||
link: '/guide/basics/stroke-width'
|
||||
},
|
||||
]
|
||||
},
|
||||
// TODO: Add this section
|
||||
// {
|
||||
// text: 'Using Icons',
|
||||
// text: 'Advanced',
|
||||
// items: [
|
||||
// {
|
||||
// text: 'How to use icons',
|
||||
// link: 'how-to-use-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Styling icons',
|
||||
// link: 'styling-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Accessibility',
|
||||
// link: 'accessibility'
|
||||
// link: '/guide/advanced/accessibility'
|
||||
// },
|
||||
// {
|
||||
// text: 'What should I use',
|
||||
// link: 'what-should-i-use'
|
||||
// text: 'Global styling',
|
||||
// },
|
||||
|
||||
// {
|
||||
// text: 'Animations',
|
||||
// },
|
||||
// {
|
||||
// text: 'Filled icons',
|
||||
// },
|
||||
// {
|
||||
// text: 'Combining icons',
|
||||
// },
|
||||
// {
|
||||
// text: 'Dynamic imports'
|
||||
// },
|
||||
// // {
|
||||
// // text: 'Auto importing'
|
||||
// // },
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
@@ -103,15 +126,9 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
]
|
||||
},
|
||||
],
|
||||
// This should be here to keep the sidebar shown on the icons page
|
||||
'icons': [
|
||||
{ text: '', link: '/' },
|
||||
// { text: 'Categorized', link: '/icons/categorized' },
|
||||
// {
|
||||
// text: 'Categories',
|
||||
// items: [
|
||||
// ...(getAllCategoryFiles().map((category) => ({ text: category, link: `/icons/category/${category}` })))
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
55
docs/.vitepress/theme/components/base/Tooltip.vue
Normal file
55
docs/.vitepress/theme/components/base/Tooltip.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref} from 'vue';
|
||||
import {useFloating, offset, shift} from '@floating-ui/vue';
|
||||
|
||||
const reference = ref(null);
|
||||
const tooltip = ref(null);
|
||||
const middleware = ref([shift(), offset(8)]);
|
||||
const { floatingStyles, update } = useFloating(reference, tooltip, {
|
||||
middleware,
|
||||
transform: false
|
||||
});
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
}>()
|
||||
|
||||
onMounted(() => {
|
||||
update()
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span ref="reference" class="reference">
|
||||
<slot/>
|
||||
</span>
|
||||
<div ref="tooltip" class="tooltip" :style="floatingStyles">
|
||||
{{title}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.reference:hover + .tooltip{
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
transform: scale(0.9);
|
||||
font-weight: 400;
|
||||
background: var(--vp-c-brand-dark);
|
||||
color: white;
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--vp-shadow-1);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: cubic-bezier(0.19, 1, 0.22, 1) .2s;
|
||||
transition-property: opacity, transform;
|
||||
}
|
||||
</style>
|
||||
@@ -64,7 +64,7 @@ watch(absoluteStrokeWidth, (enabled) => {
|
||||
<ResetButton @click="resetStyle"></ResetButton>
|
||||
</h2>
|
||||
<p class="copy">
|
||||
Lucide has a lot of customization options to match the icons with you UI.
|
||||
Lucide has a lot of customization options to match the icons with your UI.
|
||||
</p>
|
||||
|
||||
<div class="customizer">
|
||||
|
||||
@@ -3,19 +3,9 @@ import { ref } from 'vue';
|
||||
import ButtonMenu from '../base/ButtonMenu.vue'
|
||||
import { useIconStyleContext } from '../../composables/useIconStyle';
|
||||
import useConfetti from '../../composables/useConfetti';
|
||||
import getSVGIcon from '../../utils/getSVGIcon';
|
||||
import downloadData from '../../utils/downloadData';
|
||||
|
||||
const allowedAttrs = [
|
||||
'xmlns',
|
||||
'width',
|
||||
'height',
|
||||
'viewBox',
|
||||
'fill',
|
||||
'stroke',
|
||||
'stroke-width',
|
||||
'stroke-linecap',
|
||||
'stroke-linejoin',
|
||||
'class',
|
||||
]
|
||||
const downloadText = 'Download!'
|
||||
const copiedText = 'Copied!'
|
||||
const confettiText = ref(copiedText)
|
||||
@@ -28,24 +18,6 @@ const { size } = useIconStyleContext()
|
||||
|
||||
const { animate, confetti } = useConfetti()
|
||||
|
||||
function getSVGIcon() {
|
||||
const svg = document.querySelector('#previewer svg')
|
||||
if (!svg) return
|
||||
|
||||
const clonedSvg = svg.cloneNode(true) as SVGElement
|
||||
|
||||
// Filter out attributes that are not allowed in SVGs
|
||||
for (const attr of Array.from(clonedSvg.attributes)) {
|
||||
if (!allowedAttrs.includes(attr.name)) {
|
||||
clonedSvg.removeAttribute(attr.name)
|
||||
}
|
||||
}
|
||||
|
||||
const svgString = new XMLSerializer().serializeToString(clonedSvg)
|
||||
|
||||
return svgString
|
||||
}
|
||||
|
||||
function copySVG() {
|
||||
confettiText.value = copiedText
|
||||
const svgString = getSVGIcon()
|
||||
@@ -70,11 +42,7 @@ function downloadSVG() {
|
||||
confettiText.value = downloadText
|
||||
const svgString = getSVGIcon()
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.download = `${props.name}.svg`;
|
||||
link.href = `data:image/svg+xml;base64,${btoa(svgString)}`
|
||||
link.click();
|
||||
|
||||
downloadData(`${props.name}.svg`, `data:image/svg+xml;base64,${btoa(svgString)}`)
|
||||
confetti()
|
||||
}
|
||||
|
||||
@@ -91,12 +59,7 @@ function downloadPNG() {
|
||||
image.src = `data:image/svg+xml;base64,${btoa(svgString)}`;
|
||||
image.onload = function() {
|
||||
ctx.drawImage(image, 0, 0);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.download = `${props.name}.png`;
|
||||
link.href = canvas.toDataURL('image/png')
|
||||
link.click();
|
||||
|
||||
downloadData(`${props.name}.png`, canvas.toDataURL('image/png'))
|
||||
confetti()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import type { IconEntity } from '../../types'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
|
||||
import IconButton from '../base/IconButton.vue';
|
||||
import IconContributors from './IconContributors.vue';
|
||||
import IconPreview from './IconPreview.vue';
|
||||
import { x, expand } from '../../../data/iconNodes'
|
||||
import { useRouter } from 'vitepress';
|
||||
import IconInfo from './IconInfo.vue';
|
||||
import Badge from '../base/Badge.vue';
|
||||
import type { IconEntity } from '../../types'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
|
||||
import IconButton from '../base/IconButton.vue';
|
||||
import IconContributors from './IconContributors.vue';
|
||||
import IconPreview from './IconPreview.vue';
|
||||
import { x, expand } from '../../../data/iconNodes'
|
||||
import { useRouter } from 'vitepress';
|
||||
import IconInfo from './IconInfo.vue';
|
||||
import Badge from '../base/Badge.vue';
|
||||
import { computedAsync } from '@vueuse/core';
|
||||
|
||||
const props = defineProps<{
|
||||
icon: IconEntity
|
||||
}>()
|
||||
const props = defineProps<{
|
||||
iconName: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const isOpen = computed(() => !!props.icon)
|
||||
|
||||
function onClose() {
|
||||
emit('close')
|
||||
const icon = computedAsync<IconEntity | null>(async () => {
|
||||
if (props.iconName) {
|
||||
return (await import(`../../../data/iconDetails/${props.iconName}.ts`)).default as IconEntity
|
||||
}
|
||||
return null
|
||||
}, null)
|
||||
|
||||
const { go } = useRouter()
|
||||
const emit = defineEmits(['close'])
|
||||
const isOpen = computed(() => !!icon.value)
|
||||
|
||||
const CloseIcon = createLucideIcon('Close', x)
|
||||
const Expand = createLucideIcon('Expand', expand)
|
||||
function onClose() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
const { go } = useRouter()
|
||||
|
||||
const CloseIcon = createLucideIcon('Close', x)
|
||||
const Expand = createLucideIcon('Expand', expand)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -109,9 +117,8 @@
|
||||
}
|
||||
|
||||
.icon-info {
|
||||
padding: 0 24px;
|
||||
padding-left: 24px;
|
||||
flex-basis: 100%;
|
||||
|
||||
}
|
||||
|
||||
.icon-tags {
|
||||
|
||||
@@ -43,5 +43,6 @@ function setActiveIcon(name: string) {
|
||||
|
||||
.icon {
|
||||
aspect-ratio: 1/1;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,7 +17,7 @@ const { go } = useRouter()
|
||||
const { page } = useData()
|
||||
|
||||
const tags = computed(() => {
|
||||
if (!props.icon) return []
|
||||
if (!props.icon || !props?.icon?.tags) return []
|
||||
return props.icon.tags.join(' • ')
|
||||
})
|
||||
</script>
|
||||
@@ -27,9 +27,11 @@ const tags = computed(() => {
|
||||
<IconDetailName class="icon-name">
|
||||
{{ icon.name }}
|
||||
</IconDetailName>
|
||||
<p class="icon-tags">
|
||||
{{ tags }}
|
||||
</p>
|
||||
<div class="tags-scroller" v-if="tags.length">
|
||||
<p class="icon-tags horizontal-scroller">
|
||||
{{ tags }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="group">
|
||||
<Badge
|
||||
v-for="category in icon.categories"
|
||||
@@ -72,9 +74,61 @@ const tags = computed(() => {
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-text-2);
|
||||
font-weight: 500;
|
||||
margin-top: 0;;
|
||||
margin-bottom: 16px;
|
||||
line-height: 28px;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tags-scroller {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
padding: 8px 0 16px;
|
||||
margin-bottom: 16px;
|
||||
margin-top: 8px;
|
||||
align-items: center;
|
||||
|
||||
--gradient-background: var(--tags-gradient-background, var(--vp-c-bg-elv))
|
||||
}
|
||||
.horizontal-scroller {
|
||||
overflow-x: scroll;
|
||||
/* Hide Scrollbar */
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
scrollbar-width: thin; /* can also be normal, or none, to not render scrollbar */
|
||||
scrollbar-color: currentColor transparent; /* foreground background */
|
||||
}
|
||||
.horizontal-scroller::-webkit-scrollbar {
|
||||
width: 0;
|
||||
display: none
|
||||
}
|
||||
|
||||
.horizontal-scroller::-webkit-scrollbar-track {
|
||||
background: transparent
|
||||
}
|
||||
|
||||
.horizontal-scroller::-webkit-scrollbar-thumb {
|
||||
background: transparent;
|
||||
border: none
|
||||
}
|
||||
|
||||
|
||||
.tags-scroller::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 32px;
|
||||
height: 100%;
|
||||
/* Background Gradient left to right */
|
||||
background: linear-gradient(to right, rgba(255,255,255,0) 0%,var(--gradient-background) 100%);
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
|
||||
import { useMediaQuery } from '@vueuse/core';
|
||||
import { useRouter } from 'vitepress';
|
||||
import getSVGIcon from '../../utils/getSVGIcon';
|
||||
import useConfetti from '../../composables/useConfetti';
|
||||
import Tooltip from '../base/Tooltip.vue';
|
||||
|
||||
const downloadText = 'Download!'
|
||||
const copiedText = 'Copied!'
|
||||
|
||||
export type IconNode = [elementName: string, attrs: Record<string, string>][]
|
||||
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
// tags: string[];
|
||||
// categories: string[];
|
||||
iconNode: IconNode;
|
||||
active: boolean;
|
||||
customizable?: boolean;
|
||||
@@ -20,40 +24,65 @@ const emit = defineEmits(['setActiveIcon'])
|
||||
|
||||
const { go } = useRouter()
|
||||
const showOverlay = useMediaQuery('(min-width: 860px)');
|
||||
const { animate, confetti, confettiText } = useConfetti()
|
||||
|
||||
|
||||
const icon = createLucideIcon(props.name, props.iconNode)
|
||||
|
||||
function navigateToIcon() {
|
||||
async function navigateToIcon(event) {
|
||||
|
||||
if (event.shiftKey) {
|
||||
event.preventDefault()
|
||||
const svgString = getSVGIcon(event.target.firstChild, {
|
||||
class: `lucide lucide-${props.name}`,
|
||||
})
|
||||
|
||||
await navigator.clipboard.writeText(svgString)
|
||||
|
||||
confettiText.value = copiedText
|
||||
confetti()
|
||||
return
|
||||
}
|
||||
|
||||
if(props.overlayMode && showOverlay.value) {
|
||||
event.preventDefault()
|
||||
window.history.pushState({}, '', `/icons/${props.name}`)
|
||||
emit('setActiveIcon', props.name)
|
||||
}
|
||||
else {
|
||||
event.preventDefault()
|
||||
go(`/icons/${props.name}`)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
class="icon-button"
|
||||
@click="navigateToIcon"
|
||||
:class="{ 'active' : active }"
|
||||
:data-title="name"
|
||||
:aria-label="name"
|
||||
:href="`/icons/${props.name}`"
|
||||
>
|
||||
<KeepAlive>
|
||||
<component
|
||||
v-if="!hideIcon"
|
||||
:is="icon"
|
||||
class="lucide-icon"
|
||||
:class="{ customizable }"
|
||||
/>
|
||||
</KeepAlive>
|
||||
</button>
|
||||
<Tooltip :title="name">
|
||||
<a
|
||||
class="icon-button confetti-button vp-raw"
|
||||
@click="navigateToIcon"
|
||||
:class="{ active, animate }"
|
||||
:aria-label="name"
|
||||
:href="`/icons/${props.name}`"
|
||||
:data-confetti-text="confettiText"
|
||||
ref="ref"
|
||||
>
|
||||
<KeepAlive>
|
||||
<component
|
||||
v-if="!hideIcon"
|
||||
:is="icon"
|
||||
class="lucide-icon"
|
||||
:class="{
|
||||
customizable,
|
||||
}"
|
||||
/>
|
||||
</KeepAlive>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<style src="./confetti.css" />
|
||||
|
||||
<style scoped>
|
||||
.icon-button {
|
||||
display: inline-block;
|
||||
@@ -72,35 +101,13 @@ function navigateToIcon() {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.icon-button:hover:before {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, 48px) scale(1);
|
||||
.confetti-button:before,
|
||||
.confetti-button:after {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.icon-button:before {
|
||||
content: attr(data-title);
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
margin-left: 27px;
|
||||
transform: translate(-50%, 48px) scale(0.9);
|
||||
font-weight: 400;
|
||||
position: absolute;
|
||||
background: var(--vp-c-brand-dark);
|
||||
color: white;
|
||||
z-index: 10;
|
||||
white-space: nowrap;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--vp-shadow-1);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: cubic-bezier(0.19, 1, 0.22, 1) .2s;
|
||||
transition-property: opacity, transform;
|
||||
/* max-width: calc((32px * 2) + 56px); */
|
||||
overflow: hidden;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
.confetti-button:before {
|
||||
line-height: 80px;
|
||||
}
|
||||
|
||||
.icon-button:active {
|
||||
@@ -139,6 +146,7 @@ function navigateToIcon() {
|
||||
|
||||
.lucide-icon {
|
||||
margin: auto;
|
||||
pointer-events: none;
|
||||
}
|
||||
.lucide-icon.customizable {
|
||||
will-change: width, height, stroke-width, stroke;
|
||||
|
||||
@@ -6,6 +6,9 @@ import InputSearch from '../base/InputSearch.vue'
|
||||
import useSearchInput from '../../composables/useSearchInput'
|
||||
import StickyBar from './StickyBar.vue'
|
||||
import IconsCategory from './IconsCategory.vue'
|
||||
import { useFetch } from '@vueuse/core'
|
||||
import useFetchTags from '../../composables/useFetchTags'
|
||||
import useFetchCategories from '../../composables/useFetchCategories'
|
||||
|
||||
const props = defineProps<{
|
||||
icons: IconEntity[]
|
||||
@@ -22,7 +25,26 @@ function setActiveIconName(name: string) {
|
||||
activeIconName.value = name
|
||||
}
|
||||
|
||||
const searchResults = useSearch(searchQuery, props.icons, [
|
||||
const { execute: fetchTags, data: tags } = useFetchTags()
|
||||
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories()
|
||||
|
||||
const mappedIcons = computed(() => {
|
||||
if(tags.value == null) {
|
||||
return props.icons
|
||||
}
|
||||
return props.icons.map((icon) => {
|
||||
const iconTags = tags.value[icon.name]
|
||||
const iconCategories = categoriesMap.value?.[icon.name] ?? []
|
||||
|
||||
return {
|
||||
...icon,
|
||||
tags: iconTags,
|
||||
categories: iconCategories,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const searchResults = useSearch(searchQuery, mappedIcons, [
|
||||
{ name: 'name', weight: 2 },
|
||||
{ name: 'tags', weight: 1 },
|
||||
])
|
||||
@@ -37,7 +59,6 @@ const categories = computed(() => {
|
||||
return iconCategories?.includes(name)
|
||||
})
|
||||
|
||||
|
||||
const searchedCategoryIcons = isSearching
|
||||
? categoryIcons.filter(icon => searchResults.value.some((item) => item?.name === icon?.name))
|
||||
: categoryIcons;
|
||||
@@ -51,9 +72,14 @@ const categories = computed(() => {
|
||||
.filter(({ icons }) => icons.length)
|
||||
})
|
||||
|
||||
const activeIcon = computed(() =>
|
||||
props.icons?.find((icon) => icon.name === activeIconName.value)
|
||||
)
|
||||
function onFocusSearchInput() {
|
||||
if (tags.value == null) {
|
||||
fetchTags()
|
||||
}
|
||||
if (categoriesMap.value == null) {
|
||||
fetchCategories()
|
||||
}
|
||||
}
|
||||
|
||||
const NoResults = defineAsyncComponent(() =>
|
||||
import('./NoResults.vue')
|
||||
@@ -71,6 +97,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
v-model="searchQuery"
|
||||
class="input-wrapper"
|
||||
ref="searchInput"
|
||||
@focus="onFocusSearchInput"
|
||||
/>
|
||||
</StickyBar>
|
||||
<NoResults
|
||||
@@ -87,7 +114,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
/>
|
||||
<IconDetailOverlay
|
||||
v-if="activeIconName != null"
|
||||
:icon="activeIcon"
|
||||
:iconName="activeIconName"
|
||||
@close="setActiveIconName('')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -8,6 +8,8 @@ import useSearch from '../../composables/useSearch'
|
||||
import EndOfPage from '../base/EndOfPage.vue'
|
||||
import useSearchInput from '../../composables/useSearchInput'
|
||||
import StickyBar from './StickyBar.vue'
|
||||
import useFetchTags from '../../composables/useFetchTags'
|
||||
import useFetchCategories from '../../composables/useFetchCategories'
|
||||
|
||||
const props = defineProps<{
|
||||
icons: IconEntity[]
|
||||
@@ -22,7 +24,7 @@ const isSmallScreen = useMediaQuery('(min-width: 640px)');
|
||||
|
||||
const pageSize = computed(() => {
|
||||
if(isExtraLargeScreen.value) {
|
||||
return 16 * 16;
|
||||
return 16 * 20;
|
||||
}
|
||||
if(isLargeScreen.value) {
|
||||
return 16 * 12;
|
||||
@@ -38,8 +40,28 @@ const pageSize = computed(() => {
|
||||
return 10 * 5;
|
||||
})
|
||||
|
||||
const { execute: fetchTags, data: tags } = useFetchTags()
|
||||
const { execute: fetchCategories, data: categories } = useFetchCategories()
|
||||
|
||||
const mappedIcons = computed(() => {
|
||||
if(tags.value == null) {
|
||||
return props.icons
|
||||
}
|
||||
|
||||
return props.icons.map((icon) => {
|
||||
const iconTags = tags.value[icon.name]
|
||||
const iconCategories = categories.value?.[icon.name] ?? []
|
||||
|
||||
return {
|
||||
...icon,
|
||||
tags: iconTags,
|
||||
categories: iconCategories,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const { searchInput, searchQuery, searchQueryThrottled } = useSearchInput()
|
||||
const searchResults = useSearch(searchQueryThrottled, props.icons, [
|
||||
const searchResults = useSearch(searchQueryThrottled, mappedIcons, [
|
||||
{ name: 'name', weight: 3 },
|
||||
{ name: 'tags', weight: 2 },
|
||||
{ name: 'categories', weight: 1 },
|
||||
@@ -58,12 +80,19 @@ function setActiveIconName(name: string) {
|
||||
activeIconName.value = name
|
||||
}
|
||||
|
||||
const activeIcon = computed(() => props.icons.find((icon) => icon.name === activeIconName.value))
|
||||
|
||||
watch(searchQueryThrottled, (searchString) => {
|
||||
currentPage.value = 1
|
||||
})
|
||||
|
||||
function onFocusSearchInput() {
|
||||
if (tags.value == null) {
|
||||
fetchTags()
|
||||
}
|
||||
if (categories.value == null) {
|
||||
fetchCategories()
|
||||
}
|
||||
}
|
||||
|
||||
const NoResults = defineAsyncComponent(() =>
|
||||
import('./NoResults.vue')
|
||||
)
|
||||
@@ -81,6 +110,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
v-model="searchQuery"
|
||||
ref="searchInput"
|
||||
class="input-wrapper"
|
||||
@focus="onFocusSearchInput"
|
||||
/>
|
||||
</StickyBar>
|
||||
<NoResults
|
||||
@@ -97,7 +127,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
<EndOfPage @end-of-page="next" class="bottom-page"/>
|
||||
<IconDetailOverlay
|
||||
v-if="activeIconName != null"
|
||||
:icon="activeIcon"
|
||||
:iconName="activeIconName"
|
||||
@close="setActiveIconName('')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -32,8 +32,8 @@ useEventListener(document, 'mousemove', (mouseEvent) => {
|
||||
No icons found for '{{ searchQuery }}'
|
||||
</h2>
|
||||
<VPButton text="Clear your search and try again" theme="alt" @click="$emit('clear')"/>
|
||||
or
|
||||
<VPButton text="Check if someone has already requested this icon"
|
||||
<span class="text-divider">or</span>
|
||||
<VPButton text="Search on Github issues"
|
||||
theme="alt"
|
||||
:href="`https://github.com/lucide-icons/lucide/issues?q=is%3Aopen+${searchQuery}`"
|
||||
target="_blank"
|
||||
@@ -74,4 +74,10 @@ useEventListener(document, 'mousemove', (mouseEvent) => {
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-divider {
|
||||
margin: 12px 0;
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-neutral);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { shallowRef, type Ref, watch } from 'vue'
|
||||
import { shallowRef, type Ref, watch, computed } from 'vue'
|
||||
import { useCssVar, syncRef } from '@vueuse/core'
|
||||
import { useIconStyleContext } from '../../composables/useIconStyle'
|
||||
import { STYLE_DEFAULTS, useIconStyleContext } from '../../composables/useIconStyle'
|
||||
import RangeSlider from '../base/RangeSlider.vue'
|
||||
import InputField from '../base/InputField.vue'
|
||||
import ColorPicker from '../base/ColorPicker.vue'
|
||||
@@ -19,7 +19,7 @@ const colorCssVar = useCssVar(
|
||||
'--customize-color',
|
||||
props.rootEl?.value ?? documentRef.value,
|
||||
{
|
||||
initialValue: 'default'
|
||||
initialValue: `${STYLE_DEFAULTS.color}`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ const strokeWidthCssVar = useCssVar(
|
||||
'--customize-strokeWidth',
|
||||
props.rootEl?.value ?? documentRef.value,
|
||||
{
|
||||
initialValue: '2'
|
||||
initialValue: `${STYLE_DEFAULTS.strokeWidth}`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ const sizeCssVar = useCssVar(
|
||||
'--customize-size',
|
||||
props.rootEl?.value ?? documentRef.value,
|
||||
{
|
||||
initialValue: '24'
|
||||
initialValue: `${STYLE_DEFAULTS.size}`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -44,9 +44,9 @@ syncRef(strokeWidth, strokeWidthCssVar, { direction: 'ltr' })
|
||||
syncRef(size, sizeCssVar, { direction: 'ltr' })
|
||||
|
||||
function resetStyle () {
|
||||
color.value = 'currentColor'
|
||||
strokeWidth.value = 2
|
||||
size.value = 24
|
||||
color.value = STYLE_DEFAULTS.color
|
||||
strokeWidth.value = STYLE_DEFAULTS.strokeWidth
|
||||
size.value = STYLE_DEFAULTS.size
|
||||
}
|
||||
|
||||
watch(absoluteStrokeWidth, (enabled) => {
|
||||
@@ -54,10 +54,18 @@ watch(absoluteStrokeWidth, (enabled) => {
|
||||
|
||||
htmlEl.classList.toggle('absolute-stroke-width', enabled)
|
||||
})
|
||||
|
||||
const customizingActive = computed(() => {
|
||||
return color.value !== STYLE_DEFAULTS.color
|
||||
|| strokeWidth.value !== STYLE_DEFAULTS.strokeWidth
|
||||
|| size.value !== STYLE_DEFAULTS.size
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="customizer-card">
|
||||
<div class="customizer-card" :class="{ customized: customizingActive }">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">
|
||||
Customizer
|
||||
@@ -142,6 +150,12 @@ watch(absoluteStrokeWidth, (enabled) => {
|
||||
margin-bottom: 24px;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
border: 1px solid transparent;
|
||||
transition: border-color .4s ease-in-out;
|
||||
}
|
||||
|
||||
.customizer-card.customized {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
|
||||
@@ -36,15 +36,22 @@ const links = computed(() => [
|
||||
<template>
|
||||
<footer v-if="theme.footer" class="VPFooter" :class="{ 'has-sidebar': hasSidebar }">
|
||||
<div class="container">
|
||||
<p v-if="theme.footer.message" class="message" v-html="theme.footer.message"></p>
|
||||
<p v-if="theme.footer.copyright" class="copyright" v-html="theme.footer.copyright"></p>
|
||||
<div class="sponsors">
|
||||
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss" rel="noreferrer noopener">
|
||||
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
|
||||
</a>
|
||||
<a href="https://www.digitalocean.com/?refcode=b0877a2caebd&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge" rel="noreferrer noopener">
|
||||
<img src="/digitalocean.svg" alt="Digital Ocean" width="200" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<VPLink v-for="link in links" :href="link.href" :key="link.text" :rel="link.href.startsWith('http') ? 'noreferrer noopener': undefined">
|
||||
{{ link.text }}
|
||||
</VPLink>
|
||||
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss" rel="noreferrer noopener">
|
||||
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<p v-if="theme.footer.message" class="message" v-html="theme.footer.message"></p>
|
||||
<p v-if="theme.footer.copyright" class="copyright" v-html="theme.footer.copyright"></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -67,7 +74,7 @@ const links = computed(() => [
|
||||
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
max-width: var(--vp-layout-max-width);
|
||||
max-width: calc(var(--vp-layout-max-width) - 64px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -85,7 +92,7 @@ const links = computed(() => [
|
||||
.message { order: 2; }
|
||||
.copyright { order: 1; }
|
||||
|
||||
.links {
|
||||
.links, .sponsors {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
align-items: center;
|
||||
@@ -102,7 +109,7 @@ const links = computed(() => [
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.links {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ref } from "vue";
|
||||
|
||||
export default function useConfetti() {
|
||||
const animate = ref(false)
|
||||
const confettiText = ref('confetti!')
|
||||
|
||||
function confetti() {
|
||||
animate.value = true;
|
||||
@@ -13,6 +14,7 @@ export default function useConfetti() {
|
||||
|
||||
return {
|
||||
animate,
|
||||
confetti
|
||||
confetti,
|
||||
confettiText
|
||||
}
|
||||
}
|
||||
|
||||
12
docs/.vitepress/theme/composables/useFetchCategories.ts
Normal file
12
docs/.vitepress/theme/composables/useFetchCategories.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useFetch } from "@vueuse/core"
|
||||
|
||||
const useFetchCategories = () => useFetch<Record<string, string[]>>(
|
||||
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/categories`,
|
||||
{
|
||||
immediate:
|
||||
typeof window !== 'undefined'
|
||||
&& new URLSearchParams(window.location.search).has('search'),
|
||||
}
|
||||
).json()
|
||||
|
||||
export default useFetchCategories
|
||||
12
docs/.vitepress/theme/composables/useFetchTags.ts
Normal file
12
docs/.vitepress/theme/composables/useFetchTags.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useFetch } from "@vueuse/core"
|
||||
|
||||
const useFetchTags = () => useFetch<Record<string, string[]>>(
|
||||
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/tags`,
|
||||
{
|
||||
immediate:
|
||||
typeof window !== 'undefined'
|
||||
&& new URLSearchParams(window.location.search).has('search'),
|
||||
}
|
||||
).json()
|
||||
|
||||
export default useFetchTags
|
||||
@@ -10,8 +10,16 @@ interface IconSizeContext {
|
||||
size: Ref<number>
|
||||
strokeWidth: Ref<number>
|
||||
color: Ref<string>
|
||||
absoluteStrokeWidth: Ref<boolean>
|
||||
}
|
||||
|
||||
export const STYLE_DEFAULTS = {
|
||||
size: 24,
|
||||
strokeWidth: 2,
|
||||
color: 'currentColor',
|
||||
absoluteStrokeWidth: false,
|
||||
};
|
||||
|
||||
export const iconStyleContext = {
|
||||
size: ref(24),
|
||||
strokeWidth: ref(2),
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import Fuse from 'fuse.js';
|
||||
import { shallowRef, computed, Ref } from 'vue';
|
||||
|
||||
const useSearch = <T>(query: Ref<string>, collection: T[], keys: Fuse.FuseOptionKey<T>[] = []) => {
|
||||
const useSearch = <T>(query: Ref<string>, collection: Ref<T[]>, keys: Fuse.FuseOptionKey<T>[] = []) => {
|
||||
const index = shallowRef(
|
||||
new Fuse(collection, {
|
||||
new Fuse(collection.value, {
|
||||
threshold: 0.2,
|
||||
keys,
|
||||
})
|
||||
)
|
||||
|
||||
const results = computed(() => {
|
||||
index.value.setCollection(collection.value);
|
||||
|
||||
if (query.value) {
|
||||
return index.value.search(query.value).map((result) => result.item);
|
||||
}
|
||||
|
||||
return collection;
|
||||
return collection.value;
|
||||
});
|
||||
|
||||
return results;
|
||||
|
||||
@@ -11,12 +11,16 @@ const useSearchInput = () => {
|
||||
|| ''
|
||||
)
|
||||
)
|
||||
const searchQueryThrottled = refThrottled(searchQuery, 200)
|
||||
const searchQueryThrottled = refThrottled(searchQuery, 400)
|
||||
|
||||
watch(searchQueryThrottled, (searchString) => {
|
||||
const newUrl = new URL(window.location.href);
|
||||
|
||||
newUrl.searchParams.set('search', searchString);
|
||||
if(searchString === '') {
|
||||
newUrl.searchParams.delete('search');
|
||||
} else {
|
||||
newUrl.searchParams.set('search', searchString);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
window.history.replaceState({}, '', newUrl)
|
||||
|
||||
34
docs/.vitepress/theme/sandpackTheme.json
Normal file
34
docs/.vitepress/theme/sandpackTheme.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"colors": {
|
||||
"surface1": "var(--vp-code-block-bg)",
|
||||
"surface2": "var(--vp-code-block-bg)",
|
||||
"surface3": "var(--vp-code-line-highlight-color)",
|
||||
"clickable": "var(--vp-c-text-2)",
|
||||
"base": "#323232",
|
||||
"disabled": "#C5C5C5",
|
||||
"hover": "var(--vp-c-brand)",
|
||||
"accent": "var(--vp-c-brand)",
|
||||
"error": "var(--vp-c-red)",
|
||||
"errorSurface": "#ffeceb"
|
||||
},
|
||||
"syntax": {
|
||||
"plain": "var(--vp-code-editor-plain)",
|
||||
"comment": {
|
||||
"color": "var(--vp-code-editor-comment)",
|
||||
"fontStyle": "italic"
|
||||
},
|
||||
"keyword": "var(--vp-code-editor-keyword)",
|
||||
"tag": "var(--vp-code-editor-tag)",
|
||||
"punctuation": "var(--vp-code-editor-punctuation)",
|
||||
"definition": "var(--vp-code-editor-definition)",
|
||||
"property": "var(--vp-code-editor-property)",
|
||||
"static": "var(--vp-code-editor-static)",
|
||||
"string": "var(--vp-code-editor-string)"
|
||||
},
|
||||
"font": {
|
||||
"body": "var(--vp-font-family-base)",
|
||||
"mono": "var(--vp-font-family-mono)",
|
||||
"size": "var(--vp-code-font-size)",
|
||||
"lineHeight": "var(--vp-code-line-height)"
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,39 @@
|
||||
--vp-c-brand-dark: #DC5A5A;
|
||||
--vp-c-brand-darker: #C45050;
|
||||
|
||||
--vp-c-brand-1: #F67373;
|
||||
--vp-c-brand-2: #FF7070;
|
||||
--vp-c-brand-3: #F56565;
|
||||
--vp-c-brand-4: #DC5A5A;
|
||||
--vp-c-brand-5: #C45050;
|
||||
|
||||
--vp-c-bg-alt-up: #fff;
|
||||
--vp-c-bg-alt-down: #fff;
|
||||
|
||||
--vp-code-editor-plain: #24292E;
|
||||
--vp-code-editor-comment: #6A737D;
|
||||
--vp-code-editor-keyword: #D73A49;
|
||||
--vp-code-editor-tag: #22863A;
|
||||
--vp-code-editor-punctuation: #24292E;
|
||||
--vp-code-editor-definition: #6F42C1;
|
||||
--vp-code-editor-property: #005CC5;
|
||||
--vp-code-editor-static: #F78C6C;
|
||||
--vp-code-editor-string: #032F62;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--vp-c-bg-alt-up: #1B1B1D;
|
||||
--vp-c-bg-alt-down: #0F0F10;
|
||||
|
||||
--vp-code-editor-plain: #E1E4E8;
|
||||
--vp-code-editor-comment: #6A737D;
|
||||
--vp-code-editor-keyword: #F97583;
|
||||
--vp-code-editor-tag: #85E89D;
|
||||
--vp-code-editor-punctuation: #9ECBFF;
|
||||
--vp-code-editor-definition: #B392F0;
|
||||
--vp-code-editor-property: #79B8FF;
|
||||
--vp-code-editor-static: #F78C6C;
|
||||
--vp-code-editor-string: #9ECBFF;
|
||||
}
|
||||
|
||||
.VPNavBarTitle .logo {
|
||||
@@ -126,3 +152,52 @@
|
||||
html:has(* .outline-link:target) {
|
||||
scroll-behavior: smooth;
|
||||
} */
|
||||
|
||||
.sp-wrapper .sp-layout {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-tabs-scrollable-container {
|
||||
border-radius: 8px 8px 0 0;
|
||||
position: relative;
|
||||
|
||||
box-shadow: inset 0 -1px var(--vp-code-tab-divider);
|
||||
margin-bottom: 0px;
|
||||
margin-top: -1px;
|
||||
height: 48px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-preview-container {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-tabs .sp-tab-button {
|
||||
padding: 0 12px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
/* box-sizing: content-box; */
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-tabs .sp-tab-button:after {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
left: 8px;
|
||||
bottom: 0px;
|
||||
z-index: 1;
|
||||
height: 1px;
|
||||
content: '';
|
||||
background-color: transparent;
|
||||
transition: background-color 0.25s;
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-tabs .sp-tab-button[data-active="true"] {
|
||||
color: var(--vp-code-tab-active-text-color);
|
||||
}
|
||||
|
||||
.sp-wrapper .sp-tabs .sp-tab-button[data-active="true"]:after {
|
||||
background-color: var(--vp-code-tab-active-bar-color);
|
||||
}
|
||||
|
||||
6
docs/.vitepress/theme/utils/downloadData.ts
Normal file
6
docs/.vitepress/theme/utils/downloadData.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export default function downloadData(filename:string, data:string) {
|
||||
const link = document.createElement('a');
|
||||
link.download = filename;
|
||||
link.href = data
|
||||
link.click();
|
||||
}
|
||||
34
docs/.vitepress/theme/utils/getSVGIcon.ts
Normal file
34
docs/.vitepress/theme/utils/getSVGIcon.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
const allowedAttrs = [
|
||||
'xmlns',
|
||||
'width',
|
||||
'height',
|
||||
'viewBox',
|
||||
'fill',
|
||||
'stroke',
|
||||
'stroke-width',
|
||||
'stroke-linecap',
|
||||
'stroke-linejoin',
|
||||
'class',
|
||||
]
|
||||
|
||||
export default function getSVGIcon(element?: HTMLElement, attrs?: Record<string, string>) {
|
||||
const svg = element ?? document.querySelector('#previewer svg')
|
||||
if (!svg) return
|
||||
|
||||
const clonedSvg = svg.cloneNode(true) as SVGElement
|
||||
|
||||
// Filter out attributes that are not allowed in SVGs
|
||||
for (const attr of Array.from(clonedSvg.attributes)) {
|
||||
if (!allowedAttrs.includes(attr.name)) {
|
||||
clonedSvg.removeAttribute(attr.name)
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(attrs ?? {})) {
|
||||
clonedSvg.setAttribute(key, value)
|
||||
}
|
||||
|
||||
const svgString = new XMLSerializer().serializeToString(clonedSvg)
|
||||
|
||||
return svgString
|
||||
}
|
||||
14
docs/.vitepress/vue-shim.d.ts
vendored
14
docs/.vitepress/vue-shim.d.ts
vendored
@@ -1,10 +1,18 @@
|
||||
declare module "*.vue" {
|
||||
import Vue from "vue";
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue';
|
||||
export default Vue;
|
||||
}
|
||||
|
||||
declare module "*.data.ts" {
|
||||
declare module '*.data.ts' {
|
||||
const data: any;
|
||||
|
||||
export { data };
|
||||
}
|
||||
|
||||
declare module '*.wasm' {}
|
||||
|
||||
declare const resvg_wasm: RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
declare module 'node:module' {
|
||||
function createRequire(filename: string): NodeRequire;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
The Lucide docs website is built with Vitepress: https://vitepress.dev/
|
||||
This is Markdown-based documentation powered by Vue.
|
||||
|
||||
This is why this file is in txt format.
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
4
docs/guide/advanced/accessibility.md
Normal file
4
docs/guide/advanced/accessibility.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Accessibility
|
||||
|
||||
<!-- Description how you should use svg icons keeping web accessible -->
|
||||
<!-- See @JanTrichter comment about some information to write this: https://github.com/lucide-icons/lucide/pull/1521#discussion_r1332141390 -->
|
||||
13
docs/guide/advanced/filled-icons.md
Normal file
13
docs/guide/advanced/filled-icons.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Filled Icons
|
||||
|
||||
Fills are officially not supported.
|
||||
However, all SVG properties are available on all icons.
|
||||
Fill can still be used and will work fine on certain icons.
|
||||
|
||||
Example with stars:
|
||||
|
||||
<!-- Code Example with stars -->
|
||||
|
||||
## Will Lucide have fills in the future?
|
||||
|
||||
This feature is requested several times and discussion is happening at: [#458](https://github.com/lucide-icons/lucide/discussions/458).
|
||||
52
docs/guide/basics/color.md
Normal file
52
docs/guide/basics/color.md
Normal file
@@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { Sandpack } from 'sandpack-vue3'
|
||||
import sandpackTheme from '../../.vitepress/theme/sandpackTheme.json'
|
||||
import buttonExampleFiles from './examples/button-example/files.ts'
|
||||
import iconColorExampleFiles from './examples/color-icon/files.ts'
|
||||
</script>
|
||||
|
||||
# Color
|
||||
|
||||
By default, all icons have the color value: `currentColor`. This keyword uses the element's computed text `color` value to represent the icon color.
|
||||
|
||||
Read more about [ `currentColor` on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#currentcolor_keyword).
|
||||
|
||||
## Adjust the color using the `color` prop
|
||||
|
||||
The color can be adjusted by passing the color prop to the element.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="iconColorExampleFiles"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 295,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
|
||||
## Using parent elements text color value
|
||||
|
||||
Because the color of lucide icons uses `currentColor`, the color of the icon depends on the computed `color` of the element, or it inherits it from its parent.
|
||||
|
||||
For example, if a parent element's color value is `#fff` and one of the children is a lucide icon, the color of the icon will be rendered as `#fff`. This is browser native behavior.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="buttonExampleFiles"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 320,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
14
docs/guide/basics/examples/absolute-stroke-width-icon/App.js
Normal file
14
docs/guide/basics/examples/absolute-stroke-width-icon/App.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { RollerCoaster } from "lucide-react";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<RollerCoaster
|
||||
size={96}
|
||||
absoluteStrokeWidth={true}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,15 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
5
docs/guide/basics/examples/button-example/App.js
Normal file
5
docs/guide/basics/examples/button-example/App.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import Button from "./Button";
|
||||
|
||||
export default function App() {
|
||||
return <Button />;
|
||||
}
|
||||
12
docs/guide/basics/examples/button-example/Button.jsx
Normal file
12
docs/guide/basics/examples/button-example/Button.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { ThumbsUp } from "lucide-react";
|
||||
|
||||
function LikeButton() {
|
||||
return (
|
||||
<button style={{ color: "#fff" }}>
|
||||
<ThumbsUp />
|
||||
Like
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default LikeButton;
|
||||
21
docs/guide/basics/examples/button-example/files.ts
Normal file
21
docs/guide/basics/examples/button-example/files.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import App from './App.js?raw'
|
||||
import Button from './Button.jsx?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
hidden: true
|
||||
},
|
||||
'Button.jsx': {
|
||||
code: Button,
|
||||
active: true,
|
||||
readOnly: false,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
11
docs/guide/basics/examples/color-icon/App.js
Normal file
11
docs/guide/basics/examples/color-icon/App.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Smile } from "lucide-react";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<Smile color="#3e9392" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
15
docs/guide/basics/examples/color-icon/files.ts
Normal file
15
docs/guide/basics/examples/color-icon/files.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
12
docs/guide/basics/examples/size-icon-css-example/App.js
Normal file
12
docs/guide/basics/examples/size-icon-css-example/App.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Beer } from "lucide-react";
|
||||
import "./icon.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<Beer className="my-beer-icon" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
21
docs/guide/basics/examples/size-icon-css-example/files.ts
Normal file
21
docs/guide/basics/examples/size-icon-css-example/files.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
import IconCss from './icon.css?raw'
|
||||
|
||||
const files = {
|
||||
'icon.css': {
|
||||
code: IconCss,
|
||||
readOnly: false,
|
||||
active: true,
|
||||
},
|
||||
'App.js': {
|
||||
code: App,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
export default files
|
||||
@@ -0,0 +1,5 @@
|
||||
.my-beer-icon {
|
||||
/* Change this! */
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
11
docs/guide/basics/examples/size-icon-example/App.js
Normal file
11
docs/guide/basics/examples/size-icon-example/App.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Landmark } from "lucide-react";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<Landmark size={64} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
15
docs/guide/basics/examples/size-icon-example/files.ts
Normal file
15
docs/guide/basics/examples/size-icon-example/files.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
13
docs/guide/basics/examples/size-icon-font-example/App.js
Normal file
13
docs/guide/basics/examples/size-icon-font-example/App.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Star } from "lucide-react";
|
||||
import "./icon.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="text-wrapper">
|
||||
<Star class="my-icon" />
|
||||
<div>Yes</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
21
docs/guide/basics/examples/size-icon-font-example/files.ts
Normal file
21
docs/guide/basics/examples/size-icon-font-example/files.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
import IconCss from './icon.css?raw'
|
||||
|
||||
const files = {
|
||||
'icon.css': {
|
||||
code: IconCss,
|
||||
readOnly: false,
|
||||
active: true,
|
||||
},
|
||||
'App.js': {
|
||||
code: App,
|
||||
},
|
||||
'styles.css': {
|
||||
code: styles,
|
||||
hidden: true
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
export default files
|
||||
15
docs/guide/basics/examples/size-icon-font-example/icon.css
Normal file
15
docs/guide/basics/examples/size-icon-font-example/icon.css
Normal file
@@ -0,0 +1,15 @@
|
||||
.my-icon {
|
||||
/* Icon size will relative to font-size of .text-wrapper */
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.text-wrapper {
|
||||
/* Change this! */
|
||||
font-size: 96px;
|
||||
|
||||
/* layout stuff */
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
items-align: center;
|
||||
}
|
||||
11
docs/guide/basics/examples/size-icon-tailwind-example/App.js
Normal file
11
docs/guide/basics/examples/size-icon-tailwind-example/App.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { PartyPopper } from "lucide-react";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<PartyPopper className="w-24 h-24" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,15 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
11
docs/guide/basics/examples/stroke-width-icon/App.js
Normal file
11
docs/guide/basics/examples/stroke-width-icon/App.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { FolderLock } from "lucide-react";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<FolderLock strokeWidth={1} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
15
docs/guide/basics/examples/stroke-width-icon/files.ts
Normal file
15
docs/guide/basics/examples/stroke-width-icon/files.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../styles.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true,
|
||||
},
|
||||
'styles.css': {
|
||||
code:styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
50
docs/guide/basics/examples/styles.css
Normal file
50
docs/guide/basics/examples/styles.css
Normal file
@@ -0,0 +1,50 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
-webkit-font-smoothing: auto;
|
||||
-moz-font-smoothing: auto;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-smoothing: auto;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-smooth: always;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none;
|
||||
background: #202127;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
padding: 10px 20px;
|
||||
line-height: 24px;
|
||||
gap: 8px;
|
||||
border-radius: 24px;
|
||||
outline: none;
|
||||
border: none;
|
||||
background: #111;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #F56565;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 32px;
|
||||
}
|
||||
87
docs/guide/basics/sizing.md
Normal file
87
docs/guide/basics/sizing.md
Normal file
@@ -0,0 +1,87 @@
|
||||
<script setup>
|
||||
import { Sandpack } from 'sandpack-vue3'
|
||||
import sandpackTheme from '../../.vitepress/theme/sandpackTheme.json'
|
||||
import sizeIconExample from './examples/size-icon-example/files.ts'
|
||||
import sizeIconCssExample from './examples/size-icon-css-example/files.ts'
|
||||
import sizeIconFontExample from './examples/size-icon-font-example/files.ts'
|
||||
import sizeIconTailwind from './examples/size-icon-tailwind-example/files.ts'
|
||||
</script>
|
||||
|
||||
# Sizing
|
||||
|
||||
By default, the size of all icons is `24px` by `24px`. The size is adjustable using the `size` prop and CSS.
|
||||
|
||||
## Adjusting the icon size using the `size` prop
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="sizeIconExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
|
||||
## Adjusting the icon size via CSS
|
||||
|
||||
The CSS properties `width` and `height` can be used to adjust the icon size.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="sizeIconCssExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
}"
|
||||
/>
|
||||
|
||||
### Dynamically change the icon size based on the font size
|
||||
|
||||
It is possible to resize icons based on font size. This can be achieved using the `em` unit. See this [MDN article](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size#ems) for more information on the `em` unit.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="sizeIconFontExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
}"
|
||||
/>
|
||||
|
||||
### Resizing with Tailwind
|
||||
|
||||
`h-*` and `w-*` utilities can be used to adjust the size of the icon.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="sizeIconTailwind"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest",
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
externalResources: ['https://cdn.tailwindcss.com'],
|
||||
editorHeight: 300,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
|
||||
<!-- Code Example -->
|
||||
60
docs/guide/basics/stroke-width.md
Normal file
60
docs/guide/basics/stroke-width.md
Normal file
@@ -0,0 +1,60 @@
|
||||
<script setup>
|
||||
import { Sandpack } from 'sandpack-vue3'
|
||||
import sandpackTheme from '../../.vitepress/theme/sandpackTheme.json'
|
||||
import strokeWidth from './examples/stroke-width-icon/files.ts'
|
||||
import absoluteStrokeWidth from './examples/absolute-stroke-width-icon/files.ts'
|
||||
</script>
|
||||
|
||||
# Stroke width
|
||||
|
||||
All icons are designed with SVG elements using strokes.
|
||||
These have a default stroke width of `2px`.
|
||||
|
||||
The `strokeWidth` can be adjusted to create a different look of the icons.
|
||||
|
||||
## Adjusting stroke width with `strokeWidth` prop
|
||||
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="strokeWidth"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
|
||||
## Absolute stroke width
|
||||
|
||||
When adjusting the `size` prop the size of the stroke width will be relative to the size of the icon, this is the default SVG behavior. The `absoluteStrokeWidth` prop is introduced to adjust this behavior to make the stroke width constant no matter the size of the icon.
|
||||
|
||||
This means that when `absoluteStrokeWidth` is enabled and the `size` of the icons is set to `48px` the `strokeWidth` will still be `2px` on the screen.
|
||||
|
||||
Note `2px` is the default stroke width for a Lucide icon, this can be adjusted to all sizes.
|
||||
|
||||

|
||||
|
||||
### Adjusting stroke width with `absoluteStrokeWidth` prop
|
||||
|
||||
Setting `absoluteStrokeWidth` to `true` will make the stroke width absolute.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="absoluteStrokeWidth"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 320,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
@@ -2,60 +2,113 @@
|
||||
title: Icon Design Guide
|
||||
---
|
||||
|
||||
# Icon Design Principles
|
||||
## Icon Design Principles
|
||||
|
||||
Here are rules that should be followed to keep quality and consistency when making icons for Lucide.
|
||||
|
||||
## Summary of the rules we have
|
||||
|
||||
1. Icons must be designed on a **24 by 24 pixels** canvas.
|
||||
2. Icons must have at least **1 pixel padding** within the canvas.
|
||||
3. Icons must have a **stroke width of 2 pixels**.
|
||||
4. Icons must use **round joins**.
|
||||
5. Icons must use **round caps**.
|
||||
6. Icons must use **centered strokes**.
|
||||
7. Shapes (such as rectangles) in icons must have **border radius of 2 pixels**.
|
||||
8. Distinct elements must have **2 pixels of spacing between each other**.
|
||||
|
||||
## The Rules Visualized
|
||||
|
||||
### 1. Icons must be designed on a 24 by 24 pixels canvas.
|
||||
### 1. Icons must be designed on a **24 by 24 pixels** canvas.
|
||||
|
||||

|
||||
|
||||
### 2. Icons must have at least 1 pixel padding within the canvas.
|
||||
### 2. Icons must have at least **1 pixel padding** within the canvas.
|
||||
|
||||

|
||||
|
||||
### 3. Icons must have a stroke width of 2 pixels.
|
||||
### 3. Icons must have a **stroke width of 2 pixels**.
|
||||
|
||||

|
||||
|
||||
### 4. Icons must use round joins.
|
||||
### 4. Icons must use **round joins**.
|
||||
|
||||

|
||||
|
||||
### 5. Icons must use round caps.
|
||||
### 5. Icons must use **round caps**.
|
||||
|
||||

|
||||
|
||||
### 6. Icons must use centered strokes.
|
||||
### 6. Icons must use **centered strokes**.
|
||||
|
||||

|
||||
|
||||
### 7. Shapes (such as squares) in icons must have border radius of 2 pixels.
|
||||
### 7. Shapes (such as rectangles) must have a **border radius of**
|
||||
|
||||
#### A. **2 pixels** if they are at least 8 pixels in size
|
||||
|
||||

|
||||
|
||||
### 8. Distinct elements must have 2 pixels of spacing between each other.
|
||||
#### B. **1 pixel** if they are smaller than 8 pixels in size
|
||||
|
||||

|
||||
|
||||
### 8. Distinct elements must have **2 pixels of spacing between each other**
|
||||
|
||||

|
||||
|
||||
### 9. Icons should have a similar optical volume to `circle` and `square`.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Tip:** place your icon next to circle or square and blur them both; your icon should not feel much darker than the base shape.
|
||||
|
||||
### 10. Icons should be visually centered by their center of gravity.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Tip:** place your icon both above/below and next to the square or circle icon and check if it feels off center. Symmetrical icons should always be aligned to the center.
|
||||
|
||||
### 11. Icons should have similar visual density and level of detail.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Tip:** try to make abstractions to dense elements. Blur your icon, and when blurred it should not feel overly dark.
|
||||
|
||||
### 12. Continuous curves should join smoothly.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Tip:** make sure to use arcs or quadratic curves, when using cubic curves control points should have mirrored angles for smooth curves.
|
||||
|
||||
### 13. Icons should aim to be pixel perfect so that they will be sharp on low DPI displays.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Tip:** whenever possible align elements and arc centers to the grid.
|
||||
|
||||
## Naming conventions
|
||||
|
||||
1. Icon names use lower kebab case.\
|
||||
For example: `arrow-up` instead of `Arrow Up`.
|
||||
|
||||
2. Icon names use International English names, as opposed to local variants.\
|
||||
For example: `color` instead of `colour`.
|
||||
|
||||
3. Icons should be named for what they depict rather than their use case or what they represent.\
|
||||
For example: `floppy-disk` instead of `save` and `circle-slash` rather than `ban`.
|
||||
|
||||
4. Icons that are part of a group are named `<group>-<variant>`.\
|
||||
For example: `badge-plus` is based on `badge`.
|
||||
|
||||
5. Icon names for alternate icons should represent what makes the alternate unique instead of being numbered.\
|
||||
For example: `send-horizontal` instead of `send-2`.
|
||||
|
||||
6. Names containing numerals are not allowed, unless the number itself is represented in the icon.\
|
||||
For example: `arrow-down-0-to-1` contains both numerals.
|
||||
|
||||
## Code Conventions
|
||||
|
||||
Before an icon is added to the library, we like to have readable and optimized svg code.
|
||||
|
||||
Never use [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use). While it may sometimes seem like a good way to optimize file size, there's no way to ensure that the referenced element IDs will be unique once the SVGs are embedded in HTML documents.
|
||||
Before an icon is added to the library, we like to have readable and optimized SVG code.
|
||||
|
||||
### Global Attributes
|
||||
|
||||
@@ -79,11 +132,26 @@ For each icon these attributes are applied, corresponding to the above rules.
|
||||
|
||||
### Minify paths
|
||||
|
||||
Code of paths can get really big.
|
||||
To reduce file size we like to minify the code.
|
||||
We recommend to use the [SVGOMG](https://jakearchibald.github.io/svgomg/) to minify paths.
|
||||
The code of paths can sometimes get quite large. To reduce file size we like to minify the code.
|
||||
We recommend to use the [SVGOMG](https://jakearchibald.github.io/svgomg/) to minify paths to 2 points of precision.
|
||||
|
||||
### JSON metadata descriptor
|
||||
### Allowed elements
|
||||
|
||||
SVG files may only contain simple path and shape elements, which may not have any attributes other than sizing and spacing.\
|
||||
In practice only the following elements and attributes are allowed:
|
||||
* `<path d>`
|
||||
* `<line x1 x2>`
|
||||
* `<polygon points>`
|
||||
* `<polyline points>`
|
||||
* `<circle cx cy r>`
|
||||
* `<ellipse cx cy rx ry>`
|
||||
* `<rect x y width height rx>`
|
||||
|
||||
This also means that no transforms, filters, fills or explicit strokes are allowed.
|
||||
|
||||
Never use [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use). While it may sometimes seem like a good way to optimize file size, there's no way to ensure that the referenced element IDs will be unique once the SVGs are embedded in HTML documents.
|
||||
|
||||
## JSON metadata descriptor
|
||||
|
||||
Each icon added must also come with a matching JSON file listing tags and categories for the icon.
|
||||
Please use the following template:
|
||||
@@ -91,6 +159,10 @@ Please use the following template:
|
||||
```json
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"github-username",
|
||||
"another-github-username"
|
||||
],
|
||||
"tags": [
|
||||
"foo",
|
||||
"bar"
|
||||
|
||||
1
docs/guide/how-to-use-icons.md
Normal file
1
docs/guide/how-to-use-icons.md
Normal file
@@ -0,0 +1 @@
|
||||
# How to use icons
|
||||
@@ -28,7 +28,7 @@ For more details, see the [documentation](packages/lucide.md).
|
||||
|
||||
## React
|
||||
|
||||
Implementation of the lucide icon library for react applications.
|
||||
Implementation of the lucide icon library for React applications.
|
||||
|
||||
::: code-group
|
||||
|
||||
@@ -47,84 +47,138 @@ npm install lucide-react
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-react.md).
|
||||
For React Native use the `lucide-react-native` package.
|
||||
|
||||
## Vue 2
|
||||
## Vue
|
||||
|
||||
Implementation of the lucide icon library for vue applications.
|
||||
Implementation of the lucide icon library for Vue applications.
|
||||
|
||||
```bash
|
||||
yarn add lucide-vue
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-vue-next
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
npm install lucide-vue
|
||||
```
|
||||
|
||||
For more details, see the [documentation](packages/lucide-vue.md).
|
||||
|
||||
## Vue 3
|
||||
|
||||
Implementation of the lucide icon library for vue applications.
|
||||
|
||||
```bash
|
||||
```sh [yarn]
|
||||
yarn add lucide-vue-next
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-vue-next
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-vue-next.md).
|
||||
For Vue 2 use the `lucide-vue` package.
|
||||
|
||||
## Svelte
|
||||
|
||||
Implementation of the lucide icon library for vue applications.
|
||||
Implementation of the lucide icon library for Svelte applications.
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-svelte
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-svelte
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-svelte
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-svelte.md).
|
||||
|
||||
## Solid
|
||||
|
||||
Implementation of the lucide icon library for Solid applications.
|
||||
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-solid
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-solid
|
||||
```
|
||||
|
||||
```sh [npm]
|
||||
npm install lucide-solid
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-solid.md).
|
||||
|
||||
## Angular
|
||||
|
||||
```bash
|
||||
Implementation of the lucide icon library for Angular applications.
|
||||
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-angular
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-angular
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-angular
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-angular.md).
|
||||
|
||||
## Preact
|
||||
|
||||
Implementation of the lucide icon library for preact applications.
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-preact
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-preact
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-preact
|
||||
```
|
||||
|
||||
For more details, see the [documentation](packages/lucide-preact.md).
|
||||
:::
|
||||
|
||||
## Static usage
|
||||
|
||||
Implementation of the lucide icon library for multiple usages that like to use: SVG files icons, SVG Sprite, Icon Fonts and static SVG strings export in Common JS modules (for NodeJS).
|
||||
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-static
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-static
|
||||
```
|
||||
|
||||
```sh [npm]
|
||||
npm install lucide-static
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For more details, see the [documentation](packages/lucide-static.md).
|
||||
|
||||
## Figma
|
||||
|
||||
@@ -134,16 +188,6 @@ Visit [Figma community page](https://www.figma.com/community/plugin/939567362549
|
||||
|
||||

|
||||
|
||||
## Laravel
|
||||
|
||||
Implementation of Lucide icon's using `blade-icons` for Laravel based projects.
|
||||
|
||||
```bash
|
||||
composer require mallardduck/blade-lucide-icons
|
||||
```
|
||||
|
||||
For more details, see the [documentation](https://github.com/mallardduck/blade-lucide-icons/blob/main/README.md).
|
||||
|
||||
## Flutter
|
||||
|
||||
Implementation of Lucide icon library for Flutter applications.
|
||||
|
||||
@@ -4,16 +4,22 @@ Implementation of the lucide icon library for Angular applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-angular
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-angular
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
```sh [npm]
|
||||
npm install lucide-angular
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## How to use
|
||||
|
||||
### Step 1: Import `LucideAngularModule`
|
||||
@@ -98,7 +104,9 @@ To add custom icons, you will first need to convert them to an [svgson format](h
|
||||
|
||||
## Loading all icons
|
||||
|
||||
> :warning: You may also opt to import all icons if necessary using the following format but be aware that this will significantly increase your application build size.
|
||||
::: danger
|
||||
You may also opt to import all icons if necessary using the following format but be aware that this will significantly increase your application build size.
|
||||
:::
|
||||
|
||||
```js
|
||||
import { icons } from 'lucide-angular';
|
||||
|
||||
@@ -8,28 +8,34 @@ Implementation of the lucide icon library for preact applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-preact
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-preact
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-preact
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## How to use
|
||||
|
||||
It's build with ESmodules so it's completely tree-shakable.
|
||||
Each icon can be imported as a preact component.
|
||||
Lucide is built with ES Modules, so it's completely tree-shakable.
|
||||
|
||||
Each icon can be imported as a Preact component, which renders an inline SVG element. This way, only the icons that are imported into your project are included in the final bundle. The rest of the icons are tree-shaken away.
|
||||
|
||||
### Example
|
||||
|
||||
You can pass additional props to adjust the icon.
|
||||
Additional props can be passed to adjust the icon:
|
||||
|
||||
```js
|
||||
```jsx
|
||||
import { Camera } from 'lucide-preact';
|
||||
// Returns PreactComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
@@ -39,7 +45,7 @@ const App = () => {
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Props
|
||||
## Props
|
||||
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
@@ -48,29 +54,31 @@ export default App;
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props / svg attributes
|
||||
### Applying props
|
||||
|
||||
You can also pass custom props that will be added in the as attributes. With that you can modify the icons look by passing svg attributes.
|
||||
To customize the appearance of an icon, you can pass custom properties as props directly to the component. The component accepts all SVG attributes as props, which allows flexible styling of the SVG elements. See the list of SVG Presentation Attributes on [MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation).
|
||||
|
||||
```js
|
||||
```jsx
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera fill="red" stroke-linejoin="bevel" />;
|
||||
};
|
||||
```
|
||||
|
||||
> svg attributes in preact aren't transformed, so if want to change e.g. the `stroke-linejoin` you need to pass it in kebabcase, the way svg spec is written so. See this topic in the [preact documentation](https://preactjs.com/guide/v10/differences-to-react/#svg-inside-jsx).
|
||||
> SVG attributes in Preact aren't transformed, so if you want to change for example the `stroke-linejoin` you need to pass it in kebabcase. Basically how the SVG spec want you to write it. See this topic in the [Preact documentation](https://preactjs.com/guide/v10/differences-to-react/#svg-inside-jsx).
|
||||
|
||||
### One generic icon component
|
||||
## One generic icon component
|
||||
|
||||
It is possible to create one generic icon component to load icons.
|
||||
It is possible to create one generic icon component to load icons, but it is not recommended.
|
||||
|
||||
> ⚠️ Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
|
||||
::: danger
|
||||
The example below imports all ES Modules, so exercise caution when using it. Importing all icons will significantly increase the build size of the application, negatively affecting its performance. This is especially important when using bundlers like `Webpack`, `Rollup`, or `Vite`.
|
||||
:::
|
||||
|
||||
#### Icon Component Example
|
||||
### Icon Component Example
|
||||
|
||||
```js
|
||||
import * as icons from 'lucide-preact';
|
||||
```jsx
|
||||
import { icons } from 'lucide-preact';
|
||||
|
||||
const Icon = ({ name, color, size }) => {
|
||||
const LucideIcon = icons[name];
|
||||
@@ -80,3 +88,15 @@ const Icon = ({ name, color, size }) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### Using the Icon Component
|
||||
|
||||
```jsx
|
||||
import Icon from './Icon';
|
||||
|
||||
const App = () => {
|
||||
return <Icon name="home" />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
@@ -6,28 +6,32 @@ Implementation of the lucide icon library for React Native applications
|
||||
|
||||
First, ensure that you have `react-native-svg@^12.0.0` installed. Then, install the package:
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-react-native
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-react-native
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-react-native
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## How to use
|
||||
|
||||
It's build with ESmodules so it's completely tree-shakable.
|
||||
Each icon can be imported as a react component.
|
||||
Each icon can be imported as a React component.
|
||||
|
||||
### Example
|
||||
|
||||
You can pass additional props to adjust the icon.
|
||||
Additional props can be passed to adjust the icon:
|
||||
|
||||
```js
|
||||
```jsx
|
||||
import { Camera } from 'lucide-react-native';
|
||||
// Returns ReactComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
@@ -37,7 +41,7 @@ const App = () => {
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Props
|
||||
## Props
|
||||
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
@@ -46,27 +50,29 @@ export default App;
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props
|
||||
### Applying props
|
||||
|
||||
You can also pass custom props that will be added in the svg as attributes.
|
||||
To customize the appearance of an icon, you can pass custom properties as props directly to the component. The component accepts all SVG attributes as props, which allows flexible styling of the SVG elements.
|
||||
|
||||
```js
|
||||
```jsx
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera fill="red" />;
|
||||
};
|
||||
```
|
||||
|
||||
### One generic icon component
|
||||
## One generic icon component
|
||||
|
||||
It is possible to create one generic icon component to load icons.
|
||||
It is possible to create one generic icon component to load icons, but it is not recommended.
|
||||
|
||||
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
|
||||
::: warning
|
||||
The example below imports all ES Modules, so exercise caution when using it. Importing all icons will significantly increase the build size of the application, negatively affecting its performance. This is especially important to keep in mind when using bundlers like `Webpack`, `Rollup`, or `Vite`.
|
||||
:::
|
||||
|
||||
#### Icon Component Example
|
||||
### Icon Component Example
|
||||
|
||||
```js
|
||||
import * as icons from 'lucide-react';
|
||||
```jsx
|
||||
import { icons } from 'lucide-react';
|
||||
|
||||
const Icon = ({ name, color, size }) => {
|
||||
const LucideIcon = icons[name];
|
||||
@@ -76,3 +82,15 @@ const Icon = ({ name, color, size }) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### Using the Icon Component
|
||||
|
||||
```jsx
|
||||
import Icon from './Icon';
|
||||
|
||||
const App = () => {
|
||||
return <Icon name="home" />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
@@ -4,28 +4,34 @@ Implementation of the lucide icon library for react applications
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-react
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-react
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-react
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## How to use
|
||||
|
||||
It's build with ESmodules so it's completely tree-shakable.
|
||||
Each icon can be imported as a react component.
|
||||
Lucide is built with ES Modules, so it's completely tree-shakable.
|
||||
|
||||
Each icon can be imported as a React component, which renders an inline SVG element. This way, only the icons that are imported into your project are included in the final bundle. The rest of the icons are tree-shaken away.
|
||||
|
||||
### Example
|
||||
|
||||
You can pass additional props to adjust the icon.
|
||||
Additional props can be passed to adjust the icon:
|
||||
|
||||
```js
|
||||
```jsx
|
||||
import { Camera } from 'lucide-react';
|
||||
// Returns ReactComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
@@ -35,7 +41,7 @@ const App = () => {
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Props
|
||||
## Props
|
||||
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
@@ -44,27 +50,31 @@ export default App;
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props
|
||||
### Applying props
|
||||
|
||||
You can also pass custom props that will be added in the svg as attributes.
|
||||
To customize the appearance of an icon, you can pass custom properties as props directly to the component. The component accepts all SVG attributes as props, which allows flexible styling of the SVG elements. See the list of SVG Presentation Attributes on [MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation).
|
||||
|
||||
```js
|
||||
```jsx
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera fill="red" />;
|
||||
return <Camera size={48} fill="red" />;
|
||||
};
|
||||
```
|
||||
|
||||
### One generic icon component
|
||||
## One generic icon component
|
||||
|
||||
It is possible to create one generic icon component to load icons.
|
||||
It is possible to create one generic icon component to load icons, but it is not recommended.
|
||||
|
||||
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
|
||||
::: danger
|
||||
The example below imports all ES Modules, so exercise caution when using it. Importing all icons will significantly increase the build size of the application, negatively affecting its performance. This is especially important to keep in mind when using bundlers like `Webpack`, `Rollup`, or `Vite`.
|
||||
|
||||
#### Icon Component Example
|
||||
This is not the case for the latest NextJS, because it uses server side rendering. The icons will be streamed to the client when needed. For NextJS with Dynamic Imports, see [dynamic imports](#nextjs-example) section for more information.
|
||||
:::
|
||||
|
||||
```js
|
||||
import * as icons from 'lucide-react';
|
||||
### Icon Component Example
|
||||
|
||||
```jsx
|
||||
import { icons } from 'lucide-react';
|
||||
|
||||
const Icon = ({ name, color, size }) => {
|
||||
const LucideIcon = icons[name];
|
||||
@@ -74,3 +84,72 @@ const Icon = ({ name, color, size }) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### Using the Icon Component
|
||||
|
||||
```jsx
|
||||
import Icon from './Icon';
|
||||
|
||||
const App = () => {
|
||||
return <Icon name="Home" />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
#### With Dynamic Imports
|
||||
|
||||
> :warning: This is experimental and only works with bundlers that support dynamic imports.
|
||||
|
||||
Lucide react exports a dynamic import map `dynamicIconImports`, which is useful for applications that want to show icons dynamically by icon name. For example, when using a content management system with where icon names are stored in a database.
|
||||
|
||||
When using client side rendering, it will fetch the icon component when it's needed. This will reduce the initial bundle size.
|
||||
|
||||
The keys of the dynamic import map are the lucide original icon names (kebab case).
|
||||
|
||||
Example with React suspense:
|
||||
|
||||
```tsx
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
const fallback = <div style={{ background: '#ddd', width: 24, height: 24 }}/>
|
||||
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icon
|
||||
```
|
||||
|
||||
##### NextJS Example
|
||||
|
||||
In NextJS [the dynamic function](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#nextdynamic) can be used to load the icon component dynamically.
|
||||
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
import { LucideProps } from 'lucide-react';
|
||||
import dynamicIconImports from 'lucide-react/dynamicIconImports';
|
||||
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = dynamic(dynamicIconImports[name])
|
||||
|
||||
return <LucideIcon {...props} />;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
@@ -4,28 +4,34 @@ Implementation of the lucide icon library for solid applications.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
::: code-group
|
||||
|
||||
```sh [pnpm]
|
||||
pnpm install lucide-solid
|
||||
```
|
||||
|
||||
```sh [yarn]
|
||||
yarn add lucide-solid
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sh
|
||||
```sh [npm]
|
||||
npm install lucide-solid
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## How to use
|
||||
|
||||
It's build with ESmodules so it's completely tree-shakable.
|
||||
Each icon can be imported as a solid component.
|
||||
Lucide is built with ES Modules, so it's completely tree-shakable.
|
||||
|
||||
Each icon can be imported as a Solid component, which renders an inline SVG element. This way, only the icons that are imported into your project are included in the final bundle. The rest of the icons are tree-shaken away.
|
||||
|
||||
### Example
|
||||
|
||||
You can pass additional props to adjust the icon.
|
||||
Additional props can be passed to adjust the icon:
|
||||
|
||||
```js
|
||||
```jsx
|
||||
import { Camera } from 'lucide-solid';
|
||||
// Returns SolidComponent
|
||||
|
||||
// Usage
|
||||
const App = () => {
|
||||
@@ -35,7 +41,7 @@ const App = () => {
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Props
|
||||
## Props
|
||||
|
||||
| name | type | default |
|
||||
| --------------------- | --------- | ------------ |
|
||||
@@ -44,32 +50,37 @@ export default App;
|
||||
| `strokeWidth` | *number* | 2 |
|
||||
| `absoluteStrokeWidth` | *boolean* | false |
|
||||
|
||||
### Custom props / svg attributes
|
||||
### Applying props
|
||||
|
||||
You can also pass custom props that will be added in the as attributes. With that you can modify the icons look by passing svg attributes.
|
||||
To customize the appearance of an icon, you can pass custom properties as props directly to the component. The component accepts all SVG attributes as props, which allows flexible styling of the SVG elements. See the list of SVG Presentation Attributes on [MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Presentation).
|
||||
|
||||
```js
|
||||
```jsx
|
||||
// Usage
|
||||
const App = () => {
|
||||
return <Camera fill="red" stroke-linejoin="bevel" />;
|
||||
};
|
||||
```
|
||||
|
||||
### One generic icon component
|
||||
## One generic icon component
|
||||
|
||||
It is possible to create one generic icon component to load icons.
|
||||
It is possible to create one generic icon component to load icons. It's not recommended.
|
||||
|
||||
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
|
||||
::: danger
|
||||
The example below imports all ES Modules, so exercise caution when using it. Importing all icons will significantly increase the build size of the application, negatively affecting its performance. This is especially important to keep in mind when using bundlers like `Webpack`, `Rollup`, or `Vite`.
|
||||
:::
|
||||
|
||||
#### Icon Component Example
|
||||
### Icon Component Example
|
||||
|
||||
```tsx
|
||||
import * as icons from 'lucide-solid';
|
||||
import type { LucideProps } from 'lucide-solid';
|
||||
import { icons, type LucideProps } from 'lucide-solid';
|
||||
import { splitProps } from 'solid-js';
|
||||
import { Dynamic } from 'solid-js/web';
|
||||
|
||||
const Icon = (props: { name: keyof typeof icons } & LucideProps) => {
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof icons;
|
||||
}
|
||||
|
||||
const Icon = (props: IconProps) => {
|
||||
const [local, others] = splitProps(props, ["name"]);
|
||||
|
||||
return <Dynamic component={icons[local.name]} {...others} />
|
||||
@@ -77,3 +88,15 @@ const Icon = (props: { name: keyof typeof icons } & LucideProps) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### Using the Icon Component
|
||||
|
||||
```tsx
|
||||
import Icon from './Icon';
|
||||
|
||||
const App = () => {
|
||||
return <Icon name="home" />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user