Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TEST #5

Merged
merged 2 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/pages/LetterInventoryPage/LetterComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useState } from "react";
import * as S from "./styled";

const LetterComponent = ({ letter, isReceived }) => {
const [isExpanded, setIsExpanded] = useState(false);
const isLocked = !letter.isAvailable;

const toggleExpand = () => {
setIsExpanded(!isExpanded);
};

return (
<S.LetterWrapper onClick={toggleExpand} isExpanded={isExpanded}>
{isLocked ? (
<S.LockedMessage>
νŽΈμ§€λ₯Ό μ—΄ 수 μ—†μŠ΅λ‹ˆλ‹€. 도착 μ˜ˆμ •μž…λ‹ˆλ‹€.
</S.LockedMessage>
) : (
<S.LetterContent isExpanded={isExpanded}>
{letter.content}
</S.LetterContent>
)}
<S.LetterInfo>
{isReceived
? `보낸 μ‚¬λžŒ: ${letter.sender}`
: `λ°›λŠ” μ‚¬λžŒ: ${letter.receiver}`}
<span>{letter.date}</span>
</S.LetterInfo>
</S.LetterWrapper>
);
};

export default LetterComponent;
62 changes: 57 additions & 5 deletions src/pages/LetterInventoryPage/LetterInventoryPage.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,66 @@
import React, { useState } from "react";
import * as S from "./styled";
import LetterComponent from "./LetterComponent";

export const LetterInventoryPage = () => {
const [isReceived, setIsReceived] = useState(true);

const receivedLetters = Array.from({ length: 10 }, (_, index) => ({
id: index + 1,
content: `이것은 받은 νŽΈμ§€ ${
index + 1
}의 λ‚΄μš©μž…λ‹ˆλ‹€. κΈ΄ λ‚΄μš©μ„ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ 800자 길이둜 μ„€μ •λœ νŽΈμ§€μž…λ‹ˆλ‹€. 이 νŽΈμ§€μ—λŠ” λ‹€μ–‘ν•œ λ‚΄μš©μ΄ λ‹΄κ²¨μžˆμœΌλ©°, μ½λŠ” 이둜 ν•˜μ—¬κΈˆ 감동을 쀄 수 μžˆλŠ” 이야기λ₯Ό λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€. μ˜ˆμ‹œλ‘œ μž‘μ„±λœ νŽΈμ§€μ΄κΈ° λ•Œλ¬Έμ— μ€‘λ³΅λœ λ‚΄μš©μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ„ 수 있으며, μ‹€μ œ κ΅¬ν˜„ μ‹œμ—λŠ” 더 λ‹€μ–‘ν•œ λ‚΄μš©μ΄ 포함될 수 μžˆμŠ΅λ‹ˆλ‹€.`,
sender: `홍길동${index + 1}`,
receiver: "철수",
isAvailable: true,
date: `2024-11-${String(index + 1).padStart(2, "0")}`,
}));

const sentLetters = Array.from({ length: 10 }, (_, index) => ({
id: index + 11,
content: `이것은 보낸 νŽΈμ§€ ${
index + 1
}의 λ‚΄μš©μž…λ‹ˆλ‹€. κΈ΄ λ‚΄μš©μ„ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ 800자 길이둜 μ„€μ •λœ νŽΈμ§€μž…λ‹ˆλ‹€. 이 νŽΈμ§€μ—λŠ” λ‹€μ–‘ν•œ λ‚΄μš©μ΄ λ‹΄κ²¨μžˆμœΌλ©°, λ°›λŠ” μ‚¬λžŒμ—κ²Œ 감동을 쀄 수 μžˆλŠ” 이야기λ₯Ό λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€. μ˜ˆμ‹œλ‘œ μž‘μ„±λœ νŽΈμ§€μ΄κΈ° λ•Œλ¬Έμ— μ€‘λ³΅λœ λ‚΄μš©μ΄ ν¬ν•¨λ˜μ–΄ μžˆμ„ 수 있으며, μ‹€μ œ κ΅¬ν˜„ μ‹œμ—λŠ” 더 λ‹€μ–‘ν•œ λ‚΄μš©μ΄ 포함될 수 μžˆμŠ΅λ‹ˆλ‹€.`,
sender: "철수",
receiver: `홍길동${index + 1}`,
isAvailable: true,
date: `2024-10-${String(index + 1).padStart(2, "0")}`,
}));

const lettersToShow = isReceived ? receivedLetters : sentLetters;

return (
<S.Wrapper>
<S.MiniHeader>
<S.HeaderOption>받은 νŽΈμ§€</S.HeaderOption>
<S.HeaderOption>보낸 νŽΈμ§€</S.HeaderOption>
<S.HeaderOption
isSelected={isReceived}
onClick={() => setIsReceived(true)}
>
받은 νŽΈμ§€
</S.HeaderOption>
<S.HeaderOption
isSelected={!isReceived}
onClick={() => setIsReceived(false)}
>
보낸 νŽΈμ§€
</S.HeaderOption>
</S.MiniHeader>

<S.LettersContainer>
{lettersToShow.length > 0 ? (
lettersToShow.map((letter) => (
<LetterComponent
key={letter.id}
letter={letter}
isReceived={isReceived}
/>
))
) : (
<S.EmptyMessage>νŽΈμ§€κ°€ μ—†μŠ΅λ‹ˆλ‹€.</S.EmptyMessage>
)}
</S.LettersContainer>
</S.Wrapper>
)
}
);
};

export default LetterInventoryPage;
export default LetterInventoryPage;
75 changes: 68 additions & 7 deletions src/pages/LetterInventoryPage/styled.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,85 @@ export const Wrapper = styled.div`
position: relative;
height: 100vh;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 120px;
`;

export const MiniHeader = styled.div`
display: flex;
width: 100%;
justify-content: space-around;
position: absolute;
top: 60px;
padding: 20px 0;
background-color: ${({ theme }) => theme.colors.background};
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1);
`;

export const HeaderOption = styled.div`
display: flex;
cursor: pointer;

color: ${({theme}) => theme.colors.black};

font-family: ${({theme}) => theme.fonts.GowunDodum["font-family"]};
color: ${({ theme, isSelected }) =>
isSelected ? theme.colors.primary : theme.colors.black};
font-family: ${({ theme }) => theme.fonts.GowunDodum["font-family"]};
font-size: 30px;
font-style: normal;
font-weight: 400;
`;
font-weight: ${({ isSelected }) => (isSelected ? "bold" : "400")};
border-bottom: ${({ isSelected, theme }) =>
isSelected ? `2px solid ${theme.colors.primary}` : "none"};
opacity: ${({ isSelected }) => (isSelected ? 1 : 0.6)};
`;

export const LettersContainer = styled.div`
width: 100%;
max-width: 600px;
height: 70vh;
overflow-y: scroll;
padding: 0 20px;
box-sizing: border-box;
`;

export const LetterWrapper = styled.div`
padding: 20px;
margin: 10px 0;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
background-color: ${({ theme }) => theme.colors.white};
border-radius: 8px;
line-height: 1.6;
font-family: "GowunDodum", sans-serif;
text-align: left;
cursor: pointer;
overflow: hidden;
transition: max-height 0.3s ease;
max-height: ${({ isExpanded }) => (isExpanded ? "1000px" : "4.8em")};
`;

export const LockedMessage = styled.div`
color: gray;
font-size: 14px;
`;

export const LetterContent = styled.div`
color: ${({ theme }) => theme.colors.black};
font-size: 16px;
margin-bottom: 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: ${({ isExpanded }) => (isExpanded ? "normal" : "nowrap")};
display: -webkit-box;
-webkit-line-clamp: ${({ isExpanded }) => (isExpanded ? "none" : 3)};
-webkit-box-orient: vertical;
`;

export const LetterInfo = styled.div`
font-size: 12px;
color: darkgray;
display: flex;
justify-content: space-between;
`;

export const EmptyMessage = styled.div`
color: gray;
font-size: 16px;
margin-top: 20px;
`;
1 change: 1 addition & 0 deletions src/pages/LetterMakePage/LetterMakePage.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// src/pages/LetterMakePage/LetterMakePage.jsx
import React, { useState } from "react";
import * as S from "./styled";
import { LetterOne } from "@components/Letters/LetterOne";
Expand Down
91 changes: 43 additions & 48 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -1,67 +1,62 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { VitePWA } from 'vite-plugin-pwa';
import path from 'path';
import fs from 'fs';
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
import path from "path";
import fs from "fs";

export default defineConfig({
base: '/',
base: "/",
plugins: [
react(),
// PWA ν”ŒλŸ¬κ·ΈμΈ μ„€μ • μˆ˜μ •
VitePWA({
registerType: 'autoUpdate', // μ„œλΉ„μŠ€ μ›Œμ»€ μžλ™ μ—…λ°μ΄νŠΈ
includeAssets: ['/icons/pwa-192.png', '/icons/pwa-512.png'], // 둜컬 경둜의 이미지 μ°Έμ‘°
registerType: "autoUpdate", // μ„œλΉ„μŠ€ μ›Œμ»€ μžλ™ μ—…λ°μ΄νŠΈ
includeAssets: ["/icons/pwa-192.png", "/icons/pwa-512.png"], // 둜컬 경둜의 이미지 μ°Έμ‘°
manifest: {
name: 'My Vite PWA App', // PWA μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 전체 이름
short_name: 'VitePWA', // ν™ˆ 화면에 ν‘œμ‹œλ  이름
description: 'This is my Vite PWA application', // μ„€λͺ…
theme_color: '#ffffff', // ν…Œλ§ˆ 색상
background_color: '#ffffff', // λ°°κ²½ 색상
display: 'standalone', // λΈŒλΌμš°μ € μš”μ†Œ 제거
scope: '/', // PWAκ°€ 적용될 URL λ²”μœ„
start_url: '/', // μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ‹œμž‘ URL
name: "My Vite PWA App", // PWA μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 전체 이름
short_name: "VitePWA", // ν™ˆ 화면에 ν‘œμ‹œλ  이름
description: "This is my Vite PWA application", // μ„€λͺ…
theme_color: "#ffffff", // ν…Œλ§ˆ 색상
background_color: "#ffffff", // λ°°κ²½ 색상
display: "standalone", // λΈŒλΌμš°μ € μš”μ†Œ 제거
scope: "/", // PWAκ°€ 적용될 URL λ²”μœ„
start_url: "/", // μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ‹œμž‘ URL
icons: [
{
src: '/icons/pwa-192.png', // 둜컬 경둜의 192x192 μ•„μ΄μ½˜
sizes: '192x192', // μ•„μ΄μ½˜ 크기
type: 'image/png'
src: "/icons/pwa-192.png", // 둜컬 경둜의 192x192 μ•„μ΄μ½˜
sizes: "192x192", // μ•„μ΄μ½˜ 크기
type: "image/png",
},
{
src: '/icons/pwa-512.png', // 둜컬 경둜의 512x512 μ•„μ΄μ½˜
sizes: '512x512', // μ•„μ΄μ½˜ 크기
type: 'image/png'
src: "/icons/pwa-512.png", // 둜컬 경둜의 512x512 μ•„μ΄μ½˜
sizes: "512x512", // μ•„μ΄μ½˜ 크기
type: "image/png",
},
{
src: '/icons/pwa-512.png', // 둜컬 경둜의 마슀크 κ°€λŠ₯ μ•„μ΄μ½˜
sizes: '512x512',
type: 'image/png',
purpose: 'maskable' // 마슀크 κ°€λŠ₯ 속성 μΆ”κ°€
}
]
}
})
src: "/icons/pwa-512.png", // 둜컬 경둜의 마슀크 κ°€λŠ₯ μ•„μ΄μ½˜
sizes: "512x512",
type: "image/png",
purpose: "maskable", // 마슀크 κ°€λŠ₯ 속성 μΆ”κ°€
},
],
},
}),
],
server: process.env.NODE_ENV === 'development' ? {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
cert: fs.readFileSync(path.resolve(__dirname, 'localhost.pem')),
},
} : {},

resolve: {
alias: {
'@atoms': path.resolve(__dirname, 'src/atoms'),
'@components': path.resolve(__dirname, 'src/components'),
'@constants': path.resolve(__dirname, 'src/constant'),
'@contexts': path.resolve(__dirname, 'src/contexts'),
'@hooks': path.resolve(__dirname, 'src/hooks'),
'@layouts': path.resolve(__dirname, 'src/layouts'),
'@pages': path.resolve(__dirname, 'src/pages'),
'@routes': path.resolve(__dirname, 'src/routes'),
'@services': path.resolve(__dirname, 'src/services'),
'@styles': path.resolve(__dirname, 'src/styles'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@public': path.resolve(__dirname, 'public'),
"@atoms": path.resolve(__dirname, "src/atoms"),
"@components": path.resolve(__dirname, "src/components"),
"@constants": path.resolve(__dirname, "src/constant"),
"@contexts": path.resolve(__dirname, "src/contexts"),
"@hooks": path.resolve(__dirname, "src/hooks"),
"@layouts": path.resolve(__dirname, "src/layouts"),
"@pages": path.resolve(__dirname, "src/pages"),
"@routes": path.resolve(__dirname, "src/routes"),
"@services": path.resolve(__dirname, "src/services"),
"@styles": path.resolve(__dirname, "src/styles"),
"@utils": path.resolve(__dirname, "src/utils"),
"@public": path.resolve(__dirname, "public"),
},
},
});
Loading