Skip to content

Commit

Permalink
fix. 파일이름 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
ji-hunc committed Nov 20, 2024
1 parent e3a0e6b commit fef19e1
Show file tree
Hide file tree
Showing 16 changed files with 978 additions and 3 deletions.
13 changes: 13 additions & 0 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import { FooterContainer } from "./styles";

const Footer: React.FC = () => {
return (
<FooterContainer>
<p>© 2024 POFO. All rights reserved.</p>
<p>Contact us at [email protected]</p>
</FooterContainer>
);
};

export default Footer;
2 changes: 1 addition & 1 deletion src/components/Home/HomeSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useAppDispatch } from "@/stores";
import { setVisibilityStackToggle } from "@/stores/selectStackType/selectStacksReducer";
import { setVisibilityTypeToggle } from "@/stores/selectStackType/selectTypesReducer";
import { useEffect, useRef } from "react";
import SelectStackType from "../selectStackType/SelectStackType";
import SelectStackType from "../SelectStackType/SelectStackType";

export function SearchName() {
return (
Expand Down
20 changes: 20 additions & 0 deletions src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";
import Navigation from "../Navigation/Navigation";
import Footer from "../Footer/Footer";
import { Content, LayoutContainer } from "./styles";

interface LayoutProps {
children: React.ReactNode;
}

const Layout: React.FC<LayoutProps> = ({ children }) => {
return (
<LayoutContainer>
<Navigation />
<Content>{children}</Content>
<Footer />
</LayoutContainer>
);
};

export default Layout;
102 changes: 102 additions & 0 deletions src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useState } from "react";
import {
LoginText,
SignUpButton,
Logo,
NavContainer,
NavItems,
StyledNavLink,
HamburgerButton,
DrawerMenu,
Overlay,
} from "./styles";
import LoginModal from "../LoginModal/LoginModel";
import hamburger from "../../../public/icons/hamburger.svg";
import Image from "next/image";

const Navigation: React.FC = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [initialStep, setInitialStep] = useState<"main" | "signup">("main");

const handleOpenLoginModal = () => {
setInitialStep("main");
setIsModalOpen(true);
};

const handleOpenSignupModal = () => {
setInitialStep("signup");
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
};

const toggleMenu = () => {
setIsMenuOpen((prev) => !prev);
};

return (
<NavContainer>
<div
style={{
display: "flex",
alignItems: "center",
}}
>
<HamburgerButton onClick={toggleMenu}>
<Image
style={{ cursor: "pointer" }}
src={hamburger}
width={20}
height={20}
alt="close button"
/>
</HamburgerButton>
<div
style={{
display: "flex",
alignItems: "center",
}}
>
<Logo href="/">POFO</Logo>
<NavItems>
<StyledNavLink href="/counter">Home</StyledNavLink>
<StyledNavLink href="/mypage">MyPage</StyledNavLink>
</NavItems>
</div>
</div>
<div className="auth-buttons">
<LoginText onClick={handleOpenLoginModal}>로그인</LoginText>
<SignUpButton onClick={handleOpenSignupModal}>회원가입</SignUpButton>
</div>
{isMenuOpen && (
<>
<Overlay onClick={toggleMenu} />
<DrawerMenu className={isMenuOpen ? "open" : ""}>
<StyledNavLink href="/counter" onClick={toggleMenu}>
Home
</StyledNavLink>
<StyledNavLink href="/mypage" onClick={toggleMenu}>
MyPage
</StyledNavLink>
<SignUpButton
onClick={() => {
handleOpenSignupModal();
toggleMenu();
}}
>
회원가입
</SignUpButton>
</DrawerMenu>
</>
)}
{isModalOpen && (
<LoginModal onClose={handleCloseModal} initialStep={initialStep} />
)}
</NavContainer>
);
};

export default Navigation;
136 changes: 136 additions & 0 deletions src/components/Newpost/ImageUpload/ImageUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { useState } from "react";
import { MdUploadFile } from "react-icons/md";
import { IoClose } from "react-icons/io5";
import Image from "next/image";
import * as Style from "./styles";

export default function UploadBox() {
const [isActive, setActive] = useState(false);
const [imgSrc, setImgSrc] = useState<string[]>([]);

const [showModal, setShowModal] = useState(false);
const [selectedImage, setSelectedImage] = useState<string | null>(null);

const handleDragStart = () => setActive(true);
const handleDragEnd = (event: React.DragEvent<HTMLLabelElement>) => {
// 드래그가 완전히 벗어난 경우에만 setActive(false)를 호출
if (!event.currentTarget.contains(event.relatedTarget as Node)) {
setActive(false);
}
};
const handleDragOver = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
};

const setFileInfo = (file: File) => {
if (imgSrc.length >= 3) {
alert("이미지는 최대 3개까지 등록 가능합니다");
return;
}
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
// 로딩이 완료되면 실행할 콜백 함수 등록
fileReader.onload = (e) => {
if (typeof e.target?.result === "string") {
setImgSrc((prevState) => [...prevState, e.target?.result as string]);
}
};
};

const handleDrop = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
setActive(false);

const file = event.dataTransfer.files[0];
if (file) {
if (file.type.startsWith("image/")) {
setFileInfo(file);
} else {
alert("이미지 파일만 업로드할 수 있습니다.");
}
}
};

const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
if (file.type.startsWith("image/")) {
setFileInfo(file);
} else {
alert("이미지 파일만 업로드할 수 있습니다.");
}
}
};

const closeImage = (idx: number) => {
setImgSrc((prevImgSrc) => prevImgSrc.filter((_, i) => i !== idx));
};

const ImageWide = ({
src,
onClose,
}: {
src: string;
onClose: () => void;
}) => (
<Style.ModalOverlay onClick={onClose}>
<Style.ModalImage src={src} alt="" />
</Style.ModalOverlay>
);

const openImagePreview = (src: string) => {
setSelectedImage(src);
setShowModal(true);
};

const closeImagePreview = () => {
setSelectedImage(null);
setShowModal(false);
};

return (
<Style.ImageUploadContainer>
{imgSrc.map((img, index) => (
<Style.ImagePreview key={index}>
<Image
src={img}
onClick={() => {
openImagePreview(img);
}}
alt=""
width={196}
height={196}
/>
<Style.CloseButton
className="close-button"
onClick={() => closeImage(index)}
>
<IoClose />
</Style.CloseButton>
{showModal && selectedImage && (
<ImageWide src={selectedImage} onClose={closeImagePreview} />
)}
</Style.ImagePreview>
))}
<Style.ImageUpload
onDragEnter={handleDragStart}
onDragOver={handleDragOver}
onDragLeave={handleDragEnd}
onDrop={handleDrop}
isActive={isActive}
>
<input
type="file"
className="file"
accept="image/*"
style={{ display: "none" }}
onChange={handleUpload}
/>
<>
<MdUploadFile style={{ fontSize: "100px", marginBottom: "20px" }} />
<p>클릭 또는 드롭</p>
</>
</Style.ImageUpload>
</Style.ImageUploadContainer>
);
}
86 changes: 86 additions & 0 deletions src/components/Newpost/ImageUpload/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import styled from "@emotion/styled";

const lightgrey = "#d7e2eb";
const grey = "#b2c0cc";

export const ImageUploadContainer = styled.div`
display: flex;
white-space: nowrap;
gap: 20px;
justify-content: start;
align-items: center;
overflow-x: auto;
`;

interface DragProps {
isActive: boolean;
}

export const ImageUpload = styled.label<DragProps>`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-width: 200px;
min-height: 200px;
align-items: center;
border: ${({ isActive }) =>
isActive ? `dashed 2px black` : `dashed 2px ${grey}`};
border-radius: 5px;
background-color: ${({ isActive }) => (isActive ? lightgrey : "white")};
cursor: pointer;
&:hover {
border-color: black;
}
`;

export const ImagePreview = styled.div`
width: 200px;
height: 200px;
position: relative;
display: inline-block;
border-radius: 5px;
img {
object-fit: contain;
}
&:hover .close-button {
display: flex;
}
`;

export const CloseButton = styled.button`
position: absolute;
width: 20px;
height: 20px;
display: none;
justify-content: center;
align-items: center;
top: 3px;
right: 3px;
font-size: 30px;
background: transparent;
border: none;
color: black;
cursor: pointer;
`;

export const ModalOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
`;

export const ModalImage = styled.img`
max-width: 90%;
max-height: 90%;
`;
22 changes: 22 additions & 0 deletions src/components/Newpost/Mdeditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import "@uiw/react-md-editor/markdown-editor.css";
import "@uiw/react-markdown-preview/markdown.css";
import dynamic from "next/dynamic";
import { useState } from "react";

const MDEditor = dynamic(() => import("@uiw/react-md-editor"), { ssr: false });

function MdEditor() {
const [value, setValue] = useState<string>("**프로젝트 소개를 입력하세요**");

const handleChange = (val?: string) => {
setValue(val ?? "");
};

return (
<div>
<MDEditor value={value} onChange={handleChange} />
</div>
);
}

export default MdEditor;
Loading

0 comments on commit fef19e1

Please sign in to comment.