Compare commits

...
70 Commits
Author SHA1 Message Date
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
1745 changed files with 7035 additions and 4935 deletions
+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',
}
},
},
],
};
+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/*'
+2 -3
View File
@@ -1,7 +1,7 @@
name: Close stale issues and PR
on:
schedule:
- cron: "45 1 * * *"
- cron: '45 1 * * *'
jobs:
stale:
@@ -14,5 +14,4 @@ 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-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
@@ -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"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Multimedia",
"icon": "play-circle"
}
}
+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"
}
}
+1 -1
View File
@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Notifications",
"icon": "alert-triangle"
}
}
+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"
}
}
+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"
+136 -37
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}
@@ -44,15 +48,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 +71,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 +92,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 +119,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 +170,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 +186,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 +198,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 +240,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 +259,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 +267,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 +285,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 +350,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 +395,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,5 +1,4 @@
<script setup lang="ts">
import { onMounted } from 'vue';
import { useCategoryView } from '../../composables/useCategoryView';
interface Header {
@@ -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';
@@ -19,7 +19,11 @@ function setActiveIcon(name: string) {
<template>
<div class="icons">
<div class="icon" v-for="icon in icons" :key="icon.name">
<div
class="icon"
v-for="icon in icons"
:key="icon.name"
>
<IconItem
v-bind="icon"
@setActiveIcon="setActiveIcon(icon.name)"
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { computed } from 'vue';
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
import { useMediaQuery } from '@vueuse/core';
import { useRouter } from 'vitepress';
@@ -27,7 +28,10 @@ const showOverlay = useMediaQuery('(min-width: 860px)');
const { animate, confetti, confettiText } = useConfetti()
const icon = createLucideIcon(props.name, props.iconNode)
const icon = computed(() => {
if (!props.name || !props.iconNode) return null
return createLucideIcon(props.name, props.iconNode)
})
async function navigateToIcon(event) {
@@ -6,7 +6,6 @@ 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';
@@ -12,7 +12,7 @@
.confetti-button:before,
.confetti-button:after {
position: absolute;
content: "";
content: '';
display: block;
width: 140%;
max-width: 160px;
@@ -41,8 +41,16 @@
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
background-size: 10% 10%, 20% 20%, 15% 15%, 20% 20%, 18% 18%, 10% 10%, 15% 15%,
10% 10%, 18% 18%;
background-size:
10% 10%,
20% 20%,
15% 15%,
20% 20%,
18% 18%,
10% 10%,
15% 15%,
10% 10%,
18% 18%;
}
.confetti-button:after {
@@ -55,7 +63,14 @@
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
background-size: 15% 15%, 20% 20%, 18% 18%, 20% 20%, 15% 15%, 10% 10%, 20% 20%;
background-size:
15% 15%,
20% 20%,
18% 18%,
20% 20%,
15% 15%,
10% 10%,
20% 20%;
}
.confetti-button.animate:before {
@@ -70,35 +85,89 @@
@keyframes topBubbles {
0% {
color: rgb(var(--text-color) / 0);
background-position: 5% 90%, 10% 90%, 10% 90%, 15% 90%, 25% 90%, 25% 90%,
40% 90%, 55% 90%, 70% 90%;
background-position:
5% 90%,
10% 90%,
10% 90%,
15% 90%,
25% 90%,
25% 90%,
40% 90%,
55% 90%,
70% 90%;
}
30% {
color: rgb(var(--text-color) / 1);
}
50% {
background-position: 0% 80%, 0% 20%, 10% 40%, 20% 0%, 30% 30%, 22% 50%,
50% 50%, 65% 20%, 90% 30%;
background-position:
0% 80%,
0% 20%,
10% 40%,
20% 0%,
30% 30%,
22% 50%,
50% 50%,
65% 20%,
90% 30%;
}
100% {
background-position: 0% 70%, 0% 10%, 10% 30%, 20% -10%, 30% 20%, 22% 40%,
50% 40%, 65% 10%, 90% 20%;
background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
background-position:
0% 70%,
0% 10%,
10% 30%,
20% -10%,
30% 20%,
22% 40%,
50% 40%,
65% 10%,
90% 20%;
background-size:
0% 0%,
0% 0%,
0% 0%,
0% 0%,
0% 0%,
0% 0%;
color: rgb(var(--text-color) / 0);
}
}
@keyframes bottomBubbles {
0% {
background-position: 10% -10%, 30% 10%, 55% -10%, 70% -10%, 85% -10%,
70% -10%, 70% 0%;
background-position:
10% -10%,
30% 10%,
55% -10%,
70% -10%,
85% -10%,
70% -10%,
70% 0%;
}
50% {
background-position: 0% 80%, 20% 80%, 45% 60%, 60% 100%, 75% 70%, 95% 60%,
background-position:
0% 80%,
20% 80%,
45% 60%,
60% 100%,
75% 70%,
95% 60%,
105% 0%;
}
100% {
background-position: 0% 90%, 20% 90%, 45% 70%, 60% 110%, 75% 80%, 95% 70%,
background-position:
0% 90%,
20% 90%,
45% 70%,
60% 110%,
75% 80%,
95% 70%,
110% 10%;
background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
background-size:
0% 0%,
0% 0%,
0% 0%,
0% 0%,
0% 0%,
0% 0%;
}
}
@@ -1,21 +1,22 @@
import packageData from '../../../data/packageData.json';
import thirdPartyPackages from '../../../data/packageData.thirdParty.json';
import fetchPackages from "../../../lib/fetchPackages";
import fetchPackages from '../../../lib/fetchPackages';
export default {
async load() {
const packages = await fetchPackages();
return {
packages: packages
.filter(p => p.name in packageData)
.filter((p) => p.name in packageData)
.map((pData) => ({
...pData,
...packageData[pData.name],
documentation: `/guide/packages/${pData.name}`,
source: `https://github.com/lucide-icons/lucide/tree/main/packages/${pData.name}`,
icon: `/framework-logos/${packageData[pData.name].icon}.svg`,
})).sort((a, b) => a.order - b.order),
...pData,
...packageData[pData.name],
documentation: `/guide/packages/${pData.name}`,
source: `https://github.com/lucide-icons/lucide/tree/main/packages/${pData.name}`,
icon: `/framework-logos/${packageData[pData.name].icon}.svg`,
}))
.sort((a, b) => a.order - b.order),
thirdPartyPackages,
};
}
}
},
};
@@ -1,69 +1,68 @@
import { onMounted, onUpdated, onUnmounted } from 'vue';
import { throttleAndDebounce } from 'vitepress/dist/client/theme-default/support/utils'
import { throttleAndDebounce } from 'vitepress/dist/client/theme-default/support/utils';
/*
* This file is compied and adjusted from vitepress/dist/client/theme-default/composables/useActiveAnchor.ts
*/
* This file is compied and adjusted from vitepress/dist/client/theme-default/composables/useActiveAnchor.ts
*/
export function useActiveAnchor(container, marker) {
const onScroll = throttleAndDebounce(setActiveLink, 100);
let prevActiveLink = null;
onMounted(() => {
requestAnimationFrame(setActiveLink);
window.addEventListener('scroll', onScroll);
requestAnimationFrame(setActiveLink);
window.addEventListener('scroll', onScroll);
});
onUpdated(() => {
// sidebar update means a route change
activateLink(location.hash);
// sidebar update means a route change
activateLink(location.hash);
});
onUnmounted(() => {
window.removeEventListener('scroll', onScroll);
window.removeEventListener('scroll', onScroll);
});
function setActiveLink() {
const links = [].slice.call(container.value.querySelectorAll('.outline-link'));
const anchors = [].slice
.call(document.querySelectorAll('.content .header-anchor'))
.filter((anchor) => {
return links.some((link) => {
return link.hash === anchor.hash && anchor.offsetParent !== null;
});
const links = [].slice.call(container.value.querySelectorAll('.outline-link'));
const anchors = [].slice
.call(document.querySelectorAll('.content .header-anchor'))
.filter((anchor) => {
return links.some((link) => {
return link.hash === anchor.hash && anchor.offsetParent !== null;
});
});
const scrollY = window.scrollY;
const innerHeight = window.innerHeight;
const offsetHeight = document.body.offsetHeight;
const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1;
// page bottom - highlight last one
if (anchors.length && isBottom) {
activateLink(anchors[anchors.length - 1].hash);
return;
}
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i];
const nextAnchor = anchors[i + 1];
const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor);
if (isActive) {
activateLink(hash);
return;
}
const scrollY = window.scrollY;
const innerHeight = window.innerHeight;
const offsetHeight = document.body.offsetHeight;
const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1;
// page bottom - highlight last one
if (anchors.length && isBottom) {
activateLink(anchors[anchors.length - 1].hash);
return;
}
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i];
const nextAnchor = anchors[i + 1];
const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor);
if (isActive) {
activateLink(hash);
return;
}
}
}
function activateLink(hash) {
if (prevActiveLink) {
prevActiveLink.classList.remove('active');
}
if (hash !== null) {
prevActiveLink = container.value.querySelector(`a[href="${decodeURIComponent(hash)}"]`);
}
const activeLink = prevActiveLink;
if (activeLink) {
activeLink.classList.add('active');
marker.value.style.top = activeLink.offsetTop + 5 + 'px';
marker.value.style.opacity = '1';
}
else {
marker.value.style.top = '33px';
marker.value.style.opacity = '0';
}
if (prevActiveLink) {
prevActiveLink.classList.remove('active');
}
if (hash !== null) {
prevActiveLink = container.value.querySelector(`a[href="${decodeURIComponent(hash)}"]`);
}
const activeLink = prevActiveLink;
if (activeLink) {
activeLink.classList.add('active');
marker.value.style.top = activeLink.offsetTop + 5 + 'px';
marker.value.style.opacity = '1';
} else {
marker.value.style.top = '33px';
marker.value.style.opacity = '0';
}
}
}
@@ -75,13 +74,13 @@ function getAnchorTop(anchor) {
function isAnchorActive(index, anchor, nextAnchor) {
const scrollTop = window.scrollY;
if (index === 0 && scrollTop === 0) {
return [true, null];
return [true, null];
}
if (scrollTop < getAnchorTop(anchor)) {
return [false, null];
return [false, null];
}
if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) {
return [true, anchor.hash];
return [true, anchor.hash];
}
return [false, null];
}
@@ -1,12 +1,10 @@
import {
ref, inject, Ref
} from 'vue';
import { ref, inject, Ref } from 'vue';
export const CATEGORY_VIEW_CONTEXT = Symbol('categoryView');
interface CategoryViewContext {
selectedCategory: Ref<string>
categoryCounts: Ref<Record<string, number>>
selectedCategory: Ref<string>;
categoryCounts: Ref<Record<string, number>>;
}
export const categoryViewContext = {
@@ -1,8 +1,8 @@
import { ref } from "vue";
import { ref } from 'vue';
export default function useConfetti() {
const animate = ref(false)
const confettiText = ref('confetti!')
const animate = ref(false);
const confettiText = ref('confetti!');
function confetti() {
animate.value = true;
@@ -15,6 +15,6 @@ export default function useConfetti() {
return {
animate,
confetti,
confettiText
}
confettiText,
};
}
@@ -1,12 +1,12 @@
import { useFetch } from "@vueuse/core"
import { useFetch } from '@vueuse/core';
const useFetchCategories = () => useFetch<Record<string, string[]>>(
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/categories`,
{
immediate:
typeof window !== 'undefined'
&& new URLSearchParams(window.location.search).has('search'),
}
).json()
const useFetchCategories = () =>
useFetch<Record<string, string[]>>(
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/categories`,
{
immediate:
typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('search'),
},
).json();
export default useFetchCategories
export default useFetchCategories;
@@ -1,12 +1,12 @@
import { useFetch } from "@vueuse/core"
import { useFetch } from '@vueuse/core';
const useFetchTags = () => useFetch<Record<string, string[]>>(
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/tags`,
{
immediate:
typeof window !== 'undefined'
&& new URLSearchParams(window.location.search).has('search'),
}
).json()
const useFetchTags = () =>
useFetch<Record<string, string[]>>(
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/tags`,
{
immediate:
typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('search'),
},
).json();
export default useFetchTags
export default useFetchTags;

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