diff --git a/package-lock.json b/package-lock.json
index 08a26c9..2bff11e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
+ "@hugocxl/react-to-image": "^0.0.9",
"@tanstack/react-query": "^5.51.11",
"axios": "^1.7.2",
"framer-motion": "^11.3.8",
@@ -1794,6 +1795,16 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@hugocxl/react-to-image": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/@hugocxl/react-to-image/-/react-to-image-0.0.9.tgz",
+ "integrity": "sha512-UzPtjPb5k0V8oPKjmDvYnWtTNCuFh+2ysXF4+dXL0tnEaFDfu2M3iSt32pzKbJsZYoFu5X12JKKd9MKa2OsR6g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "html-to-image": ">=1",
+ "react": ">=16"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -4848,6 +4859,13 @@
"react-is": "^16.7.0"
}
},
+ "node_modules/html-to-image": {
+ "version": "1.11.11",
+ "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.11.tgz",
+ "integrity": "sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/human-signals": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
diff --git a/package.json b/package.json
index fca1453..3586a2d 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
+ "@hugocxl/react-to-image": "^0.0.9",
"@tanstack/react-query": "^5.51.11",
"axios": "^1.7.2",
"framer-motion": "^11.3.8",
diff --git a/public/bg1.jpg b/public/bg1.jpg
new file mode 100644
index 0000000..534d947
Binary files /dev/null and b/public/bg1.jpg differ
diff --git a/public/bg2.jpg b/public/bg2.jpg
new file mode 100644
index 0000000..4f86b87
Binary files /dev/null and b/public/bg2.jpg differ
diff --git a/public/bg3.jpg b/public/bg3.jpg
new file mode 100644
index 0000000..1215149
Binary files /dev/null and b/public/bg3.jpg differ
diff --git a/public/bg4.jpg b/public/bg4.jpg
new file mode 100644
index 0000000..0549876
Binary files /dev/null and b/public/bg4.jpg differ
diff --git a/src/app/letter/@create/page.tsx b/src/app/letter/@create/page.tsx
index 0704b1b..2266abf 100644
--- a/src/app/letter/@create/page.tsx
+++ b/src/app/letter/@create/page.tsx
@@ -23,13 +23,19 @@ import { useSourceStore } from '../letter-source-store';
import { useLetterStore } from '../letter-store';
import { ChevronLeftIcon, ChevronRightIcon } from '@chakra-ui/icons';
import { useState, useRef } from 'react';
+import { useLetterFlowStore } from '../letter-flow-store';
const Page = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const cancelRef = useRef(null);
const { source } = useSourceStore();
- const { letter } = useLetterStore();
- const [currentLetterIdx, setCurrentLetterIdx] = useState(0);
+ const {
+ letter,
+ currentLetterIndex,
+ increaseCurrentLetterIndex,
+ decreaseCurrentLetterIndex,
+ } = useLetterStore();
+ const { setState } = useLetterFlowStore();
// TODO : 저장 개수 + 현재 불러올 수 있는 편지 개수 받아와야 함.
const DUMMYSAVECOUNT = 2;
const DUMMYLOADCOUNT = 3;
@@ -50,7 +56,11 @@ const Page = () => {
- } />
+ }
+ />
{
- } />
+ }
+ />
From.
@@ -71,7 +85,7 @@ const Page = () => {
-
+
{
+ const { isOpen, onOpen, onClose } = useDisclosure();
+ const openButtonRef = useRef(null);
+ const { setState } = useLetterFlowStore();
+ const { letter, currentLetterIndex } = useLetterStore();
+ const [imageSrc, setImageSrc] = useState();
+ const [{ status, isLoading }, convertToImage, ref] = useToPng(
+ {
+ onStart: () => {
+ console.log('onStart');
+ },
+ onSuccess: (data) => {
+ setImageSrc(data);
+ },
+ onError: (error) => {
+ console.error(error);
+ },
+ }
+ );
+
+ const [fontWeight, setFontWeight] = useState('normal');
+ const [fontSize, setFontSize] = useState(16);
+ const [date, setDate] = useState(
+ new Date().toISOString().split('T')[0].split('-').join('-')
+ );
+ const [showDate, setShowDate] = useState(false);
+ const [bgImage, setBgImage] = useState('bg1');
+
+ return (
+ <>
+
+ {/* 편지 이미지 컴포넌트 */}
+
+ {letter[currentLetterIndex].title}
+ {`To. ${letter[currentLetterIndex].to}`}
+
+ {letter[currentLetterIndex].body.split('\n').map((line, index) => (
+
+ {line}
+
+ ))}
+
+
+ {`From. ${letter[currentLetterIndex].from}`}
+ {showDate && {`Date. ${date}`}}
+
+
+
+
+
+
+
+ }
+ />
+
+
+
+
+
+
+ 텍스트
+
+ {
+ setFontSize(valueAsNumber);
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ 텍스트
+ {
+ setShowDate(!showDate);
+ }}
+ >
+ 날짜 표시하기
+
+ {
+ setDate(event.target.value);
+ }}
+ />
+
+
+ 편지지
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default Page;
diff --git a/src/app/letter/layout.tsx b/src/app/letter/layout.tsx
index d859273..718f077 100644
--- a/src/app/letter/layout.tsx
+++ b/src/app/letter/layout.tsx
@@ -7,9 +7,10 @@ type LayoutProps = {
children: ReactNode; // 기본 페이지
initial: ReactNode; // 초기 페이지
create: ReactNode; // 편지 쓰기 페이지
+ decorate: ReactNode; // 편지 꾸미기 페이지
};
-const Layout = ({ children, initial, create }: LayoutProps) => {
+const Layout = ({ children, initial, create, decorate }: LayoutProps) => {
const { state } = useLetterFlowStore();
if (state === 'initial') {
return <>{initial}>;
@@ -17,6 +18,10 @@ const Layout = ({ children, initial, create }: LayoutProps) => {
if (state === 'create') {
return <>{create}>;
}
+ if (state === 'decorate') {
+ return <>{decorate}>;
+ }
+
return <>{children}>;
};
diff --git a/src/app/letter/letter-store.ts b/src/app/letter/letter-store.ts
index dd0a36c..4c163c3 100644
--- a/src/app/letter/letter-store.ts
+++ b/src/app/letter/letter-store.ts
@@ -9,13 +9,37 @@ export type LetterData = {
type LetterStore = {
letter: LetterData[];
+ currentLetterIndex: number;
addNewLetter: (letter: LetterData) => void;
+ decreaseCurrentLetterIndex: () => void;
+ increaseCurrentLetterIndex: () => void;
};
-const defaultState: LetterData[] = [];
+const defaultState: LetterData[] = [
+ {
+ title: '임시 저장',
+ to: '개발팀',
+ from: '기획팀',
+ body: '사전 질문의 답변으로 사용자 문체를 파악하고 아키네이터가 질문지 답변을 바탕으로 내용을 구성하여 편지 1을 보여줍니다. 그리고 사용자가 후속으로 직접 수정할 수 있으며 완성된 편지는 사용자 데이터로 남아 기존의 사용자 데이터 + 아카이빙 데이터 형식으로 누적됩니다.',
+ },
+];
+const defaultIndex = 0;
export const useLetterStore = create((set) => ({
letter: defaultState,
+ currentLetterIndex: defaultIndex,
addNewLetter: (letter) =>
set((state) => ({ letter: [...state.letter, letter] })),
+ decreaseCurrentLetterIndex: () =>
+ set((state) => ({
+ currentLetterIndex:
+ state.currentLetterIndex - 1 > 0 ? state.currentLetterIndex - 1 : 0,
+ })),
+ increaseCurrentLetterIndex: () =>
+ set((state) => ({
+ currentLetterIndex:
+ state.currentLetterIndex + 1 < state.letter.length
+ ? state.currentLetterIndex + 1
+ : state.letter.length - 1,
+ })),
}));