Add customize icon in downloadAll (#663)

This commit is contained in:
Eric Fennis
2022-05-14 20:43:15 +02:00
committed by GitHub
parent f3a1bba31d
commit 38c834bcda
4 changed files with 88 additions and 34 deletions
+32 -11
View File
@@ -1,4 +1,6 @@
import { createContext, useState } from 'react';
import { createContext, useRef, useState, MutableRefObject, useContext, useMemo } from 'react';
type IconsRef = Record<string, SVGSVGElement>;
interface ICustomIconStyle {
color: string;
@@ -8,13 +10,14 @@ interface ICustomIconStyle {
size: number;
setSize: (n: number) => void;
resetStyle: () => void;
iconsRef: MutableRefObject<IconsRef>;
}
const DEFAULT_STYLE = {
color: 'currentColor',
strokeWidth: 2,
size: 24,
}
};
export const IconStyleContext = createContext<ICustomIconStyle>({
color: 'currentColor',
@@ -23,25 +26,43 @@ export const IconStyleContext = createContext<ICustomIconStyle>({
setStroke: (n: number) => null,
size: 24,
setSize: (n: number) => null,
resetStyle: () => null
resetStyle: () => null,
iconsRef: { current: {} },
});
export function CustomizeIconContext({ children }) {
export function CustomizeIconContext({ children }): JSX.Element {
const iconsRef = useRef<IconsRef>({});
const [color, setColor] = useState(DEFAULT_STYLE.color);
const [stroke, setStroke] = useState(DEFAULT_STYLE.strokeWidth);
const [size, setSize] = useState(DEFAULT_STYLE.size);
function resetStyle(){
function resetStyle() {
setColor(DEFAULT_STYLE.color);
setStroke(DEFAULT_STYLE.strokeWidth);
setSize(DEFAULT_STYLE.size);
}
return (
<IconStyleContext.Provider
value={{ color, setColor, strokeWidth: stroke, setStroke, size, setSize, resetStyle }}
>
{children}
</IconStyleContext.Provider>
const value = useMemo(
() => ({
color,
setColor,
strokeWidth: stroke,
setStroke,
size,
setSize,
resetStyle,
iconsRef,
}),
[color, setColor, stroke, setStroke, size, setSize, resetStyle, iconsRef],
);
return <IconStyleContext.Provider value={value}>{children}</IconStyleContext.Provider>;
}
export function useCustomizeIconContext(): ICustomIconStyle {
const context = useContext(IconStyleContext);
if (context === undefined) {
throw new Error('useCustomizeIconContext must be used within a IconStyleContextProvider');
}
return context;
}
+43 -8
View File
@@ -13,20 +13,49 @@ import AngularLogo from '../../public/framework-logos/angular.svg';
import FlutterLogo from '../../public/framework-logos/flutter.svg';
import SvelteLogo from '../../public/framework-logos/svelte.svg';
import LaravelLogo from '../../public/framework-logos/laravel.svg';
import { useState } from 'react';
import { useCustomizeIconContext } from './CustomizeIconContext';
import { IconEntity } from '../types';
function generateZip(icons) {
type IconContent = [icon: string, src:string]
async function generateZip(icons: IconContent[]) {
const zip = new JSZip();
Object.values(icons).forEach(icon =>
// @ts-ignore
zip.file(`${icon.name}.svg`, icon.src),
const addingZipPromises = icons.map(([name, src]) =>
zip.file(`${name}.svg`, src),
);
await Promise.all(addingZipPromises)
return zip.generateAsync({ type: 'blob' });
}
const Header = ({ data }) => {
interface HeaderProps {
data: IconEntity[];
}
const Header = ({ data }: HeaderProps) => {
const [zippingIcons, setZippingIcons] = useState(false);
const { iconsRef } = useCustomizeIconContext();
const downloadAllIcons = async () => {
const zip = await generateZip(data);
console.log(iconsRef);
setZippingIcons(true);
let iconEntries: IconContent[] = Object.entries(iconsRef.current).map(([name, svgEl]) => [
name,
svgEl.outerHTML,
]);
// Fallback
if (iconEntries.length === 0) {
iconEntries = data.map(icon => [icon.name, icon.src]);
}
const zip = await generateZip(iconEntries);
download(zip, 'lucide.zip');
setZippingIcons(false);
};
const repositoryUrl = 'https://github.com/lucide-icons/lucide';
@@ -76,7 +105,7 @@ const Header = ({ data }) => {
name: 'lucide-laravel',
Logo: LaravelLogo,
href: 'https://github.com/mallardduck/blade-lucide-icons',
}
},
];
return (
@@ -124,7 +153,13 @@ const Header = ({ data }) => {
</Wrap>
<Wrap marginTop={3} marginBottom={12} spacing="15px" justify="center">
<WrapItem>
<Button leftIcon={<Download />} size="lg" onClick={downloadAllIcons}>
<Button
leftIcon={<Download />}
size="lg"
onClick={downloadAllIcons}
isLoading={zippingIcons}
loadingText="Creating zip.."
>
Download all
</Button>
</WrapItem>
+7 -5
View File
@@ -1,8 +1,8 @@
import { Box, Button, ButtonProps, Flex, Text, useToast } from '@chakra-ui/react';
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 { memo } from 'react';
import { useCustomizeIconContext } from './CustomizeIconContext';
import { IconWrapper } from './IconWrapper';
interface IconListItemProps {
@@ -13,9 +13,9 @@ interface IconListItemProps {
onClick?: ButtonProps['onClick'];
}
const IconListItem = ({ name, content, src, onClick }: IconListItemProps) => {
const IconListItem = ({ name, content, onClick, src: svg }: IconListItemProps) => {
const toast = useToast();
const { color, size, strokeWidth } = useContext(IconStyleContext);
const { color, size, strokeWidth, iconsRef } = useCustomizeIconContext();
return (
<Button
@@ -27,6 +27,7 @@ const IconListItem = ({ name, content, src, onClick }: IconListItemProps) => {
position="relative"
whiteSpace="normal"
onClick={event => {
const src = iconsRef.current[name].outerHTML ?? svg
if (event.shiftKey) {
copy(src);
toast({
@@ -54,6 +55,7 @@ const IconListItem = ({ name, content, src, onClick }: IconListItemProps) => {
strokeWidth={strokeWidth}
height={size}
width={size}
ref={iconEl => (iconsRef.current[name] = iconEl)}
/>
</Flex>
<Flex flex={1} minHeight={10} align="center">
+6 -10
View File
@@ -4,7 +4,7 @@ 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';
import { useMemo } from 'react';
const IconPage = ({ icon, data }) => {
const router = useRouter();
@@ -30,19 +30,15 @@ const IconPage = ({ icon, data }) => {
};
const currentIcon = useMemo(() => {
if(icon.name === router.query.iconName) {
return icon
if (icon.name === router.query.iconName) {
return icon;
}
return getIcon(router.query.iconName)
}, [router.query])
return getIcon(router.query.iconName);
}, [router.query]);
return (
<Layout>
<IconDetailOverlay
key={currentIcon.name}
icon={currentIcon}
close={onClose}
/>
<IconDetailOverlay key={currentIcon.name} icon={currentIcon} close={onClose} />
<Header {...{ data }} />
<IconOverview {...{ data }} />
</Layout>