mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-24 12:29:21 +01:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90a3f6e1dd | ||
|
|
4ae4eae53d | ||
|
|
e99228c65d | ||
|
|
34249ff42c | ||
|
|
f9d37968d6 | ||
|
|
864b71822b | ||
|
|
bc3bd1267a | ||
|
|
5d22d8e456 | ||
|
|
db98602331 |
@@ -17,5 +17,9 @@ module.exports = {
|
||||
trailingComma: 'all'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./site/tsconfig.json', './packages/*/tsconfig.json'],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
15
icons/book-open-check.svg
Normal file
15
icons/book-open-check.svg
Normal 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
17
icons/plug-2.svg
Normal 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
16
icons/plug.svg
Normal 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
15
icons/sailboat.svg
Normal 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 |
@@ -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",
|
||||
|
||||
@@ -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.86.0
|
||||
version: 0.89.0
|
||||
homepage: https://lucide.dev
|
||||
repository: https://github.com/lucide-icons/lucide
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "lucide",
|
||||
"description": "A Lucide icon library package for web and javascript applications.",
|
||||
"version": "0.86.0",
|
||||
"version": "0.89.0",
|
||||
"license": "ISC",
|
||||
"homepage": "https://lucide.dev",
|
||||
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
||||
|
||||
2314
pnpm-lock.yaml
generated
2314
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable */
|
||||
module.exports = {
|
||||
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
|
||||
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const calculateLinesToHighlight = (meta: string) => {
|
||||
};
|
||||
};
|
||||
|
||||
interface HighlightProps {
|
||||
interface HighlightProps extends BoxProps {
|
||||
code: string;
|
||||
language: Language;
|
||||
metastring?: string;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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: {} },
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) => {},
|
||||
});
|
||||
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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])
|
||||
);
|
||||
}, []);
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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 '.';
|
||||
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 } };
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
1
site/tsconfig.tsbuildinfo
Normal file
1
site/tsconfig.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user