Add documentation Section to lucide.dev (#479)

* Add docs Menu Tree data

* Start with sectiontitles

* Create link list

* Add Docs menu to mobile

* Add some more pages and text

* Optimize text

* add license to the menu

* update packages

* Fix build

* Update title

* Remove ModifiedTooltip

* Fix assets

* add yarn to copy-assets command

* update lockfile
This commit is contained in:
Eric Fennis
2022-02-01 19:26:07 +01:00
committed by GitHub
parent 082c7b07c9
commit d6f65516ad
38 changed files with 2086 additions and 1488 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"cSpell.words": [
"devs",
"preact",
"Preact"
]
}
+7
View File
@@ -0,0 +1,7 @@
---
title: Figma Template Guide
---
# Figma Template Guide
Please help us write this guide.
+5 -1
View File
@@ -1,4 +1,8 @@
# Icon Design Guide
---
title: Icon Design Guide
---
# Icon Design Principles
Here are rules that should be followed to keep quality and consistency when making icons for Lucide.
+4 -1
View File
@@ -1,3 +1,6 @@
---
title: Illustrator Template Guide
---
# Illustrator Template Guide
@@ -25,4 +28,4 @@ The Illustrator template is created following guidelines from the [Icon Design G
After that, double check that the [code conventions and SVG global attributes](https://github.com/lucide-icons/lucide/blob/master/docs/ICON_DESIGN_GUIDE.md#code-conventions) are correct.
7. Minify paths with [SVGOMG](https://jakearchibald.github.io/svgomg/).
7. Minify paths with [SVGOMG](https://jakearchibald.github.io/svgomg/).
+4
View File
@@ -1,3 +1,7 @@
---
title: Icon Design Guide
---
# Inkscape Setup Guide
This guide shows the steps to setup Inkscape for creating icons that conform to the Featherity design
+25
View File
@@ -0,0 +1,25 @@
---
title: Comparison
---
# Comparison
## Lucide vs Feather Icons
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.
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.
### Why should I choose Lucide over Feather Icons?
- Lucide already expended the icon set by 130+ in less then a year. Lucide has over 500+ icon, feather sticks around 286 icons.
- Well maintained code base.
- Active community.
### Should I migrate to Lucide?
That depends if you're fine with the icons from feather icons. If that is the case, it is maybe not the effort worth it.
But if you keep wrestling and feel limited by the icons Feather provides you can consider to migrate.
We didn't remove any icons when we forked, but there are some icons renamed.
+10 -103
View File
@@ -1,116 +1,23 @@
---
title: Introduction
nextPage:
- comparison
- installation
---
# Introduction
## What is Lucide?
An open source icon library for displaying icons and symbols in digital and non digital projects. It is containing over 500+ Vector (svg) files. To use these icons, lucide provides several official packages to make it easier to use these icons in projects.
Lucide is a community-run fork of [Feather Icons](https://github.com/feathericons/feather), open for anyone to contribute icons.
Lucide contains icons with different variants and states. With that designers and developers can choose the right icon for them selves. If icons don't exist you're free to open design request. The Lucide community will help.
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. This unfortunately means that hundreds of developers and designers wasted their time contributing to Feather Icons with no chance of PRs being accepted.
With help of the community, contributors are providing the library of new icons. With more icons, we simply have more icons to work with in your project. Also with rising of new applications with specific features lucide has the goal the provide the complete set for you project.
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 and hope that you'll join us!
When designing new icons, the community is working with a set of design rules. This is to keep icons: recognizable, consistency in style, and readable on all sizes. The community likes to have creativity in new icons but conventional design is important to have recognizable icons.
### Why choose Lucide over Feather Icons
Beside design, code is also important. Assets like icons in for example web projects can increase the transferred bytes significantly. With the growing internet, lucide has the responsibility to keep their assets small as possible. To achieve this, lucide uses SVG compression and specific code architecture for three-shaking abilities. With three-shaking used you will only ship the icons you used, helps you to keep the software small as possible when distributed.
- Lucide already expended the icon set by 130+ in less then a year, so more icons to work with.
- Well maintained code base.
- Active community.
Lucide provides several official packages for: [Web (Vanilla)](https://lucide.dev/docs/lucide), [React](https://lucide.dev/docs/lucide-react), [Vue](https://lucide.dev/docs/lucide-vue), [Vue 3](https://lucide.dev/docs/lucide-vue-next), [Preact](https://lucide.dev/docs/lucide-preact), [Angular](https://lucide.dev/docs/lucide-angular), [NodeJS](https://lucide.dev/docs/lucide-static#nodejs) and [Flutter](https://lucide.dev/docs/lucide-flutter).
## Getting Started
At its core, Lucide is a collection of [SVG](https://svgontheweb.com/#svg) files. This means that you can use Lucide icons in all the same ways you can use SVGs (e.g. `img`, `background-image`, `inline`, `object`, `embed`, `iframe`). Here's a helpful article detailing the many ways SVGs can be used on the web: [SVG on the Web – Implementation Options](https://svgontheweb.com/#implementation)
### Using Lucide packages
### Web
Implementation of the lucide icon library for web applications.
```sh
npm install lucide
#or
yarn add lucide
```
For more details, see the [documentation](lucide).
### React
Implementation of the lucide icon library for react applications.
```sh
yarn add lucide-react
# or
npm install lucide-react
```
For more details, see the [documentation](lucide-react).
### Vue 2
Implementation of the lucide icon library for vue applications.
```sh
yarn add lucide-vue
# or
npm install lucide-vue
```
For more details, see the [documentation](lucide-vue).
### Vue 3
Implementation of the lucide icon library for vue applications.
```sh
yarn add lucide-vue-next
# or
npm install lucide-vue-next
```
For more details, see the [documentation](lucide-vue-next).
### Angular
```sh
yarn add lucide-angular
# or
npm install lucide-angular
```
For more details, see the [documentation](lucide-angular).
### Preact
Implementation of the lucide icon library for preact applications.
```sh
yarn add lucide-preact
# or
npm install lucide-preact
```
For more details, see the [documentation](lucide-preact).
### Figma
The lucide figma plugin.
Visit [Figma community page](https://www.figma.com/community/plugin/939567362549682242/Lucide-Icons) to install the plugin.
![Figma Lucide Cover](https://www.figma.com/community/plugin/939567362549682242/thumbnail "Figma Lucide Cover")
Any questions about lucide? Ask the community. Active on [GitHub](https://github.com/lucide-icons/lucide) and [Discord](https://discord.gg/EH6nSts).
+106 -4
View File
@@ -4,10 +4,112 @@ title: Installation
# Installation
Hello
## Web
> hello
Implementation of the lucide icon library for web applications.
```js
console.log('asdadfasdf')
```sh
npm install lucide
#or
yarn add lucide
```
For more details, see the [documentation](packages/lucide).
## React
Implementation of the lucide icon library for react applications.
```sh
yarn add lucide-react
# or
npm install lucide-react
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-react#lucide-react).
## Vue 2
Implementation of the lucide icon library for vue applications.
```sh
yarn add lucide-vue
# or
npm install lucide-vue
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue#lucide-vue).
## Vue 3
Implementation of the lucide icon library for vue applications.
```sh
yarn add lucide-vue-next
# or
npm install lucide-vue-next
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue-next#lucide-vue-next).
## Angular
```sh
yarn add lucide-angular
# or
npm install lucide-angular
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-angular#lucide-angular).
## Preact
Implementation of the lucide icon library for preact applications.
```sh
yarn add lucide-preact
# or
npm install lucide-preact
```
For more details, see the [documentation](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-preact#lucide-preact).
## Figma
The lucide figma plugin.
Visit [Figma community page](https://www.figma.com/community/plugin/939567362549682242/Lucide-Icons) to install the plugin.
![Setting Page Size](https://www.figma.com/community/plugin/939567362549682242/thumbnail "Figma Lucide Cover")
## Laravel
Implementation of Lucide icon's using `blade-icons` for Laravel based projects.
```sh
composer require mallardduck/blade-lucide-icons
```
For more details, see the [documentation](https://github.com/mallardduck/blade-lucide-icons/blob/main/README.md).
## Flutter
Implementation of Lucide icon library for Flutter applications.
```sh
flutter pub add lucide_icons
```
For more details, see the [pub.dev](https://pub.dev/packages/lucide_icons).
+1 -1
View File
@@ -62,7 +62,7 @@ const App = () => {
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.
> ⚠️ 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
+1 -1
View File
@@ -11,7 +11,7 @@ This package include the following lucide implementations:
This package is suitable for very specific use cases for example if you want to use icon fonts, svg sprites, normal svgs or Common.js Svg strings in your javascript project.
> ⚠️ It is not recommended to use this package for svg sprites or icon fonts for web pages/applications, for prototyping it is ok. We recommend to bundlers for web applications to make sure you only bundle the used icons from this icon library (Threeshaking). Otherwise it will load all the icons, making you webpage loading slower. Threeshaking is only available in the packages: [lucide](https://github.com/lucide-icons/lucide/tree/master/packages/lucide), [lucide-react](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-react), [lucide-vue](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue), [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue-next), [lucide-angular](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-angular), [lucide-preact](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-preact)
> ⚠️ It is not recommended to use this package for svg sprites or icon fonts for web pages/applications, for prototyping it is ok. We recommend to bundlers for web applications to make sure you only bundle the used icons from this icon library (Threeshaking). Otherwise it will load all the icons, making you webpage loading slower. Threeshaking is only available in the packages: [lucide](lucide), [lucide-react](lucide-react), [lucide-vue](lucide-vue), [lucide-vue-next](lucide-vue-next), [lucide-angular](lucide-angular), [lucide-preact](lucide-preact)
## Installation
+17 -13
View File
@@ -2,15 +2,19 @@
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](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue#lucide-vue)
> ⚠️ This version of lucide is for Vue 3, For Vue 2 got to [lucide-vue-next](lucide-vue)
## Installation
```sh
**With yarn**
```bash
yarn add lucide-vue-next
```
# or
**With npm**
```bash
npm install lucide-vue-next
```
@@ -23,7 +27,7 @@ Each icon can be imported as a vue component.
You can pass additional props to adjust the icon.
``` vue
``` html
<template>
<Camera
color="red"
@@ -56,7 +60,7 @@ export default {
You can also pass custom props that will be added in the svg as attributes.
``` vue
``` html
<template>
<Camera fill="red" />
</template>
@@ -66,11 +70,11 @@ You can also pass custom props that will be added in the svg as attributes.
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.
> ⚠️ 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
``` vue
``` html
<template>
<component :is="icon" />
</template>
@@ -85,18 +89,18 @@ export default {
required: true,
},
},
computed: {
icon() {
return icons[this.name];
},
},
setup(props) {
const icon = computed(() => icons[props.name])
return { icon }
}
};
</script>
```
##### Then you can use it like this
``` vue
``` html
<template>
<div id="app">
<Icon name="Airplay" />
+6 -6
View File
@@ -2,7 +2,7 @@
Implementation of the lucide icon library for Vue applications.
> ⚠️ This version of lucide is for Vue 2, For Vue 3 got to [lucide-vue-next](https://github.com/lucide-icons/lucide/tree/master/packages/lucide-vue-next#lucide-vue-next)
> ⚠️ This version of lucide is for Vue 2, For Vue 3 got to [lucide-vue-next](lucide-vue-next)
## Installation
@@ -23,7 +23,7 @@ Each icon can be imported as a vue component.
You can pass additional props to adjust the icon.
``` vue
``` html
<template>
<Camera
color="red"
@@ -56,7 +56,7 @@ export default {
You can also pass custom props that will be added in the svg as attributes.
``` vue
``` html
<template>
<Camera fill="red" />
</template>
@@ -66,11 +66,11 @@ You can also pass custom props that will be added in the svg as attributes.
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.
> ⚠️ 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
``` vue
``` html
<template>
<component :is="icon" />
</template>
@@ -96,7 +96,7 @@ export default {
##### Then you can use it like this
``` vue
``` html
<template>
<div id="app">
<Icon name="Airplay" />
+1
View File
@@ -0,0 +1 @@
public/docs/images
+2 -1
View File
@@ -5,7 +5,8 @@
"author": "John Letey",
"scripts": {
"dev": "next dev",
"build": "next build",
"copy-assets": "mkdir -p ./public/docs/images && cp -rf ../docs/images ./public/docs",
"build": "yarn copy-assets && next build",
"export": "next export -o build",
"deploy": "yarn build && yarn export",
"lint": "eslint .",
+4 -7
View File
@@ -1,16 +1,13 @@
import { Box, ButtonProps, Button, useClipboard } from '@chakra-ui/react';
const CopyButton = ({copyText, buttonText = 'copy', ...props}) => {
const CopyButton = ({ copyText, buttonText = 'copy', ...props }) => {
const { hasCopied, onCopy } = useClipboard(copyText);
return (
<Button
onClick={onCopy}
{...props}
>
{ hasCopied ? 'copied' : buttonText }
<Button onClick={onCopy} {...props}>
{hasCopied ? 'copied' : buttonText}
</Button>
)
);
};
export default CopyButton;
+52
View File
@@ -0,0 +1,52 @@
import { Box, Text, Link, BoxProps } from '@chakra-ui/react';
import docsMenuTree from '../lib/docsMenuTree';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
const DocsMenu = (props: BoxProps) => {
const router = useRouter();
useEffect(() => {
console.log(router.asPath);
}, [router]);
const linkIsActive = (currentPath, href) => currentPath === `/docs/${href}`;
return (
<Box {...props}>
<Box paddingY={4}>
{docsMenuTree.map(({ section, items }) => (
<Box key={section}>
<Text fontSize={19} fontWeight="bold" marginBottom={2}>
{section}
</Text>
<Box as="ul" style={{ listStyle: 'none' }} marginBottom={6}>
{items.map(({ href, title }) => (
<Box as="li" key={title}>
<NextLink href={`/docs/${href}`} passHref>
<Link
_hover={{ opacity: linkIsActive(router.asPath, href) ? 1 : 0.8 }}
display="block"
color={linkIsActive(router.asPath, href) ? 'brand.500' : 'inherit'}
>
<Text
fontSize={16}
lineHeight={1.8}
opacity={linkIsActive(router.asPath, href) ? 1 : 0.5}
as="p"
width="100%"
display="block"
>
{title}
</Text>
</Link>
</NextLink>
</Box>
))}
</Box>
</Box>
))}
</Box>
</Box>
);
};
export default DocsMenu;
+2 -2
View File
@@ -70,10 +70,10 @@ const Header = ({ data }) => {
return (
<Flex direction="column" align="center" justify="center">
<Heading as="h1" fontSize="4xl" mb="4" textAlign="center">
Simply beautiful open source icons, community-sourced
Beautiful &amp; consistent icon toolkit made by the community.
</Heading>
<Text fontSize="lg" as="p" textAlign="center" mb="1">
An open-source icon library, a fork of{' '}
Open-source project and a fork of{' '}
<Link href="https://github.com/feathericons/feather" isExternal>
Feather Icons
</Link>
+2 -2
View File
@@ -1,6 +1,6 @@
import { Link, Heading } from '@chakra-ui/react';
import { useEffect } from 'react';
import { useheadingNavigationContext } from './HeadingNavigationProvider';
import { useHeadingNavigationContext } from './HeadingNavigationProvider';
function getAnchor(text: string) {
return text
@@ -10,7 +10,7 @@ function getAnchor(text: string) {
}
const HeadingAnchored = ({ children, as: headingLevel, ...restProps }) => {
const { addHeading } = useheadingNavigationContext();
const { addHeading } = useHeadingNavigationContext();
const headingText = typeof children === 'string' ? children : children[0];
const anchor = getAnchor(headingText);
@@ -1,4 +1,4 @@
import { createContext, useState, useContext } from 'react';
import { createContext, useState, useContext, useMemo, useCallback, useEffect } from 'react';
interface HeadingTypes {
anchor: string;
@@ -12,24 +12,24 @@ const HeadingNavigationContext = createContext({
addHeading: (heading: HeadingTypes) => {},
});
function HeadingNavigationProvider({ children }) {
export default function HeadingNavigationProvider({ children }) {
const [headings, setHeadings] = useState([]);
const addHeading = (heading: HeadingTypes) => {
const addHeading = useCallback((heading: HeadingTypes) => {
if (!['h1', 'h2', 'h3'].includes(heading.headingLevel)) return;
const currentHeadings = headings;
currentHeadings.push(heading);
setHeadings(currentHeadings);
};
setHeadings((currentHeadings) => [
...currentHeadings,
heading
]);
}, [headings]);
const value = { headings, addHeading };
const value = useMemo(() => ({ headings, addHeading }), [headings, addHeading]);
return (
<HeadingNavigationContext.Provider value={value}>{children}</HeadingNavigationContext.Provider>
);
}
const useheadingNavigationContext = () => useContext(HeadingNavigationContext);
export const useHeadingNavigationContext = () => useContext(HeadingNavigationContext);
export { HeadingNavigationProvider, useheadingNavigationContext };
+4 -5
View File
@@ -1,12 +1,14 @@
import { useEffect, useMemo } from 'react';
import { useheadingNavigationContext } from './HeadingNavigationProvider';
import { useHeadingNavigationContext } from './HeadingNavigationProvider';
const HeadingTreeMenu = () => {
const { headings } = useheadingNavigationContext();
const { headings } = useHeadingNavigationContext();
const headingElements = useMemo(
() =>
headings.map(heading => {
const headingElement = document.getElementById(heading.anchor);
console.log(headingElement);
return {
element: headingElement,
offsetTop: headingElement.getBoundingClientRect().top,
@@ -14,9 +16,6 @@ const HeadingTreeMenu = () => {
}),
[headings],
);
useEffect(() => {
console.log(headingElements);
}, [headingElements]);
return <div />;
};
@@ -27,6 +27,11 @@ const IconDetailOverlay = ({ open = true, close, icon }) => {
close();
};
useEffect(() => {
console.log(icon);
}, [icon])
useEffect(() => {
if(open) {
onOpen()
+17 -57
View File
@@ -1,28 +1,25 @@
import { Button, Flex, Grid, Text, useToast } from "@chakra-ui/react";
import { Button, Flex, Grid, Text, useToast } from '@chakra-ui/react';
import download from 'downloadjs';
import Link from 'next/link'
import copy from "copy-to-clipboard";
import {useContext, useMemo} from "react";
import {IconStyleContext} from "./CustomizeIconContext";
import {IconWrapper} from "./IconWrapper";
import { useRouter } from "next/router";
import Link from 'next/link';
import copy from 'copy-to-clipboard';
import { useCallback, useContext, useMemo } from 'react';
import { IconStyleContext } from './CustomizeIconContext';
import { IconWrapper } from './IconWrapper';
import { useRouter } from 'next/router';
import ModifiedTooltip from './ModifiedTooltip';
import IconListItem from './IconListItem';
const IconList = ({icons}) => {
const router = useRouter()
const IconList = ({ icons }) => {
const router = useRouter();
const toast = useToast();
const {color, size, strokeWidth} = useContext(IconStyleContext);
const { color, size, strokeWidth } = useContext(IconStyleContext);
const { search } = router.query;
const query = useMemo(()=> search !== undefined ? { search } : {},[search])
const query = useMemo(() => (search !== undefined ? { search } : {}), [search]);
return (
<Grid
templateColumns={`repeat(auto-fill, minmax(150px, 1fr))`}
gap={5}
marginBottom="320px"
>
{ icons.map((icon) => {
<Grid templateColumns={`repeat(auto-fill, minmax(150px, 1fr))`} gap={5} marginBottom="320px">
{icons.map(icon => {
const actualIcon = icon.item ? icon.item : icon;
const { name, content, contributors } = actualIcon;
@@ -30,6 +27,7 @@ const IconList = ({icons}) => {
<Link
key={name}
scroll={false}
shallow={true}
href={{
pathname: '/icon/[iconName]',
query: {
@@ -38,50 +36,12 @@ const IconList = ({icons}) => {
},
}}
>
<Button
variant="ghost"
borderWidth="1px"
rounded="lg"
padding={16}
position="relative"
onClick={(event) => {
if (event.shiftKey) {
copy(actualIcon.src);
toast({
title: "Copied!",
description: `Icon "${name}" copied to clipboard.`,
status: "success",
duration: 1500,
});
}
if (event.metaKey) {
download(
actualIcon.src,
`${name}.svg`,
"image/svg+xml"
);
}
}}
key={name}
alignItems="center"
>
{ contributors?.length ? ( <ModifiedTooltip/> ) : null}
<Flex direction="column" align="center" justify="center">
<IconWrapper
content={content}
stroke={color}
strokeWidth={strokeWidth}
height={size}
width={size}
/>
<Text marginTop={5}>{name}</Text>
</Flex>
</Button>
<IconListItem {...icon} />
</Link>
);
})}
</Grid>
);
}
};
export default IconList;
+61
View File
@@ -0,0 +1,61 @@
import { Button, ButtonProps, Flex, Text, useToast } from '@chakra-ui/react';
import download from 'downloadjs';
import copy from 'copy-to-clipboard';
import { memo, useContext } from 'react';
import { IconStyleContext } from './CustomizeIconContext';
import { IconWrapper } from './IconWrapper';
interface IconListItemProps {
name: string;
content: string;
contributors: any[];
src: string;
onClick?: ButtonProps['onClick'];
}
const IconListItem = ({ name, content, src, onClick }: IconListItemProps) => {
const toast = useToast();
const { color, size, strokeWidth } = useContext(IconStyleContext);
return (
<Button
variant="ghost"
borderWidth="1px"
rounded="lg"
padding={16}
position="relative"
onClick={event => {
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);
}
}}
key={name}
alignItems="center"
>
<Flex direction="column" align="center" justify="center">
<IconWrapper
content={content}
stroke={color}
strokeWidth={strokeWidth}
height={size}
width={size}
/>
<Text marginTop={5}>{name}</Text>
</Flex>
</Button>
);
};
export default memo(IconListItem);
+29 -17
View File
@@ -7,6 +7,7 @@ import {
useColorModeValue,
IconButton,
useBreakpointValue,
BoxProps,
} from '@chakra-ui/react';
import { useKeyBindings } from '../lib/key';
import { useRouter } from 'next/router';
@@ -15,7 +16,11 @@ import { Moon, Sun, Menu, X } from 'lucide-react';
import { useMobileNavigationContext, useMobileNavigationValue } from './MobileNavigationProvider';
import Logo from './Logo';
const Layout = ({ children }) => {
interface LayoutProps extends BoxProps {
aside?: BoxProps['children'];
}
const Layout = ({ aside, children }: LayoutProps) => {
const router = useRouter();
const { toggleMobileMenu } = useMobileNavigationContext();
const { toggleColorMode } = useColorMode();
@@ -32,12 +37,12 @@ const Layout = ({ children }) => {
};
function setQuery(query) {
router
.push({
router.push({
pathname: '/',
query: { query: query },
})
.then();
},
undefined,
{ shallow: true })
}
useKeyBindings({
@@ -57,7 +62,6 @@ const Layout = ({ children }) => {
justifyContent="space-between"
pt={4}
pb={4}
maxW="1250px"
margin="0 auto"
w="full"
px={5}
@@ -68,16 +72,21 @@ const Layout = ({ children }) => {
<Flex justifyContent="center" alignItems="center">
{showBaseNavigation ? (
<>
{/* <NextLink href="/docs" passHref>
<NextLink href="/docs" passHref>
<Link marginRight={12} fontSize="xl">
Documentation
</Link>
</NextLink> */}
</NextLink>
<NextLink href="/packages" passHref>
<Link marginRight={12} fontSize="xl">
Packages
</Link>
</NextLink>
<NextLink href="/license" passHref>
<Link marginRight={12} fontSize="xl">
License
</Link>
</NextLink>
<Link
href="https://github.com/lucide-icons/lucide"
isExternal
@@ -105,15 +114,18 @@ const Layout = ({ children }) => {
</Flex>
</Flex>
</Flex>
<Flex margin="0 auto" direction="column" maxW="1250px" px={5}>
{children}
<Divider mb={6} mt={12} />
<p style={{ alignSelf: 'center' }}>
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
</a>
</p>
<br />
<Flex>
{aside ? <Box as="aside" marginRight={{ base: 0, lg: -240, }}>{aside}</Box> : null}
<Flex margin="0 auto" direction="column" maxW="1250px" px={5} width="100%">
{children}
<Divider mb={6} mt={12} />
<p style={{ alignSelf: 'center' }}>
<a href="https://vercel.com?utm_source=lucide&utm_campaign=oss">
<img src="/vercel.svg" alt="Powered by Vercel" width="200" />
</a>
</p>
<br />
</Flex>
</Flex>
</Box>
);
+21 -17
View File
@@ -11,12 +11,11 @@ import {
} from '@chakra-ui/react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import HeadingTreeMenu from './HeadingTreeMenu';
import { ReactNode, useEffect } from 'react';
import Logo from './Logo';
import { useMobileNavigationContext } from './MobileNavigationProvider';
const MobileMenu = () => {
const MobileMenu = ({ children }: { children?: ReactNode }): JSX.Element => {
const { isOpen, onClose } = useMobileNavigationContext();
const router = useRouter();
@@ -27,7 +26,7 @@ const MobileMenu = () => {
}, [router.route]);
return (
<Drawer placement="left" onClose={onClose} isOpen={isOpen} size="md">
<Drawer placement="left" onClose={onClose} isOpen={isOpen} size="sm">
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton marginTop={3.5} marginRight={3} />
@@ -36,29 +35,34 @@ const MobileMenu = () => {
</DrawerHeader>
<DrawerBody>
<Box mb={4}>
{/* <NextLink href="/docs" passHref>
<Link fontSize="xl" fontWeight="bold">
<NextLink href="/docs" passHref>
<Link fontSize="lg" fontWeight="bold" display="block" mb={2}>
Documentation
</Link>
</NextLink> */}
<NextLink href="/packages" passHref>
<Link marginRight={12} fontSize="xl">
Packages
</Link>
</NextLink>
</Box>
<Box mb={4}>
</NextLink>
<NextLink href="/packages" passHref>
<Link marginRight={12} fontSize="lg" fontWeight="bold" display="block" mb={2}>
Packages
</Link>
</NextLink>
<NextLink href="/license" passHref>
<Link marginRight={12} fontSize="xl">
License
</Link>
</NextLink>
<Link
href="https://github.com/lucide-icons/lucide"
isExternal
fontSize="xl"
fontSize="lg"
fontWeight="bold"
display="block"
mb={2}
>
Github
</Link>
</Box>
<Divider />
<HeadingTreeMenu />
<Divider mt={2} />
{children}
</DrawerBody>
</DrawerContent>
</Drawer>
@@ -1,23 +1,27 @@
import { useDisclosure } from '@chakra-ui/react';
import { createContext, useState, useContext, useMemo, useCallback, useEffect } from 'react'
import { createContext, useState, useContext, useMemo, useCallback, useEffect } from 'react';
const MobileNavigationContext = createContext({
isOpen: false,
onOpen: () => {},
onClose: () => {},
toggleMobileMenu: () => {}
})
toggleMobileMenu: () => {},
});
export function MobileNavigationProvider({ children }) {
const { isOpen, onOpen, onClose } = useDisclosure()
const toggleMobileMenu = () => isOpen ? onClose() : onOpen()
const { isOpen, onOpen, onClose } = useDisclosure();
const toggleMobileMenu = () => (isOpen ? onClose() : onOpen());
return <MobileNavigationContext.Provider value={{ isOpen, onOpen, onClose, toggleMobileMenu }}>{children}</MobileNavigationContext.Provider>
return (
<MobileNavigationContext.Provider value={{ isOpen, onOpen, onClose, toggleMobileMenu }}>
{children}
</MobileNavigationContext.Provider>
);
}
export const useMobileNavigationContext = () => useContext(MobileNavigationContext);
export const useMobileNavigationValue = (intialValue, activeValue) => {
const { isOpen } = useMobileNavigationContext();
return useMemo(() => isOpen ? activeValue : intialValue, [ isOpen ]);
}
return useMemo(() => (isOpen ? activeValue : intialValue), [isOpen]);
};
+28 -41
View File
@@ -7,11 +7,11 @@ import {
useColorMode,
Divider,
ButtonGroup,
Stack
Stack,
} from '@chakra-ui/react';
import Image from 'next/image'
import Image from 'next/image';
import { Code, FileText } from 'lucide-react';
import Link from 'next/link'
import Link from 'next/link';
import { MDXRemote } from 'next-mdx-remote';
import mdxComponents from '../lib/mdxComponents';
@@ -31,27 +31,27 @@ const Package = ({ name, description, image, shields, source, documentation }) =
>
<Flex
justifyContent={{
base: "center",
md: "flex-start"
base: 'center',
md: 'flex-start',
}}
flexDirection={{
base: "column",
md: "row"
base: 'column',
md: 'row',
}}
>
<Flex
marginRight={{
base: 0,
md: 8
md: 8,
}}
marginBottom={{
base: 4,
md: 0
md: 0,
}}
flex={3}
align="center"
>
<Box marginX='auto'>
<Box marginX="auto">
<Image width={278} height={120} src={image} />
</Box>
</Flex>
@@ -59,31 +59,30 @@ const Package = ({ name, description, image, shields, source, documentation }) =
flex={5}
marginRight={4}
textAlign={{
base: "center",
md: "left"
base: 'center',
md: 'left',
}}
>
<Heading as="h2" fontSize='3xl' mb={2}>
<Heading as="h2" fontSize="3xl" mb={2}>
{name}
</Heading>
<Text mb={3}>{ description }</Text>
<Text mb={3}>{description}</Text>
<ButtonGroup spacing={2}>
{shields.map(({ alt, src, href }, index) => (
<Link href={href} passHref>
<a target="_blank">
<img {...{alt, src}} key={ index } />
<img {...{ alt, src }} key={index} />
</a>
</Link>
))}
</ButtonGroup>
</Box>
<Flex
placeItems="center"
align='center'
align="center"
marginTop={{
base: 4,
md: 0
md: 0,
}}
>
<ButtonGroup
@@ -91,36 +90,24 @@ const Package = ({ name, description, image, shields, source, documentation }) =
// spacing={8}
// align='center'
flexDirection={{
base: "column",
lg: "initial"
base: 'column',
lg: 'initial',
}}
margin='auto'
margin="auto"
justifyContent={{
base: "center",
sm: "flex-start"
base: 'center',
sm: 'flex-start',
}}
>
<Link passHref href={documentation} >
<Button
as='a'
variant="solid"
textDecoration="none"
leftIcon={<FileText />}
my={2}
>
<Link passHref href={documentation}>
<Button as="a" variant="solid" textDecoration="none" leftIcon={<FileText />} my={2}>
Documentation
</Button>
</Link>
<Link passHref href={source} >
<Button
as="a"
variant="solid"
textDecoration="none"
leftIcon={<Code />}
my={2}
>
Source
</Button>
<Link passHref href={source}>
<Button as="a" variant="solid" textDecoration="none" leftIcon={<Code />} my={2}>
Source
</Button>
</Link>
</ButtonGroup>
</Flex>
+128
View File
@@ -0,0 +1,128 @@
const docsMenuTree = [
{
section: 'Getting Started',
items: [
{
title: 'Introduction',
href: ''
},
{
title: 'Installation',
href: 'installation'
},
{
title: 'Comparison',
href: 'comparison'
},
// {
// title: 'Examples',
// href: 'examples'
// }
]
},
// {
// section: 'Using Icons',
// items: [
// {
// title: 'What should I use',
// href: 'what-should-i-use'
// },
// {
// title: 'For Web (Vanilla)',
// href: 'lucide-with-web'
// },
// {
// title: 'React',
// href: 'lucide-with-react'
// },
// {
// title: 'Vue',
// href: 'lucide-with-vue'
// },
// {
// title: 'Angular',
// href: 'lucide-with-angular'
// },
// {
// title: 'Preact',
// href: 'lucide-with-preact'
// },
// {
// title: 'nodejs',
// href: 'lucide-with-nodejs'
// },
// {
// title: 'Flutter',
// href: 'lucide-with-flutter'
// },
// {
// title: 'Figma',
// href: 'lucide-with-figma'
// },
// {
// title: 'Other Design programs',
// href: 'lucide-with-design-programs'
// },
// ]
// },
{
section: 'Packages',
items: [
{
title: 'Lucide',
href: 'lucide'
},
{
title: 'Lucide React',
href: 'lucide-react'
},
{
title: 'Lucide Vue',
href: 'lucide-vue'
},
{
title: 'Lucide Vue Next (Vue 3)',
href: 'lucide-vue-next'
},
{
title: 'Lucide Preact',
href: 'lucide-preact'
},
{
title: 'Lucide Angular',
href: 'lucide-angular'
},
{
title: 'Lucide Static',
href: 'lucide-static'
},
{
title: 'Lucide Flutter',
href: 'lucide-flutter'
},
]
},
{
section: 'Contributing',
items: [
{
title: 'Icon Design Principles',
href: 'icon-design-guide'
},
{
title: 'Designing in Illustrator',
href: 'illustrator-guide'
},
{
title: 'Designing in InkScape',
href: 'inkscape-guide'
},
{
title: 'Designing in Figma',
href: 'figma-guide'
},
]
},
]
export default docsMenuTree;
+14 -7
View File
@@ -31,10 +31,10 @@ const components = {
</HeadingAnchored>
),
h3: (props) => (
<HeadingAnchored as="h3" size="md" pt={4} mb={2} {...props}/>
<HeadingAnchored as="h3" size="md" pt={4} mb={4} {...props}/>
),
h4: (props) => (
<HeadingAnchored as="h4" size="sm" pt={4} mb={2} {...props}/>
<HeadingAnchored as="h4" size="sm" pt={4} mb={4} {...props}/>
),
h5: (props) => (
<HeadingAnchored as="h5" size="xs" pt={2} mb={1} {...props}/>
@@ -45,7 +45,7 @@ const components = {
ul: (props) => <UnorderedList my={2}>{props.children}</UnorderedList>,
ol: (props) => <OrderedList my={2}>{props.children}</OrderedList>,
li: (props) => <ListItem my={1}>{props.children}</ListItem>,
p: (props) => <Text my={2}>{props.children}</Text>,
p: (props) => <Text my={4}>{props.children}</Text>,
img: ({ children, ...rest }) => <Image {...rest} borderRadius={4} my={2}>{children}</Image>,
code: ({ className, children: code }) => {
const language = className.replace('language-', '');
@@ -53,13 +53,13 @@ const components = {
return (
<CodeBlock
//@ts-ignore
my={2}
my={6}
code={code}
language={language}
/>
)
},
table: (props) => <Table {...props} rounded={4}/>,
table: (props) => <Table {...props} rounded={4} mb={4}/>,
thead: Thead,
tbody: Tbody,
tr: Tr,
@@ -80,11 +80,18 @@ const components = {
inlineCode: InlineCode,
hr: (props) => <Divider my={4}/>,
a: ({children, href, ...rest}) => {
const isExternal = href.startsWith('http')
let link = href
const isExternal = link.startsWith('http')
if(link.startsWith('packages/')) {
link = href.replace('packages/', '')
}
link = link.replace('.md', '')
return (
<NextLink
href={isExternal ? href : `/docs/${href.replace('.md', '')}`}
href={isExternal ? href : `/docs/${link}`}
{...rest}
passHref
>
+16
View File
@@ -6,6 +6,22 @@ const theme = {
...chakraTheme.fonts,
body: `'Mukta', sans-serif`,
},
colors: {
...chakraTheme.colors,
brand: {
DEFAULT: '#F56565',
'50': '#FFFFFF',
'100': '#FFFEFE',
'200': '#FCD8D8',
'300': '#FAB2B2',
'400': '#F78B8B',
'500': '#F56565',
'600': '#F23030',
'700': '#DC0E0E',
'800': '#A70B0B',
'900': '#720707'
},
}
};
export default theme;
+1 -1
View File
@@ -2,7 +2,7 @@ import { ChakraProvider } from '@chakra-ui/react';
import customTheme from '../lib/theme';
import '../assets/styling.css';
import Head from 'next/head';
import { CustomizeIconContext } from "../components/CustomizeIconContext";
import { CustomizeIconContext } from '../components/CustomizeIconContext';
import { MobileNavigationProvider } from '../components/MobileNavigationProvider';
const App = ({ Component, pageProps }) => {
+20 -16
View File
@@ -1,33 +1,37 @@
import Layout from '../../components/Layout';
import Header from '../../components/Header';
import Head from 'next/head';
import fetchAllDocuments from '../../lib/fetchAllDocuments'
import fetchAllDocuments from '../../lib/fetchAllDocuments';
export { default } from '.'
export { default } from '.';
const transformToReadableSlug = (fileName: string) =>
fileName
.toLowerCase()
.replace(/_/g, '-')
.replace('.md', '');
export async function getStaticProps({ params: { docName } }) {
const allDocs = await fetchAllDocuments()
console.log();
const allDocs = await fetchAllDocuments();
const doc = allDocs.find(({filename = ''}) => filename === `${docName}.md`);
const doc = allDocs.find(({ filename = '' }) => transformToReadableSlug(filename) === docName);
return { props: doc }
return { props: doc };
}
export async function getStaticPaths() {
const docs = await fetchAllDocuments()
const docs = await fetchAllDocuments();
const paths =
docs
.filter(({filename = ''}) => filename !== 'index.md')
.map(doc => ({
params: {
docName: doc.filename.replace('.md', '')
}
}))
const paths = docs
.filter(({ filename = '' }) => filename !== 'index.md')
.map(doc => ({
params: {
docName: transformToReadableSlug(doc.filename),
},
}));
return {
paths,
fallback: false,
}
};
}
+47 -4
View File
@@ -3,22 +3,65 @@ import Head from 'next/head';
import fetchAllDocuments from '../../lib/fetchAllDocuments'
import { MDXRemote } from 'next-mdx-remote'
import mdxComponents from '../../lib/mdxComponents';
import { HeadingNavigationProvider } from '../../components/HeadingNavigationProvider';
import HeadingNavigationProvider from '../../components/HeadingNavigationProvider';
import MobileMenu from '../../components/MobileMenu';
import DocsMenu from '../../components/DocsMenu';
import { Box, Button, Text } from '@chakra-ui/react';
import { ArrowRight } from 'lucide-react'
import Link from 'next/link';
const DocPage = ({ doc, data, content }) => {
if (!data || !doc) return null
const nextPage = data.nextPage || []
return (
<HeadingNavigationProvider>
<MobileMenu />
<Layout>
<MobileMenu>
<DocsMenu/>
</MobileMenu>
<Layout aside={
<DocsMenu
display={{ base:'none', md: 'block' }}
paddingX={8}
position="sticky"
overflowY="auto"
width={240}
height="100vh"
marginTop={-4}
top={0}
/>
}
>
{ data?.title ? (
<Head>
<title>{ data.title }</title>
</Head>
) : null}
<MDXRemote {...doc} data={data} components={mdxComponents} />
<Box maxWidth="xl" width='100%' marginX='auto'>
<MDXRemote {...doc} data={data} components={mdxComponents} />
{ nextPage.map((page) => (
<Link href={`docs/${page}`}>
<Button
variant="ghost"
borderWidth="1px"
rounded="lg"
padding={8}
position="relative"
width='60%'
minWidth={240}
marginTop={6}
rightIcon={<ArrowRight />}
>
<Text fontSize={19} fontWeight="bold" textTransform="capitalize">
{page}
</Text>
</Button>
</Link>
)) }
</Box>
</Layout>
</HeadingNavigationProvider>
)
+14 -1
View File
@@ -4,9 +4,11 @@ import { getAllData, getData } from '../../lib/icons';
import IconOverview from '../../components/IconOverview';
import Layout from '../../components/Layout';
import Header from '../../components/Header';
import { useEffect, useMemo } from 'react';
const IconPage = ({ icon, data }) => {
const router = useRouter();
const getIcon = iconName => data.find(({ name }) => name === iconName) || {};
const onClose = () => {
let query = {};
@@ -28,9 +30,20 @@ const IconPage = ({ icon, data }) => {
);
};
const currentIcon = useMemo(() => {
if(icon.name === router.query.iconName) {
return icon
}
return getIcon(router.query.iconName)
}, [router.query])
return (
<Layout>
<IconDetailOverlay key={icon.name} icon={icon} close={onClose} />
<IconDetailOverlay
key={currentIcon.name}
icon={currentIcon}
close={onClose}
/>
<Header {...{ data }} />
<IconOverview {...{ data }} />
</Layout>
+8 -3
View File
@@ -6,18 +6,23 @@ 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';
const IndexPage = ({ data }) => {
const router = useRouter();
const getIcon = iconName => data.find(({ name }) => name === iconName) || {};
const currentIcon = useMemo(() => {
return getIcon(router.query.iconName)
}, [router.query])
return (
<Layout>
<MobileMenu />
<IconDetailOverlay
open={!!router.query.iconName}
icon={getIcon(router.query.iconName)}
close={() => router.push('/')}
open={!!currentIcon?.name}
icon={currentIcon}
close={() => router.push('/', undefined, { shallow: true })}
/>
<Header {...{ data }} />
<IconOverview {...{ data }} />
+57
View File
@@ -0,0 +1,57 @@
import Layout from '../components/Layout';
import Head from 'next/head';
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';
const LicensePage = ({ licenseText }) => {
return (
<Box>
<MobileMenu />
<Layout>
<Head>
<title>License - Lucide</title>
</Head>
<Box maxWidth="xl" width="100%" marginX="auto">
<Heading as="h1" mb={4}>
Lucide License
</Heading>
{licenseText.map((text, index) => {
if (index === 0) {
return (
<Heading as="h2" fontSize={24} mb={8}>
{text}
</Heading>
);
}
return (
<Text fontSize={19} mb={4}>
{text}
</Text>
);
})}
</Box>
</Layout>
</Box>
);
};
export default LicensePage;
export const getStaticProps: GetStaticProps = async ({ params }) => {
const doc = await fs.readFile(resolve('../LICENSE'), 'utf-8');
const licenseText = doc
.split('\n')
.map(line => (line === '' ? '|' : line))
.join('')
.split('|')
.filter(Boolean);
return { props: { licenseText } };
};
+3 -7
View File
@@ -1,5 +1,5 @@
import Layout from '../../components/Layout';
import { HeadingNavigationProvider } from '../../components/HeadingNavigationProvider';
import HeadingNavigationProvider from '../../components/HeadingNavigationProvider';
import MobileMenu from '../../components/MobileMenu';
import { Stack } from '@chakra-ui/react';
import Package from '../../components/Package';
@@ -16,11 +16,7 @@ const PackagesPage = ({ packages }) => {
Packages
</Heading>
<Stack spacing={8} align="center">
{ packages.length ? (
packages.map(packageItem => (
<Package {...packageItem} />
))
) : null }
{packages.length ? packages.map(packageItem => <Package {...packageItem} />) : null}
</Stack>
</Layout>
</HeadingNavigationProvider>
@@ -45,7 +41,7 @@ export async function getStaticProps({ params }) {
...packageData[packageDirectory],
};
})
.sort((a,b ) => a.order - b.order);
.sort((a, b) => a.order - b.order);
return { props: { packages } };
}
+1335 -1152
View File
File diff suppressed because it is too large Load Diff