Skip to content

Commit

Permalink
Merge pull request #36 from ssi02014/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
ssi02014 authored May 27, 2023
2 parents ca41e43 + bb4c7bb commit 09e14e4
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 87 deletions.
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@

<br />

<h3 align="center">Storybook Github Page</h3>
<h3 align="center">Storybook Demo Page</h3>
<h5 align="center">Click on the icon.</h5>
<p align="center">
<a href="https://ssi02014.github.io/react-thumbnail-generator/?path=/story/components-thumbnailgenerator--default">
<img src="https://user-images.githubusercontent.com/64779472/220122236-c90ae4a5-8271-41df-b150-230b97991d41.png" width="120">
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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.
/>
</div>
)
Expand Down Expand Up @@ -301,9 +304,15 @@ const App = () => {
- **Optional**
- Default: `false`
- Type: `boolean`
- isDefaultOpen
- **Optional**
- Default: `false`
- Type: `boolean`

<br />

## Reference
- https://github.com/wormwlrm/kwakcheolyong
- https://github.com/banner-maker/banner-makers
- https://github.com/banner-maker/banner-makers

<br />
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 2 additions & 0 deletions src/components/Canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Inputs/RangeInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const RangeInput = ({
backgroundSize={backgroundSize}
/>
</S.InputLabelRangeContainer>
<TextInput width={60} name={name} value={value} onChange={onChange} />
<TextInput width={50} name={name} value={value} onChange={onChange} />
</S.RangeInputWrapper>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Inputs/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const TextInput = ({
}: TextInputProps) => {
return (
<S.TextInputWrapper width={width}>
<label htmlFor={name}>{label}</label>
{label && <label htmlFor={name}>{label}</label>}
<input
type="text"
name={name}
Expand Down
19 changes: 3 additions & 16 deletions src/components/Layout/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,11 @@ interface HeaderProps {
}

const Header = ({ onToggle }: HeaderProps) => {
const LimitWidthSize = window.innerWidth;

return (
<S.HeaderWrapper>
<div>
<a
href="https://github.com/ssi02014/react-thumbnail-generator"
target="_blank"
rel="noreferrer">
Thumbnail Generator
</a>
<IconButton onClick={onToggle} isBorder={false}>
<Icon src={close} width={20} height={20} />
</IconButton>
</div>
<S.LimitSizeText>
Limit Width: <span>{`${LimitWidthSize}px`}</span>
</S.LimitSizeText>
<IconButton onClick={onToggle} isBorder={false}>
<Icon src={close} width={20} height={20} />
</IconButton>
</S.HeaderWrapper>
);
};
Expand Down
38 changes: 5 additions & 33 deletions src/components/Layout/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -62,6 +33,7 @@ export const BodyWrapper = styled.section<{
background-color: #ffffff;
flex-direction: column;
overflow: hidden;
font-family: Arial;
* {
Expand Down
14 changes: 0 additions & 14 deletions src/components/TG.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const TG = ({
isFullWidth,
onToggle,
}: TGProps) => {
const LIMIT_WIDTH = window.innerWidth;
const [canvasState, setCanvasState] = useState<CanvasState>({
value: 'Simple Thumbnail\nGenerator 😁',
fontSize: '30px',
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/constants/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
4 changes: 3 additions & 1 deletion src/lib/ThumbnailGenerator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Icon from '@components/Icon';

interface ThumbnailGeneratorProps {
id?: string;
isDefaultOpen?: boolean;
buttonIcon?: React.ReactNode;
iconSize?: 'small' | 'medium' | 'large';
position?: Position;
Expand All @@ -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 = () => {
Expand Down
1 change: 1 addition & 0 deletions src/stories/components/ThumbnailGenerator.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const Template: Story = ({
iconPosition={iconPosition}
iconSize={iconSize}
isFullWidth={isFullWidth}
isDefaultOpen
/>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/types/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
40 changes: 31 additions & 9 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLCanvasElement>,
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;
Expand All @@ -27,3 +22,30 @@ export const downloadCanvas = (
link.click();
document.body.removeChild(link);
};

export const downloadCanvas = (
ref: React.RefObject<HTMLCanvasElement>,
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 = `
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${imgWidth}" height="${imgHeight}">
<image xlink:href="${base64}" width="${imgWidth}" height="${imgHeight}" />
</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);
}
};

0 comments on commit 09e14e4

Please sign in to comment.