diff --git a/cocode/package.json b/cocode/package.json index 1e715ec3..96d2b13a 100644 --- a/cocode/package.json +++ b/cocode/package.json @@ -39,6 +39,7 @@ "homepage": "https://github.com/connect-foundation/2019-04#readme", "dependencies": { "@material-ui/core": "^4.6.0", + "@monaco-editor/react": "^2.3.0", "axios": "^0.19.0", "dotenv": "^8.2.0", "file-loader": "^4.2.0", diff --git a/cocode/public/index.html b/cocode/public/index.html index 7dee8479..0b59b7c1 100644 --- a/cocode/public/index.html +++ b/cocode/public/index.html @@ -11,6 +11,14 @@
+ + diff --git a/cocode/src/actions/Project.js b/cocode/src/actions/Project.js new file mode 100644 index 00000000..26e091ce --- /dev/null +++ b/cocode/src/actions/Project.js @@ -0,0 +1,16 @@ +const UPDATE_CODE = 'updateCode'; +function updateCodeActionCreator(payload) { + return { type: UPDATE_CODE, payload }; +} + +const FETCH_PROJECT = 'fetchProject'; +function fetchProjectActionCreator() { + return { type: FETCH_PROJECT }; +} + +export { + UPDATE_CODE, + updateCodeActionCreator, + FETCH_PROJECT, + fetchProjectActionCreator +}; diff --git a/cocode/src/components/Browser/index.js b/cocode/src/components/Browser/index.js index 65c8860f..c9787e7e 100644 --- a/cocode/src/components/Browser/index.js +++ b/cocode/src/components/Browser/index.js @@ -35,13 +35,20 @@ function BrowserHeader({ defaultValue={addressInputURL} onKeyUp={handleAddressInputKeyDown} adressInputBGColor={theme.adressInputBGColor} - adressInputFontColor={theme.adressInputTextColor} + adressInputTextColor={theme.adressInputTextColor} /> ); } -function Browser({ onGoBackward, onGoForward, onReload, url, theme }) { +function Browser({ + className, + onGoBackward, + onGoForward, + onReload, + url, + theme +}) { const [addressInputURL, setAddressInput] = useState( url ? url : DEFAULT_URL ); @@ -53,7 +60,7 @@ function Browser({ onGoBackward, onGoForward, onReload, url, theme }) { }; return ( - + { + try { + const parsedCode = babel.transform(code, { + presets: [reactPreset] + }); + eval(parsedCode.code); + } catch (e) { + console.log(e); + } + }; + + useEffect(buildCode, [code]); + return ; +} + +export default BrowserV1; diff --git a/cocode/src/components/BrowserV1/style.js b/cocode/src/components/BrowserV1/style.js new file mode 100644 index 00000000..0fa19cf7 --- /dev/null +++ b/cocode/src/components/BrowserV1/style.js @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +const BrowserV1 = styled.div` + & { + height: ${({ height }) => height}; + + background-color: white; + color: black; + } +`; + +export { BrowserV1 }; diff --git a/cocode/src/components/CloseButton/index.js b/cocode/src/components/CloseButton/index.js index b5facc9f..0c467cb5 100644 --- a/cocode/src/components/CloseButton/index.js +++ b/cocode/src/components/CloseButton/index.js @@ -1,11 +1,12 @@ import React from 'react'; +import * as Styled from './style'; import close from './close.svg'; function CloseButton({ onClick }) { return ( - + ); } diff --git a/cocode/src/components/CloseButton/style.js b/cocode/src/components/CloseButton/style.js new file mode 100644 index 00000000..495cbdd7 --- /dev/null +++ b/cocode/src/components/CloseButton/style.js @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +const Button = styled.button` + & { + opacity: 0.7; + } + + &:hover { + opacity: 1; + } +`; + +export { Button }; \ No newline at end of file diff --git a/cocode/src/components/DropDownMenu/index.js b/cocode/src/components/DropDownMenu/index.js new file mode 100644 index 00000000..7c48960d --- /dev/null +++ b/cocode/src/components/DropDownMenu/index.js @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { useState } from 'react'; +import * as Styled from './style'; + +function DropDownMenu({ children, menuItems, ...props }) { + const [isOpen, setIsOpen] = useState(false); + + const handleIsOpen = () => setIsOpen(!isOpen); + return ( + + {React.cloneElement(children, { onClick: handleIsOpen })} + {isOpen && ( + + {menuItems && + menuItems.map(({ value, ...props }, key) => ( + + {value} + + ))} + + )} + + ); +} + +export default DropDownMenu; diff --git a/cocode/src/components/DropDownMenu/index.stories.js b/cocode/src/components/DropDownMenu/index.stories.js new file mode 100644 index 00000000..872039ba --- /dev/null +++ b/cocode/src/components/DropDownMenu/index.stories.js @@ -0,0 +1,60 @@ +import React from 'react'; +import styled from 'styled-components'; +import DropDownMenu from '.'; + +export default { + title: 'DropDownMenu' +}; + +const Box = styled.div` + display: flex; + flex-direction: row; +`; + +const Button = styled.button` + padding: 2rem; + width: 10rem; + height: 4rem; + background-color: #5b5b5b; +`; + +export const dropDownMenu = () => { + const menuItems = [ + { + value: 'test1', + onClick: () => alert('test1') + }, + { + value: 'test2', + onClick: () => alert('test2') + }, + { + value: 'test3', + onClick: () => alert('test3') + }, + { + value: 'test4', + onClick: () => alert('test4') + }, + { + value: 'test5', + onClick: () => alert('test5') + } + ]; + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/cocode/src/components/DropDownMenu/style.js b/cocode/src/components/DropDownMenu/style.js new file mode 100644 index 00000000..3f1f48e6 --- /dev/null +++ b/cocode/src/components/DropDownMenu/style.js @@ -0,0 +1,51 @@ +import styled from 'styled-components'; + +const BUTTON_COLOR = '#2b2b2b'; +const BUTTON_COLOR_HOVER = '#4b4b4b'; +const BUTTON_BOUNDARY = '#383838'; + +const DropDownMenu = styled.div` + & { + display: flex; + justify-content: flex-end; + + position: relative; + } +`; + +const DropDownList = styled.ul` + & { + display: flex; + flex-direction: column; + + position: absolute; + + top: 100%; + padding: 0; + margin: 0; + } +`; + +const DropDownItem = styled.button` + & { + height: 2.5rem; + width: 8rem; + padding: 0.25rem 1rem; + z-index: 1; + + font-size: 1.5rem; + vertical-align: center; + text-align: right; + + background-color: ${BUTTON_COLOR}; + + border: none; + border-top: solid ${BUTTON_BOUNDARY}; + } + &:hover { + background-color: ${BUTTON_COLOR_HOVER}; + cursor: pointer; + } +`; + +export { DropDownMenu, DropDownList, DropDownItem }; diff --git a/cocode/src/components/FileTab/index.js b/cocode/src/components/FileTab/index.js new file mode 100644 index 00000000..279e6443 --- /dev/null +++ b/cocode/src/components/FileTab/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import * as Styled from './style'; + +function FileTab({ index, FileName, icon, type, className, onClick }) { + const handleTabClick = () => onClick(index); + + return ( + + + {FileName} + + ); +} + +export default FileTab; \ No newline at end of file diff --git a/cocode/src/components/FileTab/style.js b/cocode/src/components/FileTab/style.js new file mode 100644 index 00000000..017cd313 --- /dev/null +++ b/cocode/src/components/FileTab/style.js @@ -0,0 +1,37 @@ +import styled from 'styled-components'; + +//TODO 나중에 테마로 분리할 계획입니다. +const EDITOR_DARK_COLOR = '#111518'; + +const Tab = styled.li` + & { + padding: 0.8rem; + display: inline-flex; + background-color: ${EDITOR_DARK_COLOR}; + font-size: 0.8rem; + cursor: pointer; + } + + &:after { + content: 'X'; + font-weight: 800; + margin-left: 0.8rem; + visibility: hidden; + } + + &:hover { + &:after { + visibility: visible; + } + } +`; + +const Icon = styled.img` + & { + width: 1.2rem; + height: 1.2rem; + margin-right: 0.3rem; + } +`; + +export { Icon, Tab }; \ No newline at end of file diff --git a/cocode/src/components/FileTabBar/index.js b/cocode/src/components/FileTabBar/index.js new file mode 100644 index 00000000..4def0067 --- /dev/null +++ b/cocode/src/components/FileTabBar/index.js @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import * as Styled from './style'; +import FileTab from '../FileTab'; + +const DEFAULT_OPENED_FILE_INDEX = 0; + +function FileTabBar() { + const [ clickedIndex, setClickedIndex ] = useState(DEFAULT_OPENED_FILE_INDEX); + + const files = [ + { + name: 'index.html', + type: 'html', + icon: 'https://cdn.jsdelivr.net/gh/PKief/vscode-material-icon-theme@master/icons/html.svg' + }, + { + name: 'index.js', + type: 'js', + icon: 'https://cdn.jsdelivr.net/gh/PKief/vscode-material-icon-theme@master/icons/javascript.svg' + }, + { + name: 'app.js', + type: 'js', + icon: 'https://cdn.jsdelivr.net/gh/PKief/vscode-material-icon-theme@master/icons/javascript.svg' + }, + { + name: 'app.css', + type: 'css', + icon: 'https://cdn.jsdelivr.net/gh/PKief/vscode-material-icon-theme@master/icons/css.svg' + }, + ]; + + const handleSetClickedIndex = (index) => setClickedIndex(index); + + return ( + + {files.map(({ name, icon, type }, index) => { + return ( + + ); + })} + + ); +} + +export default FileTabBar; \ No newline at end of file diff --git a/cocode/src/components/FileTabBar/style.js b/cocode/src/components/FileTabBar/style.js new file mode 100644 index 00000000..b0981d2b --- /dev/null +++ b/cocode/src/components/FileTabBar/style.js @@ -0,0 +1,23 @@ +import styled from 'styled-components'; + +//TODO 나중에 테마로 분리할 계획입니다. +const EDITOR_MAIN_COLOR = '#1E2022'; + +const TabBar = styled.ul` + & { + width: 100%; + list-style: none; + display: inline-flex; + overflow: scroll; + } + + .clicked { + background-color: ${EDITOR_MAIN_COLOR}; + + &:after { + visibility: visible; + } + } +`; + +export { TabBar }; \ No newline at end of file diff --git a/cocode/src/components/GlobalStyle/index.js b/cocode/src/components/GlobalStyle/index.js index 4e1713a1..99644b7c 100644 --- a/cocode/src/components/GlobalStyle/index.js +++ b/cocode/src/components/GlobalStyle/index.js @@ -1,6 +1,34 @@ import { createGlobalStyle } from 'styled-components'; const GlobalStyle = createGlobalStyle` + ::-webkit-scrollbar { + width: 10px; + height: 5px + } + + ::-webkit-scrollbar-track { + background-color: transparent + } + + ::-webkit-scrollbar-thumb { + background-color: #2d2d2d; + border-radius: 5px + } + + ::-webkit-scrollbar-thumb:hover { + background: #4A4A4A + } + + ::-webkit-scrollbar-button:horizontal:decrement, + ::-webkit-scrollbar-button:horizontal:increment { + width: 0px; + height: 0px + } + + ::-webkit-scrollbar-corner { + background-color: transparent + } + * { font-family: 'Source Sans Pro', sans-serif; text-decoration: none; @@ -23,6 +51,14 @@ const GlobalStyle = createGlobalStyle` font-size: 16px; } + body { + overflow: overlay; + } + + #root { + height: 100%; + } + button { cursor: pointer; color: ${({ theme }) => theme.textColor}; diff --git a/cocode/src/components/LoginModalBody/github.svg b/cocode/src/components/LoginModalBody/github.svg new file mode 100644 index 00000000..3244fa6a --- /dev/null +++ b/cocode/src/components/LoginModalBody/github.svg @@ -0,0 +1,16 @@ + + + + Fill 1 + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/cocode/src/components/LoginModalBody/index.js b/cocode/src/components/LoginModalBody/index.js index 73f8cc72..dfd2de4f 100644 --- a/cocode/src/components/LoginModalBody/index.js +++ b/cocode/src/components/LoginModalBody/index.js @@ -1,11 +1,14 @@ import React from 'react'; import * as Styled from './style'; +import Github from './github.svg'; + function LoginModalBody({ onClickLoginButton }) { return ( Sign In + Sign In With GitHub diff --git a/cocode/src/components/LoginModalBody/style.js b/cocode/src/components/LoginModalBody/style.js index 3eff66f2..ed794a33 100644 --- a/cocode/src/components/LoginModalBody/style.js +++ b/cocode/src/components/LoginModalBody/style.js @@ -1,5 +1,9 @@ import styled from 'styled-components'; +const Logo = styled.img` + padding-right: 0.8rem; +`; + const LoginModalBody = styled.div` & { display: flex; @@ -24,10 +28,14 @@ const LoginModalBodyButton = styled.button` font-size: 1.25rem; - color: white; background-color: black; + opacity: 0.85; border-radius: 0.5rem; } + + &:hover { + opacity: 1; + } `; -export { LoginModalBody, LoginModalBodyTitle, LoginModalBodyButton }; +export { Logo, LoginModalBody, LoginModalBodyTitle, LoginModalBodyButton }; diff --git a/cocode/src/components/Logo/logo.svg b/cocode/src/components/Logo/logo.svg index bf1c12ee..d1b22e56 100644 --- a/cocode/src/components/Logo/logo.svg +++ b/cocode/src/components/Logo/logo.svg @@ -1,25 +1,19 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - \ No newline at end of file diff --git a/cocode/src/components/Modal/style.js b/cocode/src/components/Modal/style.js index 9cf015df..5ed807dd 100644 --- a/cocode/src/components/Modal/style.js +++ b/cocode/src/components/Modal/style.js @@ -12,7 +12,7 @@ const ModalBackGround = styled.div` width: 100%; height: 100%; - background-color: rgba(0, 0, 0, 0.3); + background-color: ${({ theme }) => theme.blackOpaqueColor}; } `; diff --git a/cocode/src/components/ModalPortal/index.js b/cocode/src/components/ModalPortal/index.js index ec1d2b91..ec0f02a7 100644 --- a/cocode/src/components/ModalPortal/index.js +++ b/cocode/src/components/ModalPortal/index.js @@ -1,6 +1,8 @@ import ReactDOM from 'react-dom'; const ModalPortal = ({ children }) => { + const root = document.getElementById('root'); + root.style.overflow = 'hidden'; const modalElement = document.getElementById('modal'); return ReactDOM.createPortal(children, modalElement); }; diff --git a/cocode/src/components/MonacoEditor/index.js b/cocode/src/components/MonacoEditor/index.js new file mode 100644 index 00000000..feb2b5af --- /dev/null +++ b/cocode/src/components/MonacoEditor/index.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { ControlledEditor } from '@monaco-editor/react'; +import * as Styled from './style'; + +function MonacoEditor({ code, onChange, ...props }) { + return ( + + + + ); +} + +export default MonacoEditor; diff --git a/cocode/src/components/MonacoEditor/index.stories.js b/cocode/src/components/MonacoEditor/index.stories.js new file mode 100644 index 00000000..1746a4cc --- /dev/null +++ b/cocode/src/components/MonacoEditor/index.stories.js @@ -0,0 +1,13 @@ +import React from 'react'; + +import MonacoEditor from '.'; + +export default { + title: 'MonacoEditor' +}; + +function Editor() { + return ; +} + +export { Editor }; diff --git a/cocode/src/components/MonacoEditor/style.js b/cocode/src/components/MonacoEditor/style.js new file mode 100644 index 00000000..0400d99c --- /dev/null +++ b/cocode/src/components/MonacoEditor/style.js @@ -0,0 +1,22 @@ +import styled from 'styled-components'; + +//TODO 나중에 테마로 분리할 계획입니다. +const EDITOR_MAIN_COLOR = '#1E2022'; +const EDITOR_CURRENT_LINT_COLOR = '#2a2f32'; + +const MonacoEditor = styled.div` + .monaco-editor-background, .margin { + background-color: ${EDITOR_MAIN_COLOR} !important; + } + + .scroll-decoration { + box-shadow: none !important; + } + + .monaco-editor .view-overlays .current-line { + border: ${EDITOR_CURRENT_LINT_COLOR}; + background-color: ${EDITOR_CURRENT_LINT_COLOR}; + } +`; + +export { MonacoEditor }; \ No newline at end of file diff --git a/cocode/src/components/ProjectIcon/index.js b/cocode/src/components/ProjectIcon/index.js new file mode 100644 index 00000000..a444df35 --- /dev/null +++ b/cocode/src/components/ProjectIcon/index.js @@ -0,0 +1,42 @@ +import React from 'react'; +import * as Styled from './style'; + +function Project({ fillColor }) { + return ( + + + + + + + + + + + ); +} + +export default Project; diff --git a/cocode/src/components/ProjectIcon/style.js b/cocode/src/components/ProjectIcon/style.js new file mode 100644 index 00000000..90d45510 --- /dev/null +++ b/cocode/src/components/ProjectIcon/style.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +const Svg = styled.svg` + .Target { + fill: ${({ fillColor }) => fillColor}; + stroke: ${({ fillColor }) => fillColor}; + } +`; + +export { Svg }; diff --git a/cocode/src/components/ReactLogo/index.js b/cocode/src/components/ReactLogo/index.js index fce47492..caefaec6 100644 --- a/cocode/src/components/ReactLogo/index.js +++ b/cocode/src/components/ReactLogo/index.js @@ -4,10 +4,10 @@ import logo from './react.svg'; function ReactLogo({ className }) { return ( -
+ -
+ ); } diff --git a/cocode/src/components/ReactLogo/style.js b/cocode/src/components/ReactLogo/style.js index 94e59235..6ff11cd2 100644 --- a/cocode/src/components/ReactLogo/style.js +++ b/cocode/src/components/ReactLogo/style.js @@ -1,5 +1,11 @@ import styled from 'styled-components'; +const Logo = styled.article` + position: relative; + width: 25rem; + height: 25rem; +`; + const Image = styled.img` position: absolute; width: 25rem; @@ -7,9 +13,10 @@ const Image = styled.img` `; const Blur = styled.img` + position: absolute; width: 25rem; height: 25rem; filter: blur(3rem); `; -export { Image, Blur }; \ No newline at end of file +export { Logo, Image, Blur }; \ No newline at end of file diff --git a/cocode/src/components/TabBar/index.js b/cocode/src/components/TabBar/index.js new file mode 100644 index 00000000..89e98f51 --- /dev/null +++ b/cocode/src/components/TabBar/index.js @@ -0,0 +1,16 @@ +import React from 'react'; +import * as Styled from './style'; + +import ProjectIcon from 'components/ProjectIcon'; + +function TabBar({ theme }) { + return ( + + + + + + ); +} + +export default TabBar; diff --git a/cocode/src/components/TabBar/style.js b/cocode/src/components/TabBar/style.js new file mode 100644 index 00000000..c1b3c549 --- /dev/null +++ b/cocode/src/components/TabBar/style.js @@ -0,0 +1,19 @@ +import styled from 'styled-components'; + +const TabBar = styled.nav` + & { + display: inline-flex; + flex-direction: column; + justify-content: flex-start; + + background-color: ${({ tabBarBGColor }) => tabBarBGColor}; + } +`; + +const TabBarItem = styled.button` + & { + margin: 1rem; + } +`; + +export { TabBar, TabBarItem }; diff --git a/cocode/src/constants/theme.js b/cocode/src/constants/theme.js index 957673f5..0ccfde8e 100644 --- a/cocode/src/constants/theme.js +++ b/cocode/src/constants/theme.js @@ -2,6 +2,7 @@ const DEFAULT_THEME = { mainColor: '#2accf9', mainOpaqueColor: '#2accf9b3', backgroundColor: '#161419', + blackOpaqueColor: '#000000b3', textColor: '#ffffff' }; @@ -13,4 +14,23 @@ const BROWSER_THEME = { browserHeignt: '88.8vh' }; -export { DEFAULT_THEME, BROWSER_THEME }; +const TAB_CONTAINER_THEME = { + tabContainerBGColor: '#0e0f10', + tabContainerTitleColor: '#7E7E7E', + tabContainerFileTextColor: '#878788', + tabContainerFileHoverTextColor: '#fff', + tabContainerFileHoverBGColor: '#2accf944', + + tabContainerTitleSize: '1.25rem', + tabContainerFileTextSize: '1rem', + + tabContainerTitleWeight: '600' +}; + +const TAB_BAR_THEME = { + tabBarBGColor: '#1d2022', + tabBarItemBGColor: '#A5A6A7', + tabBarSelectedItemBGColor: '#fff' +}; + +export { DEFAULT_THEME, BROWSER_THEME, TAB_BAR_THEME, TAB_CONTAINER_THEME }; diff --git a/cocode/src/containers/AboutCocode/style.js b/cocode/src/containers/AboutCocode/style.js index 9752d348..faf375ad 100644 --- a/cocode/src/containers/AboutCocode/style.js +++ b/cocode/src/containers/AboutCocode/style.js @@ -15,7 +15,7 @@ const DescriptionPhrase = styled.h1` & { text-align: center; - font-size: 3rem; + font-size: 2.8rem; font-weight: lighter; } diff --git a/cocode/src/containers/AboutUs/style.js b/cocode/src/containers/AboutUs/style.js index b04cdb56..6f20003f 100644 --- a/cocode/src/containers/AboutUs/style.js +++ b/cocode/src/containers/AboutUs/style.js @@ -9,7 +9,7 @@ const AboutUs = styled.section` flex-direction: column; justify-content: center; - padding: 5rem 10rem; + padding: 5rem 8rem; } .AboutUs-item { @@ -21,7 +21,7 @@ const AboutUsTitle = styled.h1` & { text-align: center; - font-size: 3rem; + font-size: 2.8rem; font-weight: lighter; } @@ -51,11 +51,11 @@ const AboutUsProfileCard = styled.div` const AboutUsProfileImage = styled.img` & { - height: 11rem; - width: 11rem; + height: 9.8rem; + width: 9.8rem; padding: 0.5rem; - margin-bottom: 1.5rem; + margin-bottom: 1.3rem; } `; @@ -63,7 +63,7 @@ const AboutUsProfileName = styled.h2` & { text-align: center; - font-size: 1.5rem; + font-size: 1.3rem; font-weight: 100; } `; @@ -74,7 +74,7 @@ const AboutUsProfileLink = styled.a` text-decoration: none; color: ${({ theme }) => theme.textColor}; - font-size: 1.5rem; + font-size: 1.3rem; font-weight: 100; } diff --git a/cocode/src/containers/Editor/index.js b/cocode/src/containers/Editor/index.js new file mode 100644 index 00000000..49235887 --- /dev/null +++ b/cocode/src/containers/Editor/index.js @@ -0,0 +1,31 @@ +import React, { useContext } from 'react'; +import * as Styled from './style'; + +import FileTabBar from 'components/FileTabBar'; +import MonacoEditor from 'components/MonacoEditor'; + +import ProjectContext from 'contexts/ProjectContext'; +import { updateCodeActionCreator } from 'actions/Project'; + +function Editor() { + const { project, dispatchProject } = useContext(ProjectContext); + const { code } = project; + + const handleChangeCode = (_, changedCode) => { + const updateCodeAction = updateCodeActionCreator(changedCode); + dispatchProject(updateCodeAction); + }; + + return ( + + + + + ); +} + +export default Editor; diff --git a/cocode/src/containers/Editor/style.js b/cocode/src/containers/Editor/style.js new file mode 100644 index 00000000..cc218ed7 --- /dev/null +++ b/cocode/src/containers/Editor/style.js @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +const Editor = styled.section` + & { + display: flex; + flex-direction: column; + + /* temp width */ + width: 30rem; + } + + .Stretch-width { + flex-grow: 2; + } +`; + +export { Editor }; diff --git a/cocode/src/containers/Header/index.js b/cocode/src/containers/Header/index.js index 71dd3755..715be341 100644 --- a/cocode/src/containers/Header/index.js +++ b/cocode/src/containers/Header/index.js @@ -9,7 +9,11 @@ import LoginModalBody from 'components/LoginModalBody'; function Header() { const [isSignInModalOpen, setIsSignInModalOpen] = useState(false); const handleOpenSignInModal = () => setIsSignInModalOpen(true); - const handleCloseSignInModal = () => setIsSignInModalOpen(false); + const handleCloseSignInModal = () => { + const root = document.getElementById('root'); + root.style.overflow = 'overlay'; + setIsSignInModalOpen(false); + }; return ( diff --git a/cocode/src/containers/Header/style.js b/cocode/src/containers/Header/style.js index 769b1bf6..8530aebb 100644 --- a/cocode/src/containers/Header/style.js +++ b/cocode/src/containers/Header/style.js @@ -1,20 +1,24 @@ import styled from 'styled-components'; const Header = styled.header` - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - height: 11.2vh; - - background-color: ${({ theme }) => theme.backgroundColor}; - padding: 1rem 2rem; + & { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + height: 12vh; + + background-color: ${({ theme }) => theme.backgroundColor}; + padding: 2rem 2.3rem; + } `; const SignInButton = styled.button` - font-size: 1.5rem; - font-weight: 100; + & { + font-size: 1.4rem; + font-weight: 100; + } &:hover { font-weight: 400; diff --git a/cocode/src/containers/Header/test.js b/cocode/src/containers/Header/test.js index d41412ed..d3f49b45 100644 --- a/cocode/src/containers/Header/test.js +++ b/cocode/src/containers/Header/test.js @@ -23,6 +23,14 @@ describe('Login modal behavior test', () => { }); function prepareForReactPortal() { + let rootElement = document.getElementById('root'); + if (!rootElement) { + rootElement = document.createElement('div'); + rootElement.setAttribute('id', 'root'); + rootElement.setAttribute('style', '{ overflow: hidden; }'); + document.body.appendChild(rootElement); + } + let modalElement = document.getElementById('modal'); if (!modalElement) { modalElement = document.createElement('div'); diff --git a/cocode/src/containers/Main/style.js b/cocode/src/containers/Main/style.js index 6bf755a9..bd7f09db 100644 --- a/cocode/src/containers/Main/style.js +++ b/cocode/src/containers/Main/style.js @@ -2,7 +2,7 @@ import styled from 'styled-components'; const Main = styled.section` & { - height: 88.8vh; + height: 88vh; display: flex; margin: 0 8rem; } @@ -35,7 +35,7 @@ const Title = styled.h1` const SubTitle = styled.h2` & { - font-size: 3rem; + font-size: 2.8rem; font-weight: 200; } diff --git a/cocode/src/containers/ProjectTab/index.js b/cocode/src/containers/ProjectTab/index.js new file mode 100644 index 00000000..1f713176 --- /dev/null +++ b/cocode/src/containers/ProjectTab/index.js @@ -0,0 +1,44 @@ +import React from 'react'; +import * as Styled from './style'; + +const TabTitle = 'EXPLOLER'; + +const mockData = [ + { + type: 'folder', + src: 'https://codesandbox.io/static/media/folder.30a30d83.svg', + depth: 1, + name: 'public' + }, + { + type: 'folder_open', + src: 'https://codesandbox.io/static/media/folder-open.df474ba4.svg', + depth: 1, + name: 'src' + }, + { + type: 'javascript', + src: + 'https://cdn.jsdelivr.net/gh/PKief/vscode-material-icon-theme@master/icons/javascript.svg', + depth: 2, + name: 'index.js' + } +]; + +function ProjectTab() { + return ( + + {TabTitle} + {mockData.map(({ type, src, depth, name }, index) => { + return ( + + + {name} + + ); + })} + + ); +} + +export default ProjectTab; diff --git a/cocode/src/containers/ProjectTab/style.js b/cocode/src/containers/ProjectTab/style.js new file mode 100644 index 00000000..98fc843d --- /dev/null +++ b/cocode/src/containers/ProjectTab/style.js @@ -0,0 +1,58 @@ +import styled from 'styled-components'; +import { TAB_CONTAINER_THEME } from 'constants/theme'; + +const ProjectTab = styled.section` + & { + /* temp width */ + width: 15rem; + + background-color: ${TAB_CONTAINER_THEME.tabContainerBGColor}; + } +`; + +const Title = styled.h1` + & { + padding: 0.7rem 1rem; + + color: ${TAB_CONTAINER_THEME.tabContainerTitleColor}; + font-size: ${TAB_CONTAINER_THEME.tabContainerTitleSize}; + font-weight: ${TAB_CONTAINER_THEME.tabContainerTitleWeight}; + } +`; + +const Icon = styled.img` + & { + margin-right: 0.5rem; + + width: ${TAB_CONTAINER_THEME.tabContainerFileTextSize}; + height: ${TAB_CONTAINER_THEME.tabContainerFileTextSize}; + } +`; + +const File = styled.div` + & { + display: flex; + flex-direction: row; + align-items: center; + + padding: 0.4rem; + padding-left: ${({ depth }) => `${depth}rem`}; + + cursor: pointer; + + font { + font-size: ${TAB_CONTAINER_THEME.tabContainerFileTextSize}; + color: ${TAB_CONTAINER_THEME.tabContainerFileTextColor}; + } + } + + &:hover { + background-color: ${TAB_CONTAINER_THEME.tabContainerFileHoverBGColor}; + + font { + color: ${TAB_CONTAINER_THEME.tabContainerFileHoverTextColor}; + } + } +`; + +export { ProjectTab, Title, Icon, File }; diff --git a/cocode/src/contexts/ProjectContext.js b/cocode/src/contexts/ProjectContext.js new file mode 100644 index 00000000..73a87ee8 --- /dev/null +++ b/cocode/src/contexts/ProjectContext.js @@ -0,0 +1,9 @@ +import PropTypes from 'prop-types'; +import { createContext } from 'react'; + +const ProjectContext = createContext(); +ProjectContext.propTypes = { + code: PropTypes.string +}; + +export default ProjectContext; diff --git a/cocode/src/pages/Project/index.js b/cocode/src/pages/Project/index.js index c2e0ca41..f6b52ea2 100644 --- a/cocode/src/pages/Project/index.js +++ b/cocode/src/pages/Project/index.js @@ -1,14 +1,42 @@ -import React from 'react'; +import React, { useReducer, useEffect } from 'react'; +import * as Styled from './style'; + +import Header from 'containers/Header'; +import TabBar from 'components/TabBar'; +import ProjectTab from 'containers/ProjectTab'; +import Editor from 'containers/Editor'; +import BrowserV1 from 'components/BrowserV1'; + +import ProjectReducer from 'reducers/ProjectReducer'; +import ProjectContext from 'contexts/ProjectContext'; +import { fetchProjectActionCreator } from 'actions/Project'; + +import { TAB_BAR_THEME } from 'constants/theme'; function Project() { + const [project, dispatchProject] = useReducer(ProjectReducer, {}); + + const handleFetchProject = () => { + const fetchProjectAction = fetchProjectActionCreator(); + dispatchProject(fetchProjectAction); + }; + + useEffect(handleFetchProject, []); + return ( - <> -
-

Hello! Project!!

-
-
-
- + +
+ + + + + + + ); } diff --git a/cocode/src/pages/Project/style.js b/cocode/src/pages/Project/style.js new file mode 100644 index 00000000..565a0f51 --- /dev/null +++ b/cocode/src/pages/Project/style.js @@ -0,0 +1,16 @@ +import styled from 'styled-components'; + +const Main = styled.main` + & { + display: flex; + flex-direction: row; + + height: 88.8vh; + + .Project-main-stretch { + flex-grow: 2; + } + } +`; + +export { Main }; diff --git a/cocode/src/reducers/ProjectReducer.js b/cocode/src/reducers/ProjectReducer.js new file mode 100644 index 00000000..131ef792 --- /dev/null +++ b/cocode/src/reducers/ProjectReducer.js @@ -0,0 +1,34 @@ +import { UPDATE_CODE, FETCH_PROJECT } from 'actions/Project'; + +const INITIAL_CODE = `const { useState } = React; + +function App() { + const [state, setState] = useState('Cocode'); + + return( + <> +

Hi! {state}

+ + ) +} + +ReactDOM.render(, document.getElementById('coconut-root')); +`; + +function ProjectReducer(state, { type, payload }) { + switch (type) { + case UPDATE_CODE: { + return { ...state, code: payload }; + } + case FETCH_PROJECT: { + // TODO: API server에 fetch 요청 보내서 가져오기 + const fetchedProject = { code: INITIAL_CODE }; + return fetchedProject; + } + default: { + throw new Error(`unexpected action.type: ${type}`); + } + } +} + +export default ProjectReducer; diff --git a/cocode/yarn.lock b/cocode/yarn.lock index 3578c343..84d2c5c2 100644 --- a/cocode/yarn.lock +++ b/cocode/yarn.lock @@ -1444,6 +1444,11 @@ prop-types "^15.7.2" react-is "^16.8.6" +"@monaco-editor/react@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-2.3.0.tgz#ef1e09c408bb3119e2dc0d369b132e82b2d3ade7" + integrity sha512-jmmZCQ4iSMfwelWGRV4HWUOJchkN4MOx9vhx1DWvC6ERpvK5DXrcwJBBzuayVtiK7cyCVOGKB7mgjT7KOdUkJw== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"