Skip to content

Commit

Permalink
reafactor : 작성 로직 리펙토링 및 스타일 수정 (#200)
Browse files Browse the repository at this point in the history
* refactor : 편지 작성 로직 수정

* refacotor : 데이터 흐름에 따라 컴포넌트 수정

* feat : uselocalstorage hook 개발

* feat : 편지 정보 로컬 스토리지 저장

* chore : 슬라이더 수정

* chore : nofication badge 수정

* chore : 사용하지 않는 마진 삭제
  • Loading branch information
HelloWook authored Dec 3, 2024
1 parent b674ab4 commit 40f74d0
Show file tree
Hide file tree
Showing 16 changed files with 1,677 additions and 1,590 deletions.
2,776 changes: 1,388 additions & 1,388 deletions .pnp.cjs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions public/to_line.f4c129e6.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/편지지_샘플_6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/Common/ItemSlider/ItemSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const ItemSlider = ({
case 'text':
return (
<div
className="flex items-center justify-center h-full p-2 cursor-pointer"
className="flex items-center justify-center h-full p-2 cursor-pointer "
onClick={() => {
setValue(item.name);
}} // 아이템 클릭 시 setValue 호출
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface SliderMenuContainerProps {
blocking?: boolean;
useDefaultSnap?: boolean;
children: ReactNode;
header?: ReactNode;
}

export const SliderMenuContainer = ({
Expand All @@ -17,7 +18,8 @@ export const SliderMenuContainer = ({
onDismiss,
blocking = false,
useDefaultSnap = false,
children
children,
header
}: SliderMenuContainerProps) => {
return (
<BottomSheet
Expand All @@ -28,12 +30,13 @@ export const SliderMenuContainer = ({
useDefaultSnap ? ({ snapPoints }) => snapPoints[0] : undefined
}
blocking={blocking} // true면 배경 클릭 불가
className="z-[1000]" // z-index 추가
className="z-[999]" // z-index 추가
style={
{
'--rsbs-z-index': '1000'
'--rsbs-z-index': '999'
} as React.CSSProperties
}
header={header}
>
{children}
</BottomSheet>
Expand Down
70 changes: 52 additions & 18 deletions src/components/Common/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { useRef, useEffect, useState } from 'react';
import { Margin } from '../Margin/Margin';
import { useToastStore } from '@/hooks/useToastStore';

type TextAreaProps = {
value: string;
Expand All @@ -7,9 +9,11 @@ type TextAreaProps = {
};

export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
const [lineHeight, setLineHeight] = useState<number>(2.5);
const [lineHeight, setLineHeight] = useState<number>(2.2);
const [lineCount, setLineCount] = useState<number>(8);
const textAreaRef = useRef<HTMLTextAreaElement>(null);

const { addToast } = useToastStore();
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
let inputValue = e.target.value;

Expand All @@ -19,31 +23,50 @@ export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
window.getComputedStyle(textAreaRef.current).lineHeight
);

const linesCount = Math.floor(textAreaHeight / textAreaLineHeight);

if (linesCount > 8) {
inputValue = value;
const calculatedLinesCount = Math.floor(
textAreaHeight / textAreaLineHeight
);
if (calculatedLinesCount > 20) {
addToast('최대 20줄까지 작성 가능합니다.', 'error');
return;
}
}

const lines = inputValue.split('\n');
if (lines.length <= 8) {
setValue(inputValue);
setLineCount(calculatedLinesCount);
}

setValue(inputValue);
};

useEffect(() => {
if (textAreaRef.current) {
textAreaRef.current.style.height = 'auto';
textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`;
// 텍스트가 변경될 때 lineCount 계산
const textAreaLineHeight = parseInt(
window.getComputedStyle(textAreaRef.current).lineHeight
);
const textAreaHeight = textAreaRef.current.scrollHeight;
const calculatedLinesCount = Math.floor(
textAreaHeight / textAreaLineHeight
);
setLineCount(calculatedLinesCount); // 라인 수 업데이트
}
}, [value]);

const renderLineImages = () => {
return Array.from({ length: lineCount }).map((_, index) => (
<React.Fragment key={index}>
<img src={'/public/to_line.f4c129e6.svg'} className="w-full" />
<Margin top={28} />
</React.Fragment>
));
};

useEffect(() => {
const handleResize = () => {
if (textAreaRef.current) {
setLineHeight(
2.5 + (textAreaRef.current.offsetWidth - 281) * 0.01
2.2 + (textAreaRef.current.offsetWidth - 281) * 0.002
);
}
};
Expand All @@ -53,14 +76,25 @@ export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
return () => window.removeEventListener('resize', handleResize);
}, []);

useEffect(() => {});

return (
<textarea
className="absolute w-9/12 px-2 bg-transparent border-none resize-none mt-[43%] overflow-hidden h-auto"
style={{ fontFamily: font || 'inherit', lineHeight: lineHeight }}
ref={textAreaRef}
placeholder="편지를 작성하세요..."
value={value}
onChange={handleInputChange}
/>
<div>
<textarea
className="w-full m-auto overflow-hidden bg-transparent border-none resize-none min-h-[413px] min-w-[281px]"
style={{
fontFamily: font || 'inherit',
lineHeight: lineHeight
}}
ref={textAreaRef}
placeholder="편지를 작성하세요..."
value={value}
onChange={handleInputChange}
/>

<div className="absolute top-0 w-full mt-[30px]">
{renderLineImages()}
</div>
</div>
);
};
Empty file.
4 changes: 2 additions & 2 deletions src/components/HomePage/LetterContainer/LetterContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ export const LetterContainer = () => {

return (
<div className="relative">
<div className="absolute right-[20px] z-30">
<div className="absolute right-[20px] z-1">
<NotificationBadge badgeType="basic" count={letters.length} />
</div>
<div className="overflow-hidden mx-[-20px] mt-[50px]">
<Swiper
effect={'cards'}
grabCursor={true}
modules={[EffectCards]}
className="mySwiper object-cover"
className="object-cover mySwiper"
>
{letters.map((letter, i) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/Letter/CreateButton/CreateButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const CreateButton = ({
<div className="flex items-center justify-center ">
<button
onClick={handleClick}
className={`border m-auto text-xl w-[330px] h-[51px] rounded-3xl bottom-24 ${
className={`border m-auto text-xl w-[95%] h-[51px] rounded-3xl bottom-24 ${
isActive
? 'bg-slate-500 text-white'
: 'bg-slate-200 text-black'
Expand Down
36 changes: 0 additions & 36 deletions src/components/Letter/Post/PostLetterForm.stories.tsx

This file was deleted.

133 changes: 61 additions & 72 deletions src/components/Letter/Post/PostLetterForm.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,80 @@
import { ItemSlider } from '@/components/Common/ItemSlider/ItemSlider';
import React from 'react';
import { Margin } from '@/components/Common/Margin/Margin';
import { SliderMenuContainer } from '@/components/Common/SliderMenuContainer/SliderMenuContainer';
import { TextArea } from '@/components/Common/TextArea/TextArea';
import { Toggle } from '@/components/Common/Toggle/Toggle';
import { useState } from 'react';
import { SelectSlider } from '../SelectSlier/SelectSlider';
import { useToastStore } from '@/hooks/useToastStore';
import { TextArea } from '@/components/Common/TextArea/TextArea';
import { TopBar } from '@/components/Common/TopBar/TopBar';
import { useNavigate } from 'react-router-dom';
import { useLocalStorage } from '@/hooks/useLocalStorage';

export const PostLetterForm = () => {
const [title, setTtile] = useState('');
const [content, setContent] = useState('');
const [isFont, setIsFont] = useState(true);
const [letter, setLetter] = useState('편지지_샘플_1');
const [font, setFont] = useState('');
const [title, setTitle] = useState<string>('');
const [letter, setLetter] = useState<string>('편지지_샘플_1');
const [letterContent, setLetterContent] = useState<string>('');
const [font, setFont] = useState<string>('initial');

const { addToast } = useToastStore();
const navigate = useNavigate();

const textItems = [
{ name: 'cursive', id: '1' },
{ name: 'fantasy', id: '2' },
{ name: 'initial', id: '3' },
{ name: 'monospace', id: '4' }
];
const { setValue: saveTitle } = useLocalStorage('title', '');
const { setValue: saveLetterContent } = useLocalStorage(
'letterContent',
''
);
const { setValue: saveFont } = useLocalStorage('font', '');
const { setValue: saveLetter } = useLocalStorage('letter', '');

const imageItems = [
{ id: '편지지_샘플_1', name: '이미지' },
{ id: '편지지_샘플_2', name: '이미지' },
{ id: '편지지_샘플_3', name: '이미지' },
{ id: '편지지_샘플_4', name: '이미지' },
{ id: '편지지_샘플_5', name: '이미지' }
];
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
if (inputValue.length > 100) {
addToast('제목은 100자 이상 쓸 수 없습니다.', 'warning');
} else {
setTitle(inputValue);
}
};

return (
<SliderMenuContainer
snapPoints={() => [
window.innerHeight * 0.05,
window.innerHeight * 0.6
]}
>
<Margin top={18} />
<div>
<div className="relative flex justify-center">
<>
<TopBar
handleBackClick={() => {
navigate(-1);
}}
handelSuccesClick={() => {
saveTitle(title);
saveLetterContent(letterContent);
saveFont(font);
saveLetter(letter);
navigate('/letter/select');
}}
/>
<div className="min-h-screen rounded-t-3xl bg-zinc-300">
<Margin top={20} />
<div className="relative flex flex-col justify-center w-9/12 m-auto py-14">
<input
onChange={(e) => setTtile(e.target.value)}
onChange={handleChange}
value={title}
type="text"
placeholder="제목을 입력해주세요"
className="absolute mt-[35%] w-9/12 bg-transparent px-2 focus:border-none focus:outline-none border-none "
/>
<TextArea
value={content}
setValue={setContent}
font={font}
className="z-10 w-full bg-transparent border-none focus:border-none focus:outline-none text-wrap"
/>
</div>
<img src={'/public/to_line.f4c129e6.svg'} />

<img
src={`/public/${letter}.png`}
className="w-full h-full rounded-lg "
alt="샘플 편지지"
/>

<div className="flex flex-col items-center justify-center aling bottom-9 ">
<Margin bottom={14} />
{isFont ? (
<ItemSlider
itemType="text"
itemIDList={textItems}
value={font}
setValue={setFont}
/>
) : (
<ItemSlider
itemType="image"
itemIDList={imageItems}
width="77px"
height="99px"
value={letter}
setValue={setLetter}
<div className="relative z-10">
<TextArea
value={letterContent}
setValue={setLetterContent}
font={font}
/>
)}
<Margin bottom={14} />
<Toggle
isChecked={isFont}
onToggle={() => setIsFont(!isFont)}
leftLabel="글씨체"
rightLabel="편지지"
/>
<Margin bottom={30} />
</div>
</div>
<SelectSlider
font={font}
letter={letter}
setFont={setFont}
setLetter={setLetter}
/>
</div>
</SliderMenuContainer>
</>
);
};
Loading

0 comments on commit 40f74d0

Please sign in to comment.