Compare commits

...

15 Commits

Author SHA1 Message Date
Karsa
48fa902b1c Added ear and ear-off (#804)
* Added ear and ear-off

* Fixes incorrect commit

Co-authored-by: Karsa <karsa@karsa.org>
2022-10-03 16:37:05 +02:00
Eric Fennis
cdd57e6610 Add Solid package (#797)
* init solid package

* add testing

* Fix tests solid

* add workflow

* update types build

* Fix typings file

* switch to camelCase props

* revert camelcased props

* Fix tests

* Fixing dynamic reactive props in lucide icons

* release beta

* strokeWidth fix

* bump beta version

* improve docs

* update beta release

* update vitest config

* Add automatic release for solid package
2022-10-03 16:36:33 +02:00
Lucide Bot
1f5119785b 📦 Bump lucide package versions to 0.90.0 2022-09-20 06:18:24 +00:00
Oliver Schmidt
90a3f6e1dd Add book-open-check icon #789 (#790)
* Add book-open-check icon

* Added tags for book-open-check

* Update icons/book-open-check.svg

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

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
Co-authored-by: Karsa <contact@karsa.org>
2022-09-20 08:12:10 +02:00
Lucide Bot
4ae4eae53d 📦 Bump lucide package versions to 0.89.0 2022-09-15 09:26:27 +00:00
Eric Fennis
e99228c65d Add plug icons (#786)
>
>
Co-authored-by: Karsa <karsa@karsa.org>
2022-09-15 11:18:55 +02:00
Eric Fennis
34249ff42c Fix site build (#796)
* Some fixes site

* A lot of fixes in the site

* move file
2022-09-13 09:03:13 +02:00
andreas
f9d37968d6 Fix typo in lucide-vuew (#795) 2022-09-12 21:26:35 +02:00
Chad Fernandez
864b71822b Fixed a small typo in the docs. (#787) 2022-08-25 11:44:40 +02:00
Lucide Bot
bc3bd1267a 📦 Bump lucide package versions to 0.88.0 2022-08-18 16:29:35 +00:00
Karsa
5d22d8e456 Added sailboat (#665)
* Added accessibility icon as per https://github.com/feathericons/feather/issues/633

* added newline to end of file

* Updated icon to comply with design guidelines and more closely match accessibleicon.org

* Added sailboat

* Updates icon based on @ericfennis' suggestion. Adds harbour and port tags.

* Update icons/sailboat.svg

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

* Update icons/sailboat.svg

Merge extra paths into a single triangle.

Co-authored-by: Karsa <karsa@karsa.org>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2022-08-18 18:20:10 +02:00
Lucide Bot
db98602331 📦 Bump lucide package versions to 0.87.0 2022-08-18 10:25:46 +00:00
it-is-not
4eca473cd4 Add arrow-up-down icon (#785)
* add arrow-up-down icon

* add more tags

* Update tags.json

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

* Update icons/arrow-up-down.svg

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

* add tags to arrow-left-right

Co-authored-by: Karsa <contact@karsa.org>
2022-08-18 12:18:23 +02:00
Eric Fennis
e6eedee22d Add version command to package.jsons 2022-08-10 19:12:21 +02:00
Lucide Bot
a8174a34b5 📦 Bump lucide package versions to 0.86.0 2022-08-10 13:38:57 +00:00
87 changed files with 3171 additions and 742 deletions

View File

@@ -17,5 +17,9 @@ module.exports = {
trailingComma: 'all'
}
]
}
},
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./site/tsconfig.json', './packages/*/tsconfig.json'],
},
};

48
.github/workflows/lucide-solid.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Lucide Solid Checks
on:
pull_request:
paths:
- packages/lucide-solid/**
push:
paths:
- packages/lucide-solid/**
jobs:
lucide-solid:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3.4.1
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 }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm --filter lucide-solid build
- name: Test
run: pnpm --filter lucide-solid test

View File

@@ -411,6 +411,61 @@ jobs:
name: lucide-preact-package-json
path: packages/lucide-preact/package.json
lucide-solid:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: pre-build
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3.4.1
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 }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
- name: Set Auth Token
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
- name: Set package.json version lucide
run: pnpm --filter lucide-solid version --new-version ${{ needs.pre-build.outputs.VERSION }} --no-git-tag-version
- name: Build
run: pnpm --filter lucide-solid build
- name: Test
run: pnpm --filter lucide-solid test
- name: Publish
run: pnpm --filter lucide-solid publish --no-git-checks
- name: Upload package.json
uses: actions/upload-artifact@v2
with:
name: lucide-solid-package-json
path: packages/lucide-solid/package.json
lucide-svelte:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest

View File

@@ -8,7 +8,7 @@ title: Comparison
Lucide is a community-run fork of [Feather Icons](https://github.com/feathericons/feather).
It began after growing disaffection of the [Feather Icons](https://github.com/feathericons/feather) project moderation. With over 300+ open issues and over 100+ open PRs, the Feather Icons project has been abandoned adn not maintained actively. This unfortunately means that hundreds of developers and designers wasted their time contributing to Feather Icons with no chance of PRs being accepted.
It began after growing disaffection of the [Feather Icons](https://github.com/feathericons/feather) project moderation. With over 300+ open issues and over 100+ open PRs, the Feather Icons project has been abandoned and not maintained actively. This unfortunately means that hundreds of developers and designers wasted their time contributing to Feather Icons with no chance of PRs being accepted.
Lucide is trying to expand the icon set as much as possible while staying faithful to the original simplistic design language. We do this as a community of devs and designers.

View File

@@ -18,7 +18,7 @@ npm install lucide-preact
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a preact component.
### Example

View File

@@ -16,7 +16,7 @@ npm install lucide-react-native
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a react component.
### Example

View File

@@ -14,7 +14,7 @@ npm install lucide-react
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a react component.
### Example

View File

@@ -2,7 +2,7 @@
Implementation of the lucide icon library for Vue 3 applications.
> ⚠️ This version of lucide is for Vue 3, For Vue 2 got to [lucide-vue-next](lucide-vue)
> ⚠️ This version of lucide is for Vue 3, For Vue 2 got to [lucide-vue](lucide-vue)
## Installation
@@ -20,7 +20,7 @@ npm install lucide-vue-next
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a vue component.
### Example

View File

@@ -16,7 +16,7 @@ npm install lucide-vue
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a vue component.
### Example

View File

@@ -44,7 +44,7 @@ Here is a complete example with unpkg
### With ESModules
To reduce bundle size, lucide is built to be fully treeshakable.
To reduce bundle size, lucide is built to be fully tree-shakable.
The `createIcons` function will search for HTMLElements with the attribute `icon-name` and replace it with the svg from the given icon name.
```html

16
icons/arrow-up-down.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="11 17 7 21 3 17"/>
<line x1="7" y1="21" x2="7" y2="9"/>
<polyline points="21 7 17 3 13 7"/>
<line x1="17" y1="15" x2="17" y2="3"/>
</svg>

After

Width:  |  Height:  |  Size: 365 B

15
icons/book-open-check.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M8 3H2v15h7c1.7 0 3 1.3 3 3V7c0-2.2-1.8-4-4-4Z" />
<path d="m16 12 2 2 4-4" />
<path d="M22 6V3h-6c-2.2 0-4 1.8-4 4v14c0-1.7 1.3-3 3-3h7v-2.3" />
</svg>

After

Width:  |  Height:  |  Size: 369 B

17
icons/ear-off.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 18.5a3.5 3.5 0 1 0 7 0c0-1.57.92-2.52 2.04-3.46" />
<path d="M6 8.5c0-.75.13-1.47.36-2.14" />
<path d="M8.8 3.15A6.5 6.5 0 0 1 19 8.5c0 1.63-.44 2.81-1.09 3.76" />
<path d="M12.5 6A2.5 2.5 0 0 1 15 8.5M10 13a2 2 0 0 0 1.82-1.18" />
<line x1="2" y1="2" x2="22" y2="22" />
</svg>

After

Width:  |  Height:  |  Size: 501 B

14
icons/ear.svg Normal file
View File

@@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 8.5a6.5 6.5 0 1 1 13 0c0 6-6 6-6 10a3.5 3.5 0 1 1-7 0" />
<path d="M15 8.5a2.5 2.5 0 0 0-5 0v1a2 2 0 1 1 0 4" />
</svg>

After

Width:  |  Height:  |  Size: 337 B

17
icons/plug-2.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 2v6" />
<path d="M15 2v6" />
<path d="M12 17v5" />
<path d="M5 8h14" />
<path d="M6 11V8h12v3a6 6 0 1 1-12 0v0Z" />
</svg>

After

Width:  |  Height:  |  Size: 346 B

16
icons/plug.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 22v-5" />
<path d="M9 7V2" />
<path d="M15 7V2" />
<path d="M6 13V8h12v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4Z" />
</svg>

After

Width:  |  Height:  |  Size: 338 B

15
icons/sailboat.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M22 18H2a4 4 0 0 0 4 4h12a4 4 0 0 0 4-4Z"/>
<path d="M21 14 10 2 3 14h18Z"/>
<path d="M10 2v16"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

View File

@@ -1,7 +1,7 @@
{
"name": "lucide-angular",
"description": "A Lucide icon library package for Angular applications",
"version": "0.84.0",
"version": "0.90.0",
"author": "SMAH1",
"license": "ISC",
"homepage": "https://lucide.dev",
@@ -31,7 +31,8 @@
"test:watch": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "ngcc"
"postinstall": "ngcc",
"version": "pnpm version --git-tag-version=false"
},
"dependencies": {
"tslib": "^2.3.1"

View File

@@ -1,6 +1,6 @@
name: lucide_icons
description: A Lucide icon library package for Flutter applications. Fork of Feather Icons, open for anyone to contribute icons.
version: 0.84.0
version: 0.90.0
homepage: https://lucide.dev
repository: https://github.com/lucide-icons/lucide

View File

@@ -16,7 +16,7 @@ npm install lucide-preact
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a preact component.
### Example

View File

@@ -1,7 +1,7 @@
{
"name": "lucide-preact",
"description": "A Lucide icon library package for Preact applications",
"version": "0.84.0",
"version": "0.90.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
@@ -17,17 +17,20 @@
"module": "dist/esm/lucide-preact.js",
"unpkg": "dist/umd/lucide-preact.min.js",
"typings": "dist/lucide-preact.d.ts",
"files": ["dist"],
"files": [
"dist"
],
"sideEffects": false,
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:types && pnpm build:bundles",
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:types && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.js",
"build:icons": "node ../../scripts/buildIcons.mjs --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey",
"build:es": "babel src -d dist/esm",
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest"
"test": "jest",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/preact": "^2.0.1",

View File

@@ -21,6 +21,7 @@ interface LucideProps extends Partial<Omit<JSX.SVGAttributes, "ref" | "size">> {
ref?: string | ((component: any) => any) | RefObject<any>;
color?: string
size?: string | number
strokeWidth?: string | number
}
// Generated icons

View File

@@ -18,7 +18,7 @@ npm install lucide-react-native
## How to use
It's built with ES modules so it's completely threeshakable.
It's built with ES modules so it's completely tree-shakable.
Each icon can be imported as a react component.
### Example

View File

@@ -27,7 +27,8 @@
"build:icons": "node ../../scripts/buildIcons.mjs --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey",
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest"
"test": "jest",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/react": "^11.2.6",

View File

@@ -16,7 +16,7 @@ npm install lucide-react
## How to use
It's built with ES modules so it's completely threeshakable.
It's built with ES modules so it's completely tree-shakable.
Each icon can be imported as a react component.
### Example

View File

@@ -1,7 +1,7 @@
{
"name": "lucide-react",
"description": "A Lucide icon library package for React applications",
"version": "0.84.0",
"version": "0.90.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
@@ -18,7 +18,9 @@
"unpkg": "dist/umd/lucide-react.min.js",
"typings": "dist/lucide-react.d.ts",
"sideEffects": false,
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:types && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE",
@@ -27,7 +29,8 @@
"build:es": "babel src -d dist/esm",
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest"
"test": "jest",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/react": "^11.2.6",

View File

@@ -0,0 +1,78 @@
# Lucide Solid
Implementation of the lucide icon library for solid applications.
> What is lucide? Read it [here](https://github.com/lucide-icons/lucide#what-is-lucide).
## Installation
```sh
yarn add lucide-solid
# or
npm install lucide-solid
```
## How to use
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a solid component.
### Example
You can pass additional props to adjust the icon.
``` js
import { Camera } from 'lucide-solid';
// Returns SolidComponent
// Usage
const App = () => {
return <Camera color="red" size={48}/>
};
export default App;
```
### Props
| name | type | default
| ------------ | -------- | --------
| `size` | *Number* | 24
| `color` | *String* | currentColor
| `strokeWidth`| *Number* | 2
### Custom props / svg attributes
You can also pass custom props that will be added in the as attributes. With that you can modify the icons look by passing svg attributes.
``` js
// Usage
const App = () => {
return <Camera fill="red" stroke-linejoin="bevel"/>
};
```
### One generic icon component
It is possible to create one generic icon component to load icons.
> :warning: Example below importing all EsModules, caution using this example, not recommended when you using bundlers, your application build size will grow strongly.
#### Icon Component Example
``` tsx
import * as icons from 'lucide-solid';
import type { LucideProps } from 'lucide-solid';
import { splitProps } from 'solid-js';
import { Dynamic } from 'solid-js/web';
const Icon = (props: { name: keyof typeof icons } & LucideProps) => {
const [local, others] = splitProps(props, ["name"]);
return <Dynamic component={icons[local.name]} {...others} />
};
export default Icon;
```

View File

@@ -0,0 +1,6 @@
const mainConfig = require('../../babel.config');
module.exports = {
presets: ['solid'],
env: mainConfig.env,
};

View File

@@ -0,0 +1,51 @@
{
"name": "lucide-solid",
"description": "A Lucide icon library package for Solid applications",
"version": "0.88.0-beta.3",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
"repository": {
"type": "git",
"url": "https://github.com/lucide-icons/lucide.git",
"directory": "packages/lucide-solid"
},
"author": "Eric Fennis",
"amdName": "lucide-solid",
"main": "dist/cjs/lucide-solid.js",
"main:umd": "dist/umd/lucide-solid.js",
"module": "dist/esm/lucide-solid.js",
"unpkg": "dist/umd/lucide-solid.min.js",
"typings": "dist/lucide-solid.d.ts",
"files": [
"dist"
],
"sideEffects": false,
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:types && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.js",
"build:icons": "node ../../scripts/buildIcons.mjs --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey",
"build:es": "babel src -d dist/esm",
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test:jest": "jest",
"test": "vitest",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"babel-preset-solid": "^1.5.4",
"jest": "^26.6.3",
"jsdom": "^20.0.0",
"solid-js": "^1.4.7",
"solid-testing-library": "^0.3.0",
"solid-jest": "^0.2.0",
"vite": "^2.6.4",
"vite-plugin-solid": "^2.3.0",
"vitest": "^0.23.2"
},
"peerDependencies": {
"solid-js": "^1.4.7"
}
}

View File

@@ -0,0 +1,47 @@
import plugins from '../../rollup.plugins';
import pkg from './package.json';
const packageName = 'LucideSolid';
const outputFileName = 'lucide-solid';
const outputDir = 'dist';
const inputs = [`src/lucide-solid.js`];
const bundles = [
{
format: 'umd',
inputs,
outputDir,
minify: true,
},
{
format: 'umd',
inputs,
outputDir,
},
{
format: 'cjs',
inputs,
outputDir,
},
];
const configs = bundles
.map(({ inputs, outputDir, format, minify }) =>
inputs.map(input => ({
input,
plugins: plugins(pkg, minify),
external: ['solid-js', 'solid-js/h'],
output: {
name: packageName,
file: `${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
format,
sourcemap: true,
globals: {
'solid-js': 'solid-js',
'solid-js/h': 'solid-js/h',
},
},
})),
)
.flat();
export default configs;

View File

@@ -0,0 +1,47 @@
import path from 'path';
import {
writeFile,
readSvgDirectory,
resetFile,
toPascalCase,
appendFile,
getCurrentDirPath
} from '../../../scripts/helpers.mjs';
const currentDir = getCurrentDirPath(import.meta.url)
const srcDirectory = path.join(currentDir, '../dist');
// Declare type definitions
const typeDefinitions = `\
/// <reference types="solid-js" />
import { JSX } from 'solid-js'
interface LucideProps extends Partial<JSX.IntrinsicElements & JSX.SvgSVGAttributes<SVGSVGElement>> {
key?: string | number;
ref?: string | ((component: any) => any);
color?: string
size?: string | number
strokeWidth?: string | number
class?: string
}
// Generated icons
`;
const ICONS_DIR = path.resolve(currentDir, '../../../icons');
const TYPES_FILE = 'lucide-solid.d.ts';
resetFile(TYPES_FILE, srcDirectory);
writeFile(typeDefinitions, TYPES_FILE, srcDirectory);
const svgFiles = readSvgDirectory(ICONS_DIR);
svgFiles.forEach(svgFile => {
const iconName = path.basename(svgFile, '.svg');
const componentName = toPascalCase(iconName);
const exportTypeString = `export declare const ${componentName}: (props: LucideProps) => JSX.Element;\n`;
appendFile(exportTypeString, TYPES_FILE, srcDirectory);
});
console.log(`Generated ${TYPES_FILE} file with`, svgFiles.length, 'icons');

View File

@@ -0,0 +1,7 @@
export default ({ componentName, children }) => `
import createSolidComponent from '../createSolidComponent';
const ${componentName} = createSolidComponent('${componentName}', ${JSON.stringify(children)});
export default ${componentName};
`;

View File

@@ -0,0 +1,47 @@
import h from 'solid-js/h';
import { splitProps } from 'solid-js';
import defaultAttributes from './defaultAttributes';
/**
* Converts string to KebabCase
* Copied from scripts/helper. If anyone knows how to properly import it here
* then please fix it.
*
* @param {string} string
* @returns {string} A kebabized string
*/
export const toKebabCase = string => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
export default (iconName, iconNode) => {
const Component = props => {
const [localProps, rest] = splitProps(props, [
'color',
'size',
'strokeWidth',
'children',
'class',
]);
const svgProps = {
...defaultAttributes,
width: () => (localProps.size != null ? localProps.size : defaultAttributes.width),
height: () => (localProps.size != null ? localProps.size : defaultAttributes.height),
stroke: () => (localProps.color != null ? localProps.color : defaultAttributes.stroke),
'stroke-width': () =>
localProps.strokeWidth != null ? localProps.strokeWidth : defaultAttributes['stroke-width'],
class: () =>
`lucide lucide-${toKebabCase(iconName)} ${
localProps.class != null ? localProps.class : ''
}`,
};
return h(
'svg',
[svgProps, rest],
[...iconNode.map(([tag, attrs]) => h(tag, attrs)), localProps.children],
);
};
Component.displayName = `${iconName}`;
return Component;
};

View File

@@ -0,0 +1,11 @@
export default {
xmlns: 'http://www.w3.org/2000/svg',
width: 24,
height: 24,
viewBox: '0 0 24 24',
fill: 'none',
stroke: 'currentColor',
'stroke-width': 2,
'stroke-linecap': 'round',
'stroke-linejoin': 'round',
};

View File

@@ -0,0 +1 @@
Folder for generated icons

View File

@@ -0,0 +1 @@
export * from './icons';

View File

@@ -0,0 +1,5 @@
// Vitest Snapshot v1
exports[`Using lucide icon components > should adjust the size, stroke color and stroke width 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"4\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid \\" data-testid=\\"grid-icon\\"><rect x=\\"3\\" y=\\"3\\" width=\\"18\\" height=\\"18\\" rx=\\"2\\" ry=\\"2\\" key=\\"maln0c\\"></rect><line x1=\\"3\\" y1=\\"9\\" x2=\\"21\\" y2=\\"9\\" key=\\"1uch6j\\"></line><line x1=\\"3\\" y1=\\"15\\" x2=\\"21\\" y2=\\"15\\" key=\\"1xojw2\\"></line><line x1=\\"9\\" y1=\\"3\\" x2=\\"9\\" y2=\\"21\\" key=\\"nvcl17\\"></line><line x1=\\"15\\" y1=\\"3\\" x2=\\"15\\" y2=\\"21\\" key=\\"jcv93v\\"></line></svg>"`;
exports[`Using lucide icon components > should render an component 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid \\"><rect x=\\"3\\" y=\\"3\\" width=\\"18\\" height=\\"18\\" rx=\\"2\\" ry=\\"2\\" key=\\"maln0c\\"></rect><line x1=\\"3\\" y1=\\"9\\" x2=\\"21\\" y2=\\"9\\" key=\\"1uch6j\\"></line><line x1=\\"3\\" y1=\\"15\\" x2=\\"21\\" y2=\\"15\\" key=\\"1xojw2\\"></line><line x1=\\"9\\" y1=\\"3\\" x2=\\"9\\" y2=\\"21\\" key=\\"nvcl17\\"></line><line x1=\\"15\\" y1=\\"3\\" x2=\\"15\\" y2=\\"21\\" key=\\"jcv93v\\"></line></svg>"`;

View File

@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import { render } from 'solid-testing-library'
import { Grid } from '../src/icons'
describe('Using lucide icon components', () => {
it('should render an component', () => {
const { container } = render(() => <Grid/> );
expect( container.innerHTML ).toMatchSnapshot();
});
it('should adjust the size, stroke color and stroke width', async () => {
const testId = 'grid-icon';
const { container, getByTestId } = render( () =>
<Grid
data-testid={testId}
size={48}
stroke="red"
strokeWidth={4}
/>,
);
const { attributes } = await getByTestId(testId) as unknown as{ attributes: Record<string, { value: string }>};
expect(attributes.stroke.value).toBe('red');
expect(attributes.width.value).toBe('48');
expect(attributes.height.value).toBe('48');
expect(attributes['stroke-width'].value).toBe('4');
expect( container.innerHTML ).toMatchSnapshot();
});
})

View File

@@ -0,0 +1 @@
import '@testing-library/jest-dom';

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true
}
}

View File

@@ -0,0 +1,19 @@
import { defineConfig } from 'vitest/config'
import solidPlugin from 'vite-plugin-solid';
export default defineConfig({
plugins: [solidPlugin()],
test: {
globals: true,
environment: 'jsdom',
transformMode: {
web: [/\.jsx?$/],
},
setupFiles: './tests/setupVitest.js',
threads: false,
isolate: false,
},
resolve: {
conditions: ['development', 'browser'],
},
});

View File

@@ -16,7 +16,8 @@
"copy:license": "cp ../../LICENSE ./LICENSE",
"build": "pnpm clean && pnpm copy:license && pnpm copy:icons && pnpm copy:tags && pnpm build:lib",
"build:lib": "node ./scripts/buildLib.mjs",
"clean": "rm -rf lib && rm -rf build && rm -rf icons && rm -f sprite.svg && rm -f tags.json"
"clean": "rm -rf lib && rm -rf build && rm -rf icons && rm -f sprite.svg && rm -f tags.json",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"prettier": "^2.3.2",

View File

@@ -1,7 +1,7 @@
{
"name": "lucide-svelte",
"description": "A Lucide icon library package for Svelte applications",
"version": "0.84.0",
"version": "0.90.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
@@ -19,7 +19,9 @@
"unpkg": "dist/umd/lucide-svelte.min.js",
"typings": "dist/lucide-svelte.d.ts",
"sideEffects": false,
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:bundles && pnpm build:types",
"copy:license": "cp ../../LICENSE ./LICENSE",
@@ -29,7 +31,8 @@
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest",
"test:watch": "jest --watch"
"test:watch": "jest --watch",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.2",

View File

@@ -18,7 +18,7 @@ npm install lucide-vue-next
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a vue component.
### Example

View File

@@ -1,6 +1,6 @@
{
"name": "lucide-vue-next",
"version": "0.84.0",
"version": "0.90.0",
"author": "Eric Fennis",
"description": "A Lucide icon library package for Vue 3 applications",
"license": "ISC",
@@ -19,7 +19,10 @@
"unpkg": "dist/umd/lucide-vue-next.min.js",
"typings": "dist/lucide-vue-next.d.ts",
"sideEffects": false,
"files": ["dist", "nuxt.js"],
"files": [
"dist",
"nuxt.js"
],
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:types && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE",
@@ -29,7 +32,8 @@
"build:types": "node ./scripts/buildTypes.mjs",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest",
"test:watch": "jest --watchAll"
"test:watch": "jest --watchAll",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/vue": "^6.4.2",

View File

@@ -18,7 +18,7 @@ npm install lucide-vue
## How to use
It's build with ESmodules so it's completely threeshakable.
It's build with ESmodules so it's completely tree-shakable.
Each icon can be imported as a vue component.
### Example

View File

@@ -1,6 +1,6 @@
{
"name": "lucide-vue",
"version": "0.84.0",
"version": "0.90.0",
"author": "Eric Fennis",
"description": "A Lucide icon library package for Vue 2 applications",
"license": "ISC",
@@ -18,7 +18,9 @@
"module": "dist/esm/lucide-vue.js",
"unpkg": "dist/umd/lucide-vue.min.js",
"sideEffects": false,
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE",
@@ -27,7 +29,8 @@
"build:es": "babel src -d dist/esm",
"build:bundles": "rollup -c ./rollup.config.js",
"test": "jest",
"test:watch": "jest --watchAll"
"test:watch": "jest --watchAll",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.2",

View File

@@ -44,7 +44,7 @@ Here is a complete example with unpkg
### With ESModules
To reduce bundle size, lucide is built to be fully treeshakable.
To reduce bundle size, lucide is built to be fully tree-shakable.
The `createIcons` function will search for HTMLElements with the attribute `icon-name` and replace it with the svg from the given icon name.
```html

View File

@@ -1,7 +1,7 @@
{
"name": "lucide",
"description": "A Lucide icon library package for web and javascript applications.",
"version": "0.84.0",
"version": "0.90.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
@@ -18,7 +18,9 @@
"unpkg": "dist/umd/lucide.min.js",
"typings": "dist/lucide.d.ts",
"sideEffects": false,
"files": ["dist"],
"files": [
"dist"
],
"scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm build:es && pnpm build:bundles && pnpm build:types",
"copy:license": "cp ../../LICENSE ./LICENSE",

2795
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,14 @@
/* eslint-disable no-undef */
/* eslint-disable */
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'import', 'prettier'],
plugins: ['@typescript-eslint', 'import'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@next/next/recommended',
'prettier',
],
rules: {
'prettier/prettier': [
'error',
{
singleQuote: true,
trailingComma: 'all',
},
],
parserOptions: {
tsconfigRootDir: __dirname,
},
};

View File

@@ -1,3 +1,4 @@
/* eslint-disable */
module.exports = {
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],

View File

@@ -1,15 +1,11 @@
/* eslint-disable no-undef */
/* eslint-disable */
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
issuer: {
and: [/\.(js|ts)x?$/],
},
use: ['@svgr/webpack'],
use: ["@svgr/webpack"]
});
return config;
},
}
};

View File

@@ -10,7 +10,9 @@
"export": "next export -o build",
"deploy": "pnpm build && pnpm export",
"lint": "eslint .",
"test": "jest"
"lint:fix": "eslint --fix .",
"test": "jest",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@chakra-ui/react": "1.8.8",
@@ -19,7 +21,7 @@
"@mdx-js/loader": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@next/mdx": "^11.0.0",
"@svgr/webpack": "^6.2.1",
"@svgr/webpack": "^6.3.1",
"downloadjs": "^1.4.7",
"framer-motion": "^4",
"fuse.js": "^6.5.3",
@@ -37,23 +39,24 @@
"react-svg-loader": "^3.0.3"
},
"devDependencies": {
"@next/eslint-plugin-next": "^11.1.0",
"@testing-library/dom": "^7.24.4",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.0.4",
"@testing-library/react-hooks": "^3.4.2",
"react-test-renderer": "17.0.2",
"@next/eslint-plugin-next": "^12.2.5",
"@testing-library/dom": "^7.31.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^11.2.7",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^28.1.7",
"@types/node": "^14.0.11",
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"@typescript-eslint/eslint-plugin": "^5.34.0",
"@typescript-eslint/parser": "^5.34.0",
"babel-jest": "^26.5.2",
"babel-loader": "^8.1.0",
"cheerio": "^1.0.0-rc.3",
"eslint": "^7.32.0",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"jest": "^26.5.2",
"prettier": "^2.3.2",
"react-test-renderer": "17.0.2",
"typescript": "^4.3.5"
}
}

View File

@@ -37,7 +37,7 @@ const calculateLinesToHighlight = (meta: string) => {
};
};
interface HighlightProps {
interface HighlightProps extends BoxProps {
code: string;
language: Language;
metastring?: string;

View File

@@ -21,7 +21,7 @@ function ColorPicker({ hsv, hsl, onChange, value: color }: ColorPickerProps) {
}, [color]);
const handleChange = (e) => {
let value = e.target.value;
const value = e.target.value;
setValue(value);
onChange(value, e);
};

View File

@@ -1,4 +1,4 @@
import { Box, ButtonProps, Button, useClipboard } from '@chakra-ui/react';
import { Button, useClipboard } from '@chakra-ui/react';
const CopyButton = ({ copyText, buttonText = 'copy', ...props }) => {
const { hasCopied, onCopy } = useClipboard(copyText);

View File

@@ -21,11 +21,11 @@ const DEFAULT_STYLE = {
export const IconStyleContext = createContext<ICustomIconStyle>({
color: 'currentColor',
setColor: (s: string) => null,
setColor: () => null,
strokeWidth: 2,
setStroke: (n: number) => null,
setStroke: () => null,
size: 24,
setSize: (n: number) => null,
setSize: () => null,
resetStyle: () => null,
iconsRef: { current: {} },
});

View File

@@ -1,4 +1,4 @@
import { Button, Flex, Link, WrapItem, Text, Wrap, Heading, Icon } from '@chakra-ui/react';
import { Button, Flex, Link, WrapItem, Text, Wrap, Heading } from '@chakra-ui/react';
import download from 'downloadjs';
import JSZip from 'jszip';
import { Download, Github } from 'lucide-react';
@@ -17,7 +17,7 @@ import { useState } from 'react';
import { useCustomizeIconContext } from './CustomizeIconContext';
import { IconEntity } from '../types';
type IconContent = [icon: string, src:string]
type IconContent = [icon: string, src:string];
async function generateZip(icons: IconContent[]) {
const zip = new JSZip();

View File

@@ -1,4 +1,4 @@
import { createContext, useState, useContext, useMemo, useCallback, useEffect } from 'react';
import { createContext, useState, useContext, useMemo, useCallback } from 'react';
interface HeadingTypes {
anchor: string;
@@ -8,7 +8,7 @@ interface HeadingTypes {
const HeadingNavigationContext = createContext({
headings: [],
// eslint-disable-next-line @typescript-eslint/no-empty-function
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars
addHeading: (heading: HeadingTypes) => {},
});

View File

@@ -1,8 +1,9 @@
import { useEffect, useMemo } from 'react';
import { useMemo } from 'react';
import { useHeadingNavigationContext } from './HeadingNavigationProvider';
const HeadingTreeMenu = () => {
const { headings } = useHeadingNavigationContext();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const headingElements = useMemo(
() =>
headings.map(heading => {

View File

@@ -1,39 +1,50 @@
import { Box, Text, IconButton, useColorMode, Flex, Slide, ButtonGroup, Button, useToast, Heading, Avatar, AvatarGroup, Link, Tooltip, useMediaQuery, useDisclosure } from "@chakra-ui/react";
import theme from "../lib/theme";
import download from 'downloadjs';
import copy from "copy-to-clipboard";
import { X as Close } from 'lucide-react';
import {useContext, useEffect, useRef} from "react";
import {IconStyleContext} from "./CustomizeIconContext";
import {IconWrapper} from "./IconWrapper";
import ModifiedTooltip from "./ModifiedTooltip";
import { IconData } from "../lib/icons";
type IconDownload = {
src: string;
name: string;
};
const IconDetailOverlay = ({ open = true, close, icon }) => {
interface IconDetailOverlayProps {
open: boolean
close: () => void
icon?: IconData
}
const IconDetailOverlay = ({ open = true, close, icon }: IconDetailOverlayProps) => {
const toast = useToast();
const { colorMode } = useColorMode();
const { tags = [], name } = icon;
const {color, strokeWidth, size} = useContext(IconStyleContext);
const iconRef = useRef<SVGSVGElement>(null);
const [isMobile] = useMediaQuery("(max-width: 560px)")
const { isOpen, onOpen, onClose } = useDisclosure()
const handleClose = () => {
onClose();
close();
};
useEffect(() => {
if(open) {
onOpen()
}
}, [open])
const iconStyling = (isLight) => ({
if(icon == null) {
return null
}
const { tags = [], name = '' } = icon;
const handleClose = () => {
onClose();
close();
};
const iconStyling = {
height: "25vw",
width: "25vw",
minHeight: "160px",
@@ -41,12 +52,15 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
maxHeight: "240px",
maxWidth: "240px",
color: color,
});
};
const downloadIcon = ({src, name} : IconDownload) => download(src, `${name}.svg`, 'image/svg+xml');
const downloadIcon = ({src, name = ''} : IconDownload) => download(src, `${name}.svg`, 'image/svg+xml');
const copyIcon = async ({src, name} : IconDownload) => {
const trimmedSrc = src.replace(/(\r\n|\n|\r|\s\s)/gm, "")
await navigator.clipboard.writeText(trimmedSrc)
const copyIcon = ({src, name} : IconDownload) => {
copy(src);
toast({
title: "Copied!",
description: `Icon "${name}" copied to clipboard.`,
@@ -95,7 +109,6 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
w="full"
px={8}
>
<Box
borderWidth="1px"
rounded="lg"
@@ -135,7 +148,7 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
padding={0}
>
<div
style={iconStyling(colorMode == "light")}
style={iconStyling}
className="icon-large"
>
<IconWrapper
@@ -216,8 +229,8 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
</Heading>
<AvatarGroup size="md">
{ icon.contributors.map((commit, index) => (
<Link href={`https://github.com/${commit.author}`} isExternal key={`${index}_${commit.sha}`}>
<Tooltip label={commit.author} key={commit.sha}>
<Link href={`https://github.com/${commit.author}`} isExternal key={`${index}_${commit.commit}`}>
<Tooltip label={commit.author} key={commit.commit}>
<Avatar name={commit.author} src={`https://github.com/${commit.author}.png?size=88`} />
</Tooltip>
</Link>

View File

@@ -1,22 +1,42 @@
import { Button, ButtonProps, Flex, Text, useToast } from '@chakra-ui/react';
import download from 'downloadjs';
import copy from 'copy-to-clipboard';
import { memo } from 'react';
import { Contributor } from '../lib/fetchAllContributors';
import { useCustomizeIconContext } from './CustomizeIconContext';
import { IconWrapper } from './IconWrapper';
interface IconListItemProps {
name: string;
content: string;
contributors: any[];
contributors: Contributor[]
src: string;
onClick?: ButtonProps['onClick'];
onClick?: ButtonProps['onClick']
}
const IconListItem = ({ name, content, onClick, src: svg }: IconListItemProps) => {
const toast = useToast();
const { color, size, strokeWidth, iconsRef } = useCustomizeIconContext();
const handleClick:ButtonProps['onClick'] = async (event) => {
const src = (iconsRef.current[name].outerHTML ?? svg).replace(/(\r\n|\n|\r|(>\s\s<))/gm, "")
if (event.shiftKey) {
await navigator.clipboard.writeText(src)
toast({
title: 'Copied!',
description: `Icon "${name}" copied to clipboard.`,
status: 'success',
duration: 1500,
});
}
if (event.altKey) {
download(src, `${name}.svg`, 'image/svg+xml');
}
if (onClick) {
onClick(event);
}
}
return (
<Button
variant="ghost"
@@ -26,24 +46,7 @@ const IconListItem = ({ name, content, onClick, src: svg }: IconListItemProps) =
height={32}
position="relative"
whiteSpace="normal"
onClick={event => {
const src = iconsRef.current[name].outerHTML ?? svg
if (event.shiftKey) {
copy(src);
toast({
title: 'Copied!',
description: `Icon "${name}" copied to clipboard.`,
status: 'success',
duration: 1500,
});
}
if (event.altKey) {
download(src, `${name}.\svg`, 'image/svg+xml');
}
if (onClick) {
onClick(event);
}
}}
onClick={handleClick}
key={name}
alignItems="center"
>

View File

@@ -121,6 +121,7 @@ const Layout = ({ aside, children }: LayoutProps) => {
<Divider mb={6} mt={12} />
<p style={{ alignSelf: 'center' }}>
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
</a>
</p>

View File

@@ -1,5 +1,4 @@
import { Icon, Link, Text } from '@chakra-ui/react';
//@ts-ignore
import LogoImage from '../../public/logo.svg';
import NextLink from 'next/link';

View File

@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { useDisclosure } from '@chakra-ui/react';
import { createContext, useState, useContext, useMemo, useCallback, useEffect } from 'react';
import { createContext, useContext, useMemo } from 'react';
const MobileNavigationContext = createContext({
isOpen: false,

View File

@@ -1,7 +1,7 @@
import { Box, Tooltip, useColorMode } from "@chakra-ui/react";
import theme from '../lib/theme';
const ModifiedTooltip = ({}) => {
const ModifiedTooltip = () => {
const { colorMode } = useColorMode();
return (

View File

@@ -5,17 +5,31 @@ import {
Heading,
Text,
useColorMode,
Divider,
ButtonGroup,
Stack,
} from '@chakra-ui/react';
import Image from 'next/image';
import { Code, FileText } from 'lucide-react';
import Link from 'next/link';
import { MDXRemote } from 'next-mdx-remote';
import mdxComponents from '../lib/mdxComponents';
const Package = ({ name, description, image, shields, source, documentation }) => {
interface Shield {
alt: string
src: string
href: string
}
export interface PackageItem {
name: string
description: string
image: string
shields: Shield[]
source: string
documentation: string
order: number
private?: boolean
flutter?: object
}
const Package = ({ name, description, image, shields, source, documentation }: PackageItem) => {
const { colorMode } = useColorMode();
return (
@@ -71,6 +85,7 @@ const Package = ({ name, description, image, shields, source, documentation }) =
{shields.map(({ alt, src, href }, index) => (
<Link href={href} passHref>
<a target="_blank">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img {...{ alt, src }} key={index} />
</a>
</Link>

View File

@@ -2,6 +2,11 @@ import crypto from 'crypto';
import fs from 'fs';
import path from 'path';
export interface Contributor {
author: string
commit: string
}
const IGNORE_COMMIT_MESSAGES = ['fork', 'optimize'];
function getContentHashOfFile(path) {
@@ -14,8 +19,7 @@ function getContentHashOfFile(path) {
});
}
const fetchCommitsOfIcon = (name) =>
new Promise(async (resolve, reject) => {
const fetchCommitsOfIcon = async (name) =>{
try {
const headers = new Headers();
const username = 'ericfennis';
@@ -35,22 +39,22 @@ const fetchCommitsOfIcon = (name) =>
const data = await res.json();
resolve({
return {
name,
commits: data,
});
};
} catch (error) {
reject(error);
throw new Error(error);
}
});
};
export const filterCommits = (commits) =>
commits.filter(({ commit }) =>
!IGNORE_COMMIT_MESSAGES.some(ignoreItem =>
commit.message.toLowerCase().includes(ignoreItem),
))
.map(({ sha, author, commit }) => ({
.map(({ sha, author }) => ({
author: author && author.login ? author.login : null,
commit: sha,
}))
@@ -86,7 +90,7 @@ async function writeIconCache(icon, content) {
fs.writeFileSync(iconCachePath, JSON.stringify(content), 'utf-8');
}
export async function getContributors(icon) {
export async function getContributors(icon): Promise<Contributor[]> {
try {
let iconCommits
const iconCache = await checkIconCache(icon);
@@ -94,7 +98,7 @@ export async function getContributors(icon) {
if (iconCache) {
iconCommits = iconCache
} else {
const { commits } : any = await fetchCommitsOfIcon(icon);
const { commits } = await fetchCommitsOfIcon(icon);
writeIconCache(icon, commits)

View File

@@ -1,10 +1,11 @@
import { promises as fs, constants } from 'fs';
import path from 'path';
import yaml from 'js-yaml'
import { PackageItem } from '../components/Package';
const fileExist = (filePath) => fs.access(filePath, constants.F_OK).then(() => true).catch(() => false)
const fetchPackages = async () => {
const fetchPackages = async (): Promise<PackageItem[]> => {
const docsDir = path.resolve(process.cwd(), '../packages');
const fileNames = await (await fs.readdir(docsDir)).map(filename => ({filename, directory: docsDir}))
@@ -31,8 +32,6 @@ const fetchPackages = async () => {
return null
}))
return packageJsons
}

View File

@@ -1,8 +1,8 @@
import fs from "fs";
import path from "path";
import cheerio from 'cheerio';
import { parseSync, stringify } from 'svgson';
import tags from '../../../tags.json';
import { getContributors } from "./fetchAllContributors";
import { Contributor, getContributors } from "./fetchAllContributors";
const directory = path.join(process.cwd(), "../icons");
@@ -14,12 +14,13 @@ export function getAllNames() {
});
}
export async function getData(name:string) {
export async function getData(name: string) {
const fullPath = path.join(directory, `${name}.svg`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const fileContent = fs.readFileSync(fullPath, "utf8");
const $ = cheerio.load(fileContents);
const content = $("svg").html();
const svgNodes = parseSync(fileContent);
const svgContent = svgNodes.children.map((node) => stringify(node)).join('');
const contributors = await getContributors(name);
@@ -27,12 +28,20 @@ export async function getData(name:string) {
name,
tags: tags[name] || [],
contributors,
src: fileContents,
content: content
src: fileContent,
content: svgContent
};
}
export async function getAllData() {
export interface IconData {
name: string
tags: string[]
contributors: Contributor[]
src: string
content: string
}
export async function getAllData(): Promise<IconData[]> {
const names = getAllNames();
return Promise.all(names.map((name) => getData(name)));

View File

@@ -10,6 +10,7 @@ export const useKeyBindings = (
const [keyBindings] = useState(initialKeyBindings);
useEffect(() => {
// eslint-disable-next-line no-undef
document.addEventListener(
eventListener,
(event) => {
@@ -28,6 +29,7 @@ export const useKeyBindings = (
return () =>
Object.keys(keyBindings).forEach((keyBinding) =>
// eslint-disable-next-line no-undef
document.removeEventListener(eventListener, keyBindings[keyBinding])
);
}, []);

View File

@@ -52,8 +52,7 @@ const components = {
return (
<CodeBlock
//@ts-ignore
my={6}
marginY={6}
code={code}
language={language}
/>
@@ -78,7 +77,7 @@ const components = {
/>
),
inlineCode: InlineCode,
hr: (props) => <Divider my={4}/>,
hr: () => <Divider my={4} />,
a: ({children, href, ...rest}) => {
let link = href
const isExternal = link.startsWith('http')

View File

@@ -1,7 +1,7 @@
import Fuse from 'fuse.js';
import { useMemo } from 'react';
const useSearch = <T>(query = '', collection: T[], keys: Fuse.FuseOptionKey[]) => {
const useSearch = <T>(query = '', collection: T[], keys: Fuse.FuseOptionKey<T>[] = []) => {
const index = useMemo(() => {
return new Fuse(collection, {
threshold: 0.2,

View File

@@ -17,15 +17,6 @@ class MyDocument extends Document {
<meta name="theme-color" content="#F56565" />
<meta name="google-site-verification" content="pr2dEIF-6zFdjXlDxutqEokeinrQNLx5qAjeVCqASDY" />
</Head>
<style jsx global>{`
* {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
-ms-transition: none !important;
transition: none !important;
}
`}</style>
<body>
<ColorModeScript />
<Main />

View File

@@ -1,6 +1,3 @@
import Layout from '../../components/Layout';
import Header from '../../components/Header';
import Head from 'next/head';
import fetchAllDocuments from '../../lib/fetchAllDocuments';
export { default } from '.';

View File

@@ -10,7 +10,7 @@ import { Box, Button, Text } from '@chakra-ui/react';
import { ArrowRight } from 'lucide-react'
import Link from 'next/link';
const DocPage = ({ doc, data, content }) => {
const DocPage = ({ doc, data }) => {
if (!data || !doc) return null
const nextPage = data.nextPage || []
@@ -69,7 +69,7 @@ const DocPage = ({ doc, data, content }) => {
export default DocPage
export async function getStaticProps({ params }) {
export async function getStaticProps() {
const allDocs = await fetchAllDocuments();
const doc = allDocs.find(({filename = ''}) => filename === 'index.md');

View File

@@ -38,7 +38,7 @@ const IconPage = ({ icon, data }) => {
return (
<Layout>
<IconDetailOverlay key={currentIcon.name} icon={currentIcon} close={onClose} />
<IconDetailOverlay key={currentIcon.name} icon={currentIcon} close={onClose} open />
<Header {...{ data }} />
<IconOverview {...{ data }} />
</Layout>

View File

@@ -1,16 +1,21 @@
import Layout from '../components/Layout';
import { getAllData } from '../lib/icons';
import { getAllData, IconData } from '../lib/icons';
import IconOverview from '../components/IconOverview';
import IconDetailOverlay from '../components/IconDetailOverlay';
import { useRouter } from 'next/router';
import Header from '../components/Header';
import MobileMenu from '../components/MobileMenu';
import { useEffect, useMemo } from 'react';
import { useMemo } from 'react';
import { GetStaticPropsResult, NextPage } from 'next';
const IndexPage = ({ data }) => {
interface HomePageProps {
data: IconData[]
}
const HomePage: NextPage<HomePageProps> = ({ data }) => {
const router = useRouter();
const getIcon = iconName => data.find(({ name }) => name === iconName) || {};
const getIcon = iconName => data.find(({ name }) => name === iconName);
const currentIcon = useMemo(() => {
return getIcon(router.query.iconName)
@@ -30,7 +35,7 @@ const IndexPage = ({ data }) => {
);
};
export async function getStaticProps() {
export async function getStaticProps(): Promise<GetStaticPropsResult<HomePageProps>> {
const data = await getAllData();
return {
@@ -40,4 +45,4 @@ export async function getStaticProps() {
};
}
export default IndexPage;
export default HomePage;

View File

@@ -5,9 +5,9 @@ import MobileMenu from '../components/MobileMenu';
import { Box, Heading, Text } from '@chakra-ui/react';
import { promises as fs } from 'fs';
import { resolve } from 'path';
import { GetStaticProps, NextPage } from 'next';
import { GetStaticProps } from 'next';
const LicensePage = ({ licenseText }) => {
const LicensePage = ({ licenseText }: { licenseText: string[] }): JSX.Element => {
return (
<Box>
<MobileMenu />
@@ -43,7 +43,7 @@ const LicensePage = ({ licenseText }) => {
export default LicensePage;
export const getStaticProps: GetStaticProps = async ({ params }) => {
export const getStaticProps: GetStaticProps = async () => {
const doc: string = await fs.readFile(resolve('../LICENSE'), 'utf-8');
const licenseText = doc

View File

@@ -2,12 +2,17 @@ import Layout from '../../components/Layout';
import HeadingNavigationProvider from '../../components/HeadingNavigationProvider';
import MobileMenu from '../../components/MobileMenu';
import { Stack } from '@chakra-ui/react';
import Package from '../../components/Package';
import packagesData from '../../lib/packageData';
import Package, { PackageItem } from '../../components/Package';
import packagesData from '../../data/packageData';
import { Heading } from '@chakra-ui/react';
import fetchPackages from '../../lib/fetchPackages';
import { GetStaticPropsResult } from 'next';
const PackagesPage = ({ packages }) => {
interface PackagesPageProps {
packages: PackageItem[]
}
const PackagesPage = ({ packages }: PackagesPageProps): JSX.Element => {
return (
<HeadingNavigationProvider>
<MobileMenu />
@@ -25,11 +30,11 @@ const PackagesPage = ({ packages }) => {
export default PackagesPage;
export async function getStaticProps({ params }) {
const packages = (await fetchPackages())
export async function getStaticProps(): Promise<GetStaticPropsResult<PackagesPageProps>> {
const packages: PackageItem[] = (await fetchPackages())
.filter(Boolean)
.filter(packageObj => !packageObj.private && packageObj.name in packagesData)
.map(({ name, description, flutter = false }) => {
.map(({ name, description, flutter }) => {
const packageDirectory = flutter ? 'lucide-flutter' : name;
return {
@@ -43,5 +48,8 @@ export async function getStaticProps({ params }) {
})
.sort((a, b) => a.order - b.order);
console.log(packages);
return { props: { packages } };
}

View File

@@ -2,15 +2,20 @@ import { getAllData } from '../src/lib/icons';
import { renderHook } from '@testing-library/react-hooks';
import useSearch from '../src/lib/useSearch';
const keys = [
{ name: 'name', weight: 2 },
{ name: 'tags', weight: 1 },
]
describe('Icon Overview', () => {
it('can search filter icons', async () => {
let allData = getAllData();
const allData = await getAllData();
const { result: result1, waitForNextUpdate: wait1 } = renderHook(() => useSearch(allData, ''));
const { result: result1 } = renderHook(() => useSearch('', allData, keys));
expect(result1.current).toHaveLength(allData.length);
const { result: result2, waitForNextUpdate: wait2 } = renderHook(() =>
useSearch(allData, 'airplay')
useSearch(allData, 'airplay', keys)
);
await wait2();
expect(result2.current).toHaveLength(2);

View File

@@ -1,14 +1,13 @@
import { act, fireEvent, screen } from '@testing-library/react';
import { screen, render } from '@testing-library/react';
import Index from '../src/pages/index';
import React from 'react';
import { render } from './test-utils';
import { getAllData } from '../src/lib/icons';
import App from '../src/pages/_app';
describe('App', () => {
it('renders without crashing', () => {
let allData = getAllData();
it('renders without crashing', async () => {
const allData = await getAllData();
render(<App Component={Index} pageProps={{ data: allData }} />);
expect(
screen.getByText('Simply beautiful open source icons, community-sourced')

View File

@@ -1,51 +0,0 @@
import React from 'react';
import { render as defaultRender } from '@testing-library/react';
import { RouterContext } from 'next/dist/next-server/lib/router-context';
import { NextRouter } from 'next/router';
export * from '@testing-library/react';
// --------------------------------------------------
// Override the default test render with our own
//
// You can override the router mock like this:
//
// const { baseElement } = render(<MyComponent />, {
// router: { pathname: '/my-custom-pathname' },
// });
// --------------------------------------------------
type DefaultParams = Parameters<typeof defaultRender>;
type RenderUI = DefaultParams[0];
type RenderOptions = DefaultParams[1] & { router?: Partial<NextRouter> };
export function render(ui: RenderUI, { wrapper, router, ...options }: RenderOptions = {}) {
if (!wrapper) {
wrapper = ({ children }) => (
<RouterContext.Provider value={{ ...mockRouter, ...router }}>
{children}
</RouterContext.Provider>
);
}
return defaultRender(ui, { wrapper, ...options });
}
const mockRouter: NextRouter = {
basePath: '',
pathname: '/',
route: '/',
asPath: '/',
query: {},
push: jest.fn(),
replace: jest.fn(),
reload: jest.fn(),
back: jest.fn(),
prefetch: jest.fn(),
beforePopState: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
},
isFallback: false,
};

File diff suppressed because one or more lines are too long

View File

@@ -304,7 +304,9 @@
"direction",
"swap",
"switch",
"transaction"
"transaction",
"reorder",
"move"
],
"arrow-right": [
"direction"
@@ -318,6 +320,17 @@
"arrow-up-circle": [
"direction"
],
"arrow-up-down": [
"bidirectional",
"direction",
"swap",
"switch",
"network",
"mobile data",
"internet",
"reorder",
"move"
],
"arrow-up-left": [
"direction"
],
@@ -552,6 +565,11 @@
"read",
"library"
],
"book-open-check": [
"read",
"library",
"plain language"
],
"bookmark": [
"read",
"clip",
@@ -1325,6 +1343,22 @@
"chicken",
"meat"
],
"ear": [
"hearing",
"noise",
"audio",
"accessibility"
],
"ear-off": [
"hearing",
"hard of hearing",
"hearing loss",
"deafness",
"noise",
"silence",
"audio",
"accessibility"
],
"edit": [
"pencil",
"change"
@@ -3236,6 +3270,13 @@
"money",
"payment"
],
"sailboat": [
"ship",
"boat",
"harbor",
"harbour",
"dock"
],
"save": [
"floppy disk"
],