Add customize icon in downloadAll (#663)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user