浏览代码

Add Carousel

LenDoc 2 年之前
父节点
当前提交
19b6cb5e02
共有 5 个文件被更改,包括 276 次插入97 次删除
  1. 40 0
      package-lock.json
  2. 1 0
      package.json
  3. 204 90
      src/App.js
  4. 25 1
      src/App.scss
  5. 6 6
      src/actions/index.js

+ 40 - 0
package-lock.json

@@ -19,6 +19,7 @@
         "react-dom": "^17.0.2",
         "react-dropzone": "^12.0.2",
         "react-redux": "^7.2.6",
+        "react-responsive-carousel": "^3.2.22",
         "react-router-dom": "^5.3.0",
         "react-scripts": "5.0.0",
         "react-sortable-hoc": "^2.0.0",
@@ -14008,6 +14009,17 @@
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz",
       "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ=="
     },
+    "node_modules/react-easy-swipe": {
+      "version": "0.0.21",
+      "resolved": "https://registry.npmjs.org/react-easy-swipe/-/react-easy-swipe-0.0.21.tgz",
+      "integrity": "sha512-OeR2jAxdoqUMHIn/nS9fgreI5hSpgGoL5ezdal4+oO7YSSgJR8ga+PkYGJrSrJ9MKlPcQjMQXnketrD7WNmNsg==",
+      "dependencies": {
+        "prop-types": "^15.5.8"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/react-error-overlay": {
       "version": "6.0.10",
       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
@@ -14050,6 +14062,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-responsive-carousel": {
+      "version": "3.2.22",
+      "resolved": "https://registry.npmjs.org/react-responsive-carousel/-/react-responsive-carousel-3.2.22.tgz",
+      "integrity": "sha512-/r7dsIaN+l417IYIS0Fr7Z5VlpK3KYnTIIsdVCWSqtuJRIZNM+qdBIA4RIbzQtuW/ZBTnQanBecblCxg0HCqLQ==",
+      "dependencies": {
+        "classnames": "^2.2.5",
+        "prop-types": "^15.5.8",
+        "react-easy-swipe": "^0.0.21"
+      }
+    },
     "node_modules/react-router": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz",
@@ -27022,6 +27044,14 @@
         }
       }
     },
+    "react-easy-swipe": {
+      "version": "0.0.21",
+      "resolved": "https://registry.npmjs.org/react-easy-swipe/-/react-easy-swipe-0.0.21.tgz",
+      "integrity": "sha512-OeR2jAxdoqUMHIn/nS9fgreI5hSpgGoL5ezdal4+oO7YSSgJR8ga+PkYGJrSrJ9MKlPcQjMQXnketrD7WNmNsg==",
+      "requires": {
+        "prop-types": "^15.5.8"
+      }
+    },
     "react-error-overlay": {
       "version": "6.0.10",
       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
@@ -27050,6 +27080,16 @@
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
       "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
     },
+    "react-responsive-carousel": {
+      "version": "3.2.22",
+      "resolved": "https://registry.npmjs.org/react-responsive-carousel/-/react-responsive-carousel-3.2.22.tgz",
+      "integrity": "sha512-/r7dsIaN+l417IYIS0Fr7Z5VlpK3KYnTIIsdVCWSqtuJRIZNM+qdBIA4RIbzQtuW/ZBTnQanBecblCxg0HCqLQ==",
+      "requires": {
+        "classnames": "^2.2.5",
+        "prop-types": "^15.5.8",
+        "react-easy-swipe": "^0.0.21"
+      }
+    },
     "react-router": {
       "version": "5.2.1",
       "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz",

+ 1 - 0
package.json

@@ -14,6 +14,7 @@
     "react-dom": "^17.0.2",
     "react-dropzone": "^12.0.2",
     "react-redux": "^7.2.6",
+    "react-responsive-carousel": "^3.2.22",
     "react-router-dom": "^5.3.0",
     "react-scripts": "5.0.0",
     "react-sortable-hoc": "^2.0.0",

+ 204 - 90
src/App.js

@@ -24,108 +24,221 @@ import {
   actionPostUpsert,
   backendURL,
   actionAllPosts,
-  actionOnePost
+  actionOnePost,
 } from './actions'
-import { Upload, Button ,  DatePicker, Space } from 'antd'
-import moment from 'moment';
+import { Upload, Button, DatePicker, Space } from 'antd'
+import moment from 'moment'
 import { UploadOutlined } from '@ant-design/icons'
 import ImgCrop from 'antd-img-crop'
 import { Avatar, Image, Divider, Radio } from 'antd'
 import { UserOutlined } from '@ant-design/icons'
 import user from './materials/user.png'
 import photoNotFound from './materials/photoNotFound.png'
-
+// import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader
+// import { Carousel } from 'react-responsive-carousel';
+import { Carousel } from 'antd'
+import { LeftCircleFilled, RightCircleFilled } from '@ant-design/icons'
 console.log(store.getState())
 store.subscribe(() => console.log(store.getState()))
 const PageMain = () => <div className="PageMain">ГЛАВНАЯ</div>
 
-const Card = ({post, onPost} )=>(
-<>
-<Link to={`/post/${post?._id}`} onClick={()=>onPost(post?._id)}>
-{post?.images && post?.images[0] && post.images[0]?.url ?
-<img className='Card'
-        src={
-          backendURL+'/' + post.images[0].url 
-        }
-        style={{ maxWidth: '200px', maxHeight: '200px' }} />
-        :
-        <img className='Card'
-        src={
-          photoNotFound
-        }
-        style={{ maxWidth: '200px', maxHeight: '200px' }} /> }
-{/* {console.log(post?._id)} */}
-</Link>
-</>
+const Card = ({ post, onPost }) => (
+  <>
+    <Link to={`/post/${post?._id}`} onClick={() => onPost(post?._id)}>
+      {post?.images && post?.images[0] && post.images[0]?.url ? (
+        <img
+          className="Card"
+          src={backendURL + '/' + post.images[0].url}
+          style={{ maxWidth: '200px', maxHeight: '200px' }}
+        />
+      ) : (
+        <img
+          className="Card"
+          src={photoNotFound}
+          style={{ maxWidth: '200px', maxHeight: '200px' }}
+        />
+      )}
+      {/* {console.log(post?._id)} */}
+    </Link>
+  </>
 )
+const SampleNextArrow = (props) => {
+  const { className, style, onClick } = props
+  return (
+    <div
+      className="carousel-control-next"
+      style={{
+        fontSize: '50px',
+        color: '#a8a8a8',
+        position: 'absolute',
+        left: '100%',
+        top: '50%',
+        margin: 'auto',
+      }}
+      onClick={onClick}
+    >
+      <RightCircleFilled />
+    </div>
+  )
+}
 
-const PagePost=({onePost,aboutMe:{avatar, login}={}, onPost})=>{
-  return(
-    <>
-  
-  {onePost?.images && onePost?.images[0] && onePost.images[0]?.url ?
-<img className='Card'
-        src={
-          backendURL+'/' + onePost.images[0].url 
-        }
-        style={{ maxWidth: '600px', maxHeight: '600px' }} />
-        :
-        <img className='Card'
-        src={
-          photoNotFound
-        }
-        style={{ maxWidth: '600px', maxHeight: '600px' }} /> }
-        {avatar ?
-<Avatar style={{width:'50px',height:'50px',position:'absolute'}} src={backendURL + '/' + avatar?.url} />
-  :
-<Avatar style={{width:'50px',height:'50px',position:'absolute'}} src={user} />
+const SamplePrevArrow = (props) => {
+  const { className, style, onClick } = props
+  return (
+    <div
+      className="carousel-control-prev"
+      style={{
+        color: '#a8a8a8',
+        fontSize: '50px',
+        position: 'absolute',
+        margin: 'auto',
+        right: '100%',
+        top: '50%'
+      }}
+      onClick={onClick}
+    >
+      <LeftCircleFilled />
+    </div>
+  )
+}
 
+const MyCarousel = ({ images = [] }) => {
+  console.log('IMAGES', images)
+  return (
+    <>
+      <div>
+        <Carousel
+          style={{
+            display: 'block',
+            minWidth: '500px',
+            minHeight: '500px',
+            background: 'blue',
+          }}
+          effect="fade"
+          arrows
+          nextArrow={<SampleNextArrow />}
+          prevArrow={<SamplePrevArrow />}
+        >
+          {images &&
+            images.map((i, index) =>
+              i?.url ? (
+                <div key={index}>
+                  <img
+                    className="PostImage"
+                    src={backendURL + '/' + i?.url}
+                    style={{
+                      display: 'flex',
+                      alignItems: 'center',
+                      maxWidth: '400px',
+                      maxHeight: '400px',
+                    }}
+                  />
+                </div>
+              ) : (
+                <div>
+                  <img
+                    className="PostImage"
+                    src={photoNotFound}
+                    style={{ maxWidth: '400px', maxHeight: '400px' }}
+                  />
+                </div>
+              ),
+            )}
+        </Carousel>
+      </div>
+    </>
+  )
 }
-  <h2> {onePost?.title||''} </h2>
-        </>)
+const PagePost = ({ onePost, aboutMe: { avatar, login } = {}, onPost }) => {
+  return (
+    <>
+      <MyCarousel images={onePost?.images} />
+
+      {avatar ? (
+        <Avatar
+          style={{ width: '50px', height: '50px' }}
+          src={backendURL + '/' + avatar?.url}
+        />
+      ) : (
+        <Avatar style={{ width: '50px', height: '50px' }} src={user} />
+      )}
+      <h2> {onePost?.title || ''} </h2>
+      <h2> {onePost?.text || ''} </h2>
+    </>
+  )
 }
 
-const CPost = connect((state)=>({ onePost: state.promise?.onePost?.payload, aboutMe: state.promise?.aboutMe?.payload}))(PagePost)
-const PageAboutMe = ({ aboutMe: {_id, login, nick, createdAt, avatar, followers,following } = {}, allPosts, onPosts,onPost }) => {
-  useEffect(() => { onPosts() }, []);
+const CPost = connect((state) => ({
+  onePost: state.promise.onePost?.payload,
+  aboutMe: state.promise?.aboutMe?.payload,
+}))(PagePost)
+const PageAboutMe = ({
+  aboutMe: { _id, login, nick, createdAt, avatar, followers, following } = {},
+  allPosts,
+  onPosts,
+  onPost,
+}) => {
+  useEffect(() => {
+    onPosts()
+  }, [])
   // console.log('CREATED AT',new Intl.DateTimeFormat().format(createdAt));
-return (
-<section className="AboutMe"> 
-<Avatar style={{width:'150px',height:'150px',position:'absolute'}} src={backendURL + '/' + avatar?.url || user} />
-<div className="Info">
-
-<h1>  {login}</h1>
-<h3> Created Account: {new Intl.DateTimeFormat(('en-GB')).format(createdAt)}</h3>
-<div style={{display: 'flex'}}>
-
-{/* {allPosts?.length} style={{display: 'flex',justifyContent: 'space-between'}}*/}
-<h3  > {allPosts?.length} posts  </h3>
-
-<h3 style={{marginLeft: '20px'}}> {followers?.length} followers  </h3>
-
-<h3 style={{marginLeft: '20px'}}> {following?.length} following  </h3>
+  return (
+    <section className="AboutMe">
+      <Avatar
+        style={{ width: '150px', height: '150px', position: 'absolute' }}
+        src={backendURL + '/' + avatar?.url || user}
+      />
+      <div className="Info">
+        <h1> {login}</h1>
+        <h3>
+          {' '}
+          Created Account: {new Intl.DateTimeFormat('en-GB').format(createdAt)}
+        </h3>
+        <div style={{ display: 'flex' }}>
+          {/* {allPosts?.length} style={{display: 'flex',justifyContent: 'space-between'}}*/}
+          <h3> {allPosts?.length} posts </h3>
 
-</div>
-<h3> nick: {nick==null?login:nick}</h3>
-<div style={{display:'flex',flexWrap: 'wrap', padding: '20px',margin:'20px'}}>
+          <h3 style={{ marginLeft: '20px' }}>
+            {' '}
+            {followers?.length} followers{' '}
+          </h3>
 
-{(allPosts||[])?.map((item) => (
-    <Card post={item} onPost={onPost}/> 
-    ))}
-</div>
-{/* <h3> Created Account: {
+          <h3 style={{ marginLeft: '20px' }}>
+            {' '}
+            {following?.length} following{' '}
+          </h3>
+        </div>
+        <h3> nick: {nick == null ? login : nick}</h3>
+        <div
+          style={{
+            display: 'flex',
+            flexWrap: 'wrap',
+            padding: '20px',
+            margin: '20px',
+          }}
+        >
+          {(allPosts || [])?.map((item) => (
+            <Card post={item} onPost={onPost} />
+          ))}
+        </div>
+        {/* <h3> Created Account: {
 <div>
 <img
       src={backendURL + '/' + allPosts?.url}
       style={{ maxWidth: '200px', maxHeight: '200px' }}/>
 </div>
 date} </h3> */}
-
-</div>
-</section>)}
-const CPageAboutMe = connect( (state) => ({ aboutMe: state.promise?.aboutMe?.payload,
-allPosts:state.promise?.allPosts?.payload
-}),{onPosts:actionAllPosts, onPost:actionOnePost})(PageAboutMe)
+      </div>
+    </section>
+  )
+}
+const CPageAboutMe = connect(
+  (state) => ({
+    aboutMe: state.promise?.aboutMe?.payload,
+    allPosts: state.promise?.allPosts?.payload,
+  }),
+  { onPosts: actionAllPosts, onPost: actionOnePost },
+)(PageAboutMe)
 const PageCreatePost = () => (
   <div style={{ maxWidth: '700px', maxHeight: '700px', background: '#FFFACD' }}>
     <h2>Edit Post</h2>
@@ -170,23 +283,21 @@ const AddPost = ({ children }) => {
 
 const CBasic = connect(null, { onLoad: actionSetAvatar })(Basic)
 // const CAddPost =connect(null,{actionPostUpsert})
-const User = ({ aboutMe: { _id, login, avatar } = {}}) => (
-  <Link className="User" to={`/profile/${_id}`} >
+const User = ({ aboutMe: { _id, login, avatar } = {} }) => (
+  <Link className="User" to={`/profile/${_id}`}>
     <Avatar src={backendURL + '/' + avatar?.url || user} />
   </Link>
 )
 
-const CUser = connect(
-  (state) => ({ aboutMe: state.promise.aboutMe?.payload }),
- 
-)(User)
+const CUser = connect((state) => ({ aboutMe: state.promise.aboutMe?.payload }))(
+  User,
+)
 
 function Basic({ onLoad }) {
   const { acceptedFiles, getRootProps, getInputProps } = useDropzone()
   const files = acceptedFiles.map((file) => (
     <li key={file.path}>
       {file.path} - {file.size} bytes
-    
     </li>
   ))
   useEffect(() => {
@@ -266,7 +377,7 @@ const PostEditor = ({ post = defaultPost, onSave, onFileDrop, fileStatus }) => {
   const [state, setState] = useState(post)
   useEffect(() => {
     fileStatus?.status == 'FULFILLED' &&
-     setState({
+      setState({
         ...state,
         images: [
           ...state.images,
@@ -302,7 +413,7 @@ const PostEditor = ({ post = defaultPost, onSave, onFileDrop, fileStatus }) => {
     })
   return (
     <section className="Post">
-      <Basic  onLoad={onFileDrop}/>
+      <Basic onLoad={onFileDrop} />
       <SortableContainer onSortEnd={onSortEnd}>
         {(state.images || []).map(({ _id, url }, index) => (
           <>
@@ -325,10 +436,13 @@ const PostEditor = ({ post = defaultPost, onSave, onFileDrop, fileStatus }) => {
     </section>
   )
 }
-const CPostEditor = connect((state) => ({ fileStatus: state.promise?.uploadFiles }), {
-  onSave: actionPostUpsert,
-  onFileDrop: actionUploadFiles,
-})(PostEditor)
+const CPostEditor = connect(
+  (state) => ({ fileStatus: state.promise?.uploadFiles }),
+  {
+    onSave: actionPostUpsert,
+    onFileDrop: actionUploadFiles,
+  },
+)(PostEditor)
 // fileStatus=connect((state)=>(state.promise?.uploadFile))(CUploadFile)
 
 const history = createHistory()
@@ -349,4 +463,4 @@ function App() {
   )
 }
 
-export default App
+export default App

+ 25 - 1
src/App.scss

@@ -82,7 +82,31 @@ main{
   //  width:  33.3%;
    padding: 10px;
    margin:50px;
+
   // padding-top: 30%;
   // background-size: 100% 100%;
  
-}
+}
+.PostImage{
+  // display: flex;
+  // align-items: 'center';
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+  // margin: 0 1.5%;
+  //  width:  33.3%;
+   padding: 10px;
+  //  margin:50px;
+   
+  // padding-top: 30%;
+  // background-size: 100% 100%;
+ 
+}
+.slick-arrow.slick-prev {
+  background-color: red;
+  color: red;
+}
+.slick-arrow.slick-next {
+  background-color: red;
+  color: red;
+}

+ 6 - 6
src/actions/index.js

@@ -101,8 +101,8 @@ export const uploadFile = (file) => {
 export const actionUploadFile = (file) =>
   actionPromise('uploadFile', uploadFile(file))
 //тут еще неправильно
-// export const actionUploadFiles = (files) =>
-//   actionPromise('uploadFiles', Promise.all([uploadFile(files)]))
+export const actionUploadFiles = (files) =>
+  actionPromise('uploadFiles', Promise.all([uploadFile(files)]))
 
 const actionAvatar = (imageId) => async (dispatch, getState) => {
   await dispatch(
@@ -178,8 +178,8 @@ export const actionAllPosts = () => async (dispatch, getState) => {
     ),
   )
 }
-
-export const actionOnePost = (_id) =>
+export const actionOnePost = (_id) => async (dispatch) => {
+  await dispatch(
   actionPromise(
     'onePost',
     gql(
@@ -192,8 +192,8 @@ export const actionOnePost = (_id) =>
         post: JSON.stringify([{ _id }]),
       },
     ),
-  )
-
+  ))
+    }
 export const actionSetAvatar = (file) => async (dispatch) => {
   let result = await dispatch(actionUploadFile(file))
   if (result) {