Compare commits

...

12 Commits

Author SHA1 Message Date
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
56 changed files with 2156 additions and 733 deletions

View File

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

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

@@ -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

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/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.89.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.89.0
homepage: https://lucide.dev
repository: https://github.com/lucide-icons/lucide

View File

@@ -1,7 +1,7 @@
{
"name": "lucide-preact",
"description": "A Lucide icon library package for Preact applications",
"version": "0.84.0",
"version": "0.89.0",
"license": "ISC",
"homepage": "https://lucide.dev",
"bugs": "https://github.com/lucide-icons/lucide/issues",
@@ -17,7 +17,9 @@
"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",
@@ -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/preact": "^2.0.1",

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

@@ -1,7 +1,7 @@
{
"name": "lucide-react",
"description": "A Lucide icon library package for React applications",
"version": "0.84.0",
"version": "0.89.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

@@ -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.89.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

@@ -1,6 +1,6 @@
{
"name": "lucide-vue-next",
"version": "0.84.0",
"version": "0.89.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

@@ -1,6 +1,6 @@
{
"name": "lucide-vue",
"version": "0.84.0",
"version": "0.89.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

@@ -1,7 +1,7 @@
{
"name": "lucide",
"description": "A Lucide icon library package for web and javascript applications.",
"version": "0.84.0",
"version": "0.89.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",

2314
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",
@@ -3236,6 +3254,13 @@
"money",
"payment"
],
"sailboat": [
"ship",
"boat",
"harbor",
"harbour",
"dock"
],
"save": [
"floppy disk"
],