Compare commits

...
38 Commits
Author SHA1 Message Date
Kesley Davidgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Copilot Autofix powered by AIEric Fennis
03eae6069e feat(icons): added asterism icon (#4687)
* feat(icons): added `asterism` icon

Adds asterism for issue #4077.
Also updates emoji category icon reference after smile rename.

* chore(icons): expand asterism metadata from PR suggestions

Apply curated tags, categories, and use-cases from automated
metadata review suggestions.

* Update icons/asterism.json

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

* Remove duplicate use-case entry in asterism.json

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

* Update use cases for asterism symbol in JSON

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

* Adjust metadata

---------

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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-11-10 13:48:06 +01:00
PrimeTestLabandClaude Opus 5.5 0991512434 Polish The Copy Confetti On The Icons Page (#5191)
- Say "Copied SVG!" and "Copied name!" when an icon is copied with
  Shift + click or Ctrl/Cmd + click.
- Center the text over the icon instead of starting at its left edge.
- Give the icon the brand border while the confetti plays.
- Keep the confetti visible when reduced motion is on; the site-wide
  reduced-motion rule shrank it to 0.01ms so it never showed.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:55:00 +01:00
Karsaandcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> 68081128b3 feat(icons): added exclamation-mark, question-mark icons (#5184)
* feat(icons): added question-mark & exclamation-mark icons

* feat(icons): added question-mark & exclamation-mark icons

* Update shield-question-mark.svg

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-11-10 12:48:11 +01:00
Eric FennisandClaude Opus 5.5 c8d0ddd437 chore(metadata): improve tags for common no-result searches (#5187)
* feat(metadata): improve tags for common no-result searches

Adds tags for the most frequent icon searches that returned nothing in
the last 30 days of site search data (customer, job, checklist, docs,
sell, invite, csv, budget, install, deploy, 404, ...).

Groups:
- Extend `user`, `check`, `x`, `exclamation-mark`, `question-mark`,
  `chart`, `code`, `search` and `exit` with missing synonyms.
- Add `face` group for the `face-*` icons (emoji, emotion, mood,
  feeling, expression, reaction).
- Add `dashed` group for icons drawn with a dashed outline, so
  "dotted" finds them.
- Use `$group:exit` on the diagonal `*-exit` arrows and `$group:code`
  on `terminal` and `square-terminal`.

Icons: add tags to ~100 icons for the top concept gaps, and drop
literals that a group or `$extends` now provides.

Replaying the top 3,000 no-result queries against this branch with the
site's Fuse settings: 173 queries (8,197 searches) now return results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G9u8Feg8TihZv9E4BxmKpt

* feat(metadata): rename `face` group to `emoticon`, tag `eye` with "eyes"

"eyes" (187 no-result searches in 30 days) did not match the eye icons:
Fuse treats the extra "s" as a typo past its threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G9u8Feg8TihZv9E4BxmKpt

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-10 12:37:50 +01:00
Samuel Alakegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
e9cfd3c6d3 feat(icons): flipped route icon, added route-arrow-right icon (#4729)
* feat(icons): add route-arrow-right

Adds route-arrow-right: a serpentine route ending in an arrow, giving
the route a direction of travel.

route depicts a path between two waypoints but has no direction. This
reuses route's exact serpentine geometry (the 3.5-radius arcs at x6.5 and
x17.5, rails at y5/y12/y19, same 2px margins), replacing the waypoint
circles with a directional arrow that follows Lucide's arrow convention
(the shaft ends at the chevron apex, as in arrow-right).

Naming: happy to switch to route-arrow if a directional family isn't
wanted. A route-arrow-left mirror and a both-arrows variant are natural
follow-ups if this lands.

* Apply batched suggestions from code review

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

* Flip route icon and fix arrow right icon

* Adjust metadata

* Rewrite usecases

* add one-way tag

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-11-10 10:16:03 +01:00
Rodrigo RodriguesandEric a25efe8dba feat(icons): added text-pen icon (#4937)
* Added icons/pencil-draft.svg

* Added icons/pencil-draft.json

* Update name, tags and contributors

Removed several contributors and tags related to writing and speed. Added new tags related to drafting and authoring.

* Update SVG paths in text-pen.svg

* Update metadata

---------

Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-10 10:14:55 +01:00
Jonathen Wilksgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>EricKarsa
6f61f73a91 feat(icons): added mound-shovel icon (#4329)
* Added icons/sandpile.svg

* Added icons/sandpile.json

* Update icons/sandpile.json

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

* Update tags and categories in mound-shovel.json

Removed unnecessary tags and added shovel-related tags. also added environment to categories

* renamed icon file

sand-shovel to mound-shovel

* Add files via upload

* Adjusted metadata

* extends from shovel

* Fix typo in karsas username

* Update icons/mound-shovel.json

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

* Add EOL

* Update mound-shovel.json

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric <eric.fennis@gmail.com>
Co-authored-by: Karsa <karsa@karsa.org>
2026-11-10 08:37:45 +00:00
bfa381ef26 feat(site): add keyboard shortcuts to the icons page (#5035)
* feat(docs): add keyboard shortcuts to the icons page

Add the shortcuts suggested in #4916 and list them on the page:

- Ctrl/Cmd + click on an icon copies its name
- Arrow keys move from the search field into the results and between
  the icons
- Ctrl/Cmd + C copies the name of the selected icon
- Ctrl/Cmd + Shift + C copies the SVG of the selected icon

Icons can now be focused with the keyboard, and a keyboard button next to
the sort select opens a dialog with all shortcuts, including the existing
Ctrl/Cmd + K and Shift + click. The dialog also opens with Shift + ?
(except while typing in a field).

Closes #4916

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(docs): add copy toasts, open icons with Enter and a shared Kbd component

- Copying an icon shows a toast (vue-sonner, bottom-center) that says
  whether its name or its SVG was copied
- Enter opens the selected icon's drawer
- The SVG shortcut is now Shift + C, as Ctrl/Cmd + Shift + C opens the
  browser's inspect tool
- Kbd component shared by the search inputs and the shortcuts dialog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Adjust keyboard shortcuts

* Revert customizer change

* Adjust kbd style

* Fix toaster styling

* Fix types

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-10 08:29:51 +01:00
Eric Fennis 3fef7aca71 Fix extends (#5186) 2026-11-09 12:35:14 +00:00
Eric Fennis 45aaec4b72 fix(icons): Renaming circle-arrow-* and square-arrow-* icons (#5168)
* Rename square arrow icons

* rename circle icons
2026-11-09 12:33:35 +01:00
Karsa f8932f8eb8 feat(icons): delegated cheese from Lab (#5185) 2026-11-09 12:33:03 +01:00
VioletClaude Opus 5.5github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>KarsaViolet RosenzweigEric
1a3f0a85a1 feat(icons): added square-arrow-down-enter, square-arrow-down-exit, square-arrow-down-left-enter and 7 more icons (#3644)
* feat: add orthognal square-arrow-out icons, and add square-arrow-in icons for all directions

* feat(icons): rename square-arrow in/out icons to `-enter`/`-exit` and update SVGs

Replace `square-arrow-in-*` and the orthogonal `square-arrow-out-*` icons
with the final designs, using the `square-arrow-<direction>-<enter|exit>`
naming pattern. `square-arrow-right-enter` and `square-arrow-right-exit`
get the new SVGs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Fix gaps and metadata

* Fix categories

* Apply batched suggestions from code review

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

* Apply batched suggestions from code review

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

* Add layout resize category

* Fix tags

* Apply batched suggestions from code review

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

* Update square-arrow-down-right-enter.svg

* Update square-arrow-up-left-enter.svg

* Update square-arrow-up-right-enter.svg

* Update square-arrow-down-left-enter.svg

---------

Co-authored-by: Violet Rosenzweig <rosenzweigv@leoncountyfl.gov>
Co-authored-by: Eric <eric.fennis@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karsa <karsa@karsa.org>
2026-11-09 11:31:28 +00:00
adc62f5963 feat(icons): added stroke-line-cap-butt, stroke-line-cap-round, stroke-line-cap-square and 3 more icons (#4171)
* Added icons/corner-join-*

* feat(icons): added stroke-line-* icons & line tag group

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2026-11-09 12:14:34 +01:00
Karsa b3058bb8cf fix(docs): removed docs/guide/comparison.md (#5182) 2026-11-09 10:05:38 +01:00
Eric FennisandCopilot Autofix powered by AI 53fab88ff9 fix(scripts): Fixes generateNextJSAliases.mts on commit hook (#5167)
* Fix nextjs aliases path generator

* Add deprecation fields to alias type definition

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-11-06 13:25:23 +00:00
Eric Fennis 1a49fd88d8 chore(site): Add support for reduced motion in HomeHeroAnimation (#5159)
* Refactor code

* Respect reduce motion

* Add icon

* Revert Icon switch
2026-11-06 09:09:23 +01:00
gridalchemygithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
b826f0c527 feat(icons): added grid-3x3-off icon (#5071)
* feat(icons): added grid-3x3-off icon

* chore(icons): add suggested tags to `grid-3x3-off`

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

* fix(icons): use standard off geometry for `grid-3x3-off`

* chore(icons): use metadata markers for `grid-3x3-off`

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-11-05 23:02:56 +01:00
Eric FennisandKarsa 558bdd83b5 feat(icons): added user-exclamation-point, user-round-exclamation-point icons (#5144)
* Added icons/user-round-exclamation-point.svg

* Added icons/user-round-exclamation-point.json

* Updated metadata

* Add user-exclamation-point

* Adds suggestions

* Update icons/user-round-exclamation-point.svg

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

* Modify user-exclamation-point icon SVG paths

---------

Co-authored-by: Karsa <karsa@karsa.org>
2026-11-05 20:32:56 +01:00
Jamie Lawgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric Fennis
a805955781 feat(icons): added moped icon (#3373)
* Add `dirt-bike` icon

* Fix JSON formatting

* Fix JSON formatting again

* Rounded the handlebars

* Rename icon and add metadata

* Update icons/moped.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-11-05 18:43:20 +01:00
tlq5landEric Fennis ee8e10d746 fix(lucide-react-native): emit runtime files for alias icon subpaths (#5055)
closes #5043

Agent: claude

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-11-05 14:11:40 +01:00
DominikCursorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Eric FennisKarsa
2c2ee80687 feat(icons): added square-dashed-search icon (#5119)
* Add the square-dashed-search lab icon.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(lab): added zoom selection use case to `square-dashed-search`

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(icons): delegated `square-dashed-search` icon from lab

Co-authored-by: Cursor <cursoragent@cursor.com>

* Update icons/square-dashed-search.json

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

* Update icons/square-dashed-search.json

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

* Adjust metadata

* Apply feedback

* Remove text category

* Update icons/square-dashed-search.svg

---------

Co-authored-by: Cursor <cursoragent@cursor.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: Karsa <contact@karsa.org>
2026-11-05 10:24:38 +01:00
Eric FennisandClaude 1c93e0a476 fix(docs): fix vercel.json redirects that land on 404 (#5157)
- Redirect /docs/lucide-*, /guide/lucide-* and /guide/packages/lucide-*/ to
  the current /guide/<pkg> pages (vue-next -> vue)
- Redirect old /guide/basics/*, /guide/advanced/* and /guide/design/* pages
- Redirect graduated lab icons carton-off and briefcase-plus to core
- Remove the /docs/:slug(lucide-?.*) rule that produced 404 destinations

Fixes LUCIDE-15


Claude-Session: https://claude.ai/code/session_01G9u8FetMRtXGCVFrfg619a

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 07:49:42 +01:00
91a1359b5e feat(icons): added circle-fading-check icon (#4089)
* Added icons/circle-fading-check.svg

* Added icons/circle-fading-check.json

* Refactor SVG paths in circle-fading-check.svg

* Add empty use-cases array to circle-fading-check.json

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

* Update metadata

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-11-04 16:03:14 +01:00
Ilya VredandEric 90e8041a35 feat(icons): added opacity icon (#4222)
* Added icons/opacity.svg

* Added icons/opacity.json

* Updated icons/opacity.svg

* Updated icons/opacity.json

* Adjust usecases

---------

Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-04 15:56:22 +01:00
Eric FennisandKarsa 3898742b6a feat(icons): added package-question-mark icon (#5155)
* Add metadata

* Add more tags to `package.json`

* Update icons/package-question-mark.json

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2026-11-04 15:29:36 +01:00
Eric FennisandKarsa a4a0e20ff5 feat(icons): added package-pen icon (#5154)
* Add package pen icon

* Update icons/package-pen.json

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

* update metadata

---------

Co-authored-by: Karsa <contact@karsa.org>
2026-11-04 15:26:37 +01:00
Eric Fennis 1980e3d59b chore(icons): Renamed *-warning and *-alert to *-exclamation-point (#5143)
* Rename icons

* Update other file

* Remove deprecation booleans
2026-11-03 15:49:26 +01:00
aa0b77386c feat(icons): added mango icon (#4902)
* feat: add mango icon

* fix: adjust mango icon leaf and body shape

* refactor: switch to rrod497's mango design, expand metadata

* Update use cases for mango in icons/mango.json

Removed outdated use cases and added updated ones for mango.

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

* Apply suggestion from @karsa-mistmere

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

* Update mango.json

---------

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-11-03 14:16:15 +01:00
Bin 7bb15b80a3 fix(docs): keep sponsor tiers within content width (#5149) 2026-11-03 09:41:31 +01:00
Eric FennisandClaude Opus 5.5 4b203ec9b6 chore(deps): Fix security vulnerabilities alerts (#5147)
* Upgrade deps

* Fix security alerts

* Keep incompatible consumers off minimatch 11 and file-type 21

The security overrides forced minimatch 11 and file-type 21 onto every
consumer, which broke ESLint (eslint-plugin-import-x imports the removed
makeRe) and the font build (jimp 0.22 calls file-type's removed
fromBuffer). glob 7 and @eslint/eslintrc also rely on the minimatch 3
callable export. Scope those consumers back to their compatible lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove minimatch override

* Fix font build

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 20:58:02 +01:00
Eric FennisandCopilot Autofix powered by AI 58c85b4758 fix(dev): avoid polynomial regex backtracking in toCamelCase helper (#5148)
* fix(dev): avoid polynomial regex backtracking in toCamelCase helper

* Add test for toCamelCase with non-word character separators

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-11-02 20:18:25 +01:00
Eric Fennis b196797ede Update deps (#5146) 2026-11-02 18:39:06 +01:00
dependabot[bot]Claude Opus 5.5dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7ebbb6abc3 chore(deps-dev): bump the solid-deps group across 1 directory with 6 updates (#5142)
* chore(deps-dev): bump the solid-deps group across 1 directory with 6 updates

Bumps the solid-deps group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `7.29.7` | `8.0.10` |
| [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) | `7.29.7` | `8.0.7` |
| [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) | `7.29.7` | `8.0.7` |
| [@rollup/plugin-babel](https://github.com/rollup/plugins/tree/HEAD/packages/babel) | `6.1.0` | `7.1.0` |
| [@solidjs/testing-library](https://github.com/solidjs/solid-testing-library) | `0.8.10` | `1.0.0-rc.2` |
| [vite-plugin-solid](https://github.com/solidjs/solid-vite-plugin) | `2.11.14` | `2.11.15` |



Updates `@babel/core` from 7.29.7 to 8.0.10
- [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/v8.0.10/packages/babel-core)

Updates `@babel/preset-env` from 7.29.7 to 8.0.7
- [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/v8.0.7/packages/babel-preset-env)

Updates `@babel/preset-typescript` from 7.29.7 to 8.0.7
- [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/v8.0.7/packages/babel-preset-typescript)

Updates `@rollup/plugin-babel` from 6.1.0 to 7.1.0
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/babel/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/babel-v7.1.0/packages/babel)

Updates `@solidjs/testing-library` from 0.8.10 to 1.0.0-rc.2
- [Commits](https://github.com/solidjs/solid-testing-library/commits)

Updates `vite-plugin-solid` from 2.11.14 to 2.11.15
- [Release notes](https://github.com/solidjs/solid-vite-plugin/releases)
- [Changelog](https://github.com/solidjs/solid-vite-plugin/blob/main/CHANGELOG.md)
- [Commits](https://github.com/solidjs/solid-vite-plugin/compare/vite-plugin-solid@2.11.14...vite-plugin-solid@2.11.15)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 8.0.10
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: solid-deps
- dependency-name: "@babel/preset-env"
  dependency-version: 8.0.7
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: solid-deps
- dependency-name: "@babel/preset-typescript"
  dependency-version: 8.0.7
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: solid-deps
- dependency-name: "@rollup/plugin-babel"
  dependency-version: 7.1.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: solid-deps
- dependency-name: "@solidjs/testing-library"
  dependency-version: 1.0.0-rc.2
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: solid-deps
- dependency-name: vite-plugin-solid
  dependency-version: 2.11.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: solid-deps
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(solid): make Solid builds work with Babel 8

- Drop the `bugfixes` option from `@babel/preset-env`; it was removed in
  Babel 8 because bugfix plugins are now always enabled.
- Enable the `jsx` parser plugin for `.jsx`/`.tsx` files. Babel 8's
  `@babel/preset-typescript` no longer does this, and babel-preset-solid's
  Babel 7 `@babel/plugin-syntax-jsx` skips it when TypeScript is enabled.
- Keep `@solidjs/testing-library` at `^0.8.10` for lucide-solid. The 1.x
  line targets Solid 2 (peer `solid-js >=2`) and breaks the Solid 1 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G9u8FhrFFoA9JwQHtymeAf

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 18:24:15 +01:00
dependabot[bot]Claude Opus 5.5dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5beea9bf83 chore(deps-dev): bump react-native from 0.88.0 to 0.88.1 in the react-native-deps group across 1 directory (#5134)
* chore(deps-dev): bump react-native

Bumps the react-native-deps group with 1 update in the / directory: [react-native](https://github.com/react/react-native/tree/HEAD/packages/react-native).


Updates `react-native` from 0.88.0 to 0.88.1
- [Release notes](https://github.com/react/react-native/releases)
- [Changelog](https://github.com/react/react-native/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react-native/commits/v0.88.1/packages/react-native)

---
updated-dependencies:
- dependency-name: react-native
  dependency-version: 0.88.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react-native-deps
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(deps): regenerate pnpm-lock.yaml for react-native 0.88.1

Dependabot's lockfile for this bump added a second, peer-less
`vitest@5.0.3` snapshot and pointed `@vitest/coverage-v8` / `@vitest/ui`
at it. That loaded two vitest instances, which broke snapshot tests in
lucide, lucide-react, lucide-vue and lucide-react-native ("The snapshot
state ... is not found. Did you call 'SnapshotClient.setup()'?"). It also
pulled unrelated @types/node and @babel/* bumps into other importers.

Regenerated with pnpm 11.22.0 from the base lockfile, so it now only
changes the react-native tree and hermes-compiler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G9u8Fhnpt1Di4KhMFtKbb2

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 18:06:07 +01:00
dependabot[bot]Claude Opus 5.5dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Eric
c06c5f0703 chore(deps-dev): bump the angular-deps group across 1 directory with 15 updates (#5114)
* chore(deps-dev): bump the angular-deps group across 1 directory with 15 updates

Bumps the angular-deps group with 15 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@angular-eslint/builder](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/builder) | `22.5.0` | `22.6.0` |
| [@angular-eslint/schematics](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/schematics) | `22.5.0` | `22.6.0` |
| [@angular/build](https://github.com/angular/angular-cli) | `22.2.2` | `22.2.5` |
| [@angular/cli](https://github.com/angular/angular-cli) | `22.2.2` | `22.2.5` |
| [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `22.2.2` | `22.2.4` |
| [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `22.2.2` | `22.2.4` |
| [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `22.2.2` | `22.2.4` |
| [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `22.2.2` | `22.2.4` |
| [@angular/forms](https://github.com/angular/angular/tree/HEAD/packages/forms) | `22.2.2` | `22.2.4` |
| [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `22.2.2` | `22.2.4` |
| [@angular/platform-server](https://github.com/angular/angular/tree/HEAD/packages/platform-server) | `22.2.2` | `22.2.4` |
| [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `22.2.2` | `22.2.4` |
| [@vitest/browser-playwright](https://github.com/vitest-dev/vitest/tree/HEAD/packages/browser-playwright) | `5.0.3` | `5.0.5` |
| [angular-eslint](https://github.com/angular-eslint/angular-eslint/tree/HEAD/packages/angular-eslint) | `22.5.0` | `22.6.0` |
| [ng-packagr](https://github.com/ng-packagr/ng-packagr) | `22.2.4` | `22.2.5` |



Updates `@angular-eslint/builder` from 22.5.0 to 22.6.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/builder/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v22.6.0/packages/builder)

Updates `@angular-eslint/schematics` from 22.5.0 to 22.6.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/schematics/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v22.6.0/packages/schematics)

Updates `@angular/build` from 22.2.2 to 22.2.5
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/v22.2.5/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/v22.2.2...v22.2.5)

Updates `@angular/cli` from 22.2.2 to 22.2.5
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/v22.2.5/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/v22.2.2...v22.2.5)

Updates `@angular/common` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/common)

Updates `@angular/compiler` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/compiler)

Updates `@angular/compiler-cli` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/compiler-cli)

Updates `@angular/core` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/core)

Updates `@angular/forms` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/forms)

Updates `@angular/platform-browser` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/platform-browser)

Updates `@angular/platform-server` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/platform-server)

Updates `@angular/router` from 22.2.2 to 22.2.4
- [Release notes](https://github.com/angular/angular/releases)
- [Commits](https://github.com/angular/angular/commits/v22.2.4/packages/router)

Updates `@vitest/browser-playwright` from 5.0.3 to 5.0.5
- [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/v5.0.5/packages/browser-playwright)

Updates `angular-eslint` from 22.5.0 to 22.6.0
- [Release notes](https://github.com/angular-eslint/angular-eslint/releases)
- [Changelog](https://github.com/angular-eslint/angular-eslint/blob/main/packages/angular-eslint/CHANGELOG.md)
- [Commits](https://github.com/angular-eslint/angular-eslint/commits/v22.6.0/packages/angular-eslint)

Updates `ng-packagr` from 22.2.4 to 22.2.5
- [Release notes](https://github.com/ng-packagr/ng-packagr/releases)
- [Changelog](https://github.com/ng-packagr/ng-packagr/blob/22.2.5/CHANGELOG.md)
- [Commits](https://github.com/ng-packagr/ng-packagr/compare/22.2.4...22.2.5)

---
updated-dependencies:
- dependency-name: "@angular-eslint/builder"
  dependency-version: 22.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: angular-deps
- dependency-name: "@angular-eslint/schematics"
  dependency-version: 22.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: angular-deps
- dependency-name: "@angular/build"
  dependency-version: 22.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/cli"
  dependency-version: 22.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/common"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/compiler"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/compiler-cli"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/core"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/forms"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/platform-browser"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/platform-server"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@angular/router"
  dependency-version: 22.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: "@vitest/browser-playwright"
  dependency-version: 5.0.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
- dependency-name: angular-eslint
  dependency-version: 22.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: angular-deps
- dependency-name: ng-packagr
  dependency-version: 22.2.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: angular-deps
...

Signed-off-by: dependabot[bot] <support@github.com>

* Dedupe deps

* fix(deps): align vitest override with @vitest/* 5.0.5

The workspace override pinned vitest to 5.0.3 while package.json files
already ask for 5.0.5, and this PR moves @vitest/browser-playwright to
5.0.5. That left @vitest/browser, mocker, utils and spy at 5.0.5 next
to a vitest 5.0.3 runtime, so the browser-mode packages were out of
sync with vitest. This broke:

- `expect.element` and jest-dom matcher types (Svelte, Nuxt, Solid 2)
- snapshot state in @lucide/vue tests ("snapshot state ... not found")

Bump the override to 5.0.5 so the whole vitest family resolves to a
single version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G9u8FeiSseTUuaZQjh6Z2N

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eric <eric.fennis@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 18:00:37 +01:00
Vugar BakhishovandVugar Bakhishov 588113e359 test(build-icons): cover Windows file URL imports (#4862)
* fix(dev): import icon templates with file URLs

Convert the resolved template path to an encoded file URL so the Node.js ESM loader accepts Windows paths and URL characters.

* fix(dev): import icon metadata with file URLs

Encode metadata file paths before dynamic JSON import, including Windows drive paths and URL characters.

* test(dev): cover icon build assets in paths with URL characters

Run the icon CLI in a Node process with a small SVG and metadata fixture; verify generation and metadata in a path containing spaces, # and %.

* test(build-icons): cover Windows file URL imports

---------

Co-authored-by: Vugar Bakhishov <vugarbbakhishov-hub@users.noreply.github.com>
2026-11-02 18:00:04 +01:00
DrashtiC07andEric 08193b1ef5 feat(lab): added cup-bubble-tea icon (#5098)
* feat(icons): add boba icon

* feat(lab): add boba icon

* Rename icon

* Update design

---------

Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-02 17:34:13 +01:00
e5e55d2b65 feat(lab): added soldering-iron icon (#4850)
* feat(icons): add soldering iron

* fix(icons): consolidate soldering iron use cases

* fix(icons): refine soldering iron geometry

* fix(icons): update soldering iron design and credits

* Update soldering-iron.json

removed solder tag, since part of the name

* Move `soldering-iron` icon to lab

---------

Co-authored-by: Peter Jamrozinski <peter.jamrozinski@johnsonfit.com>
Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric <eric.fennis@gmail.com>
2026-11-02 17:28:09 +01:00
343 changed files with 5559 additions and 3618 deletions
+5
View File
@@ -15,17 +15,22 @@ monstera
# Search tags and terms used in icon and category metadata
checkmark
activitypub
ageusia
artboard
barbeque
choy
cicd
ecommerce
enby
fediverse
flexbox
futbol
gddr
glassmorphism
gltf
halloumi
helpdesk
interpoint
interpunct
middot
@@ -12,6 +12,6 @@
"@octokit/rest": "^22.0.1",
"dotenv": "^17.4.2",
"openai": "^7.9.0",
"zod": "^4.5.4"
"zod": "^4.6.7"
}
}
@@ -56,7 +56,7 @@ When checking or adding a `$group:` marker:
- A marker must be exactly `"$group:"` followed by the name of an existing file in `groups/`, without the `.json` extension, in lowercase kebab-case.
- `$group:` is allowed **only** inside `tags`. It is not valid in `categories` or `contributors`.
- Groups are named after the variant suffix: `file-plus` uses `$group:plus`, `file-question-mark` uses `$group:question-mark`. Suffixes with the same meaning share a group: `mail-warning` uses `$group:exclamation-mark`, and every currency suffix uses `$group:currency`.
- Groups are named after the variant suffix: `file-plus` uses `$group:plus`, `file-question-mark` uses `$group:question-mark`. Suffixes with the same meaning share a group: `mail-exclamation-point` uses `$group:exclamation-mark`, and every currency suffix uses `$group:currency`.
- The same suffix can mean different things in different contexts — `-off` means "disabled" on `wifi-off` but "allergy free" on `wheat-off` — so only use the group when the icon carries the group's meaning, and keep context-specific tags as literals.
- Do not repeat a tag a group already provides, and do not use the same group twice in one array.
- Conventional order: the `$extends:` base icon first, then `$group:` markers, then the icon's own literal tags.
+1 -1
View File
@@ -2,5 +2,5 @@
"$schema": "../category.schema.json",
"title": "Notifications",
"description": "Icons for alerts, status updates, reminders, approvals, and attention states.",
"icon": "triangle-alert"
"icon": "triangle-exclamation-point"
}
@@ -1,6 +1,7 @@
<script setup>
import Icon from '@lucide/vue/src/Icon';
import { search } from '../../../data/iconNodes';
import Kbd from './Kbd.vue';
defineProps({
shortcut: {
@@ -17,10 +18,10 @@ defineProps({
class="search-icon"
/>
<slot />
<kbd
<Kbd
v-if="shortcut"
class="shortcut"
>{{ shortcut }}</kbd
>{{ shortcut }}</Kbd
>
</button>
</template>
@@ -59,7 +60,9 @@ defineProps({
.search-icon {
flex-shrink: 0;
transition: color 0.25s, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition:
color 0.25s,
transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition-duration: 0.25s, 0.3s;
}
@@ -70,15 +73,6 @@ defineProps({
.shortcut {
margin-left: auto;
padding: 2px 6px;
font-size: 12px;
font-family: inherit;
font-weight: 500;
line-height: 1.5;
color: var(--vp-c-text-3);
background: var(--vp-c-default-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
@media (hover: none) {
+11 -17
View File
@@ -15,6 +15,7 @@ import { ref, onMounted, nextTick, watch } from 'vue';
import Icon from '@lucide/vue/src/Icon';
import { x } from '../../../data/iconNodes';
import Button from './Button.vue';
import Kbd from './Kbd.vue';
const props = withDefaults(defineProps<InputProps>(), {
type: 'text',
@@ -29,7 +30,7 @@ const emit = defineEmits(['change', 'input', 'update:modelValue']);
const updateShortcutSpacing = () => {
nextTick(() => {
if (shortcutEl.value && wrapperEl.value) {
const shortcutWidth = shortcutEl.value.offsetWidth;
const shortcutWidth = shortcutEl.value.$el.offsetWidth;
wrapperEl.value.style.setProperty('--shortcut-width', `${shortcutWidth}px`);
}
});
@@ -83,11 +84,11 @@ defineExpose({
:size="20"
/>
</Button>
<kbd
<Kbd
v-if="shortcut"
class="shortcut"
ref="shortcutEl"
>{{ shortcut }}</kbd
>{{ shortcut }}</Kbd
>
</div>
</template>
@@ -146,33 +147,24 @@ defineExpose({
right: 12px;
top: 50%;
transform: translateY(-50%);
padding: 2px 6px;
font-size: 12px;
font-family: inherit;
font-weight: 500;
line-height: 1.5;
color: var(--vp-c-text-3);
background: var(--vp-c-default-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
pointer-events: none;
}
.input[type="search"]::-webkit-search-cancel-button {
.input[type='search']::-webkit-search-cancel-button {
-webkit-appearance: none;
appearance: none;
display: none;
}
.input[type="search"]::-ms-clear {
.input[type='search']::-ms-clear {
display: none;
}
.input[type="search"]::-o-clear {
.input[type='search']::-o-clear {
display: none;
}
.input[type="search"]::-moz-clear {
.input[type='search']::-moz-clear {
display: none;
}
@@ -195,7 +187,9 @@ defineExpose({
z-index: 1;
color: var(--vp-c-text-2);
pointer-events: none;
transition: color 0.25s, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition:
color 0.25s,
transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition-duration: 0.25s, 0.3s;
}
@@ -1,18 +1,28 @@
<script setup lang="ts">
defineProps<{
label: string
id: string
}>()
label: string;
id: string;
class?: string;
}>();
</script>
<template>
<div class="input-field">
<div class="input-label" v-if="label">
<label :for="id" class="customize-label">
<div
class="input-field"
:class="class"
>
<div
class="input-label"
v-if="label"
>
<label
:for="id"
class="customize-label"
>
{{ label }}
</label>
<div class="display-value" >
<slot name="display"/>
<div class="display-value">
<slot name="display" />
</div>
</div>
<slot />
@@ -25,7 +35,7 @@ defineProps<{
font-size: 13px;
font-weight: 600;
color: var(--vt-c-text-1);
transition: color .5s;
transition: color 0.5s;
display: block;
}
@@ -43,6 +53,6 @@ defineProps<{
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
gap: 12px;
gap: 6px;
}
</style>
@@ -0,0 +1,20 @@
<template>
<kbd class="kbd"><slot /></kbd>
</template>
<style scoped>
.kbd {
display: inline-block;
min-width: 24px;
padding: 2px 6px;
font-family: inherit;
font-size: 12px;
font-weight: 500;
line-height: 1.5;
text-align: center;
color: var(--vp-c-text-2);
background: var(--vp-c-default-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 4px;
}
</style>
@@ -0,0 +1,59 @@
<script setup lang="ts">
import { Toaster } from 'vue-sonner';
import 'vue-sonner/style.css';
import { useData } from 'vitepress';
import Icon from '@lucide/vue/src/Icon.ts';
import { check } from '../../../data/iconNodes';
const { isDark } = useData();
</script>
<template>
<ClientOnly>
<Toaster
position="bottom-center"
:theme="isDark ? 'dark' : 'light'"
>
<template #success-icon>
<Icon
:iconNode="check"
name="check"
:size="24"
/>
</template>
</Toaster>
</ClientOnly>
</template>
<style>
/* Same surface as base/Card.vue. The extra :root outranks sonner's per-theme rules */
:root [data-sonner-toaster][data-sonner-theme] {
--normal-bg: var(--vp-c-bg-soft);
--normal-border: var(--vp-c-divider);
--normal-text: var(--vp-c-text-1);
--border-radius: 12px;
}
/* Keep the icon and the text on one centred line; the site's line-height pushes the text down */
[data-sonner-toast] {
align-items: center;
}
[data-sonner-toast] [data-icon] {
align-self: center;
margin-top: 0;
margin-bottom: 0;
}
/* Sonner's icon box is 16px, so match the 24px check to stop it overflowing into the text */
[data-sonner-toast][data-styled='true'][data-type='success'] [data-icon] {
width: 24px;
height: 24px;
color: var(--vp-c-success-1);
}
[data-sonner-toast] [data-content],
[data-sonner-toast] [data-title] {
line-height: 20px;
}
</style>
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { ref, shallowRef } from 'vue';
import { onMounted, ref, shallowRef, type DefineComponent } from 'vue';
import { data } from './HomeHeroIconsCard.data';
import { useRouter } from 'vitepress';
import { motion, useScroll, useTransform, type Options as MotionOptions } from 'motion-v';
import { useMediaQuery } from '@vueuse/core';
import LucideIcon from '../base/LucideIcon.vue';
// motion-v re-exports framer-motion's `Variants`, which doesn't match the `variants` prop of its components
@@ -10,7 +11,8 @@ type Variants = MotionOptions['variants'];
const emit = defineEmits(['animation-complete']);
const MotionLucideIcon = motion.create(LucideIcon);
// motion.create only accepts a props-less DefineComponent, so the SFC's typed props need widening
const MotionLucideIcon = motion.create(LucideIcon as unknown as DefineComponent);
const preventFocusProps = {
tabindex: '-1',
@@ -21,6 +23,89 @@ const COLUMNS = 8;
const SIZE = 2;
const GAP = 1;
/** The two spirals of the Lucide logo, drawn the way the SVG editor previews them. */
const LOGO_PATH_OUTER =
'M14 12C14 9.79086 12.2091 8 10 8C7.79086 8 6 9.79086 6 12C6 16.4183 9.58172 20 14 20C18.4183 20 22 16.4183 22 12C22 8.446 20.455 5.25285 18 3.05557';
const LOGO_PATH_INNER =
'M10 12C10 14.2091 11.7909 16 14 16C16.2091 16 18 14.2091 18 12C18 7.58172 14.4183 4 10 4C5.58172 4 2 7.58172 2 12C2 15.5841 3.57127 18.8012 6.06253 21';
const VERTICES =
'M14 12h.01M10 8h.01M6 12h.01M14 20h.01M22 12h.01M18 3.05557h.01M10 12h.01M14 16h.01M18 12h.01M10 4h.01M2 12h.01M6.06253 21h.01';
const MARKERS = [
[14, 12],
[18, 3.05557],
[10, 12],
[6.06253, 21],
];
/** Bezier handles as [x1, y1, x2, y2] segments, grouped by when they appear. */
const HANDLE_GROUPS = [
// Outer spiral
{ delay: 0.2, segments: [[14, 12, 14, 9.79086]] },
{
delay: 0.4,
segments: [
[10, 8, 12.2091, 8],
[10, 8, 7.79086, 8],
],
},
{
delay: 0.6,
segments: [
[6, 12, 6, 9.79086],
[6, 12, 6, 16.4183],
],
},
{
delay: 0.8,
segments: [
[14, 20, 9.58172, 20],
[14, 20, 18.4183, 20],
],
},
{
delay: 1,
segments: [
[22, 12, 22, 16.4183],
[22, 12, 22, 8.446],
],
},
{ delay: 1.2, segments: [[18, 3.05557, 20.455, 5.25285]] },
// Inner spiral
{ delay: 0.2, segments: [[10, 12, 10, 14.2091]] },
{
delay: 0.4,
segments: [
[14, 16, 11.7909, 16],
[14, 16, 16.2091, 16],
],
},
{
delay: 0.6,
segments: [
[18, 12, 18, 14.2091],
[18, 12, 18, 7.58172],
],
},
{
delay: 0.8,
segments: [
[10, 4, 14.4183, 4],
[10, 4, 5.58172, 4],
],
},
{
delay: 1,
segments: [
[2, 12, 2, 7.58172],
[2, 12, 2, 15.5841],
],
},
{ delay: 1.2, segments: [[6.06253, 21, 3.57127, 18.8012]] },
];
const { scrollYProgress } = useScroll();
const opacity = useTransform(() => 1 - scrollYProgress.get() * 8);
@@ -101,6 +186,9 @@ const draw: Variants = {
// motion-v passes the variant label that finished, not the resolved variant
const onAnimationComplete = (variant: unknown) => {
// Reduced motion stops at the icon grid, so don't shrink the icons or loop
if (reducedMotion.value) return;
if (variant === 'visible') {
drawAnimation.value = 'exit';
return;
@@ -155,6 +243,24 @@ const shrinkIconVariants: Variants = {
transition: { delay: 1.8, duration: 1.5, ease: 'easeInOut' },
}),
};
// Only rendered on the client, so reduced motion is known before the first frame
const mounted = ref(false);
const reducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
onMounted(() => {
if (reducedMotion.value) {
drawAnimation.value = 'exit';
showHandles.value = false;
scaleDownAnimation.value = 'small';
iconGridAnimation.value = 'showIcons';
}
mounted.value = true;
});
/** Skips straight to the end state when the user prefers reduced motion. */
const initial = <T,>(value: T) => (reducedMotion.value ? false : value);
</script>
<template>
@@ -167,6 +273,7 @@ const shrinkIconVariants: Variants = {
v-bind="preventFocusProps"
>
<motion.svg
v-if="mounted"
xmlns="http://www.w3.org/2000/svg"
viewBox="-12 -12 48 48"
fill="none"
@@ -209,7 +316,7 @@ const shrinkIconVariants: Variants = {
<MotionLucideIcon
v-for="(icon, index) in icons"
size="2"
initial="initial"
:initial="initial('initial')"
:key="icon.name"
:variants="iconAnimationVariants"
:animate="iconGridAnimation"
@@ -223,15 +330,15 @@ const shrinkIconVariants: Variants = {
<motion.g
:variants="scaleDownVariants"
:animate="scaleDownAnimation"
initial="hidden"
:initial="initial('hidden')"
@animation-complete="onAnimationComplete"
v-bind="preventFocusProps"
>
<motion.path
d="M14 12C14 9.79086 12.2091 8 10 8C7.79086 8 6 9.79086 6 12C6 16.4183 9.58172 20 14 20C18.4183 20 22 16.4183 22 12C22 8.446 20.455 5.25285 18 3.05557"
:style="{ stroke: 'var(--vp-c-gray-1)' }"
:d="LOGO_PATH_OUTER"
:style="{ stroke: reducedMotion ? 'var(--vp-c-text-1)' : 'var(--vp-c-gray-1)' }"
:animate="drawAnimation"
initial="hidden"
:initial="initial('hidden')"
:variants="draw"
:custom="1"
@animation-complete="onAnimationComplete"
@@ -239,10 +346,10 @@ const shrinkIconVariants: Variants = {
/>
<motion.path
d="M10 12C10 14.2091 11.7909 16 14 16C16.2091 16 18 14.2091 18 12C18 7.58172 14.4183 4 10 4C5.58172 4 2 7.58172 2 12C2 15.5841 3.57127 18.8012 6.06253 21"
:style="{ stroke: 'var(--vp-c-gray-1)' }"
:d="LOGO_PATH_INNER"
:style="{ stroke: reducedMotion ? 'var(--vp-c-brand)' : 'var(--vp-c-gray-1)' }"
:animate="drawAnimation"
initial="hidden"
:initial="initial('hidden')"
:variants="draw"
:custom="0"
v-bind="preventFocusProps"
@@ -253,80 +360,36 @@ const shrinkIconVariants: Variants = {
class="svg-preview-control-path-marker-group"
:style="{ stroke: 'var(--vp-c-text-1)' }"
stroke-width="0.125"
:initial="{ opacity: 1 }"
:animate="showHandles ? { opacity: 1 } : { opacity: 0 }"
:transition="{ delay: 0, duration: 0.2 }"
:initial="initial({ opacity: 1 })"
:animate="{ opacity: showHandles ? 1 : 0 }"
:transition="{ duration: 0.2 }"
v-bind="preventFocusProps"
>
<motion.path
d="M14 12C14 9.79086 12.2091 8 10 8C7.79086 8 6 9.79086 6 12C6 16.4183 9.58172 20 14 20C18.4183 20 22 16.4183 22 12C22 8.446 20.455 5.25285 18 3.05557"
:initial="{ opacity: 0 }"
v-for="d in [LOGO_PATH_OUTER, LOGO_PATH_INNER]"
:key="d"
:d="d"
:initial="initial({ opacity: 0 })"
:animate="{ opacity: 1 }"
:transition="{ delay: 1.6, duration: 1.5 }"
v-bind="preventFocusProps"
/>
<motion.path
d="M10 12C10 14.2091 11.7909 16 14 16C16.2091 16 18 14.2091 18 12C18 7.58172 14.4183 4 10 4C5.58172 4 2 7.58172 2 12C2 15.5841 3.57127 18.8012 6.06253 21"
:initial="{ opacity: 0 }"
:animate="{ opacity: 1 }"
:transition="{ delay: 1.6, duration: 1.5 }"
v-bind="preventFocusProps"
/>
<motion.g
:initial="{ opacity: 0 }"
:d="VERTICES"
:initial="initial({ opacity: 0 })"
:animate="{ opacity: 1 }"
:transition="{ delay: 0.2, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path
d="M14 12h.01M10 8h.01M10 8h.01M6 12h.01M6 12h.01M14 20h.01M14 20h.01M22 12h.01M22 12h.01M18 3.05557h.01M10 12h.01M14 16h.01M14 16h.01M18 12h.01M18 12h.01M10 4h.01M10 4h.01M2 12h.01M2 12h.01M6.06253 21h.01"
>
</path>
</motion.g>
<motion.circle
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0, duration: 0.8 }"
cx="14"
cy="12"
r="0.5"
v-bind="preventFocusProps"
/>
<motion.circle
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0, duration: 0.8 }"
cx="14"
cy="12"
v-for="[cx, cy] in MARKERS"
:key="`${cx},${cy}`"
:cx="cx"
:cy="cy"
r="0.5"
v-bind="preventFocusProps"
/>
<motion.circle
:initial="{ opacity: 0, scale: 0.2 }"
:initial="initial({ opacity: 0, scale: 0.2 })"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0, duration: 0.8 }"
cx="18"
cy="3.05557"
r="0.5"
v-bind="preventFocusProps"
/>
<motion.circle
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0, duration: 0.8 }"
cx="10"
cy="12"
r="0.5"
v-bind="preventFocusProps"
/>
<motion.circle
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0, duration: 0.8 }"
cx="6.06253"
cy="21"
r="0.5"
:transition="{ duration: 0.8 }"
v-bind="preventFocusProps"
/>
</motion.g>
@@ -335,221 +398,30 @@ const shrinkIconVariants: Variants = {
stroke-width="0.12"
stroke="#FFF"
stroke-opacity="0.3"
:initial="{ opacity: 1 }"
:animate="showHandles ? { opacity: 1 } : { opacity: 0 }"
:transition="{ delay: 0, duration: 0.6 }"
:initial="initial({ opacity: 1 })"
:animate="{ opacity: showHandles ? 1 : 0 }"
:transition="{ duration: 0.6 }"
v-bind="preventFocusProps"
>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
v-for="(group, index) in HANDLE_GROUPS"
:key="index"
:initial="initial({ opacity: 0, scale: 0.2 })"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.2, duration: 0.3 }"
:transition="{ delay: group.delay, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M14 12 14 9.79086"></path>
<circle
cy="9.79086"
cx="14"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.4, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M10 8 12.2091 8"></path>
<circle
cy="8"
cx="12.2091"
r="0.25"
></circle>
<path d="M10 8 7.79086 8"></path>
<circle
cy="8"
cx="7.79086"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.6, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M6 12 6 9.79086"></path>
<circle
cy="9.79086"
cx="6"
r="0.25"
></circle>
<path d="M6 12 6 16.4183"></path>
<circle
cy="16.4183"
cx="6"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.8, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M14 20 9.58172 20"></path>
<circle
cy="20"
cx="9.58172"
r="0.25"
></circle>
<path d="M14 20 18.4183 20"></path>
<circle
cy="20"
cx="18.4183"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 1, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M22 12 22 16.4183"></path>
<circle
cy="16.4183"
cx="22"
r="0.25"
></circle>
<path d="M22 12 22 8.446"></path>
<circle
cy="8.446"
cx="22"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 1.2, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M18 3.05557 20.455 5.25285"></path>
<circle
cy="5.25285"
cx="20.455"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.2, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M10 12 10 14.2091"></path>
<circle
cy="14.2091"
cx="10"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.4, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M14 16 11.7909 16"></path>
<circle
cy="16"
cx="11.7909"
r="0.25"
></circle>
<path d="M14 16 16.2091 16"></path>
<circle
cy="16"
cx="16.2091"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.6, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M18 12 18 14.2091"></path>
<circle
cy="14.2091"
cx="18"
r="0.25"
></circle>
<path d="M18 12 18 7.58172"></path>
<circle
cy="7.58172"
cx="18"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 0.8, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M10 4 14.4183 4"></path>
<circle
cy="4"
cx="14.4183"
r="0.25"
></circle>
<path d="M10 4 5.58172 4"></path>
<circle
cy="4"
cx="5.58172"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 1, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M2 12 2 7.58172"></path>
<circle
cy="7.58172"
cx="2"
r="0.25"
></circle>
<path d="M2 12 2 15.5841"></path>
<circle
cy="15.5841"
cx="2"
r="0.25"
></circle>
</motion.g>
<motion.g
:initial="{ opacity: 0, scale: 0.2 }"
:animate="{ opacity: 1, scale: 1 }"
:transition="{ delay: 1.2, duration: 0.3 }"
v-bind="preventFocusProps"
>
<path d="M6.06253 21 3.57127 18.8012"></path>
<circle
cy="18.8012"
cx="3.57127"
r="0.25"
></circle>
<template
v-for="[x1, y1, x2, y2] in group.segments"
:key="`${x2},${y2}`"
>
<path :d="`M${x1} ${y1} ${x2} ${y2}`" />
<circle
:cx="x2"
:cy="y2"
r="0.25"
/>
</template>
</motion.g>
</motion.g>
</motion.svg>
@@ -3,6 +3,7 @@ import { computed } from 'vue';
import createLucideIcon from '@lucide/vue/src/createLucideIcon';
import { useMediaQuery } from '@vueuse/core';
import { useRouter } from 'vitepress';
import { toast } from 'vue-sonner';
import getSVGIcon from '../../utils/getSVGIcon';
import useConfetti from '../../composables/useConfetti';
import Tooltip from '../base/Tooltip.vue';
@@ -38,17 +39,37 @@ const href = computed(() =>
props.externalLibrary ? `/icons/${props.externalLibrary}/${props.name}` : `/icons/${props.name}`,
);
// The toast says what was copied, since the name and the SVG are copied the same way
async function copyToClipboard(text: string, confettiMessage: string, toastMessage: string) {
await navigator.clipboard.writeText(text);
confettiText.value = confettiMessage;
confetti();
toast.success(toastMessage);
}
function copyName() {
return copyToClipboard(props.name, `Copied name!`, `Copied the name of ${props.name}`);
}
function copySVG(iconButton: HTMLElement) {
const svgString = getSVGIcon(iconButton.querySelector('svg'), {
class: `lucide lucide-${props.name}`,
});
return copyToClipboard(svgString, `Copied SVG!`, `Copied the SVG of ${props.name}`);
}
async function navigateToIcon(event) {
if (event.shiftKey) {
event.preventDefault();
const svgString = getSVGIcon(event.target.firstChild, {
class: `lucide lucide-${props.name}`,
});
await copySVG(event.currentTarget);
return;
}
await navigator.clipboard.writeText(svgString);
confettiText.value = copiedText;
confetti();
if (event.ctrlKey || event.metaKey) {
event.preventDefault();
await copyName();
return;
}
@@ -76,6 +97,34 @@ async function navigateToIcon(event) {
}
}
// On a selected (focused) icon: Enter opens it, Ctrl/Cmd + C copies its name, Shift + C its SVG.
// (Ctrl/Cmd + Shift + C is the browser's inspect shortcut, so it can't be used for the SVG.)
async function handleKeydown(event: KeyboardEvent) {
if (
event.key === 'Enter' &&
!(event.shiftKey || event.ctrlKey || event.metaKey || event.altKey)
) {
await navigateToIcon(event);
return;
}
if (event.key.toLowerCase() !== 'c' || event.altKey) return;
if (event.shiftKey && !(event.ctrlKey || event.metaKey)) {
event.preventDefault();
await copySVG(event.currentTarget as HTMLElement);
return;
}
if (!(event.ctrlKey || event.metaKey) || event.shiftKey) return;
// Leave a normal copy alone when some text on the page is selected
if (window.getSelection()?.toString()) return;
event.preventDefault();
await copyName();
}
const DiamondIcon = createLucideIcon('Diamond', diamond);
</script>
@@ -83,7 +132,9 @@ const DiamondIcon = createLucideIcon('Diamond', diamond);
<Tooltip :title="name">
<a
class="icon-button confetti-button vp-raw"
tabindex="0"
@click="navigateToIcon"
@keydown="handleKeydown"
:class="{ active, animate }"
:aria-label="name"
:data-confetti-text="confettiText"
@@ -151,6 +202,12 @@ const DiamondIcon = createLucideIcon('Diamond', diamond);
.confetti-button:before {
line-height: 80px;
/* Center the "Copied ..." text over the icon (it started at the icon's left edge and ran off to the right). */
width: 160px;
max-width: none;
left: calc(50% - 80px);
text-align: center;
white-space: nowrap;
}
.icon-button:active {
@@ -186,10 +243,16 @@ const DiamondIcon = createLucideIcon('Diamond', diamond);
background-color: var(--vp-button-alt-active-bg);
}
.icon-button.active {
.icon-button.active,
.icon-button.animate,
.icon-button:focus-visible {
border-color: var(--vp-c-brand);
}
.icon-button:focus-visible {
outline: none;
}
.lucide-icon {
margin: auto;
pointer-events: none;
@@ -6,7 +6,7 @@ import Calendar from '../../../data/iconDetails/calendar.ts';
import Clock from '../../../data/iconDetails/clock.ts';
import Bug from '../../../data/iconDetails/bug.ts';
import Rocket from '../../../data/iconDetails/rocket.ts';
import TriangleAlert from '../../../data/iconDetails/triangle-alert.ts';
import TriangleExclamationPoint from '../../../data/iconDetails/triangle-exclamation-point.ts';
import PartyPopper from '../../../data/iconDetails/party-popper.ts';
import Scissors from '../../../data/iconDetails/scissors.ts';
import Copy from '../../../data/iconDetails/copy.ts';
@@ -41,7 +41,7 @@ const CalendarIcon = createLucideIcon('calendar', Calendar.iconNode);
const ClockIcon = createLucideIcon('clock', Clock.iconNode);
const BugIcon = createLucideIcon('bug', Bug.iconNode);
const RocketIcon = createLucideIcon('rocket', Rocket.iconNode);
const AlertTriangleIcon = createLucideIcon('alert-triangle', TriangleAlert.iconNode);
const TriangleExclamationPointIcon = createLucideIcon('triangle-exclamation-point', TriangleExclamationPoint.iconNode);
const ScissorsIcon = createLucideIcon('scissors', Scissors.iconNode);
const CopyIcon = createLucideIcon('copy', Copy.iconNode);
const SaveIcon = createLucideIcon('save', Save.iconNode);
@@ -128,7 +128,7 @@ const prettyName = props.name
>
<div class="placeholder"></div>
<div class="badge badge-red">
<AlertTriangleIcon :size="20" />
<TriangleExclamationPointIcon :size="20" />
Alert
</div>
</div>
@@ -208,6 +208,43 @@ function handleCloseDrawer() {
window.history.pushState({}, '', url);
}
const ARROW_STEPS = {
ArrowLeft: () => -1,
ArrowRight: () => 1,
ArrowUp: () => -columnSize.value,
ArrowDown: () => columnSize.value,
};
// Arrow keys move through the search results: from the search field down into the grid, then
// between the icons. The grid shows `columnSize` icons per row, so up and down skip a whole row.
function handleArrowKeys(event: KeyboardEvent) {
const step = ARROW_STEPS[event.key]?.();
if (step === undefined || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
return;
const iconButtons = Array.from(
overviewEl.value?.querySelectorAll<HTMLElement>('.icons .icon-button') ?? [],
);
const target = event.target as HTMLElement;
const fromSearch = target.tagName === 'INPUT' && target.closest('.input-wrapper') !== null;
let next: HTMLElement | undefined;
if (fromSearch) {
if (event.key !== 'ArrowDown') return;
next = iconButtons[0];
} else {
const index = iconButtons.indexOf(target);
if (index === -1) return;
next = iconButtons[index + step];
}
if (next) {
event.preventDefault();
next.focus();
next.scrollIntoView({ block: 'nearest' });
}
}
</script>
<template>
@@ -215,6 +252,7 @@ function handleCloseDrawer() {
ref="overviewEl"
class="overview-container"
:class="{ 'icon-drawer-open': activeIconName }"
@keydown="handleArrowKeys"
>
<StickyBar>
<InputSearch
@@ -0,0 +1,297 @@
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
import Icon from '@lucide/vue/src/Icon';
import Kbd from '../base/Kbd.vue';
import { x } from '~/.vitepress/data/iconNodes';
const dialog = ref<HTMLDialogElement | null>(null);
const isClosing = ref(false);
const modifierKey = ref('Ctrl');
const shortcuts = [
{ keys: ['mod', 'K'], alternative: ['/'], description: 'Search' },
{ keys: ['Shift', 'Click'], description: 'Copy the SVG of an icon' },
{ keys: ['mod', 'Click'], description: 'Copy the name of an icon' },
{ keys: ['Arrow keys'], description: 'Move through the search results' },
{ keys: ['Enter'], description: 'Open the selected icon' },
{ keys: ['mod', 'C'], description: 'Copy the name of the selected icon' },
{ keys: ['Shift', 'C'], description: 'Copy the SVG of the selected icon' },
{ keys: ['Shift', '?'], description: 'Show keyboard shortcuts' },
];
function keyLabel(key: string) {
return key === 'mod' ? modifierKey.value : key;
}
function open() {
dialog.value?.showModal();
// Focus the dialog itself rather than its close button, so the button is not shown as selected
dialog.value?.focus();
}
// The dialog leaves the top layer as soon as it closes, so play the exit transition first
async function close() {
const element = dialog.value;
if (!element?.open || isClosing.value) return;
isClosing.value = true;
await nextTick();
await Promise.allSettled(element.getAnimations().map((animation) => animation.finished));
element.close();
isClosing.value = false;
}
function handleDialogClick(event: MouseEvent) {
// A click on the backdrop lands on the dialog element itself
if (event.target === dialog.value) {
close();
}
}
function isTyping(event: KeyboardEvent) {
const target = event.target as HTMLElement | null;
return (
target?.isContentEditable ||
target?.tagName === 'INPUT' ||
target?.tagName === 'TEXTAREA' ||
target?.tagName === 'SELECT'
);
}
// The ? key opens the dialog, except while typing in a field
function handleKeydown(event: KeyboardEvent) {
if (event.key === '?' && !event.ctrlKey && !event.metaKey && !event.altKey && !isTyping(event)) {
event.preventDefault();
open();
}
}
onMounted(() => {
modifierKey.value = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl';
window.addEventListener('keydown', handleKeydown);
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', handleKeydown);
});
</script>
<template>
<button
type="button"
class="keyboard-shortcuts-hint"
aria-haspopup="dialog"
@click="open"
>
<span class="hint-label">Keyboard shortcuts</span>
<span class="hint-keys">
<Kbd>Shift</Kbd>
<span>+</span>
<Kbd>?</Kbd>
</span>
</button>
<dialog
ref="dialog"
class="shortcuts-dialog"
:class="{ closing: isClosing }"
tabindex="-1"
aria-labelledby="shortcuts-title"
@click="handleDialogClick"
@cancel.prevent="close"
>
<div class="shortcuts-header">
<h2 id="shortcuts-title">Keyboard shortcuts</h2>
<button
type="button"
class="shortcuts-close"
aria-label="Close"
@click="close"
>
<Icon
:iconNode="x"
name="x"
aria-hidden="true"
/>
</button>
</div>
<dl class="shortcuts-list">
<div
v-for="shortcut in shortcuts"
:key="shortcut.description"
class="shortcut-row"
>
<dt class="shortcut-keys">
<template
v-for="(key, index) in shortcut.keys"
:key="key"
>
<span
v-if="index > 0"
class="shortcut-plus"
>+</span
>
<Kbd>{{ keyLabel(key) }}</Kbd>
</template>
<template v-if="shortcut.alternative">
<span class="shortcut-or">or</span>
<Kbd
v-for="key in shortcut.alternative"
:key="key"
>{{ key }}</Kbd
>
</template>
</dt>
<dd class="shortcut-description">{{ shortcut.description }}</dd>
</div>
</dl>
</dialog>
</template>
<style scoped>
.keyboard-shortcuts-hint {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 12px;
padding: 24px 0px;
border-top: 1px solid var(--vp-c-divider);
font-size: 12px;
color: var(--vp-c-text-1);
position: sticky;
bottom: -96px;
background-color: var(--vp-sidebar-bg-color);
width: 100%;
cursor: pointer;
}
.hint-keys {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 4px;
}
.shortcuts-dialog {
width: min(480px, calc(100vw - 32px));
padding: 20px 24px 24px;
color: var(--vp-c-text-1);
background: var(--vp-c-bg);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
box-shadow: var(--vp-shadow-4);
outline: none;
}
.shortcuts-dialog::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
.shortcuts-dialog[open] {
transition:
opacity 150ms ease-out,
transform 200ms cubic-bezier(0.34, 1.4, 0.64, 1);
}
.shortcuts-dialog[open]::backdrop {
transition: background-color 150ms ease-out;
}
@starting-style {
.shortcuts-dialog[open] {
opacity: 0;
transform: translateY(-6px) scale(0.98);
}
.shortcuts-dialog[open]::backdrop {
background-color: transparent;
}
}
.shortcuts-dialog.closing {
opacity: 0;
transform: translateY(-6px) scale(0.98);
transition:
opacity 150ms ease-in,
transform 150ms ease-in;
}
.shortcuts-dialog.closing::backdrop {
background-color: transparent;
transition: background-color 150ms ease-in;
}
.shortcuts-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.shortcuts-header h2 {
margin: 0;
font-size: 18px;
font-weight: 600;
}
.shortcuts-close {
display: flex;
padding: 4px;
color: var(--vp-c-text-2);
border-radius: 6px;
cursor: pointer;
}
.shortcuts-close:hover,
.shortcuts-close:focus-visible {
color: var(--vp-c-text-1);
background: var(--vp-c-default-soft);
}
.shortcuts-close svg {
width: 20px;
height: 20px;
}
.shortcuts-list {
display: flex;
flex-direction: column;
gap: 12px;
margin: 0;
}
.shortcut-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.shortcut-keys {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 4px;
order: 2;
}
.shortcut-description {
margin: 0;
color: var(--vp-c-text-2);
font-size: 14px;
}
.shortcut-plus,
.shortcut-or {
color: var(--vp-c-text-3);
font-size: 12px;
}
.shortcut-or {
margin: 0 4px;
}
</style>
@@ -89,6 +89,7 @@ function onReset() {
<InputField
id="non-scaling-stroke"
label="Non-scaling stroke"
class="non-scaling-stroke-switch"
>
<Switch
id="non-scaling-stroke-switch"
@@ -173,3 +173,12 @@
0% 0%;
}
}
/* Keep the copy confetti even with reduced motion turned on (owner request): the site-wide
reduced-motion rule in style.css shrinks every animation to 0.01ms, which hid it at once. */
@media (prefers-reduced-motion: reduce) {
.confetti-button.animate:before,
.confetti-button.animate:after {
animation-duration: 1s !important;
}
}
@@ -117,8 +117,6 @@ function scrollTrack(direction: 1 | -1) {
.tiers {
padding-top: 96px;
padding-bottom: 48px;
/* The track bleeds to the right edge of the viewport. */
overflow-x: clip;
}
.tiers-header {
@@ -165,7 +163,6 @@ function scrollTrack(direction: 1 | -1) {
.track-wrapper {
position: relative;
margin-right: min(-24px, calc((1152px - 100vw) / 2));
}
.track {
@@ -178,12 +175,16 @@ function scrollTrack(direction: 1 | -1) {
padding-bottom: 12px;
padding-right: 24px;
scroll-padding-right: 24px;
scrollbar-width: thin;
scrollbar-width: none;
scroll-snap-align: center;
scroll-padding-left: 24px;
scroll-padding-right: 24px;
}
.track::-webkit-scrollbar {
display: none;
}
.track:focus-visible {
outline: 2px solid var(--vp-c-brand-1);
outline-offset: 4px;
+2
View File
@@ -13,6 +13,7 @@ import { EXTERNAL_LIBS_CONTEXT, externalLibContext } from './composables/useExte
import SideBarNavBefore from './layouts/SideBarNavBefore.vue';
import NavBarSponsorButton from './layouts/NavBarSponsorButton.vue';
import SnackPlayer from './components/editors/SnackPlayer.vue';
import Toaster from './components/base/Toaster.vue';
import { setupTracking } from './utils/openpanel';
import trackUnderlineDirection from './utils/underlineDirection';
@@ -25,6 +26,7 @@ const theme: Partial<Theme> = {
'sidebar-nav-after': () => h(IconsSidebarNavAfter),
'home-hero-image': () => h(HomeHeroIconsCard),
'home-hero-actions-after': () => h(HomeHeroAfter),
'layout-bottom': () => h(Toaster),
'nav-bar-content-after': () => h(NavBarSponsorButton),
// Keep this here for now, we might want to add more things to the top bar in the future
// 'layout-top': () => h(LayoutTop),
@@ -1,18 +1,21 @@
<script setup>
import { useData } from 'vitepress'
import { computed } from 'vue';
import { useData } from 'vitepress';
import SidebarIconCustomizer from '../components/icons/SidebarIconCustomizer.vue';
import ExternalLibrarySelect from '../components/icons/SidebarExternalLibrarySelect.vue';
import CategoryList from '../components/icons/CategoryList.vue';
import KeyboardShortcuts from '../components/icons/KeyboardShortcuts.vue';
import CategoryList from '../components/icons/CategoryList.vue'
import SidebarIconCustomizer from '../components/icons/SidebarIconCustomizer.vue'
import ExternalLibrarySelect from '../components/icons/SidebarExternalLibrarySelect.vue'
const { page } = useData()
const { page } = useData();
const isIconsPage = computed(() => page.value?.relativePath?.startsWith?.('icons'));
</script>
<template>
<div>
<SidebarIconCustomizer v-if="page?.relativePath?.startsWith?.('icons')"/>
<ExternalLibrarySelect v-if="page?.relativePath?.startsWith?.('icons')"/>
<CategoryList v-if="page?.relativePath?.startsWith?.('icons')"/>
<div v-if="isIconsPage">
<SidebarIconCustomizer />
<ExternalLibrarySelect />
<CategoryList />
<KeyboardShortcuts />
</div>
</template>
+6
View File
@@ -385,6 +385,12 @@ html.dark .VPNav .VPSwitchAppearance .icon .moon {
transition: transform 0.3s cubic-bezier(0.34, 1.4, 0.64, 1);
}
@media (min-width: 960px) {
.VPSidebar {
padding-right: 24px !important;
}
}
/* Links in the page text: a faint underline shows they are links, and on hover a solid
underline draws in from the left. Drawn with backgrounds so it also follows links that
wrap onto a second line. */
+1 -1
View File
@@ -11,7 +11,7 @@ const allowedAttrs = [
'class',
];
export default function getSVGIcon(element?: HTMLElement, attrs?: Record<string, string>) {
export default function getSVGIcon(element?: Element, attrs?: Record<string, string>) {
const svg = element ?? document.querySelector('#previewer svg');
if (!svg) return;
@@ -14,6 +14,8 @@ export default function useSearchShortcut(callback: () => void) {
// Check for Cmd+K (Mac), Ctrl+K (Windows/Linux), or forward slash
if (((event.metaKey || event.ctrlKey) && event.key === 'k') || event.key === '/') {
event.preventDefault();
// Algolia listens for the same keys on window, so claim them before it sees them
event.stopImmediatePropagation();
callback();
}
}
@@ -24,11 +26,11 @@ export default function useSearchShortcut(callback: () => void) {
shortcutText.value = isMac ? '⌘K' : 'Ctrl+K';
// Add keyboard shortcut listener
window.addEventListener('keydown', handleKeydown);
window.addEventListener('keydown', handleKeydown, { capture: true });
});
onBeforeUnmount(() => {
window.removeEventListener('keydown', handleKeydown);
window.removeEventListener('keydown', handleKeydown, { capture: true });
});
return { shortcutText };
@@ -3,7 +3,7 @@ description: Learn the best practices for writing use cases for Lucide icons.
---
<script setup>
import { batteryLow, creditCard, crop, handshake, heading2, microchip, search, squareLetterP, triangleAlert, wifiOff } from '~/.vitepress/data/iconNodes';
import { batteryLow, creditCard, crop, handshake, heading2, microchip, search, squareLetterP, triangleExclamationPoint, wifiOff } from '~/.vitepress/data/iconNodes';
import LucideIcon from '~/.vitepress/theme/components/base/LucideIcon.vue';
</script>
@@ -120,10 +120,10 @@ The period adds **unnecessary punctuation** and makes entries inconsistent.
Use plain text only. Formatting belongs in documentation, not metadata values.
:::: example
::: do <LucideIcon name="triangle-alert" :iconNode="triangleAlert" /> Warning users about a destructive action
::: do <LucideIcon name="triangle-exclamation-point" :iconNode="triangleExclamationPoint" /> Warning users about a destructive action
This works in search, generated pages, and other places that use metadata.
:::
::: dont <LucideIcon name="triangle-alert" :iconNode="triangleAlert" /> <span>**Warning** users about a destructive action ⚠️</span>
::: dont <LucideIcon name="triangle-exclamation-point" :iconNode="triangleExclamationPoint" /> <span>**Warning** users about a destructive action ⚠️</span>
Markdown and emoji can **show up in generated UI** and make metadata **harder to reuse**.
:::
::::
+1 -1
View File
@@ -31,7 +31,7 @@ You can then reference the registered icons by name:
```html [app.html]
<svg lucideIcon="square-check"></svg>
<svg lucideIcon="circle-alert"></svg>
<svg lucideIcon="circle-exclamation-point"></svg>
```
## How names are resolved
-26
View File
@@ -1,26 +0,0 @@
---
title: Comparison
description: A comparison between Lucide and Feather Icons, highlighting the differences and benefits of each.
---
# Comparison
## Lucide vs Feather Icons
Lucide is a community-driven fork of [Feather Icons](https://github.com/feathericons/feather).
The decision to create Lucide arose from growing dissatisfaction with the moderation of the Feather Icons project. With more than 300 open issues and over 100 open PRs, the Feather Icons project has been abandoned and is no longer actively maintained. Unfortunately, this means that numerous developers and designers have invested their time in contributing to Feather Icons without the possibility of their PRs being accepted.
In an effort to expand the icon set while remaining true to the original minimalist design language, Lucide is driven by a community of developers and designers. We strive to grow together and maintain a faithful continuation of the project.
### Why should I choose Lucide over Feather Icons?
- Lucide has expanded its icon set by 1600+ in the last few years. Lucide now has over 1800 icons, while Feather has around 287 icons.
- Well maintained code base.
- Active community.
### Should I migrate to Lucide?
That depends on whether you're satisfied with the icons from Feather Icons. If that is the case, it may not be worth the effort.
However, if you find yourself struggling and feeling limited by the icons provided by Feather, you can consider migrating.
When we forked, we didn't remove any icons, but some icons have been renamed.
-1
View File
@@ -2,7 +2,6 @@
title: What is Lucide?
description: An introduction to Lucide, an open-source icon library that provides 1600+ vector (svg) files for displaying icons and symbols in digital and non-digital projects.
nextPage:
- comparison
- installation
---
+6 -5
View File
@@ -42,12 +42,12 @@
"h3": "^1.15.11",
"markdown-it": "^15.0.3",
"markdown-it-container": "^4.0.0",
"nitropack": "^2.13.4",
"nitropack": "^2.13.5",
"rollup-plugin-copy": "^3.5.0",
"semver": "^7.8.5",
"sharp": "^0.35.5",
"shiki": "^4.4.3",
"simple-git": "^4.0.1",
"shiki": "^4.5.0",
"simple-git": "^4.0.2",
"sitemap": "^9.0.1",
"svg-path-commander": "^2.3.3",
"svg-pathdata": "^9.0.0",
@@ -73,10 +73,11 @@
"lodash-es": "^4.18.1",
"lucide": "workspace:*",
"lucide-react": "workspace:*",
"motion-v": "2.4.0",
"motion-v": "2.11.0",
"react": "19.3.1",
"react-dom": "19.3.1",
"sandpack-vue3": "3.1.12",
"vue": "^3.5.44"
"vue": "^3.5.44",
"vue-sonner": "^2.0.9"
}
}
+62 -7
View File
@@ -12,8 +12,68 @@
"permanent": true
},
{
"source": "/docs/:slug(lucide-?.*)",
"destination": "/guide/:slug",
"source": "/docs/lucide-vue-next",
"destination": "/guide/vue",
"permanent": true
},
{
"source": "/guide/packages/lucide-vue-next",
"destination": "/guide/vue",
"permanent": true
},
{
"source": "/guide/vue-next",
"destination": "/guide/vue",
"permanent": true
},
{
"source": "/docs/lucide",
"destination": "/guide/lucide",
"permanent": true
},
{
"source": "/docs/lucide-:pkg",
"destination": "/guide/:pkg",
"permanent": true
},
{
"source": "/guide/lucide-:pkg",
"destination": "/guide/:pkg",
"permanent": true
},
{
"source": "/guide/packages/lucide-:pkg/",
"destination": "/guide/:pkg",
"permanent": true
},
{
"source": "/guide/advanced/accessibility",
"destination": "/how-to/accessibility",
"permanent": true
},
{
"source": "/guide/basics/:slug",
"destination": "/guide/react/basics/:slug",
"permanent": true
},
{
"source": "/guide/advanced/:slug",
"destination": "/guide/react/advanced/:slug",
"permanent": true
},
{
"source": "/guide/design/figma-guide",
"destination": "/contribute/icons/figma-guide",
"permanent": true
},
{
"source": "/guide/design/:slug(icon-design-guide|icon-properties)",
"destination": "/contribute/icons/design-principles",
"permanent": true
},
{
"source": "/icons/lab/:name(carton-off|briefcase-plus)",
"destination": "/icons/:name",
"permanent": true
},
{
@@ -47,11 +107,6 @@
"destination": "/how-to/accessibility",
"permanent": true
},
{
"source": "/guide/advanced/accessibility",
"destination": "/how-to/accessibility",
"permanent": true
},
{
"source": "/guide/advanced",
"destination": "/guide/react/advanced",
+5 -1
View File
@@ -12,6 +12,10 @@
"presentation",
"reporting",
"data visualisation",
"visualisation"
"visualisation",
"analyze",
"kpi",
"metrics",
"insights"
]
}
+4 -1
View File
@@ -16,6 +16,9 @@
"valid",
"ticked",
"task",
"todo"
"todo",
"selected",
"okay",
"ok"
]
}
+3 -1
View File
@@ -4,6 +4,8 @@
"tags": [
"coding",
"programming",
"development"
"development",
"developer",
"dev"
]
}
+9
View File
@@ -0,0 +1,9 @@
{
"$schema": "../group.schema.json",
"description": "Style: drawn with a dashed or dotted line",
"tags": [
"dashed",
"dotted",
"broken line"
]
}
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "../group.schema.json",
"description": "Subject: a face showing an emotion",
"tags": [
"emoji",
"emotion",
"mood",
"feeling",
"expression",
"reaction"
]
}
+16
View File
@@ -0,0 +1,16 @@
{
"$schema": "../group.schema.json",
"description": "Action: moving into something or bringing something in",
"tags": [
"in",
"inside",
"inwards",
"input",
"incoming",
"import",
"insert",
"entry",
"entrance",
"ingress"
]
}
+6 -1
View File
@@ -13,6 +13,11 @@
"hazard",
"exclamation mark",
"exclamation point",
"!"
"!",
"critical",
"urgent",
"severity",
"punctuation",
"symbol"
]
}
+15
View File
@@ -0,0 +1,15 @@
{
"$schema": "../group.schema.json",
"description": "Action: moving out of something or sending something out",
"tags": [
"out",
"outside",
"outwards",
"output",
"outgoing",
"export",
"leave",
"egress",
"exit"
]
}
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "../group.schema.json",
"description": "Layout: resizing, splitting or merging panes and grid cells",
"tags": [
"pane",
"grid",
"resize",
"window",
"merge",
"resizing"
]
}
+14
View File
@@ -0,0 +1,14 @@
{
"$schema": "../group.schema.json",
"description": "Geometry: drawn strokes, paths and line segments",
"tags": [
"stroke",
"path",
"segment",
"vector",
"graphics",
"design",
"shape",
"curve"
]
}
+14 -1
View File
@@ -3,19 +3,32 @@
"description": "Status: help, or something unknown",
"tags": [
"help",
"assistance",
"support",
"guide",
"tutorial",
"manual",
"faq",
"hint",
"query",
"unknown",
"unidentified",
"unspecified",
"uncertain",
"unsure",
"doubt",
"undetermined",
"missing",
"to be determined",
"mystery",
"question",
"question mark",
"?"
"?",
"quiz",
"inquiry",
"enquiry",
"ask",
"punctuation",
"symbol"
]
}
+4 -1
View File
@@ -20,6 +20,9 @@
"investigate",
"magnifying glass",
"lens",
"zoom"
"zoom",
"inspection",
"visual search",
"loupe"
]
}
+3 -1
View File
@@ -14,6 +14,8 @@
"member",
"client",
"participant",
"guest"
"guest",
"customer",
"username"
]
}
+4 -1
View File
@@ -19,6 +19,9 @@
"cross",
"times",
"ex",
"×"
"×",
"deny",
"decline",
"refuse"
]
}
+6
View File
@@ -190,6 +190,7 @@
"$group:code",
"$group:cog",
"$group:currency",
"$group:dashed",
"$group:digit",
"$group:direction-down",
"$group:direction-down-left",
@@ -200,11 +201,16 @@
"$group:direction-up-left",
"$group:direction-up-right",
"$group:dot",
"$group:emoticon",
"$group:enter",
"$group:exclamation-mark",
"$group:exit",
"$group:graph",
"$group:heart",
"$group:key",
"$group:layout-resize",
"$group:letter",
"$group:line",
"$group:lock",
"$group:minus",
"$group:navigation-first",
+3 -1
View File
@@ -24,7 +24,9 @@
"code",
"glob pattern",
"wildcard",
"*"
"*",
"required",
"mandatory"
],
"categories": [
"text",
+31
View File
@@ -0,0 +1,31 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"KesleyDavid",
"karsa-mistmere"
],
"use-cases": [
"Marking interoperable Fediverse profile links in social clients",
"Representing a three-star typographic symbol in publishing tools",
"Separating article sections with a decorative typographic mark",
"Representing star patterns in astronomy apps"
],
"tags": [
"asterisk",
"fediverse",
"activitypub",
"symbol",
"typography",
"social",
"decentralized",
"federation",
"stars",
"three",
"ornament",
"punctuation",
"divider"
],
"categories": [
"text"
]
}
+21
View File
@@ -0,0 +1,21 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 2v8" />
<path d="m14.5 15 7 4" />
<path d="m14.5 19 7-4" />
<path d="M18 13v8" />
<path d="m2.5 15 7 4" />
<path d="m2.5 19 7-4" />
<path d="M6 13v8" />
<path d="m8.5 4 7 4" />
<path d="m8.5 8 7-4" />
</svg>

After

Width:  |  Height:  |  Size: 440 B

+4 -1
View File
@@ -10,7 +10,10 @@
"badge",
"rosette",
"prize",
"winner"
"winner",
"skill",
"skills",
"expertise"
],
"categories": [
"account",
+7 -1
View File
@@ -14,7 +14,13 @@
"use-cases": [],
"tags": [
"$extends:badge",
"$group:check"
"$group:check",
"premium",
"vip",
"exclusive",
"pro",
"guarantee",
"warranty"
],
"categories": [
"social"
@@ -15,5 +15,10 @@
"categories": [
"account",
"social"
],
"aliases": [
{
"name": "badge-alert"
}
]
}

Before

Width:  |  Height:  |  Size: 471 B

After

Width:  |  Height:  |  Size: 471 B

+5 -1
View File
@@ -7,7 +7,11 @@
"use-cases": [],
"tags": [
"$extends:badge",
"$group:percent"
"$group:percent",
"sell",
"selling",
"promotion",
"promo"
],
"categories": [
"finance",
+2 -2
View File
@@ -10,6 +10,6 @@
stroke-linejoin="round"
>
<path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<line x1="12" x2="12.01" y1="17" y2="17" />
<path d="M9 9.5a3 2.5 0 016 0c0 2-2 2-3 3.5" />
<path d="M12 17h.01" />
</svg>

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 459 B

+2 -1
View File
@@ -21,7 +21,8 @@
"emergency",
"aid",
"safety",
"patch"
"patch",
"patient"
],
"categories": [
"medical"
+2 -1
View File
@@ -13,7 +13,8 @@
"cash",
"funds",
"transaction",
"finance"
"finance",
"salary"
],
"categories": [
"finance"
@@ -12,5 +12,10 @@
],
"categories": [
"$extends:battery"
],
"aliases": [
{
"name": "battery-warning"
}
]
}
@@ -9,8 +9,8 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 17h.01" />
<path d="M10 7v6" />
<path d="M10 16h.01" />
<path d="M10 8v4" />
<path d="M14 6h2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2" />
<path d="M22 14v-4" />
<path d="M6 18H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2" />

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 393 B

+1
View File
@@ -7,6 +7,7 @@
"use-cases": [],
"tags": [
"$extends:book",
"$group:dashed",
"code",
"coding",
"version control",
@@ -15,5 +15,10 @@
],
"categories": [
"$extends:book"
],
"aliases": [
{
"name": "book-alert"
}
]
}

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 359 B

+4 -1
View File
@@ -6,7 +6,10 @@
],
"use-cases": [],
"tags": [
"$extends:book-open"
"$extends:book-open",
"docs",
"wiki",
"knowledge base"
],
"categories": [
"text",
+4 -1
View File
@@ -5,7 +5,10 @@
],
"use-cases": [],
"tags": [
"$extends:book"
"$extends:book",
"docs",
"wiki",
"knowledge base"
],
"categories": [
"text",
+4 -1
View File
@@ -24,7 +24,10 @@
"smart",
"deep learning",
"machine learning",
"computing"
"computing",
"skill",
"skills",
"expertise"
],
"categories": [
"medical",
-2
View File
@@ -20,8 +20,6 @@
"briefcase",
"portfolio",
"business",
"career",
"employment",
"professional"
],
"categories": [
+6 -1
View File
@@ -10,7 +10,12 @@
"work",
"bag",
"baggage",
"folder"
"folder",
"job",
"career",
"employment",
"hiring",
"experience"
],
"categories": [
"travel"
+2 -1
View File
@@ -7,7 +7,8 @@
"use-cases": [],
"tags": [
"count",
"calculating machine"
"calculating machine",
"budget"
],
"categories": [
"math",
+2 -1
View File
@@ -13,7 +13,8 @@
"singular",
"once",
"1",
"first"
"first",
"today"
],
"categories": [
"$extends:calendar"
+2 -1
View File
@@ -9,7 +9,8 @@
"$extends:calendar",
"$group:check",
"subscribe",
"schedule"
"schedule",
"today"
],
"categories": [
"$extends:calendar"
+3 -1
View File
@@ -6,7 +6,9 @@
],
"use-cases": [],
"tags": [
"$extends:calendar"
"$extends:calendar",
"week",
"weekly"
],
"categories": [
"$extends:calendar"
+3 -1
View File
@@ -8,7 +8,9 @@
"tags": [
"$extends:calendar",
"range",
"period"
"period",
"week",
"weekly"
],
"categories": [
"$extends:calendar"
-1
View File
@@ -20,7 +20,6 @@
"mineral",
"pentagon",
"multidimensional",
"metrics",
"performance",
"comparison",
"profile",
+6 -1
View File
@@ -1,7 +1,12 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"danielbayley"
"danielbayley",
"karsa-mistmere"
],
"use-cases": [
"Categorizing cheeses in grocery shopping apps",
"Marking cheese-based dishes on restaurant menus"
],
"tags": [
"swiss",
+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="M14 11a3 3 0 01-6 0 5 5 0 016 0" />
<path d="M14.292 2.436a1.55 1.55 0 011.463-.088l.278.13A10.33 10.33 0 0122 11v8a2 2 0 01-2 2h-1.75a.28.28 0 01-.265-.25 2 2 0 00-3.97 0 .28.28 0 01-.265.25H4a2 2 0 01-2-2v-.75a.28.28 0 01.25-.265 2 2 0 00-.046-3.975.21.21 0 01-.204-.214v-2.678a2 2 0 01.952-1.703l6.062-3.732a.3.3 0 01.27-.002A2.5 2.5 0 0013 3.5l-.002-.104a.3.3 0 01.122-.24z" />
<path d="M22 11h-8" />
<path d="M8 11H2" />
</svg>

After

Width:  |  Height:  |  Size: 651 B

@@ -6,7 +6,7 @@
"use-cases": [],
"tags": [
"$group:direction-down-left",
"outwards"
"$group:exit"
],
"categories": [
"arrows"
@@ -16,6 +16,11 @@
"name": "arrow-down-left-from-circle",
"deprecationReason": "alias.name",
"deprecated": true
},
{
"name": "circle-arrow-out-down-left",
"deprecated": true,
"deprecationReason": "alias.name"
}
]
}

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

@@ -6,7 +6,7 @@
"use-cases": [],
"tags": [
"$group:direction-down-right",
"outwards"
"$group:exit"
],
"categories": [
"arrows"
@@ -16,6 +16,11 @@
"name": "arrow-down-right-from-circle",
"deprecationReason": "alias.name",
"deprecated": true
},
{
"name": "circle-arrow-out-down-right",
"deprecated": true,
"deprecationReason": "alias.name"
}
]
}

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

@@ -6,7 +6,7 @@
"use-cases": [],
"tags": [
"$group:direction-up-left",
"outwards",
"$group:exit",
"keyboard",
"button",
"escape"
@@ -19,6 +19,11 @@
"name": "arrow-up-left-from-circle",
"deprecationReason": "alias.name",
"deprecated": true
},
{
"name": "circle-arrow-out-up-left",
"deprecated": true,
"deprecationReason": "alias.name"
}
]
}

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 296 B

@@ -6,7 +6,7 @@
"use-cases": [],
"tags": [
"$group:direction-up-right",
"outwards"
"$group:exit"
],
"categories": [
"arrows"
@@ -16,6 +16,11 @@
"name": "arrow-up-right-from-circle",
"deprecationReason": "alias.name",
"deprecated": true
},
{
"name": "circle-arrow-out-up-right",
"deprecated": true,
"deprecationReason": "alias.name"
}
]
}

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

+1
View File
@@ -6,6 +6,7 @@
],
"use-cases": [],
"tags": [
"$group:dashed",
"pending",
"dot",
"progress",
+1
View File
@@ -5,6 +5,7 @@
],
"use-cases": [],
"tags": [
"$group:dashed",
"pending",
"progress",
"issue",
@@ -16,6 +16,9 @@
"name": "alert-circle",
"deprecationReason": "alias.name",
"deprecated": true
},
{
"name": "circle-alert"
}
]
}

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

+23
View File
@@ -0,0 +1,23 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"n2duc"
],
"use-cases": [
"Indicating a submission or payment that is still being verified",
"Showing a deployment, upload, or backup that is finishing up",
"Marking a task as partially completed or awaiting final approval",
"Displaying a step in a progress tracker that is in progress"
],
"tags": [
"$group:check",
"pending",
"progress",
"processing",
"verifying",
"loading"
],
"categories": [
"notifications"
]
}
+18
View File
@@ -0,0 +1,18 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 2a10 10 0 017.38 16.75" />
<path d="m16 9-5.5 5.5L8 12" />
<path d="M2.5 8.875a10 10 0 00-.5 3" />
<path d="M2.83 16a10 10 0 002.43 3.4" />
<path d="M4.636 5.235a10 10 0 01.891-.857" />
<path d="M8.644 21.42a10 10 0 007.631-.38" />
</svg>

After

Width:  |  Height:  |  Size: 465 B

+1 -1
View File
@@ -10,6 +10,6 @@
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10" />
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<path d="M9 9.5a3 2.5 0 016 0c0 2-2 2-3 3.5" />
<path d="M12 17h.01" />
</svg>

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 320 B

+3 -1
View File
@@ -10,7 +10,9 @@
"$extends:clipboard",
"$group:check",
"copied",
"pasted"
"pasted",
"result",
"checklist"
],
"categories": [
"$extends:clipboard"
+2 -1
View File
@@ -8,7 +8,8 @@
"use-cases": [],
"tags": [
"$extends:clipboard",
"tasks"
"tasks",
"checklist"
],
"categories": [
"$extends:clipboard"
@@ -13,5 +13,10 @@
],
"categories": [
"$extends:clock"
],
"aliases": [
{
"name": "clock-alert"
}
]
}

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

+3 -1
View File
@@ -8,7 +8,9 @@
],
"use-cases": [],
"tags": [
"import"
"import",
"install",
"installation"
],
"categories": [
"arrows",
@@ -19,5 +19,10 @@
"development",
"notifications",
"weather"
],
"aliases": [
{
"name": "cloud-alert"
}
]
}

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 331 B

+4 -1
View File
@@ -9,7 +9,10 @@
"use-cases": [],
"tags": [
"$extends:cloud",
"bolt"
"bolt",
"thunder",
"thunderstorm",
"thunderbolt"
],
"categories": [
"$extends:cloud"
+3 -1
View File
@@ -9,7 +9,9 @@
],
"use-cases": [],
"tags": [
"file"
"file",
"deploy",
"deployment"
],
"categories": [
"arrows",
+3 -1
View File
@@ -10,7 +10,9 @@
"bank",
"purchase",
"payment",
"cc"
"cc",
"cashier",
"merchant"
],
"categories": [
"account",
+5 -1
View File
@@ -16,7 +16,11 @@
"ruler",
"winner",
"favorite",
"favourite"
"favourite",
"premium",
"vip",
"exclusive",
"pro"
],
"categories": [
"gaming"
+2 -1
View File
@@ -12,7 +12,8 @@
"egress",
"gate",
"gateway",
"emergency exit"
"emergency exit",
"quit"
],
"categories": [
"home",
+3 -1
View File
@@ -10,7 +10,9 @@
"import",
"export",
"save",
"pull"
"pull",
"install",
"installation"
],
"categories": [
"arrows",

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