Compare commits

...

38 Commits

Author SHA1 Message Date
Jamie Law
0f732b411d feat(icons): added hd icon (#2958)
* Add `hd` icon

* Update hd.svg

* Update hd.json

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-10 13:56:10 +01:00
Eric Fennis
ce09c31f08 Merge branch 'main' of https://github.com/lucide-icons/lucide 2025-12-10 13:12:58 +01:00
Eric Fennis
c2b059fb60 ci(release.yml): Remove deprecated token assignment 2025-12-10 13:12:55 +01:00
Peter Uithoven
b3c80d027a feat(icons): added balloon icon (#2519)
* Added icons/balloon.svg

* Added icons/balloon.json

* Updated icons/balloon.svg

* Optimize paths

* Update tags

---------

Co-authored-by: peteruithoven <peter@metabolic.nl>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-10 13:07:01 +01:00
Eric Fennis
20f30bb5ea Merge branch 'main' of https://github.com/lucide-icons/lucide 2025-12-10 13:05:38 +01:00
Eric Fennis
c47ae67a3b ci(ci.yml): Apply env variables 2025-12-10 13:05:34 +01:00
Nathan De Pachtere
7866a5a5c6 feat(icons): added circle-pile icon (#3681)
* Added icons/circle-pile.svg

* Added icons/circle-pile.json

* Add tags

* Reduce high
2025-12-10 12:58:51 +01:00
Eric Fennis
92bc88b001 ci(ci.yml): Fix latest tag from steps and remove superfluous steps 2025-12-10 12:58:06 +01:00
Eric Fennis
e75fbcdec4 feat(icons): Add cloud-sync and cloud-backup (#3466)
* Add icons

* Update cloud-backup.json

* Update cloud-sync.json

* Format code

---------

Co-authored-by: Karsa <contact@karsa.org>
2025-12-10 12:49:56 +01:00
Eric Fennis
4cef8283a7 ci(ci.yml): Fix LATEST_TAG assignment 2025-12-10 12:49:24 +01:00
Wiktor Żagiel
330f4b37db feat(icons): add search-error icon (#3292)
* feat(icons): add `search-error` icon

* Update icons/search-error.svg

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

* Update icons/search-error.json

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

* chore(icons): rename `search-error` to `search-alert`

* Fix indentation contributors in search-alert.json

* Format code

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-10 11:33:12 +01:00
Sage Fennel
fd31cb44a8 docs(dev): Fix code sample for vanilla JS (#3836)
* Fix code sample for vanilla JS

The .append method of elements takes plain text, not HTML. This updates the code to use .insertAdjacentHTML instead.

* Update createLabCodeExamples.ts

* fix(site): update createCodeExamples.ts vanilla JS code example

* Update createLabCodeExamples.ts

* Update createCodeExamples.ts

* Update createCodeExamples.ts

---------

Co-authored-by: Karsa <contact@karsa.org>
2025-12-10 11:18:57 +01:00
Juan Isidoro García Cifuentes
790d30dbfa feat(icons): added layers-plus icon (#3367)
* Added icons/layers-plus.svg

* Added icons/layers-plus.json

* Update layers-plus.json

fix: updated contributors to reflect actual author

* fix(icon): update layers-plus icon to follow size and spacing guidelines

* fix(icon): adjust layers-plus plus sign alignment and slope

* fix(icon): apply optimized version from reviewer to align on grid and spacing

* chore: add karsa-mistmere as contributor

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-10 11:13:25 +01:00
Karsa
e7c075785f fix(icons): changed tickets icon (#3859)
* Updated icons/tickets.svg

* Updated icons/tickets.json

* Updated icons/tickets-plane.svg

* Updated icons/tickets-plane.json
2025-12-10 11:10:26 +01:00
Ian Jones
6d4c91707d fix(icons): Swap thumbs-up thumbs-down paths to fix fill issue (#3873)
* Swap thumbs-up.svg paths

* Swap thumbs-down.svg paths
2025-12-10 11:09:27 +01:00
Jakob Guddas
c0ea92ebe7 fix(icons): changed brush-cleaning icon (#3863)
* Updated icons/brush-cleaning.svg

* Updated icons/brush-cleaning.json
2025-12-10 11:08:55 +01:00
Jakob Guddas
42dc5508dd fix(icons): changed paint-bucket icon (#3865)
* Updated icons/paint-bucket.svg

* Updated icons/paint-bucket.svg
2025-12-10 11:07:50 +01:00
Eric Fennis
4dda432471 chore(repo): Update Node version and overal cleanup (#3861)
* update ci script

* Update ci workflow

* Update node version
2025-12-10 11:06:48 +01:00
Karsa
0775d8647e fix(site): only show search placeholder if there aren't any results 2025-12-10 08:50:17 +01:00
Karsa
83ef8fc98d fix(icons): changed microchip icon (#3018)
* [github] Added issue template forms

* [github] yaml => yml

* Syntax fixes

* Further syntax fixes

* Sort issue templates

* Update 02_bug_report.yml

* Updated icons/microchip.svg

---------

Co-authored-by: Karsa <karsa@karsa.org>
2025-12-09 15:47:57 +01:00
Karsa
5b56ef705d fix(icons): changed memory-stick icon (#3017)
* [github] Added issue template forms

* [github] yaml => yml

* Syntax fixes

* Further syntax fixes

* Sort issue templates

* Update 02_bug_report.yml

* Updated icons/memory-stick.svg

* Update memory-stick.svg

---------

Co-authored-by: Karsa <karsa@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-09 15:46:35 +01:00
Karsa
dafe529892 fix: fixed linting issues introduced in c4e5730bc4 (#3858) 2025-12-05 15:21:00 +01:00
Ahmed Dghaies
151c5b145c feat(icons): added van icon (#3821)
* Add van icon

* update tags

* edit icon

* edit contributors

* Update icons/van.json

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

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-05 14:35:58 +01:00
Eric Fennis
d6f9043096 style(ci): Format ci.yml 2025-12-05 14:32:32 +01:00
Karsa
b4405f05ab feat(site): add brand stop words to icon search (#3824)
* feat(site): added extended no results placeholder with brand icon stop words

* feat(site): fix grammatical error

* feat: extract brand stopwords & update github action to use these stopwords

* Apply suggestions from code review

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

* feat: only use icon name section for closing brand request issues

* feat: added mcp brand stopword

---------

Co-authored-by: Jakob Guddas <github@jguddas.de>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-12-05 14:18:46 +01:00
Jakob Guddas
9076da5f1b fix(icons): changed bubbles icon (#3774)
* Updated icons/bubbles.svg

* Updated icons/bubbles.svg

* Updated icons/bubbles.json
2025-12-05 13:46:42 +01:00
Jamie Law
2e7d806282 fix(icons): changed flashlight icons (#3843)
* Update flashlight.svg

Arcified ends and adjusted the tapering

* Update flashlight-off.svg

Update to match `flashlight.svg`

* Update flashlight.json

Added attribution and tags

* Update flashlight-off.json

* Update flashlight.svg

Correctly round bottom corners

* Update flashlight-off.svg
2025-12-05 09:53:31 +01:00
Eric Fennis
c4e5730bc4 fix(workflow): Fix permissions release worklfow 2025-12-05 09:27:34 +01:00
Nathan De Pachtere
02b35e2518 feat(icons): added estimated-weight icon (#3822)
* Added icons/estimated-weight.svg

* Added icons/estimated-weight.json

* Update icons/estimated-weight.json

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

* Change name + reshape tilde

* Change name to weight-tilde

* Update weight-tilde.json

removed weight and tilde, since they're part of the name

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karsa <contact@karsa.org>
2025-12-05 09:18:42 +01:00
Jakob Guddas
f183c3ba20 feat(preview-comment): add symmetry preview (#3823) 2025-12-05 09:11:17 +01:00
Eden Yemini
67e9efb801 fix(icons): Shrink square-scissors icons to match optical volume (#3603)
* Update square-scissors to match optical volume

* Update square-bottom-dashed-scissors to match optical volume

---------

Co-authored-by: Karsa <contact@karsa.org>
2025-12-03 13:26:43 +01:00
Jakob Guddas
2e4c9a65be fix(icons): changed thermometer-sun icon (#3773)
* Updated icons/thermometer-sun.svg

* Updated icons/thermometer-sun.json

* Modify SVG paths in thermometer-sun icon
2025-12-03 13:01:26 +01:00
Jamie Law
de4e8d0acd fix(icons): changed plug icon (#3841)
* Updated icons/plug.svg

* Updated icons/plug.json
2025-12-03 12:45:33 +01:00
Ahmed Dghaies
1f113d4274 feat(icons): added scooter icon (#3818)
* Add scooter icon

* edit tags

* edit icon

* edit icon

* deit icon

* edit icon

* edit contributors

* Update scooter.json

---------

Co-authored-by: Karsa <contact@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-11-28 14:42:51 +01:00
Eric Fennis
dffffc7aff fix: Reverts vercel output path 2025-11-27 11:06:47 +01:00
Eric Fennis
f78061b488 ci(workflows): Enable trusted publishing in release (#3808)
* Add permissions for trusted publishing to workflows

* update pnpm

* Update workflow deps

* format code
2025-11-27 10:58:14 +01:00
Eric Fennis
076e0bbcd9 chore(dependencies): Update dependencies (#3809)
* update deps

* Remove ignoredBuiltDependencies

* Fix build errors

* try this

* update config

* add coma

* Try this

* Revert import change

* try this

* add wasm import

* Load wasm

* try this

* Revert nitro version change

* Revert nitro config change
2025-11-27 10:50:19 +01:00
Muhammad Aqib Bashir
33bb95edcd feat(icon): add book-search icon (#3573) (#3580)
* feat(icon): add book-search icon

* fix(icon): fix vertical alignment of `book-search` icon  .

- Fix the vertical alignment of the icon in the 24x24 grid of pixels 
- It had 3 columns on the left side and 1 on the right side, now made 2 on both sides

* fix: remove extra tag "book search"
2025-11-26 09:29:40 +01:00
104 changed files with 4988 additions and 5285 deletions

View File

@@ -7,6 +7,10 @@ on:
paths:
- icons/**/*.svg
permissions:
id-token: write # Required for OIDC
contents: write
jobs:
create-release:
if: github.repository == 'lucide-icons/lucide' && startsWith(github.event.head_commit.message, 'feat(icons)')
@@ -15,9 +19,9 @@ jobs:
VERSION: ${{ steps.new-version.outputs.NEW_VERSION }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -32,25 +36,19 @@ jobs:
id: latest-tag
run: echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_OUTPUT
- name: Log latest tag
run: echo '${{ steps.latest-tag.outputs.LATEST_TAG }}'
- name: Check if we can patch
run: .github/workflows/version-up.sh --minor
run: pnpm semver $LATEST_TAG -i minor
env:
LATEST_TAG: ${{ steps.latest-tag.outputs.LATEST_TAG }}
- name: Create new version
id: new-version
run: echo "NEW_VERSION=$(.github/workflows/version-up.sh --minor)" >> $GITHUB_OUTPUT
- name: Create change log
id: change-log
run: |
CHANGE_LOG=$(pnpm run generate:changelog --old-tag=${{ steps.latest-tag.outputs.LATEST_TAG }})
CHANGE_LOG=$(tail -n +5 <<< $CHANGE_LOG)
echo $CHANGE_LOG
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "CHANGE_LOG<<$EOF" >> $GITHUB_OUTPUT
echo "$CHANGE_LOG" >> $GITHUB_OUTPUT
echo "$EOF" >> $GITHUB_OUTPUT
run: echo "NEW_VERSION=$(pnpm semver $LATEST_TAG -i minor)" >> $GITHUB_OUTPUT
env:
GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
LATEST_TAG: ${{ steps.latest-tag.outputs.LATEST_TAG }}
- name: Check output
run: |
@@ -64,38 +62,6 @@ jobs:
name: Version ${{ steps.new-version.outputs.NEW_VERSION }}
generate_release_notes: true
test-semantic-release:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semantic Release
id: semantic
uses: cycjimmy/semantic-release-action@v4
with:
tag_format: ${version}
branches: |
['new-release-workflow']
extends: |
semantic-release-monorepo
extra_plugins: |
@semantic-release/github
@semantic-release/git
@semantic-release/release-notes-generator
conventional-changelog-conventionalcommits
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Log output
if: steps.semantic.outputs.new_release_published == 'true'
run: |
echo ${{ steps.semantic.outputs.new_release_version }}
echo ${{ steps.semantic.outputs.new_release_major_version }}
echo ${{ steps.semantic.outputs.new_release_minor_version }}
echo ${{ steps.semantic.outputs.new_release_patch_version }}
start-release:
if: github.repository == 'lucide-icons/lucide'
needs: create-release

View File

@@ -1,4 +1,4 @@
name: Close Issue with Banned Phrases
name: Close Icon Requests with Brand Terms
on:
issues:
@@ -11,25 +11,38 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Check for blocked phrases in issue title
- name: Load stopwords from JSON & check issue title & body
if: contains(github.event.issue.labels.*.name, '🙌 icon request')
run: |
ISSUE_TITLE=$(jq -r '.issue.title' "$GITHUB_EVENT_PATH")
BLOCKED_PHRASES=("twitter" "whatsapp" "logo" "google" "tiktok" "facebook" "slack" "discord" "bluesky" "spotify" "behance" "pix" "x.com" "telegram")
ISSUE_BODY=$(jq -r '.issue.body // ""' "$GITHUB_EVENT_PATH")
ICON_NAME_SECTION=$(printf '%s\n' "$ISSUE_BODY" | awk '/### Icon name/{flag=1; next} /^### /{flag=0} flag')
# Check title and body for blocked phrases
for PHRASE in "${BLOCKED_PHRASES[@]}"
do
if echo "$ISSUE_TITLE" | grep -i "$PHRASE"; then
gh issue close ${{ github.event.issue.number }} --reason "not planned" --comment "This looks like a duplicate, use the [search](https://github.com/lucide-icons/lucide/issues?q=is%3Aissue+$PHRASE) to find similar issues.
jq -r 'to_entries[] | "\(.key) \(.value)"' brand-stopwords.json | while read -r KEY VALUE; do
SAFE_KEY=$(printf '%s\n' "$KEY" | sed 's/[][\.^$*]/\\&/g')
SAFE_VALUE=$(printf '%s\n' "$VALUE" | sed 's/[][\.^$*]/\\&/g')
Read [our official statement about brand logos in Lucide](https://github.com/lucide-icons/lucide/blob/main/BRAND_LOGOS_STATEMENT.md).
if echo "$ISSUE_TITLE" | grep -iqE "$SAFE_KEY|$SAFE_VALUE" || \
{ [ -n "$ICON_NAME_SECTION" ] && echo "$ICON_NAME_SECTION" | grep -iqE "$SAFE_KEY|$SAFE_VALUE"; }; then
gh issue close ${{ github.event.issue.number }} \
--reason "not_planned" \
--comment "It looks like this request is about **${VALUE}**, which is a brand logo.
Lucide **does not accept** brand logos, and we do not plan to add them in the future. This is due to a combination of **legal restrictions**, **design consistency concerns**, and **practical maintenance reasons**.
[Click here to read our official statement about brand logos in Lucide.](./BRAND_LOGOS_STATEMENT.md)
You can [search for similar issues.](https://github.com/lucide-icons/lucide/issues?q=is%3Aissue+${VALUE})
Were always happy to help on [Discord](https://discord.gg/EH6nSts)."
Always happy to help on [Discord](https://discord.gg/EH6nSts)."
gh issue lock ${{ github.event.issue.number }} --reason spam
exit 1
exit 0
fi
done
env:
GH_TOKEN: ${{ github.token }}
env:
GH_TOKEN: ${{ github.token }}

View File

@@ -9,5 +9,5 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/labeler@v5

View File

@@ -9,9 +9,9 @@ jobs:
lint-code:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,8 +13,8 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: 'package.json'
- name: Get changed files
@@ -34,6 +34,6 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Check Uniqueness of Aliases
run: "! cat <(printf \"%s\\n\" icons/*.json | while read -r name; do basename \"$name\" .json; done) <(jq -cr 'select(.aliases) | .aliases[] | if type==\"string\" then . else .name end' icons/*.json) | sort | uniq -c | grep -ve '^\\s*1 '"

View File

@@ -11,9 +11,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -27,9 +27,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -12,9 +12,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version-file: 'package.json'
cache: 'pnpm'

View File

@@ -10,9 +10,9 @@ jobs:
lucide-font:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
lucide-preact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -29,9 +29,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -14,9 +14,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -30,9 +30,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -10,9 +10,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -29,9 +29,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -11,9 +11,9 @@ jobs:
lucide-static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -29,9 +29,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -29,9 +29,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -13,9 +13,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -29,9 +29,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -12,9 +12,9 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -28,9 +28,9 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -14,8 +14,8 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: 'package.json'
@@ -25,7 +25,7 @@ jobs:
with:
files: icons/*.svg
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
- name: Install svgson for code preview (safer and faster than installing all deps)
run: npm install svgson@5.3.1 --force

View File

@@ -16,11 +16,11 @@ jobs:
steps:
# We checkout the main branch of main repository for security reasons.
# This is to prevent the workflow from running on a forked repository.
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
repository: lucide-icons/lucide
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'

View File

@@ -18,9 +18,13 @@ on:
description: Version
required: true
permissions:
id-token: write # Required for OIDC
contents: write
jobs:
pre-release:
if: github.repository == 'lucide-icons/lucide' && contains('["ericfennis", "karsa-mistmere"]', github.actor)
if: github.repository == 'lucide-icons/lucide' && contains('["ericfennis", "karsa-mistmere", "jguddas"]', github.actor)
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.get_version.outputs.VERSION }}
@@ -39,7 +43,8 @@ jobs:
runs-on: ubuntu-latest
needs: pre-release
permissions:
id-token: write
id-token: write # Required for OIDC
contents: read
strategy:
fail-fast: false
matrix:
@@ -57,9 +62,9 @@ jobs:
'@lucide/svelte',
]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -67,9 +72,6 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Set Auth Token
run: npm config set //registry.npmjs.org/:_authToken ${{ inputs.NPM_TOKEN || secrets.NPM_TOKEN }}
- name: Set new version
run: pnpm --filter ${{ matrix.package }} version --new-version ${{ needs.pre-release.outputs.VERSION }} --no-git-tag-version
@@ -89,12 +91,14 @@ jobs:
runs-on: ubuntu-latest
needs: [pre-release, lucide-font]
permissions:
id-token: write
id-token: write # Required for OIDC
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/download-artifact@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -102,9 +106,6 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Set Auth Token
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
- name: Set new version
run: pnpm --filter lucide-static version --new-version ${{ needs.pre-release.outputs.VERSION }} --no-git-tag-version
@@ -124,9 +125,9 @@ jobs:
runs-on: ubuntu-latest
needs: pre-release
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
cache: 'pnpm'
node-version-file: 'package.json'
@@ -150,9 +151,11 @@ jobs:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: [pre-release, lucide-font]
permissions:
id-token: write # Required for OIDC
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/download-artifact@v4
- name: Zip font and icons
run: |

View File

@@ -2,7 +2,8 @@ name: 'Request Review'
on:
pull_request_target:
types: [opened]
paths: icons/*.svg
paths:
- icons/*.svg
jobs:
request-review:
@@ -12,7 +13,7 @@ jobs:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: refs/pull/${{ github.event.pull_request.number }}/merge

View File

@@ -1,284 +0,0 @@
#!/usr/bin/env bash
## Copyright (C) 2017, Oleksandr Kucherenko
## Last revisit: 2017-09-29
## get highest version tag for all branches
function highest_tag(){
local TAG=$(git describe --tags `git rev-list --tags --max-count=1`)
echo "$TAG"
}
## extract current branch name
function current_branch(){
## expected: heads/{branch_name}
## expected: {branch_name}
local BRANCH=$(git rev-parse --abbrev-ref HEAD | cut -d"/" -f2)
echo "$BRANCH"
}
## get latest/head commit hash number
function head_hash(){
local COMMIT_HASH=$(git rev-parse --verify HEAD)
echo "$COMMIT_HASH"
}
## extract tag commit hash code, tag name provided by argument
function tag_hash(){
local TAG_HASH=$(git log -1 --format=format:"%H" $1 2>/dev/null | tail -n1)
echo "$TAG_HASH"
}
## get latest revision number
function latest_revision(){
local REV=$(git rev-list --count HEAD 2>/dev/null)
echo "$REV"
}
## parse last found tag, extract it PARTS
function parse_last(){
local position=$(($1-1))
# two parts found only
local SUBS=( ${PARTS[$position]//-/ } )
#echo ${SUBS[@]}, size: ${#SUBS}
# found NUMBER
PARTS[$position]=${SUBS[0]}
#echo ${PARTS[@]}
# found SUFFIX
if [[ ${#SUBS} -ge 1 ]]; then
PARTS[4]=${SUBS[1],,} #lowercase
#echo ${PARTS[@]}, ${SUBS[@]}
fi
}
## increment REVISION part, don't touch STAGE
function increment_revision(){
PARTS[3]=$(( PARTS[3] + 1 ))
IS_DIRTY=1
}
## increment PATCH part, reset all other lower PARTS, don't touch STAGE
function increment_patch(){
PARTS[2]=$(( PARTS[2] + 1 ))
PARTS[3]=0
IS_DIRTY=1
}
## increment MINOR part, reset all other lower PARTS, don't touch STAGE
function increment_minor(){
PARTS[1]=$(( PARTS[1] + 1 ))
PARTS[2]=0
PARTS[3]=0
IS_DIRTY=1
}
## increment MAJOR part, reset all other lower PARTS, don't touch STAGE
function incremet_major(){
PARTS[0]="v$(( PARTS[0] + 1 ))"
PARTS[1]=0
PARTS[2]=0
PARTS[3]=0
IS_DIRTY=1
}
## increment the number only of last found PART: REVISION --> PATCH --> MINOR. don't touch STAGE
function increment_last_found(){
if [[ "${#PARTS[3]}" == 0 || "${PARTS[3]}" == "0" ]]; then
if [[ "${#PARTS[2]}" == 0 || "${PARTS[2]}" == "0" ]]; then
increment_minor
else
increment_patch
fi
else
increment_revision
fi
# stage part is not EMPTY
if [[ "${#PARTS[4]}" != 0 ]]; then
IS_SHIFT=1
fi
}
## compose version from PARTS
function compose(){
MAJOR="${PARTS[0]}"
MINOR=".${PARTS[1]}"
PATCH=".${PARTS[2]}"
REVISION=".${PARTS[3]}"
SUFFIX="-${PARTS[4]}"
if [[ "${#PATCH}" == 1 ]]; then # if empty {PATCH}
PATCH=""
fi
if [[ "${#REVISION}" == 1 ]]; then # if empty {REVISION}
REVISION=""
fi
if [[ "${PARTS[3]}" == "0" ]]; then # if revision is ZERO
REVISION=""
fi
# shrink patch and revision
if [[ -z "${REVISION// }" ]]; then
if [[ "${PARTS[2]}" == "0" ]]; then
PATCH=".0"
fi
else # revision is not EMPTY
if [[ "${#PATCH}" == 0 ]]; then
PATCH=".0"
fi
fi
# remove suffix if we don't have a alpha/beta/rc
if [[ "${#SUFFIX}" == 1 ]]; then
SUFFIX=""
fi
echo "${MAJOR}${MINOR}${PATCH}${REVISION}${SUFFIX}" #full format
}
# initial version used for repository without tags
INIT_VERSION=0.0.0.0-alpha
# do GIT data extracting
TAG=$(highest_tag)
REVISION=$(latest_revision)
BRANCH=$(current_branch)
TAG_HASH=$(tag_hash $TAG)
HEAD_HASH=$(head_hash)
# if tag and branch commit hashes are different, than print info about that
#echo $HEAD_HASH vs $TAG_HASH
if [[ "$@" == "" ]]; then
if [[ "$TAG_HASH" == "$HEAD_HASH" ]]; then
echo "Tag $TAG and HEAD are aligned. We will stay on the TAG version."
echo ""
NO_ARGS_VALUE='--stay'
else
PATTERN="^[0-9]+.[0-9]+(.[0-9]+)*(-(alpha|beta|rc))*$"
if [[ "$BRANCH" =~ $PATTERN ]]; then
echo "Detected version branch '$BRANCH'. We will auto-increment the last version PART."
echo ""
NO_ARGS_VALUE='--default'
else
echo "Detected branch name '$BRANCH' than does not match version pattern. We will increase MINOR."
echo ""
NO_ARGS_VALUE='--minor'
fi
fi
fi
#
# {MAJOR}.{MINOR}[.{PATCH}[.{REVISION}][-(.*)]
#
# Suffix: alpha, beta, rc
# No Suffix --> {NEW_VERSION}-alpha
# alpha --> beta
# beta --> rc
# rc --> {VERSION}
#
PARTS=( ${TAG//./ } )
parse_last ${#PARTS[@]} # array size as argument
#echo ${PARTS[@]}
# if no parameters than emulate --default parameter
if [[ "$@" == "" ]]; then
set -- $NO_ARGS_VALUE
fi
# parse input parameters
for i in "$@"
do
key="$i"
case $key in
-a|--alpha) # switched to ALPHA
PARTS[4]="alpha"
IS_SHIFT=1
;;
-b|--beta) # switched to BETA
PARTS[4]="beta"
IS_SHIFT=1
;;
-c|--release-candidate) # switched to RC
PARTS[4]="rc"
IS_SHIFT=1
;;
-r|--release) # switched to RELEASE
PARTS[4]=""
IS_SHIFT=1
;;
-p|--patch) # increment of PATCH
increment_patch
;;
-e|--revision) # increment of REVISION
increment_revision
;;
-g|--git-revision) # use git revision number as a revision part§
PARTS[3]=$(( REVISION ))
IS_DIRTY=1
;;
-i|--minor) # increment of MINOR by default
increment_minor
;;
--default) # stay on the same stage, but increment only last found PART of version code
increment_last_found
;;
-m|--major) # increment of MAJOR
incremet_major
;;
-s|--stay) # extract version info
IS_DIRTY=1
NO_APPLY_MSG=1
;;
-t|--tag-only) # extract version info
TAG_ONLY=1
;;
--apply)
DO_APPLY=1
;;
-h|--help)
help
;;
esac
shift
done
# detected shift, but no increment
if [[ "$IS_SHIFT" == "1" ]]; then
# temporary disable stage shift
stage=${PARTS[4]}
PARTS[4]=''
# detect first run on repository, INIT_VERSION was used
if [[ "$(compose)" == "0.0" ]]; then
increment_minor
fi
PARTS[4]=$stage
fi
# no increment applied yet and no shift of state, do minor increase
if [[ "$IS_DIRTY$IS_SHIFT" == "" ]]; then
increment_minor
fi
compose
# is proposed tag in conflict with any other TAG
PROPOSED_HASH=$(tag_hash $(compose))
if [[ "${#PROPOSED_HASH}" -gt 0 && "$NO_APPLY_MSG" == "" ]]; then
echo -e "\033[31mERROR:\033[0m "
echo -e "\033[31mERROR:\033[0m Found conflict with existing tag \033[32m$(compose)\033[0m / $PROPOSED_HASH"
echo -e "\033[31mERROR:\033[0m Only manual resolving is possible now."
echo -e "\033[31mERROR:\033[0m "
echo -e "\033[31mERROR:\033[0m To Resolve try to add --revision or --patch modifier."
echo -e "\033[31mERROR:\033[0m "
echo ""
exit 1
fi

2
.gitignore vendored
View File

@@ -44,7 +44,7 @@ docs/.vitepress/data/releaseMetaData
docs/.vitepress/data/categoriesData.json
docs/.vitepress/data/iconDetails
docs/.vitepress/data/relatedIcons.json
docs/.vitepress/data/brandStopwords.json
docs/.vercel
docs/.nitro
.gitignore

1
.npmrc
View File

@@ -1 +0,0 @@
auto-install-peers=true

149
brand-stopwords.json Normal file
View File

@@ -0,0 +1,149 @@
{
"adobe": "Adobe",
"airplay": "AirPlay",
"amazon": "Amazon",
"angular": "Angular",
"aws": "AWS",
"azure": "Azure",
"bandcamp": "Bandcamp",
"behance": "Behance",
"bitbucket": "Bitbucket",
"blender": "Blender",
"bluesky": "BlueSky",
"bootstrap": "Bootstrap",
"brave": "Brave",
"chakra": "Chakra UI",
"chrome": "Chrome",
"codepen": "Codepen",
"codesandbox": "CodeSandbox",
"csharp": "C#",
"cypress": "Cypress",
"dart": "Dart",
"deezer": "Deezer",
"deno": "Deno",
"discord": "Discord",
"docker": "Docker",
"dribbble": "Dribbble",
"dropbox": "Dropbox",
"edge": "Edge",
"ember": "Ember",
"epic": "Epic Games",
"erlang": "Erlang",
"esbuild": "esbuild",
"eslint": "ESLint",
"facebook": "Facebook",
"figjam": "FigJam",
"figma": "Figma",
"firebase": "Firebase",
"firefox": "Firefox",
"framer": "Framer",
"gatsby": "Gatsby",
"gcp": "Google Cloud",
"github": "GitHub",
"gitlab": "GitLab",
"golang": "GoLang",
"google": "Google",
"gmail": "Gmail",
"gravatar": "Gravatar",
"haskell": "Haskell",
"instagram": "Instagram",
"java": "Java",
"javascript": "JavaScript",
"jest": "Jest",
"jira": "Jira",
"kotlin": "Kotlin",
"kubernetes": "Kubernetes",
"less": "Less",
"leetcode": "LeetCode",
"leet-code": "LeetCode",
"line": "LINE",
"linkedin": "LinkedIn",
"lua": "Lua",
"mariadb": "MariaDB",
"mcp": "MCP",
"messenger": "Messenger",
"microsoft": "Microsoft",
"mongodb": "MongoDB",
"mui": "Material UI",
"mysql": "MySQL",
"nestjs": "NestJS",
"netflix": "Netflix",
"netlify": "Netlify",
"next": "Next.js",
"nodejs": "Node.js",
"notion": "Notion",
"nostr": "Nostr",
"npm": "npm",
"nuxt": "Nuxt",
"opera": "Opera",
"oracle": "Oracle",
"patreon": "Patreon",
"paypal": "PayPal",
"perl": "Perl",
"php": "PHP",
"pinterest": "Pinterest",
"pix": "PiX",
"playstation": "PlayStation",
"playwright": "Playwright",
"pnpm": "pnpm",
"postcss": "PostCSS",
"postgresql": "PostgreSQL",
"prettier": "Prettier",
"prisma": "Prisma",
"python": "Python",
"qwik": "Qwik",
"react": "React",
"reddit": "Reddit",
"redis": "Redis",
"rollup": "Rollup",
"rust": "Rust",
"safari": "Safari",
"sass": "Sass",
"scala": "Scala",
"scss": "Sass",
"semantic": "Semantic UI",
"shopify": "Shopify",
"skype": "Skype",
"slack": "Slack",
"solid": "SolidJS",
"soundcloud": "SoundCloud",
"spotify": "Spotify",
"sqlite": "SQLite",
"squarespace": "Squarespace",
"steam": "Steam",
"stripe": "Stripe",
"substack": "Substack",
"supabase": "Supabase",
"surge": "Surge",
"svelte": "Svelte",
"swift": "Swift",
"tailwind": "Tailwind CSS",
"telegram": "Telegram",
"terraform": "Terraform",
"tesla": "Tesla",
"tidal": "Tidal",
"tiktok": "TikTok",
"trello": "Trello",
"twitch": "Twitch",
"twitter": "Twitter",
"typescript": "TypeScript",
"unity": "Unity",
"unreal": "Unreal Engine",
"vercel": "Vercel",
"vimeo": "Vimeo",
"vite": "Vite",
"vitest": "Vitest",
"vue": "Vue",
"webpack": "Webpack",
"wechat": "WeChat",
"whatsapp": "WhatsApp",
"windows": "Windows",
"wix": "Wix",
"x.com": "X.com",
"x-social": "X.com",
"xbox": "Xbox",
"yarn": "Yarn",
"youtube": "YouTube",
"zig": "Zig",
"zoom": "Zoom"
}

View File

@@ -9,6 +9,7 @@ if (process.env.NODE_ENV === 'development') {
wasm = fs.readFileSync(require.resolve('@resvg/resvg-wasm/index_bg.wasm'));
} else {
// @ts-ignore
wasm = resvg_wasm;
}

View File

@@ -0,0 +1,55 @@
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
import { renderToString } from 'react-dom/server';
import { createElement } from 'react';
import Diff from '../../../lib/SvgPreview/Diff.tsx';
export default eventHandler((event) => {
const { params } = event.context;
const pathData = params.data.split('/');
const data = pathData.at(-1).slice(0, -4);
const [operation] = pathData;
const newSrc = Buffer.from(data, 'base64')
.toString('utf8')
.replaceAll('\n', '')
.replace(/<svg[^>]*>|<\/svg>/g, '');
const width = parseInt(
(newSrc.includes('<svg ') ? newSrc.match(/width="(\d+)"/)?.[1] : null) ?? '24',
);
const height = parseInt(
(newSrc.includes('<svg ') ? newSrc.match(/height="(\d+)"/)?.[1] : null) ?? '24',
);
const children = [];
let oldSrc = '';
if (operation.startsWith('rotate-')) {
const degrees = parseInt(operation.replace('rotate-', ''));
if (isNaN(degrees)) return '';
oldSrc = `<g transform="rotate(${degrees} ${width / 2} ${height / 2})">${newSrc}</g>`;
} else if (operation === 'flip-horizontal') {
oldSrc = `<g transform="scale(1, -1) translate(0, -${height})">${newSrc}</g>`;
} else if (operation === 'flip-vertical') {
oldSrc = `<g transform="scale(-1, 1) translate(-${width}, 0)">${newSrc}</g>`;
} else if (operation === 'flip-backslash') {
oldSrc = `<g transform="rotate(90, ${width / 2}, ${height / 2}) scale(1, -1) translate(0, -${height})">${newSrc}</g>`;
} else if (operation === 'flip-slash') {
oldSrc = `<g transform="rotate(90, ${width / 2}, ${height / 2}) scale(-1, 1) translate(-${width}, 0)">${newSrc}</g>`;
} else {
return '';
}
const svg = Buffer.from(
// We can't use jsx here, is not supported here by nitro.
renderToString(
createElement(Diff, { oldSrc, newSrc, showGrid: true, height, width }, children),
),
).toString('utf8');
defaultContentType(event, 'image/svg+xml');
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
return svg;
});

View File

@@ -1,4 +1,4 @@
import { bundledLanguages, getHighlighter, type ThemeRegistration } from 'shikiji';
import { bundledLanguages, createHighlighter, type ThemeRegistration } from 'shiki';
type CodeExampleType = {
title: string;
@@ -9,14 +9,20 @@ type CodeExampleType = {
const getIconCodes = (): CodeExampleType => {
return [
{
language: 'js',
language: 'html',
title: 'Vanilla',
code: `\
import { createIcons, icons } from 'lucide';
<script>
import { createIcons, $CamelCase } from 'lucide';
createIcons({ icons });
createIcons({
icons: {
$CamelCase
}
});
</script>
document.body.append('<i data-lucide="$Name"></i>');\
<i data-lucide="$Name"></i>\
`,
},
{
@@ -112,7 +118,7 @@ export type ThemeOptions =
| { light: ThemeRegistration; dark: ThemeRegistration };
const highLightCode = async (code: string, lang: string, active?: boolean) => {
const highlighter = await getHighlighter({
const highlighter = await createHighlighter({
themes: ['github-light', 'github-dark'],
langs: Object.keys(bundledLanguages),
});

View File

@@ -1,5 +1,5 @@
import { bundledLanguages, type ThemeRegistration } from 'shikiji';
import { getHighlighter } from 'shikiji';
import { bundledLanguages, type ThemeRegistration } from 'shiki';
import { createHighlighter } from 'shiki';
type CodeExampleType = {
title: string;
@@ -10,10 +10,11 @@ type CodeExampleType = {
const getIconCodes = (): CodeExampleType => {
return [
{
language: 'js',
language: 'html',
title: 'Vanilla',
code: `\
import { createIcons, icons } from 'lucide';
<script>
import { createIcons } from 'lucide';
import { $CamelCase } from '@lucide/lab';
createIcons({
@@ -21,8 +22,9 @@ createIcons({
$CamelCase
}
});
</script>
document.body.append('<i data-lucide="$Name"></i>');\
<i data-lucide="$Name"></i>\
`,
},
{
@@ -119,7 +121,7 @@ export type ThemeOptions =
| { light: ThemeRegistration; dark: ThemeRegistration };
const highLightCode = async (code: string, lang: string, active?: boolean) => {
const highlighter = await getHighlighter({
const highlighter = await createHighlighter({
themes: ['github-light', 'github-dark'],
langs: Object.keys(bundledLanguages),
});

View File

@@ -1,12 +1,12 @@
import { bundledLanguages, type ThemeRegistration } from 'shikiji';
import { getHighlighter } from 'shikiji';
import { bundledLanguages, type ThemeRegistration } from 'shiki';
import { createHighlighter } from 'shiki';
export type ThemeOptions =
| ThemeRegistration
| { light: ThemeRegistration; dark: ThemeRegistration };
const highLightCode = async (code: string, lang: string, active?: boolean) => {
const highlighter = await getHighlighter({
const highlighter = await createHighlighter({
themes: ['github-light', 'github-dark'],
langs: Object.keys(bundledLanguages),
});

View File

@@ -1,19 +1,19 @@
<script setup lang="ts">
import { ref, computed, defineAsyncComponent, onMounted, watch, watchEffect } 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 useSearchShortcut from '../../utils/useSearchShortcut';
import StickyBar from './StickyBar.vue';
import IconsCategory from './IconsCategory.vue';
import IconsCategory, { CategoryRow } from './IconsCategory.vue';
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';
import CarbonAdOverlay from './CarbonAdOverlay.vue';
import useSearchPlaceholder from '../../utils/useSearchPlaceholder.ts';
const ICON_SIZE = 56;
const ICON_GRID_GAP = 8;
@@ -40,10 +40,10 @@ const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categoriesMap } = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl)
const { width: containerWidth } = useElementSize(overviewEl);
const columnSize = computed(() => {
return Math.floor((containerWidth.value) / ((ICON_SIZE + ICON_GRID_GAP)));
return Math.floor(containerWidth.value / (ICON_SIZE + ICON_GRID_GAP));
});
const mappedIcons = computed(() => {
@@ -71,26 +71,27 @@ const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
const categories = computed(() => {
if (!props.categories?.length || !props.icons?.length) return [];
return props.categories
.map(({ name, title }) => {
const categoryIcons = props.icons.filter((icon) => {
const iconCategories = icon?.externalLibrary ? icon.categories : props.iconCategories[icon.name]
return props.categories.map(({ name, title }) => {
const categoryIcons = props.icons.filter((icon) => {
const iconCategories = icon?.externalLibrary
? icon.categories
: props.iconCategories[icon.name];
return iconCategories?.includes(name);
});
return iconCategories?.includes(name);
});
const searchedCategoryIcons = isSearching
? categoryIcons.filter((icon) =>
searchResults.value.some((item) => item?.name === icon?.name)
)
: categoryIcons;
const searchedCategoryIcons = isSearching
? categoryIcons.filter((icon) =>
searchResults.value.some((item) => item?.name === icon?.name),
)
: categoryIcons;
return {
title,
name,
icons: searchedCategoryIcons,
};
})
return {
title,
name,
icons: searchedCategoryIcons,
};
});
});
const categoriesList = computed(() => {
@@ -107,26 +108,24 @@ const categoriesList = computed(() => {
return acc;
}, []);
});
const searchPlaceholder = useSearchPlaceholder(searchQuery, searchResults);
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
categoriesList,
{
itemHeight: ICON_SIZE + ICON_GRID_GAP,
overscan: 10
},
)
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)
})
useEventListener(window, 'scroll', containerProps.onScroll);
});
function onFocusSearchInput() {
if (tags.value == null) {
@@ -145,16 +144,13 @@ function handleCloseDrawer() {
window.history.pushState({}, '', '/icons/categories');
}
watchEffect(() => {
console.log(props.icons.find((icon) => icon.name === 'burger'));
});
</script>
<template>
<div ref="overviewEl" class="overview-container">
<div
ref="overviewEl"
class="overview-container"
>
<StickyBar class="category-search">
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
@@ -166,8 +162,9 @@ watchEffect(() => {
/>
</StickyBar>
<NoResults
v-if="categories.length === 0"
:searchQuery="searchQuery"
v-if="searchPlaceholder.isNoResults"
:searchQuery="searchPlaceholder.query"
:isBrandSearch="searchPlaceholder.isBrand"
@clear="searchQuery = ''"
/>
<div v-bind="wrapperProps">
@@ -208,8 +205,4 @@ watchEffect(() => {
.icons {
margin-bottom: 8px;
}
.overview-container {
padding-bottom: 288px;
}
</style>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, defineAsyncComponent, onMounted, onBeforeUnmount, watch } from 'vue';
import { ref, computed, defineAsyncComponent, onMounted, watch } from 'vue';
import type { IconEntity } from '../../types';
import { useElementSize, useEventListener, useVirtualList } from '@vueuse/core';
import { useRoute } from 'vitepress';
@@ -13,17 +13,18 @@ import useFetchTags from '../../composables/useFetchTags';
import useFetchCategories from '../../composables/useFetchCategories';
import chunkArray from '../../utils/chunkArray';
import CarbonAdOverlay from './CarbonAdOverlay.vue';
import useSearchPlaceholder from '../../utils/useSearchPlaceholder.ts';
const ICON_SIZE = 56;
const ICON_GRID_GAP = 8;
const initialGridItems = computed(() => {
if (containerWidth.value === 0) return 120;
const itemsPerRow = columnSize.value || 10;
const visibleRows = Math.ceil(window.innerHeight / (ICON_SIZE + ICON_GRID_GAP));
return Math.min(itemsPerRow * (visibleRows + 2), 200);
return Math.min(itemsPerRow * (visibleRows + 2), 200);
});
const props = defineProps<{
@@ -36,10 +37,10 @@ const { execute: fetchTags, data: tags } = useFetchTags();
const { execute: fetchCategories, data: categories } = useFetchCategories();
const overviewEl = ref<HTMLElement | null>(null);
const { width: containerWidth } = useElementSize(overviewEl)
const { width: containerWidth } = useElementSize(overviewEl);
const columnSize = computed(() => {
return Math.floor((containerWidth.value) / ((ICON_SIZE + ICON_GRID_GAP)));
return Math.floor(containerWidth.value / (ICON_SIZE + ICON_GRID_GAP));
});
const mappedIcons = computed(() => {
@@ -71,29 +72,27 @@ const searchResults = useSearch(searchQueryDebounced, mappedIcons, [
{ name: 'tags', weight: 2 },
{ name: 'categories', weight: 1 },
]);
const searchPlaceholder = useSearchPlaceholder(searchQuery, searchResults);
const chunkedIcons = computed(() => {
return chunkArray(searchResults.value, columnSize.value);
});
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
chunkedIcons,
{
itemHeight: ICON_SIZE + ICON_GRID_GAP,
overscan: 10
},
)
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)
useEventListener(window, 'scroll', containerProps.onScroll);
// Check if we should focus the search input from URL parameter
const route = useRoute()
const route = useRoute();
if (route.data?.relativePath && window.location.search.includes('focus')) {
searchInput.value?.focus()
searchInput.value?.focus();
}
})
});
function setActiveIconName(name: string) {
activeIconName.value = name;
@@ -113,8 +112,8 @@ const NoResults = defineAsyncComponent(() => import('./NoResults.vue'));
const IconDetailOverlay = defineAsyncComponent(() => import('./IconDetailOverlay.vue'));
watch(searchQueryDebounced, () => {
scrollTo(0)
})
scrollTo(0);
});
function handleCloseDrawer() {
setActiveIconName('');
@@ -124,7 +123,10 @@ function handleCloseDrawer() {
</script>
<template>
<div ref="overviewEl" class="overview-container">
<div
ref="overviewEl"
class="overview-container"
>
<StickyBar>
<InputSearch
:placeholder="`Search ${icons.length} icons ...`"
@@ -136,8 +138,9 @@ function handleCloseDrawer() {
/>
</StickyBar>
<NoResults
v-if="searchResults.length === 0 && searchQuery !== ''"
:searchQuery="searchQuery"
v-if="searchPlaceholder.isNoResults"
:searchQuery="searchPlaceholder.query"
:isBrandSearch="searchPlaceholder.isBrand"
@clear="searchQuery = ''"
/>
<IconGrid
@@ -183,8 +186,4 @@ function handleCloseDrawer() {
.input-wrapper {
width: 100%;
}
.overview-container {
padding-bottom: 288px;
}
</style>

View File

@@ -1,56 +1,218 @@
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { bird, squirrel, rabbit } from '../../../data/iconNodes'
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon'
import {useEventListener} from '@vueuse/core'
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue'
import { IconNode } from '../../types'
import { ref, onMounted, computed, markRaw, shallowReadonly, watch } from 'vue';
import {
bird,
squirrel,
rabbit,
ghost,
castle,
drama,
dog,
cat,
wandSparkles,
save,
snowflake,
cake,
fish,
turtle,
rat,
worm,
testTubeDiagonal,
sword,
} from '../../../data/iconNodes';
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
import { useEventListener } from '@vueuse/core';
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue';
import { IconNode } from '../../types';
defineProps<{
searchQuery: string
}>()
const { searchQuery, isBrandSearch } = defineProps<{
searchQuery: string;
isBrandSearch: boolean;
}>();
defineEmits(['clear'])
defineEmits(['clear']);
const animalIcon = ref<HTMLElement>()
const randomAnimal = computed<IconNode>(() => {
return Math.random() > 0.5 ? squirrel : Math.random() > 0.5 ? rabbit : bird
})
const animalComponent = computed(() => createLucideIcon('animal', randomAnimal.value))
const flip = ref(false)
interface Placeholder {
title: string;
message: string;
icon: IconNode;
finePrint?: string;
}
const brandPlaceholders: Placeholder[] = shallowReadonly([
{
title: 'Boooo! What a scary brand logo!',
message:
'[name] and its friends often haunt this search box, but you wont ever find them here.',
icon: markRaw(ghost),
},
{
title: 'Thank You Mario!',
message: 'But [name] is in another castle!',
icon: markRaw(castle),
},
{
title: '[name] did audition for our icon set',
message: '...but didnt make the callback.',
icon: markRaw(drama),
},
{
title: 'Such Search. Very [name].',
message: 'Much not here. So Wow.',
icon: markRaw(dog),
},
{
title: 'I Can Has [name]?',
message: 'No [name] for you in here.',
icon: markRaw(cat),
},
{
title: 'Loading [name]...',
message: 'Fatal error: our cartridge contains only open-source pixels.',
icon: markRaw(save),
},
{
title: '[name] Shall Not Pass',
message: 'Do not look to its coming at first light of any day.',
icon: markRaw(wandSparkles),
},
{
title: 'Winter is coming',
message: 'But [name] sure isnt.',
icon: markRaw(snowflake),
},
{
title: 'The cake is a lie',
message: 'And so is the promise of an icon for [name] at Lucide.',
icon: markRaw(cake),
},
{
title: 'Its not a bug',
message: 'Having no [name] icon around is a feature.',
icon: markRaw(worm),
},
{
title: 'The lab exploded',
message: 'We tried mixing [name] with open-source icons.',
icon: markRaw(testTubeDiagonal),
},
{
title: 'Its Dangerous to Go Alone',
message: 'Take this icon instead — its not [name], but it might help.',
icon: markRaw(sword),
},
]);
const notFoundPlaceholders: Omit<Placeholder, 'title'>[] = shallowReadonly([
{
message: 'Weve looked for this icon for a birds eye view, but could not find it.',
icon: markRaw(bird),
},
{
message: 'We checked every tree. Only acorns, no results.',
icon: markRaw(squirrel),
},
{
message: 'Youve gone too deep into the rabbit hole — this icon doesnt exist.',
icon: markRaw(rabbit),
},
{
message: 'This icon seems to have slipped through the net.',
icon: markRaw(fish),
},
{
message: 'This icon might exist in the future… but it hasnt arrived yet.',
icon: markRaw(turtle),
},
{
message: 'Rats! This icon seems to have slipped through the cracks.',
icon: markRaw(rat),
},
]);
function randomItem<T>(arr: T[]): T {
return arr[Math.floor(Math.random() * arr.length)];
}
const placeholderIcon = ref<HTMLElement>();
const placeholder = ref<Placeholder>();
watch(
() => isBrandSearch,
() => {
placeholder.value = isBrandSearch
? {
...randomItem(brandPlaceholders),
finePrint:
'Lucide does not accept brand logos, and we do not plan to add them in the future. This is due to a combination of legal restrictions, design consistency concerns, and practical maintenance reasons.',
}
: {
title: `No results for “[name]”`,
finePrint:
'This icon doesnt seem to exist… yet. Try searching similar terms, browsing existing requests, or opening a new one.',
...randomItem(notFoundPlaceholders),
};
},
{ immediate: true },
);
const iconComponent = computed(() => createLucideIcon('placeholder', placeholder.value.icon));
const flip = ref(false);
onMounted(() => {
useEventListener(document, 'mousemove', (mouseEvent) => {
const {width, height, x, y} = animalIcon.value.getBoundingClientRect()
const { width, x } = placeholderIcon.value.getBoundingClientRect();
const centerX = (width / 2) + x
flip.value = mouseEvent.x < centerX
})
})
const centerX = width / 2 + x;
flip.value = !isBrandSearch && mouseEvent.x < centerX;
});
});
</script>
<template>
<div class="no-results">
<component
:is="animalComponent"
class="animal-icon"
ref="animalIcon"
:is="iconComponent"
class="placeholder-icon"
ref="placeholderIcon"
:class="{ flip }"
:strokeWidth="1"
/>
<h2 class="no-results-text">
No icons found for '{{ searchQuery }}'
</h2>
<h2 class="no-results-text">{{ placeholder.title.replace('[name]', searchQuery) }}</h2>
<p class="no-results-message">
{{ placeholder.message.replace('[name]', searchQuery) }}
</p>
<div class="divider"></div>
<p
v-if="placeholder.finePrint"
class="no-results-fine-print"
>
{{ placeholder.finePrint }}
</p>
<VPButton
text="Clear your search and try again"
theme="alt"
v-if="isBrandSearch"
text="Head over to Simple Icons"
theme="brand"
:href="`https://simpleicons.org/?q=${searchQuery}`"
target="_blank"
/>
<VPButton
v-else
text="Clear search & try again"
theme="brand"
@click="$emit('clear')"
/>
<span class="text-divider">or</span>
<VPButton
text="Search on Github issues"
v-if="isBrandSearch"
text="Read our statement on brand logos"
theme="alt"
href="https://github.com/lucide-icons/lucide/blob/main/BRAND_LOGOS_STATEMENT.md"
target="_blank"
/>
<VPButton
v-else
text="Search GitHub issues"
theme="alt"
:href="`https://github.com/lucide-icons/lucide/issues?q=is%3Aopen+${searchQuery}`"
target="_blank"
@@ -63,33 +225,38 @@ onMounted(() => {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding-block: 48px;
}
.animal-icon {
width: 160px;
height: 160px;
color: var(--vp-c-neutral);
opacity: 0.8;
margin-top: 72px;
.placeholder-icon {
width: 96px;
height: 96px;
color: var(--vp-c-text-1);
}
.animal-icon.flip {
.placeholder-icon.flip {
transform: rotateY(180deg);
}
@media (min-width: 960px) {
.animal-icon {
width: 240px;
height: 240px;
}
}
.no-results-text {
line-height: 40px;
line-height: 1.35;
font-size: 24px;
margin-top: 24px;
margin-bottom: 8px;
text-wrap: balance;
}
.no-results-message {
text-wrap: balance;
}
.no-results-fine-print {
max-inline-size: 60ch;
font-size: 14px;
margin-bottom: 32px;
text-align: center;
color: var(--vp-c-text-2);
text-wrap: balance;
}
.text-divider {
@@ -97,4 +264,10 @@ onMounted(() => {
font-size: 16px;
color: var(--vp-c-neutral);
}
.divider {
margin: 24px auto 18px;
width: 64px;
height: 1px;
background-color: var(--vp-c-divider);
}
</style>

View File

@@ -0,0 +1,41 @@
import { ref, Ref, watch } from 'vue';
import BRAND_STOPWORDS from '../../data/brandStopwords.json' with { type: 'json' };
export default function useSearchPlaceholder(
searchQuery: Ref<string, string>,
results: Ref<{ name: string }[]>,
) {
const state = ref({
isNoResults: false,
isBrand: false,
query: '',
});
watch(
results,
() => {
const query = searchQuery.value;
const searchResults = results.value;
if (query.length > 0 && searchResults.length === 0) {
for (const stopword of Object.keys(BRAND_STOPWORDS)) {
if (stopword.startsWith(query)) {
state.value = {
isNoResults: true,
isBrand: true,
query: BRAND_STOPWORDS[stopword],
};
return;
}
}
}
state.value = {
isNoResults: query in BRAND_STOPWORDS && searchResults.length === 0 && query !== '',
isBrand: query in BRAND_STOPWORDS,
query: BRAND_STOPWORDS[query] ?? query,
};
},
{ immediate: true },
);
return state;
}

View File

@@ -9,13 +9,14 @@
"docs:build": "pnpm run /^prebuild:.*/ && vitepress build",
"docs:preview": "vitepress preview",
"build:docs": "vitepress build",
"prebuild:iconNodes": "node --experimental-strip-types ./scripts/writeIconNodes.mjs",
"prebuild:metaJson": "node --experimental-strip-types ./scripts/writeIconMetaIndex.mjs",
"prebuild:releaseJson": "node --experimental-strip-types ./scripts/writeReleaseMetadata.mjs",
"prebuild:categoriesJson": "node --experimental-strip-types ./scripts/writeCategoriesMetadata.mjs",
"prebuild:relatedIcons": "node --experimental-strip-types ./scripts/writeIconRelatedIcons.mjs",
"prebuild:iconDetails": "node --experimental-strip-types ./scripts/writeIconDetails.mjs",
"postbuild:vercelJson": "node --experimental-strip-types ./scripts/writeVercelOutput.mjs",
"prebuild:iconNodes": "node ./scripts/writeIconNodes.mjs",
"prebuild:metaJson": "node ./scripts/writeIconMetaIndex.mjs",
"prebuild:releaseJson": "node ./scripts/writeReleaseMetadata.mjs",
"prebuild:categoriesJson": "node ./scripts/writeCategoriesMetadata.mjs",
"prebuild:relatedIcons": "node ./scripts/writeIconRelatedIcons.mjs",
"prebuild:iconDetails": "node ./scripts/writeIconDetails.mjs",
"prebuild:brandStopwords": "node ./scripts/writeBrandStopwords.mjs",
"postbuild:vercelJson": "node ./scripts/writeVercelOutput.mjs",
"dev": "npx nitropack dev",
"prebuild:api": "npx nitropack prepare",
"build:api": "npx nitropack build",
@@ -28,35 +29,35 @@
"@lucide/build-icons": "workspace:*",
"@lucide/helpers": "workspace:*",
"@lucide/shared": "workspace:*",
"@rollup/plugin-replace": "^6.0.2",
"@types/semver": "^7.5.3",
"@rollup/plugin-replace": "^6.0.3",
"@types/semver": "^7.7.1",
"nitropack": "2.8.1",
"rollup-plugin-copy": "^3.5.0",
"vitepress": "^1.6.3",
"svg-path-commander": "^2.1.11"
"svg-path-commander": "^2.1.11",
"vitepress": "^1.6.4"
},
"dependencies": {
"@floating-ui/vue": "^1.0.3",
"@headlessui/vue": "^1.7.17",
"@floating-ui/vue": "^1.1.9",
"@headlessui/vue": "^1.7.23",
"@resvg/resvg-wasm": "^2.6.2",
"@vueuse/components": "^12.0.0",
"@vueuse/core": "^12.0.0",
"@vueuse/components": "^14.0.0",
"@vueuse/core": "^14.0.0",
"element-to-path": "^1.2.1",
"fuse.js": "^6.5.3",
"jszip": "^3.7.0",
"lodash": "^4.17.20",
"fuse.js": "^7.1.0",
"jszip": "^3.10.1",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lucide-react": "workspace:*",
"lucide-vue-next": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"sandpack-vue3": "3.1.11",
"semver": "^7.5.2",
"shikiji": "^0.7.4",
"simple-git": "^3.18.0",
"sitemap": "^7.1.1",
"semver": "^7.7.3",
"shiki": "^3.15.0",
"simple-git": "^3.30.0",
"sitemap": "^7.1.2",
"svg-pathdata": "^6.0.3",
"svgson": "^5.2.1",
"vue": "^3.5.18"
"svgson": "^5.3.1",
"vue": "^3.5.24"
}
}

View File

@@ -0,0 +1,15 @@
import fs from 'fs/promises';
import path from 'path';
const currentDir = process.cwd();
const dataDirectory = path.resolve(currentDir, '.vitepress/data');
const stopwordsSource = path.resolve(currentDir, `../brand-stopwords.json`);
const stopwordsFile = path.resolve(dataDirectory, `brandStopwords.json`);
fs.copyFile(stopwordsSource, stopwordsFile)
.then(() => {
console.log('Successfully copied brandStopwords.json file');
})
.catch((error) => {
throw new Error(`Something went wrong generating the brandStopwords.json file,\n ${error}`);
});

22
icons/balloon.json Normal file
View File

@@ -0,0 +1,22 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"peteruithoven"
],
"tags": [
"party",
"festival",
"congratulations",
"celebration",
"decoration",
"colorful",
"floating",
"fun",
"birthday",
"event",
"entertainment"
],
"categories": [
"emoji"
]
}

15
icons/balloon.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 16v1a2 2 0 0 0 2 2h1a2 2 0 0 1 2 2v1" />
<path d="M12 6a2 2 0 0 1 2 2" />
<path d="M18 8c0 4-3.5 8-6 8s-6-4-6-8a6 6 0 0 1 12 0" />
</svg>

After

Width:  |  Height:  |  Size: 358 B

25
icons/book-search.json Normal file
View File

@@ -0,0 +1,25 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"karsa-mistmere",
"Muhammad-Aqib-Bashir"
],
"tags": [
"reading",
"library",
"study",
"education",
"research",
"knowledge",
"discover",
"browsing",
"lookup",
"finding",
"scanning"
],
"categories": [
"text",
"development",
"gaming"
]
}

16
icons/book-search.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M11 22H5.5a1 1 0 0 1 0-5h4.501" />
<path d="m21 22-1.879-1.878" />
<path d="M3 19.5v-15A2.5 2.5 0 0 1 5.5 2H18a1 1 0 0 1 1 1v8" />
<circle cx="17" cy="18" r="3" />
</svg>

After

Width:  |  Height:  |  Size: 389 B

View File

@@ -1,7 +1,8 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"karsa-mistmere"
"karsa-mistmere",
"jguddas"
],
"tags": [
"cleaning",

View File

@@ -10,7 +10,7 @@
stroke-linejoin="round"
>
<path d="m16 22-1-4" />
<path d="M19 13.99a1 1 0 0 0 1-1V12a2 2 0 0 0-2-2h-3a1 1 0 0 1-1-1V4a2 2 0 0 0-4 0v5a1 1 0 0 1-1 1H6a2 2 0 0 0-2 2v.99a1 1 0 0 0 1 1" />
<path d="M5 14h14l1.973 6.767A1 1 0 0 1 20 22H4a1 1 0 0 1-.973-1.233z" />
<path d="M19 14a1 1 0 0 0 1-1v-1a2 2 0 0 0-2-2h-3a1 1 0 0 1-1-1V4a2 2 0 0 0-4 0v5a1 1 0 0 1-1 1H6a2 2 0 0 0-2 2v1a1 1 0 0 0 1 1" />
<path d="M19 14H5l-1.973 6.767A1 1 0 0 0 4 22h16a1 1 0 0 0 .973-1.233z" />
<path d="m8 22 1-4" />
</svg>

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 470 B

View File

@@ -2,7 +2,8 @@
"$schema": "../icon.schema.json",
"contributors": [
"vqh2602",
"jguddas"
"jguddas",
"karsa-mistmere"
],
"tags": [
"water",

View File

@@ -9,7 +9,7 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7.2 14.8a2 2 0 0 1 2 2" />
<path d="M7.001 15.085A1.5 1.5 0 0 1 9 16.5" />
<circle cx="18.5" cy="8.5" r="3.5" />
<circle cx="7.5" cy="16.5" r="5.5" />
<circle cx="7.5" cy="4.5" r="2.5" />

Before

Width:  |  Height:  |  Size: 366 B

After

Width:  |  Height:  |  Size: 377 B

29
icons/circle-pile.json Normal file
View File

@@ -0,0 +1,29 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"colebemis",
"nathan-de-pachtere"
],
"tags": [
"off",
"zero",
"record",
"shape",
"circle-pile",
"circle",
"pile",
"stack",
"layer",
"structure",
"form",
"group",
"collection",
"stock",
"inventory",
"materials",
"warehouse"
],
"categories": [
"shapes"
]
}

9
icons/circle-pile.svg Normal file
View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="19" r="2" />
<circle cx="12" cy="5" r="2" />
<circle cx="16" cy="12" r="2" />
<circle cx="20" cy="19" r="2" />
<circle cx="4" cy="19" r="2" />
<circle cx="8" cy="12" r="2" />
</svg>

After

Width:  |  Height:  |  Size: 397 B

33
icons/cloud-backup.json Normal file
View File

@@ -0,0 +1,33 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"ericfennis",
"jguddas",
"danielbayley",
"karsa-mistmere"
],
"tags": [
"storage",
"memory",
"bytes",
"servers",
"backup",
"timemachine",
"rotate",
"synchronize",
"synchronise",
"refresh",
"reconnect",
"transfer",
"data",
"security",
"upload",
"save",
"remote",
"safety"
],
"categories": [
"arrows",
"files"
]
}

15
icons/cloud-backup.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 15.251A4.5 4.5 0 0 0 17.5 8h-1.79A7 7 0 1 0 3 13.607" />
<path d="M7 11v4h4" />
<path d="M8 19a5 5 0 0 0 9-3 4.5 4.5 0 0 0-4.5-4.5 4.82 4.82 0 0 0-3.41 1.41L7 15" />
</svg>

After

Width:  |  Height:  |  Size: 393 B

27
icons/cloud-sync.json Normal file
View File

@@ -0,0 +1,27 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"colebemis",
"csandman",
"ericfennis",
"karsa-mistmere"
],
"tags": [
"synchronize",
"synchronise",
"refresh",
"reconnect",
"transfer",
"backup",
"storage",
"upload",
"download",
"connection",
"network",
"data"
],
"categories": [
"arrows",
"files"
]
}

17
icons/cloud-sync.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m17 18-1.535 1.605a5 5 0 0 1-8-1.5" />
<path d="M17 22v-4h-4" />
<path d="M20.996 15.251A4.5 4.5 0 0 0 17.495 8h-1.79a7 7 0 1 0-12.709 5.607" />
<path d="M7 10v4h4" />
<path d="m7 14 1.535-1.605a5 5 0 0 1 8 1.5" />
</svg>

After

Width:  |  Height:  |  Size: 442 B

View File

@@ -4,10 +4,17 @@
"Andreto",
"ericfennis",
"karsa-mistmere",
"csandman"
"csandman",
"jamiemlaw"
],
"tags": [
"torch"
"torch",
"light",
"beam",
"emergency",
"safety",
"tool",
"bright"
],
"categories": [
"photography",

View File

@@ -9,8 +9,9 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M16 16v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2V10c0-2-2-2-2-4" />
<path d="M7 2h11v4c0 2-2 2-2 4v1" />
<line x1="11" x2="18" y1="6" y2="6" />
<line x1="2" x2="22" y1="2" y2="22" />
<path d="M11.652 6H18" />
<path d="M12 13v1" />
<path d="M16 16v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-8a4 4 0 0 0-.8-2.4l-.6-.8A3 3 0 0 1 6 7V6" />
<path d="m2 2 20 20" />
<path d="M7.649 2H17a1 1 0 0 1 1 1v4a3 3 0 0 1-.6 1.8l-.6.8a4 4 0 0 0-.55 1.007" />
</svg>

Before

Width:  |  Height:  |  Size: 399 B

After

Width:  |  Height:  |  Size: 470 B

View File

@@ -2,10 +2,17 @@
"$schema": "../icon.schema.json",
"contributors": [
"csandman",
"ericfennis"
"ericfennis",
"jamiemlaw"
],
"tags": [
"torch"
"torch",
"light",
"beam",
"emergency",
"safety",
"tool",
"bright"
],
"categories": [
"photography",

View File

@@ -9,7 +9,7 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 6c0 2-2 2-2 4v10a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2V10c0-2-2-2-2-4V2h12z" />
<line x1="6" x2="18" y1="6" y2="6" />
<line x1="12" x2="12" y1="12" y2="12" />
<path d="M12 13v1" />
<path d="M17 2a1 1 0 0 1 1 1v4a3 3 0 0 1-.6 1.8l-.6.8A4 4 0 0 0 16 12v8a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2v-8a4 4 0 0 0-.8-2.4l-.6-.8A3 3 0 0 1 6 7V3a1 1 0 0 1 1-1z" />
<path d="M6 6h12" />
</svg>

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 422 B

21
icons/hd.json Normal file
View File

@@ -0,0 +1,21 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"ahtohbi4",
"jamiemlaw",
"karsa-mistmere",
"jguddas"
],
"tags": [
"tv",
"resolution",
"video",
"high definition",
"720p",
"1080p"
],
"categories": [
"devices",
"multimedia"
]
}

17
icons/hd.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 12H6" />
<path d="M10 15V9" />
<path d="M14 14.5a.5.5 0 0 0 .5.5h1a2.5 2.5 0 0 0 2.5-2.5v-1A2.5 2.5 0 0 0 15.5 9h-1a.5.5 0 0 0-.5.5z" />
<path d="M6 15V9" />
<rect x="2" y="5" width="20" height="14" rx="2" />
</svg>

After

Width:  |  Height:  |  Size: 440 B

22
icons/layers-plus.json Normal file
View File

@@ -0,0 +1,22 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"juanisidoro",
"karsa-mistmere"
],
"tags": [
"stack",
"layers",
"add",
"new",
"increase",
"create",
"positive",
"copy",
"upgrade"
],
"categories": [
"design",
"layout"
]
}

17
icons/layers-plus.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 .83.18 2 2 0 0 0 .83-.18l8.58-3.9a1 1 0 0 0 0-1.831z" />
<path d="M16 17h6" />
<path d="M19 14v6" />
<path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 .825.178" />
<path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l2.116-.962" />
</svg>

After

Width:  |  Height:  |  Size: 539 B

View File

@@ -9,13 +9,15 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 19v-3" />
<path d="M10 19v-3" />
<path d="M14 19v-3" />
<path d="M18 19v-3" />
<path d="M8 11V9" />
<path d="M16 11V9" />
<path d="M12 11V9" />
<path d="M2 15h20" />
<path d="M2 7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v1.1a2 2 0 0 0 0 3.837V17a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-5.1a2 2 0 0 0 0-3.837Z" />
<path d="M12 12v-2" />
<path d="M12 18v-2" />
<path d="M16 12v-2" />
<path d="M16 18v-2" />
<path d="M2 11h1.5" />
<path d="M20 18v-2" />
<path d="M20.5 11H22" />
<path d="M4 18v-2" />
<path d="M8 12v-2" />
<path d="M8 18v-2" />
<rect x="2" y="6" width="20" height="10" rx="2" />
</svg>

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -9,15 +9,14 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 12h4" />
<path d="M10 17h4" />
<path d="M10 7h4" />
<path d="M18 12h2" />
<path d="M18 16h2" />
<path d="M18 20h2" />
<path d="M18 4h2" />
<path d="M18 8h2" />
<path d="M18 18h2" />
<path d="M18 6h2" />
<path d="M4 12h2" />
<path d="M4 16h2" />
<path d="M4 20h2" />
<path d="M4 4h2" />
<path d="M4 8h2" />
<path d="M8 2a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2h-1.5c-.276 0-.494.227-.562.495a2 2 0 0 1-3.876 0C9.994 2.227 9.776 2 9.5 2z" />
<path d="M4 18h2" />
<path d="M4 6h2" />
<rect x="6" y="2" width="12" height="20" rx="2" />
</svg>

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 471 B

View File

@@ -9,8 +9,8 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m19 11-8-8-8.6 8.6a2 2 0 0 0 0 2.8l5.2 5.2c.8.8 2 .8 2.8 0L19 11Z" />
<path d="m5 2 5 5" />
<path d="M2 13h15" />
<path d="M22 20a2 2 0 1 1-4 0c0-1.6 1.7-2.4 2-4 .3 1.6 2 2.4 2 4Z" />
<path d="M19 12H2" />
<path d="M21.145 18.38A3.34 3.34 0 0 1 20 16.5a3.3 3.3 0 0 1-1.145 1.88c-.575.46-.855 1.02-.855 1.595A2 2 0 0 0 20 22a2 2 0 0 0 2-2.025c0-.58-.285-1.13-.855-1.595" />
<path d="m6 2 5 5" />
<path d="m8.5 4.5 2.148-2.148a1.205 1.205 0 0 1 1.704 0l7.296 7.296a1.205 1.205 0 0 1 0 1.704l-7.592 7.592a3.615 3.615 0 0 1-5.112 0l-3.888-3.888a3.615 3.615 0 0 1 0-5.112L5.67 7.33" />
</svg>

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 613 B

View File

@@ -10,7 +10,11 @@
"energy",
"electronics",
"socket",
"outlet"
"outlet",
"power",
"voltage",
"current",
"charger"
],
"categories": [
"devices",

View File

@@ -10,7 +10,7 @@
stroke-linejoin="round"
>
<path d="M12 22v-5" />
<path d="M9 8V2" />
<path d="M15 8V2" />
<path d="M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z" />
<path d="M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z" />
<path d="M9 8V2" />
</svg>

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 363 B

22
icons/scooter.json Normal file
View File

@@ -0,0 +1,22 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"Ahmed-Dghaies",
"karsa-mistmere"
],
"tags": [
"vehicle",
"drive",
"trip",
"journey",
"transport",
"electric",
"ride",
"urban",
"commute",
"speed"
],
"categories": [
"transportation"
]
}

16
icons/scooter.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 4h-3.5l2 11.05" />
<path d="M6.95 17h5.142c.523 0 .95-.406 1.063-.916a6.5 6.5 0 0 1 5.345-5.009" />
<circle cx="19.5" cy="17.5" r="2.5" />
<circle cx="4.5" cy="17.5" r="2.5" />
</svg>

After

Width:  |  Height:  |  Size: 405 B

25
icons/search-alert.json Normal file
View File

@@ -0,0 +1,25 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"colebemis",
"ericfennis",
"jguddas",
"Veatec22"
],
"tags": [
"find",
"scan",
"magnifier",
"magnifying glass",
"stop",
"warning",
"alert",
"error",
"anomaly",
"lens"
],
"categories": [
"text",
"social"
]
}

16
icons/search-alert.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
<path d="M11 7v4" />
<path d="M11 15h.01" />
</svg>

After

Width:  |  Height:  |  Size: 321 B

View File

@@ -1,7 +1,8 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"danielbayley"
"danielbayley",
"eden881"
],
"tags": [
"cut",

View File

@@ -9,12 +9,18 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M4 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2" />
<path d="M10 22H8" />
<path d="M16 22h-2" />
<circle cx="8" cy="8" r="2" />
<path d="M9.414 9.414 12 12" />
<path d="M14.8 14.8 18 18" />
<circle cx="8" cy="16" r="2" />
<path d="m18 6-8.586 8.586" />
<line x1="5" y1="3" x2="19" y2="3" />
<line x1="3" y1="5" x2="3" y2="19" />
<line x1="21" y1="5" x2="21" y2="19" />
<line x1="9" y1="21" x2="10" y2="21" />
<line x1="14" y1="21" x2="15" y2="21" />
<path d="M 3 5 A2 2 0 0 1 5 3" />
<path d="M 19 3 A2 2 0 0 1 21 5" />
<path d="M 5 21 A2 2 0 0 1 3 19" />
<path d="M 21 19 A2 2 0 0 1 19 21" />
<circle cx="8.5" cy="8.5" r="1.5" />
<line x1="9.56066" y1="9.56066" x2="12" y2="12" />
<line x1="17" y1="17" x2="14.82" y2="14.82" />
<circle cx="8.5" cy="15.5" r="1.5" />
<line x1="9.56066" y1="14.43934" x2="17" y2="7" />
</svg>

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 801 B

View File

@@ -1,7 +1,8 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"danielbayley"
"danielbayley",
"eden881"
],
"tags": [
"cut",

View File

@@ -9,10 +9,10 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="20" height="20" x="2" y="2" rx="2" />
<circle cx="8" cy="8" r="2" />
<path d="M9.414 9.414 12 12" />
<path d="M14.8 14.8 18 18" />
<circle cx="8" cy="16" r="2" />
<path d="m18 6-8.586 8.586" />
<rect width="18" height="18" x="3" y="3" rx="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<line x1="9.56066" y1="9.56066" x2="12" y2="12" />
<line x1="17" y1="17" x2="14.82" y2="14.82" />
<circle cx="8.5" cy="15.5" r="1.5" />
<line x1="9.56066" y1="14.43934" x2="17" y2="7" />
</svg>

Before

Width:  |  Height:  |  Size: 427 B

After

Width:  |  Height:  |  Size: 495 B

View File

@@ -2,7 +2,8 @@
"$schema": "../icon.schema.json",
"contributors": [
"ericfennis",
"karsa-mistmere"
"karsa-mistmere",
"jguddas"
],
"tags": [
"temperature",

View File

@@ -9,10 +9,10 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 9a4 4 0 0 0-2 7.5" />
<path d="M12 3v2" />
<path d="m6.6 18.4-1.4 1.4" />
<path d="M20 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z" />
<path d="M4 13H2" />
<path d="M6.34 7.34 4.93 5.93" />
<path d="M12 2v2" />
<path d="M12 8a4 4 0 0 0-1.645 7.647" />
<path d="M2 12h2" />
<path d="M20 14.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0z" />
<path d="m4.93 4.93 1.41 1.41" />
<path d="m6.34 17.66-1.41 1.41" />
</svg>

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 426 B

View File

@@ -9,6 +9,6 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M17 14V2" />
<path d="M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z" />
<path d="M17 14V2" />
</svg>

Before

Width:  |  Height:  |  Size: 399 B

After

Width:  |  Height:  |  Size: 399 B

View File

@@ -9,6 +9,6 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 10v12" />
<path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" />
<path d="M7 10v12" />
</svg>

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 400 B

View File

@@ -1,7 +1,8 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jguddas"
"jguddas",
"karsa-mistmere"
],
"tags": [
"plane",

View File

@@ -11,7 +11,7 @@
>
<path d="M10.5 17h1.227a2 2 0 0 0 1.345-.52L18 12" />
<path d="m12 13.5 3.75.5" />
<path d="m4.5 8 10.58-5.06a1 1 0 0 1 1.342.488L18.5 8" />
<path d="m3.173 8.18 11-5a2 2 0 0 1 2.647.993L18.56 8" />
<path d="M6 10V8" />
<path d="M6 14v1" />
<path d="M6 19v2" />

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -1,7 +1,8 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jguddas"
"jguddas",
"karsa-mistmere"
],
"tags": [
"trip",

View File

@@ -9,7 +9,7 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m4.5 8 10.58-5.06a1 1 0 0 1 1.342.488L18.5 8" />
<path d="m3.173 8.18 11-5a2 2 0 0 1 2.647.993L18.56 8" />
<path d="M6 10V8" />
<path d="M6 14v1" />
<path d="M6 19v2" />

Before

Width:  |  Height:  |  Size: 390 B

After

Width:  |  Height:  |  Size: 390 B

28
icons/van.json Normal file
View File

@@ -0,0 +1,28 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"Ahmed-Dghaies",
"karsa-mistmere"
],
"tags": [
"minivan",
"cart",
"wagon",
"truck",
"lorry",
"trailer",
"camper",
"vehicle",
"drive",
"trip",
"journey",
"van",
"transport",
"carriage",
"delivery",
"travel"
],
"categories": [
"transportation"
]
}

17
icons/van.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M13 6v5a1 1 0 0 0 1 1h6.102a1 1 0 0 1 .712.298l.898.91a1 1 0 0 1 .288.702V17a1 1 0 0 1-1 1h-3" />
<path d="M5 18H3a1 1 0 0 1-1-1V8a2 2 0 0 1 2-2h12c1.1 0 2.1.8 2.4 1.8l1.176 4.2" />
<path d="M9 18h5" />
<circle cx="16" cy="18" r="2" />
<circle cx="7" cy="18" r="2" />
</svg>

After

Width:  |  Height:  |  Size: 494 B

20
icons/weight-tilde.json Normal file
View File

@@ -0,0 +1,20 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"nathan-de-pachtere"
],
"tags": [
"measure",
"scale",
"estimate",
"load",
"balance",
"size",
"measurement",
"quantity",
"mass"
],
"categories": [
"math"
]
}

15
icons/weight-tilde.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6.5 8a2 2 0 0 0-1.906 1.46L2.1 18.5A2 2 0 0 0 4 21h16a2 2 0 0 0 1.925-2.54L19.4 9.5A2 2 0 0 0 17.48 8z" />
<path d="M7.999 15a2.5 2.5 0 0 1 4 0 2.5 2.5 0 0 0 4 0" />
<circle cx="12" cy="5" r="3" />
</svg>

After

Width:  |  Height:  |  Size: 422 B

View File

@@ -7,8 +7,8 @@ const filenamesToAjvOption = (filenames) => filenames.map((filename) => `-d ${fi
/** @satisfies {import('lint-staged').Config} */
const config = {
'icons/*.svg': [
'node ./scripts/optimizeStagedSvgs.mjs',
'node ./scripts/generateNextJSAliases.mjs',
'node ./scripts/optimizeStagedSvgs.mts',
'node ./scripts/generateNextJSAliases.mts',
],
'icons/*.json': (filenames) => [
`ajv --spec=draft2020 -s icon.schema.json ${filenamesToAjvOption(filenames)}`,

View File

@@ -49,6 +49,7 @@
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"ajv-cli": "^5.0.0",
"dotenv": "^17.0.0",
"eslint": "^8.57.1",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.1.0",
@@ -64,18 +65,17 @@
"p-memoize": "^7.1.1",
"prettier": "3.2.4",
"prettier-plugin-astro": "^0.14.1",
"semver": "^7.7.1",
"semver": "^7.7.3",
"simple-git": "^3.27.0",
"svgo": "^3.3.2",
"svgson": "^5.3.1",
"yargs": "^17.7.2",
"dotenv": "^17.0.0",
"zod": "^3.25.67"
},
"engines": {
"node": ">=23.0.0"
"node": ">=24.11.1"
},
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a",
"pnpm": {
"packageExtensions": {
"vue-template-compiler": {
@@ -85,7 +85,13 @@
}
},
"overrides": {
"cross-spawn": "7.0.5"
"cross-spawn": "7.0.5",
"form-data": "^4.0.4",
"fast-json-patch": "^3.1.1",
"webpack-dev-middleware": "^5.3.4",
"semver": "^7.7.3",
"axios": "^1.12.0",
"vite-prerender-plugin": "0.5.12"
}
}
}

View File

@@ -55,7 +55,9 @@
"linkedom": "^0.18.5",
"prettier": "^3.4.2",
"typescript": "^5.8.3",
"vitest": "^3.1.3"
"vite": "^6.3.6",
"vitest": "^4.0.12",
"astro": "^5.16.0"
},
"peerDependencies": {
"astro": "^4 || ^5"

View File

@@ -45,18 +45,18 @@
"@lucide/build-icons": "workspace:*",
"@lucide/rollup-plugins": "workspace:*",
"@lucide/shared": "workspace:*",
"@preact/preset-vite": "^2.7.0",
"@preact/preset-vite": "^2.10.2",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/preact": "^3.2.3",
"jest-serializer-html": "^7.1.0",
"preact": "^10.19.2",
"rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.3",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
},
"peerDependencies": {
"preact": "^10.5.13"
"preact": "^10.27.2"
}
}

View File

@@ -56,11 +56,11 @@
"react-dom": "^18.0.0",
"react-native": "^0.76.0",
"react-native-svg": "^15.8.0",
"rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.3",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
},
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",

View File

@@ -61,12 +61,12 @@
"jest-serializer-html": "^7.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.3",
"rollup-plugin-preserve-directives": "^0.4.0",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
},
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"

View File

@@ -77,12 +77,12 @@
"@testing-library/jest-dom": "^6.4.2",
"babel-preset-solid": "^1.8.12",
"jest-serializer-html": "^7.1.0",
"rollup": "^4.22.4",
"rollup": "^4.53.3",
"solid-js": "^1.9.4",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vite": "^7.2.4",
"vite-plugin-solid": "^2.11.6",
"vitest": "^3.1.3",
"vitest": "^4.0.12",
"esbuild": "^0.25.0"
},
"peerDependencies": {

View File

@@ -44,7 +44,7 @@
"@types/node": "^22.15.30",
"prettier": "^2.3.2",
"svgson": "^5.2.1",
"rollup": "^4.40.0",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.1"
}
}

View File

@@ -70,8 +70,8 @@
"svelte-check": "^3.4.4",
"svelte-preprocess": "^5.0.4",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
},
"peerDependencies": {
"svelte": "^3 || ^4 || ^5.0.0-next.42"

View File

@@ -49,13 +49,13 @@
"@lucide/rollup-plugins": "workspace:*",
"@lucide/shared": "workspace:*",
"@testing-library/jest-dom": "^6.1.6",
"@testing-library/vue": "^8.0.3",
"@vitejs/plugin-vue": "^4.6.2",
"@vue/test-utils": "2.4.5",
"rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0",
"vite": "^6.3.6",
"vitest": "^3.1.3",
"@testing-library/vue": "^8.1.0",
"@vitejs/plugin-vue": "^6.0.2",
"@vue/test-utils": "2.4.6",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.3",
"vite": "^7.2.4",
"vitest": "^4.0.12",
"vue": "^3.4.21"
},
"peerDependencies": {

View File

@@ -50,10 +50,10 @@
"@testing-library/vue": "^5.9.0",
"@vitejs/plugin-vue2": "2.2.0",
"@vue/test-utils": "1.3.0",
"rollup": "^3.29.5",
"rollup": "^4.53.3",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3",
"vite": "^7.2.4",
"vitest": "^4.0.12",
"vue": "2.7.14",
"vue-template-compiler": "2.7.14"
},

View File

@@ -48,10 +48,10 @@
"@rollup/plugin-replace": "^6.0.2",
"@testing-library/jest-dom": "^6.6.3",
"jest-serializer-html": "^7.1.0",
"rollup": "^4.40.0",
"rollup-plugin-dts": "^6.2.1",
"rollup": "^4.53.3",
"rollup-plugin-dts": "^6.2.3",
"typescript": "^5.8.3",
"vite": "^6.3.6",
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
}
}

View File

@@ -13,6 +13,7 @@
"test:watch": "vitest watch"
},
"devDependencies": {
"vitest": "^3.1.3"
"vite": "^7.2.4",
"vitest": "^4.0.12"
}
}

View File

@@ -70,8 +70,8 @@
"svelte-check": "^4.1.4",
"svelte-preprocess": "^6.0.3",
"typescript": "^5.8.3",
"vite": "6.1.6",
"vitest": "^3.1.3"
"vite": "^6.3.6",
"vitest": "^4.0.12"
},
"peerDependencies": {
"svelte": "^5"

View File

@@ -112,6 +112,7 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
<!---->
</svg>
</div>
`;
@@ -206,6 +207,7 @@ exports[`Using lucide icon components > should render an component 1`] = `
<!---->
</svg>
</div>
`;
@@ -268,5 +270,6 @@ exports[`Using lucide icon components > should render an icon slot 1`] = `
<!---->
</svg>
</div>
`;

8199
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

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