Преглед изворни кода

update penPage and button SAVE

yankevych0210 пре 1 година
родитељ
комит
49c0e6c6dc

+ 0 - 1
src/assets/img/menuSmall.svg

@@ -1 +0,0 @@
-<svg viewBox="0 0 29 7"><circle cx="3.5" cy="3.5" r="3.5"></circle><circle cx="14.5" cy="3.5" r="3.5"></circle><circle cx="25.5" cy="3.5" r="3.5"></circle></svg>

+ 9 - 4
src/components/common/Editor/Editor.jsx

@@ -8,18 +8,21 @@ import { Controlled as ControlledEditor } from "react-codemirror2";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { faCompressAlt, faExpandAlt } from "@fortawesome/free-solid-svg-icons";
 import "./pen.css";
+import { useDispatch } from "react-redux";
+import style from "./Editor.module.scss";
 
 export default function Editor(props) {
   const { language, displayName, value, onChange } = props;
   const [open, setOpen] = useState(true);
+  const dispatch = useDispatch();
 
   function handleChange(editor, data, value) {
-    onChange(value);
+    dispatch(onChange(value));
   }
 
   return (
-    <div className={`editor-container ${open ? "" : "collapsed"}`}>
-      <div className="editor-title">
+    <div className={open ? style.editorOpen : style.collapsed}>
+      <div className={style.header}>
         {displayName}
         <button
           type="button"
@@ -32,13 +35,15 @@ export default function Editor(props) {
       <ControlledEditor
         onBeforeChange={handleChange}
         value={value}
-        className="code-mirror-wrapper"
+        className={style.codeMirrorWrapper}
         options={{
           lineWrapping: true,
           lint: true,
           mode: language,
           theme: "material",
           lineNumbers: true,
+          autoCorrect: true,
+          autocapitalize: true,
         }}
       />
     </div>

+ 29 - 0
src/components/common/Editor/Editor.module.scss

@@ -0,0 +1,29 @@
+.editorOpen {
+  flex-grow: 1;
+  flex-basis: 0;
+  display: flex;
+  flex-direction: column;
+  margin: 0 7px;
+  background-color: black;
+  border-left: 1px solid #2f2f2f;
+  border-right: 1px solid #2f2f2f;
+
+  .header {
+    display: flex;
+    justify-content: space-between;
+    background-color: black;
+    color: white;
+    padding: 0.5rem 0.5rem 0.5rem 1rem;
+    // background-color: red;
+  }
+
+  .codeMirrorWrapper {
+    flex-grow: 1;
+    overflow: hidden;
+  }
+}
+
+.collapsed {
+  @extend .editorOpen;
+  flex-grow: 0;
+}

+ 0 - 43
src/components/common/Editor/pen.css

@@ -1,29 +1,3 @@
-body {
-  margin: 0;
-}
-
-.top-pane {
-  background-color: hsl(225, 6%, 25%);
-}
-
-.pane {
-  height: 50vh;
-  display: flex;
-}
-
-.editor-container {
-  flex-grow: 1;
-  flex-basis: 0;
-  display: flex;
-  flex-direction: column;
-  padding: 0.5rem;
-  background-color: hsl(225, 6%, 25%);
-}
-
-.editor-container.collapsed {
-  flex-grow: 0;
-}
-
 .editor-container.collapsed .CodeMirror-scroll {
   position: absolute;
   overflow: hidden !important;
@@ -37,23 +11,6 @@ body {
   cursor: pointer;
 }
 
-.editor-title {
-  display: flex;
-  justify-content: space-between;
-  background-color: hsl(225, 6%, 13%);
-  color: white;
-  padding: 0.5rem 0.5rem 0.5rem 1rem;
-  border-top-right-radius: 0.5rem;
-  border-top-left-radius: 0.5rem;
-}
-
 .CodeMirror {
   height: 100% !important;
 }
-
-.code-mirror-wrapper {
-  flex-grow: 1;
-  border-bottom-right-radius: 0.5rem;
-  border-bottom-left-radius: 0.5rem;
-  overflow: hidden;
-}

+ 1 - 1
src/components/common/Header/Header.jsx

@@ -1,4 +1,4 @@
-import { NavLink } from "react-router-dom";
+import { NavLink, useLocation } from "react-router-dom";
 import style from "./Header.module.scss";
 import { ReactComponent as LogoBig } from "../../../assets/img/logoBig.svg";
 import { useDispatch, useSelector } from "react-redux";

+ 0 - 53
src/components/common/Header/Header.module.scss

@@ -1,63 +1,10 @@
 @import "../../../scss/index.scss";
 
-// .header {
-//   @include container;
-//   @include flex($align: center, $justify: space-between);
-
-//   padding: 20px 16px;
-//   height: 50px;
-
-//   &::before {
-//     width: 100%;
-//     height: 50px;
-//     position: absolute;
-//     top: 0;
-//     right: 0;
-//     background-color: black;
-//     border-bottom: 1px solid #2f2f2f;
-//     z-index: 2;
-//   }
-
-//   .logoBlock {
-//     display: flex;
-//     align-items: center;
-//     svg {
-//       width: 150px;
-//       height: auto;
-//     }
-//   }
-
-//   nav {
-//     a:first-child {
-//       @extend %buttonGrey;
-//       padding: 13px 16px;
-//     }
-
-//     a:last-child {
-//       @extend %buttonGreen;
-//       margin-left: 10px;
-//       padding: 13px 16px;
-//     }
-//   }
-// }
-
 .header {
   @include container();
   @include flex($justify: space-between, $align: center);
   padding: 25px 0;
 
-  // &:before {
-  //   content: "";
-  //   display: block;
-  //   height: 80px;
-  //   width: 100vw;
-  //   position: absolute;
-  //   top: 0;
-  //   left: 0;
-  //   background-color: grey;
-  //   z-index: -1;
-  // }
-
   a {
     svg {
       @extend %logo;

+ 51 - 0
src/components/common/HeaderPen/HeaderPen.jsx

@@ -0,0 +1,51 @@
+import React from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { ReactComponent as Logo } from "../../../assets/img/logo.svg";
+import { NavLink } from "react-router-dom";
+import style from "./HeaderPen.module.scss";
+
+export const HeaderPen = ({ onSave, workTitle, workOwner }) => {
+  const dispatch = useDispatch();
+  const { isLogged } = useSelector((state) => state.auth);
+
+  const logout = () => {
+    localStorage.removeItem("authToken");
+    dispatch(logout());
+  };
+
+  return (
+    <header className={style.header}>
+      <div className={style.logoBlock}>
+        <NavLink to="/">
+          <Logo />
+        </NavLink>
+        <div className={style.workInfo}>
+          <h1>{workTitle}</h1>
+          <span>{workOwner}</span>
+        </div>
+      </div>
+
+      <nav>
+        <button onClick={() => onSave()}>Save</button>
+
+        {isLogged ? (
+          <>
+            <NavLink to="/your-works">Your works</NavLink>
+            <NavLink
+              style={{ backgroundColor: "#dc143c" }}
+              onClick={logout}
+              to="/"
+            >
+              Log out
+            </NavLink>
+          </>
+        ) : (
+          <>
+            <NavLink to="/login">Log in</NavLink>
+            <NavLink to="/signup">Sign up</NavLink>
+          </>
+        )}
+      </nav>
+    </header>
+  );
+};

+ 81 - 0
src/components/common/HeaderPen/HeaderPen.module.scss

@@ -0,0 +1,81 @@
+@import "../../../scss/index.scss";
+
+.header {
+  @include container($width: 98vw);
+  @include flex($justify: space-between, $align: center);
+  height: 65px;
+
+  &::before {
+    content: "";
+    display: block;
+    background-color: black;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: inherit;
+    border-bottom: 1px solid #2f2f2f;
+  }
+
+  .logoBlock {
+    height: 100%;
+    @include flex($justify: space-between, $align: center);
+    width: fit-content;
+
+    svg {
+      position: relative;
+      width: 35px;
+      @extend %logo;
+      fill: #fff;
+      z-index: 10 !important;
+    }
+
+    .workInfo {
+      text-align: start;
+      margin-left: 10px;
+      position: relative;
+      color: white;
+      @include flex(
+        $direction: column,
+        $justify: space-between,
+        $align: center
+      );
+      h1 {
+        width: 100%;
+        font-size: 1.2rem;
+        font-weight: 700;
+        color: white;
+      }
+
+      span {
+        color: #9b9eae;
+        font-size: 0.9rem;
+        text-transform: none;
+        letter-spacing: 0;
+        text-align: start;
+        width: 100%;
+      }
+    }
+  }
+
+  nav {
+    z-index: 0;
+    button:first-of-type {
+      @extend %buttonGrey;
+      font-size: 16.5px;
+      padding: 13px 16px;
+    }
+
+    a:first-of-type {
+      @extend %buttonGrey;
+      padding: 13px 16px;
+      margin: 0 10px;
+    }
+
+    a:last-child {
+      @extend %buttonGreen;
+
+      padding: 13px 16px;
+    }
+  }
+}

+ 31 - 23
src/components/pages/PenPage/PenPage.jsx

@@ -1,5 +1,4 @@
-import React, { useEffect, useState } from "react";
-import { Header } from "../../common/Header/Header";
+import React, { useEffect } from "react";
 import Editor from "../../common/Editor/Editor";
 import "../../common/Editor/pen.css";
 import { Preview } from "../../common/Preview/Preview";
@@ -8,59 +7,68 @@ import { fetchCurrentWork } from "../../../store/currentWork/actions/fetchCurren
 import { useParams } from "react-router-dom";
 import { LoadingPage } from "../LoadingPage/LoadingPage";
 import { saveFiles } from "../../../store/currentWork/actions/saveFiles";
+import { HeaderPen } from "../../common/HeaderPen/HeaderPen";
+import style from "./PenPage.module.scss";
+import {
+  setHtml,
+  setCss,
+  setJs,
+} from "../../../store/currentWork/currentWorkSlice";
 
 export const PenPage = () => {
-  const { currentWork, isLoading, error } = useSelector(
-    (state) => state.currentWork
-  );
   const dispatch = useDispatch();
-  const [html, setHtml] = useState("");
-  const [css, setCss] = useState("");
-  const [js, setJs] = useState("");
   const { id } = useParams();
+  const { title, owner, files, isLoading, error } = useSelector(
+    (state) => state.currentWork
+  );
+  const [html, css, js] = files;
 
   useEffect(() => {
     dispatch(fetchCurrentWork(id));
   }, []);
 
-  useEffect(() => {
-    const [HTML, CSS, JS] = currentWork.files;
-    setHtml(HTML.text);
-    setCss(CSS.text);
-    setJs(JS.text);
-  }, [currentWork.files]);
+  const handleSave = () => {
+    const newFiles = {
+      id,
+      html: html.text,
+      css: css.text,
+      js: js.text,
+    };
 
-  const handleUpdate = () => {
-    dispatch(saveFiles({ id, html, css, js }));
+    dispatch(saveFiles(newFiles));
   };
 
   if (isLoading) return <LoadingPage />;
   return (
     <>
-      <Header />
-      <button onClick={handleUpdate}>save</button>
-      <div className="pane top-pane">
+      <HeaderPen
+        workTitle={title}
+        onSave={handleSave}
+        workOwner={owner.login}
+      />
+
+      <div className={style.editors}>
         <Editor
           language="xml"
           displayName="HTML"
-          value={html}
+          value={html.text}
           onChange={setHtml}
         />
         <Editor
           language="css"
           displayName="CSS"
-          value={css}
+          value={css.text}
           onChange={setCss}
         />
         <Editor
           language="javascript"
           displayName="JS"
-          value={js}
+          value={js.text}
           onChange={setJs}
         />
       </div>
 
-      <Preview html={html} css={css} js={js} />
+      <Preview html={html.text} css={css.text} js={js.text} />
     </>
   );
 };

+ 52 - 52
src/components/pages/PenPage/PenPage.module.scss

@@ -1,61 +1,61 @@
-@import '../../../scss/index.scss';
+@import "../../../scss/index.scss";
 
-.penPage {
+.editors {
+  height: 50vh;
   display: flex;
-  flex-direction: column;
-  height: 100vh;
+  background-color: black;
 }
 
-.code {
-  display: flex;
-  flex-wrap: wrap;
-  justify-content: space-between;
-  height: calc(100vh - 60px);
-}
+// .code {
+//   display: flex;
+//   flex-wrap: wrap;
+//   justify-content: space-between;
+//   height: calc(100vh - 60px);
+// }
 
-.code__html,
-.code__css,
-.code__js {
-  width: calc(33.33% - 10px);
-  height: 100%;
-  padding: 10px;
-  font-size: 16px;
-  line-height: 1.5;
-  border: 1px solid #ccc;
-  box-sizing: border-box;
-  resize: none;
-  &:focus {
-    outline: none;
-  }
-}
+// .code__html,
+// .code__css,
+// .code__js {
+//   width: calc(33.33% - 10px);
+//   height: 100%;
+//   padding: 10px;
+//   font-size: 16px;
+//   line-height: 1.5;
+//   border: 1px solid #ccc;
+//   box-sizing: border-box;
+//   resize: none;
+//   &:focus {
+//     outline: none;
+//   }
+// }
 
-.code_run {
-  height: 50px;
-  margin-top: 10px;
-  padding: 5px 10px;
-  font-size: 16px;
-  border: none;
-  background-color: black;
-  color: #fff;
-  cursor: pointer;
-  &:hover {
-    background-color: #49494a;
-  }
-}
+// .code_run {
+//   height: 50px;
+//   margin-top: 10px;
+//   padding: 5px 10px;
+//   font-size: 16px;
+//   border: none;
+//   background-color: black;
+//   color: #fff;
+//   cursor: pointer;
+//   &:hover {
+//     background-color: #49494a;
+//   }
+// }
 
-.console {
-  padding: 10px;
-  background-color: #f8f8f8;
-  overflow-y: scroll;
-}
+// .console {
+//   padding: 10px;
+//   background-color: #f8f8f8;
+//   overflow-y: scroll;
+// }
 
-.console__title {
-  margin: 0 0 10px;
-  font-size: 18px;
-}
+// .console__title {
+//   margin: 0 0 10px;
+//   font-size: 18px;
+// }
 
-.console__log {
-  white-space: pre-wrap;
-  font-size: 16px;
-  line-height: 1.5;
-}
+// .console__log {
+//   white-space: pre-wrap;
+//   font-size: 16px;
+//   line-height: 1.5;
+// }

+ 0 - 2
src/index.js

@@ -8,11 +8,9 @@ import { store } from "./store/store";
 
 const root = ReactDOM.createRoot(document.getElementById("root"));
 root.render(
-  // <React.StrictMode>
   <BrowserRouter>
     <Provider store={store}>
       <App />
     </Provider>
   </BrowserRouter>
-  // </React.StrictMode>,
 );

+ 4 - 2
src/store/currentWork/actions/fetchCurrentWork.js

@@ -13,8 +13,10 @@ export const fetchCurrentWork = createAsyncThunk(
             SnippetFindOne(query: $query) {
               _id
               title
-              description
-              createdAt
+              owner {
+                _id
+                login
+              }
               files {
                 _id
                 text

+ 23 - 10
src/store/currentWork/currentWorkSlice.js

@@ -3,21 +3,31 @@ import { fetchCurrentWork } from "./actions/fetchCurrentWork";
 import { saveFiles } from "./actions/saveFiles";
 
 const initialState = {
-  currentWork: {
-    files: [
-      { text: "", type: "HTML" },
-      { text: "", type: "CSS" },
-      { text: "", type: "JS" },
-    ],
-  },
+  title: "",
+  owner: { id: "", login: "" },
+  files: [
+    { text: "", type: "HTML" },
+    { text: "", type: "CSS" },
+    { text: "", type: "JS" },
+  ],
   isLoading: false,
   error: null,
 };
 
 export const currentWorkSlice = createSlice({
-  name: "works",
+  name: "currentWork",
   initialState,
   reducers: {
+    setHtml(state, action) {
+      state.files[0].text = action.payload;
+    },
+    setCss(state, action) {
+      state.files[1].text = action.payload;
+    },
+    setJs(state, action) {
+      state.files[2].text = action.payload;
+    },
+
     setCurrentWork(state, action) {
       state.currentWork = state.works.find(
         (work) => (work.id = action.payload)
@@ -31,7 +41,9 @@ export const currentWorkSlice = createSlice({
     });
     builder.addCase(fetchCurrentWork.fulfilled, (state, action) => {
       state.isLoading = false;
-      state.currentWork = action.payload;
+      state.title = action.payload.title;
+      state.owner = action.payload.owner;
+      state.files = action.payload.files;
     });
     builder.addCase(fetchCurrentWork.rejected, (state, action) => {
       state.isLoading = false;
@@ -50,4 +62,5 @@ export const currentWorkSlice = createSlice({
   },
 });
 
-export const { setCurrentWork } = currentWorkSlice.actions;
+export const { setCurrentWork, setHtml, setCss, setJs } =
+  currentWorkSlice.actions;