Compare commits

...
121 Commits
Author SHA1 Message Date
Jakob Guddas 13aea2d3ac Update icons/barn.svg 2024-03-21 22:40:25 +01:00
Jakob Guddas bd7ad68321 Update icons/barn.svg 2024-03-21 22:39:53 +01:00
Jakob Guddas b708d7d761 Update icons/barn.json 2024-03-21 22:36:48 +01:00
Jakob Guddas 2cdea04562 Update icons/barn.svg 2024-03-21 22:36:33 +01:00
Jakob Guddas cde043e2fc Merge branch 'main' into studio/barn 2024-03-21 22:33:11 +01:00
Jakob Guddas 912c81a8d8 chore: pull barn icon from lab branch 2024-03-21 22:28:22 +01:00
Jakob Guddas 58319dd447 fix(icons): added rounding to bug-play icon (#1990)
* Updated icons/bug-play.svg

* Updated icons/bug-play.json
2024-03-21 12:08:42 +01:00
KarsaandKarsa cf89b8eeac fix(icons/cpu): add guideline compliant rounding to CPU center (#1981)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-18 18:43:05 +01:00
Karsa a8c6add82b feat(icons): add worm icon 2024-03-14 13:51:17 +01:00
Karsa d000e4904d Update 02_bug_report.yml
Fix newly arisen syntax issue
2024-03-14 09:21:36 +01:00
Jakob GuddasandKarsa c99d6cbf4a fix(icons): optimized chef-hat icon (#1974)
* Updated icons/chef-hat.svg

* Updated icons/chef-hat.json

* Updated icons/chef-hat.svg

* Updated icons/chef-hat.svg

* Update icons/chef-hat.svg

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-03-14 08:41:01 +01:00
Jakob Guddas 0b1fb8ff1f feat(icons): added beer-off icon (#1971)
* Added icons/beer-off.svg

* Added icons/beer-off.json
2024-03-13 17:10:03 +01:00
KarsaandKarsa dcde43e97e fix(packages/lucide): exports aliases from lucide package (#1976)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-13 17:09:39 +01:00
KarsaandKarsa 96da23cc88 feat(icons): added hospital (#1952)
* feat(icons): added hospital

* chore(icons): add some extra icons

* chore(icons): add contributors

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-11 15:00:43 +01:00
KarsaandKarsa 78182c3573 fix(icons): updates crown to look more Lucide-y (#1947)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-11 14:59:06 +01:00
Eric Fennis 02f8f5a1c1 Update sandpack (#1968) 2024-03-11 14:21:03 +01:00
Jakob Guddas 16ee591f49 fix(icons): optimized hotel icon (#1951)
* Updated icons/hotel.svg

* Updated icons/hotel.json
2024-03-09 15:21:39 +01:00
Han Yeong-woo 5378156833 fix(lucide-solid): use jsx for exports too (#1970) 2024-03-09 14:11:25 +01:00
KarsaandKarsa 7b76078792 feat(icons): added ham icon (#1949)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-09 10:42:01 +01:00
KarsaandKarsa e2af1af4f9 fix(packages/lucide-solid): use jsx extension for solid build (#1964)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-09 10:41:06 +01:00
Jakob Guddas c9513d0bf4 Update 02_bug_report.yml (#1967) 2024-03-09 10:40:22 +01:00
KarsaandKarsa 6fbd5ee06a chore(icons): update icon names to match naming guidelines no. 7 to 9 (#1906)
* Update icon names to match naming guidelines no. 7 to 9
Update and extend rename icon helper script.

* Ran prettier

* Refactor rename scripts so that simplegit import doesn't cause other helper script usages to crash.

* Revert renaming key-square

* Revert renaming message-circle|square

* Fix square-dashed-kanban

* Optimize circle power

* pnpm rename square-dashed-bottom-scissors square-bottom-dashed-scissors

* Fix linting

* Fix file name linting issues via cspell configuration

* Rename unlock => lock-open

* Rename (square|circle)-check-2 => (square|circle)-check-small

* pnpm rename code-2 code-xml
pnpm rename contact-2 contact-round

* rename test-tube-2 test-tube-diagonal
rename mic-2 mic-vocal
rename loader-2 loader-circle
rename test-tube-2 test-tube-diagonal
rename school-2 university

* fix icons linting

* rename ice-cream => ice-cream-cone
rename ice-cream-2 => ice-cream-bowl
rename laptop-2 => laptop-abstract

* renamePattern "^(square|circle)-arrow-([a-z-]+)-from$" "\\1-arrow-out-\\2"

* rename wand-2 => wand-sparkles

* Update university.json tags.

* fix(icons): renamePattern '^(.+)-abstract$' '\1-minimal' --add-alias=false
feat(scripts): added yargs option parsing to renamePattern

* fix(packages): Remove protractor and puppeteer from lucide-angular, they are no longer in use but cause pnpm install to fail

* Lint fix, this is starting to get ridiculous.

* fix(packages): fix lucide-angular karma config.

* chore(icons): renamePattern '^(square|circle)-check$' '\1-check-big'
chore(icons): renamePattern '^(square|circle)-check-small$' '\1-check'

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-08 16:55:46 +01:00
Karsa d8773827fb hotfix(icons): remove circle-ellipsis alias from circle-ellipsis (#1961) 2024-03-08 16:46:56 +01:00
Daniel BayleyandEric Fennis bc1843f767 chore(icons): sort out more/ellipsis… icons/metadata (#1459)
* Add `more-horizontal-rectangle` icon

* Refine `circle-ellipsis` icon

* Rename `circle-ellipsis` to `more-circle`

* Improve `more` icons metadata

* Revert "Refine `circle-ellipsis` icon"

This reverts commit 973db1e140.

* Revert "Add `more-horizontal-rectangle` icon"

This reverts commit 3960c6ee0c.

* Rename `more-circle` to `more-horizontal-circle`

* Rename `form-input` to `more-horizontal-rectangle`

* Improve metadata

* Rename `more-horizontal-circle` to `ellipsis-circle`

* Rename `more-horizontal-rectangle` to `ellipsis-rectangle`

* Rename `more-horizontal` to `ellipsis`

* Rename `more-vertical` to `ellipsis-vertical`

* Fix lint issues

* Rename vertical ellipsis

* formatting

* Rename circle-ellipsis

* Rename rectangle ellipsis

* Revert "Rename vertical ellipsis"

This reverts commit acb80b75f8.

* Add EOFs

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-08 15:32:35 +01:00
KarsaandKarsa 07aefe3b88 feat(icons): add briefcase-medical & briefcase-business (#1954)
* feat(icons): add briefcase-medical & briefcase-business

* chore(icons): add extra tag to briefcase-business.json

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-03-08 15:28:45 +01:00
Eric Fennis 76d449a974 Aliases redirect on site (#1959)
* test aliases

* test

* Add redirect routes

* Formatting
2024-03-08 15:20:15 +01:00
Karsa dd39fa328c Update cannabis.json (#1946) 2024-03-07 10:40:20 +01:00
Bernardo FerrariandKarsa 0cf568c38b fix(icons): play icon uncentered (#1834)
* Fix play.svg

* Update play.svg

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-03-07 08:21:30 +01:00
Jakob GuddasandEric Fennis a8b8dfc58e fix(icons): optimized and closed gaps in file-pie-chart icon (#1939)
* Updated icons/file-pie-chart.svg

* Updated icons/file-pie-chart.json

* Updated icons/file-pie-chart.svg

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 22:16:52 +01:00
Jakob GuddasandEric Fennis 41dde6b574 fix(icons): added round corner to file-volume icon (#1940)
* Updated icons/file-volume.svg

* Updated icons/file-volume.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 22:16:47 +01:00
Jakob GuddasandEric Fennis ae35ca256c fix(icons): added round corner to file-search icon (#1941)
* Updated icons/file-search.svg

* Updated icons/file-search.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 22:16:41 +01:00
Eric Fennis 38142f24a5 Update metadata (#1943) 2024-03-06 22:16:23 +01:00
Eric Fennis b16f70993a workflow: Update stale workflow 2024-03-06 21:39:39 +01:00
Eric FennisandRohan ad1accb2e3 refactor: Adds repo shared package @lucide/shared (#1904)
* Fixed import of toKebabCase helper function

* Added utils package

* utils

* Make utils package work in build

* Add lucide-shared

* Transpile solid with esbuild

* Fix resolve modules

* Cleanup

* Format files

* Fix properties plugins function

* Fix properties plugins in lucide package

* Revert remove resolve plugin and cleanup

* Update snapshots

* Revert icon changes

---------

Co-authored-by: Rohan <rohancrrm@gmail.com>
2024-03-06 21:03:12 +01:00
Jakob GuddasandEric Fennis d255c6ac4e fix: readded gap between x-ray preview comment icons. (#1915)
* fix: readded gap between x-ray preview comment icons.

* feat: keep size 400px

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 21:00:26 +01:00
Jakob GuddasandEric Fennis d67ef7b0ca feat(icons): add cannabis icon (#1901)
* Added icons/cannabis.svg

* Added icons/cannabis.json

* Updated icons/cannabis.svg

* Updated icons/cannabis.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 20:59:25 +01:00
198ccb8430 fix(icons): increased rounding of zap icons (#1936)
* fix(icons): add more Lucide-ish rounding to zap icons

* chore(icons): optimise zap-off manually

* chore(icons): fix linting

* Update icons/zap-off.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update icons/zap.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
Co-authored-by: Jakob Guddas <github@jguddas.de>
2024-03-06 20:58:17 +01:00
Eric Fennis ce1b5bdefa style: Fix formatting 2024-03-06 20:54:55 +01:00
45aa928369 Optimise/refine radio[-tower]/add airdrop/Apple/mac/iOS/app related icons (#1514)
* Add `airdrop` icon

* Optimise `radio` icon

* Refine `radio-tower` icon

* Add `airplay` icon

* Add `dock` (desktop) icon

* Improve metadata

* Optimise `podcast` icon

* Add `app-window-mac` icon

* Update icons/radio.svg

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

* Update icons/radio-tower.svg

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

* Update icons/podcast.svg

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

* Update icons/radio-tower.svg

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

* Update icons/radio.svg

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

* Revert "Add `airdrop` icon"

This reverts commit af60a17784.

* Revert radio and radio-tower changes

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2024-03-06 20:29:21 +01:00
Daniel BayleyandEric Fennis 93dc356fa1 Add rotate/resize element icons (#1516)
* Add `proportions` icon

* Improve metadata

* Add `rotate-cw-square` icon

* Add `rotate-ccw-square` icon

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-06 20:13:53 +01:00
Jakob GuddasandEric Fennis a0aa132682 Updated icons/keyboard.svg (#1930)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-03-01 11:40:56 +01:00
KarsaandKarsa 1a4dd64862 feat(icons): redesign brain and related icons (#1902)
* Update brain and related icons

* Update central line and increase in size

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-28 16:53:48 +01:00
Jakob GuddasandEric Fennis 3481f70ad7 feat: added 16x16 sub grid to svg preview component (#1914)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-28 16:52:12 +01:00
Daniel Bayley 024f21e896 Add bot-message-square (chatbot) icon (#1709) 2024-02-28 16:35:25 +01:00
Jakob Guddas c30ccd472e fix(icons): update goal icon (#1924)
* Updated icons/goal.svg

* Updated icons/goal.json
2024-02-27 10:17:59 +01:00
Wojciech Maj 28ec03ebc8 Add support for react-native-svg ^15.0.0 (#1929) 2024-02-27 10:13:42 +01:00
Eric Fennis ab3a31367a feat(site): adds virtual scrolling to icons grid and categories (#1911)
* Add virtual scrolling icons page

* improve scrolling

* Small fixes in the routing

* Cleanup

* Fix routing issue

* Remove log

* Cleanup

* Cleanup

* Show search results in sidebar

* Improve alphabetical list

* Add whitespace

* Extract logic into a composable and fix icon selection

* Formatting
2024-02-27 10:09:52 +01:00
148bae88d8 feat(icons): added globe-lock icon (#1587)
* Added globe-lock icon

* feat(icons): Added globe-lock, renamed globe-2 to earth, and added earth-lock

* feat(icons): Added globe as a tag to earth

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-26 09:53:04 +01:00
Chaoying ca4a38ba85 Fix import statements (#1922) 2024-02-25 19:04:23 +01:00
KarsaandKarsa f297765a13 Update shield to have better centre of gravity (#1905)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-25 11:28:31 +01:00
KarsaandKarsa 4657ccbfff fix(icons/concierge-bell): Adds missing rounding from bottom part (#1923)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-25 10:27:22 +01:00
Jakob GuddasandEric Fennis db222d4591 Optimized and fixed alignment issues in package-open icon (#1648)
* Optimized and fixed alignment issues in `package-open` icon

* Update icons/package-open.svg

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-24 18:31:04 +01:00
Jakob Guddas bafad1c625 Add image-up icon (#1909)
* Added icons/image-up.svg

* Added icons/image-up.json
2024-02-23 11:25:17 +01:00
Jakob Guddas 7f1e95c6e7 Update image-down icon (#1910)
* Updated icons/image-down.svg

* Updated icons/image-down.json
2024-02-23 11:20:42 +01:00
ca7a87112c Fixed gap issues in flower icon (#1650)
* Fixed gap issues in `flower` icon

* Update flower.json

* Update flower.json

* Update icons/flower.svg

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

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2024-02-23 09:58:13 +01:00
Kyle Angelo GalendezandKarsa d542da0a1c Add table-cells-merge, table-cells-split, table-rows-split, and table-columns-split icons (#1856)
* Add split-table icon

* Add split-table.json

* Add split-rows icon

* Add split-rows.json

* Add merge-rows icon

* Add merge-rows.json

* Update icons/merge-rows.svg

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

* Update split-rows.svg

* Update split-table.svg

* Fix by add padding to split-table icon

- Accidentally exported the whole icon from Inkscape, but not the entire page, which creates no padding

* Update split-table icon

- Add 1px to the row borders down below

* Rename split-table.svg to table-row-split.svg

* Update and rename split-table.json to table-row-split.json

* Rename merge-rows to table-cells-merge

* Rename split-rows to table-cells-split

* Rename table-row-split to table-split

* Add `table-columns-split` icon

* Add table-columns-split.json

* Delete table-split icon and json

* Add `table-rows-split` json and icon

* Update icons/table-cells-split.json

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

* Update icons/table-rows-split.json

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

* Update icons/table-cells-merge.json

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

* Update icons/table-columns-split.json

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-02-21 22:47:20 +01:00
KarsaandKarsa 6fa51d2a22 Optimise hop (#1897)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-20 15:32:43 +01:00
KarsaandKarsa ca53b06af2 Adds pickaxe icon (#1890)
* Adds pickaxe icon

* Replace missing icon, haha 😅

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-19 09:01:32 +01:00
KarsaandKarsa b5dc96d2c2 Optimise hammer (#1893)
* Optimize and fix guideline violation in hammer

* Further adjustments to pixel perfection

* Nudge things around a bit more

* Elongate front part of head

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-19 09:00:51 +01:00
Karsa 5e5fe0085f Update tractor.svg 2024-02-19 08:12:47 +01:00
KarsaandKarsa 0c2a8d774f Fix anvil rounding (#1895)
* Fix anvil rounding

* Add rounding to spike

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-19 08:11:29 +01:00
Jakob Guddas 804906dcd8 Update tractor icon (#1894)
* Updated icons/tractor.svg

* Updated icons/tractor.json
2024-02-19 08:11:24 +01:00
KarsaandKarsa d575743d3a Fix siren rounding (#1896)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-19 08:11:15 +01:00
KarsaandKarsa 42c1faed75 Adds telescope icon (#1889)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-15 13:34:42 +01:00
42b494f853 Updated naming guidelines with element order and modifier naming scheme (#1874)
* Update icon-design-guide.md

* Update docs/guide/design/icon-design-guide.md

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-12 19:04:03 +01:00
KarsaandKarsa 9bf8a653a3 Ran prettier on updateContributors.mjs (#1887)
Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-12 18:59:06 +01:00
Jakob Guddas 01cff578e5 Update file-output icon (#1879)
* Updated icons/file-output.svg

* Updated icons/file-output.json
2024-02-12 16:18:48 +01:00
Jakob Guddas a0b1305258 feat: folder output (#1619) 2024-02-12 16:18:39 +01:00
KarsaandKarsa 0cfdfa2181 Adds images and (updates file-image to match) (#1852)
* Adds images and updates file-image to match

* Improve pixel perfection

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-12 16:17:22 +01:00
Jakob GuddasandEric Fennis a2e8ea32d2 feat: folder symlink (#1618)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-12 16:16:03 +01:00
Jakob Guddas 8a7e6ba343 Update file-symlink icon (#1878)
* Updated icons/file-symlink.svg

* Updated icons/file-symlink.json
2024-02-12 16:15:05 +01:00
Jakob GuddasandKarsa 7a9233f4a7 Update clover icon (#1883)
* Updated icons/clover.svg

* Updated icons/clover.json

* Updated icons/clover.svg

* Update icons/clover.svg

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-02-12 16:14:07 +01:00
Jakob GuddasandKarsa 71aef25812 Update circle-dashed icon (#1884)
* Updated icons/circle-dashed.svg

* Updated icons/circle-dashed.json

* Update icons/circle-dashed.svg

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-02-12 16:13:45 +01:00
Jakob Guddas 33189a81ac fix: updateContributors adds trailing line to icon.json (#1885) 2024-02-12 14:33:04 +01:00
e3923f87c2 Add radical icon (square root) (#1847)
* Add `square-root`icon

* Update square-root.svg

* Fix square icon SVG

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Rename `square-root` `radical`

* Rename radical-square.json to square-radical.json

* Rename radical-square.svg to square-radical.svg

* Update radical.json

* Match activity height

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

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2024-02-11 23:42:03 +01:00
Jakob Guddas 08c040a57d Update anchor icon (#1875)
* Updated icons/anchor.svg

* Updated icons/anchor.json
2024-02-11 18:07:39 +01:00
Jakob Guddas 981c3309ce Rounded corners of graduation-cap icon (#1870)
* Updated icons/graduation-cap.svg

* Updated icons/graduation-cap.json

* Updated icons/graduation-cap.svg

* Updated icons/graduation-cap.json
2024-02-11 17:58:43 +01:00
Jakob Guddas 2e0af66d8a Update school icon (#1872)
* Updated icons/school.svg

* Updated icons/school.json
2024-02-11 17:04:35 +01:00
Jakob Guddas a789c91213 Optimized shopping-basket icon (#1871)
* Updated icons/shopping-basket.svg

* Updated icons/shopping-basket.json

* Updated icons/shopping-basket.svg

* Updated icons/shopping-basket.json
2024-02-11 17:02:13 +01:00
Jakob Guddas 91c95600f3 Update rss icon metadata (#1873)
* Updated icons/rss.svg

* Updated icons/rss.json
2024-02-11 17:01:50 +01:00
Jakob GuddasandKarsa 99acf4102c Update wifi icon (#1877)
* Updated icons/wifi.svg

* Updated icons/wifi.json

* Updated icons/wifi.svg

* Updated icons/wifi.json

* Update wifi-off.svg

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-02-11 17:01:19 +01:00
Jakob Guddas 86f2dc12f4 Update arrow-big-down-dash icon (#1876)
* Updated icons/arrow-big-down-dash.svg

* Updated icons/arrow-big-down-dash.json
2024-02-11 16:59:54 +01:00
DefaultLPandEric Fennis b9fdde2d09 Add caption icons (#1799)
* Add caption icons

* Add subtitle category

* Changed corner radius to 2px

* Fixed metadata for caption icons

* Took suggestions to heart

* Removed trailing spaces

* Fixed captions-off violations

* Fixed name and added aliases

* Removed subtitles svg and json

* Removed alias from captions-off

* format

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-05 19:34:34 +01:00
KarsaandRigó József Karsa 5c494962e1 Various contributor fixes (#1844)
* Various manual contributor fixes

* Remove myself from a few dozen more icons I took practically no part in.

* Remove danielbayley from some icons as per https://github.com/lucide-icons/lucide/pull/1844

---------

Co-authored-by: Rigó József Karsa <karsa@sztaki.hu>
2024-02-05 19:11:34 +01:00
KarsaandKarsa 772c5be034 Fixes scaling, tag and tags to have the necessary rounding. (#1850)
* Fixes scaling, tag and tags to have the necessary rounding.

* Update tags.svg

* Update tag.svg

---------

Co-authored-by: Karsa <karsa@sztaki.hu>
2024-02-05 15:08:13 +01:00
ee3483eb1b Adds handshake icon (#1835)
* Adds handshake icon

* update handshake icon

* Update handshake.svg

* Update icons/handshake.json

Co-authored-by: Jakob Guddas <github@jguddas.de>

---------

Co-authored-by: Rigó József Karsa <karsa@sztaki.hu>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Jakob Guddas <github@jguddas.de>
2024-02-01 16:37:10 +01:00
CokaKoalaandEric Fennis 9182c51962 feat: Adds Svelte 5 support (#1748)
* adds svelte 5 support

* Update package.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-02-01 16:36:27 +01:00
Han Yeong-woo eb035fe370 Improve formatting (#1814)
* Ignore linting for examples in docs

* Formatting JSX single attribute per line

* Separte `format` and `lint:format` in package.json

* Bump prettier version

* Run format
2024-02-01 14:38:21 +01:00
KarsaandRigó József Karsa b96e6acd2e Fix plus/minus sign size in shield-plus/shield-minus (#1840)
* Update shield-plus to match other plus icons

* Update shield-minus to match other minus icons

---------

Co-authored-by: Rigó József Karsa <karsa@sztaki.hu>
2024-01-31 22:53:23 +01:00
Daniel Bayley 7b62649c39 Add smaller dots fill fix to VS Code snippets (#1837) 2024-01-31 09:02:07 +01:00
Daniel Bayley 10aff6cf7b Fix bolt missing metadata (#1836) 2024-01-31 08:42:01 +01:00
Jordan Long cfa8924025 Update truck icon to match ambulance (#1838) 2024-01-31 08:36:17 +01:00
Eric Fennis 713e9b8a09 Add clipboard-plus and clipboard-minus icons (#1812)
* Add clipboard icons

* Switch to same plus minus as file icons

* update contributors

* center plus and minus paths
2024-01-31 08:35:00 +01:00
Eric Fennis 8ab6f80e4f Add headset icon (#1780)
* Add headset icon

* Fix lint errors

* Revert headset change
2024-01-30 10:08:59 +01:00
a5221c236a Add story icon (#1820)
* Add story icon

* Split single path into multiple elements

* Refine icons/story.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update contributors to icons/story.json

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Change "story" icon name to "circle-fading-plus" and add to shapes category

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Jakob Guddas <github@jguddas.de>
2024-01-30 09:30:44 +01:00
Jordan LongandJakob Guddas cdd32b5294 Add ambulance icon (#1819)
* Add ambulance icon

* Remove extra attributes and connect path under wheels

* Lift roof and "+" to adhere to 2px gap rule for icons/ambulance.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Increase cab height of ambulance

* Add contributors from truck icon

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
2024-01-29 19:50:04 +01:00
54c8d4078d fix: Add the license banner inside of the script tag instead of an HTML comment (#1811)
* add banner inside of the script tag instead

* renamed script

* Update packages/lucide-svelte/scripts/license.mjs

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Update packages/lucide-svelte/scripts/appendLicense.mjs

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

* renamed file

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-29 19:48:14 +01:00
Daniel BayleyandEric Fennis 3302870983 Refine helping-hand/add hand-* icons (#1328)
* Refine `helping-hand` icon

* Add `hand-platter` icon

* Add `hand-coins` (savings) icon

* Add `hand-heart` icon

* Fix/optimise `helping-hand` icon

* Fix/optimise `hand-coins` icon

* Fix/optimise `hand-heart` icon

* Rename `helping-hand` to `hand-helping`

* Fix/optimise `hand-platter` icon

* Add `thumbs-up-down` icon

* Improve `thumbs-up`/`down` icons metadata

* Improve metadata

* Delete thumbs-up-down icons

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-26 10:10:19 +01:00
KarsaandEric Fennis 0f25ee86a0 Fix fills in smaller dots (#1436)
* Fixes palette

* Fixing fill on circles

* Fixing fills

* Revert tractor fill

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-26 09:58:05 +01:00
Jakob GuddasandEric Fennis 28686b5bd5 feat: added webhook-off icon (#1566)
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-25 08:54:18 +01:00
Eric Fennis 8cc143915c Update JSdoc lucide svelte (#1826) 2024-01-25 08:23:34 +01:00
Daniel BayleyandEric Fennis 06372db723 Optimise/add missing calendar[-*] icons/improve metadata (#1377)
* Optimise `calendar`[`-*`] icons

* Add `calendar-plus` variant

* Add `calendar-minus` variant

* Add `calendar-slash` icon

* Improve `calendar`[`-*`] icons metadata

* Add `calendar-fold` icon

* Remove calendar-slash

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-22 20:02:19 +01:00
Eric Fennis 114fb08556 fix icon preview comment (#1823) 2024-01-21 19:45:21 +01:00
Eric Fennis 3bad7f6ced fix site, downgrade sandpack-vue3 2024-01-21 18:20:52 +01:00
Daniel BayleyandEric Fennis e450afe408 Add ticket-* icons/improve metadata (#1312)
* Add `ticket-x` (cancel/refund) icon

* Improve `ticket` metadata

* Add `ticket-slash` (marked/redeemed) icon

* Terminal Add `ticket-check` (purchased) icon

* Add `ticket-plus` (book) icon

* Add `ticket-minus` (remove from basket) icon

* Add `ticket-percent` (discount) icon

* Add `ticket-text` (T&Cs) icon

* Remove ticket text

* Fix duplicate item

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-21 18:04:03 +01:00
Daniel Bayley 6fcfc820ca Add text-search icon (#1807) 2024-01-21 17:22:12 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 55f264bea6 Bump vite from 5.0.10 to 5.0.12 (#1817)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.10 to 5.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-21 16:46:12 +01:00
Han Yeong-wooandEric Fennis 675158df16 Cleanup tools (#1756)
* Use prettier own instead of eslint plugin

* Extend prettier config angular eslint

* Upgrade root prettier to 3

* Fix css syntax errors

* Change eslint ignore to prettier ignore

* Ignore formatting for outputs

* Fix lint-staged error when edited multiple files

* Bump pnpm version

* Remove unnecessary pnpm config

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-18 12:36:48 +01:00
Gustavo Bonfim 042393a931 docs(react-native): fix generic icon import (#1813) 2024-01-18 12:27:02 +01:00
Daniel BayleyandEric Fennis 551635003c Optimise/add receipt[-*] icons (#1401)
* Optimise `receipt` icon

* Add `receipt-text` icon

* Improve `receipt` metadata

* Add `receipt-pound-sterling` icon

* Add `receipt-euro` icon

* Add `receipt-swiss-franc` icon

* Add `receipt-japanese-yen` icon

* Add `receipt-indian-rupee` icon

* Add `receipt-russian-ruble` icon

* Add `receipt-cent` icon

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-17 20:06:56 +01:00
Eric Fennis 5c7119f6d1 Export all types lucide-react-native (#1809) 2024-01-17 14:28:14 +01:00
Daniel Bayley 7bfdb2f54a Fix missing metadata (#1808)
* Fix missing metadata

From #1280.

* Fix more missing metadata

From #1378.
2024-01-17 12:13:47 +01:00
Eric Fennis e3abcdbcc6 Remove v-memo 2024-01-17 11:17:09 +01:00
Daniel BayleyandEric Fennis 62d350140e Add missing arrow-*-from-square/optimise external-link icon/s (#1383)
* Add `arrow-up-right-from-square` (share) icon

* Add `arrow-up-left-from-square` icon

* Add `arrow-down-left-from-square` icon

* Add `arrow-down-right-from-square` icon

* Optimise `external-link` icon

* Improve `external-link` metadata

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-16 16:44:44 +01:00
ad90ee7582 Refine file/sticky-note[-*] icons/add file-dot (dotfile) icon (#1378)
* Refine `file`[`-*`] icons

* Refine `sticker` icon fold

* Refine `sticky-note` icon

* Improve `sticky-note` metadata

* Add `sticky-note-text` icon

* Add `file-dot` icon

* Update icons/file-badge-2.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Add `file-sliders-big` (config) icon

* Add `file-sliders` (config) icon

* Improve `folder-dot` metadata

* Remove icons

* Remove sticky note text

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Jakob Guddas <github@jguddas.de>
2024-01-16 16:41:08 +01:00
Eric Fennis b0e825cb57 Site improvements and update site dependencies (#1805)
* try to speed up build times

* Update deps

* Update site deps and fix search issue

* Small improvements

* fix imports

* Remove unused var
2024-01-16 16:22:09 +01:00
KarsaandRigó József Karsa d4cbe899fb Remove aliasesSupport flag from rollup.config.mjs (#1794)
* Remove aliasesSupport flag from rollup.config.mjs and add always add aliases

* Update rollup.config.mjs

* Update rollup.config.mjs

* Update rollup.config.mjs

* Update rollup.config.mjs

---------

Co-authored-by: Rigó József Karsa <karsa@sztaki.hu>
2024-01-16 16:21:57 +01:00
be3ccc8ece Add/optimise swatch-book/aperture/blend/eclipse (dark/light) mode/paint-roller icons and improve palette/brush metadata (#1280)
* Add `swatch-book` icon

* Improve `palette`/`brush` icons metadata

* Update icons/swatch-book.svg

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

* Add `color-wheel` icon

* Improve `palette`/`swatch-book` icons metadata

* Update icons/color-wheel.svg

Co-authored-by: Jakob Guddas <github@jguddas.de>

* Add `paint-roller` icon

* Improve metadata

* Add `contrast` alternate icon

* Add `eclipse` (dark/light mode toggle) icon

* Add `blend` icon

* Refine `color-wheel` icon

* Optimise `aperture` icon

* Add `aperture` variant

* Drop `color-wheel` icon

* Refine `paint-roller` icon

* Fix `aperture-2` optimisation

* Update icons/aperture.svg

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

* Fix `aperture` variant optimisation

* Rename `contrast-2` to `circle-line-vertical`

* Remove aperture-2 and circle-line-vertical

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2024-01-16 15:42:22 +01:00
Eric Fennis e56b09d400 Add cache header site assets (#1801) 2024-01-13 15:32:18 +01:00
Eric Fennis 7e936c8803 Update stale action 2024-01-13 10:10:43 +01:00
ocavueandKarsa c9ffa4033f Add list-collapse icon (#1790)
* Add `list-collapse` icon

* Update icons/list-collapse.json

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

---------

Co-authored-by: Karsa <contact@karsa.org>
2024-01-10 10:12:13 +01:00
1945 changed files with 19732 additions and 8739 deletions
+15
View File
@@ -0,0 +1,15 @@
# Custom words
fullscreen
gamepad
gantt
kanban
pilcrow
squircle
strikethrough
touchpad
ungroup
# Brands
codepen
codesandbox
dribbble
+1 -2
View File
@@ -6,6 +6,5 @@ tests
node_modules
.eslintrc.js
docs/images
docs/guide/basics/examples
docs/guide/advanced/examples
docs/**/examples/
packages/lucide-react/dynamicIconImports.js
+9 -15
View File
@@ -7,20 +7,12 @@ module.exports = {
node: true,
},
extends: ['airbnb-base', 'prettier'],
plugins: ['import', 'prettier', '@html-eslint'],
plugins: ['import', '@html-eslint'],
rules: {
'no-console': 'off',
'no-param-reassign': 'off',
'no-shadow': 'off',
'no-use-before-define': 'off',
'prettier/prettier': [
'error',
{
singleQuote: true,
trailingComma: 'all',
printWidth: 100
},
],
'import/no-extraneous-dependencies': [
'error',
{ devDependencies: ['**/*.test.js', '**/*.spec.js', './scripts/**'] },
@@ -46,17 +38,19 @@ module.exports = {
files: ['./icons/*.svg'],
parser: '@html-eslint/parser',
rules: {
'prettier/prettier': 'off',
'@html-eslint/require-doctype': 'off',
'@html-eslint/no-duplicate-attrs': 'error',
'@html-eslint/no-inline-styles': 'error',
'@html-eslint/require-attrs': [
'error',
...Object.entries(DEFAULT_ATTRS)
.map(([attr, value]) => ({ tag: 'svg', attr, value: String(value) }))
'error',
...Object.entries(DEFAULT_ATTRS).map(([attr, value]) => ({
tag: 'svg',
attr,
value: String(value),
})),
],
'@html-eslint/indent': ['error', 2],
"@html-eslint/no-multiple-empty-lines": ["error", { "max": 0 }],
'@html-eslint/no-multiple-empty-lines': ['error', { max: 0 }],
'@html-eslint/no-extra-spacing-attrs': [
'error',
{
@@ -73,7 +67,7 @@ module.exports = {
'@html-eslint/element-newline': 'error',
'@html-eslint/no-trailing-spaces': 'error',
'@html-eslint/quotes': 'error',
}
},
},
],
};
+10
View File
@@ -35,6 +35,16 @@ body:
placeholder: e.g. 0.289.1
validations:
required: true
- type: checkboxes
id: can-reproduce-in-latest-version
attributes:
label: Can you reproduce this in the latest version?
description: i.e. after running `npm install lucide-react@latest`
options:
- label: 'Yes'
- label: 'No'
validations:
required: false
- type: checkboxes
id: browsers
attributes:
+4 -4
View File
@@ -1,5 +1,5 @@
name: "Build and Test"
description: "Builds and test a package"
name: 'Build and Test'
description: 'Builds and test a package'
inputs:
name:
@@ -7,7 +7,7 @@ inputs:
required: true
runs:
using: "composite"
using: 'composite'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
@@ -18,7 +18,7 @@ runs:
name: Install pnpm
id: pnpm-install
with:
version: 7
version: 8
run_install: false
- name: Get pnpm store directory
+4 -4
View File
@@ -1,5 +1,5 @@
name: "Check icons"
description: "Cross-checks icon and category references in JSON descriptors"
name: 'Check icons'
description: 'Cross-checks icon and category references in JSON descriptors'
inputs:
name:
@@ -7,7 +7,7 @@ inputs:
required: true
runs:
using: "composite"
using: 'composite'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
@@ -18,7 +18,7 @@ runs:
name: Install pnpm
id: pnpm-install
with:
version: 7
version: 8
run_install: false
- name: Get pnpm store directory
+48 -48
View File
@@ -1,92 +1,92 @@
# For changed dependencies
📦 dependencies:
- changed-files:
- any-glob-to-any-file:
- pnpm-lock.yaml
- changed-files:
- any-glob-to-any-file:
- pnpm-lock.yaml
# For changes in documentation
📖 documentation:
- changed-files:
- any-glob-to-any-file:
- docs/*.md
- docs/**/*.md
- changed-files:
- any-glob-to-any-file:
- docs/*.md
- docs/**/*.md
# For changes in the site, but not markdown files
🌍 site:
- changed-files:
- any-glob-to-any-file:
- 'docs/**'
- changed-files:
- any-glob-to-any-file:
- 'docs/**'
# For changes in the metadata
🫧 metadata:
- changed-files:
- any-glob-to-any-file:
- 'icons/*.json'
- categories/*
- changed-files:
- any-glob-to-any-file:
- 'icons/*.json'
- categories/*
# For changes or added icons
🎨 icon:
- changed-files:
- any-glob-to-any-file:
- 'icons/*.svg'
- changed-files:
- any-glob-to-any-file:
- 'icons/*.svg'
# For changes in the lucide package
🧳 lucide package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide/*'
# For changes in the lucide React package
⚛️ react package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react/*'
# For changes in the lucide React Native package
⚛️ react native package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react-native/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react-native/*'
# For changes in the lucide vue packages
💎 vue package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-vue/*'
- 'packages/lucide-vue-next/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-vue/*'
- 'packages/lucide-vue-next/*'
# For changes in the lucide angular package
🅰️ angular package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-angular/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-angular/*'
# For changes in the lucide preact package
⚛️ preact package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-preact/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-preact/*'
# For changes in the lucide svelte package
🧣 svelte package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-svelte/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-svelte/*'
# For changes in the lucide solid package
🪝 solid package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-solid/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-solid/*'
# For changes in the lucide static package
🪨 static package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-static/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-static/*'
# For changes in the lucide flutter package
🏹 flutter package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-flutter/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-flutter/*'
+5 -3
View File
@@ -1,11 +1,13 @@
name: Close stale issues and PR
on:
schedule:
- cron: "45 1 * * *"
- cron: '45 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/stale@v9
with:
@@ -14,5 +16,5 @@ jobs:
close-pr-message: This PR was closed because it has been stalled for 5 days with no activity.
close-pr-label: 🧶 stale
days-before-stale: 30
days-before-close: 5
days-before-pr-close: -1
days-before-issue-stale: -1
days-before-close: -1
+3 -3
View File
@@ -1,6 +1,6 @@
name: "Pull Request Labeler"
name: 'Pull Request Labeler'
on:
- pull_request_target
- pull_request_target
jobs:
triage:
@@ -9,4 +9,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v5
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
- name: Create font in ./lucide-font
run: pnpm build:font
- name: "Upload to Artifacts"
- name: 'Upload to Artifacts'
uses: actions/upload-artifact@v3
with:
name: lucide-font
+14 -16
View File
@@ -41,17 +41,18 @@ jobs:
strategy:
fail-fast: false
matrix:
package: [
'lucide',
'lucide-react',
'lucide-react-native',
'lucide-vue',
'lucide-vue-next',
'lucide-angular',
'lucide-preact',
'lucide-solid',
'lucide-svelte',
]
package:
[
'lucide',
'lucide-react',
'lucide-react-native',
'lucide-vue',
'lucide-vue-next',
'lucide-angular',
'lucide-preact',
'lucide-solid',
'lucide-svelte',
]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
@@ -136,7 +137,7 @@ jobs:
- name: Create font in ./lucide-font
run: pnpm build:font
- name: "Upload to Artifacts"
- name: 'Upload to Artifacts'
uses: actions/upload-artifact@v3
with:
name: lucide-font
@@ -145,10 +146,7 @@ jobs:
post-release:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: [
pre-release,
lucide-font,
]
needs: [pre-release, lucide-font]
steps:
- uses: actions/checkout@v4
+19
View File
@@ -0,0 +1,19 @@
pnpm-lock.yaml
# docs examples
docs/**/examples/
# lucide-angular
packages/lucide-angular/.angular/cache
# lucide-static
packages/lucide-static/icons
packages/lucide-static/lib
packages/lucide-static/sprite.svg
packages/lucide-static/tags.json
packages/lucide-static/icon-nodes.json
packages/lucide-static/font
# lucide-svelte
packages/lucide-svelte/src/icons/*.svelte
packages/lucide-svelte/.svelte-kit
+1 -1
View File
@@ -12,4 +12,4 @@
"webRoot": "${workspaceFolder}"
}
]
}
}
+2 -9
View File
@@ -1,13 +1,6 @@
{
"cSpell.words": [
"devs",
"preact",
"Preact"
],
"cSpell.words": ["devs", "preact", "Preact"],
"eslint.enable": true,
"eslint.validate": [
"javascript",
"svg"
],
"eslint.validate": ["javascript", "svg"],
"svg.preview.background": "transparent"
}
+1 -1
View File
@@ -49,7 +49,7 @@
"circle",
"<circle"
],
"body": "<circle cx=\"${2:12}\" cy=\"${3:$2}\" r=\"${1|10,2,.5|}\" />"
"body": "<circle cx=\"${2:12}\" cy=\"${3:$2}\" r=\"${1|10,2,.5\" fill=\"currentColor|}\" />"
},
"Ellipse": {
"scope": "xml",
+3 -3
View File
@@ -72,8 +72,8 @@ pnpm install # Install dependencies, including the workspace packages
To distribute different packages we use PNPM workspaces. Before you start make sure you are familiar with this concept. The concept of working in workspaces is created by Yarn, they have a well written introduction: [yarn workspaces](https://classic.yarnpkg.com/lang/enhttps://lucide.dev/docs/workspaces).
The configured directory for workspaces is the [packages](./packages) directory, located in the root directory. There you will find all the current packages from lucide.
There are more workspaces defined, see [`pnpm-workspace.yaml`](./pnpm-workspace.yaml).
The configured directory for workspaces is the [packages](https://github.com/lucide-icons/lucide/tree/main/packages) directory, located in the root directory. There you will find all the current packages from lucide.
There are more workspaces defined, see [`pnpm-workspace.yaml`](https://github.com/lucide-icons/lucide/blob/main/pnpm-workspace.yaml).
> Note: One package is not managed by pnpm: **lucide-flutter**, this package is written in Dart and used pub for publishing.
@@ -153,7 +153,7 @@ lucide
### Docs
The lucide.dev website is using [vitepress](https://vitepress.dev/) to generate the static website. The markdown files are located in the docs directory.
The lucide.dev website is using [vitepress](https://vitepress.dev/) to generate the static website. The markdown files are located in the docs directory.
### Guides
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Accessibility",
"icon": "accessibility"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Accounts & access",
"icon": "user"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Animals",
"icon": "dog"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Arrows",
"icon": "arrow-left-right"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Brands",
"icon": "facebook"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Buildings",
"icon": "building"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Charts",
"icon": "pie-chart"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Communication",
"icon": "message-circle"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Connectivity",
"icon": "wifi"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Currency",
"icon": "dollar-sign"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Cursors",
"icon": "mouse-pointer-2"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Design",
"icon": "palette"
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Coding & development",
"icon": "code-2"
"icon": "code-xml"
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Devices",
"icon": "smartphone"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Emoji",
"icon": "smile"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "File icons",
"icon": "panels-top-left"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Food & beverage",
"icon": "coffee"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Furniture",
"icon": "rocking-chair"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Gaming",
"icon": "gamepad-2"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Home",
"icon": "home"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Layout",
"icon": "panels-top-left"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Mail",
"icon": "mail"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Maps",
"icon": "map"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Maths",
"icon": "divide"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Medical",
"icon": "heart"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Money",
"icon": "piggy-bank"
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Multimedia",
"icon": "play-circle"
}
"icon": "circle-play"
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Nature",
"icon": "sprout"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Navigation",
"icon": "compass"
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Notifications",
"icon": "alert-triangle"
}
"icon": "triangle-alert"
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "People",
"icon": "person-standing"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Photography",
"icon": "camera"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Science",
"icon": "flask-conical"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Seasons",
"icon": "leaf"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Security",
"icon": "shield"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Shapes",
"icon": "triangle"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Shopping",
"icon": "shopping-bag"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Social",
"icon": "thumbs-up"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Sports",
"icon": "type"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Sustainability",
"icon": "recycle"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Time & calendar",
"icon": "calendar"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Tools",
"icon": "hammer"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Transportation",
"icon": "train-front"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Travel",
"icon": "backpack"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Weather",
"icon": "cloud-sun"
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"dictionaries": ["en-us", "custom-words"],
"dictionaryDefinitions": [
{
"name": "custom-words",
"path": "./.cspell/custom-words.txt",
"addWords": true
}
]
}
+7 -7
View File
@@ -1,11 +1,11 @@
import { eventHandler, setResponseHeader } from 'h3'
import iconMetaData from '../../data/iconMetaData'
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../data/iconMetaData';
export default eventHandler((event) => {
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
return Object.fromEntries(
Object.entries(iconMetaData).map(([name, { categories }]) => [ name, categories ])
)
})
Object.entries(iconMetaData).map(([name, { categories }]) => [name, categories]),
);
});
+2 -2
View File
@@ -37,13 +37,13 @@ export default eventHandler((event) => {
backdropString,
src,
color: name in iconNodes ? 'red' : '#777',
})
}),
);
}
const svg = Buffer.from(
// We can't use jsx here, is not supported here by nitro.
renderToString(createElement(SvgPreview, { src, showGrid: true }, children))
renderToString(createElement(SvgPreview, { src, showGrid: true }, children)),
).toString('utf8');
defaultContentType(event, 'image/svg+xml');
@@ -28,7 +28,7 @@ export default eventHandler(async (event) => {
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
`
`,
);
const resvg = new Resvg(svg, { background: '#000' });
@@ -1,12 +1,12 @@
import { eventHandler, setResponseHeader, defaultContentType } from 'h3'
import { renderToString } from 'react-dom/server'
import { createElement } from 'react'
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
import { renderToString } from 'react-dom/server';
import { createElement } from 'react';
import SvgPreview from '../../../lib/SvgPreview/index.tsx';
import createLucideIcon, { IconNode } from 'lucide-react/src/createLucideIcon'
import createLucideIcon, { IconNode } from 'lucide-react/src/createLucideIcon';
import { parseSync } from 'svgson';
export default eventHandler((event) => {
const { params } = event.context
const { params } = event.context;
const [strokeWidth, svgData] = params.data.split('/');
const data = svgData.slice(0, -4);
@@ -16,8 +16,8 @@ export default eventHandler((event) => {
const Icon = createLucideIcon(
'icon',
parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`).children.map(
({ name, attributes }) => [name, attributes]
) as IconNode
({ name, attributes }) => [name, attributes],
) as IconNode,
);
const svg = Buffer.from(
@@ -33,12 +33,12 @@ export default eventHandler((event) => {
@media screen and (prefers-color-scheme: dark) {
svg { stroke: #fff; fill: transparent !important; }
}
</style>`
)
</style>`,
),
).toString('utf8');
defaultContentType(event, 'image/svg+xml')
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
defaultContentType(event, 'image/svg+xml');
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
return svg
})
return svg;
});
+16 -16
View File
@@ -1,30 +1,30 @@
import { eventHandler, getQuery, setResponseHeader } from 'h3'
import iconNodes from '../../data/iconNodes'
import { IconNodeWithKeys } from '../../theme/types'
import { eventHandler, getQuery, setResponseHeader } from 'h3';
import iconNodes from '../../data/iconNodes';
import { IconNodeWithKeys } from '../../theme/types';
export default eventHandler((event) => {
const query = getQuery(event)
const query = getQuery(event);
const withUniqueKeys = query.withUniqueKeys === 'true'
const withUniqueKeys = query.withUniqueKeys === 'true';
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
if (withUniqueKeys) {
return iconNodes
return iconNodes;
}
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
if (withUniqueKeys) {
return [name, iconNode]
return [name, iconNode];
}
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs}]) => {
return [name, attrs]
})
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs }]) => {
return [name, attrs];
});
acc[name] = newIconNode
acc[name] = newIconNode;
return acc
}, {})
})
return acc;
}, {});
});
+21 -22
View File
@@ -1,29 +1,29 @@
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3'
import iconNodes from '../../data/iconNodes'
import createLucideIcon from 'lucide-react/src/createLucideIcon'
import { renderToString } from 'react-dom/server'
import { createElement } from 'react'
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3';
import iconNodes from '../../data/iconNodes';
import createLucideIcon from 'lucide-react/src/createLucideIcon';
import { renderToString } from 'react-dom/server';
import { createElement } from 'react';
export default eventHandler((event) => {
const { params } = event.context
const { params } = event.context;
const iconNode = iconNodes[params.iconName]
const iconNode = iconNodes[params.iconName];
if (iconNode == null) {
const error = createError({
statusCode: 404,
message: `Icon "${params.iconName}" not found`,
})
});
return sendError(event, error)
return sendError(event, error);
}
const width = getQuery(event).width || undefined
const height = getQuery(event).height || undefined
const color = getQuery(event).color || undefined
const strokeWidth = getQuery(event).strokeWidth || undefined
const width = getQuery(event).width || undefined;
const height = getQuery(event).height || undefined;
const color = getQuery(event).color || undefined;
const strokeWidth = getQuery(event).strokeWidth || undefined;
const LucideIcon = createLucideIcon(params.iconName, iconNode)
const LucideIcon = createLucideIcon(params.iconName, iconNode);
const svg = Buffer.from(
renderToString(
@@ -32,14 +32,13 @@ export default eventHandler((event) => {
height,
color: color ? `#${color}` : undefined,
strokeWidth,
}
))
}),
),
).toString('utf8');
defaultContentType(event, 'image/svg+xml')
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
defaultContentType(event, 'image/svg+xml');
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
return svg
})
return svg;
});
+6 -8
View File
@@ -1,11 +1,9 @@
import { eventHandler, setResponseHeader } from 'h3'
import iconMetaData from '../../data/iconMetaData'
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../data/iconMetaData';
export default eventHandler((event) => {
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
return Object.fromEntries(
Object.entries(iconMetaData).map(([name, { tags }]) => [ name, tags ])
)
})
return Object.fromEntries(Object.entries(iconMetaData).map(([name, { tags }]) => [name, tags]));
});
+2 -2
View File
@@ -1,3 +1,3 @@
export default eventHandler(() => {
return { nitro: 'Is Awesome! asda' }
})
return { nitro: 'Is Awesome! asda' };
});
+126 -81
View File
@@ -1,10 +1,10 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vitepress';
import sidebar from './sidebar';
const title = "Lucide";
const socialTitle = "Lucide Icons";
const description = "Beautiful & consistent icon toolkit made by the community."
const title = 'Lucide';
const socialTitle = 'Lucide Icons';
const description = 'Beautiful & consistent icon toolkit made by the community.';
// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -19,86 +19,131 @@ export default defineConfig({
{
find: /^.*\/VPIconAlignLeft\.vue$/,
replacement: fileURLToPath(
new URL('./theme/components/overrides/VPIconAlignLeft.vue', import.meta.url)
)
new URL('./theme/components/overrides/VPIconAlignLeft.vue', import.meta.url),
),
},
{
find: /^.*\/VPFooter\.vue$/,
replacement: fileURLToPath(
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url)
)
}
]
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url),
),
},
],
},
},
head: [
[ 'script', {
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: ''
}],
[ 'meta', {
property:"og:locale",
content:"en_US"
}],
[ 'meta', {
property:"og:type",
content:"website"
}],
[ 'meta', {
property:"og:site_name",
content: title,
}],
[ 'meta', {
property:"og:title",
content: socialTitle,
}],
[ 'meta', {
property:"og:description",
content: description
}],
[ 'meta', {
property:"og:url",
content:"https://lucide.dev"
}],
[ 'meta', {
property:"og:image",
content: "https://lucide.dev/og.png"
}],
[ 'meta', {
property:"og:image:width",
content:"1200"
}],
[ 'meta', {
property:"og:image:height",
content:"630"
}],
[ 'meta', {
property:"og:image:type",
content:"image/png"
}],
[ 'meta', {
property:"twitter:card",
content:"summary_large_image"
}],
[ 'meta', {
property:"twitter:title",
content: socialTitle,
}],
[ 'meta', {
property:"twitter:description",
content: description
}],
[ 'meta', {
property:"twitter:image",
content:"https://lucide.dev/og.png"
}],
[
'script',
{
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: '',
},
],
[
'meta',
{
property: 'og:locale',
content: 'en_US',
},
],
[
'meta',
{
property: 'og:type',
content: 'website',
},
],
[
'meta',
{
property: 'og:site_name',
content: title,
},
],
[
'meta',
{
property: 'og:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'og:description',
content: description,
},
],
[
'meta',
{
property: 'og:url',
content: 'https://lucide.dev',
},
],
[
'meta',
{
property: 'og:image',
content: 'https://lucide.dev/og.png',
},
],
[
'meta',
{
property: 'og:image:width',
content: '1200',
},
],
[
'meta',
{
property: 'og:image:height',
content: '630',
},
],
[
'meta',
{
property: 'og:image:type',
content: 'image/png',
},
],
[
'meta',
{
property: 'twitter:card',
content: 'summary_large_image',
},
],
[
'meta',
{
property: 'twitter:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'twitter:description',
content: description,
},
],
[
'meta',
{
property: 'twitter:image',
content: 'https://lucide.dev/og.png',
},
],
],
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: {
light: '/logo.light.svg',
dark: '/logo.dark.svg'
dark: '/logo.dark.svg',
},
nav: [
{ text: 'Icons', link: '/icons/' },
@@ -110,21 +155,21 @@ export default defineConfig({
sidebar,
socialLinks: [
{ icon: 'github', link: 'https://github.com/lucide-icons/lucide' },
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' }
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' },
],
footer: {
message: 'Released under the ISC License.',
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`,
},
editLink: {
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path',
},
carbonAds: {
code: 'CWYIC53U',
placement: 'lucidedev'
}
placement: 'lucidedev',
},
},
sitemap: {
hostname: 'https://lucide.dev/'
}
})
hostname: 'https://lucide.dev/',
},
});
+105 -21
View File
@@ -3,87 +3,171 @@
"order": 0,
"icon": "js",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide", "href": "https://www.npmjs.com/package/lucide" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide", "href": "https://www.npmjs.com/package/lucide" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide",
"href": "https://www.npmjs.com/package/lucide"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide",
"href": "https://www.npmjs.com/package/lucide"
}
]
},
"lucide-react": {
"order": 1,
"icon": "react",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-react", "href": "https://www.npmjs.com/package/lucide-react" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-react", "href": "https://www.npmjs.com/package/lucide-react" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-react",
"href": "https://www.npmjs.com/package/lucide-react"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-react",
"href": "https://www.npmjs.com/package/lucide-react"
}
]
},
"lucide-vue": {
"order": 2,
"icon": "vue",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-vue", "href": "https://www.npmjs.com/package/lucide-vue" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-vue", "href": "https://www.npmjs.com/package/lucide-vue" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-vue",
"href": "https://www.npmjs.com/package/lucide-vue"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-vue",
"href": "https://www.npmjs.com/package/lucide-vue"
}
]
},
"lucide-vue-next": {
"order": 3,
"icon": "vue-next",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-vue-next", "href": "https://www.npmjs.com/package/lucide-vue-next" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-vue-next", "href": "https://www.npmjs.com/package/lucide-vue-next" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-vue-next",
"href": "https://www.npmjs.com/package/lucide-vue-next"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-vue-next",
"href": "https://www.npmjs.com/package/lucide-vue-next"
}
]
},
"lucide-svelte": {
"order": 4,
"icon": "svelte",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-svelte", "href": "https://www.npmjs.com/package/lucide-svelte" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-svelte", "href": "https://www.npmjs.com/package/lucide-svelte" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-svelte",
"href": "https://www.npmjs.com/package/lucide-svelte"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-svelte",
"href": "https://www.npmjs.com/package/lucide-svelte"
}
]
},
"lucide-solid": {
"order": 4,
"icon": "solid",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-solid", "href": "https://www.npmjs.com/package/lucide-solid" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-solid", "href": "https://www.npmjs.com/package/lucide-solid" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-solid",
"href": "https://www.npmjs.com/package/lucide-solid"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-solid",
"href": "https://www.npmjs.com/package/lucide-solid"
}
]
},
"lucide-preact": {
"order": 5,
"icon": "preact",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-preact", "href": "https://www.npmjs.com/package/lucide-preact" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-preact", "href": "https://www.npmjs.com/package/lucide-preact" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-preact",
"href": "https://www.npmjs.com/package/lucide-preact"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-preact",
"href": "https://www.npmjs.com/package/lucide-preact"
}
]
},
"lucide-react-native": {
"order": 6,
"icon": "react-native",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-react-native", "href": "https://www.npmjs.com/package/lucide-react-native" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-react-native", "href": "https://www.npmjs.com/package/lucide-react-native" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-react-native",
"href": "https://www.npmjs.com/package/lucide-react-native"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-react-native",
"href": "https://www.npmjs.com/package/lucide-react-native"
}
]
},
"lucide-angular": {
"order": 7,
"icon": "angular",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-angular", "href": "https://www.npmjs.com/package/lucide-angular" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-angular", "href": "https://www.npmjs.com/package/lucide-angular" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-angular",
"href": "https://www.npmjs.com/package/lucide-angular"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-angular",
"href": "https://www.npmjs.com/package/lucide-angular"
}
]
},
"lucide-static": {
"order": 8,
"icon": "svg",
"shields": [
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-static", "href": "https://www.npmjs.com/package/lucide-static" },
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-static", "href": "https://www.npmjs.com/package/lucide-static" }
{
"alt": "npm",
"src": "https://img.shields.io/npm/v/lucide-static",
"href": "https://www.npmjs.com/package/lucide-static"
},
{
"alt": "npm",
"src": "https://img.shields.io/npm/dw/lucide-static",
"href": "https://www.npmjs.com/package/lucide-static"
}
]
},
"lucide-flutter": {
"order": 9,
"icon": "flutter",
"shields": [
{ "alt": "flutter", "src": "https://img.shields.io/pub/v/lucide_icons", "href": "https://img.shields.io/pub/v/lucide_icons" }
{
"alt": "flutter",
"src": "https://img.shields.io/pub/v/lucide_icons",
"href": "https://img.shields.io/pub/v/lucide_icons"
}
]
}
}
+52 -11
View File
@@ -17,21 +17,62 @@ const Backdrop = ({ src, color = 'red', backdropString }: BackdropProps): JSX.El
patternUnits="userSpaceOnUse"
patternTransform="rotate(45 50 50)"
>
<line stroke={color} strokeWidth={0.1} y2={1} />
<line stroke={color} strokeWidth={0.1} y2={1} />
<line
stroke={color}
strokeWidth={0.1}
y2={1}
/>
<line
stroke={color}
strokeWidth={0.1}
y2={1}
/>
</pattern>
</defs>
<mask id="svg-preview-backdrop-mask-outline" maskUnits="userSpaceOnUse">
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
<mask
id="svg-preview-backdrop-mask-outline"
maskUnits="userSpaceOnUse"
>
<g
stroke="#fff"
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
<g
dangerouslySetInnerHTML={{ __html: src }}
strokeWidth={2.05}
/>
</mask>
<mask id="svg-preview-backdrop-mask-fill" maskUnits="userSpaceOnUse">
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
<g strokeWidth={1.75} dangerouslySetInnerHTML={{ __html: backdropString }} />
<mask
id="svg-preview-backdrop-mask-fill"
maskUnits="userSpaceOnUse"
>
<g
stroke="#fff"
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
<g
dangerouslySetInnerHTML={{ __html: src }}
strokeWidth={2.05}
/>
<g
strokeWidth={1.75}
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
</mask>
<g strokeWidth={2.25} stroke="url(#pattern)" mask={'url(#svg-preview-backdrop-mask-outline)'}>
<rect x="0" y="0" width="24" height="24" fill="url(#pattern)" opacity={0.5} stroke="none" />
<g
strokeWidth={2.25}
stroke="url(#pattern)"
mask={'url(#svg-preview-backdrop-mask-outline)'}
>
<rect
x="0"
y="0"
width="24"
height="24"
fill="url(#pattern)"
opacity={0.5}
stroke="none"
/>
</g>
<rect
x="0"
+155 -38
View File
@@ -10,7 +10,11 @@ const Grid = ({
strokeWidth: number;
radius: number;
} & PathProps<'stroke', 'strokeWidth'>) => (
<g className="svg-preview-grid-group" strokeLinecap="butt" {...props}>
<g
className="svg-preview-grid-group"
strokeLinecap="butt"
{...props}
>
<rect
className="svg-preview-grid-rect"
width={24 - props.strokeWidth}
@@ -21,11 +25,29 @@ const Grid = ({
fill={fill}
/>
<path
strokeDasharray={'0 0.1 ' + '0.1 0.15 '.repeat(11) + '0 0.15'}
strokeWidth={0.1}
d={
props.d ||
new Array(Math.floor(24 - 1))
.fill(null)
.flatMap((_, i) => [
.map((_, i) => i)
.filter((i) => i % 3 !== 2)
.flatMap((i) => [
`M${props.strokeWidth} ${i + 1}h${24 - props.strokeWidth * 2}`,
`M${i + 1} ${props.strokeWidth}v${24 - props.strokeWidth * 2}`,
])
.join('')
}
/>
<path
d={
props.d ||
new Array(Math.floor(24 - 1))
.fill(null)
.map((_, i) => i)
.filter((i) => i % 3 === 2)
.flatMap((i) => [
`M${props.strokeWidth} ${i + 1}h${24 - props.strokeWidth * 2}`,
`M${i + 1} ${props.strokeWidth}v${24 - props.strokeWidth * 2}`,
])
@@ -44,15 +66,21 @@ const Shadow = ({
paths: Path[];
} & PathProps<'stroke' | 'strokeWidth' | 'strokeOpacity', 'd'>) => {
const groupedPaths = Object.entries(
paths.reduce((groups, val) => {
const key = val.c.id;
groups[key] = [...(groups[key] || []), val];
return groups;
}, {} as Record<number, Path[]>)
paths.reduce(
(groups, val) => {
const key = val.c.id;
groups[key] = [...(groups[key] || []), val];
return groups;
},
{} as Record<number, Path[]>,
),
);
return (
<>
<g className="svg-preview-shadow-mask-group" {...props}>
<g
className="svg-preview-shadow-mask-group"
{...props}
>
{groupedPaths.map(([id, paths]) => (
<mask
id={`svg-preview-shadow-mask-${id}`}
@@ -61,7 +89,15 @@ const Shadow = ({
strokeWidth={props.strokeWidth}
stroke="#000"
>
<rect x={0} y={0} width={24} height={24} fill="#fff" stroke="none" rx={radius} />
<rect
x={0}
y={0}
width={24}
height={24}
fill="#fff"
stroke="none"
rx={radius}
/>
<path
d={paths
.flatMap(({ prev, next }) => [
@@ -74,9 +110,16 @@ const Shadow = ({
</mask>
))}
</g>
<g className="svg-preview-shadow-group" {...props}>
<g
className="svg-preview-shadow-group"
{...props}
>
{paths.map(({ d, c: { id } }, i) => (
<path key={i} mask={`url(#svg-preview-shadow-mask-${id})`} d={d} />
<path
key={i}
mask={`url(#svg-preview-shadow-mask-${id})`}
d={d}
/>
))}
<path
d={paths
@@ -94,9 +137,16 @@ const ColoredPath = ({
paths,
...props
}: { paths: Path[]; colors: string[] } & PathProps<never, 'd' | 'stroke'>) => (
<g className="svg-preview-colored-path-group" {...props}>
<g
className="svg-preview-colored-path-group"
{...props}
>
{paths.map(({ d, c }, i) => (
<path key={i} d={d} stroke={colors[(c.name === 'path' ? i : c.id) % colors.length]} />
<path
key={i}
d={d}
stroke={colors[(c.name === 'path' ? i : c.id) % colors.length]}
/>
))}
</g>
);
@@ -138,7 +188,15 @@ const ControlPath = ({
key={i}
maskUnits="userSpaceOnUse"
>
<rect x="0" y="0" width="24" height="24" fill="#fff" stroke="none" rx={radius} />
<rect
x="0"
y="0"
width="24"
height="24"
fill="#fff"
stroke="none"
rx={radius}
/>
<path d={`M${prev.x} ${prev.y}h.01`} />
<path d={`M${next.x} ${next.y}h.01`} />
</mask>
@@ -146,7 +204,10 @@ const ControlPath = ({
);
})}
</g>
<g className="svg-preview-control-path-group" {...props}>
<g
className="svg-preview-control-path-group"
{...props}
>
{controlPaths.map(({ d, showMarker }, i) => (
<path
key={i}
@@ -155,18 +216,33 @@ const ControlPath = ({
/>
))}
</g>
<g className="svg-preview-control-path-marker-group" {...props}>
<g
className="svg-preview-control-path-marker-group"
{...props}
>
<path
d={controlPaths
.flatMap(({ prev, next, showMarker }) =>
showMarker ? [`M${prev.x} ${prev.y}h.01`, `M${next.x} ${next.y}h.01`] : []
showMarker ? [`M${prev.x} ${prev.y}h.01`, `M${next.x} ${next.y}h.01`] : [],
)
.join('')}
/>
{controlPaths.map(({ d, prev, next, startMarker, endMarker }, i) => (
<React.Fragment key={i}>
{startMarker && <circle cx={prev.x} cy={prev.y} r={pointSize / 2} />}
{endMarker && <circle cx={next.x} cy={next.y} r={pointSize / 2} />}
{startMarker && (
<circle
cx={prev.x}
cy={prev.y}
r={pointSize / 2}
/>
)}
{endMarker && (
<circle
cx={next.x}
cy={next.y}
r={pointSize / 2}
/>
)}
</React.Fragment>
))}
</g>
@@ -182,15 +258,16 @@ const Radii = ({
any
>) => {
return (
<g className="svg-preview-radii-group" {...props}>
<g
className="svg-preview-radii-group"
{...props}
>
{paths.map(
({ c, prev, next, circle }, i) =>
circle && (
<React.Fragment key={i}>
{c.name !== "circle" && (
<path
d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`}
/>
{c.name !== 'circle' && (
<path d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`} />
)}
<circle
cy={circle.y}
@@ -200,7 +277,7 @@ const Radii = ({
stroke={
(Math.round(circle.x * 100) / 100) % 1 !== 0 ||
(Math.round(circle.y * 100) / 100) % 1 !== 0
? "red"
? 'red'
: undefined
}
/>
@@ -208,11 +285,7 @@ const Radii = ({
cy={circle.y}
cx={circle.x}
r={circle.r}
stroke={
(Math.round(circle.r * 1000) / 1000) % 1 !== 0
? "red"
: undefined
}
stroke={(Math.round(circle.r * 1000) / 1000) % 1 !== 0 ? 'red' : undefined}
/>
</React.Fragment>
),
@@ -230,13 +303,28 @@ const Handles = ({
>) => {
console.log(paths);
return (
<g className="svg-preview-handles-group" {...props}>
<g
className="svg-preview-handles-group"
{...props}
>
{paths.map(({ c, prev, next, cp1, cp2 }) => (
<>
{cp1 && <path d={`M${prev.x} ${prev.y} ${cp1.x} ${cp1.y}`} />}
{cp1 && <circle cy={cp1.y} cx={cp1.x} r={0.25} />}
{cp1 && (
<circle
cy={cp1.y}
cx={cp1.x}
r={0.25}
/>
)}
{cp2 && <path d={`M${next.x} ${next.y} ${cp2.x} ${cp2.y}`} />}
{cp2 && <circle cy={cp2.y} cx={cp2.x} r={0.25} />}
{cp2 && (
<circle
cy={cp2.y}
cx={cp2.x}
r={0.25}
/>
)}
</>
))}
</g>
@@ -280,9 +368,27 @@ const SvgPreview = React.forwardRef<
{...props}
>
<style>{darkModeCss}</style>
{showGrid && <Grid strokeWidth={0.1} stroke="#777" strokeOpacity={0.3} radius={1} />}
<Shadow paths={paths} strokeWidth={4} stroke="#777" radius={1} strokeOpacity={0.15} />
<Handles paths={paths} strokeWidth={0.12} stroke="#777" strokeOpacity={0.6} />
{showGrid && (
<Grid
strokeWidth={0.1}
stroke="#777"
strokeOpacity={0.3}
radius={1}
/>
)}
<Shadow
paths={paths}
strokeWidth={4}
stroke="#777"
radius={1}
strokeOpacity={0.15}
/>
<Handles
paths={paths}
strokeWidth={0.12}
stroke="#777"
strokeOpacity={0.6}
/>
<ColoredPath
paths={paths}
colors={[
@@ -307,8 +413,19 @@ const SvgPreview = React.forwardRef<
stroke="#777"
strokeOpacity={0.3}
/>
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
<Handles paths={paths} strokeWidth={0.12} stroke="#FFF" strokeOpacity={0.3} />
<ControlPath
radius={1}
paths={paths}
pointSize={1}
stroke="#fff"
strokeWidth={0.125}
/>
<Handles
paths={paths}
strokeWidth={0.12}
stroke="#FFF"
strokeOpacity={0.3}
/>
{children}
</svg>
);
+1 -1
View File
@@ -16,7 +16,7 @@ export type Path = {
export type PathProps<
RequiredProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>,
NeverProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>
NeverProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>,
> = Required<Pick<React.SVGProps<SVGElement & SVGRectElement & SVGCircleElement>, RequiredProps>> &
Omit<
React.SVGProps<SVGPathElement & SVGRectElement & SVGCircleElement>,
+10 -10
View File
@@ -51,7 +51,7 @@ export const getCommands = (src: string) =>
getNodes(src)
.map(convertToPathNode)
.flatMap(({ d, name }, idx) =>
new SVGPathData(d).toAbs().commands.map((c, cIdx) => ({ ...c, id: idx, idx: cIdx, name }))
new SVGPathData(d).toAbs().commands.map((c, cIdx) => ({ ...c, id: idx, idx: cIdx, name })),
);
export const getPaths = (src: string) => {
@@ -60,10 +60,10 @@ export const getPaths = (src: string) => {
let prev: Point | undefined = undefined;
let start: Point | undefined = undefined;
const addPath = (
c: typeof commands[number],
c: (typeof commands)[number],
next: Point,
d?: string,
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] }
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] },
) => {
assert(prev);
paths.push({
@@ -153,7 +153,7 @@ export const getPaths = (src: string) => {
{
cp1: { x: prev.x - reflectedCp1.x, y: prev.y - reflectedCp1.y },
cp2: { x: c.x2, y: c.y2 },
}
},
);
break;
}
@@ -169,7 +169,7 @@ export const getPaths = (src: string) => {
assert(prev);
const backTrackCP = (
index: number,
currentPoint: { x: number; y: number }
currentPoint: { x: number; y: number },
): { x: number; y: number } => {
const previousCommand = commands[index - 1];
if (!previousCommand) {
@@ -211,7 +211,7 @@ export const getPaths = (src: string) => {
{
cp1: { x: prevCP.x, y: prevCP.y },
cp2: { x: prevCP.x, y: prevCP.y },
}
},
);
break;
}
@@ -226,13 +226,13 @@ export const getPaths = (src: string) => {
c.lArcFlag,
c.sweepFlag,
c.x,
c.y
c.y,
);
addPath(
c,
c,
`M ${prev.x} ${prev.y} A${c.rX} ${c.rY} ${c.xRot} ${c.lArcFlag} ${c.sweepFlag} ${c.x} ${c.y}`,
{ circle: c.rX === c.rY ? { ...center, r: c.rX } : undefined }
{ circle: c.rX === c.rY ? { ...center, r: c.rX } : undefined },
);
break;
}
@@ -253,7 +253,7 @@ export const arcEllipseCenter = (
fa: number,
fs: number,
x2: number,
y2: number
y2: number,
) => {
const phi = (a * Math.PI) / 180;
@@ -280,7 +280,7 @@ export const arcEllipseCenter = (
sign *
Math.sqrt(
Math.max(rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p, 0) /
(rx * rx * y1p * y1p + ry * ry * x1p * x1p)
(rx * rx * y1p * y1p + ry * ry * x1p * x1p),
);
const V2 = [(rx * y1p) / ry, (-ry * x1p) / rx];
+17 -11
View File
@@ -1,28 +1,34 @@
import fs from "fs";
import path from "path";
import {Category, IconEntity} from "../theme/types";
import fs from 'fs';
import path from 'path';
import { Category, IconEntity } from '../theme/types';
const directory = path.join(process.cwd(), "../categories");
const directory = path.join(process.cwd(), '../categories');
export function getAllCategoryFiles(): Category[] {
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json');
return fileNames.map((fileName) => {
const name = path.basename(fileName, '.json')
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8')
const name = path.basename(fileName, '.json');
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8');
const parsedFileContent = JSON.parse(fileContent)
const parsedFileContent = JSON.parse(fileContent);
return {
name,
title: parsedFileContent.title,
}
};
});
}
export function mapCategoryIconCount(categories: Category[], icons: { categories: IconEntity['categories'] }[]) {
export function mapCategoryIconCount(
categories: Category[],
icons: { categories: IconEntity['categories'] }[],
) {
return categories.map((category) => ({
...category,
iconCount: icons.reduce((acc, curr) => (curr.categories.includes(category.name) ? ++acc : acc), 0)
}))
iconCount: icons.reduce(
(acc, curr) => (curr.categories.includes(category.name) ? ++acc : acc),
0,
),
}));
}
+26 -31
View File
@@ -1,24 +1,18 @@
import {
bundledLanguages,
type ThemeRegistration
} from 'shikiji'
import {
getHighlighter,
} from 'shikiji'
import { bundledLanguages, type ThemeRegistration } from 'shikiji';
import { getHighlighter } from 'shikiji';
type CodeExampleType = {
title: string,
language: string,
code: string,
}[]
title: string;
language: string;
code: string;
}[];
const getIconCodes = (): CodeExampleType => {
return [
{
language: 'html',
title: 'HTML',
code: `<i data-lucide="Name"></i>`
code: `<i data-lucide="Name"></i>`,
},
{
language: 'tsx',
@@ -109,36 +103,37 @@ import { LucideAngularModule, PascalCase } from 'lucide-angular';
<div class="icon-Name"></div>
`,
}
]
}
},
];
};
export type ThemeOptions =
| ThemeRegistration
| { light: ThemeRegistration; dark: ThemeRegistration }
| { light: ThemeRegistration; dark: ThemeRegistration };
const highLightCode = async (code: string, lang: string, active?: boolean) => {
const highlighter = await getHighlighter({
themes: ['github-light', 'github-dark'],
langs: Object.keys(bundledLanguages)
})
langs: Object.keys(bundledLanguages),
});
const highlightedCode = highlighter.codeToHtml(code, {
lang,
themes: {
light: 'github-light',
dark: 'github-dark'
},
defaultColor: false
}).replace('shiki-themes', 'shiki-themes vp-code')
const highlightedCode = highlighter
.codeToHtml(code, {
lang,
themes: {
light: 'github-light',
dark: 'github-dark',
},
defaultColor: false,
})
.replace('shiki-themes', 'shiki-themes vp-code');
return `<div class="language-${lang} ${active ? 'active' : ''}">
<button title="Copy Code" class="copy"></button>
<span class="lang">${lang}</span>
${highlightedCode}
</div>`
}
</div>`;
};
export default async function createCodeExamples() {
const codes = getIconCodes();
@@ -153,7 +148,7 @@ export default async function createCodeExamples() {
language: language,
code: codeString,
};
})
});
return Promise.all(codeExamplePromises);
}
+27 -23
View File
@@ -1,38 +1,42 @@
import { promises as fs, constants } from 'fs';
import path from 'path';
import yaml from 'js-yaml'
import yaml from 'js-yaml';
import { PackageItem } from '../theme/types';
const fileExist = (filePath) => fs.access(filePath, constants.F_OK).then(() => true).catch(() => false)
const fileExist = (filePath) =>
fs
.access(filePath, constants.F_OK)
.then(() => true)
.catch(() => false);
const fetchPackages = async (): Promise<PackageItem[]> => {
const docsDir = path.resolve(process.cwd(), '../packages');
const fileNames = await (await fs.readdir(docsDir)).map(filename => ({filename, directory: docsDir}))
const fileNames = await (
await fs.readdir(docsDir)
).map((filename) => ({ filename, directory: docsDir }));
const packageJsons = await Promise.all(fileNames.map( async ({filename, directory}) => {
const filePath = path.resolve(directory, filename)
const fileStat = await fs.lstat(filePath);
const packageJsons = await Promise.all(
fileNames.map(async ({ filename, directory }) => {
const filePath = path.resolve(directory, filename);
const fileStat = await fs.lstat(filePath);
if(!fileStat.isDirectory()) return null;
if (!fileStat.isDirectory()) return null;
const jsonFilePath = path.resolve(filePath, 'package.json')
if (await fileExist(jsonFilePath)) {
return JSON.parse(
await fs.readFile(jsonFilePath, 'utf-8')
)
}
const jsonFilePath = path.resolve(filePath, 'package.json');
if (await fileExist(jsonFilePath)) {
return JSON.parse(await fs.readFile(jsonFilePath, 'utf-8'));
}
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml')
if(await fileExist(ymlFilePath)) {
return yaml.load(
await fs.readFile(ymlFilePath, 'utf-8')
);
}
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml');
if (await fileExist(ymlFilePath)) {
return yaml.load(await fs.readFile(ymlFilePath, 'utf-8'));
}
return null
}))
return null;
}),
);
return packageJsons
}
return packageJsons;
};
export default fetchPackages;
+5 -7
View File
@@ -1,17 +1,15 @@
export type IconContent = [icon: string, src:string];
export type IconContent = [icon: string, src: string];
async function generateZip(icons: IconContent[]) {
const JSZip = (await import('jszip')).default
const JSZip = (await import('jszip')).default;
const zip = new JSZip();
const addingZipPromises = icons.map(([name, src]) =>
zip.file(`${name}.svg`, src),
);
const addingZipPromises = icons.map(([name, src]) => zip.file(`${name}.svg`, src));
await Promise.all(addingZipPromises)
await Promise.all(addingZipPromises);
return zip.generateAsync({ type: 'blob' });
}
export default generateZip
export default generateZip;
+11 -13
View File
@@ -1,17 +1,15 @@
import { createLucideIcon } from "lucide-react/src/lucide-react"
import { type LucideProps, type IconNode } from "lucide-react/src/createLucideIcon"
import { IconEntity } from "../theme/types"
import { createLucideIcon } from 'lucide-react/src/lucide-react';
import { type LucideProps, type IconNode } from 'lucide-react/src/createLucideIcon';
import { IconEntity } from '../theme/types';
import { renderToStaticMarkup } from 'react-dom/server';
import { IconContent } from "./generateZip";
import { IconContent } from './generateZip';
const getFallbackZip = (icons: IconEntity[], params: LucideProps) => {
return icons
.map<IconContent>((icon) => {
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode)
const src = renderToStaticMarkup(<Icon {...params} />)
return [icon.name, src]
})
}
return icons.map<IconContent>((icon) => {
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode);
const src = renderToStaticMarkup(<Icon {...params} />);
return [icon.name, src];
});
};
export default getFallbackZip
export default getFallbackZip;
+19 -19
View File
@@ -1,34 +1,34 @@
import fs from "fs";
import path from "path";
import { IconNodeWithKeys } from "../theme/types";
import iconNodes from '../data/iconNodes'
import releaseMeta from "../data/releaseMetaData.json";
import fs from 'fs';
import path from 'path';
import { IconNodeWithKeys } from '../theme/types';
import iconNodes from '../data/iconNodes';
import releaseMeta from '../data/releaseMetaData.json';
const DATE_OF_FORK = '2020-06-08T16:39:52+0100';
const directory = path.join(process.cwd(), "../icons");
const directory = path.join(process.cwd(), '../icons');
export interface GetDataOptions {
withChildKeys?: boolean
withChildKeys?: boolean;
}
export async function getData(name: string) {
const jsonPath = path.join(directory, `${name}.json`);
const jsonContent = fs.readFileSync(jsonPath, "utf8");
const jsonContent = fs.readFileSync(jsonPath, 'utf8');
const { tags, categories, contributors } = JSON.parse(jsonContent);
const iconNode = iconNodes[name]
const iconNode = iconNodes[name];
const releaseData = releaseMeta?.[name] ?? {
"createdRelease": {
"version": "0.0.0",
"date": DATE_OF_FORK
createdRelease: {
version: '0.0.0',
date: DATE_OF_FORK,
},
"changedRelease": {
"version": "0.0.0",
"date": DATE_OF_FORK
}
}
changedRelease: {
version: '0.0.0',
date: DATE_OF_FORK,
},
};
return {
name,
@@ -36,11 +36,11 @@ export async function getData(name: string) {
categories,
iconNode,
contributors,
...releaseData
...releaseData,
};
}
export async function getAllData(): Promise<{ name: string, iconNode: IconNodeWithKeys}[]> {
export async function getAllData(): Promise<{ name: string; iconNode: IconNodeWithKeys }[]> {
const names = Object.keys(iconNodes);
return Promise.all(names.map((name) => getData(name)));
+29 -39
View File
@@ -1,31 +1,31 @@
import { DefaultTheme, UserConfig } from "vitepress"
import { DefaultTheme, UserConfig } from 'vitepress';
const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
'guide':[
guide: [
{
text: 'Introduction',
items: [
{ text: 'What is lucide?', link: '/guide/' },
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Comparison', link: '/guide/comparison' }
]
{ text: 'Comparison', link: '/guide/comparison' },
],
},
{
text: 'Basics',
items: [
{
text: 'Color',
link: '/guide/basics/color'
link: '/guide/basics/color',
},
{
text: 'Sizing',
link: '/guide/basics/sizing'
link: '/guide/basics/sizing',
},
{
text: 'Stroke width',
link: '/guide/basics/stroke-width'
link: '/guide/basics/stroke-width',
},
]
],
},
// TODO: Add this section
{
@@ -37,14 +37,14 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
// },
{
text: 'Global styling',
link: '/guide/advanced/global-styling'
link: '/guide/advanced/global-styling',
},
// {
// text: 'Animations',
// },
{
text: 'Filled icons',
link: '/guide/advanced/filled-icons'
link: '/guide/advanced/filled-icons',
},
// {
// text: 'Combining icons',
@@ -55,83 +55,73 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
// {
// text: 'Auto importing'
// },
]
],
},
{
text: 'Packages',
items: [
{
text: 'Lucide',
link: '/guide/packages/lucide'
link: '/guide/packages/lucide',
},
{
text: 'Lucide React',
link: '/guide/packages/lucide-react'
link: '/guide/packages/lucide-react',
},
{
text: 'Lucide React Native',
link: '/guide/packages/lucide-react-native'
link: '/guide/packages/lucide-react-native',
},
{
text: 'Lucide Vue',
link: '/guide/packages/lucide-vue'
},
{
text: 'Lucide Vue Next (Vue 3)',
link: '/guide/packages/lucide-vue-next'
link: '/guide/packages/lucide-vue-next',
},
{
text: 'Lucide Svelte',
link: '/guide/packages/lucide-svelte'
link: '/guide/packages/lucide-svelte',
},
{
text: 'Lucide Solid',
link: '/guide/packages/lucide-solid'
link: '/guide/packages/lucide-solid',
},
{
text: 'Lucide Preact',
link: '/guide/packages/lucide-preact'
link: '/guide/packages/lucide-preact',
},
{
text: 'Lucide Angular',
link: '/guide/packages/lucide-angular'
link: '/guide/packages/lucide-angular',
},
{
text: 'Lucide Static',
link: '/guide/packages/lucide-static'
link: '/guide/packages/lucide-static',
},
{
text: 'Lucide Flutter',
link: '/guide/packages/lucide-flutter'
},
]
],
},
{
text: 'Contributing',
items: [
{
text: 'Icon Design Principles',
link: '/guide/design/icon-design-guide'
link: '/guide/design/icon-design-guide',
},
{
text: 'Designing in Illustrator',
link: '/guide/design/illustrator-guide'
link: '/guide/design/illustrator-guide',
},
{
text: 'Designing in InkScape',
link: '/guide/design/inkscape-guide'
link: '/guide/design/inkscape-guide',
},
{
text: 'Designing in Figma',
link: '/guide/design/figma-guide'
link: '/guide/design/figma-guide',
},
]
],
},
],
// This should be here to keep the sidebar shown on the icons page
'icons': [
{ text: '', link: '/' },
],
}
icons: [{ text: '', link: '/' }],
};
export default sidebar
export default sidebar;
@@ -9,8 +9,6 @@ const props = defineProps<{
}>()
const component = computed(() => props.href ? 'a' : 'div')
</script>
<template>
@@ -25,7 +23,7 @@ const component = computed(() => props.href ? 'a' : 'div')
</template>
<style>
.badge, a.badge {
.badge, a.badge, .vp-doc a.badge {
display: block;
border: 1px solid transparent;
text-align: center;
@@ -60,4 +58,6 @@ const component = computed(() => props.href ? 'a' : 'div')
/* color: var(--vp-button-alt-active-text);
background-color: var(--vp-button-alt-active-bg); */
}
</style>
@@ -94,8 +94,7 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
.menu {
position: relative;
}
.menu-items {
--menu-offset: 44px;
ul.menu-items {
position: absolute;
display: flex;
flex-direction: column;
@@ -103,7 +102,7 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
padding: 12px;
min-width: 128px;
border: 1px solid var(--vp-c-divider);
background-color: var(--vp-c-bg);
background-color: var(--vp-c-bg-elv);
box-shadow: var(--vp-shadow-3);
transition: background-color 0.5s;
max-height: calc(100vh - var(--vp-nav-height));
@@ -124,11 +123,12 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
color: var(--vp-c-text-1);
white-space: nowrap;
transition: background-color .25s,color .25s;
list-style: none;
}
.menu-item:hover {
color: var(--vp-c-brand);
background-color: var(--vp-c-bg-elv-mute);
background-color: var(--vp-c-default-soft);
}
.menu-item:active {
@@ -170,11 +170,11 @@ const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
}
.menu-items.bottom {
top: var(--menu-offset);
top: 32px;
}
.menu-items.top {
bottom: var(--menu-offset);
bottom: 48px;
}
.arrow-up-button.top::before {
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, defineProps, onMounted } from 'vue'
import { computed, onMounted } from 'vue'
const props = defineProps<{
groups: string[] | undefined,
groupName: string,
@@ -17,7 +17,7 @@ const SearchIcon = createLucideIcon('search', search)
background: var(--vp-c-bg-soft);
border-radius: 8px;
color: var(--vp-c-text-2);
padding: 12px 16px;
padding: 11px 16px;
height: auto;
font-size: 14px;
/* box-shadow: var(--vp-shadow-4), var(--vp-shadow-2); */
@@ -1,16 +1,18 @@
export default {
async load() {
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest').then(res => {
if (res.ok) {
const releaseData = res.json() as Promise<{ tag_name: string }>
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest')
.then((res) => {
if (res.ok) {
const releaseData = res.json() as Promise<{ tag_name: string }>;
return releaseData
}
return null
}).then(res => res.tag_name)
return releaseData;
}
return null;
})
.then((res) => res.tag_name);
return {
version
}
}
}
version,
};
},
};
@@ -1,16 +1,17 @@
import iconNodes from '../../../data/iconNodes'
import iconNodes from '../../../data/iconNodes';
const getRandomItem = <Item>(items: Item[]): Item => items[Math.floor(Math.random()*items.length)];
const getRandomItem = <Item>(items: Item[]): Item =>
items[Math.floor(Math.random() * items.length)];
export default {
async load() {
const icons = Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode }))
const icons = Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode }));
const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons))
const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons));
return {
icons: randomIcons,
iconsCount: icons.length,
}
}
}
};
},
};
@@ -47,7 +47,7 @@ export default {
logo: '/framework-logos/flutter.svg',
label: 'Lucide documentation for Flutter',
},
]
}
}
}
],
};
},
};
@@ -1,16 +1,15 @@
import { getAllData } from '../../../lib/icons';
import { getAllCategoryFiles, mapCategoryIconCount } from '../../../lib/categories';
import iconsMetaData from '../../../data/iconMetaData'
import iconsMetaData from '../../../data/iconMetaData';
export default {
async load() {
let categories = getAllCategoryFiles()
let categories = getAllCategoryFiles();
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData))
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData));
return {
categories,
}
}
}
};
},
};
@@ -1,13 +1,15 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref, computed, watch } from 'vue'
import { useData } from 'vitepress'
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
import { isActive } from 'vitepress/dist/client/shared'
import { useActiveAnchor } from '../../composables/useActiveAnchor'
import { data } from './CategoryList.data'
import CategoryListItem from './CategoryListItem.vue'
import { useCategoryView } from '../../composables/useCategoryView'
const { page } = useData()
const { categoryCounts } = useCategoryView();
const categoriesIsActive = computed(() => {
return isActive(page.value.relativePath, '/icons/categories');
@@ -25,14 +27,21 @@ const headers = computed(() => {
level: 2,
link: `${linkPrefix}#${name}`,
title,
iconCount
iconCount: categoryCounts.value[name] ?? iconCount,
name
}))
})
const container = ref()
const marker = ref()
useActiveAnchor(container, marker)
const { setActiveLinkDebounced } = useActiveAnchor(container, marker)
watch(headers, () => {
setTimeout(() => {
setActiveLinkDebounced()
}, 200)
})
</script>
<template>
@@ -1,5 +1,4 @@
<script setup lang="ts">
import { onMounted } from 'vue';
import { useCategoryView } from '../../composables/useCategoryView';
interface Header {
@@ -8,6 +7,7 @@ interface Header {
slug: string;
iconCount: number;
link: string;
name: string;
children: Header[];
}
@@ -15,36 +15,35 @@ type MenuItem = Omit<Header, 'slug' | 'children'> & {
children?: MenuItem[];
};
const props = defineProps<{
defineProps<{
headers: MenuItem[];
root?: boolean;
}>();
const { selectedCategory } = useCategoryView();
function onClick(event: Event) {
const target =
(event.target as HTMLElement).nodeName === 'span'
? (event.target as HTMLElement).parentNode
: (event.target as HTMLElement);
const href = (target as HTMLAnchorElement)?.href;
function onClick(categoryName: string) {
selectedCategory.value = categoryName;
if (href) {
const id = '#' + href.split('#')[1];
const decodedId = decodeURIComponent(id);
const heading = document.querySelector<HTMLAnchorElement>(categoryName);
heading?.focus();
selectedCategory.value = decodedId.replace('#', '');
const heading = document.querySelector<HTMLAnchorElement>(decodedId);
heading?.focus();
}
window.history.pushState({}, '', `/icons/categories#${categoryName}`)
}
</script>
<template>
<ul :class="root ? 'root' : 'nested'">
<li v-for="{ children, link, title, iconCount } in headers">
<a class="outline-link" :href="link" @click="onClick" :title="title">
<li v-for="{ children, link, title, iconCount, name } in headers">
<a
class="outline-link"
:href="link"
@click="onClick(name)"
:title="title"
:class="{
inactive: iconCount === 0,
}"
>
<span>
{{ title }}
</span>
@@ -84,6 +83,10 @@ function onClick(event: Event) {
transition: color 0.25s;
}
.outline-link.inactive {
color: var(--vp-c-text-4);
}
.outline-link.nested {
padding-left: 13px;
}
@@ -94,4 +97,8 @@ function onClick(event: Event) {
font-size: 11px;
font-weight: 400;
}
.outline-link.inactive .icon-count {
opacity: 0;
}
</style>
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { computed } from 'vue';
import { startCase, camelCase } from 'lodash-es'
import ButtonMenu from '../base/ButtonMenu.vue'
import { useIconStyleContext } from '../../composables/useIconStyle';
@@ -1,6 +1,6 @@
<script setup lang="ts">
import type { IconEntity } from '../../types'
import { computed, ref, watch } from 'vue'
import { computed } from 'vue'
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
import IconButton from '../base/IconButton.vue';
import IconContributors from './IconContributors.vue';
@@ -4,7 +4,7 @@ import IconItem from './IconItem.vue'
const emit = defineEmits(['setActiveIcon'])
const props = defineProps<{
defineProps<{
icons: IconEntity[]
activeIcon?: string
overlayMode?: boolean
@@ -19,7 +19,11 @@ function setActiveIcon(name: string) {
<template>
<div class="icons">
<div class="icon" v-for="icon in icons" :key="icon.name">
<div
class="icon"
v-for="icon in icons"
:key="icon.name"
>
<IconItem
v-bind="icon"
@setActiveIcon="setActiveIcon(icon.name)"
@@ -36,7 +40,6 @@ function setActiveIcon(name: string) {
.icons {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
/* padding: 32px 32px 96px; */
gap: 8px;
width: 100%;
}
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
import { useMediaQuery } from '@vueuse/core';
import { useRouter } from 'vitepress';
@@ -27,7 +28,10 @@ const showOverlay = useMediaQuery('(min-width: 860px)');
const { animate, confetti, confettiText } = useConfetti()
const icon = createLucideIcon(props.name, props.iconNode)
const icon = computed(() => {
if (!props.name || !props.iconNode) return null
return createLucideIcon(props.name, props.iconNode)
})
async function navigateToIcon(event) {
@@ -1,56 +1,53 @@
<script lang="ts">
import { IconEntity } from '../../types';
type CategoryNameRow = {
type: 'category';
title: string;
name: string;
};
type CategoryIconsRow = {
type: 'icons';
icons: IconEntity[];
};
export type CategoryRow = CategoryNameRow | CategoryIconsRow;
</script>
<script setup lang="ts">
import { ref } from 'vue';
import { Category } from '../../types';
import IconGrid from './IconGrid.vue'
import { vIntersectionObserver } from '@vueuse/components'
defineProps<{
activeIconName: string
category: Category
categoryRow: CategoryRow
}>()
const emit = defineEmits(['setActiveIcon'])
const showIcons = ref(false)
// Added intersection observer to improve performance
const onIntersectionObserver: IntersectionObserverCallback = ([{ isIntersecting }]) => {
showIcons.value = isIntersecting
}
</script>
<template>
<section
class="category"
:key="category.name"
:id="category.name"
v-intersection-observer="onIntersectionObserver"
<h2
v-if="categoryRow.type === 'category'"
class="title"
>
<h2 class="title" >
<a class="header-anchor" :href="`#${category.name}`" :aria-label="`Permalink to &quot;${category.title}&quot;`">&ZeroWidthSpace;</a>
{{ category.title }}
</h2>
<IconGrid
:activeIcon="activeIconName"
:icons="category.icons"
@setActiveIcon="$event => $emit('setActiveIcon', $event)"
overlayMode
:hideIcons="!showIcons"
/>
</section>
<a class="header-anchor" :href="`#${categoryRow.name}`" :aria-label="`Permalink to &quot;${categoryRow.title}&quot;`">&ZeroWidthSpace;</a>
{{ categoryRow.title }}
</h2>
<IconGrid
v-else-if="categoryRow.type === 'icons'"
:activeIcon="activeIconName"
:icons="categoryRow.icons"
@setActiveIcon="$event => $emit('setActiveIcon', $event)"
overlayMode
/>
</template>
<style scoped>
.title {
margin-bottom: 24px;
margin-bottom: 8px;
font-size: 19px;
font-weight: 500;
padding-top: 86px;
/* scroll-padding-top: 240px; */
}
.category {
margin-bottom: calc(-86px + 32px);
padding: 24px 0 8px;
}
</style>
@@ -1,14 +1,20 @@
<script setup lang="ts">
import { ref, computed, defineAsyncComponent } from 'vue';
import { ref, computed, defineAsyncComponent, onMounted } from 'vue';
import type { IconEntity, Category } from '../../types';
import useSearch from '../../composables/useSearch';
import InputSearch from '../base/InputSearch.vue';
import useSearchInput from '../../composables/useSearchInput';
import StickyBar from './StickyBar.vue';
import IconsCategory from './IconsCategory.vue';
import { useFetch } from '@vueuse/core';
import useFetchTags from '../../composables/useFetchTags';
import useFetchCategories from '../../composables/useFetchCategories';
import { useElementSize, useEventListener, useVirtualList } from '@vueuse/core';
import chunkArray from '../../utils/chunkArray';
import { CategoryRow } from './IconsCategory.vue';
import useScrollToCategory from '../../composables/useScrollToCategory';
const ICON_SIZE = 56;
const ICON_GRID_GAP = 8;
const props = defineProps<{
icons: IconEntity[];
@@ -18,7 +24,6 @@ const props = defineProps<{
const activeIconName = ref(null);
const { searchInput, searchQuery, searchQueryDebounced } = useSearchInput();
const isSearching = computed(() => !!searchQuery.value);
function setActiveIconName(name: string) {
@@ -28,6 +33,13 @@ function setActiveIconName(name: string) {
const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl)
const columnSize = computed(() => {
return Math.floor((containerWidth.value) / ((ICON_SIZE + ICON_GRID_GAP)));
});
const mappedIcons = computed(() => {
if (tags.value == null) {
return props.icons;
@@ -44,9 +56,10 @@ const mappedIcons = computed(() => {
});
});
const searchResults = useSearch(searchQuery, mappedIcons, [
{ name: 'name', weight: 2 },
{ name: 'tags', weight: 1 },
const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
{ name: 'name', weight: 3 },
{ name: 'aliases', weight: 3 },
{ name: 'tags', weight: 2 },
]);
const categories = computed(() => {
@@ -72,9 +85,43 @@ const categories = computed(() => {
icons: searchedCategoryIcons,
};
})
.filter(({ icons }) => icons.length);
});
const categoriesList = computed(() => {
return categories.value
.filter(({ icons }) => icons.length)
.reduce<CategoryRow[]>((acc, category) => {
acc.push({ type: 'category', title: category.title, name: category.name });
const categoryIcons = chunkArray(category.icons, columnSize.value);
categoryIcons.forEach((icons) => {
acc.push({ type: 'icons', icons });
});
return acc;
}, []);
});
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
categoriesList,
{
itemHeight: ICON_SIZE + ICON_GRID_GAP,
overscan: 10
},
)
useScrollToCategory({
categories,
categoriesList,
scrollTo,
searchQueryDebounced,
})
onMounted(() => {
containerProps.ref.value = document.documentElement;
useEventListener(window, 'scroll', containerProps.onScroll)
})
function onFocusSearchInput() {
if (tags.value == null) {
fetchTags();
@@ -85,28 +132,35 @@ function onFocusSearchInput() {
}
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
</script>
<template>
<StickyBar class="search-bar category-search">
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
v-model="searchQuery"
class="input-wrapper"
ref="searchInput"
@focus="onFocusSearchInput"
<div ref="overviewEl" class="overview-container">
<StickyBar class="category-search">
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
v-model="searchQuery"
class="input-wrapper"
ref="searchInput"
@focus="onFocusSearchInput"
/>
</StickyBar>
<NoResults
v-if="categories.length === 0"
:searchQuery="searchQuery"
@clear="searchQuery = ''"
/>
</StickyBar>
<NoResults v-if="categories.length === 0" :searchQuery="searchQuery" @clear="searchQuery = ''" />
<IconsCategory
v-for="category in categories"
:key="category.name"
:category="category"
:activeIconName="activeIconName"
@setActiveIcon="setActiveIconName"
/>
<div v-bind="wrapperProps">
<IconsCategory
v-for="{ index, data } in list"
:categoryRow="data"
:activeIconName="activeIconName"
@setActiveIcon="setActiveIconName"
:key="index"
/>
</div>
</div>
<IconDetailOverlay
v-if="activeIconName != null"
:iconName="activeIconName"
@@ -120,6 +174,21 @@ const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay
}
.search-bar.category-search {
margin-bottom: -54px;
margin-bottom: 10px;
}
.title {
margin-bottom: 8px;
font-size: 19px;
font-weight: 500;
padding: 24px 0 8px;
}
.icons {
margin-bottom: 8px;
}
.overview-container {
padding-bottom: 288px;
}
</style>
@@ -1,15 +1,18 @@
<script setup lang="ts">
import { ref, computed, watch, defineAsyncComponent } from 'vue';
import { ref, computed, defineAsyncComponent, onMounted, watch } from 'vue';
import type { IconEntity } from '../../types';
import { useMediaQuery, useOffsetPagination } from '@vueuse/core';
import { useElementSize, useEventListener, useVirtualList } from '@vueuse/core';
import IconGrid from './IconGrid.vue';
import InputSearch from '../base/InputSearch.vue';
import useSearch from '../../composables/useSearch';
import EndOfPage from '../base/EndOfPage.vue';
import useSearchInput from '../../composables/useSearchInput';
import StickyBar from './StickyBar.vue';
import useFetchTags from '../../composables/useFetchTags';
import useFetchCategories from '../../composables/useFetchCategories';
import chunkArray from '../../utils/chunkArray';
const ICON_SIZE = 56;
const ICON_GRID_GAP = 8;
const props = defineProps<{
icons: IconEntity[];
@@ -17,32 +20,16 @@ const props = defineProps<{
const activeIconName = ref(null);
const isExtraLargeScreen = useMediaQuery('(min-width: 1440px)');
const isLargeScreen = useMediaQuery('(min-width: 1280px)');
const isMediumScreen = useMediaQuery('(min-width: 960px)');
const isSmallScreen = useMediaQuery('(min-width: 640px)');
const pageSize = computed(() => {
if (isExtraLargeScreen.value) {
return 16 * 20;
}
if (isLargeScreen.value) {
return 16 * 12;
}
if (isMediumScreen.value) {
return 13 * 12;
}
if (isSmallScreen.value) {
return 10 * 10;
}
return 10 * 5;
});
const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categories } = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl)
const columnSize = computed(() => {
return Math.floor((containerWidth.value) / ((ICON_SIZE + ICON_GRID_GAP)));
});
const mappedIcons = computed(() => {
if (tags.value == null) {
return props.icons;
@@ -63,26 +50,33 @@ const mappedIcons = computed(() => {
const { searchInput, searchQuery, searchQueryDebounced } = useSearchInput();
const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
{ name: 'name', weight: 3 },
{ name: 'aliases', weight: 3 },
{ name: 'tags', weight: 2 },
{ name: 'categories', weight: 1 },
]);
const { next, currentPage } = useOffsetPagination({ pageSize });
const paginatedIcons = computed(() => {
const end = pageSize.value * currentPage.value;
return searchResults.value.slice(0, end);
const chunkedIcons = computed(() => {
return chunkArray(searchResults.value, columnSize.value);
});
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
chunkedIcons,
{
itemHeight: ICON_SIZE + ICON_GRID_GAP,
overscan: 10
},
)
onMounted(() => {
containerProps.ref.value = document.documentElement;
useEventListener(window, 'scroll', containerProps.onScroll)
})
function setActiveIconName(name: string) {
activeIconName.value = name;
}
watch(searchQueryDebounced, (searchString) => {
currentPage.value = 1;
});
function onFocusSearchInput() {
if (tags.value == null) {
fetchTags();
@@ -95,30 +89,40 @@ function onFocusSearchInput() {
const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
watch(searchQueryDebounced, () => {
scrollTo(0)
})
</script>
<template>
<StickyBar>
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
v-model="searchQuery"
ref="searchInput"
class="input-wrapper"
@focus="onFocusSearchInput"
<div ref="overviewEl" class="overview-container">
<StickyBar>
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
v-model="searchQuery"
ref="searchInput"
class="input-wrapper"
@focus="onFocusSearchInput"
/>
</StickyBar>
<NoResults
v-if="list.length === 0"
:searchQuery="searchQuery"
@clear="searchQuery = ''"
/>
</StickyBar>
<NoResults
v-if="paginatedIcons.length === 0"
:searchQuery="searchQuery"
@clear="searchQuery = ''"
/>
<IconGrid
overlayMode
:activeIcon="activeIconName"
:icons="paginatedIcons"
@setActiveIcon="setActiveIconName"
/>
<EndOfPage @end-of-page="next" class="bottom-page" />
<div v-bind="wrapperProps" class="icon">
<IconGrid
v-for="{ index, data: icons } in list"
:key="index"
overlayMode
:icons="icons"
:activeIcon="activeIconName"
@setActiveIcon="setActiveIconName"
/>
</div>
</div>
<IconDetailOverlay
v-if="activeIconName != null"
:iconName="activeIconName"
@@ -128,10 +132,7 @@ const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay
<style>
.icons {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
gap: 8px;
width: 100%;
margin-bottom: 8px;
}
.icon {
@@ -142,7 +143,7 @@ const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay
width: 100%;
}
.bottom-page {
height: 288px;
.overview-container {
padding-bottom: 288px;
}
</style>

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