Add contributors to icon overlay and add dot (#223)
* add contributers * Add icon fetcher * add contributing json * Fix fetch call * Add contributers to site * Add caching for github api * Fix build * Move context provider * Revert packages changes * Fix mobile layout * remove react-spring * remove incorrect type prop
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/core": "^1.0.0-rc.8",
|
"@chakra-ui/core": "^1.0.0-rc.8",
|
||||||
"downloadjs": "^1.4.7",
|
"downloadjs": "^1.4.7",
|
||||||
"framer-motion": "^2.9.4",
|
"framer-motion": "^3.3.0",
|
||||||
"fuse.js": "^6.0.4",
|
"fuse.js": "^6.0.4",
|
||||||
"jszip": "^3.4.0",
|
"jszip": "^3.4.0",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-color": "2.17.3",
|
"react-color": "2.17.3",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
"react-spring": "^8.0.27",
|
|
||||||
"react-svg-loader": "^3.0.3"
|
"react-svg-loader": "^3.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Button, Flex, Link, Stack, Text,} from "@chakra-ui/core";
|
import {Button, Flex, Link, WrapItem, Text, Wrap,} from "@chakra-ui/core";
|
||||||
import download from "downloadjs";
|
import download from "downloadjs";
|
||||||
import JSZip from "jszip";
|
import JSZip from "jszip";
|
||||||
import { Download, Github } from 'lucide-react';
|
import { Download, Github } from 'lucide-react';
|
||||||
@@ -30,15 +30,26 @@ const Header = ({ data }) => {
|
|||||||
<Text fontSize="lg" as="p" textAlign="center" mb="8">
|
<Text fontSize="lg" as="p" textAlign="center" mb="8">
|
||||||
An open-source icon library, a fork of <Link href="https://github.com/feathericons/feather" isExternal>Feather Icons</Link>. <br/>We're expanding the icon set as much as possible while keeping it nice-looking - <Link href={repositoryUrl} isExternal>join us</Link>!
|
An open-source icon library, a fork of <Link href="https://github.com/feathericons/feather" isExternal>Feather Icons</Link>. <br/>We're expanding the icon set as much as possible while keeping it nice-looking - <Link href={repositoryUrl} isExternal>join us</Link>!
|
||||||
</Text>
|
</Text>
|
||||||
<Stack isInline marginTop={3} marginBottom={10}>
|
<Wrap
|
||||||
<Button
|
isInline
|
||||||
leftIcon={<Download/>}
|
marginTop={3}
|
||||||
size="lg"
|
marginBottom={10}
|
||||||
onClick={downloadAllIcons}
|
spacing="15px"
|
||||||
>
|
justify="center"
|
||||||
Download all
|
>
|
||||||
</Button>
|
<WrapItem>
|
||||||
|
<Button
|
||||||
|
leftIcon={<Download/>}
|
||||||
|
size="lg"
|
||||||
|
onClick={downloadAllIcons}
|
||||||
|
>
|
||||||
|
Download all
|
||||||
|
</Button>
|
||||||
|
</WrapItem>
|
||||||
|
<WrapItem>
|
||||||
<IconCustomizerDrawer/>
|
<IconCustomizerDrawer/>
|
||||||
|
</WrapItem>
|
||||||
|
<WrapItem>
|
||||||
<Button
|
<Button
|
||||||
as="a"
|
as="a"
|
||||||
leftIcon={<Github/>}
|
leftIcon={<Github/>}
|
||||||
@@ -49,7 +60,8 @@ const Header = ({ data }) => {
|
|||||||
>
|
>
|
||||||
Github
|
Github
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</WrapItem>
|
||||||
|
</Wrap>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
import { useSpring, animated } from "react-spring";
|
import { Box, Text, IconButton, useColorMode, Flex, Slide, ButtonGroup, Button, useToast, Heading, Avatar, AvatarGroup, Link, Tooltip, useMediaQuery, useDisclosure } from "@chakra-ui/core";
|
||||||
import { Box, Text, IconButton, useColorMode, Flex, ButtonGroup, Button, useToast } from "@chakra-ui/core";
|
|
||||||
import theme from "../lib/theme";
|
import theme from "../lib/theme";
|
||||||
import download from 'downloadjs';
|
import download from 'downloadjs';
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { X as Close } from 'lucide-react';
|
import { X as Close } from 'lucide-react';
|
||||||
import {useContext, useRef} from "react";
|
import {useContext, useEffect, useRef} from "react";
|
||||||
import {IconStyleContext} from "./CustomizeIconContext";
|
import {IconStyleContext} from "./CustomizeIconContext";
|
||||||
import {IconWrapper} from "./IconWrapper";
|
import {IconWrapper} from "./IconWrapper";
|
||||||
|
import ModifiedTooltip from "./ModifiedTooltip";
|
||||||
|
|
||||||
type IconDownload = {
|
type IconDownload = {
|
||||||
src: string;
|
src: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
const IconDetailOverlay = ({ open = true, close, icon }) => {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { colorMode } = useColorMode();
|
const { colorMode } = useColorMode();
|
||||||
const { tags = [], name } = icon;
|
const { tags = [], name } = icon;
|
||||||
const {color, strokeWidth, size} = useContext(IconStyleContext);
|
const {color, strokeWidth, size} = useContext(IconStyleContext);
|
||||||
const iconRef = useRef<SVGSVGElement>(null);
|
const iconRef = useRef<SVGSVGElement>(null);
|
||||||
|
const [isMobile] = useMediaQuery("(max-width: 560px)")
|
||||||
const { transform, opacity } = useSpring({
|
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||||
opacity: isOpen ? 1 : 0,
|
|
||||||
transform: `translateY(${isOpen ? -120 : 0}%)`,
|
|
||||||
config: { mass: 5, tension: 500, friction: 80 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const panelStyling = {
|
useEffect(() => {
|
||||||
transform: transform.interpolate(t => t),
|
if(open) {
|
||||||
opacity: opacity.interpolate(o => o),
|
onOpen()
|
||||||
width: "100%",
|
}
|
||||||
willChange: "transform"
|
}, [open])
|
||||||
}
|
|
||||||
|
|
||||||
const iconStyling = (isLight) => ({
|
const iconStyling = (isLight) => ({
|
||||||
height: "25vw",
|
height: "25vw",
|
||||||
@@ -88,6 +84,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
|||||||
height={0}
|
height={0}
|
||||||
key={name}
|
key={name}
|
||||||
>
|
>
|
||||||
|
<Slide direction="bottom" in={isOpen} style={{ zIndex: 10 }}>
|
||||||
<Flex
|
<Flex
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="space-between"
|
justifyContent="space-between"
|
||||||
@@ -98,9 +95,7 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
|||||||
w="full"
|
w="full"
|
||||||
px={8}
|
px={8}
|
||||||
>
|
>
|
||||||
<animated.div
|
|
||||||
style={panelStyling}
|
|
||||||
>
|
|
||||||
<Box
|
<Box
|
||||||
borderWidth="1px"
|
borderWidth="1px"
|
||||||
rounded="lg"
|
rounded="lg"
|
||||||
@@ -163,11 +158,25 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
|||||||
</svg>
|
</svg>
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex marginLeft={[0, 8]}>
|
<Flex marginLeft={[0, 8]} w="100%">
|
||||||
<Box>
|
<Box w="100%">
|
||||||
<Text fontSize="3xl" style={{ cursor: "pointer" }} mb={1}>
|
<Flex
|
||||||
{icon.name}
|
justify={isMobile ? 'center' : 'flex-start'}
|
||||||
</Text>
|
marginTop={isMobile ? 10 : 0}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
position="relative"
|
||||||
|
mb={1}
|
||||||
|
display="inline-block"
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
pr={6}
|
||||||
|
>
|
||||||
|
<Text fontSize="3xl">
|
||||||
|
{icon.name}
|
||||||
|
</Text>
|
||||||
|
{ icon?.contributors?.length ? ( <ModifiedTooltip/> ) : null}
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
{ tags?.length ? (
|
{ tags?.length ? (
|
||||||
<Text
|
<Text
|
||||||
@@ -187,23 +196,42 @@ const IconDetailOverlay = ({ isOpen = true, onClose, icon }) => {
|
|||||||
Edit Tags
|
Edit Tags
|
||||||
</Button> */}
|
</Button> */}
|
||||||
</Box>
|
</Box>
|
||||||
<ButtonGroup spacing={4}>
|
<Box overflowY="auto" w="100%" pt={1} pb={1}>
|
||||||
<Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
<ButtonGroup spacing={4}>
|
||||||
Download SVG
|
<Button variant="solid" onClick={() => downloadIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||||
</Button>
|
Download SVG
|
||||||
<Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
</Button>
|
||||||
Copy SVG
|
<Button variant="solid" onClick={() => copyIcon({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||||
</Button>
|
Copy SVG
|
||||||
<Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
</Button>
|
||||||
Download PNG
|
<Button variant="solid" onClick={() => downloadPNG({src: iconRef.current.outerHTML, name: icon.name})} mb={1}>
|
||||||
</Button>
|
Download PNG
|
||||||
</ButtonGroup>
|
</Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
</Box>
|
||||||
|
{ icon?.contributors?.length ? (
|
||||||
|
<>
|
||||||
|
<Heading as="h5" size="sm" marginTop={4} marginBottom={2}>
|
||||||
|
Contributors:
|
||||||
|
</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}>
|
||||||
|
<Avatar name={commit.author} showBorder={false} src={`https://github.com/${commit.author}.png?size=88`} />
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
)) }
|
||||||
|
</AvatarGroup>
|
||||||
|
</>
|
||||||
|
) : null }
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
</animated.div>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Slide>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {useContext, useMemo} from "react";
|
|||||||
import {IconStyleContext} from "./CustomizeIconContext";
|
import {IconStyleContext} from "./CustomizeIconContext";
|
||||||
import {IconWrapper} from "./IconWrapper";
|
import {IconWrapper} from "./IconWrapper";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import ModifiedTooltip from './ModifiedTooltip';
|
||||||
|
|
||||||
const IconList = ({icons}) => {
|
const IconList = ({icons}) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -17,13 +18,13 @@ const IconList = ({icons}) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid
|
<Grid
|
||||||
templateColumns={`repeat(auto-fill, minmax(160px, 1fr))`}
|
templateColumns={`repeat(auto-fill, minmax(150px, 1fr))`}
|
||||||
gap={5}
|
gap={5}
|
||||||
marginBottom="320px"
|
marginBottom="320px"
|
||||||
>
|
>
|
||||||
{ icons.map((icon) => {
|
{ icons.map((icon) => {
|
||||||
const actualIcon = icon.item ? icon.item : icon;
|
const actualIcon = icon.item ? icon.item : icon;
|
||||||
const { name, content } = actualIcon;
|
const { name, content, contributors } = actualIcon;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
@@ -42,6 +43,7 @@ const IconList = ({icons}) => {
|
|||||||
borderWidth="1px"
|
borderWidth="1px"
|
||||||
rounded="lg"
|
rounded="lg"
|
||||||
padding={16}
|
padding={16}
|
||||||
|
position="relative"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
copy(actualIcon.src);
|
copy(actualIcon.src);
|
||||||
@@ -63,6 +65,7 @@ const IconList = ({icons}) => {
|
|||||||
key={name}
|
key={name}
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
>
|
>
|
||||||
|
{ contributors?.length ? ( <ModifiedTooltip/> ) : null}
|
||||||
<Flex direction="column" align="center" justify="center">
|
<Flex direction="column" align="center" justify="center">
|
||||||
<IconWrapper
|
<IconWrapper
|
||||||
content={content}
|
content={content}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const Layout = ({ children }) => {
|
|||||||
maxW="1250px"
|
maxW="1250px"
|
||||||
margin="0 auto"
|
margin="0 auto"
|
||||||
w="full"
|
w="full"
|
||||||
px={8}
|
px={5}
|
||||||
>
|
>
|
||||||
<Flex justifyContent="center" alignItems="center">
|
<Flex justifyContent="center" alignItems="center">
|
||||||
<NextLink href="/" passHref>
|
<NextLink href="/" passHref>
|
||||||
@@ -77,7 +77,7 @@ const Layout = ({ children }) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex margin="0 auto" direction="column" maxW="1250px" px={8}>
|
<Flex margin="0 auto" direction="column" maxW="1250px" px={5}>
|
||||||
{children}
|
{children}
|
||||||
<Divider marginBottom={8} />
|
<Divider marginBottom={8} />
|
||||||
<p style={{ alignSelf: "center" }}>
|
<p style={{ alignSelf: "center" }}>
|
||||||
|
|||||||
31
site/src/components/ModifiedTooltip.tsx
Normal file
31
site/src/components/ModifiedTooltip.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Box, Tooltip, useColorMode } from "@chakra-ui/core";
|
||||||
|
import theme from '../lib/theme';
|
||||||
|
|
||||||
|
const ModifiedTooltip = ({}) => {
|
||||||
|
const { colorMode } = useColorMode();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
hasArrow
|
||||||
|
label="This is new or modified icon"
|
||||||
|
bg={colorMode === 'light' ? theme.colors.white : theme.colors.gray[700]}
|
||||||
|
color={colorMode === 'dark' ? theme.colors.white : null}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
{
|
||||||
|
...{
|
||||||
|
position: 'absolute',
|
||||||
|
height: '8px',
|
||||||
|
width: '8px',
|
||||||
|
background: '#F56565',
|
||||||
|
top: '8px',
|
||||||
|
right: '8px',
|
||||||
|
borderRadius: '4px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModifiedTooltip;
|
||||||
129
site/src/lib/fetchAllContributors.ts
Normal file
129
site/src/lib/fetchAllContributors.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const IGNORE_COMMIT_MESSAGES = ['fork', 'optimize'];
|
||||||
|
|
||||||
|
function getContentHashOfFile(path) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const hash = crypto.createHash('md4');
|
||||||
|
const stream = fs.createReadStream(path);
|
||||||
|
stream.on('error', err => reject(err));
|
||||||
|
stream.on('data', chunk => hash.update(chunk));
|
||||||
|
stream.on('end', () => resolve(hash.digest('hex')));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchCommitsOfIcon = (name) =>
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const headers = new Headers();
|
||||||
|
const username = 'ericfennis';
|
||||||
|
const password = process.env.GITHUB_API_KEY;
|
||||||
|
headers.set(
|
||||||
|
'Authorization',
|
||||||
|
`Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api.github.com/repos/lucide-icons/lucide/commits?path=icons/${name}.svg`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
name,
|
||||||
|
commits: data,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const filterCommits = (commits) =>
|
||||||
|
commits.filter(({ commit }) =>
|
||||||
|
!IGNORE_COMMIT_MESSAGES.some(ignoreItem =>
|
||||||
|
commit.message.toLowerCase().includes(ignoreItem),
|
||||||
|
))
|
||||||
|
.map(({ sha, author, commit }) => ({
|
||||||
|
author: author && author.login ? author.login : null,
|
||||||
|
commit: sha,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const getIconHash = async (icon) => await getContentHashOfFile(path.join(process.cwd(), "../icons", `${icon}.svg`))
|
||||||
|
const iconCacheDir = path.join(process.cwd(),'.next/cache/github-api');
|
||||||
|
const iconCache = (hash) => path.join(iconCacheDir, `${hash}.json`);
|
||||||
|
|
||||||
|
export async function checkIconCache(icon) {
|
||||||
|
const hash = await getIconHash(icon);
|
||||||
|
|
||||||
|
const cachePath = iconCache(hash);
|
||||||
|
|
||||||
|
if(fs.existsSync( cachePath )) {
|
||||||
|
const iconCache = fs.readFileSync(cachePath, "utf8");
|
||||||
|
|
||||||
|
return JSON.parse(iconCache)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeIconCache(icon, content) {
|
||||||
|
const hash = await getIconHash(icon);
|
||||||
|
|
||||||
|
const iconCachePath = iconCache(hash);
|
||||||
|
|
||||||
|
if (!fs.existsSync(iconCacheDir)){
|
||||||
|
fs.mkdirSync(iconCacheDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(iconCachePath, JSON.stringify(content), 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getContributors(icon) {
|
||||||
|
try {
|
||||||
|
let iconCommits
|
||||||
|
const iconCache = await checkIconCache(icon);
|
||||||
|
|
||||||
|
if (iconCache) {
|
||||||
|
iconCommits = iconCache
|
||||||
|
} else {
|
||||||
|
const { commits } : any = await fetchCommitsOfIcon(icon);
|
||||||
|
|
||||||
|
writeIconCache(icon, commits)
|
||||||
|
|
||||||
|
iconCommits = commits
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iconCommits && iconCommits.length) {
|
||||||
|
return filterCommits(iconCommits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllContributors(icons) {
|
||||||
|
try {
|
||||||
|
const AllIconCommits = await Promise.all(icons.map(fetchCommitsOfIcon));
|
||||||
|
|
||||||
|
const filteredCommits = AllIconCommits.reduce((acc, { name, commits }) => {
|
||||||
|
if (commits && commits.length) {
|
||||||
|
acc[name] = filterCommits(commits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return filteredCommits
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import fs from "fs";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import cheerio from 'cheerio';
|
import cheerio from 'cheerio';
|
||||||
import tags from '../../../tags.json';
|
import tags from '../../../tags.json';
|
||||||
|
import { getContributors } from "./fetchAllContributors";
|
||||||
|
|
||||||
const directory = path.join(process.cwd(), "../icons");
|
const directory = path.join(process.cwd(), "../icons");
|
||||||
|
|
||||||
@@ -13,25 +14,26 @@ export function getAllNames() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getData(name) {
|
export async function getData(name:string) {
|
||||||
const fullPath = path.join(directory, `${name}.svg`);
|
const fullPath = path.join(directory, `${name}.svg`);
|
||||||
const fileContents = fs.readFileSync(fullPath, "utf8");
|
const fileContents = fs.readFileSync(fullPath, "utf8");
|
||||||
|
|
||||||
const $ = cheerio.load(fileContents);
|
const $ = cheerio.load(fileContents);
|
||||||
const content = $("svg").html();
|
const content = $("svg").html();
|
||||||
|
|
||||||
|
const contributors = await getContributors(name);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
tags: tags[name] || [],
|
tags: tags[name] || [],
|
||||||
|
contributors,
|
||||||
src: fileContents,
|
src: fileContents,
|
||||||
content: content
|
content: content
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAllData() {
|
export async function getAllData() {
|
||||||
const names = getAllNames();
|
const names = getAllNames();
|
||||||
|
|
||||||
return names.map((name) => {
|
return Promise.all(names.map((name) => getData(name)));
|
||||||
return getData(name);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ChakraProvider } from '@chakra-ui/core';
|
|||||||
import customTheme from '../lib/theme';
|
import customTheme from '../lib/theme';
|
||||||
import '../assets/styling.css';
|
import '../assets/styling.css';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
import { CustomizeIconContext } from "../components/CustomizeIconContext";
|
||||||
|
|
||||||
const App = ({ Component, pageProps }) => {
|
const App = ({ Component, pageProps }) => {
|
||||||
return (
|
return (
|
||||||
@@ -10,7 +11,9 @@ const App = ({ Component, pageProps }) => {
|
|||||||
<title>Lucide</title>
|
<title>Lucide</title>
|
||||||
</Head>
|
</Head>
|
||||||
<ChakraProvider theme={customTheme}>
|
<ChakraProvider theme={customTheme}>
|
||||||
<Component {...pageProps} />
|
<CustomizeIconContext>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</CustomizeIconContext>
|
||||||
</ChakraProvider>
|
</ChakraProvider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useEffect } from 'react'
|
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import IconDetailOverlay from '../../components/IconDetailOverlay'
|
import IconDetailOverlay from '../../components/IconDetailOverlay'
|
||||||
import { getAllData, getData } from '../../lib/icons';
|
import { getAllData, getData } from '../../lib/icons';
|
||||||
@@ -29,7 +28,7 @@ const IconPage = ({ icon, data }) => {
|
|||||||
<IconDetailOverlay
|
<IconDetailOverlay
|
||||||
key={icon.name}
|
key={icon.name}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
onClose={onClose}
|
close={onClose}
|
||||||
/>
|
/>
|
||||||
<Header {...{data}}/>
|
<Header {...{data}}/>
|
||||||
<IconOverview {...{data}}/>
|
<IconOverview {...{data}}/>
|
||||||
@@ -39,15 +38,17 @@ const IconPage = ({ icon, data }) => {
|
|||||||
|
|
||||||
export default IconPage
|
export default IconPage
|
||||||
|
|
||||||
export function getStaticProps({ params: { iconName } }) {
|
export async function getStaticProps({ params: { iconName } }) {
|
||||||
const data = getAllData();
|
const data = await getAllData();
|
||||||
const icon = getData(iconName);
|
const icon = await getData(iconName);
|
||||||
return { props: { icon, data } }
|
return { props: { icon, data } }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
|
const data = await getAllData();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: getAllData().map(({name: iconName }) => ({
|
paths: data.map(({ name: iconName }) => ({
|
||||||
params: { iconName },
|
params: { iconName },
|
||||||
})),
|
})),
|
||||||
fallback: false,
|
fallback: false,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import IconOverview from "../components/IconOverview";
|
|||||||
import IconDetailOverlay from "../components/IconDetailOverlay";
|
import IconDetailOverlay from "../components/IconDetailOverlay";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import Header from "../components/Header";
|
import Header from "../components/Header";
|
||||||
import {CustomizeIconContext} from "../components/CustomizeIconContext";
|
|
||||||
|
|
||||||
const IndexPage = ({ data }) => {
|
const IndexPage = ({ data }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -13,21 +12,19 @@ const IndexPage = ({ data }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<CustomizeIconContext>
|
<IconDetailOverlay
|
||||||
<IconDetailOverlay
|
open={!!router.query.iconName}
|
||||||
isOpen={!!router.query.iconName}
|
icon={getIcon(router.query.iconName)}
|
||||||
icon={getIcon(router.query.iconName)}
|
close={() => router.push('/')}
|
||||||
onClose={() => router.push('/')}
|
/>
|
||||||
/>
|
<Header {...{data}}/>
|
||||||
<Header {...{data}}/>
|
<IconOverview {...{data}}/>
|
||||||
<IconOverview {...{data}}/>
|
|
||||||
</CustomizeIconContext>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getStaticProps() {
|
||||||
let data = getAllData();
|
let data = await getAllData();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -356,7 +356,7 @@
|
|||||||
core-js-pure "^3.0.0"
|
core-js-pure "^3.0.0"
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/runtime@7.12.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.9.2":
|
"@babel/runtime@7.12.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.9.2":
|
||||||
version "7.12.5"
|
version "7.12.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
|
||||||
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
|
||||||
@@ -3774,25 +3774,23 @@ fragment-cache@^0.2.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
map-cache "^0.2.2"
|
map-cache "^0.2.2"
|
||||||
|
|
||||||
framer-motion@^2.9.4:
|
framer-motion@^3.3.0:
|
||||||
version "2.9.5"
|
version "3.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-2.9.5.tgz#bbb185325d531c57f494cf3f6cf7719fc2c225c7"
|
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-3.3.0.tgz#e355824369f03c8cd07a87ef59b7a8348c33fafd"
|
||||||
integrity sha512-epSX4Co1YbDv0mjfHouuY0q361TpHE7WQzCp/xMTilxy4kXd+Z23uJzPVorfzbm1a/9q1Yu8T5bndaw65NI4Tg==
|
integrity sha512-bjUrwXfMJZ6D+HSMDiXbMGKmlWGnUux8HotWgORTZkdPTgKAndlRXjeC2ikCgNVo2ifmRvEla5ckP9JaZc7JKA==
|
||||||
dependencies:
|
dependencies:
|
||||||
framesync "^4.1.0"
|
framesync "^5.0.0"
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
popmotion "9.0.0-rc.20"
|
popmotion "^9.1.0"
|
||||||
style-value-types "^3.1.9"
|
style-value-types "^4.0.1"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@emotion/is-prop-valid" "^0.8.2"
|
"@emotion/is-prop-valid" "^0.8.2"
|
||||||
|
|
||||||
framesync@^4.1.0:
|
framesync@5.0.0, framesync@^5.0.0:
|
||||||
version "4.1.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a"
|
resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.0.0.tgz#7de8caedf53ac441118e79680f1beb7391c328b6"
|
||||||
integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ==
|
integrity sha512-wd8t+JsQGisluSv1twiEeDv0aNGpavGb9q7xgIk9fGbcIWkNXF/KVtrjnOrCwBWJuiXxlJfNkcvGudsI32FxYA==
|
||||||
dependencies:
|
|
||||||
hey-listen "^1.0.5"
|
|
||||||
|
|
||||||
from2@^2.1.0:
|
from2@^2.1.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
@@ -4064,7 +4062,7 @@ he@1.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||||
|
|
||||||
hey-listen@^1.0.5, hey-listen@^1.0.8:
|
hey-listen@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
|
resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68"
|
||||||
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
|
integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==
|
||||||
@@ -6049,14 +6047,14 @@ pnp-webpack-plugin@1.6.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ts-pnp "^1.1.6"
|
ts-pnp "^1.1.6"
|
||||||
|
|
||||||
popmotion@9.0.0-rc.20:
|
popmotion@^9.1.0:
|
||||||
version "9.0.0-rc.20"
|
version "9.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.0.0-rc.20.tgz#f3550042ae31957b5416793ae8723200951ad39d"
|
resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-9.1.0.tgz#4360d06bd18ce8baa8f9284ecec7d55344af6325"
|
||||||
integrity sha512-f98sny03WuA+c8ckBjNNXotJD4G2utG/I3Q23NU69OEafrXtxxSukAaJBxzbtxwDvz3vtZK69pu9ojdkMoBNTg==
|
integrity sha512-+J7pzzBy5kk2qsP8ilowKs/CH+HoZa3kOGEBNCleCvsPXEF3nKHdfAR3SboMyPvdpIrofaT7ZIy/xWgz446Azw==
|
||||||
dependencies:
|
dependencies:
|
||||||
framesync "^4.1.0"
|
framesync "5.0.0"
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
style-value-types "^3.1.9"
|
style-value-types "^4.0.1"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
|
|
||||||
posix-character-classes@^0.1.0:
|
posix-character-classes@^0.1.0:
|
||||||
@@ -6215,7 +6213,7 @@ prompts@^2.0.1:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2:
|
prop-types@15.7.2, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
@@ -6421,14 +6419,6 @@ react-remove-scroll@2.4.0:
|
|||||||
use-callback-ref "^1.2.3"
|
use-callback-ref "^1.2.3"
|
||||||
use-sidecar "^1.0.1"
|
use-sidecar "^1.0.1"
|
||||||
|
|
||||||
react-spring@^8.0.27:
|
|
||||||
version "8.0.27"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-spring/-/react-spring-8.0.27.tgz#97d4dee677f41e0b2adcb696f3839680a3aa356a"
|
|
||||||
integrity sha512-nDpWBe3ZVezukNRandTeLSPcwwTMjNVu1IDq9qA/AMiUqHuRN4BeSWvKr3eIxxg1vtiYiOLy4FqdfCP5IoP77g==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.3.1"
|
|
||||||
prop-types "^15.5.8"
|
|
||||||
|
|
||||||
react-style-singleton@^2.1.0:
|
react-style-singleton@^2.1.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66"
|
||||||
@@ -7343,10 +7333,10 @@ style-loader@1.2.1:
|
|||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
schema-utils "^2.6.6"
|
schema-utils "^2.6.6"
|
||||||
|
|
||||||
style-value-types@^3.1.9:
|
style-value-types@^4.0.1:
|
||||||
version "3.2.0"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-3.2.0.tgz#eb89cab1340823fa7876f3e289d29d99c92111bb"
|
resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-4.0.1.tgz#23f05dd03e8a850654defc22cf03ebac572aaa00"
|
||||||
integrity sha512-ih0mGsrYYmVvdDi++/66O6BaQPRPRMQHoZevNNdMMcPlP/cH28Rnfsqf1UEba/Bwfuw9T8BmIMwbGdzsPwQKrQ==
|
integrity sha512-aOV/HHyynIyTmU27qfs0oAHhFde6BFIvV4+nMerE2MAPZMwYOeQk1/F3S6djxF2u4HdbiieCPs3ZzWsbNUoc9A==
|
||||||
dependencies:
|
dependencies:
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user