Compare commits

..
Author SHA1 Message Date
Eric Fennis 6d1fc51b9a Prepare @lucide/lab 0.2.0 release 2026-07-31 14:09:41 +02:00
Eric FennisandCopilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> 1502285072 fix(@lucide/lab): Fix lab build (#4618)
* chore(lab): Adjust build scripts

* add check workflow

* Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* update gitignore

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-07-31 09:11:20 +02:00
Karsa 240118e521 feat(icons): improve calendar icons centre of gravity (#4614)
* feat(icons): improve calendar icons centre of gravity

* fix(icons): reoptimize everything using Lucide Studio
2026-07-30 09:50:10 +02:00
Samuel Alakegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
4aec3f892f feat(icons): add layout-freeform (#4543)
* feat(icons): add layout-freeform

Adds an icon for freeform layout: three blocks, no two sharing an edge.
It matches the "no auto layout" / free positioning mode found in design
tools, as the counterpart to constrained layout modes.

Design notes:
- Reuses the 7x7 rx=1 block already shared by layout-grid, layout-list
  and layout-panel-*, rather than introducing a new base shape.
- Each block is offset so that no two share an edge, which is what
  separates it from layout-grid.
- The offset is 1px: a 2px offset reads more clearly at 16px, but brings
  the top-right and bottom-left blocks within 1.66px of each other
  diagonally, under the 2px element spacing guideline. See the PR for the
  alternatives.

* Update icons/layout-freeform.json

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-25 22:59:55 +02:00
Karsa dbfe130652 feat(icons): replaces podcast icon with new mic-* icons (#4583)
* feat(icons): replaces `podcast` icon with new `mic-*` icons

* fix(icons): change contributors, since these are now essentially brand new icons

* fix(prettier): remove path fill from allowed SVG element attributes
2026-07-25 22:58:54 +02:00
Jakob GuddasandEric Fennis d29db5e98e feat(icons): added pilot icon (#2409)
* Added icons/pilot.svg

* Added icons/pilot.json

* Move pilot icon to lab directory

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-25 15:06:22 +02:00
Daniel BayleyandEric Fennis bb26580cfb feat(docs): Add lab requirement in pull_request_template.md (#3651)
* feat(docs): update pull_request_template.md

* Fix link to Lab directory in PR template

Updated link reference for the Lab directory in the pull request template.

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-25 13:13:01 +02:00
Jakob Guddas 74c46711c7 feat(analytics): add utm source and medium (#4596) 2026-07-25 12:26:26 +02:00
KarsaandKarsa c3b6795394 fix(icons): changed trophy icon (#4591)
* [github] Added issue template forms

* [github] yaml => yml

* Syntax fixes

* Further syntax fixes

* Sort issue templates

* Update 02_bug_report.yml

* Updated icons/trophy.svg

* Updated icons/trophy.svg

* fix(icons/trophy): fill in metadata

---------

Co-authored-by: Karsa <karsa@karsa.org>
2026-07-25 12:21:12 +02:00
Bálint TóthandEric Fennis 33342b8790 feat(icons): added police-cap icon to lab (#3019)
* Added icons/police-cap.svg

* Added icons/police-cap.json

* Move police cap to lab directory

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-24 15:57:26 +02:00
9ecaafbc4d feat(lab): Migrate lab to main repo. (#4521)
* Add directory

* Add lab check script

* Delete duplicated icons

* Fix the lab page

* Adjust paths

* update lockfile

* update lockfile

* fix(lab/planet): replace with guideline-compliant design

* Add install step

* Add second install step

* Adjust lab in site

* try this

* Fix workflow

* Add cspell

* Format code

* Temporary delete icons for copilot review

* Place back lab icons

* Apply suggestions from code review

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

* Update lock file

* Revert svg changes

* Fix list

* Rename filenames

* Format tsconfig

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-24 15:05:40 +02:00
KarsaandEric Fennis 1d578ab536 fix(icons): changed barrel icon (#4592)
* Updated icons/barrel.svg

* Updated icons/barrel.json

* Update barrel.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-24 14:41:37 +02:00
Eric Fennis c757cb9d4b ci(ci.yml): Remove concurrency in ci.yml (#4595) 2026-07-24 14:39:12 +02:00
KarsaandEric Fennis 5d36179bf4 feat(ci): added custom prettier plugin for icon SVG files (#4576)
* feat(ci): added custom prettier plugin for icon SVG files

* feat(ci): added custom prettier plugin for icon SVG files

* feat(ci): replace prettier plugin implementation with one based on svgo

* fix(ci): fix linting issues in prettier plugin

* Allow fill in path to fix podcast icon

* Format code

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-24 14:23:56 +02:00
Karsa 357df0d660 fix(icons): changed feather icon (#4584)
* Updated icons/feather.svg

* Updated icons/feather.json

* Update feather.json
2026-07-24 13:28:42 +02:00
Eric Fennis 5a06f7cb1d fix(request-review): Remove pull_request_target (#4593) 2026-07-24 13:23:58 +02:00
مُحَمّد سِيّدgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric FennisKarsa
63d0ef6664 feat(icons): added mosque icon (#4494)
* Added icons/mosque.svg

* Added icons/mosque.json

* Update icons/mosque.json

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

* Update icons/mosque.json

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

* Add contributor 'rrod497' to mosque.json

* Add empty use-cases array to mosque.json

* Update mosque.svg

* Update mosque.json

* Update mosque.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-07-23 20:31:03 +02:00
Martin VítekCopilot Autofix powered by AIgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
0adb963d07 feat(icons): added user-shield icon (#3099)
* Added icons/user-shield.svg

* Added icons/user-shield.json

* Apply design from karsa

* Potential fix for pull request finding

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

* Update icons/user-shield.json

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

* Update icons/user-shield.json

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

* 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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-23 15:20:10 +02:00
Samuel Alakegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric FennisKarsa
89147bbecc feat(icons): add scan-square (#4550)
* feat(icons): add scan-square

Adds scan-square: a scanning frame with a square detected inside it.

The scan-* family covers what is being detected — scan-face, scan-heart,
scan-text, scan-eye, scan-barcode, scan-qr-code, scan-search, scan-line —
but has nothing for a plain shape or object.

Composed entirely from two existing icons rather than new geometry: the
four corner brackets are scan's, verbatim, and the inner block is
square-square's rect(8,8,8,8) rx=1, verbatim. Nothing here is drawn from
scratch, so it sits in the family without introducing a new vocabulary.

* chore(icons): fill scan-square use-cases and fix recognise/recognize tags

Addresses review on #4550: fills the use-cases field per @ericfennis, and
collapses the duplicate recognise/recognize tags into a single
recognition tag, matching scan-text's vocabulary per @Copilot.

* Update icons/scan-square.json

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

* Update icons/scan-square.json

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-07-23 14:08:52 +02:00
Karsa 0ad5aaf323 Updated icons/toolbox.svg (#4571) 2026-07-23 14:03:34 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Eric Fennis
50f9af4ed2 chore(deps-dev): bump astro from 6.4.8 to 7.1.0 (#4572)
Bumps [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) from 6.4.8 to 7.1.0.
- [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@7.1.0/packages/astro)

---
updated-dependencies:
- dependency-name: astro
  dependency-version: 7.1.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>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-23 14:02:34 +02:00
Octobergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Karsa
4c61dc4826 feat(icons): add square-off icon (#4496)
* feat(icons): add square-off icon

* Apply suggestion from @github-actions[bot]

Added tags

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

* Apply suggestion from @github-actions[bot]

added categories

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

* Apply suggestion from @github-actions[bot]

added use cases

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

* Update icons/square-off.json

update use cases

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

* Update icons/square-off.svg

update code convention

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

* Update square-off.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-07-23 14:00:53 +02:00
99a8602c5d fix(icons): changed zap and zap-off icons (#4536)
* fix(icons): changed `zap` and `zap-off` icons

* Update zap.svg

* Update zap-off.svg

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-23 14:00:17 +02:00
NielsLazaromsgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric FennisKarsa
75b6ac1969 feat(icons): added pending-cw icon (#4439)
* Added icons/pending-cw.svg

* Added icons/pending-cw.json

* Update icons/pending-cw.json

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

* Rename pending-cw.json to clock-arrow-cw.json

* Add clock-arrow-cw.svg icon file

* Update icons/clock-arrow-cw.json

* Update icons: replace and refine `history` and `clock-*` SVGs and metadata

* update file name

* updated icon name

* Refine `clock-arrow-ccw` metadata: add use-cases, tags, and aliases

* fix(icons): rename history/pending _yet again_. Sorry, Niels 🫣

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-07-23 11:59:09 +02:00
KarsaandEric Fennis 138ce8e748 fix(packages/angular): add more supported attributes for SVG nodes (#4570)
* fix(packages/angular): add more supported attributes for SVG nodes

* fix(packages/angular): use original matcher syntax instead of toMatchInlineSnapshot matcher

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-23 11:29:24 +02:00
KarsaandEric Fennis 87ec1a0587 fix(icons): optimised square-scissors icons (#4581)
* Updated icons/square-bottom-dashed-scissors.svg

* Updated icons/square-bottom-dashed-scissors.json

* Update square-bottom-dashed-scissors.json

* Update square-scissors.svg

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-23 10:43:44 +02:00
Eric Fennis 02eaf471a9 fix(docs): Fix site build (#4582)
* Fix site build

* Fix site build
2026-07-23 10:15:09 +02:00
Karsa 3035ed309e feat(icons): removed brand names from tags & revised brand stopwords (#4575) 2026-07-23 08:13:10 +02:00
Karsagithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
4e50f0d759 feat(icons): added shield-keyhole icon (#4580)
* Added icons/shield-keyhole.svg

* Added icons/shield-keyhole.json

* Update shield-keyhole.json

* Update icons/shield-keyhole.json

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-23 08:10:33 +02:00
Karsa a924c01b8e fix(icons): changed book-open icons (#4565)
* Updated icons/book-open.svg

* Updated icons/book-open.json

* Updated icons/book-open-text.svg

* Updated icons/book-open-text.json

* Updated icons/book-open-check.svg
2026-07-23 08:10:07 +02:00
Karsa 37f32cb73a Update ad.json (#4579) 2026-07-23 07:47:39 +02:00
kamilaandKarsa 4e2efb9350 fix(icons): changed columns-3-cog icon (#4578)
* fix(icons)/columns-3-cog

* Update icons/columns-3-cog.svg

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

* add EOF new line to columns-3-cog.svg

---------

Co-authored-by: Karsa <contact@karsa.org>
2026-07-22 16:13:09 +02:00
Karsa 658573b017 fix(docs): fix home page package links & accessible labels (#4540) 2026-07-17 13:33:45 +02:00
Karsagithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
5136572c10 feat(icons): added scan-box icon (#4551)
* Added icons/scan-box.svg

* Added icons/scan-box.json

* Update scan-box.json

* Update scan-box.svg

* Update icons/scan-box.json

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

* Update icons/scan-box.json

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-17 10:25:16 +02:00
Karsa 4f8088fd90 fix(icons): changed file-box icon (#4552)
* Updated icons/file-box.svg

* chore(icons/file-box): extend tags & use case metadata
2026-07-17 10:24:40 +02:00
Karsa ae40cfbc73 fix(icons): changed ethernet-port icon (#4555)
* Updated icons/ethernet-port.svg

* Updated icons/ethernet-port.json
2026-07-17 09:28:22 +02:00
Karsa cdd7db1ce6 fix(icons): changed hdmi-port icon (#4554)
* Updated icons/hdmi-port.svg

* Updated icons/hdmi-port.json
2026-07-17 09:28:17 +02:00
Jakob Guddas f930bbe07c feat(docs): add studio link (#4534)
* feat: add studio link

* fix: add aria label
2026-07-16 14:41:14 +02:00
Eric Fennis f229f83f0c chore(depedencies): Update dependencies (#4553)
* update deps

* Update even more

* Fix lint errors

* Apply feedback

* Update lockfile
2026-07-16 14:38:12 +02:00
Jakob Guddas b442632ee6 fix: broken link in brand logo comment (#4533) 2026-07-11 12:59:38 +02:00
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Eric Fennis
078a0b2339 chore(deps-dev): bump @babel/core from 7.28.5 to 7.29.6 (#4476)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.28.5 to 7.29.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.6/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 7.29.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-10 11:53:34 +02:00
5d78605650 fix(site): empty search results on first load for tag-only matches (#4413)
* fix(site): fetch icon search metadata when typing

* fix(site): gate "No results" on metadata availability, not fetch state

* fix(site): also wait on categories metadata on the category page

Keeps the loading guard symmetric with the icons page. The narrower
tags-only check was technically more precise (this page's useSearch
doesn't index categories), but the failure case it guarded against —
brand search landing on a blank area if /api/categories lags behind
/api/tags — is too narrow to justify the asymmetry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-10 11:22:57 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ab61fa277b chore(deps-dev): bump astro from 6.1.10 to 6.4.6 (#4487)
Bumps [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) from 6.1.10 to 6.4.6.
- [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.4.6/packages/astro)

---
updated-dependencies:
- dependency-name: astro
  dependency-version: 6.4.6
  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-07-10 09:58:42 +02:00
Eric Fennis bb1329e512 fix(icons): Rename to circle-euro to match other euro icons (#4531)
* fix(icons): Rename to `circle-euro` to match other euro icons

* Add usecase
2026-07-10 09:58:01 +02:00
Turboman3000 b5b5d95933 feat(icons): added server-plus icon (#4232)
* Added icons/server-plus.svg

* Added icons/server-plus.json

* Updated icons/server-plus.json
2026-07-09 15:09:49 +02:00
Julian Solimandogithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AIEric Fennis
7b589f2b5c feat(icons): added circle-euro-sign icon (#4353)
* Added icons/circle-euro-sign.svg

* Added icons/circle-euro-sign.json

* Update icons/circle-euro-sign.json

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

* Potential fix for pull request finding

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

* Apply suggestions from code review

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>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-09 14:54:38 +02:00
2d36863568 feat(icons): center the dot icon (#4492)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-07-09 14:54:20 +02:00
Eric FennisandCopilot Autofix powered by AI 7291cbcc0f fix(lucide-react-native): Add icon exports property to the package.json file (#4522)
* Add export per icon

* 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>

* Add documentations

* Format code

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-09 14:53:06 +02:00
4c663b9a32 fix(vue): support kebab-case icon-node prop on Icon component (#4512)
* fix(vue): support kebab-case icon-node prop on Icon component

The Icon component destructured `iconNode` camelCase-only while
`stroke-width`/`absolute-stroke-width` accept both cases, so the
idiomatic Vue usage `<Icon :icon-node="..." />` left iconNode undefined
and crashed with 'Cannot read properties of undefined (reading map)'
(#3485). Accept the kebab-case alias and guard the render path.

Closes #3485

* Potential fix for pull request finding

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

* chore(vue): apply prettier formatting to Icon.ts

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-09 14:11:20 +02:00
Pavlos Vinieratos 63369b1ac0 fix(lucide-react-native): restore the icons entry point in the JS bundles (#4528) 2026-07-09 13:57:22 +02:00
Jamie Law f07465f82e Updated icons/option.svg (#4326) 2026-07-09 13:32:55 +02:00
GyeongHo KimandEric Fennis 60d583ce4e docs(site): list @gyeonghokim/lucide-lit as third-party package (#4421)
Add the @gyeonghokim/lucide-lit Lit web components package to the
third-party packages list, with a Lit framework logo for the card icon.

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-08 09:55:54 +02:00
Karsa 5828ecb38f fix(packages/angular): move child rendering logic to template from effect (#4519)
* fix(packages/angular): move child rendering logic to template from effect

* test(packages/angular): add unit tests on SSR hydration
2026-07-06 12:16:52 +02:00
Eric Fennis 031b226ac6 Add merch link (#4524) 2026-07-05 14:22:51 +02:00
Copilotandcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> 35d535a477 chore(icons): remove toBeRemovedInVersion metadata and make it optional in schema (#4513)
* Remove toBeRemovedInVersion from icons and make optional in schema

* fix(build-icons): align alias deprecation type with schema optional removal version

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-02 12:34:23 +02:00
Karsa 8930dfa827 fix(scripts): fix typo in renameIcon.function.mts (#4514) 2026-07-02 11:41:51 +02:00
Daniel CastillejoandEric Fennis c67c9bdbfb feat(icons): added paper-bag icon (#4023)
* Added icons/paper-bag.svg

* Added icons/paper-bag.json

* Update paper-bag.svg

* Update paper-bag.json with new fields and tags

Added 'use-cases' field and updated 'tags' list.

* Update paper-bag.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-07-01 16:02:09 +02:00
Eric Fennis 52d7c549c3 Set custom COPILOT_GITHUB_TOKEN (#4509) 2026-06-30 20:06:34 +02:00
Eric Fennis 9cb4e49849 Small fix in the workflow (#4508) 2026-06-30 19:15:07 +02:00
Eric FennisandCopilot Autofix powered by AI f59db07ef9 ci(repo-journal.yml): GH copilot repo summary (#4505)
* gh bot posting info

* Set secret

* 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-06-30 14:09:53 +02:00
Eric Fennis 46bcf1fa89 chore(docs): Remove certificates banner (#4504)
* chore(docs): Remove certificate dev banner

* Remove css
2026-06-29 15:41:58 +02:00
George Nick Gorzynski 7d15e8466a fix(docs): prevent scrollbar layout shift on icons page (#4500)
Adds scrollbar-gutter: stable to html to reserve space for the scrollbar,
preventing layout shift when navigating to/from the icons route.
2026-06-29 09:21:11 +02:00
Ankit SharmaandEric Fennis ce2d598d96 feat(icons): added phi icon also used as golden-ratio (#4218)
* Added icons/phi.svg

* Added icons/phi.json

* Updated icons/phi.json

* Add use-cases to phi.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-28 18:36:16 +02:00
Jakob GuddasandEric Fennis 627b4c1672 fix(icons): changed ungroup icon (#3969)
* Updated icons/ungroup.svg

* Updated icons/ungroup.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-28 17:23:52 +02:00
Jakob Guddasgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
ee02505468 fix(icons): changed carrot icon (#4010)
* Updated icons/carrot.svg

* Updated icons/carrot.json

* Updated icons/carrot.svg

* Updated icons/carrot.json

* Apply suggestions from code review

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-28 17:20:06 +02:00
Konrad SzajnaandClaude Opus 4.8 7c8fbb4813 fix(astro): add Astro v7 compatibility (#4491)
Astro 7 is released and @lucide/astro works with it unchanged. Widen the peerDependencies range to include ^7.

Dev dependencies are intentionally kept on Astro 6: bumping them pulls Vite 8 into the workspace, which destabilizes pnpm's shared peer resolution and breaks the vitest snapshot tests in other packages (icons, svelte).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:32:55 +02:00
Eric Fennis 7e938845f0 fix(lcuide-react-native): Fix context provider export (#4497) 2026-06-25 07:22:42 +02:00
Eric Fennis 0d6c47d545 docs(installation.md): Remove outdate next tag in installation (#4495) 2026-06-24 12:03:14 +02:00
HsiandEric Fennis 2f5af2ceb5 fix(docs): allow icon popularity prebuild without token (#4481)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-24 11:35:49 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 448bcc90fe chore(deps): bump esbuild from 0.25.12 to 0.28.1 (#4459)
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.25.12 to 0.28.1.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2025.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.12...v0.28.1)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.28.1
  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-06-24 11:23:17 +02:00
Bartek Iwańczuk 2fed527c00 docs(site): add Deno to installation instructions (#4486) 2026-06-24 11:17:59 +02:00
Hsi 8fc6b70aa5 fix(docs): fix color input clipping (#4488)
* fix(docs): cap customizer hex input

* fix(docs): use full width color field
2026-06-19 16:16:39 +02:00
Eric Fennis cf0e1e44ba ci(release.yml): Remove concurrency field to prevent release mess (#4485) 2026-06-18 14:41:27 +02:00
BarakudumandEric Fennis 65ef069acc feat(icons): add 6 database variant icons (#4336)
* feat(icons): added database-variants `database-check`, `database-x`, `database-plus`, `database-minus`, `database-arrow-down`, `database-arrow-up`

* fix(metadata): add missing use-cases for database variant icons

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-18 09:06:07 +02:00
7983b2a262 feat(icons): added broken-bone icon (#4131)
* Added icons/broken-bone.svg

* Added icons/broken-bone.json

* redesign according to guidelines

* fix(bone-fracture.json): Remove trailing comma and ensure proper JSON formatting

* 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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-18 08:54:04 +02:00
Hsi 7ddb1e237d fix(docs): rename navigation category label (#4483) 2026-06-17 07:42:12 +02:00
Eric Fennis 5ff536e139 ci(release.yml): Fix workflow and remove version scripts in package scripts (#4479)
* ci(release.yml): Remove new-version in release flow

* Remove version in scripts

* Update workflow
2026-06-16 16:24:07 +02:00
Eric Fennis bb7d2d9839 ci(release.yml): Remove new-version in release flow (#4478) 2026-06-16 15:01:58 +02:00
fc20eb6c7a feat(icons): added pencil-sparkles icon (#4445)
* Added icons/pencil-sparkles.svg

* Added icons/pencil-sparkles.json

* Fix pencil-sparkles artboard

viewbox was previously set to 22px instead of 24px

* 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>

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-06-16 13:21:44 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> d850228c3c chore(deps-dev): bump @angular/common from 21.2.5 to 21.2.17 (#4471)
Bumps [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) from 21.2.5 to 21.2.17.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/v21.2.17/packages/common)

---
updated-dependencies:
- dependency-name: "@angular/common"
  dependency-version: 21.2.17
  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-06-16 08:41:07 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f6cef23cd7 chore(deps-dev): bump markdown-it from 14.1.1 to 14.2.0 (#4475)
Bumps [markdown-it](https://github.com/markdown-it/markdown-it) from 14.1.1 to 14.2.0.
- [Changelog](https://github.com/markdown-it/markdown-it/blob/master/CHANGELOG.md)
- [Commits](https://github.com/markdown-it/markdown-it/compare/14.1.1...14.2.0)

---
updated-dependencies:
- dependency-name: markdown-it
  dependency-version: 14.2.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-06-16 08:37:37 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 766c98af22 chore(deps-dev): bump vitest from 4.0.12 to 4.1.0 (#4429)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.0.12 to 4.1.0.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.0/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.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-06-16 08:36:08 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 1f0f070e84 chore(deps-dev): bump @angular/core from 21.2.5 to 21.2.17 (#4470)
Bumps [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) from 21.2.5 to 21.2.17.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/v21.2.17/packages/core)

---
updated-dependencies:
- dependency-name: "@angular/core"
  dependency-version: 21.2.17
  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-06-16 08:08:03 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> a90271b282 chore(deps-dev): bump @angular/compiler from 21.2.5 to 21.2.17 (#4474)
Bumps [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) from 21.2.5 to 21.2.17.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/v21.2.17/packages/compiler)

---
updated-dependencies:
- dependency-name: "@angular/compiler"
  dependency-version: 21.2.17
  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-06-16 06:32:06 +02:00
Scott Krukowski c81680e066 docs(docs): fix broken Svelte package source link in README (#4468) 2026-06-15 09:42:24 +02:00
0c57f7265a feat(icons): added clock-arrow-out icon (#2404)
* Added icons/clock-arrow-out.svg

* Added icons/clock-arrow-out.json

* Rename icon

* Add empty use-cases array

* Potential fix for pull request finding

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

* Update clock-arrow-right.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 17:51:32 +02:00
Jakob Guddasgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
f917f247e3 feat(icons): added user-round-arrow-in icon (#2283)
* Added icons/user-round-arrow-inwards.svg

* Added icons/user-round-arrow-inwards.json

* Updated icons/user-round-arrow-inwards.json

* Rename user-round-arrow-inwards.json to user-round-arrow-in.json

* Rename user-round-arrow-inwards.svg to user-round-arrow-in.svg

* Rename icon

* Add use cases empty

* Apply suggestions from code review

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-13 17:35:55 +02:00
Jacob Padillagithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AIEric FennisJakob Guddas
aef0f98a68 feat(icons): added summary icon (#3114)
* ai summary icon

* other summary icon svg

* slightly less pronounced curve

* Modify SVG paths in summary.svg

* Update icons/summary.json

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

* 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: Jakob Guddas <github@jguddas.de>
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-06-13 17:31:07 +02:00
6e5c250af0 feat(icons): added clock-arrow-in icon (#2403)
* Added icons/clock-arrow-in.svg

* Added icons/clock-arrow-in.json

* Updated icons/clock-arrow-in.json

* Rename to clock-arrow-left

* 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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 17:25:43 +02:00
Marcos Ramírez F.github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>KarsaCopilot Autofix powered by AIEric Fennis
f37f235d78 feat(icons): added banknote-check icon (#3956)
* Added icons/banknote-check.svg

* Added icons/banknote-check.json

* Update icons/banknote-check.json

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

* Apply suggestions from code review

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

* Potential fix for pull request finding

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

* Update banknote-check.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 17:02:57 +02:00
b973e42174 feat(icons): added tag-plus and tag-x icons (#3980)
* add tag-plus icon

* add tag-x icon

* Update icons/tag-x.svg

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

* Apply suggestions from code review

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

* Apply suggestions from code review

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-13 17:02:40 +02:00
Eric Fennis ce6fb3dd6c fix(metadata): Add use-cases to auto-save 2026-06-13 16:55:50 +02:00
c3262987be feat(icons): added save-check icon (#3120)
* Added icons/save-check.svg

* Added icons/save-check.json

* Fixing angle of the checkmark to be 90 degrees

* Adding contributors of the save icon

* Update save-check.svg paths for new design

* Update save-check.svg

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-06-13 15:51:47 +02:00
Jamie Law 52ee7b3692 Add tags to search- icons (#4099) 2026-06-13 15:32:02 +02:00
Jakob Guddas 04ee825d6b fix(icons): decreased size of arrows inside square-arrow-* icons (#3926)
* Updated icons/square-arrow-down-left.svg

* Updated icons/square-arrow-down-left.json

* Updated icons/square-arrow-up-right.svg

* Updated icons/square-arrow-up-right.json

* Updated icons/square-arrow-up-left.svg

* Updated icons/square-arrow-up-left.json

* Updated icons/square-arrow-down-right.svg

* Updated icons/square-arrow-down-right.json
2026-06-13 15:29:54 +02:00
Jakob GuddasKyle Angelo GalendezEric Fennisgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AI
0241b57c35 feat(icons): added podium icon (#2124)
* Added icons/podium.svg

* Added icons/podium.json

* Updated icons/podium.svg

* Update icons/podium.json

Co-authored-by: Kyle Angelo Galendez <xcxkyleangelo26@gmail.com>

* Update icons/podium.svg

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

* Apply suggestion from @github-actions[bot]

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

* 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>

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Kyle Angelo Galendez <xcxkyleangelo26@gmail.com>
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-06-13 15:25:52 +02:00
Eric FennisandCopilot Autofix powered by AI 24dd855b87 feat(site): Improve search and add sorting options (#4453)
* setup icon popularity call

* Adjust sort button

* Adjust sorting

* Adds aliases

* Format code

* 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>

* 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>

* 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>

* Add check for env variable

* 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>

* Improve styling on mobile

* Remove hardcoded sort icon

* Fix build

* Format code

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 15:25:41 +02:00
Jakob Guddasgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
4e5fce4adc fix(icons): changed wallet-cards icon (#3888)
* Updated icons/wallet-cards.svg

* Updated icons/wallet-cards.json

* Update icons/wallet-cards.json

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

* Updated icons/wallet-cards.svg

* Updated icons/wallet-cards.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-13 15:23:19 +02:00
Vyctor H. Brzezowski ae94b5118b fix(site): reserve space for icon detail drawer (#4344) 2026-06-13 15:04:57 +02:00
Eric Fennis 2dd4be802a Fix provider exports (#4463) 2026-06-13 14:51:48 +02:00
Eric Fennisgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AI
f4fa0512d3 feat(icons): added list-sort-descending icon (#4457)
* Added icons/list-sort.svg

* Added icons/list-sort.json

* Update list-sort.json

* Apply suggestions from code review

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

* Potential fix for pull request finding

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

* Update naming

* Also add the ascending version

* 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>

* Potential fix for pull request finding

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

---------

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-06-13 14:05:31 +02:00
d1150cea7a feat(icons): added save-plus icon (#4448)
* add json for icons

* Added icons/save-plus.svg

* Added icons/save-plus.json

* Add additional tags to save-plus.json

* Removed out of scope changes

* 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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 14:04:52 +02:00
KarsaandEric Fennis 4afccc1842 feat(icons): added eye-dashed icon (#4415)
* Added icons/eye-dashed.svg

* Added icons/eye-dashed.json

* Update icons/eye-dashed.json

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

* Improve writing of use-cases

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-13 14:04:20 +02:00
4e161a15ef feat(icons): added ad icon (#4323)
* Added icons/ad.svg

* Added icons/ad.json

* Add use-cases to meta json file

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>

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 12:41:38 +02:00
76175250cd feat(icons): added wrench-off icon (#4434)
* Added icons/wrench-off.svg

* Added icons/wrench-off.json

* Update icons/wrench-off.svg

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

* 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>

* Add new tags to wrench-off.json

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 12:38:38 +02:00
2e58e319e7 feat(icons): added save-pen icon (#4179)
* Added icons/save-pen.svg

* Added icons/save-pen.json

* Updated icons/save-pen.svg

* Apply design from karsa

* 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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-13 12:33:48 +02:00
Eric FennisandCopilot Autofix powered by AI 283e4b2805 chore(suggest-tags): Update metadata suggestion script (#4462)
* feat(metadata): implement pull request metadata suggestions workflow and replace suggestTags script

* Switch to GPT 5

* Update comment description

* 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-06-13 12:28:04 +02:00
db63e66333 feat(icons): added star-* icons (#3918)
* Added icons/star-check.svg

* Added icons/star-check.json

* Add star-x.svg icon

* Add star-x icon JSON

* Add star-minus.svg icon file

* Add star-plus SVG icon

* Add star-plus icon JSON configuration

* Add 'remove' and 'deselect' to star-minus.json

* Update star-check.svg with new path data

* Modify star-x.svg paths for new design

* Modify star-minus SVG paths for new design

* Modify star-plus.svg paths for new design

* Update star-x.svg

* Username change

* Username change

* Update star-minus.json

* Update and rename star-check.json to Username change

* Username change

* Modify star-plus.svg paths for new design

* Refactor star-minus.svg paths for clarity

* Update star-plus.svg paths for new design

* Update SVG path for star-check icon

* Adjust path element in star-minus.svg

* Update star-minus.svg paths and adjust dimensions

* Update icons/star-x.svg

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

* Update icons/star-check.svg

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

* Update star-check.svg

* Merge pull request #1

Added use case

* Fix JSON formatting in star-minus.json

* Update star-plus.json

* Fix JSON syntax in star-x.json

---------

Co-authored-by: Rajnish Mehta <172272341+KnarliX@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-06-13 12:19:51 +02:00
Eric Fennis 4b3521a3e3 chore(deps): upgrade pnpm to version 11.6.0 (#4458)
* chore: upgrade pnpm to version 11.6.0 and restore package extensions and overrides in pnpm workspace

* Remove packageExtensions

* Update lockfile
2026-06-12 16:09:47 +02:00
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
2723 changed files with 29218 additions and 11860 deletions
+1
View File
@@ -9,3 +9,4 @@ strikethrough
touchpad
ungroup
toc
sunlounger
+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
View File
@@ -47,7 +47,9 @@ Common scopes: icons, docs, studio, site, dev
### Design <!-- ONLY for new icons -->
<!-- All of these requirements must be fulfilled. -->
- [ ] I've read and followed the [icon design guidelines](https://lucide.dev/contribute/icon-design-guide)
- [ ] I've made sure that the icons don't [already exist](https://lucide.dev/icons), including the [Lab directory](https://github.com/lucide-icons/lucide/tree/main/lab).
- [ ] I've made sure that the icons look sharp on low DPI displays.
- [ ] I've made sure that the icons look consistent with the icon set in size, optical volume and density.
- [ ] I've made sure that the icons are visually centered.
+30 -5
View File
@@ -27,13 +27,38 @@ permissions:
id-token: write # Required for OIDC
contents: write
# This is added to make sure we wait until last release is done, this is needed for the font-build process
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 }}
@@ -33,7 +33,7 @@ jobs:
Lucide **does not accept** brand logos, and we do not plan to add them in the future. This is due to a combination of **legal restrictions**, **design consistency concerns**, and **practical maintenance reasons**.
[Click here to read our official statement about brand logos in Lucide.](./BRAND_LOGOS_STATEMENT.md)
[Click here to read our official statement about brand logos in Lucide.](https://github.com/lucide-icons/lucide/blob/main/BRAND_LOGOS_STATEMENT.md)
You can [search for similar issues.](https://github.com/lucide-icons/lucide/issues?q=is%3Aissue+${VALUE})
+1 -3
View File
@@ -1,9 +1,7 @@
name: Linting PR
name: Linting PR code
on:
pull_request:
paths-ignore:
- icons/*.svg
jobs:
lint-code:
+1 -1
View File
@@ -1,4 +1,4 @@
name: Linting PR
name: Linting PR title
on:
pull_request:
+29 -1
View File
@@ -7,6 +7,7 @@ on:
pull_request:
paths:
- 'icons/*'
- 'lab/*'
jobs:
lint-filenames:
@@ -17,20 +18,47 @@ jobs:
contents: read
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: Get changed files
id: changed-files
uses: tj-actions/changed-files@v46
with:
files: icons/*
files: |
icons/*
lab/*
- name: Generate annotations
run: node ./scripts/lintFilenames.mts
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
check-lab-icons:
name: Check Lab Icons
runs-on: ubuntu-latest
permissions:
contents: read
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: Check lab icons do not already exist in icons
run: node ./scripts/checkLabIcons.mts
lint-aliases:
name: Check Uniqueness of Aliases
runs-on: ubuntu-latest
+30
View File
@@ -0,0 +1,30 @@
name: Lucide Lab checks
on:
pull_request:
paths:
- packages/lab/**
- packages/shared/**
- tools/build-icons/**
- tools/rollup-plugins/**
- pnpm-lock.yaml
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
cache: 'pnpm'
node-version-file: 'package.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm --filter @lucide/lab build
-3
View File
@@ -11,9 +11,6 @@ on:
- tools/rollup-plugins/**
- pnpm-lock.yaml
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -1,4 +1,4 @@
name: Pull request tags suggestions
name: Pull request metadata suggestions
on:
pull_request_target:
@@ -6,8 +6,8 @@ on:
- 'icons/*.json'
jobs:
pull-request-tags-suggestions:
name: Pull Request Tags Suggestions
pull-request-metadata-suggestions:
name: Pull Request Metadata Suggestions
runs-on: ubuntu-latest
permissions:
contents: read
@@ -29,7 +29,7 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Generate comment markup
run: node ./scripts/suggestTags.mts
run: node ./scripts/suggestMetaData.mts
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PULL_REQUEST_NUMBER: ${{ github.event.number }}
+2 -5
View File
@@ -20,9 +20,6 @@ permissions:
id-token: write # Required for OIDC
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
prepare:
if: github.repository == 'lucide-icons/lucide' && contains('["ericfennis", "karsa-mistmere", "jguddas"]', github.actor)
@@ -74,7 +71,7 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Set new version
run: pnpm --fail-if-no-match --filter ${{ matrix.package }} version --new-version ${{ needs.prepare.outputs.VERSION }} --no-git-tag-version
run: pnpm version ${{ needs.prepare.outputs.VERSION }} --filter ${{ matrix.package }} --fail-if-no-match --no-git-tag-version
- name: Build
run: pnpm --filter ${{ matrix.package }} build
@@ -108,7 +105,7 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Set new version
run: pnpm --filter lucide-static version --new-version ${{ needs.prepare.outputs.VERSION }} --no-git-tag-version
run: pnpm version ${{ needs.prepare.outputs.VERSION }} --filter lucide-static --no-git-tag-version
- name: Move Font
run: cp -r lucide-font packages/lucide-static/font
+42
View File
@@ -0,0 +1,42 @@
name: Weekly Repo Report
on:
workflow_dispatch:
# Run this workflow every Monday at 07:00 UTC
schedule:
- cron: '0 7 * * 1'
permissions:
contents: read
jobs:
weekly-summary:
runs-on: ubuntu-latest
steps:
- name: Set up Node.js environment
uses: actions/setup-node@v4
with:
node-version: 24
- name: Install Copilot CLI
run: npm install -g @github/copilot
- name: Run the prompt
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
run: |
copilot -p "${{ vars.REPO_REPORT_PROMPT }} Write the details to summary.md" --allow-tool='shell(git:*)' --allow-tool=write --no-ask-user
cat summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Post report to Discord (private channel)
env:
DISCORD_WEBHOOK_URL: ${{ secrets.LUCIDE_DISCORD_WEBHOOK }}
run: |
jq -Rs '{
embeds: [{
title: "📊 Weekly Repo Report",
description: (.[0:4096]),
color: 5814783
}]
}' summary.md > payload.json
curl -sS --fail -X POST \
-H "Content-Type: application/json" \
-d @payload.json \
"$DISCORD_WEBHOOK_URL"
+2 -2
View File
@@ -1,6 +1,6 @@
name: 'Request Review'
name: Request Review
on:
pull_request_target:
pull_request:
types: [opened]
paths:
- icons/*.svg
+4 -1
View File
@@ -53,8 +53,11 @@ docs/.vitepress/data/categoriesData.json
docs/.vitepress/data/iconDetails
docs/.vitepress/data/relatedIcons.json
docs/.vitepress/data/brandStopwords.json
docs/.vitepress/data/iconPopularity
docs/.vitepress/data/lab/iconNodes
docs/.vitepress/data/lab/iconMetaData.ts
docs/.vitepress/data/lab/iconPopularity
docs/.vercel
docs/.nitro
docs/public/og/**
!docs/public/og/general.png
.gitignore
+1 -1
View File
@@ -30,7 +30,7 @@ Read it here: [ICON_GUIDELINES](https://lucide.dev/contribute/icon-design-guide)
#### Lucide Studio
For formatting and adjusting SVG icons, [@jguddas](https://github.com/jguddas) made a great tool called [Lucide Studio](https://studio.lucide.dev/). It is a web-based SVG editor that allows you to edit and adjust icons in the Lucide style. You can use it to create new icons or modify existing ones.
For formatting and adjusting SVG icons, [@jguddas](https://github.com/jguddas) made a great tool called [Lucide Studio](https://studio.lucide.dev/?utm_source=lucide.dev&utm_medium=contributing-guide). It is a web-based SVG editor that allows you to edit and adjust icons in the Lucide style. You can use it to create new icons or modify existing ones.
#### Editor guides
+1 -1
View File
@@ -35,7 +35,7 @@ Lucide is an open-source icon library that provides 1600+ vector (svg) files for
| <img src="https://lucide.dev/framework-logos/js.svg" alt="JS logo" width="48"> | **`lucide`** | [![npm](https://img.shields.io/npm/v/lucide)](https://www.npmjs.com/package/lucide) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide) | [Docs](https://lucide.dev/guide/lucide) · [Source](./packages/lucide) |
| <img src="https://lucide.dev/framework-logos/react.svg" alt="React logo" width="48"> | **`lucide-react`** | [![npm](https://img.shields.io/npm/v/lucide-react)](https://www.npmjs.com/package/lucide-react) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react) | [Docs](https://lucide.dev/guide/react) · [Source](./packages/lucide-react) |
| <img src="https://lucide.dev/framework-logos/vue.svg" alt="Vue logo" width="48"> | **`@lucide/vue`** | [![npm](https://img.shields.io/npm/v/@lucide/vue)](https://www.npmjs.com/package/@lucide/vue) | ![NPM Downloads](https://img.shields.io/npm/dw/@lucide/vue) | [Docs](https://lucide.dev/guide/vue) · [Source](./packages/vue) |
| <img src="https://lucide.dev/framework-logos/svelte.svg" alt="Svelte logo" width="48"> | **`@lucide/svelte`** | [![npm](https://img.shields.io/npm/v/@lucide/svelte)](https://www.npmjs.com/package/@lucide/svelte) | ![NPM Downloads](https://img.shields.io/npm/dw/@lucide/svelte) | [Docs](https://lucide.dev/guide/svelte) · [Source](./packages/@lucide/svelte) |
| <img src="https://lucide.dev/framework-logos/svelte.svg" alt="Svelte logo" width="48"> | **`@lucide/svelte`** | [![npm](https://img.shields.io/npm/v/@lucide/svelte)](https://www.npmjs.com/package/@lucide/svelte) | ![NPM Downloads](https://img.shields.io/npm/dw/@lucide/svelte) | [Docs](https://lucide.dev/guide/svelte) · [Source](./packages/svelte) |
| <img src="https://lucide.dev/framework-logos/solid.svg" alt="Solid logo" width="48"> | **`lucide-solid`** | [![npm](https://img.shields.io/npm/v/lucide-solid)](https://www.npmjs.com/package/lucide-solid) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-solid) | [Docs](https://lucide.dev/guide/solid) · [Source](./packages/lucide-solid) |
| <img src="https://lucide.dev/framework-logos/preact.svg" alt="Preact logo" width="48"> | **`lucide-preact`** | [![npm](https://img.shields.io/npm/v/lucide-preact)](https://www.npmjs.com/package/lucide-preact) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-preact) | [Docs](https://lucide.dev/guide/preact) · [Source](./packages/lucide-preact) |
| <img src="https://lucide.dev/framework-logos/react-native.svg" alt="React Native logo" width="48"> | **`lucide-react-native`** | [![npm](https://img.shields.io/npm/v/lucide-react-native)](https://www.npmjs.com/package/lucide-react-native) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react-native) | [Docs](https://lucide.dev/guide/react-native) · [Source](./packages/lucide-react-native) |
+4 -5
View File
@@ -56,7 +56,6 @@
"kubernetes": "Kubernetes",
"leetcode": "LeetCode",
"leet-code": "LeetCode",
"line": "LINE",
"linkedin": "LinkedIn",
"lua": "Lua",
"mariadb": "MariaDB",
@@ -69,7 +68,7 @@
"nestjs": "NestJS",
"netflix": "Netflix",
"netlify": "Netlify",
"next": "Next.js",
"nextjs": "Next.js",
"nodejs": "Node.js",
"notion": "Notion",
"nostr": "Nostr",
@@ -105,7 +104,8 @@
"shopify": "Shopify",
"skype": "Skype",
"slack": "Slack",
"solid": "SolidJS",
"snapchat": "Snapchat",
"solidjs": "SolidJS",
"soundcloud": "SoundCloud",
"spotify": "Spotify",
"sqlite": "SQLite",
@@ -144,6 +144,5 @@
"xbox": "Xbox",
"yarn": "Yarn",
"youtube": "YouTube",
"zig": "Zig",
"zoom": "Zoom"
"zig": "Zig"
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Navigation, Maps, and POIs",
"title": "Navigation & Places",
"icon": "compass"
}
@@ -0,0 +1,25 @@
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../../data/lab/iconMetaData';
import iconPopularity from '../../../data/lab/iconPopularity';
import iconNodes from '../../../data/lab/iconNodes';
export default eventHandler((event) => {
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
return Object.fromEntries(
Object.entries(iconMetaData).map(([iconName, iconData]) => {
// Remove $schema from the response
delete iconData['$schema'];
return [
iconName,
{
name: iconName,
iconNode: iconNodes[iconName],
popularity: iconPopularity[iconName]?.count ?? 0,
...iconData,
},
];
}),
);
});
@@ -0,0 +1,14 @@
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../../data/lab/iconMetaData';
export default eventHandler((event) => {
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
for (const iconDetail in iconMetaData) {
// Remove $schema from the response
delete iconMetaData[iconDetail]['$schema'];
}
return iconMetaData;
});
@@ -0,0 +1,30 @@
import { eventHandler, getQuery, setResponseHeader } from 'h3';
import iconNodes from '../../../data/lab/iconNodes';
type IconNodeWithKeys = [elementName: string, attrs: Record<string, string> & { key?: string }][];
export default eventHandler((event) => {
const query = getQuery(event);
const withUniqueKeys = query.withUniqueKeys === 'true';
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
if (withUniqueKeys) {
return iconNodes;
}
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
if (withUniqueKeys) {
return [name, iconNode];
}
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs }]) => {
return [name, attrs];
});
acc[name] = newIconNode;
return acc;
}, {});
});
+2 -1
View File
@@ -101,6 +101,7 @@ export default defineConfig({
},
{ text: 'Packages', link: '/packages' },
{ text: 'Showcase', link: '/showcase' },
{ text: 'Merch', link: 'https://merch.lucide.dev/' },
],
sidebar,
socialLinks: [
@@ -109,7 +110,7 @@ export default defineConfig({
],
footer: {
message: 'Released under the ISC License.',
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`,
copyright: `Copyright © ${new Date().getFullYear()} Lucide Icons`,
},
editLink: {
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path',
+1 -1
View File
@@ -97,7 +97,7 @@
},
{
"name": "navigation",
"title": "Navigation, Maps, and POIs"
"title": "Navigation & Places"
},
{
"name": "notifications",
View File
@@ -209,5 +209,24 @@
],
"source": "https://github.com/shx08/strapi-lucide-icons",
"documentation": "https://github.com/shx08/strapi-lucide-icons/blob/main/README.md"
},
{
"name": "lucide-lit",
"description": "Implementation of Lucide icons as Lit web components.",
"icon": "/framework-logos/lit.svg",
"shields": [
{
"alt": "Latest Stable Version",
"src": "https://img.shields.io/npm/v/@gyeonghokim/lucide-lit",
"href": "https://www.npmjs.com/package/@gyeonghokim/lucide-lit"
},
{
"alt": "Total Downloads",
"src": "https://img.shields.io/npm/dw/@gyeonghokim/lucide-lit",
"href": "https://www.npmjs.com/package/@gyeonghokim/lucide-lit"
}
],
"source": "https://github.com/GyeongHoKim/lucide-lit",
"documentation": "https://github.com/GyeongHoKim/lucide-lit/blob/main/README.md"
}
]
-7
View File
@@ -24,13 +24,6 @@ const getHeadConfig = ({
defer: '',
},
],
[
'script',
{
src: 'https://media.bitterbrains.com/main.js?from=LUCIDE&type=top',
async: 'true',
},
],
[
'meta',
{
+5
View File
@@ -72,6 +72,11 @@ export const reactNativeSidebar = [
link: '/guide/react-native/advanced/combining-icons',
desc: 'Combine multiple icons into one',
},
{
text: 'Optimizations',
link: '/guide/react-native/advanced/optimizations',
desc: 'Optimizing your app for performance',
},
],
},
{
@@ -11,6 +11,14 @@ const { isDark } = useData();
const emit = defineEmits(['update:modelValue']);
function limitHexInput(val: string) {
if (val.startsWith('#')) {
return val.slice(0, 9);
}
return val.slice(0, 8);
}
const value = computed({
get: () => {
if (props.modelValue == null || props.modelValue === 'currentColor') {
@@ -19,7 +27,7 @@ const value = computed({
return props.modelValue;
},
set: (val) => emit('update:modelValue', val),
set: (val) => emit('update:modelValue', limitHexInput(val)),
});
</script>
@@ -41,6 +49,7 @@ const value = computed({
class="color-input-text"
aria-label="Color picker input"
v-model="value"
maxlength="9"
placeholder="[default]"
/>
</div>
@@ -91,6 +100,7 @@ const value = computed({
background: transparent;
color: var(--vp-c-text-1);
font-size: 13px;
font-family: var(--vp-font-family-mono);
text-align: left;
border-radius: 8px;
cursor: text;
@@ -6,10 +6,10 @@ import SelectIcon from './SelectIcon.vue';
defineProps<{
id?: string;
items?: { name: string; route: string; icon: string; iconDark?: string }[];
items?: { name: string; value: string; icon?: string; iconDark?: string }[];
}>();
const selected = defineModel<{ name: string; icon: string; iconDark?: string }>();
const selected = defineModel<{ name: string; value: string; icon?: string; iconDark?: string }>();
</script>
<template>
@@ -19,14 +19,18 @@ const selected = defineModel<{ name: string; icon: string; iconDark?: string }>(
class="select-button"
:id="id"
>
<SelectIcon :item="selected" />
<slot name="start-icon">
<SelectIcon v-if="selected.icon" :item="selected" />
</slot>
<span class="select-text">{{ selected.name }}</span>
<span class="select-icon">
<Icon
:iconNode="chevronsUpDown"
class="chevron-icon"
aria-hidden="true"
/>
<slot name="end-icon">
<Icon
:iconNode="chevronsUpDown"
class="chevron-icon"
aria-hidden="true"
/>
</slot>
</span>
</ListboxButton>
@@ -43,8 +47,9 @@ const selected = defineModel<{ name: string; icon: string; iconDark?: string }>(
:value="item"
as="template"
>
<li :class="['select-option', { active, selected }]">
<SelectIcon :item="item" />
<SelectIcon v-if="item.icon" :item="item" />
<span :class="['option-text', { selected }]">{{ item.name }}</span>
<span
v-if="selected"
@@ -2,25 +2,28 @@
const { item } = defineProps<{
item: {
name: string;
icon: string;
icon?: string;
iconDark?: string;
};
}>();
</script>
<template>
<img
:src="item.icon"
:class="{ 'select-item-icon': true, light: item.iconDark }"
:alt="`${item.name} logo`"
loading="lazy"
/>
<img
v-if="item.iconDark"
:src="item.iconDark"
:alt="`${item.name} logo`"
class="select-item-icon dark"
/>
<div v-if="item.icon || item.iconDark">
<img
v-if="item.icon"
:src="item.icon"
:class="{ 'select-item-icon': true, light: item.iconDark }"
:alt="`${item.name} logo`"
loading="lazy"
/>
<img
v-if="item.iconDark"
:src="item.iconDark"
:alt="`${item.name} logo`"
class="select-item-icon dark"
/>
</div>
</template>
<style scoped>
@@ -1,90 +0,0 @@
<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>
@@ -11,49 +11,49 @@ const { page } = useData();
const router = useRouter();
const frameworks = [
{ name: 'Vanilla', icon: '/framework-logos/js.svg', route: '/guide/lucide/' },
{ name: 'React', icon: '/framework-logos/react.svg', route: '/guide/react/' },
{ name: 'Vue', icon: '/framework-logos/vue.svg', route: '/guide/vue/' },
{ name: 'Svelte', icon: '/framework-logos/svelte.svg', route: '/guide/svelte/' },
{ name: 'Solid', icon: '/framework-logos/solid.svg', route: '/guide/solid/' },
{ name: 'Angular', icon: '/framework-logos/angular.svg', route: '/guide/angular/' },
{ name: 'Preact', icon: '/framework-logos/preact.svg', route: '/guide/preact/' },
{ name: 'Vanilla', icon: '/framework-logos/js.svg', value: '/guide/lucide/' },
{ name: 'React', icon: '/framework-logos/react.svg', value: '/guide/react/' },
{ name: 'Vue', icon: '/framework-logos/vue.svg', value: '/guide/vue/' },
{ name: 'Svelte', icon: '/framework-logos/svelte.svg', value: '/guide/svelte/' },
{ name: 'Solid', icon: '/framework-logos/solid.svg', value: '/guide/solid/' },
{ name: 'Angular', icon: '/framework-logos/angular.svg', value: '/guide/angular/' },
{ name: 'Preact', icon: '/framework-logos/preact.svg', value: '/guide/preact/' },
{
name: 'React Native',
icon: '/framework-logos/react-native.svg',
route: '/guide/react-native/',
value: '/guide/react-native/',
},
{
name: 'Astro',
icon: '/framework-logos/astro.svg',
iconDark: '/framework-logos/astro-dark.svg',
route: '/guide/astro/',
value: '/guide/astro/',
},
{ name: 'Static', icon: '/framework-logos/svg.svg', route: '/guide/static/' },
{ name: 'Static', icon: '/framework-logos/svg.svg', value: '/guide/static/' },
];
const fallbackFramework = useLocalStorage('lucide-docs-fallback-framework', frameworks[1]);
const selected = computed(() => {
const current = frameworks.find(({ route }) => {
const current = frameworks.find(({ value }) => {
if (router.route.path?.startsWith?.('/guide')) {
const [, , framework] = router.route.path.split('/');
const [, frameWorkRoute] = route.split('/').filter(Boolean);
const [, frameWorkRoute] = value.split('/').filter(Boolean);
return framework === frameWorkRoute;
}
return router.route.path.split('/').slice(0, 3).join('/') === route;
return router.route.path.split('/').slice(0, 3).join('/') === value;
});
return current || fallbackFramework.value;
return current || (fallbackFramework.value?.value ? fallbackFramework.value : frameworks[0]);
});
function onSelectFramework(item: { name: string; icon: string; iconDark?: string; route: string }) {
function onSelectFramework(item: { name: string; icon: string; iconDark?: string; value: string }) {
fallbackFramework.value = item;
if (item.route !== router.route.path) {
const likeRoute = router.route.path.replace(selected.value.route, item.route);
if (item.value !== router.route.path) {
const likeRoute = router.route.path.replace(selected.value.value, item.value);
const hasRoute = sidebar[item.route]?.some((section) =>
const hasRoute = sidebar[item.value]?.some((section) =>
section?.items?.some(({ link }) => link === likeRoute),
);
@@ -62,7 +62,7 @@ function onSelectFramework(item: { name: string; icon: string; iconDark?: string
return;
}
router.go(item.route);
router.go(item.value);
}
}
</script>
@@ -85,12 +85,12 @@ function onSelectFramework(item: { name: string; icon: string; iconDark?: string
/>
</div>
<VPSidebarGroup
:key="selected.route"
:key="selected.value"
v-if="
page?.relativePath?.startsWith?.('guide') &&
!page?.relativePath?.startsWith?.(selected.route.substring(1))
!page?.relativePath?.startsWith?.(selected.value.substring(1))
"
:items="sidebar[selected.route]"
:items="sidebar[selected.value]"
/>
</template>
@@ -13,23 +13,21 @@ const { go } = useRouter()
<HomeSectionTitle>Available For:</HomeSectionTitle>
<div class="packages-list">
<a
v-for="{ name, logo, logoDark } in data.packages"
:href="`/guide/packages/${name}`"
v-for="{ name, label, path, logo, logoDark } in data.packages"
:href="path"
class="package-logo"
:aria-label="`Read more about: ${name} package`"
@click.prevent="go(`/guide/packages/${name}`)"
@click.prevent="go(path)"
>
<img
:src="logo"
:class="{ light: logoDark, 'image-logo': true }"
:alt="`${name} logo`"
:alt="label"
loading="lazy"
/>
<img
v-if="logoDark"
:src="logoDark"
:alt="`${name} logo`"
:alt="label"
class="image-logo dark"
loading="lazy"
/>
@@ -188,7 +188,7 @@ const deprecatedTitle = computed(() => {
-ms-overflow-style: none;
scrollbar-width: none;
scrollbar-width: thin; /* can also be normal, or none, to not render scrollbar */
scrollbar-color: currentColor transparent; /* foreground background */
scrollbar-color: var(--vp-c-text-4) transparent; /* foreground background */
}
.horizontal-scroller::-webkit-scrollbar {
width: 0;
@@ -3,6 +3,7 @@ import type { IconEntity } from '../../types';
import { computed, ref } from 'vue';
import createLucideIcon from '@lucide/vue/src/createLucideIcon';
import { useIconStyleContext } from '../../composables/useIconStyle';
import { squarePen } from '../../../data/iconNodes';
const props = defineProps<{
name: IconEntity['name'];
@@ -19,6 +20,31 @@ const iconComponent = computed(() => {
if (!props.name || !props.iconNode) return null;
return createLucideIcon(props.name, props.iconNode);
});
const SquarePenIcon = createLucideIcon('SquarePen', squarePen);
const innerSvg = computed(() => {
if (!props.iconNode) return '';
const string = props.iconNode
.map(([tag, attrs]) => {
const attributes = Object.entries(attrs)
.map(([key, value]) => `${key}="${value}"`)
.join(' ');
return `<${tag} ${attributes}/>`;
})
.join('');
return string
.replace(/>[\r\n ]+</g, '><')
.replace(/(<.*?>)|\s+/g, (m, $1) => $1 || ' ')
.trim();
});
const base64InnerSvg = computed(() => {
if (typeof window === 'undefined') return '';
return btoa(innerSvg.value);
});
</script>
<template>
@@ -57,6 +83,16 @@ const iconComponent = computed(() => {
/>
</g>
</svg>
<a
:href="`https://studio.lucide.dev/edit?value=${encodeURIComponent(base64InnerSvg)}&name=${name}&utm_source=lucide.dev&utm_medium=icon-detail-preview`"
target="_blank"
rel="noopener noreferrer"
class="studio-button"
title="Open in Lucide Studio"
aria-label="Open in Lucide Studio"
>
<SquarePenIcon :size="14" />
</a>
</div>
</template>
@@ -75,6 +111,8 @@ const iconComponent = computed(() => {
position: relative;
background: var(--vp-c-bg-alt);
border-radius: 8px;
overflow: hidden;
flex-shrink: 0;
}
.icon-container > :deep(svg:not(.icon-grid)) {
width: 100%;
@@ -85,6 +123,34 @@ const iconComponent = computed(() => {
opacity: 0.8;
}
.studio-button {
position: absolute;
bottom: 8px;
right: 8px;
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
padding: 5px;
display: flex;
align-items: center;
justify-content: center;
color: var(--vp-c-text-2);
opacity: 0;
transition: opacity 0.2s, color 0.2s, background-color 0.2s;
z-index: 2;
}
.icon-container:hover .studio-button,
.studio-button:focus-visible {
opacity: 1;
}
.studio-button:hover,
.studio-button:focus-visible {
background: var(--vp-c-bg-soft);
color: var(--vp-c-text-1);
}
.icon-component.customizable {
will-change: width, height, stroke-width, stroke;
/* color: var(--customize-color, currentColor);
@@ -44,8 +44,12 @@ function setActiveIconName(name: string) {
activeIconName.value = name;
}
const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories();
const { execute: fetchTags, data: tags, isFetching: isFetchingTags } = useFetchTags();
const {
execute: fetchCategories,
data: categoriesMap,
isFetching: isFetchingCategories,
} = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl);
@@ -117,6 +121,9 @@ const categoriesList = computed(() => {
}, []);
});
const searchPlaceholder = useSearchPlaceholder(searchQuery, searchResults);
const isSearchMetadataLoading = computed(
() => searchQuery.value.length > 0 && (tags.value == null || categoriesMap.value == null),
);
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(categoriesList, {
itemHeight: ICON_SIZE + ICON_GRID_GAP,
@@ -135,15 +142,21 @@ onMounted(() => {
useEventListener(window, 'scroll', containerProps.onScroll);
});
function onFocusSearchInput() {
if (tags.value == null) {
fetchTags();
function loadSearchMetadata() {
if (tags.value == null && !isFetchingTags.value) {
void fetchTags();
}
if (categoriesMap.value == null) {
fetchCategories();
if (categoriesMap.value == null && !isFetchingCategories.value) {
void fetchCategories();
}
}
watch(searchQuery, (searchString) => {
if (searchString !== '') {
loadSearchMetadata();
}
});
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
@@ -156,11 +169,11 @@ function handleCloseDrawer() {
if (searchQueryDebounced.value) {
url.searchParams.set('search', searchQueryDebounced.value);
}
if (selectedCategory.value) {
url.hash = selectedCategory.value;
}
window.history.pushState({}, '', url);
}
</script>
@@ -169,6 +182,7 @@ function handleCloseDrawer() {
<div
ref="overviewEl"
class="overview-container"
:class="{ 'icon-drawer-open': activeIconName }"
>
<StickyBar class="category-search">
<InputSearch
@@ -177,11 +191,11 @@ function handleCloseDrawer() {
:shortcut="kbdSearchShortcut"
class="input-wrapper"
ref="searchInput"
@focus="onFocusSearchInput"
@focus="loadSearchMetadata"
/>
</StickyBar>
<NoResults
v-if="searchPlaceholder.isNoResults"
v-if="searchPlaceholder.isNoResults && !isSearchMetadataLoading"
:searchQuery="searchPlaceholder.query"
:isBrandSearch="searchPlaceholder.isBrand"
@clear="searchQuery = ''"
@@ -4,6 +4,7 @@ import type { IconEntity } from '../../types';
import { useElementSize, useEventListener, useVirtualList } from '@vueuse/core';
import { useRoute } from 'vitepress';
import IconGrid from './IconGrid.vue';
import Select from '../base/Select.vue';
import InputSearch from '../base/InputSearch.vue';
import useSearch from '../../composables/useSearch';
import useSearchInput from '../../composables/useSearchInput';
@@ -14,9 +15,26 @@ import useFetchCategories from '../../composables/useFetchCategories';
import chunkArray from '../../utils/chunkArray';
import CarbonAdOverlay from './CarbonAdOverlay.vue';
import useSearchPlaceholder from '../../utils/useSearchPlaceholder.ts';
import Icon from '@lucide/vue/src/Icon';
import { listSortDescending } from '~/.vitepress/data/iconNodes';
const ICON_SIZE = 56;
const ICON_GRID_GAP = 8;
const SORTING = [
{
name: 'Popularity',
value: 'popularity',
},
{
name: 'Release date',
value: 'release-date',
},
{
name: 'Name',
value: 'name',
},
]
const initialGridItems = computed(() => {
if (containerWidth.value === 0) return 120;
@@ -32,9 +50,14 @@ const props = defineProps<{
}>();
const activeIconName = ref(null);
const selectedSort = ref(SORTING[0])
const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categories } = useFetchCategories();
const { execute: fetchTags, data: tags, isFetching: isFetchingTags } = useFetchTags();
const {
execute: fetchCategories,
data: categories,
isFetching: isFetchingCategories,
} = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl);
@@ -43,12 +66,29 @@ const columnSize = computed(() => {
return Math.floor(containerWidth.value / (ICON_SIZE + ICON_GRID_GAP));
});
const sortedIcons = computed(() => {
switch (selectedSort.value.value) {
case 'popularity':
return [...props.icons].sort((a, b) => (b.popularity || 0) - (a.popularity || 0));
case 'release-date':
return [...props.icons].sort((a, b) => {
const aDate = a.createdRelease?.date ? new Date(a.createdRelease.date).getTime() : 0;
const bDate = b.createdRelease?.date ? new Date(b.createdRelease.date).getTime() : 0;
return bDate - aDate;
});
case 'name':
return [...props.icons].sort((a, b) => a.name.localeCompare(b.name));
default:
return props.icons;
}
});
const mappedIcons = computed(() => {
if (tags.value == null) {
return props.icons;
return sortedIcons.value;
}
return props.icons.map((icon) => {
return sortedIcons.value.map((icon) => {
const iconTags = tags.value[icon.name];
const iconCategories = categories.value?.[icon.name] ?? [];
@@ -68,11 +108,15 @@ const { shortcutText: kbdSearchShortcut } = useSearchShortcut(() => {
const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
{ name: 'name', weight: 3 },
{ name: 'aliases', weight: 3 },
{ name: 'aliases', weight: 8 },
{ name: 'tags', weight: 2 },
{ name: 'categories', weight: 1 },
]);
const searchPlaceholder = useSearchPlaceholder(searchQuery, searchResults);
const isSearchMetadataLoading = computed(
() => searchQuery.value.length > 0 && (tags.value == null || categories.value == null),
);
const chunkedIcons = computed(() => {
return chunkArray(searchResults.value, columnSize.value);
@@ -98,15 +142,21 @@ function setActiveIconName(name: string) {
activeIconName.value = name;
}
function onFocusSearchInput() {
if (tags.value == null) {
fetchTags();
function loadSearchMetadata() {
if (tags.value == null && !isFetchingTags.value) {
void fetchTags();
}
if (categories.value == null) {
fetchCategories();
if (categories.value == null && !isFetchingCategories.value) {
void fetchCategories();
}
}
watch(searchQuery, (searchString) => {
if (searchString !== '') {
loadSearchMetadata();
}
});
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
@@ -124,7 +174,7 @@ function handleCloseDrawer() {
if (searchQueryDebounced.value) {
url.searchParams.set('search', searchQueryDebounced.value);
}
window.history.pushState({}, '', url);
}
</script>
@@ -133,6 +183,7 @@ function handleCloseDrawer() {
<div
ref="overviewEl"
class="overview-container"
:class="{ 'icon-drawer-open': activeIconName }"
>
<StickyBar>
<InputSearch
@@ -141,11 +192,25 @@ function handleCloseDrawer() {
ref="searchInput"
:shortcut="kbdSearchShortcut"
class="input-wrapper"
@focus="onFocusSearchInput"
@focus="loadSearchMetadata"
/>
<Select
id="sort-select"
:items="SORTING"
v-model="selectedSort"
>
<template #start-icon>
<Icon
:iconNode="listSortDescending"
class="chevron-icon"
aria-hidden="true"
/>
</template>
</Select>
</StickyBar>
<NoResults
v-if="searchPlaceholder.isNoResults"
v-if="searchPlaceholder.isNoResults && !isSearchMetadataLoading"
:searchQuery="searchPlaceholder.query"
:isBrandSearch="searchPlaceholder.isBrand"
@clear="searchQuery = ''"
@@ -73,13 +73,11 @@ const customizingActive = computed(() => {
id="icon-color"
label="Color"
>
<template #display>
<ColorPicker
v-model="color"
id="icon-color"
class="color-picker"
/>
</template>
<ColorPicker
v-model="color"
id="icon-color"
class="color-picker"
/>
</InputField>
<InputField
@@ -161,6 +159,6 @@ const customizingActive = computed(() => {
}
.color-picker {
margin-left: auto;
width: 100%;
}
</style>
@@ -15,6 +15,50 @@
margin-bottom: 32px;
background: var(--vp-c-bg);
box-shadow: 0 16px 24px var(--vp-c-bg);
gap: 16px;
}
.search-bar :deep(.select-button) {
padding: 11px 14px;
background-color: var(--vp-c-bg-alt);
color: var(--vp-c-text-2);
flex-shrink: 0;
flex: 1;
font-weight: 500;
cursor: pointer;
}
.search-bar :deep(.select-button):hover,
.search-bar :deep(.select-button):focus {
border-color: var(--vp-c-brand);
background: var(--vp-c-bg-alt);
}
.search-bar :deep(.select-options) {
min-width: 160px;
}
.search-bar :deep(.select-option) {
padding-right: 36px;
padding-left: 8px;
}
.search-bar :deep(.select-icon) {
display: none;
}
.search-bar :deep(.select-button) .select-text {
display: none;
}
@media (min-width: 640px) {
.search-bar :deep(.select-button) {
padding: 11px 16px 11px 16px;
}
.search-bar :deep(.select-button) .select-text {
display: block;
}
}
@media (min-width: 960px) {
@@ -42,7 +42,6 @@ const links = computed(() => [
class="VPFooter"
:class="{ 'has-sidebar': hasSidebar }"
>
<SurveyAskOverlay/>
<div class="container">
<div class="sponsors">
<a
@@ -16,7 +16,7 @@ export const externalLibContext = {
};
const externalLibIconNodesAPI = {
lab: 'https://lab.lucide.dev/api/icon-details',
lab: `${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/lab/icon-details`,
};
export function useExternalLibs(): ExternalLibContext {
@@ -32,13 +32,15 @@ export function useExternalLibs(): ExternalLibContext {
newExternalIconNodes[lib] = savedIconNodes[lib];
} else {
const response = await fetch(externalLibIconNodesAPI[lib]);
const iconNodes = await response.json();
const iconDetails = await response.json();
if (iconNodes) {
newExternalIconNodes[lib] = Object.values(iconNodes).map((iconEntity: IconEntity) => ({
...iconEntity,
externalLibrary: lib,
}));
if (iconDetails) {
newExternalIconNodes[lib] = Object.values(iconDetails).map((iconEntity: IconEntity) => {
return {
...iconEntity,
externalLibrary: lib,
};
});
}
}
}
@@ -20,16 +20,6 @@ const useSearch = <T>(
return index.value.search(query.value).map((result) => result.item);
}
if (keys.length !== 0) {
const mainKey = keys[0].name;
return collection.value.sort((a, b) => {
const aString = a[mainKey as keyof T] as string;
const bString = b[mainKey as keyof T] as string;
return aString.localeCompare(bString);
});
}
return collection.value;
});
-2
View File
@@ -12,7 +12,6 @@ import { CATEGORY_VIEW_CONTEXT, categoryViewContext } from './composables/useCat
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 +22,6 @@ const theme: Partial<Theme> = {
'sidebar-nav-after': () => h(IconsSidebarNavAfter),
'home-hero-image': () => h(HomeHeroIconsCard),
'home-hero-actions-after': () => h(HomeHeroAfter),
'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),
});
+29 -8
View File
@@ -67,6 +67,10 @@
animation: .3s transition 0s ease;
} */
html {
scrollbar-gutter: stable;
}
.VPHome {
overflow-x: hidden;
}
@@ -117,6 +121,10 @@
padding-left: 0;
}
.overview-container.icon-drawer-open {
padding-bottom: 288px;
}
.VPHomeHero .container {
flex-direction: column-reverse;
}
@@ -144,14 +152,6 @@
.VPHomeHero .container {
flex-direction: row;
}
html.has-bb-banner {
--vp-layout-top-height: 72px;
}
html.has-bb-banner {
--Dark-Background: #161618;
}
}
.VPNavBarHamburger .container > span {
@@ -162,3 +162,24 @@
margin: 0 auto 48px;
max-width: 480px;
}
.VPSidebar {
/* Hide Scrollbar */
-ms-overflow-style: none;
scrollbar-width: none;
scrollbar-width: thin; /* can also be normal, or none, to not render scrollbar */
scrollbar-color: var(--vp-c-text-4) transparent; /* foreground background */
}
.VPSidebar::-webkit-scrollbar {
width: 0;
display: none;
}
.VPSidebar::-webkit-scrollbar-track {
background: transparent;
}
.VPSidebar::-webkit-scrollbar-thumb {
background: transparent;
border: none;
}
+1
View File
@@ -18,6 +18,7 @@ export interface IconEntity extends IconMetaData {
externalLibrary?: ExternalLibs;
createdRelease?: Release;
changedRelease?: Release;
popularity?: number;
}
export interface Category {
+1 -1
View File
@@ -1,4 +1,4 @@
import { PageData } from 'vitepress';
import { type PageData } from 'vitepress';
import getStructuredData from './getStructuredData';
import { createGeneralOGImage, createIconOGImage } from './createOGImage';
+1 -1
View File
@@ -158,7 +158,7 @@ For each icon these attributes are applied, corresponding to the above rules.
### Minify paths
The code of paths can sometimes get quite large. To reduce file size we like to minify the code.
We recommend to use [Lucide Studio](https://studio.lucide.dev/) to tidy paths to 3 points of precision.
We recommend to use [Lucide Studio](https://studio.lucide.dev/?utm_source=lucide.dev&utm_medium=design-guide) to tidy paths to 3 points of precision.
### Allowed elements
@@ -12,6 +12,10 @@ import Sandpack from '~/.vitepress/theme/components/editors/SandpackAngular.vue'
While they aren't provided as standalone components, they can be still be passed to the `LucideIcon` component the same way as official icons:
::: info Limitation
Only custom icons that follow Lucide's [code conventions](../../../contribute/icon-design-guide.md#code-conventions) are supported.
:::
### Directly as LucideIconData
::: sandpack {template=angular showTabs=false editorHeight=400 editorWidthPercentage=60 dependencies="@lucide/angular,@lucide/lab"}
+64 -28
View File
@@ -12,19 +12,23 @@ Implementation of the Lucide icon library for web applications.
::: code-group
```sh [pnpm]
pnpm add lucide@next
pnpm add lucide
```
```sh [yarn]
yarn add lucide@next
yarn add lucide
```
```sh [npm]
npm install lucide@next
npm install lucide
```
```sh [bun]
bun add lucide@next
bun add lucide
```
```sh [deno]
deno add lucide
```
:::
@@ -38,19 +42,23 @@ Implementation of the Lucide icon library for React applications.
::: code-group
```sh [pnpm]
pnpm add lucide-react@next
pnpm add lucide-react
```
```sh [yarn]
yarn add lucide-react@next
yarn add lucide-react
```
```sh [npm]
npm install lucide-react@next
npm install lucide-react
```
```sh [bun]
bun add lucide-react@next
bun add lucide-react
```
```sh [deno]
deno add lucide-react
```
:::
@@ -80,6 +88,10 @@ npm install @lucide/vue
bun add @lucide/vue
```
```sh [deno]
deno add @lucide/vue
```
:::
For more details, see the [documentation](./vue/index.md).
@@ -91,19 +103,23 @@ Implementation of the Lucide icon library for Svelte applications.
::: code-group
```sh [pnpm]
pnpm add @lucide/svelte@next
pnpm add @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
```
```sh [deno]
deno add @lucide/svelte
```
:::
> `@lucide/svelte` is only for Svelte 5, for Svelte 4 use the `lucide-svelte` package.
@@ -117,19 +133,23 @@ Implementation of the Lucide icon library for Solid applications.
::: code-group
```sh [pnpm]
pnpm add lucide-solid@next
pnpm add lucide-solid
```
```sh [yarn]
yarn add lucide-solid@next
yarn add lucide-solid
```
```sh [npm]
npm install lucide-solid@next
npm install lucide-solid
```
```sh [bun]
bun add lucide-solid@next
bun add lucide-solid
```
```sh [deno]
deno add lucide-solid
```
:::
@@ -158,6 +178,10 @@ npm install @lucide/angular
bun add @lucide/angular
```
```sh [deno]
deno add @lucide/angular
```
:::
For more details, see the [documentation](./angular/index.md).
@@ -169,19 +193,23 @@ Implementation of the Lucide icon library for preact applications.
::: code-group
```sh [pnpm]
pnpm add lucide-preact@next
pnpm add lucide-preact
```
```sh [yarn]
yarn add lucide-preact@next
yarn add lucide-preact
```
```sh [npm]
npm install lucide-preact@next
npm install lucide-preact
```
```sh [bun]
bun add lucide-preact@next
bun add lucide-preact
```
```sh [deno]
deno add lucide-preact
```
@@ -196,19 +224,23 @@ Implementation of the Lucide icon library for Astro applications.
::: code-group
```sh [pnpm]
pnpm add @lucide/astro@next
pnpm add @lucide/astro
```
```sh [yarn]
yarn add @lucide/astro@next
yarn add @lucide/astro
```
```sh [npm]
npm install @lucide/astro@next
npm install @lucide/astro
```
```sh [bun]
bun add @lucide/astro@next
bun add @lucide/astro
```
```sh [deno]
deno add @lucide/astro
```
:::
@@ -222,19 +254,23 @@ Implementation of the Lucide icon library for multiple usages that like to use:
::: code-group
```sh [pnpm]
pnpm add lucide-static@next
pnpm add lucide-static
```
```sh [yarn]
yarn add lucide-static@next
yarn add lucide-static
```
```sh [npm]
npm install lucide-static@next
npm install lucide-static
```
```sh [bun]
bun add lucide-static@next
bun add lucide-static
```
```sh [deno]
deno add lucide-static
```
:::
@@ -0,0 +1,56 @@
---
title: Optimizations - React Native
description: Learn how to optimize the bundle size of your React Native and Expo web exports by tree-shaking Lucide icons.
---
# Optimizations
By default you import icons from the `lucide-react-native` entry point:
```jsx
import { Camera } from 'lucide-react-native';
```
This is convenient, but it relies on the bundler to _tree-shake_ the entry point (a "barrel" file that re-exports every icon) so that only the icons you actually use end up in your bundle.
On native platforms this is usually fine. On **web exports** it can be a problem, because the Metro bundler is currently not very good at tree-shaking barrel imports and may include **all** icons in your final bundle.
## The Metro tree-shaking limitation
When you build for web with Expo (`expo export --platform web`), Metro is used to bundle your JavaScript. Metro bundles modules on-demand and, by default, does not remove unused exports from a barrel file.
This means an import like the one below can pull in the entire icon set, even though only a single icon is rendered:
```jsx
// May bundle every Lucide icon on web exports
import { Camera } from 'lucide-react-native';
```
Expo documents an experimental optimization for [React Native web imports](https://docs.expo.dev/guides/tree-shaking/#react-native-web-imports) and for [removing unused imports and exports](https://docs.expo.dev/guides/tree-shaking/#remove-unused-imports-and-exports). In practice this tree-shaking does **not** currently work reliably for `lucide-react-native` barrel imports, so the unused icons are not removed from web exports.
## Recommended: import icons individually
To guarantee that only the icons you use are bundled — regardless of the bundler's tree-shaking capabilities — import each icon directly from its own module:
```jsx
import Camera from 'lucide-react-native/icons/camera';
// Usage
const App = () => {
return <Camera />;
};
export default App;
```
Because each icon lives in its own file, the bundler only ever includes the icons you explicitly import. This keeps your web export small without depending on Metro's experimental tree-shaking.
The icon module name is the [kebab-case](https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case) version of the icon name. For example, the `ArrowRight` icon is imported from `lucide-react-native/icons/arrow-right`:
```jsx
import ArrowRight from 'lucide-react-native/icons/arrow-right';
```
::: tip
Individual icon imports work identically on native and web, so you can safely use this style across your whole project to keep bundles as small as possible on every platform.
:::
+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
```
:::
+12 -2
View File
@@ -1,9 +1,19 @@
import iconNodes from '../.vitepress/data/iconNodes';
import * as iconDetails from '../.vitepress/data/iconDetails';
export default {
async load() {
return {
icons: Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode })),
icons: Object.entries(iconDetails).map(
([, { name, iconNode, popularity, createdRelease, aliases = [] }]) => ({
name,
iconNode,
popularity: popularity?.count ?? 0,
aliases: aliases
.map((alias) => (typeof alias === 'string' ? alias : alias?.name))
.filter((alias): alias is string => Boolean(alias)),
createdRelease,
}),
),
};
},
};
+19 -17
View File
@@ -1,24 +1,26 @@
import { IconEntity } from '../../.vitepress/theme/types';
import iconNodes from '../../.vitepress/data/lab/iconNodes';
import iconPopularity from '../../.vitepress/data/lab/iconPopularity';
import iconMetaData from '../../.vitepress/data/lab/iconMetaData';
import { type IconEntity } from '../../.vitepress/theme/types';
export default {
paths: async () => {
try {
const iconDetailsResponse = await fetch('https://lab.lucide.dev/api/icon-details');
const iconDetails = (await iconDetailsResponse.json()) as Record<string, IconEntity>;
return (Object.entries(iconNodes) as unknown as IconEntity[]).map(([name, iconNode]) => {
const iconDetails = iconMetaData[name];
return Object.values(iconDetails).map((iconEntity) => {
const params = {
externalLibrary: 'lab',
...iconEntity,
};
delete iconDetails['$schema'];
return {
params,
};
});
} catch (error) {
console.error('Error fetching icon details:', error);
return [];
}
const params = {
name,
iconNode,
externalLibrary: 'lab',
popularity: iconPopularity[name]?.count ?? 0,
...iconDetails,
};
return {
params,
};
});
},
};
+32 -28
View File
@@ -8,18 +8,21 @@
"docs:dev": "pnpm run /^prebuild:.*/ && vitepress dev",
"docs:build": "pnpm run /^prebuild:.*/ && vitepress build",
"docs:preview": "vitepress preview",
"build:docs": "vitepress build",
"prebuild:iconNodes": "node ./scripts/writeIconNodes.mjs",
"prebuild:metaJson": "node ./scripts/writeIconMetaIndex.mjs",
"prebuild:releaseJson": "node ./scripts/writeReleaseMetadata.mjs",
"prebuild:categoriesJson": "node ./scripts/writeCategoriesMetadata.mjs",
"prebuild:relatedIcons": "node ./scripts/writeIconRelatedIcons.mjs",
"prebuild:iconDetails": "node ./scripts/writeIconDetails.mjs",
"prebuild:brandStopwords": "node ./scripts/writeBrandStopwords.mjs",
"postbuild:vercelJson": "node ./scripts/writeVercelOutput.mjs",
"dev": "npx nitropack dev",
"prebuild:api": "npx nitropack prepare",
"build:api": "npx nitropack build",
"build:docs": "NODE_OPTIONS=--max-old-space-size=8192 vitepress build",
"prebuild:iconNodes": "node ./scripts/writeIconNodes.mts",
"prebuild:metaJson": "node ./scripts/writeIconMetaIndex.mts",
"prebuild:releaseJson": "node ./scripts/writeReleaseMetadata.mts",
"prebuild:categoriesJson": "node ./scripts/writeCategoriesMetadata.mts",
"prebuild:relatedIcons": "node ./scripts/writeIconRelatedIcons.mts",
"prebuild:iconDetails": "node ./scripts/writeIconDetails.mts",
"prebuild:iconPopularity": "node ./scripts/writeiconPopularity.mts && node ./scripts/writeiconPopularityIndex.mts",
"prebuild:brandStopwords": "node ./scripts/writeBrandStopwords.mts",
"prebuild:writeLabIconNodes": "node ./scripts/writeLabIconNodes.mts",
"prebuild:writeLabIconMetaIndex": "node ./scripts/writeLabIconMetaIndex.mts",
"postbuild:vercelJson": "node ./scripts/writeVercelOutput.mts",
"dev": "nitropack dev",
"prebuild:api": "nitropack prepare",
"build:api": "NODE_OPTIONS=--max-old-space-size=8192 nitropack build",
"build": "pnpm run /^prebuild:.*/ && pnpm run build:api && pnpm run build:docs && pnpm postbuild:vercelJson",
"preview": "node .output/server/index.mjs"
},
@@ -31,31 +34,32 @@
"@lucide/shared": "workspace:*",
"@rollup/plugin-replace": "^6.0.3",
"@types/semver": "^7.7.1",
"h3": "^1.15.9",
"h3": "^1.15.11",
"markdown-it": "^14.3.0",
"markdown-it-container": "^4.0.0",
"nitropack": "^2.13.4",
"rollup-plugin-copy": "^3.5.0",
"svg-path-commander": "^2.1.11",
"vitepress": "^1.6.4",
"vitepress-plugin-group-icons": "^1.6.5",
"vitepress-plugin-llms": "^1.11.1",
"markdown-it": "^14.1.0",
"markdown-it-container": "^4.0.0",
"semver": "^7.7.3",
"semver": "^7.8.5",
"sharp": "^0.34.5",
"shiki": "^3.15.0",
"shiki": "^3.23.0",
"simple-git": "^3.36.0",
"sitemap": "^7.1.2",
"sitemap": "^7.1.3",
"svg-path-commander": "^2.2.1",
"svg-pathdata": "^6.0.3",
"svgson": "^5.3.1"
"svgson": "^5.3.1",
"vitepress": "^1.6.4",
"vitepress-plugin-group-icons": "^1.7.5",
"vitepress-plugin-llms": "^1.13.3"
},
"dependencies": {
"@floating-ui/vue": "^1.1.9",
"@floating-ui/vue": "^1.1.11",
"@headlessui/vue": "^1.7.23",
"@lucide/vue": "workspace:*",
"@vueuse/components": "^14.0.0",
"@vueuse/core": "^14.0.0",
"@vueuse/components": "^14.3.0",
"@vueuse/core": "^14.3.0",
"@vueuse/integrations": "^14.3.0",
"element-to-path": "^1.2.1",
"fuse.js": "^7.1.0",
"fuse.js": "^7.5.0",
"jszip": "^3.10.1",
"lodash-es": "^4.18.1",
"lucide": "workspace:*",
@@ -64,6 +68,6 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"sandpack-vue3": "3.1.12",
"vue": "^3.5.24"
"vue": "^3.5.39"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 200" fill="none">
<path fill="#00e8ff" d="M40 120l20-60l90 90l-30 50l-40-40h-20" />
<path fill="#283198" d="M80 160 L80 80 L120 40 L 120 120 M0 160 L40 200 L40 120 L20 120" />
<path fill="#324fff" d="M40 120v-80l40-40v80M120 200v-80l40-40v80M0 160v-80l40 40" />
<path fill="#0ff" d="M40 200v-80l40 40" />
</svg>

After

Width:  |  Height:  |  Size: 377 B

@@ -23,11 +23,12 @@ const writeIconFiles = icons.map(async (iconFileName) => {
const location = path.resolve(iconDetailsDirectory, `${iconName}.ts`);
const contents = `\
import iconNode from '../iconNodes/${iconName}.node.json'
import metaData from '../../../../icons/${iconName}.json'
import releaseData from '../releaseMetadata/${iconName}.json'
import iconNode from '../iconNodes/${iconName}.node.json' with { type: 'json' };
import metaData from '../../../../icons/${iconName}.json' with { type: 'json' };
import releaseData from '../releaseMetadata/${iconName}.json' with { type: 'json' };
import popularity from '../iconPopularity/${iconName}.json' with { type: 'json' };
const { tags, categories, contributors, aliases, deprecated, deprecationReason, toBeRemovedInVersion } = metaData
const { tags, categories, contributors, aliases, deprecated, deprecationReason, toBeRemovedInVersion } = metaData;
const iconDetails = {
name: '${iconName}',
@@ -37,12 +38,13 @@ const iconDetails = {
categories,
aliases,
deprecated,
popularity,
deprecationReason,
toBeRemovedInVersion,
...releaseData,
}
};
export default iconDetails
export default iconDetails;
`;
await fs.promises.writeFile(location, contents, 'utf-8');
@@ -42,7 +42,7 @@ const getRelatedIcons = (currentIcon, icons) => {
};
const iconsMetaDataPromises = svgFiles.map(async (iconName) => {
const metaDataFileContent = await fs.promises.readFile(`../icons/${iconName}`);
const metaDataFileContent = await fs.promises.readFile(`../icons/${iconName}`, 'utf-8');
const metaData = JSON.parse(metaDataFileContent);
const name = iconName.replace('.json', '');
+49
View File
@@ -0,0 +1,49 @@
import fs from 'fs';
import path from 'path';
import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../lab');
const iconJsonFiles = await readSvgDirectory(ICONS_DIR, '.json');
const labDirectory = path.resolve(currentDir, '.vitepress/data/lab');
const location = path.resolve(currentDir, labDirectory, 'iconMetaData.ts');
if (fs.existsSync(location)) {
fs.unlinkSync(location);
}
if (!fs.existsSync(labDirectory)) {
fs.mkdirSync(labDirectory);
}
const iconMetaIndexFileImports = [];
const iconMetaIndexFileExports = [];
iconJsonFiles.forEach((iconJsonFile) => {
const iconName = path.basename(iconJsonFile, '.json');
iconMetaIndexFileImports.push(
`import ${toCamelCase(iconName)}Metadata from '../../../../lab/${iconName}.json';`,
);
iconMetaIndexFileExports.push(` '${iconName}': ${toCamelCase(iconName)}Metadata,`);
});
try {
await fs.promises.writeFile(
location,
`\
${iconMetaIndexFileImports.join('\n')}
export default {
${iconMetaIndexFileExports.join('\n')}
}
`,
'utf-8',
);
console.log('Successfully write icon json file index');
} catch (error) {
throw new Error(`Something went wrong generating icon json file index file,\n ${error}`);
}
+62
View File
@@ -0,0 +1,62 @@
import fs from 'fs';
import path from 'path';
import { renderIconsObject } from '@lucide/build-icons';
import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../lab');
const svgFiles = await readSvgDirectory(ICONS_DIR);
const icons = await renderIconsObject(svgFiles, ICONS_DIR, true);
const iconNodesDirectory = path.resolve(currentDir, '.vitepress/data/lab', 'iconNodes');
if (fs.existsSync(iconNodesDirectory)) {
fs.rmSync(iconNodesDirectory, { recursive: true, force: true });
}
if (!fs.existsSync(iconNodesDirectory)) {
fs.mkdirSync(iconNodesDirectory);
}
const iconIndexFile = path.resolve(iconNodesDirectory, `index.ts`);
const iconIndexFileImports: string[] = [];
const iconIndexFileExports: string[] = [];
const iconIndexFileDefaultExports: string[] = [];
const writeIconFiles = Object.entries(icons).map(async ([iconName, { children }]) => {
// We need to use .node.json because the there is a file called package, which is a reserved word for packages.
const location = path.resolve(iconNodesDirectory, `${iconName}.node.json`);
const iconNode = children.map(({ name, attributes }) => [name, attributes]);
const output = JSON.stringify(iconNode, null, 2);
await fs.promises.writeFile(location, output, 'utf-8');
iconIndexFileImports.push(
`import ${toCamelCase(iconName)}Node from './${iconName}.node.json' with { type: "json" };`,
);
iconIndexFileExports.push(` ${toCamelCase(iconName)}Node as ${toCamelCase(iconName)},`);
iconIndexFileDefaultExports.push(` '${iconName}': ${toCamelCase(iconName)}Node,`);
});
try {
await Promise.all(writeIconFiles);
await fs.promises.writeFile(
iconIndexFile,
`\
${iconIndexFileImports.join('\n')}
export {
${iconIndexFileExports.join('\n')}
}
export default {
${iconIndexFileDefaultExports.join('\n')}
}
`,
'utf-8',
);
console.log('Successfully write', writeIconFiles.length, 'iconNodes.');
} catch (error) {
throw new Error(`Something went wrong generating iconNode files,\n ${error}`);
}
@@ -70,10 +70,10 @@ const comparisonsPromises = tags.map(async (tag, index) => {
};
});
const comparisons = await Promise.all(comparisonsPromises);
const comparisons = (await Promise.all(comparisonsPromises)).filter((comparison) => comparison != null && Object.keys(comparison.iconFiles).length > 0);
const newReleaseMetaData = {};
comparisons.forEach(({ tag, iconFiles, date } = {}) => {
comparisons.forEach(({ tag, iconFiles, date }) => {
if (tag == null) return;
iconFiles.forEach(({ status, file, renamedFile }) => {
@@ -11,7 +11,7 @@ const iconMetaData = await getIconMetaData(path.resolve(scriptDir, '../../icons'
const iconAliasesRedirectRoutes = Object.entries(iconMetaData)
.filter(([, { aliases }]) => aliases?.length)
.map(([iconName, { aliases }]) => {
const aliasRouteMatches = aliases.map((alias) => alias.name).join('|');
const aliasRouteMatches = aliases.map((alias) => typeof alias === 'string' ? alias : alias?.name).join('|');
return {
src: `^/icons/(${aliasRouteMatches})$`,
+152
View File
@@ -0,0 +1,152 @@
/* eslint-disable no-restricted-syntax, no-await-in-loop */
import fs from 'fs';
import path from 'path';
import { loadEnvFile } from 'node:process';
import { readSvgDirectory } from '@lucide/helpers';
const currentDir = process.cwd();
const dataDirectory = path.resolve(currentDir, '.vitepress/data');
try {
// Load environment variables from .env file, if it exists.
loadEnvFile(`${currentDir}/.env`);
} catch (error) {}
interface IconCollection {
/** Human readable name, used for logging. */
name: string;
/** Directory containing the icon `.json` files. */
iconsDir: string;
/** Directory the `${iconName}.json` popularity files are written to. */
outputDir: string;
/** Matches an analytics route and captures the icon name in group 1. */
routePattern: RegExp;
}
// Lab must come before the default collection because `/icons/lab/foo` also
// matches the default `/icons/(...)` pattern; the first match wins per route.
const iconCollections: IconCollection[] = [
{
name: 'lab',
iconsDir: path.resolve(currentDir, '../lab'),
outputDir: path.resolve(dataDirectory, 'lab', 'iconPopularity'),
// e.g. /icons/lab/burger, /icons/lab/burger/ or /icons/lab/burger?ref=homepage
routePattern: /^\/icons\/lab\/([^\/\?]+)(?:[\/\?]|$)/,
},
{
name: 'default',
iconsDir: path.resolve(currentDir, '../icons'),
outputDir: path.resolve(dataDirectory, 'iconPopularity'),
// e.g. /icons/activity, /icons/activity/ or /icons/activity?ref=homepage
routePattern: /^\/icons\/([^\/\?]+)(?:[\/\?]|$)/,
},
];
interface CollectionData extends IconCollection {
iconNames: string[];
counts: Record<string, number>;
}
const collections: CollectionData[] = await Promise.all(
iconCollections.map(async (collection) => {
const iconJsonFiles = await readSvgDirectory(collection.iconsDir, '.json');
const iconNames = iconJsonFiles.map((file) => path.basename(file, '.json'));
return {
...collection,
iconNames,
counts: Object.fromEntries(iconNames.map((iconName) => [iconName, 0])),
};
}),
);
interface AnalyticsResponse {
results: {
dimensions: [route: string];
metrics: [count: number];
}[];
}
const writeIconPopularity = async ({ name, outputDir, counts }: CollectionData) => {
if (fs.existsSync(outputDir)) {
fs.rmSync(outputDir, { recursive: true, force: true });
}
fs.mkdirSync(outputDir, { recursive: true });
const writePopularityPromises = Object.entries(counts).map(([iconName, count]) => {
const location = path.resolve(outputDir, `${iconName}.json`);
return fs.promises.writeFile(location, JSON.stringify({ count }, null, 2), 'utf-8');
});
await Promise.all(writePopularityPromises);
console.log(
'Successfully written icon popularity data for',
writePopularityPromises.length,
`${name} icons.`,
);
};
const writeAllIconPopularity = () => Promise.all(collections.map(writeIconPopularity));
if (process.env.LUCIDE_ANALYTICS_TOKEN === undefined) {
console.warn('LUCIDE_ANALYTICS_TOKEN environment variable is not set. Writing default icon popularity data.');
await writeAllIconPopularity();
process.exit(0);
}
try {
const response = await fetch('https://analytics.lucide.dev/api/v2/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.LUCIDE_ANALYTICS_TOKEN}`,
},
body: JSON.stringify({
"site_id": "lucide.dev",
"metrics": [
"visitors"
],
"dimensions": [
"visit:entry_page"
],
"date_range": "12mo"
}),
})
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.statusText}`);
}
const analyticsData: AnalyticsResponse = await response.json();
for (const { dimensions, metrics } of analyticsData.results) {
const [route] = dimensions;
const [count] = metrics;
if (!route.startsWith('/icons')) {
continue;
}
// Route each visit to the first collection whose pattern matches. Lab is
// checked first so `/icons/lab/foo` is not swallowed by the default pattern.
for (const collection of collections) {
const match = route.match(collection.routePattern);
if (!match) {
continue;
}
const iconName = match[1];
if (collection.iconNames.includes(iconName)) {
collection.counts[iconName] += count;
}
break;
}
}
await writeAllIconPopularity();
} catch (error) {
console.error('Error fetching analytics data:', error);
await writeAllIconPopularity();
}
+49
View File
@@ -0,0 +1,49 @@
import fs from 'fs';
import path from 'path';
import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../lab');
const iconJsonFiles = await readSvgDirectory(ICONS_DIR, '.json');
const labIconPopularityDirectory = path.resolve(currentDir, '.vitepress/data/lab/iconPopularity');
const location = path.resolve(currentDir, labIconPopularityDirectory, 'index.ts');
if (fs.existsSync(location)) {
fs.unlinkSync(location);
}
if (!fs.existsSync(labIconPopularityDirectory)) {
fs.mkdirSync(labIconPopularityDirectory);
}
const iconMetaIndexFileImports = [];
const iconMetaIndexFileExports = [];
iconJsonFiles.forEach((iconJsonFile) => {
const iconName = path.basename(iconJsonFile, '.json');
iconMetaIndexFileImports.push(
`import ${toCamelCase(iconName)}Popularity from './${iconName}.json' with { type: 'json' };`,
);
iconMetaIndexFileExports.push(` '${iconName}': ${toCamelCase(iconName)}Popularity,`);
});
try {
await fs.promises.writeFile(
location,
`\
${iconMetaIndexFileImports.join('\n')}
export default {
${iconMetaIndexFileExports.join('\n')}
}
`,
'utf-8',
);
console.log('Successfully write icon json file index');
} catch (error) {
throw new Error(`Something went wrong generating icon json file index file,\n ${error}`);
}
+11 -3
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"
@@ -40,7 +40,7 @@
}
},
"dependentRequired": {
"deprecated": ["deprecationReason", "toBeRemovedInVersion"],
"deprecated": ["deprecationReason"],
"deprecationReason": ["deprecated"],
"toBeRemovedInVersion": ["deprecated"]
}
@@ -114,6 +114,14 @@
"minItems": 1,
"uniqueItems": true
},
"use-cases": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 0,
"uniqueItems": true
},
"deprecated": {
"const": true
},
@@ -126,7 +134,7 @@
}
},
"dependentRequired": {
"deprecated": ["deprecationReason", "toBeRemovedInVersion"],
"deprecated": ["deprecationReason"],
"deprecationReason": ["deprecated"],
"toBeRemovedInVersion": ["deprecated"]
},
+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 -1
View File
@@ -13,4 +13,4 @@
<path d="M15.697 14h5.606" />
<path d="m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16" />
<path d="M3.304 13h6.392" />
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 391 B

+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",
+35
View File
@@ -0,0 +1,35 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"ahtohbi4",
"jamiemlaw",
"karsa-mistmere",
"jguddas"
],
"use-cases": [
"marking content as sponsored",
"linking to an advertise with us page"
],
"tags": [
"advert",
"affiliate",
"brand",
"campaign",
"commercial",
"marketing",
"monetize",
"paid",
"partner",
"promo",
"sponsor",
"audio description",
"video description",
"described video",
"visual description"
],
"categories": [
"multimedia",
"accessibility",
"notifications"
]
}
+16
View File
@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 13H6" />
<path d="M10 15v-4a2 2 0 0 0-4 0v4" />
<path d="M14 14.5a.5.5 0 0 0 .5.5h1a2.5 2.5 0 0 0 2.5-2.5v-1A2.5 2.5 0 0 0 15.5 9h-1a.5.5 0 0 0-.5.5z" />
<rect x="2" y="5" width="20" height="14" rx="2" />
</svg>

After

Width:  |  Height:  |  Size: 434 B

+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",
+2 -2
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"done",
"todo",
@@ -22,8 +23,7 @@
{
"name": "alarm-check",
"deprecationReason": "alias.name",
"deprecated": true,
"toBeRemovedInVersion": "v1.0"
"deprecated": true
}
]
}
+2 -2
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"remove"
],
@@ -18,8 +19,7 @@
{
"name": "alarm-minus",
"deprecationReason": "alias.name",
"deprecated": true,
"toBeRemovedInVersion": "v1.0"
"deprecated": true
}
]
}
+1
View File
@@ -6,6 +6,7 @@
"karsa-mistmere",
"jguddas"
],
"use-cases": [],
"tags": [
"morning",
"turn-off"
+2 -2
View File
@@ -6,6 +6,7 @@
"jguddas",
"karsa-mistmere"
],
"use-cases": [],
"tags": [
"add"
],
@@ -18,8 +19,7 @@
{
"name": "alarm-plus",
"deprecationReason": "alias.name",
"deprecated": true,
"toBeRemovedInVersion": "v1.0"
"deprecated": true
}
]
}
+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",

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