mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 23:07:43 +01:00
Compare commits
342 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
275c2cbc69 | ||
|
|
4bd6a273db | ||
|
|
34155d48e7 | ||
|
|
82db590192 | ||
|
|
70be55b78f | ||
|
|
7163aeaa6b | ||
|
|
99cd76bb35 | ||
|
|
f5fb1ec263 | ||
|
|
6916aebee4 | ||
|
|
65d213264f | ||
|
|
ee77147aff | ||
|
|
3b7b74fe86 | ||
|
|
3a2f052ce9 | ||
|
|
cf34d61971 | ||
|
|
2814a63b8f | ||
|
|
4bcab462dc | ||
|
|
6c93bb97c7 | ||
|
|
3c1993c463 | ||
|
|
7a57c306c3 | ||
|
|
32637199f5 | ||
|
|
e490bc35b8 | ||
|
|
496058cc15 | ||
|
|
4ee46673af | ||
|
|
5a46f4b87c | ||
|
|
875e8a2d06 | ||
|
|
e006a171c1 | ||
|
|
606706e8e0 | ||
|
|
ffc03ea1f6 | ||
|
|
b2e685262b | ||
|
|
5bfc736b61 | ||
|
|
2ebf99f591 | ||
|
|
7a17a2f343 | ||
|
|
4b5d343791 | ||
|
|
b19b01d323 | ||
|
|
d2dc5bf75f | ||
|
|
9b93200567 | ||
|
|
a878596572 | ||
|
|
9d50c05937 | ||
|
|
6196c261d3 | ||
|
|
85cec0dea1 | ||
|
|
07039b7619 | ||
|
|
cf05bd766f | ||
|
|
f05855d1d1 | ||
|
|
6f39d3743a | ||
|
|
7ed206af4a | ||
|
|
95daa7c313 | ||
|
|
17ecb92946 | ||
|
|
9ef9921f04 | ||
|
|
ac08bb92c1 | ||
|
|
53109037ec | ||
|
|
66de90d63e | ||
|
|
f3c7e44a3d | ||
|
|
3823993c39 | ||
|
|
36c53f956a | ||
|
|
58c652908a | ||
|
|
f4d887339e | ||
|
|
bde11234ea | ||
|
|
3449097f77 | ||
|
|
aec41eae39 | ||
|
|
3da3cbc63f | ||
|
|
3fc3122054 | ||
|
|
871de752e7 | ||
|
|
25d7b55459 | ||
|
|
4d8a8091b6 | ||
|
|
a17c1aafbd | ||
|
|
d1d6eec36e | ||
|
|
abec311bc9 | ||
|
|
3df9be04a8 | ||
|
|
016c9d1fac | ||
|
|
17f9509f71 | ||
|
|
b6c7434e92 | ||
|
|
47aa3c2664 | ||
|
|
e50b03f316 | ||
|
|
0065b5952b | ||
|
|
b35b586eda | ||
|
|
8b57fab71b | ||
|
|
badd34374d | ||
|
|
902431199c | ||
|
|
bdbb4834b0 | ||
|
|
07fc4da6fa | ||
|
|
e1815242cf | ||
|
|
d104ad5c8a | ||
|
|
69989c5ae5 | ||
|
|
9e996ef63c | ||
|
|
6ec9cc3dcf | ||
|
|
01fa96ced3 | ||
|
|
481b27cc49 | ||
|
|
c5df7e73c6 | ||
|
|
428088436d | ||
|
|
eec2c97595 | ||
|
|
f0529b9ef7 | ||
|
|
0c216b41c5 | ||
|
|
ac892e5476 | ||
|
|
38f62a571c | ||
|
|
507750d0a7 | ||
|
|
33a0ed9539 | ||
|
|
37cb860ebe | ||
|
|
bd74ac880e | ||
|
|
e81b76f445 | ||
|
|
c50c0e435b | ||
|
|
afd2db296c | ||
|
|
175b2cd483 | ||
|
|
716c5baea0 | ||
|
|
890474889a | ||
|
|
e596cd2bad | ||
|
|
d4641a4641 | ||
|
|
3e3409cee2 | ||
|
|
477f2b2aff | ||
|
|
000ff56278 | ||
|
|
7117220943 | ||
|
|
f820da257d | ||
|
|
de629f0fcc | ||
|
|
8f7e9b3cde | ||
|
|
4e79f147cf | ||
|
|
3482cd0949 | ||
|
|
701f2a1a41 | ||
|
|
79f5c6e584 | ||
|
|
02fddd3aac | ||
|
|
7816ed88f6 | ||
|
|
9c2d57b0dc | ||
|
|
6d9a0c3d63 | ||
|
|
6f647c58bf | ||
|
|
41375d5b05 | ||
|
|
11ce2b6ff3 | ||
|
|
cc7881e759 | ||
|
|
bf530d39d3 | ||
|
|
71e8df6354 | ||
|
|
cafd2a838b | ||
|
|
e16f368502 | ||
|
|
d38509a03d | ||
|
|
6550e22874 | ||
|
|
22193420c7 | ||
|
|
70827d4571 | ||
|
|
7d980f6cc1 | ||
|
|
67131489c8 | ||
|
|
ebf03a5434 | ||
|
|
8fda42c719 | ||
|
|
b17627b82d | ||
|
|
84ec1620a8 | ||
|
|
a87ae2a92b | ||
|
|
f35f45c7b3 | ||
|
|
c9a418dfc4 | ||
|
|
70be608a58 | ||
|
|
db311ab023 | ||
|
|
cac81636fb | ||
|
|
4b225a2e80 | ||
|
|
8aac1c7ba6 | ||
|
|
d513a2b9df | ||
|
|
204a418643 | ||
|
|
36039d8bdc | ||
|
|
49bd49b843 | ||
|
|
4679ff791d | ||
|
|
bfab755958 | ||
|
|
63aa17a001 | ||
|
|
db6194369d | ||
|
|
29c952fdaf | ||
|
|
637e285c52 | ||
|
|
d6ee5d963c | ||
|
|
97d02ec6e5 | ||
|
|
f5be205fc9 | ||
|
|
f2e0da9bb1 | ||
|
|
2ca852fc7d | ||
|
|
a64215bb25 | ||
|
|
6d975609c4 | ||
|
|
13b9c1fadb | ||
|
|
dcf396f1e3 | ||
|
|
debf9b77c1 | ||
|
|
d30f3fe0c5 | ||
|
|
7d0f9996e6 | ||
|
|
c263c8baee | ||
|
|
c61207c0ac | ||
|
|
ec5327b870 | ||
|
|
61d3c6f452 | ||
|
|
d777895135 | ||
|
|
846a74ef50 | ||
|
|
3901a12d78 | ||
|
|
f9c49d9973 | ||
|
|
08b04f84b7 | ||
|
|
f3a97ed59e | ||
|
|
01663fb90b | ||
|
|
97aec42fb2 | ||
|
|
05eaf17ef9 | ||
|
|
e4d3a74434 | ||
|
|
de6b172e0a | ||
|
|
348628329d | ||
|
|
38d5093b1d | ||
|
|
3014d0aa32 | ||
|
|
a418010baa | ||
|
|
329d75a2c1 | ||
|
|
2482416aef | ||
|
|
11d7b48d70 | ||
|
|
5cbf9363cf | ||
|
|
92531a8a86 | ||
|
|
c67655d402 | ||
|
|
edc614bf43 | ||
|
|
ded24ab61f | ||
|
|
b626e91d7c | ||
|
|
a68ea8c33e | ||
|
|
4fd815a46c | ||
|
|
0e180515a3 | ||
|
|
5dbae5df45 | ||
|
|
bcad75bddd | ||
|
|
78a0640832 | ||
|
|
05ea32948c | ||
|
|
2e11931d2b | ||
|
|
689b3e1d83 | ||
|
|
8ec672bd86 | ||
|
|
c096bf2325 | ||
|
|
a796cb105d | ||
|
|
e4ac2cc4e9 | ||
|
|
2ee208652f | ||
|
|
d0826259d1 | ||
|
|
3acbfb428b | ||
|
|
250bd20199 | ||
|
|
221e213292 | ||
|
|
1e48aecbfe | ||
|
|
7a6dc5b2f7 | ||
|
|
7f6999fee7 | ||
|
|
08c1bc68da | ||
|
|
930260aab5 | ||
|
|
96473f7f7d | ||
|
|
f620c85e3b | ||
|
|
f4a8f3d0d8 | ||
|
|
36725eeed9 | ||
|
|
ee7ee203e6 | ||
|
|
7a26dddbcb | ||
|
|
408c683a13 | ||
|
|
546cf61a2e | ||
|
|
a7496aa454 | ||
|
|
93cfd3d27d | ||
|
|
76ce22ef14 | ||
|
|
873997b48e | ||
|
|
03276eee9d | ||
|
|
cf5aa0534b | ||
|
|
cccf89e7bb | ||
|
|
2d4676160b | ||
|
|
6346d80ee7 | ||
|
|
e983ccf974 | ||
|
|
f0fe196872 | ||
|
|
85eaa5fc50 | ||
|
|
6a7732077a | ||
|
|
c1c0f99d65 | ||
|
|
ee2bfaff0d | ||
|
|
9370449d7e | ||
|
|
244a5a396e | ||
|
|
2396a53bad | ||
|
|
07a78731a5 | ||
|
|
4e2449dc9f | ||
|
|
f02067ea55 | ||
|
|
57a72cbb38 | ||
|
|
0baf1a49ef | ||
|
|
0879262bdb | ||
|
|
9a41d931e9 | ||
|
|
7c111a53e1 | ||
|
|
7209ed3fcd | ||
|
|
e85dffa9b4 | ||
|
|
0c3d6cd097 | ||
|
|
72c25a9936 | ||
|
|
5226c326f8 | ||
|
|
de2e3036c0 | ||
|
|
8adeb025a6 | ||
|
|
22ffb58649 | ||
|
|
278309fe55 | ||
|
|
bcbae1e406 | ||
|
|
1173134099 | ||
|
|
894993478f | ||
|
|
36f84a74f6 | ||
|
|
1479a9dbd8 | ||
|
|
2485f6117a | ||
|
|
0bbaaa8abd | ||
|
|
a82af02687 | ||
|
|
a5be1b4101 | ||
|
|
639c0e8d85 | ||
|
|
b863445492 | ||
|
|
8c4a41035b | ||
|
|
4a55ae4b91 | ||
|
|
30f683a192 | ||
|
|
25e0aaf33c | ||
|
|
3cd84c8adf | ||
|
|
096ce92866 | ||
|
|
57abe654b1 | ||
|
|
852da97d46 | ||
|
|
ba86ca5ef0 | ||
|
|
f2e325264f | ||
|
|
de366a1cb0 | ||
|
|
5f5cec5b58 | ||
|
|
2ccd5b7422 | ||
|
|
e38137822d | ||
|
|
a9fef9f6b0 | ||
|
|
f646d84559 | ||
|
|
6f6ffa2478 | ||
|
|
76326cb289 | ||
|
|
13a3f565b6 | ||
|
|
b0f2e084d8 | ||
|
|
fc78d27cc3 | ||
|
|
9b0d0edb61 | ||
|
|
6a5f8d3755 | ||
|
|
35c96ab61f | ||
|
|
8fd8007c96 | ||
|
|
621cf6b290 | ||
|
|
a5ce1df506 | ||
|
|
c784dd09c7 | ||
|
|
0f11acdd7f | ||
|
|
2149645895 | ||
|
|
fa6ed02297 | ||
|
|
4a2c6ed8b0 | ||
|
|
f67dfab128 | ||
|
|
c3b9cff578 | ||
|
|
9ba4f8c359 | ||
|
|
dd5a5b16f6 | ||
|
|
a1f9a95322 | ||
|
|
7572d2d6c8 | ||
|
|
58370d63dc | ||
|
|
6552a4cca1 | ||
|
|
dace5a9f9c | ||
|
|
90f32d38a2 | ||
|
|
619b7040da | ||
|
|
04ada85c0f | ||
|
|
17ccaeea75 | ||
|
|
692faadd91 | ||
|
|
89a8274246 | ||
|
|
26987c6eda | ||
|
|
bf8db289a3 | ||
|
|
50f0eaec4b | ||
|
|
dbe35c4f69 | ||
|
|
c3056b9ce6 | ||
|
|
b016ea08f8 | ||
|
|
8e041c3c17 | ||
|
|
e3d2525994 | ||
|
|
e846b725f6 | ||
|
|
b924c0a70b | ||
|
|
0d6e89332e | ||
|
|
6ecf908ded | ||
|
|
f623ac6362 | ||
|
|
e3644e1419 | ||
|
|
84e09058b2 | ||
|
|
3e4bde1d39 | ||
|
|
164854c636 | ||
|
|
2d1214fc37 | ||
|
|
d528fb728a | ||
|
|
53d7b772ef | ||
|
|
c73fbb6159 |
@@ -34,6 +34,7 @@ module.exports = {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./site/tsconfig.json', './packages/*/tsconfig.json'],
|
||||
ecmaVersion: 2020,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
};
|
||||
|
||||
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# These are supported funding model platforms
|
||||
open_collective: lucide-icons
|
||||
6
.github/PULL_REQUEST_TEMPLATE/new-icon.md
vendored
6
.github/PULL_REQUEST_TEMPLATE/new-icon.md
vendored
@@ -5,11 +5,11 @@ labels: "🎨 <icon"
|
||||
---
|
||||
|
||||
<!-- Thanks for submitting an icon! Please make sure you read the icon design guide
|
||||
at https://github.com/lucide-icons/lucide/blob/main/docs/ICON_DESIGN_GUIDE.md beforehand,
|
||||
at https://github.com/lucide-icons/lucide/blob/main/docs/icon-design-guide.md beforehand,
|
||||
and please fill everything below. -->
|
||||
|
||||
- **Name of the icon** : <!-- `icon` -->
|
||||
- **Tags (alternative names for this icon)** (add them in tags.json) :
|
||||
- **Tags (alternative names for this icon)** (add them in as a separate json file using the same icon name) :
|
||||
- **What is the purpose of this icon?** : <!-- Shows that one can click it to... / Is used to denote or label... -->
|
||||
- **100% scale preview** : <!-- upload an image -->
|
||||
- **Have you considered alternative possibilities** for its naming or design? :
|
||||
- **Have you considered alternative possibilities** for its naming or design? :
|
||||
|
||||
44
.github/actions/build-and-test.yml
vendored
Normal file
44
.github/actions/build-and-test.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: "Build and Test"
|
||||
description: "Builds and test a package"
|
||||
|
||||
inputs:
|
||||
name:
|
||||
description: “Name of the package”
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-lucide-preact-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-lucide-preact-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter lucide-preact
|
||||
|
||||
- name: Build
|
||||
run: pnpm --filter lucide-preact build
|
||||
|
||||
- name: Test
|
||||
run: pnpm --filter lucide-preact test
|
||||
41
.github/actions/check-icons.yml
vendored
Normal file
41
.github/actions/check-icons.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: "Check icons"
|
||||
description: "Cross-checks icon and category references in JSON descriptors"
|
||||
|
||||
inputs:
|
||||
name:
|
||||
description: “Name of the package”
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- uses: pnpm/action-setup@v2.0.1
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
run: |
|
||||
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
|
||||
|
||||
- uses: actions/cache@v3
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
|
||||
key: ${{ runner.os }}-lucide-preact-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-lucide-preact-pnpm-store-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --filter .
|
||||
|
||||
- name: Check icons and categories
|
||||
run: pnpm checkIcons
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- icons/**
|
||||
- icons/**/*.svg
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
|
||||
4
.github/workflows/lucide-angular.yml
vendored
4
.github/workflows/lucide-angular.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-angular/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-angular/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-angular:
|
||||
|
||||
4
.github/workflows/lucide-font.yml
vendored
4
.github/workflows/lucide-font.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- icons/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- icons/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-font:
|
||||
|
||||
4
.github/workflows/lucide-preact.yml
vendored
4
.github/workflows/lucide-preact.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-preact/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-preact/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-preact:
|
||||
|
||||
4
.github/workflows/lucide-react-native.yml
vendored
4
.github/workflows/lucide-react-native.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-react-native/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-react-native/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-react-native:
|
||||
|
||||
4
.github/workflows/lucide-react.yml
vendored
4
.github/workflows/lucide-react.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-react/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-react/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-react:
|
||||
|
||||
4
.github/workflows/lucide-solid.yml
vendored
4
.github/workflows/lucide-solid.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-solid/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-solid/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-solid:
|
||||
|
||||
4
.github/workflows/lucide-static.yml
vendored
4
.github/workflows/lucide-static.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-static/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-static/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-static:
|
||||
|
||||
4
.github/workflows/lucide-svelte.yml
vendored
4
.github/workflows/lucide-svelte.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-svelte/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-svelte/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-svelte:
|
||||
|
||||
4
.github/workflows/lucide-vue-next.yml
vendored
4
.github/workflows/lucide-vue-next.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-vue-next/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-vue-next/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-vue-next:
|
||||
|
||||
4
.github/workflows/lucide-vue.yml
vendored
4
.github/workflows/lucide-vue.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide-vue/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide-vue/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide-vue:
|
||||
|
||||
4
.github/workflows/lucide.yml
vendored
4
.github/workflows/lucide.yml
vendored
@@ -5,10 +5,6 @@ on:
|
||||
paths:
|
||||
- packages/lucide/**
|
||||
- pnpm-lock.yaml
|
||||
push:
|
||||
paths:
|
||||
- packages/lucide/**
|
||||
- pnpm-lock.yaml
|
||||
|
||||
jobs:
|
||||
lucide:
|
||||
|
||||
140
.github/workflows/pull-request.yml
vendored
Normal file
140
.github/workflows/pull-request.yml
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
name: Add Changed Icons comment
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- 'icons/*.svg'
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
add-changed-icons-comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v35
|
||||
with:
|
||||
files: icons/*.svg
|
||||
- name: Generate cohesion check random
|
||||
id: generate-cohesion-check-random
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in $(printf "%s\\n" icons/*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ steps.changed-files.outputs.all_changed_files }}')); do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate cohesion check squares
|
||||
id: generate-cohesion-check-squares
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in $(printf "%s\\n" icons/*square*.svg | shuf | head -n$(awk -F' ' '{print NF}' <<< '${{ steps.changed-files.outputs.all_changed_files }}')); do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 1px stroke-width
|
||||
id: generate-1px-stroke-width
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/1/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 2px stroke-width
|
||||
id: generate-2px-stroke-width
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/2/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate 3px stroke-width
|
||||
id: generate-3px-stroke-width
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/stroke-width/3/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Generate X-rays
|
||||
id: generate-x-rays
|
||||
run: |
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
|
||||
cat "$file" | # get file content
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img width=\"400\" title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/$(basename ${file//\.svg/})/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Added or changed icons
|
||||
- name: Create or update comment
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
with:
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
### Added or changed icons
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
<details>
|
||||
<summary>Preview cohesion</summary>
|
||||
${{ steps.generate-cohesion-check-squares.outputs.body }}<br/>
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
${{ steps.generate-cohesion-check-random.outputs.body }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Preview stroke widths</summary>
|
||||
${{ steps.generate-1px-stroke-width.outputs.body }}<br/>
|
||||
${{ steps.generate-2px-stroke-width.outputs.body }}<br/>
|
||||
${{ steps.generate-3px-stroke-width.outputs.body }}<br/>
|
||||
</details>
|
||||
<details>
|
||||
<summary>Icon X-rays</summary>
|
||||
${{ steps.generate-x-rays.outputs.body }}
|
||||
</details>
|
||||
edit-mode: replace
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -15,4 +15,22 @@ stats
|
||||
outlined
|
||||
packages/**/src/icons/*.js
|
||||
packages/**/src/icons/*.ts
|
||||
packages/**/src/icons/*.tsx
|
||||
packages/**/src/aliases.ts
|
||||
packages/**/LICENSE
|
||||
categories.json
|
||||
tags.json
|
||||
.vercel
|
||||
|
||||
# docs
|
||||
docs/.vitepress/cache
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/.temp
|
||||
docs/.vitepress/data/iconNodes
|
||||
docs/.vitepress/data/iconMetaData.ts
|
||||
docs/.vitepress/data/releaseMetaData.json
|
||||
docs/.vitepress/data/releaseMetaData
|
||||
docs/.vitepress/data/iconDetails
|
||||
docs/.vitepress/data/relatedIcons.json
|
||||
docs/.vercel
|
||||
docs/.nitro
|
||||
|
||||
5
.husky/pre-commit
Executable file
5
.husky/pre-commit
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm lint-staged
|
||||
pnpm checkIcons
|
||||
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"devs",
|
||||
"preact",
|
||||
"Preact"
|
||||
]
|
||||
}
|
||||
@@ -25,28 +25,21 @@ Guidelines for pull requests:
|
||||
|
||||
Please make sure you follow the icon guidelines, that should be followed to keep quality and consistency when making icons for Lucide.
|
||||
|
||||
Read it here: [ICON_GUIDELINES](docs/ICON_DESIGN_GUIDE.md).
|
||||
Read it here: [ICON_GUIDELINES](https://lucide.dev/docs/icon-design-guide).
|
||||
|
||||
### Templates
|
||||
### Editor guides
|
||||
|
||||
Here you can find templates and instructions on how to implement the guidelines with different programs.
|
||||
Here you can find instructions on how to implement the guidelines with different vector graphics editors:
|
||||
|
||||
#### Adobe Illustrator
|
||||
#### [Adobe Illustrator Guide](https://lucide.dev/docs/illustrator-guide)
|
||||
|
||||
`Template`: You can find a template for Adobe Illustrator under `/docs/templates/illustrator-template.ai`.
|
||||
`Instructions`: You can find the [Illustrator Guide](/docs/ILLUSTRATOR_GUIDE.md) and how to work with the template in `/docs/ILLUSTRATOR_GUIDE.md`.
|
||||
You can also [download an Adobe Illustrator template](https://lucide.dev/templates/illustrator-template.ai).
|
||||
|
||||
#### Inkscape
|
||||
#### [Inkscape Guide](https://lucide.dev/docs/inkscape-guide)
|
||||
|
||||
`Template`: None
|
||||
`Instructions`: You can find the [Inkscape Guide](/docs/INKSCAPE_GUIDE.md) and how to set up Inkscape under `/docs/INKSCAPE_GUIDE.md`.
|
||||
#### [Figma Guide](https://lucide.dev/docs/figma-guide)
|
||||
|
||||
#### Figma
|
||||
|
||||
`Template`: None
|
||||
`Instructions`: You can find the [Figma Guide](/docs/FIGMA_GUIDE.md) and how to set up Figma under `/docs/FIGMA_GUIDE.md`.
|
||||
|
||||
#### Submitting Multiple Icons
|
||||
### Submitting Multiple Icons
|
||||
|
||||
If you want submit multiple icons, please separate the icons and group them. That makes reviewing the icons easier and keep the thread clean and scoped.
|
||||
So don't submit multiple icons in one PR that have noting to do with each other.
|
||||
@@ -66,20 +59,21 @@ If you are a designer who wants to contribute to Lucide but you don't know what
|
||||
## Development
|
||||
|
||||
You will need minimum version of [Nodejs 16.4+](https://nodejs.org)
|
||||
For packagemanagement you will need [yarn v1](https://yarnpkg.com/getting-started/install).
|
||||
For package management you will need [PNPM](https://pnpm.io/installation).
|
||||
For flutter package development, you need [Flutter 1.17+](https://docs.flutter.dev/get-started/install).
|
||||
|
||||
After cloning the project you need to run:
|
||||
|
||||
```sh
|
||||
yarn # Install dependencies, including the workspace packages
|
||||
pnpm install # Install dependencies, including the workspace packages
|
||||
```
|
||||
|
||||
### Packages -> PNPM Workspaces
|
||||
|
||||
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/en/docs/workspaces).
|
||||
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).
|
||||
|
||||
> Note: One package is not managed by pnpm: **lucide-flutter**, this package is written in Dart and used pub for publishing.
|
||||
|
||||
@@ -178,11 +172,11 @@ Includes usefully scripts to automate certain jobs. Big part of the scripts is t
|
||||
|
||||
### site
|
||||
|
||||
The lucide.dev website using [Nextjs](https://nextjs.org).
|
||||
The lucide.dev website is using [vitepress](https://vitepress.dev/) to generate the static website. The markdown files are located in the docs directory.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation files are located in the [docs](./docs) directory. All these markdown files will be loaded in the build of the lucide.dev website.
|
||||
The documentation files are located in the [docs](https://github.com/lucide-icons/lucide/tree/main/docs) directory. All these markdown files will be loaded in the build of the lucide.dev website.
|
||||
|
||||
Feel free to write, adjust or add new markdown files to improve our documentation.
|
||||
|
||||
|
||||
11
README.md
11
README.md
@@ -39,6 +39,7 @@ Lucide is trying to expand the icon set as much as possible while staying faithf
|
||||
- [Svelte](#svelte)
|
||||
- [Solid](#solid)
|
||||
- [Hyva](#hyva)
|
||||
- [Eleventy](#eleventy)
|
||||
- [Contributing](#contributing)
|
||||
- [Community](#community)
|
||||
- [License](#license)
|
||||
@@ -251,6 +252,16 @@ composer require siteation/magento2-hyva-icons-lucide
|
||||
|
||||
For more details, see the [documentation](https://github.com/Siteation/magento2-hyva-icons-lucide/blob/main/README.md).
|
||||
|
||||
### Eleventy
|
||||
|
||||
Using this plugin, Eleventy projects can incorporate Lucide icons. it makes it simple to use Lucide icons into your themes via shortcodes, improving your website's overall usability and visual appeal.
|
||||
|
||||
```sh
|
||||
npm install @grimlink/eleventy-plugin-lucide-icons
|
||||
```
|
||||
|
||||
For more details, see the [documentation](https://github.com/GrimLink/eleventy-plugin-lucide-icons/blob/main/README.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
For more info on how to contribute please see the [contribution guidelines](https://github.com/lucide-icons/lucide/blob/main/CONTRIBUTING.md).
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ['@babel/env'],
|
||||
// babelrcRoots: ['.', './packages/*'],
|
||||
env: {
|
||||
test: {
|
||||
presets: ['@babel/env'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
},
|
||||
dev: {
|
||||
plugins: [
|
||||
[
|
||||
'transform-inline-environment-variables',
|
||||
{
|
||||
include: ['NODE_ENV'],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"arrows": [],
|
||||
"brands": [],
|
||||
"code": [],
|
||||
"connectivity": ["airplay"],
|
||||
"cursors": [],
|
||||
"development": [],
|
||||
"devices": ["alarm-clock"],
|
||||
"file-system": [],
|
||||
"layout": [],
|
||||
"maths": ["activity"],
|
||||
"multimedia": [],
|
||||
"notifications": ["alert-circle", "alert-octagon", "alert-triangle"],
|
||||
"nature": [],
|
||||
"shopping": [],
|
||||
"shapes": [],
|
||||
"sports": [],
|
||||
"text-edit": ["align-center","align-right","align-left","align-justify" ]
|
||||
}
|
||||
5
categories/accessibility.json
Normal file
5
categories/accessibility.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Accessibility",
|
||||
"icon": "accessibility"
|
||||
}
|
||||
5
categories/account.json
Normal file
5
categories/account.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Accounts & access",
|
||||
"icon": "user"
|
||||
}
|
||||
5
categories/animals.json
Normal file
5
categories/animals.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Animals",
|
||||
"icon": "dog"
|
||||
}
|
||||
5
categories/arrows.json
Normal file
5
categories/arrows.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Arrows",
|
||||
"icon": "arrow-left-right"
|
||||
}
|
||||
5
categories/brands.json
Normal file
5
categories/brands.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Brands",
|
||||
"icon": "facebook"
|
||||
}
|
||||
5
categories/buildings.json
Normal file
5
categories/buildings.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Buildings",
|
||||
"icon": "building"
|
||||
}
|
||||
5
categories/charts.json
Normal file
5
categories/charts.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Charts",
|
||||
"icon": "pie-chart"
|
||||
}
|
||||
5
categories/communication.json
Normal file
5
categories/communication.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Communication",
|
||||
"icon": "message-circle"
|
||||
}
|
||||
5
categories/connectivity.json
Normal file
5
categories/connectivity.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Connectivity",
|
||||
"icon": "wifi"
|
||||
}
|
||||
5
categories/currency.json
Normal file
5
categories/currency.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Currency",
|
||||
"icon": "dollar-sign"
|
||||
}
|
||||
5
categories/cursors.json
Normal file
5
categories/cursors.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Cursors",
|
||||
"icon": "mouse-pointer-2"
|
||||
}
|
||||
5
categories/design.json
Normal file
5
categories/design.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Design",
|
||||
"icon": "palette"
|
||||
}
|
||||
5
categories/development.json
Normal file
5
categories/development.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Coding & development",
|
||||
"icon": "code-2"
|
||||
}
|
||||
5
categories/devices.json
Normal file
5
categories/devices.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Devices",
|
||||
"icon": "smartphone"
|
||||
}
|
||||
5
categories/emoji.json
Normal file
5
categories/emoji.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Emoji",
|
||||
"icon": "smile"
|
||||
}
|
||||
5
categories/files.json
Normal file
5
categories/files.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "File icons",
|
||||
"icon": "layout"
|
||||
}
|
||||
5
categories/food-beverage.json
Normal file
5
categories/food-beverage.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Food & beverage",
|
||||
"icon": "coffee"
|
||||
}
|
||||
5
categories/furniture.json
Normal file
5
categories/furniture.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Furniture",
|
||||
"icon": "rocking-chair"
|
||||
}
|
||||
5
categories/gaming.json
Normal file
5
categories/gaming.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Gaming",
|
||||
"icon": "gamepad-2"
|
||||
}
|
||||
5
categories/home.json
Normal file
5
categories/home.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Home",
|
||||
"icon": "home"
|
||||
}
|
||||
5
categories/layout.json
Normal file
5
categories/layout.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Layout",
|
||||
"icon": "layout"
|
||||
}
|
||||
5
categories/mail.json
Normal file
5
categories/mail.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Mail",
|
||||
"icon": "mail"
|
||||
}
|
||||
5
categories/maps.json
Normal file
5
categories/maps.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Maps",
|
||||
"icon": "map"
|
||||
}
|
||||
5
categories/maths.json
Normal file
5
categories/maths.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Maths",
|
||||
"icon": "divide"
|
||||
}
|
||||
5
categories/medical.json
Normal file
5
categories/medical.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Medical",
|
||||
"icon": "heart"
|
||||
}
|
||||
5
categories/money.json
Normal file
5
categories/money.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Money",
|
||||
"icon": "piggy-bank"
|
||||
}
|
||||
5
categories/multimedia.json
Normal file
5
categories/multimedia.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Multimedia",
|
||||
"icon": "play-circle"
|
||||
}
|
||||
5
categories/nature.json
Normal file
5
categories/nature.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Nature",
|
||||
"icon": "sprout"
|
||||
}
|
||||
5
categories/navigation.json
Normal file
5
categories/navigation.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Navigation",
|
||||
"icon": "compass"
|
||||
}
|
||||
5
categories/notifications.json
Normal file
5
categories/notifications.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Notifications",
|
||||
"icon": "alert-triangle"
|
||||
}
|
||||
5
categories/people.json
Normal file
5
categories/people.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "People",
|
||||
"icon": "person-standing"
|
||||
}
|
||||
5
categories/photography.json
Normal file
5
categories/photography.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Photography",
|
||||
"icon": "camera"
|
||||
}
|
||||
5
categories/science.json
Normal file
5
categories/science.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Science",
|
||||
"icon": "flask-conical"
|
||||
}
|
||||
5
categories/seasons.json
Normal file
5
categories/seasons.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Seasons",
|
||||
"icon": "leaf"
|
||||
}
|
||||
5
categories/security.json
Normal file
5
categories/security.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Security",
|
||||
"icon": "shield"
|
||||
}
|
||||
5
categories/shapes.json
Normal file
5
categories/shapes.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Shapes",
|
||||
"icon": "triangle"
|
||||
}
|
||||
5
categories/shopping.json
Normal file
5
categories/shopping.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Shopping",
|
||||
"icon": "shopping-bag"
|
||||
}
|
||||
5
categories/social.json
Normal file
5
categories/social.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Social",
|
||||
"icon": "thumbs-up"
|
||||
}
|
||||
5
categories/sports.json
Normal file
5
categories/sports.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Sports",
|
||||
"icon": "type"
|
||||
}
|
||||
5
categories/sustainability.json
Normal file
5
categories/sustainability.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Sustainability",
|
||||
"icon": "recycle"
|
||||
}
|
||||
5
categories/text.json
Normal file
5
categories/text.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Text formatting",
|
||||
"icon": "type"
|
||||
}
|
||||
5
categories/time.json
Normal file
5
categories/time.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Time & calendar",
|
||||
"icon": "calendar"
|
||||
}
|
||||
5
categories/tools.json
Normal file
5
categories/tools.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Tools",
|
||||
"icon": "hammer"
|
||||
}
|
||||
5
categories/transportation.json
Normal file
5
categories/transportation.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Transportation",
|
||||
"icon": "train"
|
||||
}
|
||||
5
categories/travel.json
Normal file
5
categories/travel.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Travel",
|
||||
"icon": "backpack"
|
||||
}
|
||||
5
categories/weather.json
Normal file
5
categories/weather.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "../category.schema.json",
|
||||
"title": "Weather",
|
||||
"icon": "cloud-sun"
|
||||
}
|
||||
34
category.schema.json
Normal file
34
category.schema.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"$id": "https://lucide.dev/category.schema.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$vocabulary": {
|
||||
"https://json-schema.org/draft/2020-12/vocab/core": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/applicator": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/validation": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/meta-data": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
|
||||
"https://json-schema.org/draft/2020-12/vocab/content": true
|
||||
},
|
||||
"title": "Lucide Icons category schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"weight": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"icon"
|
||||
],
|
||||
"description": "A JSON Schema for categories defined by Lucide Icons."
|
||||
}
|
||||
11
docs/.vitepress/api/categories/index.get.ts
Normal file
11
docs/.vitepress/api/categories/index.get.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
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', '*')
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(iconMetaData).map(([name, { categories }]) => [ name, categories ])
|
||||
)
|
||||
})
|
||||
41
docs/.vitepress/api/gh-icon/[...data].get.ts
Normal file
41
docs/.vitepress/api/gh-icon/[...data].get.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { eventHandler, setResponseHeader, defaultContentType } from 'h3'
|
||||
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
|
||||
import { createElement } from 'react'
|
||||
import SvgPreview from '../../lib/SvgPreview/index.tsx';
|
||||
import iconNodes from '../../data/iconNodes'
|
||||
import createLucideIcon from 'lucide-react/src/createLucideIcon'
|
||||
import Backdrop from '../../lib/SvgPreview/Backdrop.tsx';
|
||||
|
||||
export default eventHandler((event) => {
|
||||
const { params } = event.context
|
||||
|
||||
const [name, svgData] = params.data.split('/');
|
||||
const data = svgData.slice(0, -4);
|
||||
|
||||
const src = Buffer.from(data, 'base64').toString('utf8');
|
||||
|
||||
const children = []
|
||||
|
||||
if (name in iconNodes) {
|
||||
const iconNode = iconNodes[name]
|
||||
|
||||
const LucideIcon = createLucideIcon(name, iconNode)
|
||||
const svg = renderToStaticMarkup(createElement(LucideIcon))
|
||||
const backdropString = svg.replace(/<svg[^>]*>|<\/svg>/g, '');
|
||||
|
||||
children.push(createElement(Backdrop, { backdropString, src }))
|
||||
}
|
||||
|
||||
const svg = Buffer.from(
|
||||
// We can't use jsx here, is not supported here by nitro.
|
||||
renderToString(createElement(SvgPreview, {src, showGrid: true}, children)).replace(
|
||||
/>/,
|
||||
'><style>@media screen and (prefers-color-scheme: dark) { svg { stroke: #fff } }</style>'
|
||||
)
|
||||
).toString('utf8');
|
||||
|
||||
defaultContentType(event, 'image/svg+xml')
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
||||
|
||||
return svg
|
||||
})
|
||||
35
docs/.vitepress/api/gh-icon/stroke-width/[...data].get.ts
Normal file
35
docs/.vitepress/api/gh-icon/stroke-width/[...data].get.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
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 { parseSync } from 'svgson';
|
||||
|
||||
export default eventHandler((event) => {
|
||||
const { params } = event.context
|
||||
|
||||
const [strokeWidth, svgData] = params.data.split('/');
|
||||
const data = svgData.slice(0, -4);
|
||||
|
||||
const src = Buffer.from(data, 'base64').toString('utf8');
|
||||
|
||||
const Icon = createLucideIcon(
|
||||
'icon',
|
||||
parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`).children.map(
|
||||
({ name, attributes }) => [name, attributes]
|
||||
) as IconNode
|
||||
);
|
||||
|
||||
const svg = Buffer.from(
|
||||
// We can't use jsx here, is not supported here by nitro.
|
||||
renderToString(createElement(Icon, { strokeWidth })).replace(
|
||||
/>/,
|
||||
'><style>@media screen and (prefers-color-scheme: dark) { svg { stroke: #fff } }</style>'
|
||||
)
|
||||
).toString('utf8');
|
||||
|
||||
defaultContentType(event, 'image/svg+xml')
|
||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
||||
|
||||
return svg
|
||||
})
|
||||
30
docs/.vitepress/api/icon-nodes/index.get.ts
Normal file
30
docs/.vitepress/api/icon-nodes/index.get.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
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 withUniqueKeys = query.withUniqueKeys === 'true'
|
||||
|
||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
||||
|
||||
if (withUniqueKeys) {
|
||||
return iconNodes
|
||||
}
|
||||
|
||||
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
|
||||
if (withUniqueKeys) {
|
||||
return [name, iconNode]
|
||||
}
|
||||
|
||||
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs}]) => {
|
||||
return [name, attrs]
|
||||
})
|
||||
|
||||
acc[name] = newIconNode
|
||||
|
||||
return acc
|
||||
}, {})
|
||||
})
|
||||
45
docs/.vitepress/api/icons/[iconName].get.ts
Normal file
45
docs/.vitepress/api/icons/[iconName].get.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
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 iconNode = iconNodes[params.iconName]
|
||||
|
||||
if (iconNode == null) {
|
||||
const error = createError({
|
||||
statusCode: 404,
|
||||
message: `Icon "${params.iconName}" not found`,
|
||||
})
|
||||
|
||||
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 LucideIcon = createLucideIcon(params.iconName, iconNode)
|
||||
|
||||
const svg = Buffer.from(
|
||||
renderToString(
|
||||
createElement(LucideIcon, {
|
||||
width,
|
||||
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', '*')
|
||||
|
||||
return svg
|
||||
|
||||
})
|
||||
11
docs/.vitepress/api/tags/index.get.ts
Normal file
11
docs/.vitepress/api/tags/index.get.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
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', '*')
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(iconMetaData).map(([name, { tags }]) => [ name, tags ])
|
||||
)
|
||||
})
|
||||
3
docs/.vitepress/api/test.ts
Normal file
3
docs/.vitepress/api/test.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default eventHandler(() => {
|
||||
return { nitro: 'Is Awesome! asda' }
|
||||
})
|
||||
157
docs/.vitepress/config.ts
Normal file
157
docs/.vitepress/config.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vitepress'
|
||||
import { createWriteStream } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { SitemapStream } from 'sitemap'
|
||||
import sidebar from './sidebar';
|
||||
import fs from 'fs';
|
||||
|
||||
const links = []
|
||||
|
||||
|
||||
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({
|
||||
title,
|
||||
description,
|
||||
cleanUrls: true,
|
||||
outDir: '.vercel/output/static',
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: /^.*\/VPIconAlignLeft\.vue$/,
|
||||
replacement: fileURLToPath(
|
||||
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)
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
head: [
|
||||
[ 'script', {
|
||||
src: 'https://plausible.io/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'
|
||||
},
|
||||
nav: [
|
||||
{ text: 'Icons', link: '/icons/' },
|
||||
{ text: 'Guide', link: '/guide/' },
|
||||
{ text: 'Packages', link: '/packages' },
|
||||
{ text: 'License', link: '/license' },
|
||||
],
|
||||
sidebar,
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/lucide-icons/lucide' },
|
||||
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' }
|
||||
],
|
||||
footer: {
|
||||
message: 'Released under the ISC License.',
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`
|
||||
},
|
||||
editLink: {
|
||||
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
|
||||
},
|
||||
},
|
||||
transformHtml: (_, id, { pageData }) => {
|
||||
if (/[\\/]404\.html$/.test(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (pageData.relativePath.startsWith('icons/')) {
|
||||
links.push({
|
||||
url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
|
||||
lastmod: pageData?.params?.changedRelease?.date
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
links.push({
|
||||
url: pageData.relativePath.replace(/((^|\/)index)?\.md$/, '$2'),
|
||||
lastmod: pageData.lastUpdated
|
||||
})
|
||||
},
|
||||
buildEnd: async ({ outDir }) => {
|
||||
const sitemap = new SitemapStream({
|
||||
hostname: 'https://lucide.dev/'
|
||||
})
|
||||
const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml'))
|
||||
sitemap.pipe(writeStream)
|
||||
links.forEach((link) => sitemap.write(link))
|
||||
sitemap.end()
|
||||
await new Promise((r) => writeStream.on('finish', r))
|
||||
},
|
||||
})
|
||||
80
docs/.vitepress/data/packageData.thirdParty.json
Normal file
80
docs/.vitepress/data/packageData.thirdParty.json
Normal file
@@ -0,0 +1,80 @@
|
||||
[
|
||||
{
|
||||
"name": "blade-lucide-icons",
|
||||
"description": "Implementation of Lucide icon's using blade-icons for Laravel based projects.",
|
||||
"icon": "/framework-logos/laravel.svg",
|
||||
"shields": [
|
||||
{
|
||||
"alt": "Latest Stable Version",
|
||||
"src": "https://img.shields.io/packagist/v/mallardduck/blade-lucide-icons",
|
||||
"href": "https://packagist.org/packages/mallardduck/blade-lucide-icons"
|
||||
},
|
||||
{
|
||||
"alt": "Total Downloads",
|
||||
"src": "https://img.shields.io/packagist/dt/mallardduck/blade-lucide-icons",
|
||||
"href": "https://packagist.org/packages/mallardduck/blade-lucide-icons"
|
||||
}
|
||||
],
|
||||
"source": "https://github.com/mallardduck/blade-lucide-icons",
|
||||
"documentation": "https://github.com/mallardduck/blade-lucide-icons/blob/main/README.md"
|
||||
},
|
||||
{
|
||||
"name": "hyva-lucide-icons",
|
||||
"description": "Implementation of Lucide icon's using Hyvä's svg php viewmodal to render icons for Magento 2 Hyva theme based projects.",
|
||||
"icon": "/framework-logos/hyva.svg",
|
||||
"iconDark": "/framework-logos/hyva-dark.svg",
|
||||
"shields": [
|
||||
{
|
||||
"alt": "Latest Stable Version",
|
||||
"src": "https://img.shields.io/packagist/v/siteation/magento2-hyva-icons-lucide",
|
||||
"href": "https://packagist.org/packages/siteation/magento2-hyva-icons-lucide"
|
||||
},
|
||||
{
|
||||
"alt": "Total Downloads",
|
||||
"src": "https://img.shields.io/packagist/dt/siteation/magento2-hyva-icons-lucide",
|
||||
"href": "https://packagist.org/packages/siteation/magento2-hyva-icons-lucide"
|
||||
}
|
||||
],
|
||||
"source": "https://github.com/siteation/magento2-hyva-icons-lucide",
|
||||
"documentation": "https://github.com/siteation/magento2-hyva-icons-lucide/blob/main/README.md"
|
||||
},
|
||||
{
|
||||
"name": "eleventy-lucide-icons",
|
||||
"description": "Using this plugin, Eleventy projects can incorporate Lucide icons. it makes it simple to use Lucide icons into your themes via shortcodes, improving your website's overall usability and visual appeal.",
|
||||
"icon": "/framework-logos/11ty.svg",
|
||||
"iconClass": "package-icon-invert",
|
||||
"shields": [
|
||||
{
|
||||
"alt": "Latest Stable Version",
|
||||
"src": "https://img.shields.io/npm/v/@grimlink/eleventy-plugin-lucide-icons",
|
||||
"href": "https://www.npmjs.com/package/@grimlink/eleventy-plugin-lucide-icons"
|
||||
},
|
||||
{
|
||||
"alt": "Total Downloads",
|
||||
"src": "https://img.shields.io/npm/dw/@grimlink/eleventy-plugin-lucide-icons",
|
||||
"href": "https://www.npmjs.com/package/@grimlink/eleventy-plugin-lucide-icons"
|
||||
}
|
||||
],
|
||||
"source": "https://github.com/GrimLink/eleventy-plugin-lucide-icons",
|
||||
"documentation": "https://github.com/GrimLink/eleventy-plugin-lucide-icons/blob/main/README.md"
|
||||
},
|
||||
{
|
||||
"name": "nuxt-lucide-icons",
|
||||
"description": "Using this module, Nuxt projects can incorporate Lucide icons. It is fully configurable and supports auto imports and tree-shaking.",
|
||||
"icon": "/framework-logos/nuxt.svg",
|
||||
"shields": [
|
||||
{
|
||||
"alt": "Latest Stable Version",
|
||||
"src": "https://img.shields.io/npm/v/nuxt-lucide-icons",
|
||||
"href": "https://www.npmjs.com/package/nuxt-lucide-icons"
|
||||
},
|
||||
{
|
||||
"alt": "Total Downloads",
|
||||
"src": "https://img.shields.io/npm/dw/nuxt-lucide-icons",
|
||||
"href": "https://www.npmjs.com/package/nuxt-lucide-icons"
|
||||
}
|
||||
],
|
||||
"source": "https://github.com/swisnl/nuxt-lucide-icons",
|
||||
"documentation": "https://github.com/swisnl/nuxt-lucide-icons/blob/main/README.md"
|
||||
}
|
||||
]
|
||||
71
docs/.vitepress/lib/SvgPreview/Backdrop.tsx
Normal file
71
docs/.vitepress/lib/SvgPreview/Backdrop.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
|
||||
interface BackdropProps {
|
||||
src: string
|
||||
backdropString: string
|
||||
}
|
||||
|
||||
const Backdrop = ({ src, backdropString }: BackdropProps): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<defs xmlns="http://www.w3.org/2000/svg">
|
||||
<pattern
|
||||
id="pattern"
|
||||
width=".1"
|
||||
height=".1"
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternTransform="rotate(45 50 50)"
|
||||
>
|
||||
<line stroke="red" strokeWidth={0.1} y2={1} />
|
||||
<line stroke="red" 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>
|
||||
<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>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="url(#pattern)"
|
||||
stroke="none"
|
||||
mask={'url(#svg-preview-backdrop-mask-fill)'}
|
||||
/>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="red"
|
||||
opacity={0.5}
|
||||
stroke="none"
|
||||
mask={'url(#svg-preview-backdrop-mask-fill)'}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default Backdrop;
|
||||
265
docs/.vitepress/lib/SvgPreview/index.tsx
Normal file
265
docs/.vitepress/lib/SvgPreview/index.tsx
Normal file
@@ -0,0 +1,265 @@
|
||||
import React from 'react';
|
||||
import { PathProps, Path } from './types';
|
||||
import { getPaths, assert } from './utils';
|
||||
|
||||
const Grid = ({
|
||||
radius,
|
||||
fill,
|
||||
...props
|
||||
}: {
|
||||
strokeWidth: number;
|
||||
radius: number;
|
||||
} & PathProps<'stroke', 'strokeWidth'>) => (
|
||||
<g className="svg-preview-grid-group" strokeLinecap="butt" {...props}>
|
||||
<rect
|
||||
width={24 - props.strokeWidth}
|
||||
height={24 - props.strokeWidth}
|
||||
x={props.strokeWidth / 2}
|
||||
y={props.strokeWidth / 2}
|
||||
rx={radius}
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d={
|
||||
props.d ||
|
||||
new Array(Math.floor(24 - 1))
|
||||
.fill(null)
|
||||
.flatMap((_, i) => [
|
||||
`M${props.strokeWidth} ${i + 1}h${24 - props.strokeWidth * 2}`,
|
||||
`M${i + 1} ${props.strokeWidth}v${24 - props.strokeWidth * 2}`,
|
||||
])
|
||||
.join('')
|
||||
}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
|
||||
const Shadow = ({
|
||||
radius,
|
||||
paths,
|
||||
...props
|
||||
}: {
|
||||
radius: number;
|
||||
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[]>)
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<g className="svg-preview-shadow-mask-group" {...props}>
|
||||
{groupedPaths.map(([id, paths]) => (
|
||||
<mask
|
||||
id={`svg-preview-shadow-mask-${id}`}
|
||||
maskUnits="userSpaceOnUse"
|
||||
strokeOpacity="1"
|
||||
strokeWidth={props.strokeWidth}
|
||||
stroke="#000"
|
||||
>
|
||||
<rect x={0} y={0} width={24} height={24} fill="#fff" stroke="none" rx={radius} />
|
||||
<path
|
||||
d={paths
|
||||
.flatMap(({ prev, next }) => [
|
||||
`M${prev.x} ${prev.y}h.01`,
|
||||
`M${next.x} ${next.y}h.01`,
|
||||
])
|
||||
.filter((val, idx, arr) => arr.indexOf(val) === idx)
|
||||
.join('')}
|
||||
/>
|
||||
</mask>
|
||||
))}
|
||||
</g>
|
||||
<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
|
||||
d={paths
|
||||
.flatMap(({ prev, next }) => [`M${prev.x} ${prev.y}h.01`, `M${next.x} ${next.y}h.01`])
|
||||
.filter((val, idx, arr) => arr.indexOf(val) === idx)
|
||||
.join('')}
|
||||
/>
|
||||
</g>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ColoredPath = ({
|
||||
colors,
|
||||
paths,
|
||||
...props
|
||||
}: { paths: Path[]; colors: string[] } & PathProps<never, 'd' | 'stroke'>) => (
|
||||
<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]} />
|
||||
))}
|
||||
</g>
|
||||
);
|
||||
|
||||
const ControlPath = ({
|
||||
paths,
|
||||
radius,
|
||||
pointSize,
|
||||
...props
|
||||
}: { pointSize: number; paths: Path[]; radius: number } & PathProps<
|
||||
'stroke' | 'strokeWidth',
|
||||
'd'
|
||||
>) => {
|
||||
const controlPaths = paths.map((path, i) => {
|
||||
const element = paths.filter((p) => p.c.id === path.c.id);
|
||||
const lastElement = element.at(-1)?.next;
|
||||
assert(lastElement);
|
||||
const isClosed = element[0].prev.x === lastElement.x && element[0].prev.y === lastElement.y;
|
||||
const showMarker = !['rect', 'circle', 'ellipse'].includes(path.c.name);
|
||||
return {
|
||||
...path,
|
||||
showMarker,
|
||||
startMarker: showMarker && path.isStart && !isClosed,
|
||||
endMarker: showMarker && paths[i + 1]?.isStart !== false && !isClosed,
|
||||
};
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<g
|
||||
className="svg-preview-control-path-marker-mask-group"
|
||||
strokeWidth={pointSize}
|
||||
stroke="#000"
|
||||
>
|
||||
{controlPaths.map(({ prev, next, showMarker }, i) => {
|
||||
return (
|
||||
showMarker && (
|
||||
<mask
|
||||
id={`svg-preview-control-path-marker-mask-${i}`}
|
||||
key={i}
|
||||
maskUnits="userSpaceOnUse"
|
||||
>
|
||||
<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>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
<g className="svg-preview-control-path-group" {...props}>
|
||||
{controlPaths.map(({ d, showMarker }, i) => (
|
||||
<path
|
||||
key={i}
|
||||
mask={showMarker ? `url(#svg-preview-control-path-marker-mask-${i})` : undefined}
|
||||
d={d}
|
||||
/>
|
||||
))}
|
||||
</g>
|
||||
<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`] : []
|
||||
)
|
||||
.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} />}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</g>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Radii = ({
|
||||
paths,
|
||||
...props
|
||||
}: { paths: Path[] } & PathProps<
|
||||
'strokeWidth' | 'stroke' | 'strokeDasharray' | 'strokeOpacity',
|
||||
any
|
||||
>) => {
|
||||
return (
|
||||
<g className="svg-preview-radii-group" {...props}>
|
||||
{paths
|
||||
.filter(({ circle }) => circle)
|
||||
.map(({ c, prev, next, circle: { x, y, r } }) =>
|
||||
c.name === 'circle' ? (
|
||||
<path d={`M${x} ${y}h.01`} />
|
||||
) : (
|
||||
<>
|
||||
<path d={`M${prev.x} ${prev.y} ${x} ${y} ${next.x} ${next.y}`} />
|
||||
<circle cy={y} cx={x} r={r} />
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
|
||||
const SvgPreview = React.forwardRef<
|
||||
SVGSVGElement,
|
||||
{
|
||||
src: string | ReturnType<typeof getPaths>;
|
||||
showGrid?: boolean;
|
||||
} & React.SVGProps<SVGSVGElement>
|
||||
>(({ src, children, showGrid = false, ...props }, ref) => {
|
||||
const paths = typeof src === 'string' ? getPaths(src) : src;
|
||||
|
||||
const darkModeCss = `@media screen and (prefers-color-scheme: dark) {
|
||||
.svg-preview-grid-group,
|
||||
.svg-preview-radii-group,
|
||||
.svg-preview-shadow-mask-group,
|
||||
.svg-preview-shadow-group {
|
||||
stroke: #fff;
|
||||
}
|
||||
}`;
|
||||
return (
|
||||
<svg
|
||||
ref={ref}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...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} />
|
||||
<ColoredPath
|
||||
paths={paths}
|
||||
colors={[
|
||||
'#1982c4',
|
||||
'#4267AC',
|
||||
'#6a4c93',
|
||||
'#B55379',
|
||||
'#FF595E',
|
||||
'#FF7655',
|
||||
'#ff924c',
|
||||
'#FFAE43',
|
||||
'#ffca3a',
|
||||
'#C5CA30',
|
||||
'#8ac926',
|
||||
'#52A675',
|
||||
]}
|
||||
/>
|
||||
<Radii
|
||||
paths={paths}
|
||||
strokeWidth={0.12}
|
||||
strokeDasharray="0 0.25 0.25"
|
||||
stroke="#777"
|
||||
strokeOpacity={0.3}
|
||||
/>
|
||||
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
});
|
||||
|
||||
export default SvgPreview;
|
||||
22
docs/.vitepress/lib/SvgPreview/types.ts
Normal file
22
docs/.vitepress/lib/SvgPreview/types.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { SVGProps } from 'react';
|
||||
import { getCommands } from './utils';
|
||||
|
||||
export type Point = { x: number; y: number };
|
||||
|
||||
export type Path = {
|
||||
d: string;
|
||||
prev: Point;
|
||||
next: Point;
|
||||
isStart: boolean;
|
||||
circle: { x: number; y: number; r: number };
|
||||
c: ReturnType<typeof getCommands>[number];
|
||||
};
|
||||
|
||||
export type PathProps<
|
||||
RequiredProps 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>,
|
||||
RequiredProps & NeverProps
|
||||
>;
|
||||
286
docs/.vitepress/lib/SvgPreview/utils.ts
Normal file
286
docs/.vitepress/lib/SvgPreview/utils.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
import { INode, parseSync } from 'svgson';
|
||||
import toPath from 'element-to-path';
|
||||
import { SVGPathData, encodeSVGPath } from 'svg-pathdata';
|
||||
import { Path, Point } from './types';
|
||||
|
||||
function assertNever(x: never): never {
|
||||
throw new Error('Unknown type: ' + x['type']);
|
||||
}
|
||||
export function assert(value: unknown): asserts value {
|
||||
if (value === undefined) {
|
||||
throw new Error('value must be defined');
|
||||
}
|
||||
}
|
||||
|
||||
const convertToPathNode = (node: INode): { d: string; name: typeof node.name } => {
|
||||
if (node.name === 'path') {
|
||||
return { d: node.attributes.d, name: node.name };
|
||||
}
|
||||
if (node.name === 'circle') {
|
||||
const cx = parseFloat(node.attributes.cx);
|
||||
const cy = parseFloat(node.attributes.cy);
|
||||
const r = parseFloat(node.attributes.r);
|
||||
return {
|
||||
d: [
|
||||
`M ${cx} ${cy - r}`,
|
||||
`a ${r} ${r} 0 0 1 ${r} ${r}`,
|
||||
`a ${r} ${r} 0 0 1 ${0 - r} ${r}`,
|
||||
`a ${r} ${r} 0 0 1 ${0 - r} ${0 - r}`,
|
||||
`a ${r} ${r} 0 0 1 ${r} ${0 - r}`,
|
||||
].join(''),
|
||||
name: node.name,
|
||||
};
|
||||
}
|
||||
return { d: toPath(node).replace(/z$/i, ''), name: node.name };
|
||||
};
|
||||
|
||||
const extractNodes = (node: INode): INode[] => {
|
||||
if (['rect', 'circle', 'ellipse', 'polygon', 'polyline', 'line', 'path'].includes(node.name)) {
|
||||
return [node];
|
||||
} else if (node.children && Array.isArray(node.children)) {
|
||||
return node.children.flatMap(extractNodes);
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getNodes = (src: string) =>
|
||||
extractNodes(parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`));
|
||||
|
||||
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 }))
|
||||
);
|
||||
|
||||
export const getPaths = (src: string) => {
|
||||
const commands = getCommands(src.includes('<svg') ? src : `<svg>${src}</svg>`);
|
||||
const paths: Path[] = [];
|
||||
let prev: Point | undefined = undefined;
|
||||
let start: Point | undefined = undefined;
|
||||
const addPath = (
|
||||
c: typeof commands[number],
|
||||
next: Point,
|
||||
d?: string,
|
||||
circle?: Path['circle']
|
||||
) => {
|
||||
assert(prev);
|
||||
paths.push({
|
||||
c,
|
||||
d: d || `M ${prev.x} ${prev.y} L ${next.x} ${next.y}`,
|
||||
prev,
|
||||
next,
|
||||
circle,
|
||||
isStart: start === prev,
|
||||
});
|
||||
prev = next;
|
||||
};
|
||||
let prevCP: Point | undefined = undefined;
|
||||
for (let i = 0; i < commands.length; i++) {
|
||||
const previousCommand = commands[i - 1];
|
||||
const c = commands[i];
|
||||
switch (c.type) {
|
||||
case SVGPathData.MOVE_TO: {
|
||||
prev = c;
|
||||
start = c;
|
||||
break;
|
||||
}
|
||||
case SVGPathData.LINE_TO: {
|
||||
assert(prev);
|
||||
addPath(c, c);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.HORIZ_LINE_TO: {
|
||||
assert(prev);
|
||||
addPath(c, { x: c.x, y: prev.y });
|
||||
break;
|
||||
}
|
||||
case SVGPathData.VERT_LINE_TO: {
|
||||
assert(prev);
|
||||
addPath(c, { x: prev.x, y: c.y });
|
||||
break;
|
||||
}
|
||||
case SVGPathData.CLOSE_PATH: {
|
||||
assert(prev);
|
||||
assert(start);
|
||||
addPath(c, start);
|
||||
start = undefined;
|
||||
break;
|
||||
}
|
||||
case SVGPathData.CURVE_TO: {
|
||||
assert(prev);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.SMOOTH_CURVE_TO: {
|
||||
assert(prev);
|
||||
assert(previousCommand);
|
||||
const reflectedCp1 = {
|
||||
x:
|
||||
previousCommand &&
|
||||
(previousCommand.type === SVGPathData.SMOOTH_CURVE_TO ||
|
||||
previousCommand.type === SVGPathData.CURVE_TO)
|
||||
? previousCommand.relative
|
||||
? previousCommand.x2 - previousCommand.x
|
||||
: previousCommand.x2 - prev.x
|
||||
: 0,
|
||||
y:
|
||||
previousCommand &&
|
||||
(previousCommand.type === SVGPathData.SMOOTH_CURVE_TO ||
|
||||
previousCommand.type === SVGPathData.CURVE_TO)
|
||||
? previousCommand.relative
|
||||
? previousCommand.y2 - previousCommand.y
|
||||
: previousCommand.y2 - prev.y
|
||||
: 0,
|
||||
};
|
||||
addPath(
|
||||
c,
|
||||
c,
|
||||
`M ${prev.x} ${prev.y} ${encodeSVGPath({
|
||||
type: SVGPathData.CURVE_TO,
|
||||
relative: false,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
x1: prev.x - reflectedCp1.x,
|
||||
y1: prev.y - reflectedCp1.y,
|
||||
x2: c.x2,
|
||||
y2: c.y2,
|
||||
})}`
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.QUAD_TO: {
|
||||
assert(prev);
|
||||
addPath(c, c, `M ${prev.x} ${prev.y} ${encodeSVGPath(c)}`);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.SMOOTH_QUAD_TO: {
|
||||
assert(prev);
|
||||
const backTrackCP = (
|
||||
index: number,
|
||||
currentPoint: { x: number; y: number }
|
||||
): { x: number; y: number } => {
|
||||
const previousCommand = commands[index - 1];
|
||||
if (!previousCommand) {
|
||||
return currentPoint;
|
||||
}
|
||||
if (previousCommand.type === SVGPathData.QUAD_TO) {
|
||||
return {
|
||||
x: previousCommand.relative
|
||||
? currentPoint.x - (previousCommand.x1 - previousCommand.x)
|
||||
: currentPoint.x - (previousCommand.x1 - currentPoint.x),
|
||||
y: previousCommand.relative
|
||||
? currentPoint.y - (previousCommand.y1 - previousCommand.y)
|
||||
: currentPoint.y - (previousCommand.y1 - currentPoint.y),
|
||||
};
|
||||
}
|
||||
if (previousCommand.type === SVGPathData.SMOOTH_QUAD_TO) {
|
||||
if (!prevCP) {
|
||||
return currentPoint;
|
||||
}
|
||||
return {
|
||||
x: currentPoint.x - (prevCP.x - currentPoint.x),
|
||||
y: currentPoint.y - (prevCP.y - currentPoint.y),
|
||||
};
|
||||
}
|
||||
return currentPoint;
|
||||
};
|
||||
prevCP = backTrackCP(i, prev);
|
||||
addPath(
|
||||
c,
|
||||
c,
|
||||
`M ${prev.x} ${prev.y} ${encodeSVGPath({
|
||||
type: SVGPathData.QUAD_TO,
|
||||
relative: false,
|
||||
x: c.x,
|
||||
y: c.y,
|
||||
x1: prevCP.x,
|
||||
y1: prevCP.y,
|
||||
})}`
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SVGPathData.ARC: {
|
||||
assert(prev);
|
||||
const center = arcEllipseCenter(
|
||||
prev.x,
|
||||
prev.y,
|
||||
c.rX,
|
||||
c.rY,
|
||||
c.xRot,
|
||||
c.lArcFlag,
|
||||
c.sweepFlag,
|
||||
c.x,
|
||||
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}`,
|
||||
c.rX === c.rY ? { ...center, r: c.rX } : undefined
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertNever(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
export const arcEllipseCenter = (
|
||||
x1: number,
|
||||
y1: number,
|
||||
rx: number,
|
||||
ry: number,
|
||||
a: number,
|
||||
fa: number,
|
||||
fs: number,
|
||||
x2: number,
|
||||
y2: number
|
||||
) => {
|
||||
const phi = (a * Math.PI) / 180;
|
||||
|
||||
const M = [
|
||||
[Math.cos(phi), Math.sin(phi)],
|
||||
[-Math.sin(phi), Math.cos(phi)],
|
||||
];
|
||||
const V = [(x1 - x2) / 2, (y1 - y2) / 2];
|
||||
|
||||
const [x1p, y1p] = [M[0][0] * V[0] + M[0][1] * V[1], M[1][0] * V[0] + M[1][1] * V[1]];
|
||||
|
||||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
|
||||
const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);
|
||||
if (lambda > 1) {
|
||||
rx = Math.sqrt(lambda) * rx;
|
||||
ry = Math.sqrt(lambda) * ry;
|
||||
}
|
||||
|
||||
const sign = fa === fs ? -1 : 1;
|
||||
|
||||
const co =
|
||||
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)
|
||||
);
|
||||
|
||||
const V2 = [(rx * y1p) / ry, (-ry * x1p) / rx];
|
||||
const Cp = [V2[0] * co, V2[1] * co];
|
||||
|
||||
const M2 = [
|
||||
[Math.cos(phi), -Math.sin(phi)],
|
||||
[Math.sin(phi), Math.cos(phi)],
|
||||
];
|
||||
const V3 = [(x1 + x2) / 2, (y1 + y2) / 2];
|
||||
const C = [
|
||||
M2[0][0] * Cp[0] + M2[0][1] * Cp[1] + V3[0],
|
||||
M2[1][0] * Cp[0] + M2[1][1] * Cp[1] + V3[1],
|
||||
];
|
||||
|
||||
return { x: C[0], y: C[1] };
|
||||
};
|
||||
28
docs/.vitepress/lib/categories.ts
Normal file
28
docs/.vitepress/lib/categories.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import {Category, IconEntity} from "../theme/types";
|
||||
|
||||
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 parsedFileContent = JSON.parse(fileContent)
|
||||
|
||||
return {
|
||||
name,
|
||||
title: parsedFileContent.title,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
}))
|
||||
}
|
||||
218
docs/.vitepress/lib/createCodeExamples.ts
Normal file
218
docs/.vitepress/lib/createCodeExamples.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
import {
|
||||
BUNDLED_LANGUAGES,
|
||||
type IThemeRegistration
|
||||
} from 'shiki'
|
||||
import {
|
||||
getHighlighter,
|
||||
} from 'shiki-processor'
|
||||
|
||||
type CodeExampleType = {
|
||||
title: string,
|
||||
lang: string,
|
||||
codes: {
|
||||
language?: string,
|
||||
code: string,
|
||||
metastring?: string,
|
||||
}[],
|
||||
}[]
|
||||
|
||||
const getIconCodes = (): CodeExampleType => {
|
||||
return [
|
||||
{
|
||||
lang: 'html',
|
||||
title: 'HTML',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<i data-lucide-name="Name"></i>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'tsx',
|
||||
title: 'React',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-react';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<PascalCase />
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'vue',
|
||||
title: 'Vue 3',
|
||||
codes: [
|
||||
{
|
||||
language: 'vue',
|
||||
code: `<script setup>
|
||||
import { PascalCase } from 'lucide-vue-next';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PascalCase />
|
||||
</template>
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'svelte',
|
||||
title: 'Svelte',
|
||||
codes: [
|
||||
{
|
||||
language: 'svelte',
|
||||
code: `<script>
|
||||
import { PascalCase } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<PascalCase />
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'preact',
|
||||
title: 'Preact',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-preact';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<PascalCase />
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'solid',
|
||||
title: 'Solid',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { PascalCase } from 'lucide-solid';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<PascalCase />
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'angular',
|
||||
title: 'Angular',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `// app.module.ts
|
||||
import { LucideAngularModule, PascalCase } from 'lucide-angular';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
LucideAngularModule.pick({ PascalCase })
|
||||
],
|
||||
})
|
||||
|
||||
// app.component.html
|
||||
<lucide-icon name="Name"></lucide-icon>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'html',
|
||||
title: 'Icon Font',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<style>
|
||||
@import ('~lucide-static/font/Lucide.css');
|
||||
</style>
|
||||
|
||||
<div class="icon-Name"></div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'dart',
|
||||
title: 'Flutter',
|
||||
codes: [
|
||||
{
|
||||
language: 'dart',
|
||||
code: `Icon(LucideIcons.Name);
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export type ThemeOptions =
|
||||
| IThemeRegistration
|
||||
| { light: IThemeRegistration; dark: IThemeRegistration }
|
||||
|
||||
const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
||||
const highlighter = await getHighlighter({
|
||||
themes: ['material-theme-palenight'],
|
||||
langs: [...BUNDLED_LANGUAGES],
|
||||
processors: []
|
||||
})
|
||||
|
||||
const highlightedCode = highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
// lineOptions,
|
||||
theme: 'material-theme-palenight'
|
||||
}).replace('background-color: #292D3E', '')
|
||||
|
||||
return `<div class="language-${lang} ${active ? 'active' : ''}">
|
||||
<button title="Copy Code" class="copy"></button>
|
||||
<span class="lang">${lang}</span>
|
||||
${highlightedCode}
|
||||
</div>`
|
||||
}
|
||||
|
||||
|
||||
export default async function createCodeExamples() {
|
||||
const codes = getIconCodes();
|
||||
|
||||
const codeExamplePromises = codes.map(async (codeTemplate, index) => {
|
||||
const { title, lang, codes } = codeTemplate;
|
||||
const isFirst = index === 0;
|
||||
|
||||
const code = await highLightCode(codes[0].code, codes[0].language || lang, isFirst);
|
||||
|
||||
return {
|
||||
title,
|
||||
language: codes[0].language || lang,
|
||||
code,
|
||||
};
|
||||
})
|
||||
|
||||
return Promise.all(codeExamplePromises);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { promises as fs, constants } from 'fs';
|
||||
import path from 'path';
|
||||
import yaml from 'js-yaml'
|
||||
import { PackageItem } from '../components/Package';
|
||||
import { PackageItem } from '../theme/types';
|
||||
|
||||
const fileExist = (filePath) => fs.access(filePath, constants.F_OK).then(() => true).catch(() => false)
|
||||
|
||||
17
docs/.vitepress/lib/generateZip.ts
Normal file
17
docs/.vitepress/lib/generateZip.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export type IconContent = [icon: string, src:string];
|
||||
|
||||
async function generateZip(icons: IconContent[]) {
|
||||
const JSZip = (await import('jszip')).default
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
const addingZipPromises = icons.map(([name, src]) =>
|
||||
zip.file(`${name}.svg`, src),
|
||||
);
|
||||
|
||||
await Promise.all(addingZipPromises)
|
||||
|
||||
return zip.generateAsync({ type: 'blob' });
|
||||
}
|
||||
|
||||
export default generateZip
|
||||
17
docs/.vitepress/lib/getFallbackZip.tsx
Normal file
17
docs/.vitepress/lib/getFallbackZip.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
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";
|
||||
|
||||
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]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export default getFallbackZip
|
||||
28
docs/.vitepress/lib/helpers.ts
Normal file
28
docs/.vitepress/lib/helpers.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* djb2 hashing function
|
||||
*
|
||||
* @param {string} string
|
||||
* @param {number} seed
|
||||
* @returns {string} A hashed string of 6 characters
|
||||
*/
|
||||
export const hash = (string: string, seed = 5381) => {
|
||||
let i = string.length;
|
||||
|
||||
while (i) {
|
||||
// eslint-disable-next-line no-bitwise, no-plusplus
|
||||
seed = (seed * 33) ^ string.charCodeAt(--i);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return (seed >>> 0).toString(36).substr(0, 6);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate Hashed string based on name and attributes
|
||||
*
|
||||
* @param {object} seed
|
||||
* @param {string} seed.name A name, for example an icon name
|
||||
* @param {object} seed.attributes An object of SVGElement Attrbutes
|
||||
* @returns {string} A hashed string of 6 characters
|
||||
*/
|
||||
export const generateHashedKey = ({ name, attributes }) => hash(JSON.stringify([name, attributes]));
|
||||
47
docs/.vitepress/lib/icons.ts
Normal file
47
docs/.vitepress/lib/icons.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
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");
|
||||
|
||||
export interface GetDataOptions {
|
||||
withChildKeys?: boolean
|
||||
}
|
||||
|
||||
export async function getData(name: string) {
|
||||
const jsonPath = path.join(directory, `${name}.json`);
|
||||
const jsonContent = fs.readFileSync(jsonPath, "utf8");
|
||||
const { tags, categories, contributors } = JSON.parse(jsonContent);
|
||||
|
||||
const iconNode = iconNodes[name]
|
||||
|
||||
const releaseData = releaseMeta?.[name] ?? {
|
||||
"createdRelease": {
|
||||
"version": "0.0.0",
|
||||
"date": DATE_OF_FORK
|
||||
},
|
||||
"changedRelease": {
|
||||
"version": "0.0.0",
|
||||
"date": DATE_OF_FORK
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
tags,
|
||||
categories,
|
||||
iconNode,
|
||||
contributors,
|
||||
...releaseData
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAllData(): Promise<{ name: string, iconNode: IconNodeWithKeys}[]> {
|
||||
const names = Object.keys(iconNodes);
|
||||
|
||||
return Promise.all(names.map((name) => getData(name)));
|
||||
}
|
||||
118
docs/.vitepress/sidebar.ts
Normal file
118
docs/.vitepress/sidebar.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { DefaultTheme, UserConfig } from "vitepress"
|
||||
|
||||
const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||
'guide':[
|
||||
{
|
||||
text: 'Introduction',
|
||||
items: [
|
||||
{ text: 'What is lucide?', link: '/guide/' },
|
||||
{ text: 'Installation', link: '/guide/installation' },
|
||||
{ text: 'Comparison', link: '/guide/comparison' }
|
||||
]
|
||||
},
|
||||
// {
|
||||
// text: 'Using Icons',
|
||||
// items: [
|
||||
// {
|
||||
// text: 'How to use icons',
|
||||
// link: 'how-to-use-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Styling icons',
|
||||
// link: 'styling-icons'
|
||||
// },
|
||||
// {
|
||||
// text: 'Accessibility',
|
||||
// link: 'accessibility'
|
||||
// },
|
||||
// {
|
||||
// text: 'What should I use',
|
||||
// link: 'what-should-i-use'
|
||||
// },
|
||||
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
text: 'Packages',
|
||||
items: [
|
||||
{
|
||||
text: 'Lucide',
|
||||
link: '/guide/packages/lucide'
|
||||
},
|
||||
{
|
||||
text: 'Lucide React',
|
||||
link: '/guide/packages/lucide-react'
|
||||
},
|
||||
{
|
||||
text: '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'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Svelte',
|
||||
link: '/guide/packages/lucide-svelte'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Solid',
|
||||
link: '/guide/packages/lucide-solid'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Preact',
|
||||
link: '/guide/packages/lucide-preact'
|
||||
},
|
||||
{
|
||||
text: 'Lucide Angular',
|
||||
link: '/guide/packages/lucide-angular'
|
||||
},
|
||||
{
|
||||
text: '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'
|
||||
},
|
||||
{
|
||||
text: 'Designing in Illustrator',
|
||||
link: '/guide/design/illustrator-guide'
|
||||
},
|
||||
{
|
||||
text: 'Designing in InkScape',
|
||||
link: '/guide/design/inkscape-guide'
|
||||
},
|
||||
{
|
||||
text: 'Designing in Figma',
|
||||
link: '/guide/design/figma-guide'
|
||||
},
|
||||
]
|
||||
},
|
||||
],
|
||||
'icons': [
|
||||
{ text: '', link: '/' },
|
||||
// { text: 'Categorized', link: '/icons/categorized' },
|
||||
// {
|
||||
// text: 'Categories',
|
||||
// items: [
|
||||
// ...(getAllCategoryFiles().map((category) => ({ text: category, link: `/icons/category/${category}` })))
|
||||
// ]
|
||||
// }
|
||||
],
|
||||
}
|
||||
|
||||
export default sidebar
|
||||
11
docs/.vitepress/theme/components/PageContainer.vue
Normal file
11
docs/.vitepress/theme/components/PageContainer.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 32px;
|
||||
}
|
||||
</style>
|
||||
62
docs/.vitepress/theme/components/base/Badge.vue
Normal file
62
docs/.vitepress/theme/components/base/Badge.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { useRouter } from 'vitepress';
|
||||
|
||||
const { go } = useRouter()
|
||||
const props = defineProps<{
|
||||
href?: string
|
||||
}>()
|
||||
|
||||
const component = computed(() => props.href ? 'a' : 'div')
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="component"
|
||||
:href="href"
|
||||
class="badge"
|
||||
@click="props?.href ? go(href) : undefined"
|
||||
>
|
||||
<slot/>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.badge, a.badge {
|
||||
display: block;
|
||||
border: 1px solid transparent;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
padding: 2px 12px;
|
||||
white-space: nowrap;
|
||||
transition: color 0.25s, border-color 0.25s, background-color 0.25s;
|
||||
border-radius: 6px;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
color: var(--vp-c-text-1);
|
||||
/* width: 56px;
|
||||
height: 56px; */
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.badge[href]:hover, a.badge:hover {
|
||||
border-color: var(--vp-button-alt-hover-border);
|
||||
color: var(--vp-button-alt-hover-text);
|
||||
background-color: var(--vp-button-alt-hover-bg);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.badge[href]:active {
|
||||
border-color: var(--vp-button-alt-active-border);
|
||||
color: var(--vp-button-alt-active-text);
|
||||
background-color: var(--vp-button-alt-active-bg);
|
||||
}
|
||||
|
||||
.badge.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
/* color: var(--vp-button-alt-active-text);
|
||||
background-color: var(--vp-button-alt-active-bg); */
|
||||
}
|
||||
</style>
|
||||
187
docs/.vitepress/theme/components/base/ButtonMenu.vue
Normal file
187
docs/.vitepress/theme/components/base/ButtonMenu.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<script setup lang="ts">
|
||||
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import {
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
ListboxOptions,
|
||||
ListboxOption,
|
||||
} from '@headlessui/vue'
|
||||
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon'
|
||||
import { chevronUp } from '../../../data/iconNodes'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
|
||||
interface Props {
|
||||
options: {
|
||||
text: string
|
||||
onClick?: () => void
|
||||
}[],
|
||||
callOptionOnClick?: boolean
|
||||
buttonClass?: string
|
||||
id: string
|
||||
popoverPosition?: 'top' | 'bottom'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
callOptionOnClick: false,
|
||||
popoverPosition: 'bottom'
|
||||
})
|
||||
|
||||
const emit = defineEmits(['click', 'optionClick'])
|
||||
|
||||
const buttonRef = ref(null)
|
||||
|
||||
const selectedOption = useStorage(props.id, props.options[0].text)
|
||||
const selectionOptionAction = computed(() => props.options.find(option => option.text === selectedOption.value).onClick)
|
||||
|
||||
function onClick(event) {
|
||||
selectionOptionAction.value()
|
||||
|
||||
|
||||
emit('click', event)
|
||||
}
|
||||
|
||||
function onOptionClick(event, option) {
|
||||
if(!props.callOptionOnClick) {
|
||||
return
|
||||
}
|
||||
|
||||
option.onClick()
|
||||
|
||||
emit('optionClick', event)
|
||||
}
|
||||
|
||||
const ChevronUp = createLucideIcon('ChevronUp', chevronUp)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Listbox v-model="selectedOption">
|
||||
<div class="menu" >
|
||||
<div class="button-wrapper">
|
||||
<VPButton
|
||||
v-bind="$attrs"
|
||||
:text="selectedOption"
|
||||
@click="onClick"
|
||||
theme="alt"
|
||||
class="main-button"
|
||||
:class="[props.buttonClass]"
|
||||
ref="buttonRef"
|
||||
/>
|
||||
<ListboxButton
|
||||
:as="VPButton"
|
||||
:text="''"
|
||||
theme="alt"
|
||||
class="arrow-up-button"
|
||||
:class="popoverPosition"
|
||||
/>
|
||||
</div>
|
||||
<ListboxOptions class="menu-items" :class="popoverPosition">
|
||||
<ListboxOption
|
||||
as="button"
|
||||
class="menu-item"
|
||||
v-for="option in options"
|
||||
:value="option.text"
|
||||
@click="onOptionClick($event, option)"
|
||||
>
|
||||
{{ option.text }}
|
||||
</ListboxOption>
|
||||
</ListboxOptions>
|
||||
</div>
|
||||
</Listbox>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.menu {
|
||||
position: relative;
|
||||
}
|
||||
.menu-items {
|
||||
--menu-offset: 44px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
min-width: 128px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background-color: var(--vp-c-bg);
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
transition: background-color 0.5s;
|
||||
max-height: calc(100vh - var(--vp-nav-height));
|
||||
overflow-y: auto;
|
||||
z-index: 90;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 2px 8px;
|
||||
text-align: left;
|
||||
display: block;
|
||||
border-radius: 6px;
|
||||
padding: 0 12px;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--vp-c-text-1);
|
||||
white-space: nowrap;
|
||||
transition: background-color .25s,color .25s;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
color: var(--vp-c-brand);
|
||||
background-color: var(--vp-c-bg-elv-mute);
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
color: var(--vp-c-brand);
|
||||
background-color: var(--vp-c-bg-elv);
|
||||
}
|
||||
|
||||
.main-button {
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-right-radius: 0 !important;
|
||||
padding-right: 12px !important;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.arrow-up-button {
|
||||
display: inline-flex;
|
||||
height: 40px;
|
||||
border-top-left-radius: 0 !important;
|
||||
border-bottom-left-radius: 0 !important;
|
||||
padding-left: 4px !important;
|
||||
padding-right: 8px !important;
|
||||
position: relative;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
.arrow-up-button::before {
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%0A%3E%3Cpolyline points='18 15 12 9 6 15' /%3E%3C/svg%3E%0A");
|
||||
width: 20px;
|
||||
height: 28px;
|
||||
margin: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dark .arrow-up-button::before {
|
||||
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%0A%3E%3Cpolyline points='18 15 12 9 6 15' /%3E%3C/svg%3E%0A");
|
||||
}
|
||||
|
||||
.menu-items.bottom {
|
||||
top: var(--menu-offset);
|
||||
}
|
||||
|
||||
.menu-items.top {
|
||||
bottom: var(--menu-offset);
|
||||
}
|
||||
|
||||
.arrow-up-button.top::before {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.arrow-up-button.bottom::before {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
51
docs/.vitepress/theme/components/base/CodeGroup.vue
Normal file
51
docs/.vitepress/theme/components/base/CodeGroup.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineProps, onMounted } from 'vue'
|
||||
const props = defineProps<{
|
||||
groups: string[] | undefined,
|
||||
groupName: string,
|
||||
}>()
|
||||
|
||||
const getSaveIdname = (name: string) => {
|
||||
return name.toLowerCase().replace(/\s/g, '-')
|
||||
}
|
||||
|
||||
const tabs = computed(() => props.groups?.map((group) => {
|
||||
return {
|
||||
id: getSaveIdname(group),
|
||||
name: group,
|
||||
}
|
||||
}))
|
||||
|
||||
const saveTabId = (id: string) => {
|
||||
localStorage.setItem(props.groupName, id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const id = localStorage.getItem(props.groupName)
|
||||
if (id) {
|
||||
const tab = document.getElementById(`label-tab-${id}`)
|
||||
|
||||
if (tab) {
|
||||
tab.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-code-group">
|
||||
<div class="tabs">
|
||||
<template v-for="(tab, index) in tabs">
|
||||
<input
|
||||
type="radio"
|
||||
:id="`tab-${tab.id}`"
|
||||
:name="`group-${groupName}`"
|
||||
:checked="index === 0"
|
||||
@change="saveTabId(tab.id)"
|
||||
>
|
||||
<label :for="`tab-${tab.id}`" :id="`label-tab-${tab.id}`">{{ tab.name }}</label>
|
||||
</template>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
93
docs/.vitepress/theme/components/base/ColorPicker.vue
Normal file
93
docs/.vitepress/theme/components/base/ColorPicker.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
id: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="color-picker">
|
||||
<div class="color-input-wrapper">
|
||||
<!-- TODO: Add currentColor div if value is currentColor -->
|
||||
<input
|
||||
type="color"
|
||||
:id="id"
|
||||
:name="id"
|
||||
class="color-input"
|
||||
v-model="value"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
:id="`${id}-input`"
|
||||
:name="`${id}-input`"
|
||||
class="color-input-text"
|
||||
aria-label="Color picker input"
|
||||
v-model="value"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.color-input {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: -5px;
|
||||
}
|
||||
.color-input-wrapper {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.color-picker {
|
||||
background: var(--color-picker-bg, var(--vp-c-bg-soft));
|
||||
border-radius: 8px;
|
||||
color: var(--vp-c-text-2);
|
||||
padding: 4px 8px;
|
||||
height: auto;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
border: 1px solid transparent;
|
||||
cursor: text;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.color-input-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 8px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
border-radius: 8px;
|
||||
cursor: text;
|
||||
transition: border-color 0.25s, background 0.4s ease;
|
||||
}
|
||||
|
||||
.color-picker:hover, .color-picker:focus {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-alt);
|
||||
}
|
||||
|
||||
.color-input[value="currentColor"] {
|
||||
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user