Skip to content

Commit f2b77b1

Browse files
committed
feat: svg download
1 parent c312aa1 commit f2b77b1

File tree

6 files changed

+39
-70
lines changed

6 files changed

+39
-70
lines changed

src/components/Layout/Header/index.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,11 @@ interface HeaderProps {
99
}
1010

1111
const Header = ({ onToggle }: HeaderProps) => {
12-
const LimitWidthSize = window.innerWidth;
13-
1412
return (
1513
<S.HeaderWrapper>
16-
<div>
17-
<a
18-
href="https://github.com/ssi02014/react-thumbnail-generator"
19-
target="_blank"
20-
rel="noreferrer">
21-
Thumbnail Generator
22-
</a>
23-
<IconButton onClick={onToggle} isBorder={false}>
24-
<Icon src={close} width={20} height={20} />
25-
</IconButton>
26-
</div>
27-
<S.LimitSizeText>
28-
Limit Width: <span>{`${LimitWidthSize}px`}</span>
29-
</S.LimitSizeText>
14+
<IconButton onClick={onToggle} isBorder={false}>
15+
<Icon src={close} width={20} height={20} />
16+
</IconButton>
3017
</S.HeaderWrapper>
3118
);
3219
};

src/components/Layout/styled.tsx

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,12 @@ import styled from 'styled-components';
33

44
export const HeaderWrapper = styled.div`
55
display: flex;
6+
justify-content: end;
7+
width: 100%;
68
position: sticky;
79
top: 0;
8-
flex-direction: column;
9-
padding: 10px;
10-
padding-bottom: 0;
11-
background-color: #fff;
12-
13-
& > div:first-child {
14-
justify-content: space-between;
15-
align-items: center;
16-
display: flex;
17-
}
18-
19-
a {
20-
color: #111111;
21-
padding: 0;
22-
margin: 0;
23-
font-size: 0.875rem;
24-
font-weight: bold;
25-
text-decoration: none;
26-
27-
&:hover {
28-
color: #3264b5;
29-
}
30-
}
10+
padding: 8px;
11+
border-bottom: 1px solid rgb(243, 243, 243);
3112
3213
button {
3314
cursor: pointer;
@@ -38,16 +19,6 @@ export const HeaderWrapper = styled.div`
3819
}
3920
`;
4021

41-
export const LimitSizeText = styled.div`
42-
font-size: 0.85rem;
43-
margin-top: 5px;
44-
text-align: center;
45-
46-
span {
47-
font-weight: bold;
48-
}
49-
`;
50-
5122
export const BodyWrapper = styled.section<{
5223
modalPosition: 'left' | 'right' | 'center';
5324
isFullWidth: boolean;
@@ -62,6 +33,7 @@ export const BodyWrapper = styled.section<{
6233
background-color: #ffffff;
6334
flex-direction: column;
6435
overflow: hidden;
36+
6537
font-family: Arial;
6638
6739
* {

src/components/TG.tsx

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ const TG = ({
3737
isFullWidth,
3838
onToggle,
3939
}: TGProps) => {
40-
const LIMIT_WIDTH = window.innerWidth;
4140
const [canvasState, setCanvasState] = useState<CanvasState>({
4241
value: 'Simple Thumbnail\nGenerator 😁',
4342
fontSize: '30px',
@@ -98,13 +97,6 @@ const TG = ({
9897
const replacedCallback = getReplaceCallback(name);
9998
const replacedValue = value.replace(regex, replacedCallback);
10099

101-
const validMessage = getValidMessage(
102-
name === 'canvasWidth' && +replacedValue > LIMIT_WIDTH,
103-
'canvasSize'
104-
);
105-
106-
if (validMessage) return alert(validMessage);
107-
108100
setCanvasState({
109101
...canvasState,
110102
[name]: replacedValue,
@@ -143,12 +135,6 @@ const TG = ({
143135

144136
img.src = files[0] && URL.createObjectURL(files[0]);
145137
img.onload = async () => {
146-
const validMessage = getValidMessage(
147-
img.width > LIMIT_WIDTH,
148-
'imageSize'
149-
);
150-
if (validMessage) return alert(validMessage);
151-
152138
setCanvasState({
153139
...canvasState,
154140
selectedImage: img,

src/constants/select.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const fontFamilies = [
88
];
99
export const strokeTypes = ['None', 'Thin', 'Normal', 'Thick'];
1010

11-
export const imageTypes = ['png', 'jpg', 'webp'];
11+
export const imageTypes = ['png', 'jpg', 'svg', 'webp'];
1212

1313
export const fontSizes = [
1414
'10px',

src/types/canvas.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Color } from 'react-color-palette';
22

33
export type StrokeTypes = 'None' | 'Thin' | 'Normal' | 'Thick';
44

5-
export type ImageTypes = 'png' | 'jpg' | 'webp';
5+
export type ImageTypes = 'png' | 'jpg' | 'webp' | 'svg';
66

77
export interface CanvasState {
88
value: string;

src/utils/common.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { ImageTypes } from '../types/canvas';
33

44
export type ValidType = 'imageSize' | 'canvasSize' | 'angle' | 'lineHeight';
5+
56
export const getValidMessage = (condition: boolean, type: ValidType) => {
67
const message = {
78
imageSize: `Please register a picture smaller than "Limit Width"`,
@@ -14,11 +15,7 @@ export const getValidMessage = (condition: boolean, type: ValidType) => {
1415
return '';
1516
};
1617

17-
export const downloadCanvas = (
18-
ref: React.RefObject<HTMLCanvasElement>,
19-
imageType: ImageTypes
20-
) => {
21-
const url = ref.current?.toDataURL(`image/${imageType}`);
18+
const download = (url: string, imageType: string) => {
2219
const link = document.createElement('a');
2320

2421
link.href = url as string;
@@ -27,3 +24,30 @@ export const downloadCanvas = (
2724
link.click();
2825
document.body.removeChild(link);
2926
};
27+
28+
export const downloadCanvas = (
29+
ref: React.RefObject<HTMLCanvasElement>,
30+
imageType: ImageTypes
31+
) => {
32+
if (ref.current) {
33+
if (imageType === 'svg') {
34+
const imgWidth = ref.current.width;
35+
const imgHeight = ref.current.height;
36+
const base64 = ref.current.toDataURL('image/png');
37+
const svg = `
38+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${imgWidth}" height="${imgHeight}">
39+
<image xlink:href="${base64}" width="${imgWidth}" height="${imgHeight}" />
40+
</svg>
41+
`;
42+
43+
const svgUrl =
44+
'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg);
45+
46+
download(svgUrl, 'svg');
47+
return;
48+
}
49+
50+
const url = ref.current.toDataURL(`image/${imageType}`);
51+
download(url, imageType);
52+
}
53+
};

0 commit comments

Comments
 (0)