diff --git a/frontend/public/codezap.png b/frontend/public/codezap.png new file mode 100644 index 000000000..0eae5f67d Binary files /dev/null and b/frontend/public/codezap.png differ diff --git a/frontend/public/index.html b/frontend/public/index.html index 268d1c971..ff20b8126 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -1,5 +1,5 @@ - + + + + + - codezap + 코드잽 diff --git a/frontend/src/assets/images/checkCircle.svg b/frontend/src/assets/images/checkCircle.svg new file mode 100644 index 000000000..95f120964 --- /dev/null +++ b/frontend/src/assets/images/checkCircle.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/images/index.ts b/frontend/src/assets/images/index.ts index 4e56dbc01..53009ee3d 100644 --- a/frontend/src/assets/images/index.ts +++ b/frontend/src/assets/images/index.ts @@ -15,8 +15,10 @@ export { default as HamburgerIcon } from './Hamburger'; export { default as PersonIcon } from './person.svg'; export { default as ClockIcon } from './clock.svg'; export { default as BooksIcon } from './books.svg'; +export { default as CheckCircleIcon } from './checkCircle.svg'; // Logo export { default as CodeZapLogo } from './codezapLogo.svg'; export { default as TigerLogo } from './tiger.svg'; export { default as ZapzapLogo } from './zapzap.svg'; +export { default as ZapzapCuriousLogo } from './zapzapCurious.svg'; diff --git a/frontend/src/assets/images/zapzapCurious.svg b/frontend/src/assets/images/zapzapCurious.svg new file mode 100644 index 000000000..53c53d2df --- /dev/null +++ b/frontend/src/assets/images/zapzapCurious.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/pages/LandingPage/LandingPage.style.ts b/frontend/src/pages/LandingPage/LandingPage.style.ts new file mode 100644 index 000000000..98245eeae --- /dev/null +++ b/frontend/src/pages/LandingPage/LandingPage.style.ts @@ -0,0 +1,103 @@ +import styled from '@emotion/styled'; + +export const Container = styled.div` + max-width: 1200px; + margin: auto; + padding: 1.25rem; +`; + +export const ContentSection = styled.div` + display: flex; + gap: 3rem; + align-items: center; + justify-content: space-between; + + width: 100%; + margin-top: 4rem; + + @media (max-width: 768px) { + flex-direction: column-reverse; + text-align: center; + } +`; + +export const TextContent = styled.div` + display: flex; + flex-direction: column; + gap: 2rem; + justify-content: space-between; + + @media (max-width: 768px) { + align-items: center; + justify-content: center; + } +`; + +export const ImageWrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; +`; + +export const CardSection = styled.div` + display: flex; + justify-content: space-between; + padding: 3rem 0; + + @media (max-width: 768px) { + flex-direction: column; + } +`; + +export const Card = styled.div` + display: flex; + flex: 1; + flex-direction: column; + gap: 0.5rem; + + margin: 0 10px; + padding: 20px; + + text-align: center; + + background-color: white; + border-radius: 8px; + box-shadow: 1px 2px 8px 1px #00000030; + &:hover { + bottom: 0.5rem; + transform: scale(1.025); + } + + @media (max-width: 768px) { + align-items: center; + margin: 10px 0; + } +`; + +export const TemplateSection = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + + width: 100%; + margin-top: 3rem; + padding: 4rem 0; + + @media (max-width: 768px) { + flex-direction: column; + } +`; + +export const CodeSection = styled.div` + margin-right: 2rem; + + @media (max-width: 768px) { + width: 100%; + } +`; + +export const SyntaxHighlighterWrapper = styled.div<{ isOpen: boolean }>` + overflow: hidden; + max-height: ${({ isOpen }) => (isOpen ? '1000rem' : '0')}; + animation: ${({ isOpen }) => (!isOpen ? 'collapse' : 'expand')} 0.7s ease-in-out forwards; +`; diff --git a/frontend/src/pages/LandingPage/LandingPage.tsx b/frontend/src/pages/LandingPage/LandingPage.tsx index 192d25d76..4ac5dcf5a 100644 --- a/frontend/src/pages/LandingPage/LandingPage.tsx +++ b/frontend/src/pages/LandingPage/LandingPage.tsx @@ -1,78 +1,106 @@ -import styled from '@emotion/styled'; import { type LanguageName, loadLanguage } from '@uiw/codemirror-extensions-langs'; import { quietlight } from '@uiw/codemirror-theme-quietlight'; import CodeMirror, { EditorView } from '@uiw/react-codemirror'; +import { Link } from 'react-router-dom'; -import { ChevronIcon, CodeZapLogo } from '@/assets/images'; +import { CheckCircleIcon, ChevronIcon, ZapzapLogo } from '@/assets/images'; import { Button, Flex, Heading, Text } from '@/components'; import { CustomCodeMirrorTheme } from '@/components/TemplateCard/TemplateCard.style'; +import { ToastContext } from '@/contexts'; +import { useCustomContext } from '@/hooks/utils'; import { theme } from '@/style/theme'; +import { SourceCodes } from '@/types'; import { getLanguageByFilename } from '@/utils'; -import * as S from '../TemplatePage/TemplatePage.style'; +import * as S from './LandingPage.style'; const LandingPage = () => ( - - - - 코드잽 - - - - 자주 쓰는 코드를 나만의 템플릿으로 저장해보세요. - 코드잽에서 나의 코드를 빠르게 찾고, 효율적으로 관리할 수 있습니다. - - - - - 💾 간편한 저장 - - 자주 쓰는 나의 코드를 ZAP하게 저장하세요. - - - - - 🔍 빠른 검색 - - 필요한 나의 코드를 ZAP하게 찾아 사용하세요. - - + + + + 이런 경험 한 번쯤 있으시죠? + {'"아, 그때 그 코드 어디에 썼더라..."'} + + + 더이상 코드를 찾느데 헤매지 마세요! + 코드잽에 자주 쓰는 코드를 템플릿으로 저장하고 빠르게 찾아요. + + + + + + - - 📊 체계적인 관리 - - 직관적인 분류 시스템으로 ZAP하게 정리하세요. + + + + + ZAP하게 저장 + + 자주 쓰는 나의 코드를 간편하게 저장하세요 + + + + + ZAP하게 관리 + + + 직관적인 분류 시스템으로 체계적으로 관리하세요 - - + + + + + ZAP하게 검색 + + 필요한 나의 코드를 빠르게 찾아 사용하세요 + + - + - - + + - ⚡️ 템플릿이란? + 템플릿이란? - - 템플릿은 반복적으로 작성하게 되는 코드 블럭 모음 - + + 코드잽에서 템플릿이란 반복적으로 작성하게 되는 소스 코드의 모음을 뜻해요. + + + 하나의 템플릿에 여러개의 소스코드를 넣을 수 있어요! + - + - 🙌 코드잽은 이런 분들에게 딱이에요 + 소스코드란? - - • 자주 쓰는 코드 템플릿을 간편하게 저장하고 싶은 분 - - - • 프로젝트 파일을 뒤적거리는 대신 필요한 코드를 빠르게 찾고 싶은 분 - - - • 체계적으로 코드를 정리하고 싶지만 방법을 모르셨던 분 - + + 코드잽에서 소스코드란 파일명 + 소스코드 내용으로 이루어진 코드 단위를 뜻해요. + + + 파일명.[확장자]를 입력하면 하이라이트가 되고 복사 버튼으로 편하게 복사할 수 있어요! + - - + + + + + 코드잽은 이런 분들에게 딱이에요 ! + 자주 쓰는 코드 템플릿을 간편하게 저장하고 싶은 분 + 프로젝트 파일을 뒤적거리는 대신 필요한 코드를 빠르게 찾고 싶은 분 + 체계적으로 코드를 정리하고 싶지만 방법을 모르셨던 분 + + + + + + + + + + + ); export default LandingPage; @@ -82,12 +110,18 @@ const ExamCode = () => { id: 102, filename: 'App.tsx', content: - "import React from 'react';\nimport MyComponent from './MyComponent';\n\nconst App: React.FC = () => {\n return (\n
\n \n
\n );\n};\n\nexport default App;", + "import React from 'react';\nimport MyComponent from './MyComponent';\n\nconst Template = () => {\n return (\n
\n \n
\n );\n};\n\nexport default Template;", ordinal: 2, }; + const { infoAlert } = useCustomContext(ToastContext); + const copyCode = (sourceCode: SourceCodes) => () => { + navigator.clipboard.writeText(sourceCode.content); + infoAlert('코드가 복사되었습니다!'); + }; + return ( -
+ { {sourceCode.filename} -
+ ); }; - -const Card = styled.div` - cursor: pointer; - - display: flex; - flex-direction: column; - gap: 2rem; - - padding: 2rem; - - background-color: ${theme.color.light.primary_500}; - border-radius: 24px; - - transition: 0.1s ease; - &:hover { - bottom: 0.5rem; - transform: scale(1.025); - box-shadow: 1px 2px 8px 1px #00000030; - } -`; diff --git a/frontend/src/pages/MyTemplatesPage/MyTemplatePage.tsx b/frontend/src/pages/MyTemplatesPage/MyTemplatePage.tsx index 41f62286b..287612170 100644 --- a/frontend/src/pages/MyTemplatesPage/MyTemplatePage.tsx +++ b/frontend/src/pages/MyTemplatesPage/MyTemplatePage.tsx @@ -2,7 +2,7 @@ import { useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { DEFAULT_SORTING_OPTION, SORTING_OPTIONS } from '@/api'; -import { ArrowUpIcon, PlusIcon, SearchIcon } from '@/assets/images'; +import { ArrowUpIcon, PlusIcon, SearchIcon, ZapzapCuriousLogo } from '@/assets/images'; import { CategoryFilterMenu, Flex, @@ -108,7 +108,12 @@ const MyTemplatePage = () => { if (templates.length === 0) { if (debouncedKeyword !== '') { - return 검색 결과가 없습니다.; + return ( + + + 검색 결과가 없습니다. + + ); } else { return ; } diff --git a/frontend/src/pages/TemplatePage/TemplatePage.tsx b/frontend/src/pages/TemplatePage/TemplatePage.tsx index f0c907d6e..244065efa 100644 --- a/frontend/src/pages/TemplatePage/TemplatePage.tsx +++ b/frontend/src/pages/TemplatePage/TemplatePage.tsx @@ -8,6 +8,7 @@ import { ChevronIcon, ClockIcon, PencilIcon, PersonIcon, TrashcanIcon } from '@/ import { Button, Flex, Heading, Modal, SelectList, TagButton, Text } from '@/components'; import { CustomCodeMirrorTheme } from '@/components/TemplateCard/TemplateCard.style'; import { ToastContext } from '@/contexts'; +import { useAuth } from '@/hooks/authentication'; import { useTemplate } from '@/hooks/template'; import { useCustomContext, useToggle } from '@/hooks/utils'; import { TemplateEditPage } from '@/pages'; @@ -18,6 +19,9 @@ import * as S from './TemplatePage.style'; const TemplatePage = () => { const { id } = useParams<{ id: string }>(); const theme = useTheme(); + const { + memberInfo: { name }, + } = useAuth(); const { infoAlert } = useCustomContext(ToastContext); const [isOpen, toggleModal] = useToggle(); @@ -65,20 +69,22 @@ const TemplatePage = () => { {template.category?.name} - - { - handleEditButtonClick(); - }} - > - - - - - - + {template.member.name === name && ( + + { + handleEditButtonClick(); + }} + > + + + + + + + )}