diff --git a/README.md b/README.md index b762532..26105f6 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@
-

Storybook Github Page

+

Storybook Demo Page

+
Click on the icon.

@@ -76,7 +77,7 @@ - Dragging and dropping text on the canvas - Adding custom web font families - Selecting the modal button and its location -- Choosing the image type (png, jpg, webp) +- Choosing the image type (png, jpg, webp, svg) - Supporting TypeScript and Next @@ -146,22 +147,24 @@ const App = () => { // If you do not include this option, the default icon will be used. iconSize="medium" - // Please select the size of the default button icon. - // If no size is specified, the default size (medium) will be applied. + // Through this property, you can specify the size of the button icon. // However, if you are inserting a custom button icon, this option is meaningless. iconPosition={[0, 20, 20, 0]} - // Please select the location of the button to open the Thumbnail Model. - // Sequence: [top, right, bottom, left] + // Through this property, you can specify the position of the button icon. + // [top, right, bottom, left] modalPosition='right' - // Please select the location to open the ThumbnailModal. + // Through this property, you can specify the position of the thumbnail generator. additionalFontFamily={['Noto Sans', ...]} // You can add the font of your choice to your project, but that font must already applied to your project. isFullWidth={true} - // Setting this property to true will make the thumbnail generator modal full width. + // Setting this property to true will make the thumbnail generator full-width. + + isDefaultOpen={false} + // Setting this property to true will open the thumbnail generator by default. /> ) @@ -301,9 +304,15 @@ const App = () => { - **Optional** - Default: `false` - Type: `boolean` +- isDefaultOpen + - **Optional** + - Default: `false` + - Type: `boolean`
## Reference - https://github.com/wormwlrm/kwakcheolyong -- https://github.com/banner-maker/banner-makers \ No newline at end of file +- https://github.com/banner-maker/banner-makers + +
\ No newline at end of file diff --git a/package.json b/package.json index a740f13..32b2793 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-thumbnail-generator", - "version": "2.8.0", + "version": "2.9.0", "description": "react-thumbnail-generator", "main": "dist/index.js", "module": "dist/index.js", diff --git a/src/components/Canvas/index.tsx b/src/components/Canvas/index.tsx index 37caec9..8194edf 100644 --- a/src/components/Canvas/index.tsx +++ b/src/components/Canvas/index.tsx @@ -122,11 +122,13 @@ const Canvas = React.forwardRef(({ canvasState }: CanvasProps, ref: any) => { const ctx = canvas.getContext('2d'); if (!ctx) return; + if (selectedImage) { if (isBlur) ctx.filter = 'blur(5px)'; ctx.drawImage(selectedImage, 0, 0); return; } + ctx.fillStyle = bgColor.hex; ctx.fillRect(0, 0, canvas.width, canvas.height); }; diff --git a/src/components/Inputs/RangeInput/index.tsx b/src/components/Inputs/RangeInput/index.tsx index 8ebf5d0..e841f1a 100644 --- a/src/components/Inputs/RangeInput/index.tsx +++ b/src/components/Inputs/RangeInput/index.tsx @@ -36,7 +36,7 @@ const RangeInput = ({ backgroundSize={backgroundSize} /> - + ); }; diff --git a/src/components/Inputs/TextInput/index.tsx b/src/components/Inputs/TextInput/index.tsx index e87b9cd..86ac407 100644 --- a/src/components/Inputs/TextInput/index.tsx +++ b/src/components/Inputs/TextInput/index.tsx @@ -16,7 +16,7 @@ const TextInput = ({ }: TextInputProps) => { return ( - + {label && } { - const LimitWidthSize = window.innerWidth; - return ( -

- - Thumbnail Generator - - - - -
- - Limit Width: {`${LimitWidthSize}px`} - + + + ); }; diff --git a/src/components/Layout/styled.tsx b/src/components/Layout/styled.tsx index 7820e17..5e948f8 100644 --- a/src/components/Layout/styled.tsx +++ b/src/components/Layout/styled.tsx @@ -3,31 +3,12 @@ import styled from 'styled-components'; export const HeaderWrapper = styled.div` display: flex; + justify-content: end; + width: 100%; position: sticky; top: 0; - flex-direction: column; - padding: 10px; - padding-bottom: 0; - background-color: #fff; - - & > div:first-child { - justify-content: space-between; - align-items: center; - display: flex; - } - - a { - color: #111111; - padding: 0; - margin: 0; - font-size: 0.875rem; - font-weight: bold; - text-decoration: none; - - &:hover { - color: #3264b5; - } - } + padding: 8px; + border-bottom: 1px solid rgb(243, 243, 243); button { cursor: pointer; @@ -38,16 +19,6 @@ export const HeaderWrapper = styled.div` } `; -export const LimitSizeText = styled.div` - font-size: 0.85rem; - margin-top: 5px; - text-align: center; - - span { - font-weight: bold; - } -`; - export const BodyWrapper = styled.section<{ modalPosition: 'left' | 'right' | 'center'; isFullWidth: boolean; @@ -62,6 +33,7 @@ export const BodyWrapper = styled.section<{ background-color: #ffffff; flex-direction: column; overflow: hidden; + font-family: Arial; * { diff --git a/src/components/TG.tsx b/src/components/TG.tsx index 0ce7023..71b6568 100644 --- a/src/components/TG.tsx +++ b/src/components/TG.tsx @@ -37,7 +37,6 @@ const TG = ({ isFullWidth, onToggle, }: TGProps) => { - const LIMIT_WIDTH = window.innerWidth; const [canvasState, setCanvasState] = useState({ value: 'Simple Thumbnail\nGenerator 😁', fontSize: '30px', @@ -98,13 +97,6 @@ const TG = ({ const replacedCallback = getReplaceCallback(name); const replacedValue = value.replace(regex, replacedCallback); - const validMessage = getValidMessage( - name === 'canvasWidth' && +replacedValue > LIMIT_WIDTH, - 'canvasSize' - ); - - if (validMessage) return alert(validMessage); - setCanvasState({ ...canvasState, [name]: replacedValue, @@ -143,12 +135,6 @@ const TG = ({ img.src = files[0] && URL.createObjectURL(files[0]); img.onload = async () => { - const validMessage = getValidMessage( - img.width > LIMIT_WIDTH, - 'imageSize' - ); - if (validMessage) return alert(validMessage); - setCanvasState({ ...canvasState, selectedImage: img, diff --git a/src/constants/select.ts b/src/constants/select.ts index 4d8c0e8..82b548f 100644 --- a/src/constants/select.ts +++ b/src/constants/select.ts @@ -8,7 +8,7 @@ export const fontFamilies = [ ]; export const strokeTypes = ['None', 'Thin', 'Normal', 'Thick']; -export const imageTypes = ['png', 'jpg', 'webp']; +export const imageTypes = ['png', 'jpg', 'svg', 'webp']; export const fontSizes = [ '10px', diff --git a/src/lib/ThumbnailGenerator.tsx b/src/lib/ThumbnailGenerator.tsx index 5eafdf7..e6ee9e6 100644 --- a/src/lib/ThumbnailGenerator.tsx +++ b/src/lib/ThumbnailGenerator.tsx @@ -8,6 +8,7 @@ import Icon from '@components/Icon'; interface ThumbnailGeneratorProps { id?: string; + isDefaultOpen?: boolean; buttonIcon?: React.ReactNode; iconSize?: 'small' | 'medium' | 'large'; position?: Position; @@ -20,13 +21,14 @@ interface ThumbnailGeneratorProps { const ThumbnailGenerator = ({ id, buttonIcon, + isDefaultOpen = false, iconSize = 'medium', iconPosition = [0, 20, 20, 0], modalPosition = 'right', isFullWidth = false, additionalFontFamily = [], }: ThumbnailGeneratorProps) => { - const [isOpen, setIsOpen] = useState(false); + const [isOpen, setIsOpen] = useState(isDefaultOpen); const tgIconSize = getIconSize(iconSize); const onToggleGenerator = () => { diff --git a/src/stories/components/ThumbnailGenerator.stories.tsx b/src/stories/components/ThumbnailGenerator.stories.tsx index d00c180..35a2b8a 100644 --- a/src/stories/components/ThumbnailGenerator.stories.tsx +++ b/src/stories/components/ThumbnailGenerator.stories.tsx @@ -43,6 +43,7 @@ const Template: Story = ({ iconPosition={iconPosition} iconSize={iconSize} isFullWidth={isFullWidth} + isDefaultOpen /> ); }; diff --git a/src/types/canvas.ts b/src/types/canvas.ts index 3e67beb..b7d091a 100644 --- a/src/types/canvas.ts +++ b/src/types/canvas.ts @@ -2,7 +2,7 @@ import { Color } from 'react-color-palette'; export type StrokeTypes = 'None' | 'Thin' | 'Normal' | 'Thick'; -export type ImageTypes = 'png' | 'jpg' | 'webp'; +export type ImageTypes = 'png' | 'jpg' | 'webp' | 'svg'; export interface CanvasState { value: string; diff --git a/src/utils/common.ts b/src/utils/common.ts index e59fb9e..e315953 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -2,23 +2,18 @@ import React from 'react'; import { ImageTypes } from '../types/canvas'; export type ValidType = 'imageSize' | 'canvasSize' | 'angle' | 'lineHeight'; + export const getValidMessage = (condition: boolean, type: ValidType) => { const message = { - imageSize: `Please register a picture smaller than "Limit Width"`, - canvasSize: `Please set the canvas width smaller than "Limit Width"`, - angle: 'Please set a value in the range of -360 to 360', - lineHeight: 'Please set a value in the range of 0 to 360', + angle: 'Please set the value to within the range', + lineHeight: 'Please set the value to within the range', } as { [key: string]: string }; if (condition) return message[type]; return ''; }; -export const downloadCanvas = ( - ref: React.RefObject, - imageType: ImageTypes -) => { - const url = ref.current?.toDataURL(`image/${imageType}`); +const download = (url: string, imageType: string) => { const link = document.createElement('a'); link.href = url as string; @@ -27,3 +22,30 @@ export const downloadCanvas = ( link.click(); document.body.removeChild(link); }; + +export const downloadCanvas = ( + ref: React.RefObject, + imageType: ImageTypes +) => { + if (ref.current) { + if (imageType === 'svg') { + const imgWidth = ref.current.width; + const imgHeight = ref.current.height; + const base64 = ref.current.toDataURL('image/png'); + const svg = ` + + + + `; + + const svgUrl = + 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg); + + download(svgUrl, 'svg'); + return; + } + + const url = ref.current.toDataURL(`image/${imageType}`); + download(url, imageType); + } +};