Compare commits

...
40 Commits
Author SHA1 Message Date
f664af1933 feat(icons): added webcam-off icon (#4242)
* Added icons/webcam-off.svg

* Added icons/webcam-off.json

* Update webcam-off.svg

Co-authored-by: Karsa <contact@karsa.org>

* Update webcam-off.json

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-12 14:38:04 +02:00
Eric FennisandCopilot Autofix powered by AI 03ad294db0 fix(ci): add check to skip release if latest tag was created today (#4085)
* fix(ci): add check to skip release if latest tag was created today

* Apply dispatch gate to the ci workflow

* Fix ci

* Revert svg changes

* Revert svg

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Format ci file

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-12 14:27:59 +02:00
Karsa a2ec77fc7f feat(packages/angular): remove upper limit for peer dependencies, as the risk of breakage is very little (#4450) 2026-06-11 15:03:02 +02:00
Alec Glassford 602bca62a2 fix(docs): Remove @next from installation instructions for@lucide/svelte (#4432)
Installing `@lucide/svelte@next` currently gets version 1.3.0, which is out of date compared to installing `@lucide/svelte` (aka `@lucide/svelte@latest`), which gets version 1.17.0. It seems to make more sense to instruct users to get the latest version.

This change matches identical changes to the getting-started guides for other frameworks in 5f83bbf7e7 - it seems like the omission of Svelte was likely an oversight (?)
2026-06-09 09:57:13 +02:00
KarsaandEric Fennis 423afc6d03 fix(): force hide #bb-banner, if html.has-bb-banner is missing (#4422)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-05-30 17:39:05 +02:00
KarsaandEric Fennis 374398b58d fix(metadata): add missing use-cases prop on play-off.json (#4423)
* fix: add missing use-cases prop on play-off.json

* Apply suggestion from @ericfennis

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-05-30 15:28:33 +02:00
Ahmed Dghaiesgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AI
6c2b8e6fa0 feat(icons): added play-off icon (#4412)
* Added icons/no-play.svg

* Added icons/no-play.json

* Update icons/no-play.json

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update no-play.svg

* Update no-play.json

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Update and rename no-play.json to play-off.json

* Rename no-play.svg to play-off.svg

* Update play-off.svg

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-28 10:53:16 +02:00
Eric Fennis ecc612044e chore(site): Remove survey from site (#4417)
* chore(site): Remove survey from site

* Add usecases to parasol
2026-05-28 10:49:54 +02:00
KarsaandEric Fennis 896aba0d19 feat(icons): added parasol icon (#4347)
* feat(github): create release-angular.yml for testing purposes

* Update release-angular.yml

* Update release-angular.yml

* Added icons/parasol.svg

* Added icons/parasol.json

* Delete .github/workflows/release-angular.yml

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-05-28 10:20:16 +02:00
Eric FennisandCopilot 45740bef8b feat(metadata): Require use-cases in meta json (#4321)
* Require use-cases in meta json

Co-authored-by: Copilot <copilot@github.com>

* adjust schema

* Adjust icon meta json files

* Add usecases to tags.json

---------

Co-authored-by: Copilot <copilot@github.com>
2026-05-28 10:15:02 +02:00
BarakudumandKarsa 84ab8524b5 feat(icon): added globe-check (#4342)
Co-authored-by: Karsa <contact@karsa.org>
2026-05-27 13:45:13 +02:00
Eric FennisandCopilot Autofix powered by AI 071e4d2738 feat(copilot): Adding copilot instructions (#4407)
* Adding copilot instructions

* Adjust text

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Add contributors to schema

* Adjust headers

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-22 16:08:38 +02:00
Eric Fennisandcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> 3c9d1a56a4 Update deps (#4377)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-05-22 12:58:05 +02:00
Jakob Guddas c20dd8464d fix: limit icon size to a maximum of 256 pixels (#4398)
Ensure icon size does not exceed 256 pixels.
2026-05-22 12:04:48 +02:00
dependabot[bot] 29af709846 chore(deps): bump ws from 8.18.0 to 8.20.1 (#4392) 2026-05-22 10:03:13 +02:00
dependabot[bot] 410dfc3577 chore(deps): bump devalue from 5.8.0 to 5.8.1 (#4391) 2026-05-22 10:03:01 +02:00
dependabot[bot] 574e156701 chore(deps): bump @tootallnate/once from 2.0.0 to 2.0.1 (#4404) 2026-05-22 09:56:47 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 22cfe96931 chore(deps): bump brace-expansion from 1.1.11 to 5.0.6 (#4386)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 5.0.6.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v5.0.6)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 11:38:51 +02:00
Jamie Law 1475fc02e0 fix(icons): changed martini icon (#4335)
* Updated icons/martini.svg

* Updated icons/martini.json

* Don't round bottom of glass

Also increase the size of the base to make the glass a little less top-heavy

* Update tags for `martini`
2026-05-20 11:35:37 +02:00
Eric FennisandCopilot Autofix powered by AI 7f14e74e4d feat(site): Certificate dev links (#4390)
* Update readme

* Add carbon ads component

* Adjust config

* Adjust ads

* minor fixes

* Remove script

* Place back script

* Add cert link component

* add certificates link

* Adds new images

* Formatting

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-20 11:34:51 +02:00
Eric Fennis 5b40f2c5a7 feat(site): Adds survey overlay to website (#4380)
* Finalize overlay

* Minor fix

* Remove if

* cleanup

* Revert theme config change

* Remove comments

* Format code

* Use localstorage instead of session storage

* Improve css

* Update old-package link
2026-05-15 18:36:44 +02:00
Eric Fennis bac39e6c53 chore(repo): Update issue templates and documentation for package ren… (#4379)
* chore(repo): Update issue templates and documentation for package renaming and deprecations

* Format code

* Remove flutter label

* Format code
2026-05-15 17:55:33 +02:00
Eric Fennis 523026ac18 chore(lucide-vue-next|lucide-svelte|lucide-angular): Remove deprecated packages (#4376)
* Remove deprecated packages

* Remove `lucide-angular` package

* Remove workflow

* Update lock file
2026-05-15 15:03:42 +02:00
Rodrigo Rodrigues 2214caa407 feat(icons): added blender icon (#3884)
* original/blender: add  icon

* fix typo in tags, clean tags

* srhink width by 1px
2026-05-14 13:39:44 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 105f501730 chore(deps-dev): bump astro from 6.1.6 to 6.1.10 (#4361)
Bumps [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) from 6.1.6 to 6.1.10.
- [Release notes](https://github.com/withastro/astro/releases)
- [Changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md)
- [Commits](https://github.com/withastro/astro/commits/astro@6.1.10/packages/astro)

---
updated-dependencies:
- dependency-name: astro
  dependency-version: 6.1.10
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-14 13:29:14 +02:00
BarakudumandKarsa 5f787f956b feat(icons): added sticky note variants (#4348)
* feat(icons): added `sticky-note` variants

* feat(icons): added `sticky-notes`

* applied requested changes from @karsa-mistmere

Co-authored-by: Karsa <contact@karsa.org>

---------

Co-authored-by: Karsa <contact@karsa.org>
2026-05-14 13:28:36 +02:00
Eric Fennis 437c370821 chore(site): Updates to site and updated carbon ads (#4359)
* Update readme

* Add carbon ads component

* Adjust config

* Adjust ads

* minor fixes

* Remove script

* Remove commented code

* Revert icon changes

* Format code

* Apply some feedback from Copilot
2026-05-12 08:09:01 +02:00
Eric Fennis fb885f333a Merge branch 'main' of https://github.com/lucide-icons/lucide 2026-05-11 19:31:00 +02:00
Eric Fennis 71ec48ce30 chore: Remove npm lock file 2026-05-11 19:30:54 +02:00
Swastik Sharmagithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Jakob Guddas
d624fc51ab feat(icon): added broccoli icon (#4263)
* feat(icon): add broccoli icon against issue#4094

* Update icons/broccoli.json

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(icons): tilt broccoli icon to 45 degrees and update contributors

* Modify broccoli SVG paths for updated design

* Update contributors in broccoli.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jakob Guddas <github@jguddas.de>
2026-05-11 19:20:49 +02:00
Jakob Guddas 1c381a075c fix(icons): changed chart-no-axes-combined icon (#3567)
* Updated icons/chart-no-axes-combined.svg

* Updated icons/chart-no-axes-combined.json
2026-05-11 19:17:24 +02:00
Jamie LawandJakob Guddas a168a87834 fix(icons): changed volleyball icon (#4338)
* Updated icons/volleyball.svg

* Updated icons/volleyball.json

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2026-05-11 19:13:17 +02:00
Jakob Guddas 7e9def13a6 fix(icons): changed candy-cane icon (#4148)
* Updated icons/candy-cane.svg

* Updated icons/candy-cane.json
2026-05-11 19:12:44 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 228c86ed12 chore(deps-dev): bump simple-git from 3.33.0 to 3.36.0 (#4349)
Bumps [simple-git](https://github.com/steveukx/git-js/tree/HEAD/simple-git) from 3.33.0 to 3.36.0.
- [Release notes](https://github.com/steveukx/git-js/releases)
- [Changelog](https://github.com/steveukx/git-js/blob/main/simple-git/CHANGELOG.md)
- [Commits](https://github.com/steveukx/git-js/commits/simple-git@3.36.0/simple-git)

---
updated-dependencies:
- dependency-name: simple-git
  dependency-version: 3.36.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-11 19:11:18 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 50b7038d27 chore(deps-dev): bump nitropack from 2.13.1 to 2.13.4 (#4352)
Bumps [nitropack](https://github.com/nitrojs/nitro) from 2.13.1 to 2.13.4.
- [Release notes](https://github.com/nitrojs/nitro/releases)
- [Changelog](https://github.com/nitrojs/nitro/blob/main/changelog.config.ts)
- [Commits](https://github.com/nitrojs/nitro/compare/v2.13.1...v2.13.4)

---
updated-dependencies:
- dependency-name: nitropack
  dependency-version: 2.13.4
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-11 19:10:30 +02:00
Jamie Law a51e94b25c fix(icons): changed landmark icon (#4334)
* Updated icons/landmark.svg

* Updated icons/landmark.json

* Update tags for `landmark`
2026-05-08 09:55:11 +02:00
Jamie LawandJakob Guddas 3d7a12949b fix(icons): changed text-cursor icon (#4340)
* Updated icons/text-cursor.svg

* Updated icons/text-cursor.json

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2026-05-08 09:53:23 +02:00
Karsa 07c885e6c1 fix(docs): fix zephyr-cloud URL in readmes 2026-05-07 15:35:49 +02:00
Thomas HochstetterandAxtho 446e644e63 fix(vue): clone slots before passing to icon (#4339)
Co-authored-by: Axtho <th@ebtc.org>
2026-05-01 14:52:32 +02:00
Jakob Guddas 6d38f90429 fix: remove 'less' from brand stopwords (#4331) 2026-04-30 10:42:58 +02:00
1856 changed files with 4846 additions and 17481 deletions
+9 -11
View File
@@ -13,21 +13,19 @@ body:
description: Which Lucide packages are affected? You may select more than one.
options:
- label: lucide
- label: lucide-angular (old version)
- label: '@lucide/angular (new version)'
- label: '@lucide/astro'
- label: lucide-flutter
- label: lucide-preact
- label: lucide-react
- label: '@lucide/vue'
- label: '@lucide/svelte'
- label: '@lucide/angular'
- label: '@lucide/astro'
- label: lucide-react-native
- label: lucide-preact
- label: lucide-solid
- label: lucide-static
- label: lucide-svelte (old version)
- label: '@lucide/svelte (new version)'
- label: lucide-vue
- label: lucide-vue-next
- label: lucide-astro
- label: '@lucide/icons'
- label: lucide-vue-next (deprecated)
- label: lucide-svelte (deprecated)
- label: lucide-angular (deprecated)
- label: Figma plugin
- label: source/main
- label: other/not relevant
@@ -38,7 +36,7 @@ body:
attributes:
label: Version
description: What version of Lucide are you running?
placeholder: e.g. 0.289.1
placeholder: e.g. 1.1.0
validations:
required: true
- type: checkboxes
+8 -10
View File
@@ -13,21 +13,19 @@ body:
description: Which Lucide project do you wish this feature were added to? You may select more than one.
options:
- label: lucide
- label: lucide-angular (old version)
- label: '@lucide/angular (new version)'
- label: '@lucide/astro'
- label: lucide-flutter
- label: lucide-preact
- label: lucide-react
- label: '@lucide/vue'
- label: '@lucide/svelte'
- label: '@lucide/angular'
- label: '@lucide/astro'
- label: lucide-react-native
- label: lucide-preact
- label: lucide-solid
- label: lucide-static
- label: lucide-svelte (old version)
- label: '@lucide/svelte (new version)'
- label: lucide-vue
- label: lucide-vue-next
- label: lucide-astro
- label: '@lucide/icons'
- label: lucide-vue-next (deprecated)
- label: lucide-svelte (deprecated)
- label: lucide-angular (deprecated)
- label: Figma plugin
- label: all JS packages
- label: site
+8
View File
@@ -0,0 +1,8 @@
## Reviewing PRs
When reviewing PRs, please respond in a friendly and constructive manner.
- First, thank the contributor for their contribution in an enthusiastic way.
- If you have any suggestions for improvement, provide them clearly and concisely.
- If you have any questions about the PR, ask them respectfully.
- Let the contributor know that we have many PRs to review and that we appreciate their patience while we review their contribution.
@@ -0,0 +1,20 @@
---
applyTo: "icons/*.json"
---
# JSON Metadata Descriptor
The schema for the JSON metadata descriptor can be found in `icon.schema.json`. It defines the required and optional properties for the JSON files that accompany each icon. The JSON metadata descriptor should be placed in the same directory as the SVG file of the icon and should have the same name as the SVG file, but with a `.json` extension. For example, if the SVG file is named `home.svg`, the JSON metadata descriptor should be named `home.json`.
## Contributors
The `contributors` property is a required array of GitHub usernames for the people who created or contributed to the icon. It is used to give credit to contributors and to track the icon's history. Add the PR author to the `contributors` array if they are not already listed and they have made a significant contribution to the icon's SVG.
## Tags
The `tags` property is an array of strings that describe the icon and can be used for searching.
Validate the tags against the `icon.schema.json` to ensure they are correctly formatted and adhere to the defined structure.
Provide tag suggestions based on the name of the icon and the use cases provided in the PR description. Use the existing tags in the repository as a reference for consistency and to avoid duplicates. Don't suggest words like: 'icon' and preferably use single words. Tags should always be in lowercase and should not contain spaces. The name of icon should not be included in the tags, as it is already specified.
# Categories
The `categories` property is an array of strings that specify the categories to which the icon belongs, such as "devices", "interface", "media", etc. See the `categories` property in the `icon.schema.json` for more details on the allowed values. The categories should be chosen based on the use cases provided in the PR description and the existing categories in the repository. The categories should be relevant to the icon and should help users find the icon when searching for specific types of icons. The name of icon should not be included in the categories, as it is already specified. Suggest categories based on the name of the icon and the use cases provided in the PR description. Use the existing categories in the repository as a reference for consistency and to avoid duplicates. Categories should always be in lowercase and should not contain spaces.
+2 -10
View File
@@ -52,15 +52,13 @@
💎 vue package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-vue/*'
- 'packages/lucide-vue-next/*'
- 'packages/vue/*'
# For changes in the Lucide angular package
🅰️ angular package:
- changed-files:
- any-glob-to-any-file:
- 'packages/angular/*'
- 'packages/lucide-angular/*'
# For changes in the Lucide preact package
⚛️ preact package:
@@ -72,7 +70,7 @@
🧣 svelte package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-svelte/*'
- 'packages/svelte/*'
# For changes in the Lucide solid package
🪝 solid package:
@@ -97,9 +95,3 @@
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-static/*'
# For changes in the Lucide flutter package
🏹 flutter package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-flutter/*'
+30 -1
View File
@@ -32,8 +32,37 @@ concurrency:
group: continuous-integration
jobs:
check-dispatch-gate:
if: github.repository == 'lucide-icons/lucide' &&
startsWith(github.event.head_commit.message, 'feat(icons)') &&
github.event_name != 'workflow_dispatch'
runs-on: ubuntu-latest
outputs:
RELEASE_ENVIRONMENT: ${{ steps.environment.outputs.RELEASE_ENVIRONMENT }}
steps:
- uses: actions/checkout@v6
- name: Fetch tags
run: git fetch --all --tags
- name: Check if latest tag was created today
id: environment
run: |
LATEST_TAG=$(git tag --sort=-v:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1)
TAG_DATE=$(git log -1 --format=%cs "$LATEST_TAG")
TODAY=$(date +%Y-%m-%d)
if [ "$TAG_DATE" == "$TODAY" ]; then
echo "::warning::A release tag already exists for today ($TODAY): $LATEST_TAG. Manual approval will be required to proceed."
echo "RELEASE_ENVIRONMENT=Icon Release Gated" >> $GITHUB_OUTPUT
else
echo "RELEASE_ENVIRONMENT=Icon Release" >> $GITHUB_OUTPUT
fi
create-release:
if: github.repository == 'lucide-icons/lucide' && startsWith(github.event.head_commit.message, 'feat(icons)') && github.event_name != 'workflow_dispatch'
if: github.repository == 'lucide-icons/lucide'
needs: check-dispatch-gate
environment: ${{ needs.check-dispatch-gate.outputs.RELEASE_ENVIRONMENT }}
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.new-version.outputs.NEW_VERSION }}
-44
View File
@@ -1,44 +0,0 @@
name: Lucide Angular checks
on:
push:
branches:
- next
pull_request:
paths:
- packages/lucide-angular/**
- tools/build-icons/**
- pnpm-lock.yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm --filter lucide-angular build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Test
run: pnpm --filter lucide-angular test
-46
View File
@@ -1,46 +0,0 @@
name: Lucide Svelte checks
on:
push:
branches:
- next
pull_request:
paths:
- packages/lucide-svelte/**
- packages/shared/**
- tools/build-icons/**
- tools/rollup-plugins/**
- pnpm-lock.yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm --filter lucide-svelte build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Test
run: pnpm --filter lucide-svelte test
-46
View File
@@ -1,46 +0,0 @@
name: Lucide Vue Next checks
on:
push:
branches:
- next
pull_request:
paths:
- packages/lucide-vue-next/**
- packages/shared/**
- tools/build-icons/**
- tools/rollup-plugins/**
- pnpm-lock.yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm --filter lucide-vue-next build
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Test
run: pnpm --filter lucide-vue-next test
+1
View File
@@ -39,6 +39,7 @@ packages/**/LICENSE
categories.json
tags.json
.vercel
package-lock.json
# docs
docs/.vitepress/cache
+5 -4
View File
@@ -7,8 +7,8 @@ docs/.vitepress/cache
docs/.vitepress/data
docs/.nitro
# lucide-angular
packages/lucide-angular/.angular/cache
# @lucide/angular
packages/angular/.angular
# lucide-static
packages/lucide-static/icons
@@ -17,7 +17,8 @@ packages/lucide-static/sprite.svg
packages/lucide-static/tags.json
packages/lucide-static/icon-nodes.json
packages/lucide-static/font
packages/svelte/.svelte-kit
# lucide-svelte
packages/lucide-svelte/src/icons/*.svelte
packages/lucide-svelte/.svelte-kit
packages/svelte/src/icons/*.svelte
packages/svelte/.svelte-kit
+1 -1
View File
@@ -92,7 +92,7 @@ Thank you to all the people who contributed to Lucide!
### Hero backers 🦸
<a href="https://https://zephyr-cloud.io/"><img src="docs/public/sponsors/zephyr-cloud.svg" width="180" alt="Zephyr Cloud – From idea to prod: fast micro-frontend delivery!" /></a>
<a href="https://zephyr-cloud.io/"><img src="docs/public/sponsors/zephyr-cloud.svg" width="180" alt="Zephyr Cloud – From idea to prod: fast micro-frontend delivery!" /></a>
### Awesome backers 🍺
-1
View File
@@ -54,7 +54,6 @@
"jira": "Jira",
"kotlin": "Kotlin",
"kubernetes": "Kubernetes",
"less": "Less",
"leetcode": "LeetCode",
"leet-code": "LeetCode",
"line": "LINE",
@@ -11,7 +11,7 @@ export default eventHandler(async (event) => {
const name = params.data.split('/').at(-3);
const iconSizeString = params.data.split('/').at(-2);
const svgData = params.data.split('/').at(-1);
const iconSize = parseInt(iconSizeString, 10);
const iconSize = Math.min(parseInt(iconSizeString, 10) || imageSize, 256);
const data = svgData.slice(0, -4);
const prevSvg = iconNodes[name]
+12 -194
View File
@@ -1,14 +1,14 @@
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vitepress';
import { defineConfig, UserConfig } from 'vitepress';
import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-icons';
import sidebar from './sidebar';
import snackPlayer from './markdown/snackPlayer';
import sandpackPlugin from './markdown/sandpack';
import { readFile } from 'node:fs/promises';
import { resourcesSidebar } from './sidebar/resources';
import getStructuredData from './getStructuredData';
import { createGeneralOGImage, createIconOGImage } from './createOGImage';
import llmstxt from 'vitepress-plugin-llms';
import { transformPageData } from './transformPageData';
import getHeadConfig from './getHeadConfig';
const defaultSandpackCSS = await readFile(
fileURLToPath(new URL('./theme/sandpack-default.css', import.meta.url)),
@@ -56,6 +56,12 @@ export default defineConfig({
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url),
),
},
{
find: /^.*\/VPCarbonAds\.vue$/,
replacement: fileURLToPath(
new URL('./theme/components/overrides/VPCarbonAds.vue', import.meta.url),
),
},
{
find: '~/.vitepress',
replacement: fileURLToPath(new URL('./', import.meta.url)),
@@ -73,199 +79,11 @@ export default defineConfig({
'brand-logo-statement.md',
'icons/**', // Not working, need investigation
],
}),
}) as unknown as UserConfig['vite']['plugins'][0],
],
},
head: [
[
'link',
{
rel: 'preconnect',
href: 'https://analytics.lucide.dev',
},
],
[
'script',
{
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: '',
},
],
[
'meta',
{
property: 'og:locale',
content: 'en_US',
},
],
[
'meta',
{
property: 'og:type',
content: 'website',
},
],
[
'meta',
{
property: 'og:site_name',
content: title,
},
],
[
'meta',
{
property: 'og:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'og:description',
content: description,
},
],
[
'meta',
{
property: 'og:url',
content: 'https://lucide.dev',
},
],
[
'meta',
{
property: 'og:image',
content: 'https://lucide.dev/og.png',
},
],
[
'meta',
{
property: 'og:image:width',
content: '1200',
},
],
[
'meta',
{
property: 'og:image:height',
content: '630',
},
],
[
'meta',
{
property: 'og:image:type',
content: 'image/png',
},
],
[
'meta',
{
property: 'twitter:card',
content: 'summary_large_image',
},
],
[
'meta',
{
property: 'twitter:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'twitter:description',
content: description,
},
],
[
'meta',
{
property: 'twitter:image',
content: 'https://lucide.dev/og.png',
},
],
],
async transformPageData(pageData) {
pageData.frontmatter.head ??= [];
if (
pageData.relativePath.startsWith('icons/') &&
!pageData.relativePath.startsWith('icons/lab/') &&
pageData.params?.name
) {
const iconName = pageData.params.name;
pageData.title = `${iconName} icon details`;
const taggedAs = pageData.params?.tags?.length
? `Tagged as: ${pageData.params.tags.join(', ')}.`
: '';
const categorizedIn = pageData.params?.category?.length
? `Categorized in: ${pageData.params.category.join(', ')}.`
: '';
pageData.description =
`Details and related icons for ${iconName} icon. ${taggedAs} ${categorizedIn}`.trim();
const structuredData = await getStructuredData(iconName, pageData);
const ogPath = await createIconOGImage(iconName, pageData.params?.tags || []);
if (ogPath) {
const content = `https://lucide.dev${ogPath}`;
pageData.frontmatter.head.push(
[
'meta',
{
property: 'og:image',
content,
},
],
[
'meta',
{
property: 'twitter:image',
content,
},
],
);
}
pageData.frontmatter.head.push([
'script',
{ type: 'application/ld+json' },
JSON.stringify(structuredData),
]);
}
if (pageData.relativePath.startsWith('guide/')) {
const ogPath = await createGeneralOGImage(pageData);
if (ogPath) {
const content = `https://lucide.dev${ogPath}`;
pageData.frontmatter.head.push(
[
'meta',
{
property: 'og:image',
content,
},
],
[
'meta',
{
property: 'twitter:image',
content,
},
],
);
}
}
},
head: getHeadConfig({ title, description, socialTitle }),
transformPageData,
themeConfig: {
logo: {
light: '/logo.light.svg',
+134
View File
@@ -0,0 +1,134 @@
import { HeadConfig } from 'vitepress';
const getHeadConfig = ({
title,
description,
socialTitle,
}: {
title: string;
description: string;
socialTitle?: string;
}): HeadConfig[] => [
[
'link',
{
rel: 'preconnect',
href: 'https://analytics.lucide.dev',
},
],
[
'script',
{
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: '',
},
],
[
'script',
{
src: 'https://media.bitterbrains.com/main.js?from=LUCIDE&type=top',
async: 'true',
},
],
[
'meta',
{
property: 'og:locale',
content: 'en_US',
},
],
[
'meta',
{
property: 'og:type',
content: 'website',
},
],
[
'meta',
{
property: 'og:site_name',
content: title,
},
],
[
'meta',
{
property: 'og:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'og:description',
content: description,
},
],
[
'meta',
{
property: 'og:url',
content: 'https://lucide.dev',
},
],
[
'meta',
{
property: 'og:image',
content: 'https://lucide.dev/og.png',
},
],
[
'meta',
{
property: 'og:image:width',
content: '1200',
},
],
[
'meta',
{
property: 'og:image:height',
content: '630',
},
],
[
'meta',
{
property: 'og:image:type',
content: 'image/png',
},
],
[
'meta',
{
property: 'twitter:card',
content: 'summary_large_image',
},
],
[
'meta',
{
property: 'twitter:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'twitter:description',
content: description,
},
],
[
'meta',
{
property: 'twitter:image',
content: 'https://lucide.dev/og.png',
},
],
];
export default getHeadConfig;
@@ -0,0 +1,160 @@
<script setup lang="ts">
import { useLocalStorage } from '@vueuse/core';
import IconButton from './base/IconButton.vue';
import { x } from '../../data/iconNodes';
import Icon from '@lucide/vue/src/Icon';
import { computed, onMounted, ref } from 'vue';
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue';
const showAskSurvey = useLocalStorage('show-ask-overlay', true, {
initOnMounted: true,
});
const delayedShow = ref(false)
const showPopup = computed(() => showAskSurvey.value && delayedShow.value );
let isInitialized = false
function startTally() {
window.Tally.openPopup('EkvOpB', {
layout: 'modal',
width: 700,
autoClose: 5000,
onClose() {
showAskSurvey.value = false;
},
onSubmit() {
showAskSurvey.value = false;
},
});
}
onMounted(() => {
setTimeout(() => {
delayedShow.value = true
}, 10000)
})
function initTally() {
try {
if (!isInitialized) {
isInitialized = true
const s = document.createElement('script')
s.src = `//tally.so/widgets/embed.js`
s.async = true
s.onload = startTally
document.body.appendChild(s)
} else {
startTally();
}
} catch (error) {
window.open('https://tally.so/r/EkvOpB', '_blank');
}
}
function hidePopup() {
showAskSurvey.value = false;
}
</script>
<template>
<Teleport to="body">
<div
:class="{
'show-popup': showPopup,
}"
class="ask-overlay"
>
<IconButton
@click="hidePopup"
class="hide-button"
>
<Icon
:iconNode="x"
:size="20"
absoluteStrokeWidth
/>
</IconButton>
<h2 class="title">
We value your feedback!
</h2>
<p class="description">
Can you spare a moment to take our survey? <br>Your feedback helps us improve Lucide and make it better for everyone.
</p>
<div class="buttons">
<VPButton
text="Take the Survey"
theme="brand"
@click="initTally"
/>
<VPButton
text="Close"
theme="alt"
@click="hidePopup"
/>
</div>
</div>
</Teleport>
</template>
<style scoped>
.ask-overlay {
position: fixed;
z-index: 99;;
bottom: 24px;
width: calc(100% - 48px);
max-width: 420px;
left: 24px;
transition:
opacity 0.25s,
transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
padding: 20px;
border-radius: 12px;
box-shadow: var(--vp-shadow-4);
background-color: var(--vp-carbon-ads-bg-color);
opacity: 0;
transform: translateY(200px);
}
.ask-overlay .title {
line-height: 24px;
font-size: 16px;
font-weight: 600;
}
.ask-overlay .description {
padding-top: 8px;
line-height: 24px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-2);
}
.ask-overlay.show-popup {
transform: translateY(0);
opacity: 1;
pointer-events: auto;
transition:
opacity 0.5s,
transform 0.25s ease;
}
.ask-overlay .buttons {
margin-top: 16px;
display: flex;
gap: 16px;
}
.hide-button {
padding: 4px;
position: absolute;
top: 8px;
right: 8px;
z-index: 3;
background-color: transparent;
}
</style>
@@ -0,0 +1,90 @@
<script setup lang="ts">
import { useRouter } from 'vitepress';
import { computed } from 'vue';
const router = useRouter();
const frameworks = [
{
ariaLabel: 'Get JavaScript certificates from certificates.dev',
image: '/certificates-dev/js-certificates-dev.jpg',
href: 'https://certificates.dev/javascript?friend=LUCIDE',
routes: [
'/guide/lucide/',
'/guide/svelte/',
'/guide/solid/',
'/guide/astro/',
'/guide/static/'
],
},
{
ariaLabel: 'Get React certificates from certificates.dev',
image: '/certificates-dev/react-certificates-dev.jpg',
href: 'https://certificates.dev/react?friend=LUCIDE',
routes: [
'/guide/react/',
'/guide/react-native/',
'/guide/preact/',
],
},
{
ariaLabel: 'Get Vue certificates from certificates.dev',
href: 'https://certificates.dev/vuejs?friend=LUCIDE',
image: '/certificates-dev/vue-certificates-dev.jpg',
routes: [
'/guide/vue/',
],
},
{
ariaLabel: 'Get Angular certificates from certificates.dev',
href: 'https://certificates.dev/angular?friend=LUCIDE',
image: '/certificates-dev/angular-certificates-dev.jpg',
routes: [
'/guide/angular/',
],
}
];
const selected = computed(() => {
const current = frameworks.find(({ routes }) => {
return routes.some(route => router.route.path.startsWith(route));
});
return current || frameworks[0];
});
</script>
<template>
<a class="certificates-link" :href="selected.href" :aria-label="selected.ariaLabel" target="_blank" rel="noopener noreferrer">
<img :src="selected.image" :alt="selected.ariaLabel" />
</a>
</template>
<style scoped>
.certificates-link {
/* padding: 20px; */
border-radius: 12px;
min-height: 100px;
text-align: center;
line-height: 18px;
font-size: 12px;
font-weight: 500;
background-color: var(--vp-carbon-ads-bg-color);
margin-bottom: 20px;
overflow: hidden;
}
.certificates-link img {
width: 100%;
height: 100%;
max-width: 100%;
border-radius: 6px;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.certificates-link:hover img {
transform: scale(1.05);
opacity: 0.9;
}
</style>
@@ -50,7 +50,7 @@ onMounted(() => {
absoluteStrokeWidth
/>
</IconButton>
<VPDocAsideCarbonAds :carbon-ads="theme.carbonAds" />
<VPDocAsideCarbonAds :carbon-ads="theme.carbonAds" overlay />
</div>
</template>
@@ -9,9 +9,7 @@
margin-bottom: 16px;
position: sticky;
z-index: 10;
top: 48px;
padding-top: 24px;
margin-top: -32px;
top: var(--vp-layout-top-height);
width: 100%;
display: flex;
margin-bottom: 32px;
@@ -22,7 +20,8 @@
@media (min-width: 960px) {
.search-bar {
padding-top: 32px;
top: 64px;
margin-top: calc((var(--vp-layout-top-height, 0px) + 32px) * -1);
top: calc(var(--vp-layout-top-height, 0px) + 64px);
}
}
</style>
@@ -0,0 +1,133 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { ref, watch, onMounted } from 'vue'
import { useAside } from 'vitepress/dist/client/theme-default/composables/aside.js'
import { useData } from 'vitepress/dist/client/theme-default/composables/data.js'
const { page } = useData()
const props = defineProps<{
carbonAds: DefaultTheme.CarbonAdsOptions
overlay?: boolean
}>()
const carbonOptions = props.carbonAds
const { isAsideEnabled } = useAside()
const container = ref()
let isInitialized = false
function init() {
if (!isInitialized) {
isInitialized = true
const params = new URLSearchParams({
serve: carbonOptions.code,
placement: carbonOptions.placement,
format: 'responsive',
})
const s = document.createElement('script')
s.id = '_carbonads_js'
s.src = `//cdn.carbonads.com/carbon.js?${params.toString()}`
s.async = true
container.value.appendChild(s)
}
}
watch(() => page.value.relativePath, () => {
if (isInitialized && isAsideEnabled.value) {
;(window as any)._carbonads?.refresh()
}
})
// no need to account for option changes during dev, we can just
// refresh the page
if (carbonOptions) {
onMounted(() => {
// if the page is loaded when aside is active, load carbon directly.
// otherwise, only load it if the page resizes to wide enough. this avoids
// loading carbon at all on mobile where it's never shown
if (isAsideEnabled.value || props.overlay) {
init()
} else {
watch(isAsideEnabled, (wide) => wide && init())
}
})
}
</script>
<template>
<div class="VPCarbonAds" ref="container" />
</template>
<style scoped>
.VPCarbonAds {
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
border-radius: 12px;
min-height: 256px;
text-align: center;
line-height: 18px;
font-size: 12px;
font-weight: 500;
background-color: var(--vp-carbon-ads-bg-color);
}
.VPCarbonAds :deep(img) {
margin: 0 auto;
border-radius: 6px;
}
.VPCarbonAds :deep(.carbon-text) {
display: block;
margin: 0 auto;
padding-top: 12px;
color: var(--vp-carbon-ads-text-color);
transition: color 0.25s;
}
.VPCarbonAds :deep(.carbon-text:hover) {
color: var(--vp-carbon-ads-hover-text-color);
}
.VPCarbonAds :deep(#carbon-responsive .carbon-poweredby),
.VPCarbonAds :deep(.carbon-poweredby) {
display: block;
padding-bottom: 2px;
font-size: 11px;
font-weight: 500;
color: var(--vp-carbon-ads-poweredby-color);
text-transform: uppercase;
transition: color 0.25s;
}
.VPCarbonAds :deep(#carbon-responsive) {
font-size: 12px;
line-height: 18px;
font-weight: 500;
}
.VPCarbonAds :deep(#carbon-responsive .carbon-poweredby) {
text-align: left;
}
.VPCarbonAds :deep(#carbon-responsive .carbon-poweredby:hover),
.VPCarbonAds :deep(.carbon-poweredby:hover) {
color: var(--vp-carbon-ads-hover-poweredby-color);
}
.VPCarbonAds :deep(> div) {
display: none;
}
.VPCarbonAds :deep(> div:first-of-type) {
display: block;
}
.VPCarbonAds :deep(#carbon-responsive) {
flex-direction: column-reverse;
}
.VPCarbonAds :deep(#carbon-responsive .carbon-responsive-wrap) {
border-radius: 10px;
}
</style>
@@ -3,6 +3,7 @@ import { useData } from 'vitepress';
import { useSidebar } from 'vitepress/dist/client/theme-default/composables/sidebar';
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue';
import { computed } from 'vue';
import SurveyAskOverlay from '../SurveyAskOverlay.vue';
const { theme } = useData();
const { hasSidebar } = useSidebar();
+4 -2
View File
@@ -7,12 +7,12 @@ import IconsSidebarNavAfter from './layouts/IconsSidebarNavAfter.vue';
import HomeHeroIconsCard from './components/home/HomeHeroIconsCard.vue';
import HomeHeroAfter from './components/home/HomeHeroAfter.vue';
import HomeHeroInfoBefore from './components/home/HomeHeroInfoBefore.vue';
import LayoutTop from './components/base/LayoutTop.vue';
import { ICON_STYLE_CONTEXT, iconStyleContext } from './composables/useIconStyle';
import { CATEGORY_VIEW_CONTEXT, categoryViewContext } from './composables/useCategoryView';
import { EXTERNAL_LIBS_CONTEXT, externalLibContext } from './composables/useExternalLibs';
import FrameworkSelect from './components/guide/FrameworkSelect.vue';
import SnackPlayer from './components/editors/SnackPlayer.vue';
import CertificatesLink from './components/guide/CertificatesLink.vue';
const theme: Partial<Theme> = {
extends: DefaultTheme,
@@ -23,7 +23,9 @@ const theme: Partial<Theme> = {
'sidebar-nav-after': () => h(IconsSidebarNavAfter),
'home-hero-image': () => h(HomeHeroIconsCard),
'home-hero-actions-after': () => h(HomeHeroAfter),
'layout-top': () => h(LayoutTop),
'aside-ads-before': () => h(CertificatesLink),
// Keep this here for now, we might want to add more things to the top bar in the future
// 'layout-top': () => h(LayoutTop),
});
},
enhanceApp({ app }) {
+14
View File
@@ -144,6 +144,14 @@
.VPHomeHero .container {
flex-direction: row;
}
html.has-bb-banner {
--vp-layout-top-height: 72px;
}
html.has-bb-banner {
--Dark-Background: #161618;
}
}
.VPNavBarHamburger .container > span {
@@ -154,3 +162,9 @@
margin: 0 auto 48px;
max-width: 480px;
}
html:not(.has-bb-banner) #bb-banner {
display: none !important;
visibility: hidden !important;
pointer-events: none !important;
}
+79
View File
@@ -0,0 +1,79 @@
import { PageData } from 'vitepress';
import getStructuredData from './getStructuredData';
import { createGeneralOGImage, createIconOGImage } from './createOGImage';
export async function transformPageData(pageData: PageData) {
pageData.frontmatter.head ??= [];
if (
pageData.relativePath.startsWith('icons/') &&
!pageData.relativePath.startsWith('icons/lab/') &&
pageData.params?.name
) {
const iconName = pageData.params.name;
pageData.title = `${iconName} icon details`;
const taggedAs = pageData.params?.tags?.length
? `Tagged as: ${pageData.params.tags.join(', ')}.`
: '';
const categorizedIn = pageData.params?.category?.length
? `Categorized in: ${pageData.params.category.join(', ')}.`
: '';
pageData.description =
`Details and related icons for ${iconName} icon. ${taggedAs} ${categorizedIn}`.trim();
const structuredData = await getStructuredData(iconName, pageData);
const ogPath = await createIconOGImage(iconName, pageData.params?.tags || []);
if (ogPath) {
const content = `https://lucide.dev${ogPath}`;
pageData.frontmatter.head.push(
[
'meta',
{
property: 'og:image',
content,
},
],
[
'meta',
{
property: 'twitter:image',
content,
},
],
);
}
pageData.frontmatter.head.push([
'script',
{ type: 'application/ld+json' },
JSON.stringify(structuredData),
]);
}
if (pageData.relativePath.startsWith('guide/')) {
const ogPath = await createGeneralOGImage(pageData);
if (ogPath) {
const content = `https://lucide.dev${ogPath}`;
pageData.frontmatter.head.push(
[
'meta',
{
property: 'og:image',
content,
},
],
[
'meta',
{
property: 'twitter:image',
content,
},
],
);
}
}
}
+38
View File
@@ -46,5 +46,43 @@ declare global {
*/
append(container: Element): void;
};
Tally: {
// From https://tally.so/help/developer-resources#2f676e40530a460ea6a634b8441f6001
openPopup: (
formId: string,
options?: {
key?: string; // This is used as a unique identifier used for the "Show only once" and "Don't show after submit" functionality
layout?: 'default' | 'modal';
width?: number;
alignLeft?: boolean;
hideTitle?: boolean;
overlay?: boolean;
emoji?: {
text: string;
animation:
| 'none'
| 'wave'
| 'tada'
| 'heart-beat'
| 'spin'
| 'flash'
| 'bounce'
| 'rubber-band'
| 'head-shake';
};
autoClose?: number; // in milliseconds
showOnce?: boolean;
doNotShowAfterSubmit?: boolean;
customFormUrl?: string; // when you want to load the form via it's custom domain URL
hiddenFields?: {
[key: string]: any;
};
onOpen?: () => void;
onClose?: () => void;
onPageView?: (page: number) => void;
onSubmit?: (payload: SubmissionPayload) => void;
},
) => void;
};
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ However, not everyone can understand them easily. Read more about [how to use Lu
## Official Packages
Lucide's official packages are designed to work on different platforms, making it easier for users to integrate icons into their projects. The packages are available for various technologies, including [Web (Vanilla)](https://lucide.dev/guide/packages/lucide), [React](https://lucide.dev/guide/packages/lucide-react), [React Native](https://lucide.dev/guide/packages/lucide-react-native), [Vue](https://lucide.dev/guide/packages/lucide-vue), [Vue 3](https://lucide.dev/guide/packages/lucide-vue-next), [Svelte](https://lucide.dev/guide/packages/lucide-svelte), [Preact](https://lucide.dev/guide/packages/lucide-preact), [Solid](https://lucide.dev/guide/packages/lucide-solid), [Angular](https://lucide.dev/guide/packages/angular), [Astro](https://lucide.dev/guide/packages/lucide-astro), and [NodeJS](https://lucide.dev/guide/packages/lucide-static#nodejs).
Lucide's official packages are designed to work on different platforms, making it easier for users to integrate icons into their projects. The packages are available for various technologies, including [Web (Vanilla)](./lucide/index.md), [React](./react/index.md), [React Native](./react-native/index.md), [Vue](./vue/index.md), [Svelte](./svelte/index.md), [Preact](./preact/index.md), [Solid](./solid/index.md), [Angular](./angular/index.md), [Astro](./astro/index.md), and [Static](./static/index.md).
## Community
+10 -1
View File
@@ -3,12 +3,13 @@
::: warning
This documentation is for `@lucide/angular`.
To learn about our legacy package for Angular, please refer to [`lucide-angular`](./lucide-angular).
To learn about our legacy package for Angular, please refer to [`lucide-angular`](https://v0.lucide.dev/guide/packages/lucide-angular).
:::
A standalone, signal-based, zoneless implementation of Lucide icons for Angular.
**What you can accomplish:**
- Use icons as standalone Angular components with full dependency injection support
- Configure icons globally through modern Angular providers
- Integrate with Angular's reactive forms and data binding
@@ -118,6 +119,7 @@ Alternatively, the component also accepts string inputs.
To use icons this way, first, you have to provide icons via `provideLucideIcons`:
:::code-group
```ts{7-10} [app.config.ts]
import { ApplicationConfig } from '@angular/core';
import { provideLucideIcons, LucideCircleCheck, LucideCircleX } from '@lucide/angular';
@@ -148,6 +150,7 @@ import { LucideIcon } from '@lucide/angular';
})
export class Foobar { }
```
:::
::: tip
@@ -259,19 +262,25 @@ export class Foobar {
## Troubleshooting
### The icon is not being displayed
If using per-icon-components:
1. Ensure that the icon component is being imported, if using per-icon-components
2. Check that the icon name matches exactly (case-sensitive)
If using the dynamic component:
1. Ensure the icon is provided via `provideLucideIcons()` if using string names
2. Verify the icon is imported from `@lucide/angular` and not the legacy package
### TypeScript errors?
Make sure you're importing from `@lucide/angular` and not `lucide-angular`.
### Icons render with wrong defaults
Ensure `provideLucideConfig()` is used at the right level.
## Migration guide
Migrating from `lucide-angular`? Read our [comprehensive migration guide](https://github.com/lucide-icons/lucide/blob/main/packages/angular/MIGRATION.md).
-187
View File
@@ -1,187 +0,0 @@
# Lucide Angular
::: warning
This documentation is for our legacy package for Angular.
For our modern, standalone-first implementation, please refer to [`@lucide/angular`](./angular).
:::
Angular components and services for Lucide icons that integrate with Angular's dependency injection and component system. Provides both traditional module-based and modern standalone component approaches for maximum flexibility in Angular applications.
**What you can accomplish:**
- Use icons as Angular components with full dependency injection support
- Configure icons globally through Angular services and providers
- Choose from multiple component selectors (lucide-angular, lucide-icon, i-lucide, span-lucide)
- Integrate with Angular's reactive forms and data binding
- Build scalable applications with tree-shaken icon bundles and lazy loading support
## Installation
::: code-group
```sh [pnpm]
pnpm add lucide-angular
```
```sh [yarn]
yarn add lucide-angular
```
```sh [npm]
npm install lucide-angular
```
```sh [bun]
bun add lucide-angular
```
:::
## How to use
### Step 1: Import `LucideAngularModule`
In any Angular module you wish to use Lucide icons in, you have to import `LucideAngularModule`, and pick any icons you wish to use:
```js
import { LucideAngularModule, File, House, Menu, UserCheck } from 'lucide-angular';
@NgModule({
imports: [
LucideAngularModule.pick({File, House, Menu, UserCheck})
]
})
export class AppModule { }
```
or using standalone version:
```js
import { Component } from '@angular/core';
import { LucideAngularModule, FileIcon } from 'lucide-angular';
@Component({
standalone: true,
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
imports: [LucideAngularModule]
})
export class AppComponent {
readonly FileIcon = FileIcon;
}
```
### Step 2: Use the icons in templates
Within your templates you may now use one of the following component tags to insert an icon:
```html
<lucide-angular name="file" class="my-icon"></lucide-angular>
<lucide-icon name="house" class="my-icon"></lucide-icon>
<i-lucide name="menu" class="my-icon"></i-lucide>
<span-lucide name="user-check" class="my-icon"></span-lucide>
```
for standalone
```html
<lucide-angular [img]="FileIcon" class="my-icon"></lucide-angular>
<lucide-icon [img]="FileIcon" class="my-icon"></lucide-icon>
<i-lucide [img]="FileIcon" class="my-icon"></i-lucide>
<span-lucide [img]="FileIcon" class="my-icon"></span-lucide>
```
### Props
You can pass additional props to adjust the icon appearance.
| name | type | default |
| --------------------- | --------- | ------------ |
| `size` | *number* | 24 |
| `color` | *string* | currentColor |
| `strokeWidth` | *number* | 2 |
| `absoluteStrokeWidth` | *boolean* | false |
```html
<i-lucide name="house" [size]="48" color="red" [strokeWidth]="1"></i-lucide>
```
### Global configuration
You can inject the `LucideIconConfig` service in your root component to globally configure the default property values as defined above.
### Styling using a custom CSS class
Any extra HTML attribute is ignored, but the `class` attribute
is passed onto the internal SVG image element and it can be used to style it:
```css
svg.my-icon {
width: 12px;
height: 12px;
stroke-width: 3;
}
```
## Injecting multiple icon providers
You may provide additional icons using the `LUCIDE_ICONS` injection token,
which accepts multiple providers of the interface `LucideIconsProviderInterface`
with the utility class `LucideIconsProvider` available for easier usage:
```js
import { LUCIDE_ICONS, LucideIconProvider } from 'lucide-angular';
import { MyIcon } from './icons/my-icon';
const myIcons = {MyIcon};
@NgModule({
providers: [
{provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(myIcons)},
]
})
export class AppModule { }
```
To add custom icons, you will first need to convert them to an [svgson format](https://github.com/elrumordelaluz/svgson).
## Loading all icons
::: danger
You may also opt to import all icons if necessary using the following format but be aware that this will significantly increase your application build size.
:::
```js
import { icons } from 'lucide-angular';
...
LucideAngularModule.pick(icons)
```
## With Lucide Lab or custom icons
[Lucide Lab](https://github.com/lucide-icons/lucide-lab) is a collection of icons that are not part of the Lucide main library.
They can be used in the same way as the official icons.
```js
import { LucideAngularModule } from 'lucide-angular';
import { coconut } from '@lucide/lab';
@NgModule({
imports: [
LucideAngularModule.pick({ coconut })
]
})
export class AppModule { }
```
## Accessibility
By default, we hide icons from screen readers using `aria-hidden="true"`.
You can add accessibility attributes using aria-labels.
```html
<lucide-icon name="check" aria-label="Task completed"></lucide-icon>
```
For best practices on accessibility, please see our [accessibility guide](../accessibility.md).
+2 -1
View File
@@ -3,6 +3,7 @@
Vue 2 components for Lucide icons that integrate with Vue's Options API and template system. Each icon is a Vue component that renders as an inline SVG, providing familiar Vue development patterns for legacy applications still using Vue 2.
**What you can accomplish:**
- Use icons as Vue 2 components with Options API integration
- Maintain legacy Vue 2 applications with modern icon components
- Integrate with Vue 2's template system and component lifecycle
@@ -155,7 +156,7 @@ You can add accessibility attributes using aria-labels.
```vue
<script setup>
import { Check } from 'lucide-vue-next';
import { Check } from '@lucide/vue';
</script>
<template>
+4 -6
View File
@@ -15,24 +15,22 @@ Make sure you have a Svelte environment set up. If you don't have one yet, you c
## Installation
<!-- TODO: v1 Remove After full release -->
::: code-group
```sh [pnpm]
pnpm install @lucide/svelte@next
pnpm install @lucide/svelte
```
```sh [yarn]
yarn add @lucide/svelte@next
yarn add @lucide/svelte
```
```sh [npm]
npm install @lucide/svelte@next
npm install @lucide/svelte
```
```sh [bun]
bun add @lucide/svelte@next
bun add @lucide/svelte
```
:::
+2 -2
View File
@@ -32,7 +32,7 @@
"@rollup/plugin-replace": "^6.0.3",
"@types/semver": "^7.7.1",
"h3": "^1.15.9",
"nitropack": "^2.12.4",
"nitropack": "^2.13.4",
"rollup-plugin-copy": "^3.5.0",
"svg-path-commander": "^2.1.11",
"vitepress": "^1.6.4",
@@ -43,7 +43,7 @@
"semver": "^7.7.3",
"sharp": "^0.34.5",
"shiki": "^3.15.0",
"simple-git": "^3.32.3",
"simple-git": "^3.36.0",
"sitemap": "^7.1.2",
"svg-pathdata": "^6.0.3",
"svgson": "^5.3.1"
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+9 -1
View File
@@ -13,7 +13,7 @@
"title": "Lucide Icons icon schema",
"type": "object",
"additionalProperties": false,
"required": ["$schema", "categories", "tags"],
"required": ["$schema", "contributors", "categories", "tags", "use-cases"],
"properties": {
"$schema": {
"type": "string"
@@ -114,6 +114,14 @@
"minItems": 1,
"uniqueItems": true
},
"use-cases": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 0,
"uniqueItems": true
},
"deprecated": {
"const": true
},
+1
View File
@@ -6,6 +6,7 @@
"danielbayley",
"ericfennis"
],
"use-cases": [],
"tags": [
"letter",
"font size",
+1
View File
@@ -6,6 +6,7 @@
"danielbayley",
"ericfennis"
],
"use-cases": [],
"tags": [
"letter",
"font size",
+5
View File
@@ -1,5 +1,10 @@
{
"$schema": "../icon.schema.json",
"use-cases": [
"indicating a large and small text size",
"formatting text size",
"indicating a heading and body text"
],
"contributors": [
"it-is-not",
"jguddas",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"disability",
"disabled",
+1
View File
@@ -4,6 +4,7 @@
"colebemis",
"jguddas"
],
"use-cases": [],
"tags": [
"pulse",
"action",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"air conditioner",
"ac",
+1
View File
@@ -5,6 +5,7 @@
"csandman",
"ericfennis"
],
"use-cases": [],
"tags": [
"stream",
"cast",
+1
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"done",
"todo",
+1
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"remove"
],
+1
View File
@@ -6,6 +6,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"morning",
"turn-off"
+1
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"add"
],
+1
View File
@@ -7,6 +7,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"morning"
],
+1
View File
@@ -5,6 +5,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"fire",
"alert",
+1
View File
@@ -5,6 +5,7 @@
"csandman",
"mittalyashu"
],
"use-cases": [],
"tags": [
"photo",
"book"
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"items",
"flex",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"items",
"flex",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"items",
"bottom",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"items",
"right",
@@ -4,6 +4,7 @@
"r4lv",
"ericfennis"
],
"use-cases": [],
"tags": [
"items",
"flex",
@@ -4,6 +4,7 @@
"r4lv",
"ericfennis"
],
"use-cases": [],
"tags": [
"right",
"items",
@@ -4,6 +4,7 @@
"r4lv",
"ericfennis"
],
"use-cases": [],
"tags": [
"left",
"items",
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"center",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"right",
"items",
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"left",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"center",
"items",
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"around",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"top",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"left",
"items",
@@ -4,6 +4,7 @@
"ericfennis",
"jguddas"
],
"use-cases": [],
"tags": [
"items",
"flex",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"bottom",
"items",
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"top",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"center",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"bottom",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"top",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"center",
"items",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"ericfennis"
],
"use-cases": [],
"tags": [
"center",
"items",
+1
View File
@@ -11,6 +11,7 @@
"karsa-mistmere",
"danielbayley"
],
"use-cases": [],
"tags": [
"ambulance",
"emergency",
+1
View File
@@ -5,6 +5,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"and",
"typography",
+1
View File
@@ -4,6 +4,7 @@
"danielbayley",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"and",
"operator",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"pottery",
"artifact",
+1
View File
@@ -6,6 +6,7 @@
"ericfennis",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"ship"
],
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"ericfennis"
],
"use-cases": [],
"tags": [
"emoji",
"anger",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"emoji",
"nuisance",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"danielbayley"
],
"use-cases": [],
"tags": [
"signal",
"connection",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"danielbayley"
],
"use-cases": [],
"tags": [
"metal",
"iron",
+1
View File
@@ -4,6 +4,7 @@
"colebemis",
"ericfennis"
],
"use-cases": [],
"tags": [
"camera",
"photo",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"danielbayley"
],
"use-cases": [],
"tags": [
"application",
"menu bar",
+1
View File
@@ -4,6 +4,7 @@
"danielbayley",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"application",
"menu bar",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"fruit",
"food",
+1
View File
@@ -5,6 +5,7 @@
"ericfennis",
"danielbayley"
],
"use-cases": [],
"tags": [
"unarchive",
"index",
+1
View File
@@ -3,6 +3,7 @@
"contributors": [
"danielbayley"
],
"use-cases": [],
"tags": [
"index",
"backup",
+1
View File
@@ -6,6 +6,7 @@
"karsa-mistmere",
"danielbayley"
],
"use-cases": [],
"tags": [
"index",
"backup",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"sofa",
"furniture",
+1
View File
@@ -6,6 +6,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"backwards",
"reverse",
+1
View File
@@ -8,6 +8,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"backwards",
"reverse",
+1
View File
@@ -6,6 +6,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"previous",
"back",
+1
View File
@@ -9,6 +9,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"previous",
"back",
+1
View File
@@ -6,6 +6,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"next",
"forward",
+1
View File
@@ -9,6 +9,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"next",
"forward",
+1
View File
@@ -6,6 +6,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"caps lock",
"capitals",
+1
View File
@@ -8,6 +8,7 @@
"jamiemlaw",
"jguddas"
],
"use-cases": [],
"tags": [
"shift",
"keyboard",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"danielbayley"
],
"use-cases": [],
"tags": [
"filter",
"sort",
+1
View File
@@ -4,6 +4,7 @@
"karsa-mistmere",
"danielbayley"
],
"use-cases": [],
"tags": [
"filter",
"sort",

Some files were not shown because too many files have changed in this diff Show More