diff --git a/public/fonts/eunyoung.woff2 b/public/fonts/eunyoung.woff2 new file mode 100644 index 0000000..8c87701 Binary files /dev/null and b/public/fonts/eunyoung.woff2 differ diff --git a/public/fonts/hipi.ttf b/public/fonts/hipi.ttf new file mode 100644 index 0000000..3f1e49a Binary files /dev/null and b/public/fonts/hipi.ttf differ diff --git a/public/fonts/ttaerom.ttf b/public/fonts/ttaerom.ttf new file mode 100644 index 0000000..a5e1ca9 Binary files /dev/null and b/public/fonts/ttaerom.ttf differ diff --git a/public/images/polaroidThemas/F-0.png b/public/images/polaroidThemas/F-0.png new file mode 100644 index 0000000..022943a Binary files /dev/null and b/public/images/polaroidThemas/F-0.png differ diff --git a/public/images/polaroidThemas/F-1.png b/public/images/polaroidThemas/F-1.png new file mode 100644 index 0000000..67618c5 Binary files /dev/null and b/public/images/polaroidThemas/F-1.png differ diff --git a/public/images/polaroidThemas/F-2.png b/public/images/polaroidThemas/F-2.png new file mode 100644 index 0000000..cb461a8 Binary files /dev/null and b/public/images/polaroidThemas/F-2.png differ diff --git a/public/images/polaroidThemas/F-3.png b/public/images/polaroidThemas/F-3.png new file mode 100644 index 0000000..ce824d4 Binary files /dev/null and b/public/images/polaroidThemas/F-3.png differ diff --git a/public/images/polaroidThemas/F-4.png b/public/images/polaroidThemas/F-4.png new file mode 100644 index 0000000..7cd852f Binary files /dev/null and b/public/images/polaroidThemas/F-4.png differ diff --git a/public/images/polaroidThemas/F-5.png b/public/images/polaroidThemas/F-5.png new file mode 100644 index 0000000..7bfd1c6 Binary files /dev/null and b/public/images/polaroidThemas/F-5.png differ diff --git a/public/images/polaroidThemas/F-6.png b/public/images/polaroidThemas/F-6.png new file mode 100644 index 0000000..2fc09ed Binary files /dev/null and b/public/images/polaroidThemas/F-6.png differ diff --git a/public/images/polaroidThemas/F-7.png b/public/images/polaroidThemas/F-7.png new file mode 100644 index 0000000..24dbdf8 Binary files /dev/null and b/public/images/polaroidThemas/F-7.png differ diff --git a/public/images/polaroidThemas/F-8.png b/public/images/polaroidThemas/F-8.png new file mode 100644 index 0000000..9a1bb3b Binary files /dev/null and b/public/images/polaroidThemas/F-8.png differ diff --git a/src/app/board/[boardId]/_actions/uploadAction.ts b/src/app/board/[boardId]/_actions/uploadAction.ts index 7dd11dd..fd9aa54 100644 --- a/src/app/board/[boardId]/_actions/uploadAction.ts +++ b/src/app/board/[boardId]/_actions/uploadAction.ts @@ -1,12 +1,15 @@ 'use server' import { getPreSignedUrl, postPolaroid, uploadImage } from '@/lib' +import { FontKeyType, ThemaKeyType } from '@/types' export const uploadAction = async (id: string, formData: FormData) => { try { const fileInput = formData.get('fileInput') const oneLineMessage = formData.get('oneLineMessage') const nickname = formData.get('nickname') + const font = formData.get('font') + const thema = formData.get('thema') if (!fileInput || !(fileInput instanceof File)) { throw new Error('Invalid file input') @@ -20,6 +23,10 @@ export const uploadAction = async (id: string, formData: FormData) => { imageKey, oneLineMessage: oneLineMessage as string, nickname: nickname as string, + options: { + FONT: font as FontKeyType, + THEMA: thema as ThemaKeyType, + }, }) return res } catch (error) { diff --git a/src/app/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx b/src/app/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx index aef9b45..af66867 100644 --- a/src/app/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx +++ b/src/app/board/[boardId]/_components/CreatePolaroidModal/ArrowBack.tsx @@ -11,7 +11,7 @@ const ArrowBack = () => { return ( <> setShowAskBfCloseModal(true)} /> Promise + setImage: Dispatch> + setMessage: Dispatch> + setNickname: Dispatch> + setShowFontSelect: Dispatch> + setSelectedFontKey: Dispatch> + setShowThemaSelect: Dispatch> + setIsValid: Dispatch> +} + +const CreatePolaroid = ({ + image, + selectedFontKey, + selectedThemaKey, + message, + nickname, + setImage, + setMessage, + setNickname, + showFontSelect, + setShowFontSelect, + setSelectedFontKey, + setShowThemaSelect, + submit, + isValid, + setIsValid, +}: CreatePolaroidProps) => { + const fontSelectRef = useRef(null) + + useEffect(() => { + setIsValid(!!image) + }, [image]) + + useEffect(() => { + if (fontSelectRef.current) { + fontSelectRef.current.scrollIntoView() + } + }, [fontSelectRef, showFontSelect]) + + return ( +
+ +
+
+ +
+ setShowFontSelect((prev) => !prev)} + > + 폰트 고르기 + + setShowThemaSelect((prev) => !prev)} + > + + 프레임 고르기 + +
+
+ {showFontSelect && ( + + )} +
+
+ +
+
+ ) +} + +export default CreatePolaroid diff --git a/src/app/board/[boardId]/_components/CreatePolaroidModal/FontSelect.tsx b/src/app/board/[boardId]/_components/CreatePolaroidModal/FontSelect.tsx new file mode 100644 index 0000000..1de1b73 --- /dev/null +++ b/src/app/board/[boardId]/_components/CreatePolaroidModal/FontSelect.tsx @@ -0,0 +1,42 @@ +import { FontKeyType } from '@/types' +import { FONTS } from '@/lib' +import { twMerge } from 'tailwind-merge' +import TagButton from '@/components/TagButton' +import { forwardRef } from 'react' + +interface FontSelectProps { + selectedFont: FontKeyType + onSelect: (fontKey: FontKeyType) => void +} + +const FontSelect = forwardRef( + ({ selectedFont, onSelect }, ref) => { + const selectedFontClass = 'bg-gray-0 text-gray-1000 border border-gray-900' + const fontClass = 'text-neutral-500 bg-gray-300 border border-gray-500 ' + return ( +
+
+ {Object.entries(FONTS).map(([key, font]) => ( + onSelect(key as FontKeyType)} + > + {font.title} + + ))} +
+
+ ) + }, +) + +FontSelect.displayName = 'FontSelect' + +export default FontSelect diff --git a/src/app/board/[boardId]/_components/CreatePolaroidModal/ThemaSelect.tsx b/src/app/board/[boardId]/_components/CreatePolaroidModal/ThemaSelect.tsx new file mode 100644 index 0000000..dc31f6d --- /dev/null +++ b/src/app/board/[boardId]/_components/CreatePolaroidModal/ThemaSelect.tsx @@ -0,0 +1,89 @@ +import Image from 'next/image' +import { twMerge } from 'tailwind-merge' +import { ThemaKeyType } from '@/types' +import { THEMAS } from '@/lib' +import { useEffect, useState } from 'react' +import Button from '@/components/Button' +import ArrowBackIcon from 'public/icons/arrow_back_ios.svg' + +interface ThemaSelectItemProps { + themaType: ThemaKeyType + isCurrentThema: boolean + setCurrentThema: (thema: ThemaKeyType) => void +} + +const ThemaSelectItem = ({ + themaType, + isCurrentThema, + setCurrentThema, +}: ThemaSelectItemProps) => { + return ( +
+ polabo setCurrentThema(themaType)} + /> +
+ ) +} + +interface ThemaSelectProps { + selectedThema: ThemaKeyType + setSelectedThema: (thema: ThemaKeyType) => void + setShowThemaSelect: (showThemaSelect: boolean) => void +} + +const ThemaSelect = ({ + selectedThema, + setSelectedThema, + setShowThemaSelect, +}: ThemaSelectProps) => { + const [currentThema, setCurrentThema] = useState(selectedThema) + + useEffect(() => { + setCurrentThema(selectedThema) + }, [selectedThema]) + + const onSelectThema = () => { + setSelectedThema(currentThema) + setShowThemaSelect(false) + } + + return ( +
+
+ setShowThemaSelect(false)} + /> +
+
+
+ {Object.entries(THEMAS).map(([key]) => ( + + ))} +
+
+
+ +
+
+ ) +} + +export default ThemaSelect diff --git a/src/app/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx b/src/app/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx index 58ad809..50a543f 100644 --- a/src/app/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx +++ b/src/app/board/[boardId]/_components/CreatePolaroidModal/UploadBtn.tsx @@ -18,23 +18,20 @@ const UploadBtn = ({ submitForm, btnDisabled }: UploadBtnProps) => { } return ( -
-
- -
+ <> + setShowFinalModal(false)} onConfirm={onSubmit} /> -
+ ) } diff --git a/src/app/board/[boardId]/_components/CreatePolaroidModal/index.tsx b/src/app/board/[boardId]/_components/CreatePolaroidModal/index.tsx index c6992d2..64d82fb 100644 --- a/src/app/board/[boardId]/_components/CreatePolaroidModal/index.tsx +++ b/src/app/board/[boardId]/_components/CreatePolaroidModal/index.tsx @@ -1,29 +1,29 @@ 'use client' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useSession } from 'next-auth/react' import { getPolaroidNickname } from '@/lib/utils/polaroid' -import PolaroidMaker from '@/components/Polaroid/PolaroidMaker' +import { FontKeyType, ThemaKeyType } from '@/types' +import ThemaSelect from '@/app/board/[boardId]/_components/CreatePolaroidModal/ThemaSelect' +import CreatePolaroid from '@/app/board/[boardId]/_components/CreatePolaroidModal/CreatePolaroid' import { uploadAction } from '../../_actions/uploadAction' -import ArrowBack from './ArrowBack' import { useModal } from './ModalContext' -import UploadBtn from './UploadBtn' interface CreatePolaroidProps { id: string } -const CreatePolaroid = ({ id }: CreatePolaroidProps) => { +const CreatePolaroidModal = ({ id }: CreatePolaroidProps) => { const [isValid, setIsValid] = useState(false) const [image, setImage] = useState(null) const [nickname, setNickname] = useState('') const [message, setMessage] = useState('') + const [selectedFontKey, setSelectedFontKey] = useState('HESOM') + const [showFontSelect, setShowFontSelect] = useState(false) + const [selectedThemaKey, setSelectedThemaKey] = useState('F-0') + const [showThemaSelect, setShowThemaSelect] = useState(false) const { closeModal } = useModal() - useEffect(() => { - setIsValid(!!image) - }, [image]) - const { data: session } = useSession() const submit = async () => { @@ -35,6 +35,8 @@ const CreatePolaroid = ({ id }: CreatePolaroidProps) => { formData.append('fileInput', image!) formData.append('oneLineMessage', message) formData.append('nickname', getPolaroidNickname(nickname, session)) + formData.append('font', selectedFontKey) + formData.append('thema', selectedThemaKey) const res = await uploadAction(id, formData) @@ -43,22 +45,35 @@ const CreatePolaroid = ({ id }: CreatePolaroidProps) => { } } + if (showThemaSelect) { + return ( + + ) + } + return ( -
- -
- -
- -
+ ) } -export default CreatePolaroid +export default CreatePolaroidModal diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 04936a0..f90583b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -21,6 +21,21 @@ const Hesom = localFont({ variable: '--font-hesom', }) +const Eunyoung = localFont({ + src: '../../public/fonts/eunyoung.woff2', + variable: '--font-eunyoung', +}) + +const Ttaerom = localFont({ + src: '../../public/fonts/ttaerom.ttf', + variable: '--font-ttaerom', +}) + +const Hipi = localFont({ + src: '../../public/fonts/hipi.ttf', + variable: '--font-hipi', +}) + export const metadata: Metadata = { title: 'POLABO | 함께 꾸미는 폴라로이드 보드, 폴라보', description: @@ -63,7 +78,7 @@ export default function RootLayout({ diff --git a/src/components/Polaroid/Base/PolaroidDescription.tsx b/src/components/Polaroid/Base/PolaroidDescription.tsx index 7e6b392..e8f30f7 100644 --- a/src/components/Polaroid/Base/PolaroidDescription.tsx +++ b/src/components/Polaroid/Base/PolaroidDescription.tsx @@ -1,17 +1,23 @@ import { HTMLAttributes } from 'react' import { twMerge } from 'tailwind-merge' +import { ThemaKeyType } from '@/types' +import { THEMAS } from '@/lib' + +interface PolaroidDescriptionProps extends HTMLAttributes { + themaKey: ThemaKeyType +} const PolaroidDescription = ({ children, className, + themaKey, ...props -}: HTMLAttributes) => { +}: PolaroidDescriptionProps) => { return (
diff --git a/src/components/Polaroid/Base/PolaroidFrame.tsx b/src/components/Polaroid/Base/PolaroidFrame.tsx index 7f74dc1..9bfa9a3 100644 --- a/src/components/Polaroid/Base/PolaroidFrame.tsx +++ b/src/components/Polaroid/Base/PolaroidFrame.tsx @@ -1,14 +1,23 @@ import { HTMLAttributes } from 'react' import { twMerge } from 'tailwind-merge' +import { FontKeyType, ThemaKeyType } from '@/types' +import { FONTS, THEMAS } from '@/lib' + +interface PolaroidFrameProps extends HTMLAttributes { + themaKey: ThemaKeyType + fontKey: FontKeyType +} const PolaroidFrame = ({ children, className, + themaKey, + fontKey, ...props -}: HTMLAttributes) => { +}: PolaroidFrameProps) => { return (
{children} diff --git a/src/components/Polaroid/PolaroidCard/index.tsx b/src/components/Polaroid/PolaroidCard/index.tsx index 944e093..cb71631 100644 --- a/src/components/Polaroid/PolaroidCard/index.tsx +++ b/src/components/Polaroid/PolaroidCard/index.tsx @@ -12,11 +12,16 @@ interface PolaroidCardProps { function PolaroidCard({ polaroid, onClick = () => {} }: PolaroidCardProps) { return ( - +
- + - +
- + (null) + useEffect(() => { + const element = ref.current + + const resizeObserver = new ResizeObserver(() => { + if (element) { + setWidth(element.offsetWidth) + } + }) + + if (element) { + resizeObserver.observe(element) + } + + return () => { + if (element) { + resizeObserver.unobserve(element) + } + } + }, []) + useEffect(() => { if (!ref.current) { return diff --git a/src/components/Polaroid/PolaroidMaker/index.tsx b/src/components/Polaroid/PolaroidMaker/index.tsx index ebe1042..8115c7d 100644 --- a/src/components/Polaroid/PolaroidMaker/index.tsx +++ b/src/components/Polaroid/PolaroidMaker/index.tsx @@ -8,6 +8,7 @@ import { import imageCompression from 'browser-image-compression' import PolaroidFrame from '@/components/Polaroid/Base/PolaroidFrame' import PolaroidDescription from '@/components/Polaroid/Base/PolaroidDescription' +import { FontKeyType, ThemaKeyType } from '@/types' import PolaroidImageInput from './PolaroidImageInput' import PolaroidMessageInput from './PolaroidMessageInput' import PolaroidNicknameInput from './PolaroidNicknameInput' @@ -25,18 +26,22 @@ interface PolaroidMakerProps { setImage: Dispatch> setMessage: Dispatch> setNickname: Dispatch> + fontKey: FontKeyType + themaKey: ThemaKeyType } const MAX_MESSAGE_LENGTH = 20 const MAX_FROM_LENGTH = 10 const PolaroidMaker = ({ + themaKey, image, message, nickname, setImage, setMessage, setNickname, + fontKey, }: PolaroidMakerProps) => { const [previewFile, setPreviewFile] = useState(null) @@ -78,14 +83,18 @@ const PolaroidMaker = ({ } return ( - +
- + {} + +const TagButton = ({ children, className, ...props }: TagButtonProps) => { + return ( + + ) +} + +export default TagButton diff --git a/src/lib/constants/polaroidConfig.ts b/src/lib/constants/polaroidConfig.ts index 648e250..8e24871 100644 --- a/src/lib/constants/polaroidConfig.ts +++ b/src/lib/constants/polaroidConfig.ts @@ -1,6 +1,75 @@ +import { FontKeyType, FontType, ThemaKeyType, ThemaType } from '@/types' + export const FILTERS = { NORMAL: 'none', POLAROID: 'sepia(0.2) contrast(1.0) brightness(1) saturate(1.2) blur(0px)', VINTAGE: 'sepia(0.4) contrast(1.1) brightness(0.9) saturate(0.8) hue-rotate(-20deg) blur(0.6px)', } as const + +export const THEMAS: Record = { + 'F-0': { + className: 'bg-[#eaeaea]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #eaeaea', + }, + 'F-1': { + className: 'bg-[#ede2d8]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #ede2d8', + }, + 'F-2': { + className: 'bg-[#ffd7e0]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #ffd7e0', + }, + 'F-3': { + className: 'bg-[#ffdbfb]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #ffdbfb', + }, + 'F-4': { + className: 'bg-[#fff7db]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #fff7db', + }, + 'F-5': { + className: 'bg-[#e5ffdc]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #e5ffdc', + }, + 'F-6': { + className: 'bg-[#c4f0e6]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #c4f0e6', + }, + 'F-7': { + className: 'bg-[#dbf2ff]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #dbf2ff', + }, + 'F-8': { + className: 'bg-[#e6daff]', + descriptionStyle: + 'linear-gradient(180deg, rgba(255, 255, 255, 0.20) 10.71%, rgba(255, 255, 255, 0.50) 57.96%, rgba(255, 255, 255, 0.00) 100%), #e6daff', + }, +} as const + +export const FONTS: Record = { + HESOM: { + title: '해솜체', + className: 'font-hesom', + }, + EUNYOUNG: { + title: '은영체', + className: 'font-eunyoung', + }, + TTAEROM: { + title: '때롬체', + className: 'font-ttaerom', + }, + HIPI: { + title: '바른히피체', + className: 'font-hipi', + }, +} diff --git a/src/types/polaroid.ts b/src/types/polaroid.ts index 7a6379b..56a5cc4 100644 --- a/src/types/polaroid.ts +++ b/src/types/polaroid.ts @@ -1,19 +1,43 @@ -import { FILTERS } from '../lib/constants/polaroidConfig' - export interface Polaroid { id: number imageUrl: string oneLineMessage: string nickname: string + options: { + FONT: FontKeyType + THEMA: ThemaKeyType + } } export interface CreatePolaroidPayload { imageKey: string oneLineMessage: string nickname: string + options: { + FONT: FontKeyType + THEMA: ThemaKeyType + } } -export interface PolaroidImageProps { - imageUrl: string - filter?: keyof typeof FILTERS +export type FontKeyType = 'HESOM' | 'EUNYOUNG' | 'TTAEROM' | 'HIPI' + +export interface FontType { + title: string + className: string +} + +export type ThemaKeyType = + | 'F-0' + | 'F-1' + | 'F-2' + | 'F-3' + | 'F-4' + | 'F-5' + | 'F-6' + | 'F-7' + | 'F-8' + +export interface ThemaType { + className: string + descriptionStyle: string } diff --git a/tailwind.config.ts b/tailwind.config.ts index 796ff7a..d14052f 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -2,11 +2,7 @@ import type { Config } from 'tailwindcss' const config: Config = { - content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', - ], + content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'], theme: { colors: { gray: { @@ -72,6 +68,9 @@ const config: Config = { pretendard: ['var(--font-pretendard-variable)'], jooree: ['var(--font-jooree)'], hesom: ['var(--font-hesom)'], + eunyoung: ['var(--font-eunyoung)'], + ttaerom: ['var(--font-ttaerom)'], + hipi: ['var(--font-hipi)'], }, keyframes: { 'slide-left': {