Евгения Акиншина 2 سال پیش
والد
کامیت
0578d5651d

+ 25 - 0
package-lock.json

@@ -3712,6 +3712,11 @@
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
       "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
     },
+    "blueimp-load-image": {
+      "version": "5.16.0",
+      "resolved": "https://registry.npmjs.org/blueimp-load-image/-/blueimp-load-image-5.16.0.tgz",
+      "integrity": "sha512-3DUSVdOtlfNRk7moRZuTwDmA3NnG8KIJuLcq3c0J7/BIr6X3Vb/EpX3kUH1joxUhmoVF4uCpDfz7wHkz8pQajA=="
+    },
     "bn.js": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
@@ -6246,6 +6251,11 @@
         "strip-eof": "^1.0.0"
       }
     },
+    "exif-js": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/exif-js/-/exif-js-2.3.0.tgz",
+      "integrity": "sha1-nRCBm/Vx+HOBPnZAJBJVq5zhqBQ="
+    },
     "exit": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -9852,6 +9862,11 @@
       "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
       "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA=="
     },
+    "konva": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/konva/-/konva-2.6.0.tgz",
+      "integrity": "sha512-LCOoavICTD9PYoAqtWo8sbxYtCiXdgEeY7vj/Sq8b2bwFmrQr9Ak0RkD4/jxAf5fcUQRL5e1zPLyfRpVndp20A=="
+    },
     "language-subtag-registry": {
       "version": "0.3.21",
       "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
@@ -12451,6 +12466,16 @@
         "whatwg-fetch": "^3.4.1"
       }
     },
+    "react-avatar-edit": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/react-avatar-edit/-/react-avatar-edit-1.1.0.tgz",
+      "integrity": "sha512-aeJUk2/JQShMhoQIAZjipTNGvvK2wOHy42fPIQ29+aFehHcNOily6OGOabkcs+xbhe2q8+C+6h7VrnUtG0TMBA==",
+      "requires": {
+        "blueimp-load-image": "^5.14.0",
+        "exif-js": "^2.3.0",
+        "konva": "^2.5.1"
+      }
+    },
     "react-codemirror2": {
       "version": "7.2.1",
       "resolved": "https://registry.npmjs.org/react-codemirror2/-/react-codemirror2-7.2.1.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "codemirror": "^5.62.3",
     "react": "^17.0.2",
     "react-ace": "^9.4.4",
+    "react-avatar-edit": "^1.1.0",
     "react-codemirror2": "^7.2.1",
     "react-dom": "^17.0.2",
     "react-dropzone": "^11.4.2",

+ 2 - 2
src/App.css

@@ -1,6 +1,6 @@
-.App {
+/* .App {
   text-align: center;
-}
+} */
 
 .App-logo {
   height: 40vmin;

+ 12 - 28
src/App.js

@@ -1,33 +1,17 @@
-import './App.css';
-import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
-import createHistory from "history/createBrowserHistory";
-import {Provider, connect} from 'react-redux';
-import { actionFullLogin, actionFullRegister, actionUploadFile } from './actions';
-import { LoginForm } from './pages/LoginForm';
-import { FormReg } from './pages/FormReg';
-import { FormDate } from './components/FormDate';
-import { Main } from './pages/Main';
+import React from 'react';
+import { Provider }   from 'react-redux';
+import ConnectedRouts from './components/Routers';
 import store from './reducers';
-
-const ConnectLoginForm = connect(null, {onLogin:actionFullLogin}) (LoginForm);
-
-const ConnectFormReg = connect(null, {FormReg:actionFullRegister}) (FormReg);
-
-const ConnectFormUpload = connect(null, {onUpload:actionUploadFile}) (FormDate);
+import './App.css';
 
 function App() {
     return (
-        <Provider store = {store}>
-            <Router history = {createHistory()}>
-                <div className="App">
-                    <Route path = "/login" component={ConnectLoginForm} exact />
-                    <Route path = "/reg" component={ConnectFormReg} exact />
-                    <Route path = "/upload" component={ConnectFormUpload} exact />
-                    <Route path = "/" component={Main} exact />
-                </div>
-            </Router>
-        </Provider>
+        <>
+            <Provider store = {store}>
+            <ConnectedRouts/>
+            </Provider>
+        </>
     )
-  }
-
-  export default App;
+}
+    
+export default App;

+ 155 - 44
src/actions/index.js

@@ -41,40 +41,68 @@ let reg = async(login, password) => {
     return res
 }
 
-let ChangePass = async(login, password, newPassword) => {
-    let query = `mutation changePass($login:String!, $password:String!, $newPassword:String!) {
-    changePassword(
-        login: $login,
-        password: $password,
-        newPassword: $newPassword
-
-    ){
-       _id
-    }`
+export const actionAuthLogout = () => ({type: 'LOGOUT'})
+const actionAuthLogin = token => ({type: 'LOGIN', token})
+const actionLogin = (login, password) => actionPromise("login", log(login, password))
+const actionReg = (login, password) => actionPromise("reg", reg(login, password))
 
-    let variables = {"login":login, "password":password, newPassword:"newPassword"}
+export const actionFullLogin = (login, password) => async(dispatch) => {
+let result = await dispatch(actionLogin(login, password))
+    if (result !== null){
+        dispatch(actionAuthLogin(result))
+    } else {
+        alert ('That user doesn’t exist!')
+        localStorage.clear()
+    }
+}
 
-    let res = await gql(query, variables)
-    return res 
+export const actionFullRegister = (login, password) => async(dispatch) => {
+    let result = await dispatch(actionReg(login, password))
+    if(result?.data?.createUser !== null) {
+        dispatch(actionFullLogin(login, password))
+    } else {
+        alert('Such a user already exists!')
+    }
 }
 
-let SnippetUpsert = async (title, description, files , id) => {
+// let ChangePass = async(login, password, newPassword) => {
+//     let query = `mutation changePass($login:String!, $password:String!, $newPassword:String!) {
+//     changePassword(
+//         login: $login,
+//         password: $password,
+//         newPassword: $newPassword
+
+//     ){
+//        _id
+//     }`
+
+//     let variables = {"login":login, "password":password, "newPassword":newPassword}
+
+//     let res = await gql(query, variables)
+//     return res 
+// }
+
+// export const actionchangePass = (login, password, newPassword) => actionPromise("changePass", ChangePass(login, password, newPassword))
+
+let SnippetUpsert = async (title, description, files) => {
     let query = `mutation SnippetUpsert($snippet:SnippetInput) {
       SnippetUpsert(snippet:$snippet){
         _id
       }
     }`
   
-    let variables = { snippet: { title, description, files } ,_id: id };
+    let variables = { snippet: { title, description, files:files }};
   
     let res = await gql(query, variables)
     return res
 }
 
+export const actionSnippetUpsert = (title, description, files) => actionPromise("SnippetUpsert", SnippetUpsert(title, description, files))
+
 const UserFind = async (_id) => {
     let query = `UserFind(query:'[{}])' {
         UserFind(query:$query) {
-            _id login nick avatar{
+            _id login avatar{
                 url
             }
         }
@@ -85,7 +113,37 @@ const UserFind = async (_id) => {
       return res
 }
 
-// actions
+export const actionUserFind = (_id) => actionPromise("UserFind", UserFind(_id))
+
+export const imgFind = async () => {
+    return await gql(`query ImageFind{
+      ImageFind(query:"[{}]"){
+        url owner{
+          nick
+        }
+      }
+    }`)
+}
+
+export const actionImgFind = () => async (dispatch) => {
+    return await dispatch(actionPromise("img", imgFind()));
+}
+
+const setAva = async (idUser, id) => {
+    let query = `mutation setAvatar($idUser:String , $idAvatar:ID){ 
+      UserUpsert(user:{_id: $idUser, avatar: {_id: $idAvatar}}){
+          _id, avatar{
+              url
+          }
+      }
+  }`
+    let variables = { idUser: idUser, idAvatar: id }
+  
+    let res = await gql(query, variables)
+    return res
+}
+
+export const actionSetAva = (idUser, id) => actionPromise("setAva", setAva(idUser, id))
 
 const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name})
 const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload})
@@ -104,33 +162,6 @@ const actionPromise = (name, promise) =>
         }
     }
 
-export const actionchangePass = (login, password, newPassword) => actionPromise("changePass", ChangePass(login, password, newPassword))
-const actionAuthLogin = token => ({type: 'LOGIN', token})
-export const actionAuthLogout = () => ({type: 'LOGOUT'})
-const actionLogin = (login, password) => actionPromise("login", log(login, password))
-const actionReg = (login, password) => actionPromise("reg", reg(login, password))
-
-export const actionUserFind = (_id) => actionPromise("UserFind", UserFind(_id))
-export const actionSnippetUpsert = (title, description, files , id) => actionPromise("UserFind", SnippetUpsert(title, description, files , id))
-
-export const actionFullLogin = (login, password) => async(dispatch) => {
-let result = await dispatch(actionLogin(login, password))
-    if (result !== null){
-        dispatch(actionAuthLogin(result))
-    } else {
-        alert ('Такой пользователь не существует!')
-    }
-}
-
-export const actionFullRegister = (login, password) => async(dispatch) => {
-    let result = await dispatch(actionReg(login, password))
-    if(result?.data?.createUser !== null) {
-        dispatch(actionFullLogin(login, password))
-    } else {
-        alert('Такой пользователь уже существует!')
-    }
-}
-
 let up = async(file) => {
     let formData = new FormData()
     formData.append('photo', file)
@@ -142,3 +173,83 @@ let up = async(file) => {
     }
 
 export const actionUploadFile = (file) => actionPromise("upload", up(file))
+
+export const actionFullAvatar = (file) => async (dispatch) => {
+    let result = await dispatch(actionUploadFile(file));
+    await dispatch(actionSetAva(result._id));
+    await dispatch(actionUserFind());
+}
+  
+//   const snippetByOwner = async (id) => {
+//     let query = `query snippetFind($query:String){
+//         SnippetFind(query:$query){
+//                           owner{
+//                             _id 
+//                           }
+//               title description _id files {
+//                type text name
+//              }
+//           }
+//   }`;
+//     let variables = {
+//       query: JSON.stringify([{___owner: id } , {sort:[{_id: -1}]}])
+//     };
+  
+//     let res = gql(query, variables);
+//     return res;
+//   }
+  
+//   const snippetById = async(id) => {
+//     let query = `query snippetFind($query:String){
+//       SnippetFind(query:$query){
+//                         owner{
+//                           _id 
+//                         }
+//             title description _id files {
+//              type text name
+//            }
+//         }
+//   }`;
+//   let variables = {
+//     query: JSON.stringify([{_id: id }])
+//   };
+  
+//   let res = gql(query, variables);
+//   return res;
+//   }
+  
+//   let snippetAdd = async (title, description, files , idSnippet) => {
+//     let query = `mutation newSnippet($snippet:SnippetInput) {
+//       SnippetUpsert(snippet:$snippet){
+//         _id
+//       }
+//     }`;
+  
+//     let qVariables = { snippet: { title, description, files } ,_id: idSnippet  };
+  
+//     let res = await gql(query, qVariables);
+//     return res;
+//   };
+
+//   export const actionSnippetAdd =
+//     (title, description, files , idSnippet) => async (dispatch) => {
+//       return await dispatch(
+//         actionPromise("addSnippet",
+//         snippetAdd(title, description, files , idSnippet))
+//       );
+//     };
+  
+//     export const actionSnippetFindByOwner =
+//     (id) => async (dispatch) => {
+//       return await dispatch(
+//         actionPromise("findSnippet",
+//         snippetByOwner(id))
+//       );
+//     };
+//     export const actionSnippetById =
+//     (id) => async (dispatch) => {
+//       return await dispatch(
+//         actionPromise("findSnippetById",
+//         snippetById(id))
+//       );
+//     };

+ 14 - 0
src/components/Avatar.js

@@ -0,0 +1,14 @@
+import React from "react";
+import { connect } from "react-redux";
+import icon from '../user.png';
+import './Header.css';
+
+function AvaLogo({ link }) {
+    return <img src= {link ? ('http://localhost:3000/' + link) : icon} className = 'avatar' alt='user_photo'></img>
+}
+
+const ConnectedAvaLogo = connect((state) => ({link: state?.p?.payload?.data?.avatar?.url}))(AvaLogo);
+
+export default ConnectedAvaLogo;
+
+// https://w7.pngwing.com/pngs/946/367/png-transparent-gray-cat-illustration-cat-pusheen-kitten-cuteness-desktop-cute-love-animals-pet.png

+ 15 - 0
src/components/Editor.css

@@ -0,0 +1,15 @@
+.all_editors {
+    display: inline-block;
+    width: 464px;
+    padding-left: 10px;
+    color: rgb(196, 192, 192);
+}
+
+select {
+    margin: 5px;
+    font-size: 17px;
+}
+
+.editor {
+    margin-top: 5px;
+}

+ 17 - 19
src/components/Editor.js

@@ -3,28 +3,26 @@ import "ace-builds/src-noconflict/mode-html";
 import "ace-builds/src-noconflict/mode-css";
 import "ace-builds/src-noconflict/mode-javascript";
 import "ace-builds/src-noconflict/mode-java";
+import "ace-builds/src-noconflict/mode-python";
+import "ace-builds/src-noconflict/mode-xml";
+import "ace-builds/src-noconflict/mode-sass";
+import "ace-builds/src-noconflict/mode-ruby";
+import "ace-builds/src-noconflict/mode-markdown";
+import "ace-builds/src-noconflict/mode-mysql";
+import "ace-builds/src-noconflict/mode-json";
+import "ace-builds/src-noconflict/mode-handlebars";
+import "ace-builds/src-noconflict/mode-golang";
+import "ace-builds/src-noconflict/mode-csharp";
+import "ace-builds/src-noconflict/mode-elixir";
+import "ace-builds/src-noconflict/mode-typescript";
 import "ace-builds/src-noconflict/theme-monokai";
-import "ace-builds/src-noconflict/theme-github";
-import "ace-builds/src-noconflict/theme-tomorrow";
-import "ace-builds/src-noconflict/theme-kuroir";
-import "ace-builds/src-noconflict/theme-twilight";
-import "ace-builds/src-noconflict/theme-xcode";
-import "ace-builds/src-noconflict/theme-textmate";
-import "ace-builds/src-noconflict/theme-terminal";
-import "ace-builds/src-noconflict/theme-solarized_dark";
-import "ace-builds/src-noconflict/theme-solarized_light"; 
 import "ace-builds/src-noconflict/ext-language_tools";
 import { Select } from "../helpers/Select";
+import './Editor.css'
 
 export const Editor = ({ data={type:"", name:"", text:""}, onChange }) => {
     return (
-      <div
-        style={{
-          display: "inline-block",
-          width: "calc(100% / 3)",
-          marginBottom: "10px",
-        }}
-      >
+      <div className='all_editors'>
         {"Mode: "}
         <Select
           onChange={(type) =>
@@ -33,8 +31,8 @@ export const Editor = ({ data={type:"", name:"", text:""}, onChange }) => {
           value={data.type}
         />
         <br />
-        <input
-          style={{ marginBottom: "10px", marginLeft: "5px" }}
+        {"Name of editor: "}
+        <input placeholder='Enter a name for your editor'
           type="text"
           value={data.name}
           onChange={(e) =>
@@ -58,7 +56,7 @@ export const Editor = ({ data={type:"", name:"", text:""}, onChange }) => {
           setOptions={{
             enableBasicAutocompletion: true,
             enableLiveAutocompletion: true,
-            enableSnippets: false,
+            enableSnippets: true,
             showLineNumbers: true,
             tabSize: 2,
           }}

+ 88 - 0
src/components/EditorsPage.css

@@ -0,0 +1,88 @@
+body {
+    margin-top: 20px;
+}
+
+.button_plus {
+    display: flex;
+    justify-content: center;
+    cursor: pointer;
+    margin-left: 47.2%;
+    margin-bottom: 20px;
+    width: 6em;
+    height: 2.5em;
+    cursor: pointer;
+    margin-top: 7px;
+    line-height: 2.4em;
+    vertical-align: middle;
+    font-weight: 550;
+    text-align: center;
+    text-decoration: none;
+    user-select: none;
+    color: rgb(41, 14, 66);
+    outline: none;
+    border: 1px solid rgba(110,121,128,.8);
+    border-top-color: rgba(0,0,0,.3);
+    border-radius: 5px;
+    background: rgb(206, 220, 231) linear-gradient(rgb(206,220,231), rgb(106, 70, 148));
+    box-shadow:
+     0 -1px rgba(10,21,28,.9) inset,
+     0 1px rgba(255,255,255,.5) inset;
+}
+
+.button_plus:hover {
+    background: linear-gradient(#baa7cc, #9285b4);
+}
+
+.pane {
+    background-color:white;
+    width: 99%;
+    height: 300px;
+    margin-left: 10px;
+    margin-bottom: 30px;
+    border: dotted;
+}
+
+.input_title {
+    margin-left: 37.5%;
+    width: 400px;
+}
+
+.text_desc {
+    margin-left: 37.5%;
+    width: 400px;
+}
+
+.text {
+    margin-left: 37.5%;
+    font-size: 17px;
+    color: rgb(197, 193, 226);
+}
+
+.button_submit {
+    cursor: pointer;
+    margin-bottom: 90px;
+    margin-left: 46%;
+    width: 10em;
+    height: 2.5em;
+    cursor: pointer;
+    margin-top: 30px;
+    line-height: 2.4em;
+    vertical-align: middle;
+    font-weight: 550;
+    text-align: center;
+    text-decoration: none;
+    user-select: none;
+    color: rgb(41, 14, 66);
+    outline: none;
+    border: 1px solid rgba(110,121,128,.8);
+    border-top-color: rgba(0,0,0,.3);
+    border-radius: 5px;
+    background: rgb(206, 220, 231) linear-gradient(rgb(206,220,231), rgb(106, 70, 148));
+    box-shadow:
+     0 -1px rgba(10,21,28,.9) inset,
+     0 1px rgba(255,255,255,.5) inset;
+}
+
+.button_submit:hover {
+    background: linear-gradient(#baa7cc, #9285b4);
+} 

+ 78 - 0
src/components/EditorsPage.js

@@ -0,0 +1,78 @@
+import { useState, useEffect } from 'react';
+import { Editor } from '../components/Editor';
+import './EditorsPage.css';
+
+const datas = [{type: "html", name:"", text:'<h1 id="codepen">Welcome to the Codepen</h1>'}, {type: "css", name:"", text:`#codepen {
+    color: blue;
+    font-size: 25px;
+    font-family: Times New Roman;
+  }`}, {type: "javascript", name:"", text:`let btn = document.createElement('button')
+  btn.innerHTML = 'Change color'
+  btn.style.color = 'red'
+  btn.style.fontSize = '20px'
+  document.body.append(btn)
+  btn.style.cursor = 'pointer'
+  btn.onclick = () => {
+    document.getElementById('codepen').style.color = 'red'}`}];
+
+export const EditorsPage = ({onSave}) => {
+    const [editors, setEditors] = useState(datas);
+    const [title, setTitle] = useState("");
+    const [description, setDescription] = useState("");
+    const [srcDoc, setSrcDoc] = useState("");
+
+    useEffect(() => {
+        const timeout = setTimeout(() => {
+          let html, css, javascript;
+          editors.forEach(e => {
+              if(e.type === 'html') html = e.text
+              if(e.type === 'css') css = e.text
+              if(e.type === 'javascript') javascript = e.text
+          })
+          setSrcDoc(`
+            <html>
+              <body>${html}</body>
+              <style>${css}</style>
+              <script>${javascript}</script>
+            </html>
+          `)
+        }, 250)
+    
+        return () => clearTimeout(timeout)
+      }, [editors])    
+
+    return (
+       <>{editors.map((data, index) => {
+            return <Editor data={data}
+                            onChange={newData => { let editor = [...editors]
+                                editor.splice(index, 1, newData)
+                                setEditors(editor);
+                            } 
+
+                            } />
+        })}
+        
+        <button className='button_plus' onClick={newArray => { let editors2 = [...editors]
+            editors2.push(newArray);
+            setEditors(editors2);
+            }
+            }>+</button>
+
+        <div className="pane">
+            <iframe
+                srcDoc={srcDoc}
+                title="output"
+                sandbox="allow-scripts"
+                frameBorder="0"
+                width="100%"
+                height="100%"
+            />
+        </div>
+        <p className='text'>Name of your project: </p>
+        <input className='input_title' placeholder='Name of your project' value={title} onChange={e => setTitle(e.target.value)} /> 
+        <p className='text'>Description: </p>
+        <textarea className='text_desc' placeholder='Description' value={description} onChange={e => setDescription(e.target.value)} />
+        <button className='button_submit' onClick = {() => onSave(title, description, editors)}>Submit this Editor</button>
+        </>
+
+    )}

+ 17 - 2
src/components/FormDate.css

@@ -3,11 +3,11 @@
     height: 40px;
     text-decoration: none;
     padding-top: 9px;
-    color: #a675b3;
+    color: #c9b6cf;
     text-align: center;
     line-height: 20px;
     display: block;
-    margin: 50px auto;
+    margin: 200px auto 15px;
     font: normal 17px arial;
     cursor: pointer;
 }
@@ -27,4 +27,19 @@
 
 .buttons:not(:hover) {
       transition: 0.6s;
+}
+
+.back a {
+    text-decoration: none;
+}
+
+.back {
+    display: block;
+    width: 100px;
+    height: 20px;
+    text-decoration: none;
+    color: #c9b6cf;
+    text-align: center;
+    margin: auto;
+    cursor: pointer;
 }

+ 11 - 8
src/components/FormDate.js

@@ -9,13 +9,16 @@ export const FormDate = ({onUpload}) => {
     const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})
   
     return (
-      <div {...getRootProps()}>
-        <input {...getInputProps()} />
-        {
-          isDragActive ?
-            <p> Drop the files here ...</p> :
-            <p className='buttons'> Download files</p>
-        }
-      </div>
+        <>
+        <div {...getRootProps()}>
+            <input {...getInputProps()} />
+            {
+            isDragActive ?
+                <p> Drop the files here ...</p> :
+                <p className='buttons'> Download photo</p>
+            }
+        </div>
+        <button className='back'><a href = '/cabinet'>Go Back</a></button>
+      </>
     )
 }

+ 68 - 0
src/components/Header.css

@@ -0,0 +1,68 @@
+body{
+    margin:0;
+}
+  
+nav {
+    display: flex;
+    margin-bottom: 30px;
+    background: linear-gradient(#a088bd, #c7a9aa);
+}
+
+.img_logo {
+    width: 100px;
+    margin-right: 1135px;
+    border: 1.5px solid rgb(72, 70, 75);
+    margin-top: 5px;
+    margin-left: 20px;
+}
+
+.img_logo:hover {
+    border: 1.5px solid rgb(231, 224, 224);
+    width: 99px;
+}
+
+.logaut a {
+    color: rgb(23, 6, 39);
+    text-decoration: none;
+    font-size: 20px;
+}
+
+.logaut {
+    padding-top: 20px;
+    height: 100px;
+}
+
+.logaut button {
+    position: relative;
+    display: inline-block;
+    width: 6em;
+    height: 2.5em;
+    cursor: pointer;
+    margin-top: 7px;
+    line-height: 2em;
+    vertical-align: middle;
+    font-weight: 550;
+    text-align: center;
+    text-decoration: none;
+    user-select: none;
+    color: rgb(41, 14, 66);
+    outline: none;
+    border: 1px solid rgba(110,121,128,.8);
+    border-top-color: rgba(0,0,0,.3);
+    border-radius: 5px;
+    background: rgb(206, 220, 231) linear-gradient(rgb(206,220,231), rgb(106, 70, 148));
+    box-shadow:
+     0 -1px rgba(10,21,28,.9) inset,
+     0 1px rgba(255,255,255,.5) inset;
+}
+
+.logaut button:hover {
+    background: linear-gradient(#baa7cc, #9285b4);
+} 
+
+.avatar {
+   margin-top: 20px;
+   margin-right: 10px;
+   width: 70px;
+   height: 70px;
+}

+ 14 - 0
src/components/Header.js

@@ -0,0 +1,14 @@
+import './Header.css';
+import ImgLogo from './Logo';
+import ConnectedNick from './Nick';
+
+const Header = () => {
+    return (
+<nav className="navbar_header">
+    <ImgLogo />
+    <ConnectedNick/>
+</nav>
+    )
+}
+
+export default Header;

+ 8 - 0
src/components/Logo.js

@@ -0,0 +1,8 @@
+import React from "react";
+import logo from '../logo.png'
+
+function ImgLogo() {
+    return <a href="/home"> <img src={logo} alt="logo" className='img_logo'/> </a>
+  }
+  
+  export default ImgLogo;

+ 22 - 0
src/components/Nick.js

@@ -0,0 +1,22 @@
+import { connect } from "react-redux";
+import { actionAuthLogout } from "../actions";
+import ConnectedAvaLogo from "./Avatar";
+import './Header.css';
+
+const NickName = ({ nick, onLogOut }) => {
+    return (
+      <>
+        <a href = '/cabinet'>
+        <ConnectedAvaLogo />
+        </a>
+        <div className='logaut'>
+        <a href = '/cabinet'>{nick}
+        </a>
+        <a href = '/'><button onClick = {() => (onLogOut())}>Log out</button></a>
+        </div>
+      </>
+      )
+    }
+    
+const ConnectedNick = connect(state => ({nick: state?.a?.payload?.sub?.login, logedIn: state.a.token}),{onLogOut:actionAuthLogout})(NickName);
+export default ConnectedNick;

+ 13 - 0
src/components/Profile.js

@@ -0,0 +1,13 @@
+import React from "react";
+import wall from "../profileWall.jpeg";
+
+function ImgProfile({ px }) {
+  return (
+    <a href="/">
+      {" "}
+      <img src={wall} alt="wall" style={{ width: px }} />{" "}
+    </a>
+  );
+}
+
+export default ImgProfile;

+ 43 - 0
src/components/Routers.js

@@ -0,0 +1,43 @@
+import React from 'react';
+import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
+import createHistory from "history/createBrowserHistory";
+import { connect } from 'react-redux';
+import { actionFullLogin, actionFullRegister, actionFullAvatar } from '../actions';
+import { LoginForm } from '../pages/LoginForm';
+import { FormReg } from '../pages/FormReg';
+import { FormDate } from '../components/FormDate';
+import { Main } from '../pages/Main';
+import { Home } from '../pages/HomePage';
+import { Cabinet } from '../pages/Cabinet';
+
+const ConnectLoginForm = connect(null, {onLogin:actionFullLogin}) (LoginForm);
+
+const ConnectFormReg = connect(null, {FormReg:actionFullRegister}) (FormReg);
+
+export const ConnectFormUpload = connect(null, {onUpload:actionFullAvatar}) (FormDate);
+
+export let history = createHistory();
+
+const Routs = ({token}) => {
+    return (
+        <div className="App">
+          <Router history = {history}>
+            {token && <Switch>
+                <Redirect from="/login" to="/home" />
+                <Route exact path='/home' component={Home} />
+                <Route path='/upload' component={ConnectFormUpload}/>
+                <Route path='/cabinet' component={Cabinet}/>
+            </Switch>}
+            {!token && <Switch>
+                <Route path='/login' component={ConnectLoginForm}/>
+                <Route path='/reg' component={ConnectFormReg}/>
+                <Route path='/' component={Main}/>
+            </Switch>}
+          </Router>
+        </div>
+      )
+}
+
+const ConnectedRouts = connect(state=>({token: state.a.token}), null)(Routs);
+
+export default ConnectedRouts;

+ 15 - 0
src/components/User.js

@@ -0,0 +1,15 @@
+import { connect } from "react-redux"
+
+const Nick =  ({nick}) => {
+    return (
+      <>
+      <div>
+      <p>{nick}</p>
+      </div>
+      
+      </>
+      )
+    }
+    
+const ConnectNickName = connect(state => ({nick:state?.a?.payload?.sub?.login || 0 }))(Nick)
+export default ConnectNickName;

+ 4 - 4
src/helpers/Select.js

@@ -1,11 +1,11 @@
 const types = {
-    xml: "xml",
     html: "html",
     css: "css",
-    js: "javascript",
+    javascript: "javascript",
     java: "java",
     python: "python",
     ruby: "ruby",
+    xml: "xml",
     sass: "sass",
     json: "json",
     typescript: "typescript",
@@ -17,9 +17,9 @@ const types = {
     elixir: "elixir"
 }
 
-export const Select = ({listObj=types, onChange}) => 
+export const Select = ({listObj=types, onChange, value}) => 
     {
-        return <select onChange={e => onChange(e.target.value)}>
+        return <select value = {value} onChange={e => onChange(e.target.value)}>
             {Object.entries(listObj).map(([value, text]) => <option value={value} key={value}>
                 {text}
             </option>)}

BIN
src/logo.png


+ 36 - 0
src/pages/Cabinet.js

@@ -0,0 +1,36 @@
+import React from "react";
+import ConnectedNick from '../components/Nick';
+import './Main.css';
+
+export const Cabinet = () => {
+  return (
+    <>
+        <div className="card">
+            <div className='nick_style'>
+                <ConnectedNick />
+            </div>
+            <div className="cart_1">
+                <a href="/upload">
+                    <button className='btn'>
+                        Add Your Photo
+                    </button>
+                </a>
+            </div>
+            <div className="cart_2">
+                <a href="/projects">
+                    <button className='btn'>
+                        My Projects
+                    </button>
+                </a>
+            </div>
+            <div className="cart_3">
+                <a href="/home">
+                    <button className='btn'>
+                        Work Page
+                    </button>
+                </a>
+            </div>
+          </div>
+    </>
+  )
+}

+ 2 - 1
src/pages/FormReg.js

@@ -8,10 +8,11 @@ export const FormReg = ({FormReg}) => {
     return (
         <div className='login'>
         <h3>Registration</h3>
-        <input className='u'type ='login' placeholder='Username' value = {login} onChange = {e => setLogin(e.target.value)} />
+        <input className='u'type ='login' placeholder='Username' value = {login} onChange = {e => setLogin(e.target.value)}/>
         <input className='p' type ='password' placeholder='Password' value = {password} onChange = {e => setPassword(e.target.value)} />
         <input className='p' type ='password' placeholder='RepeatYourPassword' value = {passwordValid} onChange = {e => setPasswordValid(e.target.value)} />
         <button type="submit" className='btn btn-primary btn-block btn-large' disabled = {!login || !password || (password !== passwordValid)} onClick = {() => FormReg(login, password)}>Remember me. </button>
+        <button className='main_page'><a href = '/'>Main page</a></button>
         </div>
     )
 }

+ 16 - 0
src/pages/HomePage.js

@@ -0,0 +1,16 @@
+import { EditorsPage } from '../components/EditorsPage';
+import { actionSnippetUpsert } from '../actions';
+import { connect }  from 'react-redux';
+import Header from '../components/Header';
+
+export const Home = () => {
+    return (
+    <>
+    <Header />
+    <ConnectEditorsPage />
+    </>
+    )
+}
+
+export const ConnectEditorsPage = connect(null, {onSave:actionSnippetUpsert}) (EditorsPage);
+export default ConnectEditorsPage;

+ 3 - 2
src/pages/LoginForm.js

@@ -1,5 +1,5 @@
 import { useState } from 'react';
-import './LoginReg.css'
+import './LoginReg.css';
 
 export const LoginForm = ({onLogin}) => {
     const [login, setLogin] = useState('')
@@ -7,9 +7,10 @@ export const LoginForm = ({onLogin}) => {
     return (
         <div className='login'>
         <h3>Login</h3>
-        <input className='u'type ='login' placeholder='Username' value = {login} onChange = {e => setLogin(e.target.value)} />
+        <input className='u'type ='login' placeholder='Username' value = {login} onChange = {e => setLogin(e.target.value)}/>
         <input className='p' type ='password' placeholder='Password' value = {password} onChange = {e => setPassword(e.target.value)} />
         <button type="submit" className='btn btn-primary btn-block btn-large' disabled = {!login || !password} onClick = {() => onLogin(login, password)}>Let me in. </button>
+        <button className='main_page'><a href = '/'>Main page</a></button>
         </div>
     )
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 53 - 7
src/pages/LoginReg.css


+ 98 - 36
src/pages/Main.css

@@ -1,41 +1,103 @@
-body {
-    margin-top: 20px;
-}
-
-.button_plus {
-    position: relative;
-    z-index: 1;
-    display: inline-block;
-    width: 1em;
-    height: 1em;
-    line-height: 1em;
-    vertical-align: middle;
-    text-align: center;
+#body {
+    margin: 0;
+    padding: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    min-height: 90vh;
+    font-family: 'Telefon Black', Sans-Serif;
+}
+
+.box {
+  position: relative;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #170422;
+  max-width: 500px;
+}
+
+.box::before {
+  content: '';
+  position: absolute;
+  top: -2px;
+  left: -2px;
+  right: -2px;
+  bottom: -2px;
+  background: #fff;
+  z-index: -1;
+}
+
+.box::after {
+  content: '';
+  position: absolute;
+  top: -2px;
+  left: -2px;
+  right: -2px;
+  bottom: -2px;
+  background: #fff;
+  z-index: -2;
+  filter: blur(40px);
+}
+
+.box::before,
+.box::after {
+  background: linear-gradient(235deg, #89ff00, #060c21, #00bcd4);
+}
+
+.content {
+  padding: 40px;
+  box-sizing: border-box;
+  color: #ffffff;
+  font-size: 20px;
+}
+
+.btn_form {
+    width: 180px;
+    height: 40px;
     text-decoration: none;
-    text-shadow: 1px 1px rgba(255,255,255,.3);
-    font-size: 300%;
-    font-weight: 400;
-    color: #000;
-    border-radius: 100%;
-    background: rgb(183, 146, 190) linear-gradient(rgb(168, 151, 185), rgb(131, 116, 185));
-    box-shadow:
-     inset 0 -2px 1px rgba(0,0,0,.5),
-     inset 0 2px 1px rgba(255,255,255,.9),
-     0 4px 4px rgba(0,0,0,.9);
+    color: #c9b6cf;
+    text-align: center;
+    line-height: 20px;
+    display: block;
+    margin-left: 10px;
+    margin-right: 10px;
+    font: normal 17px arial;
     cursor: pointer;
 }
 
-.button_plus:after {
-    content: "";
-    position: absolute;
-    z-index: -1;
-    top: 10%;
-    left: 10%;
-    right: 10%;
-    bottom: 10%;
-    border-radius: 100%;
-    background: rgb(233, 230, 243) linear-gradient(rgb(216, 202, 238), rgb(236, 222, 245));
-    box-shadow:
-     inset 0 2px 1px rgba(0,0,0,.5),
-     inset 0 -2px 1px rgba(255,255,255,.3);
+.btn_form:not(.active) {
+    box-shadow: inset 0 1px 1px rgba(111, 55, 125, 0.8), inset 0 -1px 0px rgba(63, 59, 113, 0.2), 0 9px 16px 0 rgba(0, 0, 0, 0.3), 0 4px 3px 0 rgba(0, 0, 0, 0.3), 0 0 0 1px #150a1e;
+    background-image: linear-gradient(#3b2751, #271739);
+    text-shadow: 0 0 21px rgba(223, 206, 228, 0.5), 0 -1px 0 #311d47;
+}
+  
+.btn_form:not(.active):hover,
+.btn_form:not(.active):focus {
+    transition: color 200ms linear, text-shadow 500ms linear;
+    color: #fff;
+    text-shadow: 0 0 21px rgba(223, 206, 228, 0.5), 0 0 10px rgba(223, 206, 228, 0.4), 0 0 2px #2a153c;
+}
+
+.btn_form:not(:hover) {
+      transition: 0.6s;
+}
+
+.card {
+    width: 500px;
+    height: 400px;
+    padding-left: 100px;
+    margin-left: 470px;
+    margin-top: 100px;
+    padding-top: 10px;
+    background: linear-gradient(#f0e2ef, #faf5f5);
+    -webkit-box-shadow: inset 0 0 40px rgb(36, 16, 61);
+    -moz-box-shadow: inset 0 0 40px rgb(37, 12, 58);
+    box-shadow: inset 0 0 40px rgb(26, 10, 48);
+}
+
+.nick_style {
+    display: block;
+    width: 100px;
+    margin-left: 115px;
 }

+ 24 - 27
src/pages/Main.js

@@ -1,31 +1,28 @@
-import { useState } from 'react';
-import { Editor } from '../components/Editor';
-import './Main.css'
+import './Main.css';
 
-const datas = [{type: "", name:"", text:""}, {type: "", name:"", text:""}];
-
-export const Main = () => {
-    const [editors, setEditors] = useState(datas);
-    console.log(editors);
+export const Main = ({history}) => {
     return (
-        editors.map((data, index) => {
-            return <><Editor data={data}
-                            onChange={newData => { let editors1 = [...editors]
-                                editors1[index] = newData;
-                                setEditors(editors1);
-                            } 
+        <section id='body'>
+            <button className='btn_form' onClick={ () => history.push('./login') }>Login</button>
+            <div className='box'>
+                <div className='content'>
+                    <h1>Welcome To The CodePen</h1>
+                    <p>The best place to build, test, and discover front-end code.
+                        CodePen is a social development environment for front-end designers and developers.
+                        Build and deploy a website, show off your work, build test cases to learn and debug, and find inspiration.
+                    </p>
+                </div>
+            </div>
+            <button className='btn_form' onClick={ () => history.push('./reg') }>Reristration</button>
+        </section>
+    )
+}
 
-                            } />
-                            <button className='button_plus' onClick={newArray => { let editors2 = [...editors]
-                            editors2.push(newArray);
-                            setEditors(editors2);
-                            }
-                            }>+</button>
-                            </>
-        })    
-    )}
+// сделать запросы
+// кабинет
+// страницу с историей эдиторов
+// поиск как его реализовать
+// страница 1 едитора
+// заливка фото пользователя
 
-// приконэктить его к снипету чтобы на бэк начали отправляться данные?
-// сделать главную стр
-// запросы
-// сделать theme и font size
+// тему и прелоадер если останется время

BIN
src/user.png