mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-17 10:17:42 +01:00
Compare commits
180 Commits
0.269.0
...
lucide-vue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1d57d3c85 | ||
|
|
701c2fb6b2 | ||
|
|
294ec9c727 | ||
|
|
99c883e60a | ||
|
|
9e68779d22 | ||
|
|
06372db723 | ||
|
|
114fb08556 | ||
|
|
3bad7f6ced | ||
|
|
e450afe408 | ||
|
|
6fcfc820ca | ||
|
|
55f264bea6 | ||
|
|
675158df16 | ||
|
|
042393a931 | ||
|
|
551635003c | ||
|
|
5c7119f6d1 | ||
|
|
7bfdb2f54a | ||
|
|
e3abcdbcc6 | ||
|
|
62d350140e | ||
|
|
ad90ee7582 | ||
|
|
b0e825cb57 | ||
|
|
d4cbe899fb | ||
|
|
be3ccc8ece | ||
|
|
e56b09d400 | ||
|
|
7e936c8803 | ||
|
|
c9ffa4033f | ||
|
|
32a6187d69 | ||
|
|
2bf20db4bf | ||
|
|
4473df5ad5 | ||
|
|
bc5efd7f0d | ||
|
|
05f209cb04 | ||
|
|
ef89510a47 | ||
|
|
b72cea6399 | ||
|
|
d2152b3cdd | ||
|
|
ea43df6431 | ||
|
|
4042a366e8 | ||
|
|
5e0ba7e897 | ||
|
|
6b4f575992 | ||
|
|
92784de9c5 | ||
|
|
314ee3b255 | ||
|
|
ee7add11bf | ||
|
|
001d0a51fb | ||
|
|
fd4308e755 | ||
|
|
59893119b5 | ||
|
|
faff6a8269 | ||
|
|
3fe74beeb0 | ||
|
|
f8aafd63b9 | ||
|
|
f0422f415c | ||
|
|
14a196d89c | ||
|
|
87a89b30da | ||
|
|
3180910b23 | ||
|
|
46a4041cc7 | ||
|
|
e3166c65df | ||
|
|
d9d7e245a3 | ||
|
|
e19a9cc43a | ||
|
|
5ecfd61397 | ||
|
|
5366782da0 | ||
|
|
262f9e8865 | ||
|
|
7af26002a0 | ||
|
|
e71a776acc | ||
|
|
0a69fb9e52 | ||
|
|
3648e02992 | ||
|
|
64504da1cd | ||
|
|
e166ba4e80 | ||
|
|
1123214b13 | ||
|
|
4140ba5612 | ||
|
|
019f38281c | ||
|
|
633595d1c1 | ||
|
|
df58c3ff2f | ||
|
|
e7abba5273 | ||
|
|
2693da38d3 | ||
|
|
ab59a1ec36 | ||
|
|
315c020279 | ||
|
|
494f7953c8 | ||
|
|
a5ea3a5368 | ||
|
|
6486f76c55 | ||
|
|
e32db96f1f | ||
|
|
73f70c885a | ||
|
|
14c7ea8e13 | ||
|
|
9fc7653dc1 | ||
|
|
2b007e7962 | ||
|
|
bb1e470f3a | ||
|
|
4a1e6bbfa5 | ||
|
|
e5ee997566 | ||
|
|
27c0a136cd | ||
|
|
84b3c46b65 | ||
|
|
1a09e7fb39 | ||
|
|
75e9724072 | ||
|
|
fbaccc7d9f | ||
|
|
c24bc4d7ef | ||
|
|
5c8c8f4362 | ||
|
|
ffd2a62941 | ||
|
|
e77959e1a6 | ||
|
|
149ee36e61 | ||
|
|
88bf60b5d7 | ||
|
|
1e5df716a4 | ||
|
|
fc0ea760e5 | ||
|
|
c85275899a | ||
|
|
288edde1ea | ||
|
|
207ff6c487 | ||
|
|
a1a9a4d839 | ||
|
|
c5804ad9a5 | ||
|
|
c72fb4a28b | ||
|
|
da5ad547b5 | ||
|
|
66cfe527b3 | ||
|
|
d1866225ba | ||
|
|
372735999f | ||
|
|
f3a33346dd | ||
|
|
3373acf596 | ||
|
|
73d5bfc318 | ||
|
|
ddbc074aa3 | ||
|
|
8f4d6b1651 | ||
|
|
d8b08f8fda | ||
|
|
fddacb6260 | ||
|
|
3d0c8691c9 | ||
|
|
47998b05aa | ||
|
|
9a9e051343 | ||
|
|
6c6c8448fa | ||
|
|
49445aad3a | ||
|
|
70656eb4f0 | ||
|
|
930f862547 | ||
|
|
931b7f5376 | ||
|
|
81e44bdc40 | ||
|
|
e6e90944b9 | ||
|
|
f6fd369bfe | ||
|
|
bbf183fe48 | ||
|
|
4f5642b872 | ||
|
|
1dce6a141a | ||
|
|
dbfce919fc | ||
|
|
52adb78df8 | ||
|
|
c5cfbed28c | ||
|
|
1e4fd13852 | ||
|
|
0a0fd1cf6c | ||
|
|
487d03fc4d | ||
|
|
950160ad5a | ||
|
|
b6f5898aee | ||
|
|
a9c1dca801 | ||
|
|
c05c7e333f | ||
|
|
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 |
@@ -4,3 +4,8 @@ coverage
|
||||
lib
|
||||
tests
|
||||
node_modules
|
||||
.eslintrc.js
|
||||
docs/images
|
||||
docs/guide/basics/examples
|
||||
docs/guide/advanced/examples
|
||||
packages/lucide-react/dynamicIconImports.js
|
||||
|
||||
48
.eslintrc.js
48
.eslintrc.js
@@ -1,22 +1,18 @@
|
||||
const DEFAULT_ATTRS = require('./scripts/render/default-attrs.json');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ['airbnb-base', 'prettier'],
|
||||
plugins: ['import', 'prettier'],
|
||||
plugins: ['import', '@html-eslint'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
},
|
||||
],
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{ devDependencies: ['**/*.test.js', '**/*.spec.js', './scripts/**'] },
|
||||
@@ -33,8 +29,42 @@ module.exports = {
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./site/tsconfig.json', './packages/*/tsconfig.json'],
|
||||
project: ['./docs/tsconfig.json', './packages/*/tsconfig.json'],
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['./icons/*.svg'],
|
||||
parser: '@html-eslint/parser',
|
||||
rules: {
|
||||
'@html-eslint/require-doctype': 'off',
|
||||
'@html-eslint/no-duplicate-attrs': 'error',
|
||||
'@html-eslint/no-inline-styles': 'error',
|
||||
'@html-eslint/require-attrs': [
|
||||
'error',
|
||||
...Object.entries(DEFAULT_ATTRS)
|
||||
.map(([attr, value]) => ({ tag: 'svg', attr, value: String(value) }))
|
||||
],
|
||||
'@html-eslint/indent': ['error', 2],
|
||||
"@html-eslint/no-multiple-empty-lines": ["error", { "max": 0 }],
|
||||
'@html-eslint/no-extra-spacing-attrs': [
|
||||
'error',
|
||||
{
|
||||
enforceBeforeSelfClose: true,
|
||||
},
|
||||
],
|
||||
'@html-eslint/require-closing-tags': [
|
||||
'error',
|
||||
{
|
||||
selfClosing: 'always',
|
||||
allowSelfClosingCustom: true,
|
||||
},
|
||||
],
|
||||
'@html-eslint/element-newline': 'error',
|
||||
'@html-eslint/no-trailing-spaces': 'error',
|
||||
'@html-eslint/quotes': 'error',
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
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:
|
||||
8
.github/actions/build-and-test.yml
vendored
8
.github/actions/build-and-test.yml
vendored
@@ -9,16 +9,16 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
|
||||
8
.github/actions/check-icons.yml
vendored
8
.github/actions/check-icons.yml
vendored
@@ -9,16 +9,16 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
|
||||
66
.github/labeler.yml
vendored
66
.github/labeler.yml
vendored
@@ -1,62 +1,92 @@
|
||||
# For changed dependencies
|
||||
📦 dependencies:
|
||||
- pnpm-lock.yaml
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- pnpm-lock.yaml
|
||||
|
||||
# For changes in documentation
|
||||
📖 documentation:
|
||||
- docs/*.md
|
||||
- docs/**/*.md
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- docs/*.md
|
||||
- docs/**/*.md
|
||||
|
||||
# For changes in the site, but not markdown files
|
||||
🌍 site:
|
||||
- 'docs/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'docs/**'
|
||||
|
||||
# For changes in the metadata
|
||||
🫧 metadata:
|
||||
- 'icons/*.json'
|
||||
- categories/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'icons/*.json'
|
||||
- categories/*
|
||||
|
||||
# For changes or added icons
|
||||
🎨 icon:
|
||||
- 'icons/*.svg'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'icons/*.svg'
|
||||
|
||||
# For changes in the lucide package
|
||||
🧳 lucide package:
|
||||
- 'packages/lucide/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide/*'
|
||||
|
||||
# For changes in the lucide React package
|
||||
⚛️ react package:
|
||||
- 'packages/lucide-react/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-react/*'
|
||||
|
||||
# For changes in the lucide React Native package
|
||||
⚛️ react native package:
|
||||
- 'packages/lucide-react-native/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-react-native/*'
|
||||
|
||||
# For changes in the lucide vue packages
|
||||
💎 vue package:
|
||||
- 'packages/lucide-vue/*'
|
||||
- 'packages/lucide-vue-next/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-vue/*'
|
||||
- 'packages/lucide-vue-next/*'
|
||||
|
||||
# For changes in the lucide angular package
|
||||
🅰️ angular package:
|
||||
- 'packages/lucide-angular/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-angular/*'
|
||||
|
||||
# For changes in the lucide preact package
|
||||
⚛️ preact package:
|
||||
- 'packages/lucide-preact/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-preact/*'
|
||||
|
||||
# For changes in the lucide svelte package
|
||||
🧣 svelte package:
|
||||
- 'packages/lucide-svelte/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-svelte/*'
|
||||
|
||||
# For changes in the lucide solid package
|
||||
🪝 solid package:
|
||||
- 'packages/lucide-solid/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-solid/*'
|
||||
|
||||
# For changes in the lucide static package
|
||||
🪨 static package:
|
||||
- 'packages/lucide-static/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-static/*'
|
||||
|
||||
# For changes in the lucide flutter package
|
||||
🏹 flutter package:
|
||||
- 'packages/lucide-flutter/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'packages/lucide-flutter/*'
|
||||
|
||||
24
.github/pull_request_template.md
vendored
24
.github/pull_request_template.md
vendored
@@ -2,13 +2,13 @@
|
||||
|
||||
<!-- Insert `closes #issueNumber` here if merging this PR will resolve an existing issue -->
|
||||
|
||||
## What is the purpose of this pull request? <!-- (put an "X" next to an item) -->
|
||||
|
||||
## 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
|
||||
- [ ] Other:
|
||||
|
||||
### Description
|
||||
<!-- Please insert your description here and provide info about the "what" this PR is contribution -->
|
||||
@@ -21,28 +21,28 @@
|
||||
|
||||
## Icon Design Checklist <!-- ONLY for new icons, remove this part if not icon PR -->
|
||||
|
||||
#### Concept <!-- ONLY for new icons -->
|
||||
|
||||
### 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 -->
|
||||
### 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 -->
|
||||
|
||||
### 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 -->
|
||||
|
||||
### 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.
|
||||
@@ -50,6 +50,6 @@
|
||||
- [ ] 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.
|
||||
|
||||
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@@ -15,33 +15,17 @@ jobs:
|
||||
VERSION: ${{ steps.new-version.outputs.NEW_VERSION }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Fetch tags
|
||||
run: git fetch --all --tags
|
||||
@@ -50,9 +34,6 @@ jobs:
|
||||
id: latest-tag
|
||||
run: echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Check if we can patch
|
||||
run: .github/workflows/version-up.sh --minor
|
||||
|
||||
|
||||
5
.github/workflows/close-stale-prs.yml
vendored
5
.github/workflows/close-stale-prs.yml
vendored
@@ -7,12 +7,11 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-pr-message: This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 5 days.
|
||||
close-pr-message: This PR was closed because it has been stalled for 5 days with no activity.
|
||||
close-pr-label: 🧶 stale
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
days-before-pr-close: -1
|
||||
days-before-close: -1
|
||||
|
||||
2
.github/workflows/labeler.yml
vendored
2
.github/workflows/labeler.yml
vendored
@@ -9,4 +9,4 @@ jobs:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
- uses: actions/labeler@v5
|
||||
|
||||
25
.github/workflows/linting.yml
vendored
Normal file
25
.github/workflows/linting.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Linting
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
linting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run Linter
|
||||
run: pnpm lint
|
||||
30
.github/workflows/lucide-angular.yml
vendored
30
.github/workflows/lucide-angular.yml
vendored
@@ -11,33 +11,17 @@ jobs:
|
||||
lucide-angular:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-angular build
|
||||
|
||||
40
.github/workflows/lucide-font.yml
vendored
40
.github/workflows/lucide-font.yml
vendored
@@ -10,47 +10,27 @@ on:
|
||||
jobs:
|
||||
lucide-font:
|
||||
runs-on: ubuntu-latest
|
||||
container: ericfennis/lucide-font:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter outline-svg
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Outline svg Icons
|
||||
run: pnpm build:outline-icons
|
||||
|
||||
- name: Create directory
|
||||
run: mkdir lucide-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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: lucide-font
|
||||
path: lucide-font
|
||||
|
||||
31
.github/workflows/lucide-preact.yml
vendored
31
.github/workflows/lucide-preact.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-preact/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-preact:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-preact build
|
||||
|
||||
31
.github/workflows/lucide-react-native.yml
vendored
31
.github/workflows/lucide-react-native.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-react-native/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-react-native:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-react-native build
|
||||
|
||||
32
.github/workflows/lucide-react.yml
vendored
32
.github/workflows/lucide-react.yml
vendored
@@ -5,39 +5,25 @@ on:
|
||||
paths:
|
||||
- packages/lucide-react/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- scripts/generateNextJSAliases.mjs
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-react:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-react build
|
||||
|
||||
31
.github/workflows/lucide-solid.yml
vendored
31
.github/workflows/lucide-solid.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-solid/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-solid:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-solid build
|
||||
|
||||
30
.github/workflows/lucide-static.yml
vendored
30
.github/workflows/lucide-static.yml
vendored
@@ -11,33 +11,17 @@ jobs:
|
||||
lucide-static:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-static build
|
||||
|
||||
31
.github/workflows/lucide-svelte.yml
vendored
31
.github/workflows/lucide-svelte.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-svelte/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-svelte:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-svelte build
|
||||
|
||||
31
.github/workflows/lucide-vue-next.yml
vendored
31
.github/workflows/lucide-vue-next.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-vue-next/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-vue-next:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-vue-next build
|
||||
|
||||
31
.github/workflows/lucide-vue.yml
vendored
31
.github/workflows/lucide-vue.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide-vue/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-vue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-vue build
|
||||
|
||||
31
.github/workflows/lucide.yml
vendored
31
.github/workflows/lucide.yml
vendored
@@ -5,39 +5,24 @@ on:
|
||||
paths:
|
||||
- packages/lucide/**
|
||||
- tools/build-icons/**
|
||||
- tools/rollup-plugins/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide build
|
||||
|
||||
213
.github/workflows/pull-request.yml
vendored
213
.github/workflows/pull-request.yml
vendored
@@ -4,155 +4,106 @@ on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- 'icons/*.svg'
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
branches:
|
||||
- main
|
||||
- fix-icon-preview
|
||||
|
||||
jobs:
|
||||
add-changed-icons-comment:
|
||||
lint-filenames:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v35
|
||||
uses: tj-actions/changed-files@v41
|
||||
with:
|
||||
files: icons/*
|
||||
- name: Generate annotations
|
||||
run: node ./scripts/lintFilenames.mjs
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
|
||||
lint-contributors:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v41
|
||||
with:
|
||||
files: icons/*
|
||||
- uses: actions/setup-node@v4
|
||||
- name: Install simple-git (safer and faster than installing all deps)
|
||||
run: npm install simple-git
|
||||
- name: Generate annotations
|
||||
run: node ./scripts/updateContributors.mjs
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FETCH_DEPTH: ${{ github.event.pull_request.commits }}
|
||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
- name: Generate annotations
|
||||
env:
|
||||
ANNOTATION_SEVERITY: notice
|
||||
ANNOTATION_TITLE: Contributors have changed!
|
||||
ANNOTATION_DESCRIPTION: Don't add people who have only performed automatic optimizations.
|
||||
run: |
|
||||
git diff --unified=0 -- icons/*.json | # diff icon metadata (unified=0 gives the correct chunk line number)
|
||||
perl -ne '/^(\+|- |@)/ && print' | # get chunks (lines that start with "+++", "@@", "+ ", "- ")
|
||||
perl -pe 's/\n/%0A/' | # url encode line breaks (\n -> %0A)
|
||||
perl -pe 's/%0A(\+\+\+ b\/)/\n\1/g' | # split chunks(one chunk per line)
|
||||
perl -pe "s/\+\+\+ b\/([^@]*)%0A@@ -(\d+)[^\s]* \+(\d+)[^@]*@@(.*)/::$ANNOTATION_SEVERITY file=\1,line=\2,endLine=\3,title=$ANNOTATION_TITLE::$ANNOTATION_DESCRIPTION%0A\4/"
|
||||
# Example for the previous substitution
|
||||
# input: +++ b/icons/accessibility.json%0A@@ -2,0 +3 @@%0A+ "contributors": ["hi"],%0A@@ -13 +14 @@%0A+}%0A
|
||||
# output: ::$ANNOTATION_SEVERITY file=icons/accessibility.json,line=2,endLine=3,title=$ANNOTATION_TITLE::$ANNOTATION_DESCRIPTION%0A%0A+ "contributors": ["hi"],%0A@@ -13 +14 @@%0A+}%0A
|
||||
|
||||
generate-changed-icons-comment:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v41
|
||||
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: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in $(printf "%s\\n" icons/*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ 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/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate cohesion check squares
|
||||
id: generate-cohesion-check-squares
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in $(printf "%s\\n" icons/*square*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ 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/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 1px stroke-width
|
||||
id: generate-1px-stroke-width
|
||||
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/stroke-width/1/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 2px stroke-width
|
||||
id: generate-2px-stroke-width
|
||||
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/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 3px stroke-width
|
||||
id: generate-3px-stroke-width
|
||||
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/stroke-width/3/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate X-rays
|
||||
id: generate-x-rays
|
||||
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 width=\"400\" title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/$(basename ${file//\.svg/})/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
id: fc
|
||||
id: pr-comment
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Added or changed icons
|
||||
|
||||
- name: Generate comment markup
|
||||
run: node ./scripts/generateChangedIconsCommentMarkup.mjs >> comment-markup.md
|
||||
id: comment-markup
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
comment-id: ${{ steps.pr-comment.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
### Added or changed icons
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
<details>
|
||||
<summary>Preview cohesion</summary>
|
||||
${{ steps.generate-cohesion-check-squares.outputs.body }}<br/>
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
${{ steps.generate-cohesion-check-random.outputs.body }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Preview stroke widths</summary>
|
||||
${{ steps.generate-1px-stroke-width.outputs.body }}<br/>
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
${{ 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>
|
||||
body-path: ./comment-markup.md
|
||||
edit-mode: replace
|
||||
|
||||
104
.github/workflows/release.yml
vendored
104
.github/workflows/release.yml
vendored
@@ -39,6 +39,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-release
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package: [
|
||||
'lucide',
|
||||
@@ -52,30 +53,14 @@ jobs:
|
||||
'lucide-svelte',
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- 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 "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -100,32 +85,15 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pre-release, lucide-font]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -149,47 +117,27 @@ jobs:
|
||||
if: github.repository == 'lucide-icons/lucide'
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-release
|
||||
container: ericfennis/lucide-font:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3.4.1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
version: 8
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
node-version: 18
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter outline-svg
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Outline svg Icons
|
||||
run: pnpm build:outline-icons
|
||||
|
||||
- name: Create directory
|
||||
run: mkdir lucide-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
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: lucide-font
|
||||
path: lucide-font
|
||||
@@ -203,8 +151,8 @@ jobs:
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
- name: Zip font and icons
|
||||
run: |
|
||||
zip -r lucide-font-${{ needs.pre-release.outputs.VERSION }}.zip lucide-font
|
||||
|
||||
@@ -4,7 +4,6 @@ stats
|
||||
node_modules
|
||||
tests
|
||||
scripts
|
||||
site
|
||||
src
|
||||
build
|
||||
babel.config.js
|
||||
|
||||
16
.prettierignore
Normal file
16
.prettierignore
Normal file
@@ -0,0 +1,16 @@
|
||||
pnpm-lock.yaml
|
||||
|
||||
# lucide-angular
|
||||
packages/lucide-angular/.angular/cache
|
||||
|
||||
# lucide-static
|
||||
packages/lucide-static/icons
|
||||
packages/lucide-static/lib
|
||||
packages/lucide-static/sprite.svg
|
||||
packages/lucide-static/tags.json
|
||||
packages/lucide-static/icon-nodes.json
|
||||
packages/lucide-static/font
|
||||
|
||||
# lucide-svelte
|
||||
packages/lucide-svelte/src/icons/*.svelte
|
||||
packages/lucide-svelte/.svelte-kit
|
||||
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -3,5 +3,11 @@
|
||||
"devs",
|
||||
"preact",
|
||||
"Preact"
|
||||
]
|
||||
],
|
||||
"eslint.enable": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"svg"
|
||||
],
|
||||
"svg.preview.background": "transparent"
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ Here you can find instructions on how to implement the guidelines with different
|
||||
|
||||
#### [Adobe Illustrator Guide](https://lucide.dev/docs/illustrator-guide)
|
||||
|
||||
You can also [download an Adobe Illustrator template](https://lucide.dev/templates/illustrator-template.ai).
|
||||
You can also [download an Adobe Illustrator template](https://github.com/lucide-icons/lucide/blob/main/docs/public/templates/illustrator_template.ai).
|
||||
|
||||
#### [Inkscape Guide](https://lucide.dev/docs/inkscape-guide)
|
||||
|
||||
@@ -50,7 +50,7 @@ Seperate them by two PRs; 'pr-01' `arrow`, `arrow-down` and 'pr-02' `bicycle`.
|
||||
|
||||
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 :+1:.
|
||||
|
||||
If the icon has not already been requested, [create an issue](https://github.com/lucide-icons/lucide/issues/new?title=Icon%20Request:) with a title of `Icon request: <icon name>` and add as much information as possible.
|
||||
If the icon has not already been requested, [create an icon request issue](https://github.com/lucide-icons/lucide/issues/new?assignees=&labels=%F0%9F%99%8C+icon+request&projects=&template=01_icon_request.yml) and add as much information as possible.
|
||||
|
||||
### Icon Requests from Feather
|
||||
|
||||
@@ -72,8 +72,8 @@ pnpm install # Install dependencies, including the workspace packages
|
||||
|
||||
To distribute different packages we use PNPM workspaces. Before you start make sure you are familiar with this concept. The concept of working in workspaces is created by Yarn, they have a well written introduction: [yarn workspaces](https://classic.yarnpkg.com/lang/enhttps://lucide.dev/docs/workspaces).
|
||||
|
||||
The configured directory for workspaces is the [packages](./packages) directory, located in the root directory. There you will find all the current packages from lucide.
|
||||
There are more workspaces defined, see [`pnpm-workspace.yaml`](./pnpm-workspace.yaml).
|
||||
The configured directory for workspaces is the [packages](https://github.com/lucide-icons/lucide/tree/main/packages) directory, located in the root directory. There you will find all the current packages from lucide.
|
||||
There are more workspaces defined, see [`pnpm-workspace.yaml`](https://github.com/lucide-icons/lucide/blob/main/pnpm-workspace.yaml).
|
||||
|
||||
> Note: One package is not managed by pnpm: **lucide-flutter**, this package is written in Dart and used pub for publishing.
|
||||
|
||||
@@ -144,16 +144,19 @@ Root directories
|
||||
|
||||
```sh
|
||||
lucide
|
||||
|
|
||||
├── docs
|
||||
│ ├── guide
|
||||
├── icons
|
||||
├── packages
|
||||
├── scripts
|
||||
└── site
|
||||
└── scripts
|
||||
```
|
||||
|
||||
### Docs
|
||||
|
||||
The lucide.dev website is using [vitepress](https://vitepress.dev/) to generate the static website. The markdown files are located in the docs directory.
|
||||
|
||||
### Guides
|
||||
|
||||
Detailed documentation about: installation, guides, packages, design guides etc.
|
||||
|
||||
### Icons
|
||||
@@ -170,10 +173,6 @@ Includes all the (npm) packages of lucide.
|
||||
|
||||
Includes usefully scripts to automate certain jobs. Big part of the scripts is the template generation, for example it generates icon components for all the packages. These scripts are usually executed from the "scripts" section in the package.json.
|
||||
|
||||
### site
|
||||
|
||||
The lucide.dev website is using [vitepress](https://vitepress.dev/) to generate the static website. The markdown files are located in the docs directory.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation files are located in the [docs](https://github.com/lucide-icons/lucide/tree/main/docs) directory. All these markdown files will be loaded in the build of the lucide.dev website.
|
||||
|
||||
20
README.md
20
README.md
@@ -11,14 +11,14 @@
|
||||
|
||||
Community-run fork of [Feather Icons](https://github.com/feathericons/feather), open for anyone to contribute icons.
|
||||
|
||||
It began after growing disaffection with the [Feather Icons](https://github.com/feathericons/feather) project moderation. With over 300+ open issues and over 100+ open PRs, the Feather Icons project has been abandoned. This unfortunately means that hundreds of developers and designers wasted their time contributing to Feather Icons with no chance of PRs being accepted.
|
||||
It began after growing dissatisfaction with the [Feather Icons](https://github.com/feathericons/feather) project moderation. With over 300+ open issues and over 100+ open PRs, the Feather Icons project has been abandoned. This unfortunately means that hundreds of developers and designers wasted their time contributing to Feather Icons with no chance of PRs being accepted.
|
||||
|
||||
Lucide is trying to expand the icon set as much as possible while staying faithful to the original simplistic design language. We do this as a community of devs and designers and hope that you'll join us!
|
||||
|
||||
### Why choose Lucide over Feather Icons
|
||||
|
||||
- More icons to work with: Lucide already has hundreds of icons more than Feather does.
|
||||
- Official librairies and integrations with popular frameworks and design tools.
|
||||
- Official libraries and integrations with popular frameworks and design tools.
|
||||
- Well maintained code base.
|
||||
- Active community, regularly growing and improving the set.
|
||||
|
||||
@@ -35,7 +35,6 @@ Lucide is trying to expand the icon set as much as possible while staying faithf
|
||||
- [Static (svg sprite, font, icons ..)](#static-svg-sprite-font-icons-)
|
||||
- [Figma](#figma)
|
||||
- [Laravel](#laravel)
|
||||
- [Flutter](#flutter)
|
||||
- [Svelte](#svelte)
|
||||
- [Solid](#solid)
|
||||
- [Hyva](#hyva)
|
||||
@@ -200,16 +199,6 @@ 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.
|
||||
|
||||
```sh
|
||||
flutter pub add lucide_icons
|
||||
```
|
||||
|
||||
For more details, see the [pub.dev](https://pub.dev/packages/lucide_icons).
|
||||
|
||||
### Svelte
|
||||
|
||||
Implementation of the lucide icon library for Svelte applications.
|
||||
@@ -285,6 +274,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="/docs/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": "File icons",
|
||||
"icon": "layout"
|
||||
"icon": "panels-top-left"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Layout",
|
||||
"icon": "layout"
|
||||
"icon": "panels-top-left"
|
||||
}
|
||||
@@ -12,8 +12,10 @@
|
||||
},
|
||||
"title": "Lucide Icons category schema",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["$schema", "icon", "title"],
|
||||
"properties": {
|
||||
"title": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
@@ -22,13 +24,12 @@
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"weight": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"icon"
|
||||
],
|
||||
"description": "A JSON Schema for categories defined by Lucide Icons."
|
||||
}
|
||||
|
||||
@@ -1,41 +1,53 @@
|
||||
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]
|
||||
// Finds the longest matching icon to be use as the backdrop.
|
||||
// For `square-dashed-bottom-code` it suggests `square-dashed-bottom-code`.
|
||||
// For `square-dashed-bottom-i-dont-exist` it suggests `square-dashed-bottom`.
|
||||
const backdropName = name
|
||||
.split('-')
|
||||
.map((_, idx, arr) => arr.slice(0, idx + 1).join('-'))
|
||||
.reverse()
|
||||
.find((groupName) => groupName in iconNodes);
|
||||
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,
|
||||
color: name in iconNodes ? 'red' : '#777',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ export default defineConfig({
|
||||
description,
|
||||
cleanUrls: true,
|
||||
outDir: '.vercel/output/static',
|
||||
srcExclude: ['**/README.md'],
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: [
|
||||
@@ -103,6 +104,7 @@ export default defineConfig({
|
||||
{ text: 'Icons', link: '/icons/' },
|
||||
{ text: 'Guide', link: '/guide/' },
|
||||
{ text: 'Packages', link: '/packages' },
|
||||
{ text: 'Showcase', link: '/showcase' },
|
||||
{ text: 'License', link: '/license' },
|
||||
],
|
||||
sidebar,
|
||||
@@ -117,6 +119,10 @@ export default defineConfig({
|
||||
editLink: {
|
||||
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
|
||||
},
|
||||
carbonAds: {
|
||||
code: 'CWYIC53U',
|
||||
placement: 'lucidedev'
|
||||
}
|
||||
},
|
||||
sitemap: {
|
||||
hostname: 'https://lucide.dev/'
|
||||
|
||||
50
docs/.vitepress/data/companiesData.json
Normal file
50
docs/.vitepress/data/companiesData.json
Normal file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"name": "Vercel",
|
||||
"url": "https://vercel.com",
|
||||
"image": {
|
||||
"light": "/company-logos/vercel-light.svg",
|
||||
"dark": "/company-logos/vercel-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Supabase",
|
||||
"url": "https://supabase.com",
|
||||
"image": {
|
||||
"light": "/company-logos/supabase-light.svg",
|
||||
"dark": "/company-logos/supabase-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Obsidian",
|
||||
"url": "https://obsidian.md",
|
||||
"image": {
|
||||
"light": "/company-logos/obsidian-light.svg",
|
||||
"dark": "/company-logos/obsidian-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Open Collective",
|
||||
"url": "https://opencollective.com",
|
||||
"image": {
|
||||
"light": "/company-logos/open-collective-light.svg",
|
||||
"dark": "/company-logos/open-collective-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Super",
|
||||
"url": "https://super.so",
|
||||
"image": {
|
||||
"light": "/company-logos/super-light.svg",
|
||||
"dark": "/company-logos/super-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Noodle",
|
||||
"url": "https://noodle.run/",
|
||||
"image": {
|
||||
"light": "/company-logos/noodle-light.svg",
|
||||
"dark": "/company-logos/noodle-dark.svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
18
docs/.vitepress/data/componentLibrariesData.json
Normal file
18
docs/.vitepress/data/componentLibrariesData.json
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"name": "Shadcn/ui",
|
||||
"url": "https://ui.shadcn.com/",
|
||||
"image": {
|
||||
"light": "/library-logos/shadcn-ui-light.svg",
|
||||
"dark": "/library-logos/shadcn-ui-dark.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Tamagui",
|
||||
"url": "https://tamagui.dev/",
|
||||
"image": {
|
||||
"light": "/library-logos/tamagui.svg",
|
||||
"dark": "/library-logos/tamagui.svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
interface BackdropProps {
|
||||
src: string
|
||||
backdropString: string
|
||||
src: string;
|
||||
color?: string;
|
||||
backdropString: string;
|
||||
}
|
||||
|
||||
const Backdrop = ({ src, backdropString }: BackdropProps): JSX.Element => {
|
||||
const Backdrop = ({ src, color = 'red', backdropString }: BackdropProps): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<defs xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -16,8 +17,8 @@ const Backdrop = ({ src, backdropString }: BackdropProps): JSX.Element => {
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternTransform="rotate(45 50 50)"
|
||||
>
|
||||
<line stroke="red" strokeWidth={0.1} y2={1} />
|
||||
<line stroke="red" strokeWidth={0.1} y2={1} />
|
||||
<line stroke={color} strokeWidth={0.1} y2={1} />
|
||||
<line stroke={color} strokeWidth={0.1} y2={1} />
|
||||
</pattern>
|
||||
</defs>
|
||||
<mask id="svg-preview-backdrop-mask-outline" maskUnits="userSpaceOnUse">
|
||||
@@ -29,20 +30,8 @@ const Backdrop = ({ src, backdropString }: BackdropProps): JSX.Element => {
|
||||
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
|
||||
<g strokeWidth={1.75} dangerouslySetInnerHTML={{ __html: backdropString }} />
|
||||
</mask>
|
||||
<g
|
||||
strokeWidth={2.25}
|
||||
stroke="url(#pattern)"
|
||||
mask={'url(#svg-preview-backdrop-mask-outline)'}
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="url(#pattern)"
|
||||
opacity={0.5}
|
||||
stroke="none"
|
||||
/>
|
||||
<g strokeWidth={2.25} stroke="url(#pattern)" mask={'url(#svg-preview-backdrop-mask-outline)'}>
|
||||
<rect x="0" y="0" width="24" height="24" fill="url(#pattern)" opacity={0.5} stroke="none" />
|
||||
</g>
|
||||
<rect
|
||||
x="0"
|
||||
@@ -58,14 +47,13 @@ const Backdrop = ({ src, backdropString }: BackdropProps): JSX.Element => {
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="red"
|
||||
fill={color}
|
||||
opacity={0.5}
|
||||
stroke="none"
|
||||
mask={'url(#svg-preview-backdrop-mask-fill)'}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default Backdrop;
|
||||
|
||||
@@ -183,18 +183,62 @@ const Radii = ({
|
||||
>) => {
|
||||
return (
|
||||
<g className="svg-preview-radii-group" {...props}>
|
||||
{paths
|
||||
.filter(({ circle }) => circle)
|
||||
.map(({ c, prev, next, circle: { x, y, r } }) =>
|
||||
c.name === 'circle' ? (
|
||||
<path d={`M${x} ${y}h.01`} />
|
||||
) : (
|
||||
<>
|
||||
<path d={`M${prev.x} ${prev.y} ${x} ${y} ${next.x} ${next.y}`} />
|
||||
<circle cy={y} cx={x} r={r} />
|
||||
</>
|
||||
)
|
||||
)}
|
||||
{paths.map(
|
||||
({ c, prev, next, circle }, i) =>
|
||||
circle && (
|
||||
<React.Fragment key={i}>
|
||||
{c.name !== "circle" && (
|
||||
<path
|
||||
d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`}
|
||||
/>
|
||||
)}
|
||||
<circle
|
||||
cy={circle.y}
|
||||
cx={circle.x}
|
||||
r={0.25}
|
||||
strokeDasharray="0"
|
||||
stroke={
|
||||
(Math.round(circle.x * 100) / 100) % 1 !== 0 ||
|
||||
(Math.round(circle.y * 100) / 100) % 1 !== 0
|
||||
? "red"
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
<circle
|
||||
cy={circle.y}
|
||||
cx={circle.x}
|
||||
r={circle.r}
|
||||
stroke={
|
||||
(Math.round(circle.r * 1000) / 1000) % 1 !== 0
|
||||
? "red"
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
),
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
const Handles = ({
|
||||
paths,
|
||||
...props
|
||||
}: { paths: Path[] } & PathProps<
|
||||
'strokeWidth' | 'stroke' | 'strokeDasharray' | 'strokeOpacity',
|
||||
any
|
||||
>) => {
|
||||
console.log(paths);
|
||||
return (
|
||||
<g className="svg-preview-handles-group" {...props}>
|
||||
{paths.map(({ c, prev, next, cp1, cp2 }) => (
|
||||
<>
|
||||
{cp1 && <path d={`M${prev.x} ${prev.y} ${cp1.x} ${cp1.y}`} />}
|
||||
{cp1 && <circle cy={cp1.y} cx={cp1.x} r={0.25} />}
|
||||
{cp2 && <path d={`M${next.x} ${next.y} ${cp2.x} ${cp2.y}`} />}
|
||||
{cp2 && <circle cy={cp2.y} cx={cp2.x} r={0.25} />}
|
||||
</>
|
||||
))}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
@@ -238,6 +282,7 @@ const SvgPreview = React.forwardRef<
|
||||
<style>{darkModeCss}</style>
|
||||
{showGrid && <Grid strokeWidth={0.1} stroke="#777" strokeOpacity={0.3} radius={1} />}
|
||||
<Shadow paths={paths} strokeWidth={4} stroke="#777" radius={1} strokeOpacity={0.15} />
|
||||
<Handles paths={paths} strokeWidth={0.12} stroke="#777" strokeOpacity={0.6} />
|
||||
<ColoredPath
|
||||
paths={paths}
|
||||
colors={[
|
||||
@@ -263,6 +308,7 @@ const SvgPreview = React.forwardRef<
|
||||
strokeOpacity={0.3}
|
||||
/>
|
||||
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
|
||||
<Handles paths={paths} strokeWidth={0.12} stroke="#FFF" strokeOpacity={0.3} />
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -8,7 +8,9 @@ export type Path = {
|
||||
prev: Point;
|
||||
next: Point;
|
||||
isStart: boolean;
|
||||
circle: { x: number; y: number; r: number };
|
||||
circle?: { x: number; y: number; r: number };
|
||||
cp1?: Point;
|
||||
cp2?: Point;
|
||||
c: ReturnType<typeof getCommands>[number];
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export const getPaths = (src: string) => {
|
||||
c: typeof commands[number],
|
||||
next: Point,
|
||||
d?: string,
|
||||
circle?: Path['circle']
|
||||
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] }
|
||||
) => {
|
||||
assert(prev);
|
||||
paths.push({
|
||||
@@ -71,7 +71,7 @@ export const getPaths = (src: string) => {
|
||||
d: d || `M ${prev.x} ${prev.y} L ${next.x} ${next.y}`,
|
||||
prev,
|
||||
next,
|
||||
circle,
|
||||
...extras,
|
||||
isStart: start === prev,
|
||||
});
|
||||
prev = next;
|
||||
@@ -110,7 +110,10 @@ export const getPaths = (src: string) => {
|
||||
}
|
||||
case SVGPathData.CURVE_TO: {
|
||||
assert(prev);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`, {
|
||||
cp1: { x: c.x1, y: c.y1 },
|
||||
cp2: { x: c.x2, y: c.y2 },
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SVGPathData.SMOOTH_CURVE_TO: {
|
||||
@@ -146,13 +149,20 @@ export const getPaths = (src: string) => {
|
||||
y1: prev.y - reflectedCp1.y,
|
||||
x2: c.x2,
|
||||
y2: c.y2,
|
||||
})}`
|
||||
})}`,
|
||||
{
|
||||
cp1: { x: prev.x - reflectedCp1.x, y: prev.y - reflectedCp1.y },
|
||||
cp2: { x: c.x2, y: c.y2 },
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.QUAD_TO: {
|
||||
assert(prev);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`, {
|
||||
cp1: { x: c.x1, y: c.y1 },
|
||||
cp2: { x: c.x1, y: c.y1 },
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SVGPathData.SMOOTH_QUAD_TO: {
|
||||
@@ -197,7 +207,11 @@ export const getPaths = (src: string) => {
|
||||
y: c.y,
|
||||
x1: prevCP.x,
|
||||
y1: prevCP.y,
|
||||
})}`
|
||||
})}`,
|
||||
{
|
||||
cp1: { x: prevCP.x, y: prevCP.y },
|
||||
cp2: { x: prevCP.x, y: prevCP.y },
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -218,7 +232,7 @@ export const getPaths = (src: string) => {
|
||||
c,
|
||||
c,
|
||||
`M ${prev.x} ${prev.y} A${c.rX} ${c.rY} ${c.xRot} ${c.lArcFlag} ${c.sweepFlag} ${c.x} ${c.y}`,
|
||||
c.rX === c.rY ? { ...center, r: c.rX } : undefined
|
||||
{ circle: c.rX === c.rY ? { ...center, r: c.rX } : undefined }
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,41 +1,29 @@
|
||||
import {
|
||||
BUNDLED_LANGUAGES,
|
||||
type IThemeRegistration
|
||||
} from 'shiki'
|
||||
bundledLanguages,
|
||||
type ThemeRegistration
|
||||
} from 'shikiji'
|
||||
import {
|
||||
getHighlighter,
|
||||
} from 'shiki-processor'
|
||||
} from 'shikiji'
|
||||
|
||||
|
||||
type CodeExampleType = {
|
||||
title: string,
|
||||
lang: string,
|
||||
codes: {
|
||||
language?: string,
|
||||
code: string,
|
||||
metastring?: string,
|
||||
}[],
|
||||
language: string,
|
||||
code: string,
|
||||
}[]
|
||||
|
||||
const getIconCodes = (): CodeExampleType => {
|
||||
return [
|
||||
{
|
||||
lang: 'html',
|
||||
language: 'html',
|
||||
title: 'HTML',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<i data-lucide-name="Name"></i>
|
||||
`,
|
||||
},
|
||||
],
|
||||
code: `<i data-lucide="Name"></i>`
|
||||
},
|
||||
{
|
||||
lang: 'tsx',
|
||||
language: 'tsx',
|
||||
title: 'React',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-react';
|
||||
code: `import { PascalCase } from 'lucide-react';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@@ -45,17 +33,11 @@ const App = () => {
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'vue',
|
||||
title: 'Vue 3',
|
||||
codes: [
|
||||
{
|
||||
language: 'vue',
|
||||
code: `<script setup>
|
||||
language: 'vue',
|
||||
title: 'Vue',
|
||||
code: `<script setup>
|
||||
import { PascalCase } from 'lucide-vue-next';
|
||||
</script>
|
||||
|
||||
@@ -63,33 +45,21 @@ export default App;
|
||||
<PascalCase />
|
||||
</template>
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'svelte',
|
||||
language: 'svelte',
|
||||
title: 'Svelte',
|
||||
codes: [
|
||||
{
|
||||
language: 'svelte',
|
||||
code: `<script>
|
||||
code: `<script>
|
||||
import { PascalCase } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<PascalCase />
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'preact',
|
||||
language: 'tsx',
|
||||
title: 'Preact',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-preact';
|
||||
code: `import { PascalCase } from 'lucide-preact';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@@ -99,17 +69,11 @@ const App = () => {
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'solid',
|
||||
language: 'tsx',
|
||||
title: 'Solid',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-solid';
|
||||
code: `import { PascalCase } from 'lucide-solid';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@@ -119,17 +83,11 @@ const App = () => {
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'angular',
|
||||
language: 'tsx',
|
||||
title: 'Angular',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `// app.module.ts
|
||||
code: `// app.module.ts
|
||||
import { LucideAngularModule, PascalCase } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
@@ -141,54 +99,38 @@ import { LucideAngularModule, PascalCase } from 'lucide-angular';
|
||||
// app.component.html
|
||||
<lucide-icon name="Name"></lucide-icon>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'html',
|
||||
language: 'html',
|
||||
title: 'Icon Font',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<style>
|
||||
code: `<style>
|
||||
@import ('~lucide-static/font/Lucide.css');
|
||||
</style>
|
||||
|
||||
<div class="icon-Name"></div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'dart',
|
||||
title: 'Flutter',
|
||||
codes: [
|
||||
{
|
||||
language: 'dart',
|
||||
code: `Icon(LucideIcons.Name);
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export type ThemeOptions =
|
||||
| IThemeRegistration
|
||||
| { light: IThemeRegistration; dark: IThemeRegistration }
|
||||
| ThemeRegistration
|
||||
| { light: ThemeRegistration; dark: ThemeRegistration }
|
||||
|
||||
const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
||||
const highlighter = await getHighlighter({
|
||||
themes: ['material-theme-palenight'],
|
||||
langs: [...BUNDLED_LANGUAGES],
|
||||
processors: []
|
||||
themes: ['github-light', 'github-dark'],
|
||||
langs: Object.keys(bundledLanguages)
|
||||
})
|
||||
|
||||
const highlightedCode = highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
// lineOptions,
|
||||
theme: 'material-theme-palenight'
|
||||
}).replace('background-color: #292D3E', '')
|
||||
themes: {
|
||||
light: 'github-light',
|
||||
dark: 'github-dark'
|
||||
},
|
||||
defaultColor: false
|
||||
}).replace('shiki-themes', 'shiki-themes vp-code')
|
||||
|
||||
return `<div class="language-${lang} ${active ? 'active' : ''}">
|
||||
<button title="Copy Code" class="copy"></button>
|
||||
@@ -201,16 +143,15 @@ const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
||||
export default async function createCodeExamples() {
|
||||
const codes = getIconCodes();
|
||||
|
||||
const codeExamplePromises = codes.map(async (codeTemplate, index) => {
|
||||
const { title, lang, codes } = codeTemplate;
|
||||
const codeExamplePromises = codes.map(async ({ title, language, code }, index) => {
|
||||
const isFirst = index === 0;
|
||||
|
||||
const code = await highLightCode(codes[0].code, codes[0].language || lang, isFirst);
|
||||
const codeString = await highLightCode(code, language, isFirst);
|
||||
|
||||
return {
|
||||
title,
|
||||
language: codes[0].language || lang,
|
||||
code,
|
||||
language: language,
|
||||
code: codeString,
|
||||
};
|
||||
})
|
||||
|
||||
|
||||
@@ -10,28 +10,53 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
{ text: 'Comparison', link: '/guide/comparison' }
|
||||
]
|
||||
},
|
||||
// {
|
||||
// text: 'Using Icons',
|
||||
// items: [
|
||||
// {
|
||||
// text: 'How to use icons',
|
||||
// link: 'how-to-use-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Styling icons',
|
||||
// link: 'styling-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Accessibility',
|
||||
// link: 'accessibility'
|
||||
// },
|
||||
// {
|
||||
// text: 'What should I use',
|
||||
// link: 'what-should-i-use'
|
||||
// },
|
||||
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
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: 'Advanced',
|
||||
items: [
|
||||
// {
|
||||
// text: 'Accessibility',
|
||||
// link: '/guide/advanced/accessibility'
|
||||
// },
|
||||
{
|
||||
text: 'Global styling',
|
||||
link: '/guide/advanced/global-styling'
|
||||
},
|
||||
// {
|
||||
// text: 'Animations',
|
||||
// },
|
||||
{
|
||||
text: 'Filled icons',
|
||||
link: '/guide/advanced/filled-icons'
|
||||
},
|
||||
// {
|
||||
// text: 'Combining icons',
|
||||
// },
|
||||
// {
|
||||
// text: 'Dynamic imports'
|
||||
// },
|
||||
// {
|
||||
// text: 'Auto importing'
|
||||
// },
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Packages',
|
||||
items: [
|
||||
@@ -49,10 +74,6 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
},
|
||||
{
|
||||
text: 'Lucide Vue',
|
||||
link: '/guide/packages/lucide-vue'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Vue Next (Vue 3)',
|
||||
link: '/guide/packages/lucide-vue-next'
|
||||
},
|
||||
{
|
||||
@@ -75,10 +96,6 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
text: 'Lucide Static',
|
||||
link: '/guide/packages/lucide-static'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Flutter',
|
||||
link: '/guide/packages/lucide-flutter'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -103,15 +120,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}` })))
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 32px;
|
||||
padding-top: 33px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,8 +9,6 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const component = computed(() => props.href ? 'a' : 'div')
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -25,7 +23,7 @@ const component = computed(() => props.href ? 'a' : 'div')
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.badge, a.badge {
|
||||
.badge, a.badge, .vp-doc a.badge {
|
||||
display: block;
|
||||
border: 1px solid transparent;
|
||||
text-align: center;
|
||||
@@ -36,6 +34,7 @@ const component = computed(() => props.href ? 'a' : 'div')
|
||||
border-radius: 6px;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
color: var(--vp-c-text-1);
|
||||
text-decoration: none;
|
||||
/* width: 56px;
|
||||
height: 56px; */
|
||||
font-size: 16px;
|
||||
@@ -59,4 +58,6 @@ const component = computed(() => props.href ? 'a' : 'div')
|
||||
/* color: var(--vp-button-alt-active-text);
|
||||
background-color: var(--vp-button-alt-active-bg); */
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@@ -94,8 +94,7 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
|
||||
.menu {
|
||||
position: relative;
|
||||
}
|
||||
.menu-items {
|
||||
--menu-offset: 44px;
|
||||
ul.menu-items {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -103,7 +102,7 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
|
||||
padding: 12px;
|
||||
min-width: 128px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background-color: var(--vp-c-bg);
|
||||
background-color: var(--vp-c-bg-elv);
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
transition: background-color 0.5s;
|
||||
max-height: calc(100vh - var(--vp-nav-height));
|
||||
@@ -124,11 +123,12 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
|
||||
color: var(--vp-c-text-1);
|
||||
white-space: nowrap;
|
||||
transition: background-color .25s,color .25s;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
color: var(--vp-c-brand);
|
||||
background-color: var(--vp-c-bg-elv-mute);
|
||||
background-color: var(--vp-c-default-soft);
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
@@ -170,11 +170,11 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
|
||||
}
|
||||
|
||||
.menu-items.bottom {
|
||||
top: var(--menu-offset);
|
||||
top: 32px;
|
||||
}
|
||||
|
||||
.menu-items.top {
|
||||
bottom: var(--menu-offset);
|
||||
bottom: 48px;
|
||||
}
|
||||
|
||||
.arrow-up-button.top::before {
|
||||
|
||||
56
docs/.vitepress/theme/components/base/Card.vue
Normal file
56
docs/.vitepress/theme/components/base/Card.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
href?: string;
|
||||
}>()
|
||||
|
||||
const isExternal = computed(() => {
|
||||
return props.href?.startsWith('http') ?? false
|
||||
})
|
||||
|
||||
const component = computed(() => {
|
||||
return props.href ? 'a' : 'div'
|
||||
})
|
||||
|
||||
const rel = computed(() => {
|
||||
return isExternal.value ? 'noreferrer noopener' : undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="component"
|
||||
:href="href"
|
||||
:rel="rel"
|
||||
class="card"
|
||||
>
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
border: 1px solid var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card[href] {
|
||||
display: block;
|
||||
border: 1px solid var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
height: 100%;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
transition: border-color .25s,background-color .25s;
|
||||
}
|
||||
|
||||
.card[href]:hover {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
</style>
|
||||
36
docs/.vitepress/theme/components/base/CardGrid.vue
Normal file
36
docs/.vitepress/theme/components/base/CardGrid.vue
Normal file
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="grid">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
align-content: space-evenly;
|
||||
box-sizing: border-box;
|
||||
margin: -8px;
|
||||
}
|
||||
|
||||
.grid > * {
|
||||
flex-basis: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.grid > * {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.grid > * {
|
||||
flex-basis: 33.33%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineProps, onMounted } from 'vue'
|
||||
import { computed, onMounted } from 'vue'
|
||||
const props = defineProps<{
|
||||
groups: string[] | undefined,
|
||||
groupName: string,
|
||||
|
||||
@@ -54,7 +54,7 @@ const value = computed({
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.color-picker {
|
||||
background: var(--color-picker-bg, var(--vp-c-bg-soft));
|
||||
background: var(--color-picker-bg, var(--vp-c-bg-alt));
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-2);
|
||||
padding: 4px 8px;
|
||||
@@ -71,10 +71,10 @@ const value = computed({
|
||||
.color-input-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
padding: 0 0 0 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--vp-c-text-2);
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -17,7 +17,7 @@ const SearchIcon = createLucideIcon('search', search)
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-2);
|
||||
padding: 12px 16px;
|
||||
padding: 11px 16px;
|
||||
height: auto;
|
||||
font-size: 14px;
|
||||
/* box-shadow: var(--vp-shadow-4), var(--vp-shadow-2); */
|
||||
|
||||
63
docs/.vitepress/theme/components/base/GridSection.vue
Normal file
63
docs/.vitepress/theme/components/base/GridSection.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import CardGrid from './CardGrid.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
title: string,
|
||||
headingLevel: 1 | 2 | 3 | 4 | 5 | 6,
|
||||
}>()
|
||||
|
||||
const headingElement = computed(() => `h${props.headingLevel}`)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section>
|
||||
<component :is="headingElement" class="name">{{ title }}</component>
|
||||
<CardGrid>
|
||||
<slot />
|
||||
</CardGrid>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.name {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 96px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
align-content: space-evenly;
|
||||
box-sizing: border-box;
|
||||
margin: -8px;
|
||||
}
|
||||
|
||||
.grid > * {
|
||||
flex-basis: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.grid > * {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.grid > * {
|
||||
flex-basis: 33.33%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -49,7 +49,7 @@ const percentage = computed<string>(() => `${((Number(props.modelValue) - props.
|
||||
width: 100%;
|
||||
line-height: 10px;
|
||||
height: 20px;
|
||||
--bar-color: var(--slider-bar-color, var(--vp-c-bg-soft));
|
||||
--bar-color: var(--slider-bar-color, var(--vp-input-switch-bg-color));
|
||||
}
|
||||
|
||||
.slider:hover input{
|
||||
|
||||
@@ -10,7 +10,7 @@ import { data } from './HomeHeroBefore.data'
|
||||
:href="`https://github.com/lucide-icons/lucide/releases/tag/${data.version}`"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>{{ data.version }}</Badge>
|
||||
>v{{ data.version }}</Badge>
|
||||
</HomeContainer>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -67,7 +67,10 @@ watch(absoluteStrokeWidth, (enabled) => {
|
||||
Lucide has a lot of customization options to match the icons with your UI.
|
||||
</p>
|
||||
|
||||
<div class="customizer">
|
||||
<div
|
||||
class="customizer"
|
||||
style="--color-picker-bg: var(--vp-input-switch-bg-color)"
|
||||
>
|
||||
<InputField
|
||||
id="icon-color"
|
||||
label="Color"
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useCategoryView } from '../../composables/useCategoryView'
|
||||
import { useCategoryView } from '../../composables/useCategoryView';
|
||||
|
||||
interface Header {
|
||||
level: number
|
||||
title: string
|
||||
slug: string
|
||||
iconCount: number
|
||||
link: string
|
||||
children: Header[]
|
||||
level: number;
|
||||
title: string;
|
||||
slug: string;
|
||||
iconCount: number;
|
||||
link: string;
|
||||
children: Header[];
|
||||
}
|
||||
|
||||
type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
||||
children?: MenuItem[]
|
||||
}
|
||||
children?: MenuItem[];
|
||||
};
|
||||
|
||||
const props = defineProps<{
|
||||
headers: MenuItem[]
|
||||
root?: boolean
|
||||
}>()
|
||||
headers: MenuItem[];
|
||||
root?: boolean;
|
||||
}>();
|
||||
|
||||
const { selectedCategory } = useCategoryView()
|
||||
const { selectedCategory } = useCategoryView();
|
||||
|
||||
function onClick(event: Event) {
|
||||
const target = (event.target as HTMLElement).nodeName === 'span' ? (event.target as HTMLElement).parentNode : event.target as HTMLElement
|
||||
const id = '#' + (target as HTMLAnchorElement).href!.split('#')[1]
|
||||
const decodedId = decodeURIComponent(id)
|
||||
const target =
|
||||
(event.target as HTMLElement).nodeName === 'span'
|
||||
? (event.target as HTMLElement).parentNode
|
||||
: (event.target as HTMLElement);
|
||||
const href = (target as HTMLAnchorElement)?.href;
|
||||
|
||||
selectedCategory.value = decodedId.replace('#', '')
|
||||
if (href) {
|
||||
const id = '#' + href.split('#')[1];
|
||||
const decodedId = decodeURIComponent(id);
|
||||
|
||||
const heading = document.querySelector<HTMLAnchorElement>(decodedId)
|
||||
heading?.focus()
|
||||
selectedCategory.value = decodedId.replace('#', '');
|
||||
|
||||
const heading = document.querySelector<HTMLAnchorElement>(decodedId);
|
||||
heading?.focus();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul :class="root ? 'root' : 'nested'">
|
||||
<li v-for="{ children, link, title, iconCount } in headers">
|
||||
<a
|
||||
class="outline-link"
|
||||
:href="link"
|
||||
@click="onClick"
|
||||
:title="title"
|
||||
>
|
||||
<a class="outline-link" :href="link" @click="onClick" :title="title">
|
||||
<span>
|
||||
{{ title }}
|
||||
</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { startCase, camelCase } from 'lodash-es'
|
||||
import ButtonMenu from '../base/ButtonMenu.vue'
|
||||
import { useIconStyleContext } from '../../composables/useIconStyle';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { IconEntity } from '../../types'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
|
||||
import IconButton from '../base/IconButton.vue';
|
||||
import IconContributors from './IconContributors.vue';
|
||||
@@ -10,6 +10,7 @@ import { useRouter } from 'vitepress';
|
||||
import IconInfo from './IconInfo.vue';
|
||||
import Badge from '../base/Badge.vue';
|
||||
import { computedAsync } from '@vueuse/core';
|
||||
import { satisfies } from 'semver';
|
||||
|
||||
const props = defineProps<{
|
||||
iconName: string
|
||||
@@ -25,6 +26,12 @@ const icon = computedAsync<IconEntity | null>(async () => {
|
||||
const emit = defineEmits(['close'])
|
||||
const isOpen = computed(() => !!icon.value)
|
||||
|
||||
function releaseTagLink(version) {
|
||||
const shouldAddV = satisfies(version, `<0.266.0`)
|
||||
|
||||
return `https://github.com/lucide-icons/lucide/releases/tag/${shouldAddV ? 'v' : ''}${version}`
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
emit('close')
|
||||
}
|
||||
@@ -43,7 +50,7 @@ const Expand = createLucideIcon('Expand', expand)
|
||||
<Badge
|
||||
v-if="icon.createdRelease"
|
||||
class="version"
|
||||
:href="`https://github.com/lucide-icons/lucide/releases/tag/v${icon.createdRelease.version}`"
|
||||
:href="releaseTagLink(icon.createdRelease.version)"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>v{{ icon.createdRelease.version }}</Badge>
|
||||
|
||||
@@ -19,7 +19,11 @@ function setActiveIcon(name: string) {
|
||||
|
||||
<template>
|
||||
<div class="icons">
|
||||
<div class="icon" v-for="icon in icons" :key="icon.name">
|
||||
<div
|
||||
class="icon"
|
||||
v-for="icon in icons"
|
||||
:key="icon.name"
|
||||
>
|
||||
<IconItem
|
||||
v-bind="icon"
|
||||
@setActiveIcon="setActiveIcon(icon.name)"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
|
||||
import { useMediaQuery } from '@vueuse/core';
|
||||
import { useRouter } from 'vitepress';
|
||||
@@ -27,7 +28,10 @@ const showOverlay = useMediaQuery('(min-width: 860px)');
|
||||
const { animate, confetti, confettiText } = useConfetti()
|
||||
|
||||
|
||||
const icon = createLucideIcon(props.name, props.iconNode)
|
||||
const icon = computed(() => {
|
||||
if (!props.name || !props.iconNode) return null
|
||||
return createLucideIcon(props.name, props.iconNode)
|
||||
})
|
||||
|
||||
async function navigateToIcon(event) {
|
||||
|
||||
|
||||
@@ -1,93 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, defineAsyncComponent } from 'vue'
|
||||
import type { IconEntity, Category } from '../../types'
|
||||
import useSearch from '../../composables/useSearch'
|
||||
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'
|
||||
import { ref, computed, defineAsyncComponent } from 'vue';
|
||||
import type { IconEntity, Category } from '../../types';
|
||||
import useSearch from '../../composables/useSearch';
|
||||
import InputSearch from '../base/InputSearch.vue';
|
||||
import useSearchInput from '../../composables/useSearchInput';
|
||||
import StickyBar from './StickyBar.vue';
|
||||
import IconsCategory from './IconsCategory.vue';
|
||||
import useFetchTags from '../../composables/useFetchTags';
|
||||
import useFetchCategories from '../../composables/useFetchCategories';
|
||||
|
||||
const props = defineProps<{
|
||||
icons: IconEntity[]
|
||||
categories: Category[]
|
||||
iconCategories: Record<string, string[]>
|
||||
}>()
|
||||
icons: IconEntity[];
|
||||
categories: Category[];
|
||||
iconCategories: Record<string, string[]>;
|
||||
}>();
|
||||
|
||||
const activeIconName = ref(null)
|
||||
const { searchInput, searchQuery, searchQueryThrottled } = useSearchInput()
|
||||
const activeIconName = ref(null);
|
||||
const { searchInput, searchQuery, searchQueryDebounced } = useSearchInput();
|
||||
|
||||
const isSearching = computed(() => !!searchQuery.value)
|
||||
const isSearching = computed(() => !!searchQuery.value);
|
||||
|
||||
function setActiveIconName(name: string) {
|
||||
activeIconName.value = name
|
||||
activeIconName.value = name;
|
||||
}
|
||||
|
||||
const { execute: fetchTags, data: tags } = useFetchTags()
|
||||
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories()
|
||||
const { execute: fetchTags, data: tags } = useFetchTags();
|
||||
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories();
|
||||
|
||||
const mappedIcons = computed(() => {
|
||||
if(tags.value == null) {
|
||||
return props.icons
|
||||
if (tags.value == null) {
|
||||
return props.icons;
|
||||
}
|
||||
return props.icons.map((icon) => {
|
||||
const iconTags = tags.value[icon.name]
|
||||
const iconCategories = categoriesMap.value?.[icon.name] ?? []
|
||||
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 },
|
||||
])
|
||||
]);
|
||||
|
||||
const categories = computed(() => {
|
||||
if( !props.categories?.length || !props.icons?.length ) return []
|
||||
if (!props.categories?.length || !props.icons?.length) return [];
|
||||
|
||||
return props.categories.map(({ name, title }) => {
|
||||
const categoryIcons = props.icons.filter((icon) => {
|
||||
const iconCategories = props.iconCategories[icon.name]
|
||||
return props.categories
|
||||
.map(({ name, title }) => {
|
||||
const categoryIcons = props.icons.filter((icon) => {
|
||||
const iconCategories = props.iconCategories[icon.name];
|
||||
|
||||
return iconCategories?.includes(name)
|
||||
return iconCategories?.includes(name);
|
||||
});
|
||||
|
||||
const searchedCategoryIcons = isSearching
|
||||
? categoryIcons.filter((icon) =>
|
||||
searchResults.value.some((item) => item?.name === icon?.name)
|
||||
)
|
||||
: categoryIcons;
|
||||
|
||||
return {
|
||||
title,
|
||||
name,
|
||||
icons: searchedCategoryIcons,
|
||||
};
|
||||
})
|
||||
|
||||
const searchedCategoryIcons = isSearching
|
||||
? categoryIcons.filter(icon => searchResults.value.some((item) => item?.name === icon?.name))
|
||||
: categoryIcons;
|
||||
|
||||
return {
|
||||
title,
|
||||
name,
|
||||
icons: searchedCategoryIcons,
|
||||
};
|
||||
})
|
||||
.filter(({ icons }) => icons.length)
|
||||
})
|
||||
.filter(({ icons }) => icons.length);
|
||||
});
|
||||
|
||||
function onFocusSearchInput() {
|
||||
if (tags.value == null) {
|
||||
fetchTags()
|
||||
fetchTags();
|
||||
}
|
||||
if (categoriesMap.value == null) {
|
||||
fetchCategories()
|
||||
fetchCategories();
|
||||
}
|
||||
}
|
||||
|
||||
const NoResults = defineAsyncComponent(() =>
|
||||
import('./NoResults.vue')
|
||||
)
|
||||
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
|
||||
|
||||
const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
import('./IconDetailOverlay.vue')
|
||||
)
|
||||
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -100,11 +98,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
@focus="onFocusSearchInput"
|
||||
/>
|
||||
</StickyBar>
|
||||
<NoResults
|
||||
v-if="categories.length === 0"
|
||||
:searchQuery="searchQuery"
|
||||
@clear="searchQuery = ''"
|
||||
/>
|
||||
<NoResults v-if="categories.length === 0" :searchQuery="searchQuery" @clear="searchQuery = ''" />
|
||||
<IconsCategory
|
||||
v-for="category in categories"
|
||||
:key="category.name"
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, defineAsyncComponent } from 'vue'
|
||||
import type { IconEntity } from '../../types'
|
||||
import { useMediaQuery, useOffsetPagination } from '@vueuse/core'
|
||||
import IconGrid from './IconGrid.vue'
|
||||
import InputSearch from '../base/InputSearch.vue'
|
||||
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'
|
||||
import { ref, computed, watch, defineAsyncComponent } from 'vue';
|
||||
import type { IconEntity } from '../../types';
|
||||
import { useMediaQuery, useOffsetPagination } from '@vueuse/core';
|
||||
import IconGrid from './IconGrid.vue';
|
||||
import InputSearch from '../base/InputSearch.vue';
|
||||
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[]
|
||||
}>()
|
||||
icons: IconEntity[];
|
||||
}>();
|
||||
|
||||
const activeIconName = ref(null)
|
||||
const activeIconName = ref(null);
|
||||
|
||||
const isExtraLargeScreen = useMediaQuery('(min-width: 1440px)');
|
||||
const isLargeScreen = useMediaQuery('(min-width: 1280px)');
|
||||
@@ -23,84 +23,78 @@ const isMediumScreen = useMediaQuery('(min-width: 960px)');
|
||||
const isSmallScreen = useMediaQuery('(min-width: 640px)');
|
||||
|
||||
const pageSize = computed(() => {
|
||||
if(isExtraLargeScreen.value) {
|
||||
if (isExtraLargeScreen.value) {
|
||||
return 16 * 20;
|
||||
}
|
||||
if(isLargeScreen.value) {
|
||||
if (isLargeScreen.value) {
|
||||
return 16 * 12;
|
||||
}
|
||||
if(isMediumScreen.value) {
|
||||
if (isMediumScreen.value) {
|
||||
return 13 * 12;
|
||||
}
|
||||
|
||||
if(isSmallScreen.value) {
|
||||
if (isSmallScreen.value) {
|
||||
return 10 * 10;
|
||||
}
|
||||
|
||||
return 10 * 5;
|
||||
})
|
||||
});
|
||||
|
||||
const { execute: fetchTags, data: tags } = useFetchTags()
|
||||
const { execute: fetchCategories, data: categories } = useFetchCategories()
|
||||
const { execute: fetchTags, data: tags } = useFetchTags();
|
||||
const { execute: fetchCategories, data: categories } = useFetchCategories();
|
||||
|
||||
const mappedIcons = computed(() => {
|
||||
if(tags.value == null) {
|
||||
return props.icons
|
||||
if (tags.value == null) {
|
||||
return props.icons;
|
||||
}
|
||||
|
||||
return props.icons.map((icon) => {
|
||||
const iconTags = tags.value[icon.name]
|
||||
const iconCategories = categories.value?.[icon.name] ?? []
|
||||
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, mappedIcons, [
|
||||
const { searchInput, searchQuery, searchQueryDebounced } = useSearchInput();
|
||||
const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
|
||||
{ name: 'name', weight: 3 },
|
||||
{ name: 'tags', weight: 2 },
|
||||
{ name: 'categories', weight: 1 },
|
||||
])
|
||||
|
||||
const { next, currentPage } = useOffsetPagination( { pageSize })
|
||||
]);
|
||||
|
||||
const { next, currentPage } = useOffsetPagination({ pageSize });
|
||||
|
||||
const paginatedIcons = computed(() => {
|
||||
const end = pageSize.value * currentPage.value
|
||||
const end = pageSize.value * currentPage.value;
|
||||
|
||||
return searchResults.value.slice(0, end)
|
||||
})
|
||||
return searchResults.value.slice(0, end);
|
||||
});
|
||||
|
||||
function setActiveIconName(name: string) {
|
||||
activeIconName.value = name
|
||||
activeIconName.value = name;
|
||||
}
|
||||
|
||||
watch(searchQueryThrottled, (searchString) => {
|
||||
currentPage.value = 1
|
||||
})
|
||||
watch(searchQueryDebounced, (searchString) => {
|
||||
currentPage.value = 1;
|
||||
});
|
||||
|
||||
function onFocusSearchInput() {
|
||||
if (tags.value == null) {
|
||||
fetchTags()
|
||||
fetchTags();
|
||||
}
|
||||
if (categories.value == null) {
|
||||
fetchCategories()
|
||||
fetchCategories();
|
||||
}
|
||||
}
|
||||
|
||||
const NoResults = defineAsyncComponent(() =>
|
||||
import('./NoResults.vue')
|
||||
)
|
||||
|
||||
const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
import('./IconDetailOverlay.vue')
|
||||
)
|
||||
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
|
||||
|
||||
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -124,7 +118,7 @@ const IconDetailOverlay = defineAsyncComponent(() =>
|
||||
:icons="paginatedIcons"
|
||||
@setActiveIcon="setActiveIconName"
|
||||
/>
|
||||
<EndOfPage @end-of-page="next" class="bottom-page"/>
|
||||
<EndOfPage @end-of-page="next" class="bottom-page" />
|
||||
<IconDetailOverlay
|
||||
v-if="activeIconName != null"
|
||||
:iconName="activeIconName"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import {data} from './PackageList.data'
|
||||
import GridSection from '../base/GridSection.vue'
|
||||
import PackageListItem from "./PackageListItem.vue";</script>
|
||||
|
||||
<template>
|
||||
<section class="package-group">
|
||||
<h1 class="name">Packages</h1>
|
||||
<div class="grid package-list" ref="container">
|
||||
<div v-for="packageData in data.packages" class="item">
|
||||
<PackageListItem :packageData="packageData"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="package-group">
|
||||
<h2 class="name">Third-party packages</h2>
|
||||
<div class="grid package-list" ref="container">
|
||||
<div v-for="packageData in data.thirdPartyPackages" class="item">
|
||||
<PackageListItem :packageData="packageData"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<GridSection
|
||||
title="Packages"
|
||||
:headingLevel="1"
|
||||
class="package-group"
|
||||
>
|
||||
<PackageListItem
|
||||
v-for="packageData in data.packages"
|
||||
:packageData="packageData"
|
||||
/>
|
||||
</GridSection>
|
||||
|
||||
<GridSection
|
||||
title="Third-party packages"
|
||||
:headingLevel="2"
|
||||
class="package-group"
|
||||
>
|
||||
<PackageListItem
|
||||
v-for="packageData in data.thirdPartyPackages"
|
||||
:packageData="packageData"
|
||||
/>
|
||||
</GridSection>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -26,7 +32,7 @@ import PackageListItem from "./PackageListItem.vue";</script>
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.package-group {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useRouter } from 'vitepress';
|
||||
import {PackageItem} from "../../types";
|
||||
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue';
|
||||
import Card from '../base/Card.vue'
|
||||
|
||||
const { go } = useRouter()
|
||||
const props = defineProps<{
|
||||
@@ -10,48 +11,40 @@ const props = defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="package">
|
||||
<header class="package-header">
|
||||
<div class="package-icon-well">
|
||||
<img :src="packageData.icon" alt="" class="package-icon" :class="{[packageData.iconClass]: true, light: packageData.iconDark}" />
|
||||
<img v-if="packageData.iconDark" :src="packageData.iconDark" alt="" class="package-icon dark" :class="packageData.iconClass" />
|
||||
<div>
|
||||
<Card class="package">
|
||||
<header class="package-header">
|
||||
<div class="package-icon-well">
|
||||
<img :src="packageData.icon" alt="" class="package-icon" :class="{[packageData.iconClass]: true, light: packageData.iconDark}" />
|
||||
<img v-if="packageData.iconDark" :src="packageData.iconDark" alt="" class="package-icon dark" :class="packageData.iconClass" />
|
||||
</div>
|
||||
<div class="package-title">
|
||||
<h2 class="title">{{ props.packageData.name }}</h2>
|
||||
<a v-for="shield in props.packageData.shields" :href="shield.href" class="package-shield" rel="noreferrer noopener">
|
||||
<img :src="shield.src" :alt="shield.href" />
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="package-details">
|
||||
{{ packageData.description }}
|
||||
</div>
|
||||
<div class="package-title">
|
||||
<h2 class="title">{{ props.packageData.name }}</h2>
|
||||
<a v-for="shield in props.packageData.shields" :href="shield.href" class="package-shield" rel="noreferrer noopener">
|
||||
<img :src="shield.src" :alt="shield.href" />
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="package-details">
|
||||
{{ packageData.description }}
|
||||
</div>
|
||||
<footer class="package-footer">
|
||||
<VPButton
|
||||
:href="packageData.documentation"
|
||||
text="Guide"
|
||||
theme="brand"
|
||||
@click="go(packageData.documentation)"
|
||||
/>
|
||||
<VPButton
|
||||
:href="packageData.source"
|
||||
text="Source"
|
||||
theme="alt"
|
||||
@click="go(packageData.source)"
|
||||
/>
|
||||
</footer>
|
||||
</article>
|
||||
<footer class="package-footer">
|
||||
<VPButton
|
||||
:href="packageData.documentation"
|
||||
text="Guide"
|
||||
theme="brand"
|
||||
/>
|
||||
<VPButton
|
||||
:href="packageData.source"
|
||||
text="Source"
|
||||
theme="alt"
|
||||
/>
|
||||
</footer>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.package {
|
||||
border: 1px solid var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
}
|
||||
.package {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
72
docs/.vitepress/theme/components/showcase/ShowcaseList.vue
Normal file
72
docs/.vitepress/theme/components/showcase/ShowcaseList.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
import companies from '../../../data/companiesData.json'
|
||||
import componentLibraries from '../../../data/componentLibrariesData.json'
|
||||
import GridSection from '../base/GridSection.vue'
|
||||
import ShowcaseListItem from "./ShowcaseListItem.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<GridSection
|
||||
title="Used by"
|
||||
:headingLevel="1"
|
||||
class="package-group"
|
||||
>
|
||||
<ShowcaseListItem
|
||||
v-for="company in companies"
|
||||
:showcaseItem="company"
|
||||
/>
|
||||
</GridSection>
|
||||
|
||||
<GridSection
|
||||
title="Used in"
|
||||
:headingLevel="1"
|
||||
class="package-group"
|
||||
>
|
||||
<ShowcaseListItem
|
||||
v-for="componentLibrary in componentLibraries"
|
||||
:showcaseItem="componentLibrary"
|
||||
/>
|
||||
</GridSection>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.name {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.package-group {
|
||||
margin-bottom: 96px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
align-content: space-evenly;
|
||||
box-sizing: border-box;
|
||||
margin: -8px;
|
||||
}
|
||||
|
||||
.grid > * {
|
||||
flex-basis: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.grid > * {
|
||||
flex-basis: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.grid > * {
|
||||
flex-basis: 33.33%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vitepress';
|
||||
import { ShowcaseItem } from "../../types";
|
||||
import Card from '../base/Card.vue'
|
||||
|
||||
const { go } = useRouter()
|
||||
defineProps<{
|
||||
showcaseItem: ShowcaseItem,
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Card
|
||||
class="company"
|
||||
:href="showcaseItem.url"
|
||||
:aria-label="showcaseItem.name"
|
||||
>
|
||||
<img
|
||||
:src="showcaseItem.image.light"
|
||||
class="logo light"
|
||||
:alt="`${showcaseItem.name} logo`"
|
||||
/>
|
||||
<img
|
||||
:src="showcaseItem.image.dark"
|
||||
class="logo dark"
|
||||
:alt="`${showcaseItem.name} logo`"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.company {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 48px 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height:64px;
|
||||
width: 240px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
html.dark .logo.dark {
|
||||
display: none;
|
||||
}
|
||||
html:not(.dark) .logo.light {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -1,43 +1,41 @@
|
||||
import { refThrottled } from '@vueuse/core';
|
||||
import { useDebounce } from '@vueuse/core';
|
||||
import { nextTick, onMounted, ref, watch } from 'vue';
|
||||
|
||||
const useSearchInput = () => {
|
||||
const searchInput = ref()
|
||||
const searchQuery = ref(
|
||||
typeof window === 'undefined'
|
||||
? ''
|
||||
: (
|
||||
new URLSearchParams(window.location.search).get('search')
|
||||
|| ''
|
||||
)
|
||||
)
|
||||
const searchQueryThrottled = refThrottled(searchQuery, 400)
|
||||
const searchInput = ref();
|
||||
const searchQuery = ref<string>('');
|
||||
const searchQueryDebounced = useDebounce<string>(searchQuery, 200);
|
||||
|
||||
watch(searchQueryThrottled, (searchString) => {
|
||||
watch(searchQueryDebounced, (searchString) => {
|
||||
const newUrl = new URL(window.location.href);
|
||||
|
||||
if(searchString === '') {
|
||||
if (searchString === '') {
|
||||
newUrl.searchParams.delete('search');
|
||||
} else {
|
||||
newUrl.searchParams.set('search', searchString);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
window.history.replaceState({}, '', newUrl)
|
||||
})
|
||||
})
|
||||
window.history.replaceState({}, '', newUrl);
|
||||
});
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
if(searchParams.has('focus')) {
|
||||
searchInput.value.focus()
|
||||
|
||||
if (searchParams.has('search')) {
|
||||
searchQuery.value = searchParams.get('search');
|
||||
}
|
||||
})
|
||||
|
||||
if (searchParams.has('focus')) {
|
||||
searchInput.value.focus();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
searchInput,
|
||||
searchQuery,
|
||||
searchQueryThrottled
|
||||
searchQueryDebounced,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
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,56 @@
|
||||
html:has(* .outline-link:target) {
|
||||
scroll-behavior: smooth;
|
||||
} */
|
||||
|
||||
.sp-wrapper + * {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
@@ -44,3 +44,14 @@ export interface Release {
|
||||
version: string
|
||||
date: string
|
||||
}
|
||||
|
||||
interface ShowcaseItemImage {
|
||||
light: string
|
||||
dark: string
|
||||
}
|
||||
|
||||
export interface ShowcaseItem {
|
||||
name: string
|
||||
url: string
|
||||
image: ShowcaseItemImage
|
||||
}
|
||||
|
||||
@@ -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 -->
|
||||
23
docs/guide/advanced/examples/filled-icon-example/App.js
Normal file
23
docs/guide/advanced/examples/filled-icon-example/App.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Star, StarHalf } from "lucide-react";
|
||||
import "./icon.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="star-rating">
|
||||
<div className="stars">
|
||||
{ Array.from({ length: 5 }, () => (
|
||||
<Star fill="#111" strokeWidth={0} />
|
||||
))}
|
||||
</div>
|
||||
<div className="stars rating">
|
||||
<Star fill="yellow" strokeWidth={0} />
|
||||
<Star fill="yellow" strokeWidth={0} />
|
||||
<StarHalf fill="yellow" strokeWidth={0} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
20
docs/guide/advanced/examples/filled-icon-example/files.ts
Normal file
20
docs/guide/advanced/examples/filled-icon-example/files.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../../../basics/examples/styles.css?raw'
|
||||
import IconCss from './icon.css?raw'
|
||||
|
||||
const files = {
|
||||
'App.js': {
|
||||
code: App,
|
||||
active: true,
|
||||
},
|
||||
'icon.css': {
|
||||
code: IconCss,
|
||||
readOnly: false,
|
||||
},
|
||||
'styles.css': {
|
||||
code: styles,
|
||||
hidden: true
|
||||
},
|
||||
}
|
||||
|
||||
export default files
|
||||
14
docs/guide/advanced/examples/filled-icon-example/icon.css
Normal file
14
docs/guide/advanced/examples/filled-icon-example/icon.css
Normal file
@@ -0,0 +1,14 @@
|
||||
.star-rating {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stars {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.rating {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
TentTree,
|
||||
Caravan,
|
||||
FlameKindling,
|
||||
MountainSnow,
|
||||
Trees,
|
||||
Axe,
|
||||
Map,
|
||||
CloudMoon,
|
||||
Sparkles,
|
||||
} from "lucide-react";
|
||||
import "./icon.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<TentTree />
|
||||
<Caravan />
|
||||
<FlameKindling />
|
||||
<MountainSnow />
|
||||
<Trees />
|
||||
<Axe />
|
||||
<Map />
|
||||
<CloudMoon />
|
||||
<Sparkles />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,20 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../../../basics/examples/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,16 @@
|
||||
.lucide {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
stroke-width: 1.5;
|
||||
}
|
||||
|
||||
.lucide * {
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
CakeSlice,
|
||||
Candy,
|
||||
Apple,
|
||||
Cookie,
|
||||
Martini,
|
||||
IceCream2,
|
||||
Sandwich,
|
||||
Wine,
|
||||
Dessert,
|
||||
} from "lucide-react";
|
||||
import "./icon.css";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<CakeSlice />
|
||||
<Candy />
|
||||
<Apple />
|
||||
<Cookie />
|
||||
<Martini />
|
||||
<IceCream2 />
|
||||
<Sandwich />
|
||||
<Wine />
|
||||
<Dessert />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,20 @@
|
||||
import App from './App.js?raw'
|
||||
import styles from '../../../basics/examples/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,14 @@
|
||||
.lucide {
|
||||
/* Change this! */
|
||||
color: #ffadff;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.app {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr;
|
||||
gap: 6px;
|
||||
}
|
||||
31
docs/guide/advanced/filled-icons.md
Normal file
31
docs/guide/advanced/filled-icons.md
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup>
|
||||
import { Sandpack } from 'sandpack-vue3'
|
||||
import sandpackTheme from '../../.vitepress/theme/sandpackTheme.json'
|
||||
import sizeIconExample from './examples/filled-icon-example/files.ts'
|
||||
</script>
|
||||
|
||||
# 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:
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="sizeIconExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 480,
|
||||
editorWidthPercentage: 60,
|
||||
}"
|
||||
/>
|
||||
|
||||
## Will Lucide have fills in the future?
|
||||
|
||||
This feature has been requested several times and discussion is happening at [#458](https://github.com/lucide-icons/lucide/discussions/458).
|
||||
55
docs/guide/advanced/global-styling.md
Normal file
55
docs/guide/advanced/global-styling.md
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup>
|
||||
import { Sandpack } from 'sandpack-vue3'
|
||||
import sandpackTheme from '../../.vitepress/theme/sandpackTheme.json'
|
||||
import globalIconCssExample from './examples/global-styling-css-example/files.ts'
|
||||
import globalAbsoluteStrokewidthExample from './examples/global-styling-absolute-strokewidth-example/files.ts'
|
||||
|
||||
</script>
|
||||
|
||||
# Global Styling
|
||||
|
||||
Adjusting icons can be done by [color](../basics/color.md), [size](../basics/sizing.md) and [stroke width](../basics/stroke-width.md).
|
||||
|
||||
By default, all icons have a **color** value of `currentColor`, a **size** value of `24px`, and a **stroke width** of `2`. Styling icons individually can be done by passing props to the icon component.
|
||||
|
||||
## Style by using CSS
|
||||
Styling icons is easy to accomplish using CSS.
|
||||
|
||||
Every icon has a class attribute applied called `lucide`. This class name can be used in the CSS file to target all icons that are being used within the app.
|
||||
|
||||
- The **color** of the icons can be changed using the [`color`](https://developer.mozilla.org/en-US/docs/Web/CSS/color) CSS property.
|
||||
- The **size** of the icons can be changed using [`width`](https://developer.mozilla.org/en-US/docs/Web/CSS/width) and [`height`](https://developer.mozilla.org/en-US/docs/Web/CSS/height) CSS properties.
|
||||
- The **stroke width** of the icons can be changed using the [`stroke-width`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-width) CSS property.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="globalIconCssExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
}"
|
||||
/>
|
||||
|
||||
### Absolute stroke width
|
||||
|
||||
For global absolute stroke width styling the `vector-effect: non-scaling-stroke` CSS property can be applied to the children. This will keep the stroke-width the same size no matter the size of the icon. See [absolute-stroke-width](../basics/stroke-width.md#absolute-stroke-width) for more info.
|
||||
|
||||
<Sandpack
|
||||
template="react"
|
||||
:theme="sandpackTheme"
|
||||
:files="globalAbsoluteStrokewidthExample"
|
||||
:customSetup='{
|
||||
dependencies: {
|
||||
"lucide-react": "latest"
|
||||
}
|
||||
}'
|
||||
:options="{
|
||||
editorHeight: 300,
|
||||
}"
|
||||
/>
|
||||
|
||||
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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user