├── .babelrc ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── Assets ├── download_photos.jpg └── unsplash_clone.jpg ├── LICENSE.md ├── README.md ├── _config.yml ├── package-lock.json ├── package.json ├── postcss.config.js └── src ├── Api.js ├── App.js ├── Cover.js ├── Loader.js ├── Navbar.js ├── Photo.js ├── Styles ├── ButtonStyle.js ├── CommonStyle.js ├── Cover.css ├── NavbarStyle.js └── hideStyle.css ├── images ├── avatar.jpg ├── download_icon.png ├── favicon-16x16.png └── ms-icon.png └── index.html /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended", "prettier", "prettier/react"], 3 | "plugins": [], 4 | "parserOptions": { 5 | "ecmaVersion": 2016, 6 | "sourceType": "module", 7 | "ecmaFeatures": { 8 | "jsx": true 9 | } 10 | }, 11 | "env": { 12 | "es6": true, 13 | "browser": true, 14 | "node": true 15 | } 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache/ 3 | dist/ 4 | .env 5 | .DS_Store 6 | coverage/ 7 | .vscode/ 8 | .env 9 | public/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "proseWrap": "always", 3 | "tabWidth": 2 4 | } -------------------------------------------------------------------------------- /Assets/download_photos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/Assets/download_photos.jpg -------------------------------------------------------------------------------- /Assets/unsplash_clone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/Assets/unsplash_clone.jpg -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Junip Dewan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![forthebadge](https://forthebadge.com/images/badges/made-with-javascript.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/uses-css.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/check-it-out.svg)](https://forthebadge.com) 2 | 3 | 4 | [![madewithreact](https://img.shields.io/badge/madewith-react-green.svg)](https://reactjs.org/) [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 5 | 6 | # React Unsplash 7 | 8 | React Unsplash is photo search webapp made in React which uses Unsplash JSON APIs for photo search. A clone app of [https://unsplash.com](https://unsplash.com/) the most powerful photo engine in the world. Trying to make the unplash like UI and add functionality as much as possible. Completed UI screenshots 9 | 10 | 11 | Main search UI 12 | 13 | ![Interface](Assets/unsplash_clone.jpg?raw=true "Web App picture") 14 | 15 | Donwloading Photos and showing likes 16 | 17 | ![Interface](Assets/download_photos.jpg?raw=true "Web App picture") 18 | 19 | ## Prerequisites 20 | 21 | You are required to have [Node.js](https://nodejs.org/) installed to run the app locally. 22 | 23 | ## Getting Started 24 | 25 | Install [unsplash-js](https://github.com/unsplash/unsplash-js) ([github](https://github.com/unsplash/unsplash-js)) 26 | 27 | ``` 28 | npm i --save unsplash-js 29 | ``` 30 | ### Website Link 31 | [react-unsplash](react-unsplash.now.sh) 32 | 33 | ## Key Usages 34 | - Access the unsplash API by [registering as a developer](https://unsplash.com/developers). 35 | - Before using the Unsplash API, read the API Guidelines. Specifically you must: 36 | - [hotlink images](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-hotlinking-images) 37 | - [attribute photographers](https://help.unsplash.com/en/articles/2511315-guideline-attribution) 38 | - [trigger a download when appropriate](https://help.unsplash.com/en/articles/2511258-guideline-triggering-a-download) 39 | 40 | 41 | ## API Usage in Project 42 | Make a new `.env` file and do the following 43 | 44 | ``` 45 | APP_ACCESS_KEY = your_app_access_key 46 | ``` 47 | 48 | ## Usage 49 | 50 | ```sh 51 | # install all dependency 52 | ~/ npm install 53 | 54 | # run 55 | ~/ npm run dev 56 | ``` 57 | 58 | ## Formatting Code 59 | 60 | ```sh 61 | ~/ npm run format 62 | ``` 63 | 64 | ## Clearing Build 65 | 66 | ```sh 67 | ~/ npm run clear 68 | ``` 69 | 70 | 71 | ## Contribution 72 | 73 | The devlopement of the App is still in progress. Only some part is implemented. You can help with 74 | code contribution to add more functionality in the App. 75 | 76 | ## License 77 | 78 | **React Unplash** is available under the **MIT license**. See the [LICENSE](https://github.com/junipdewan/react-unsplash/blob/master/LICENSE.md) file for more info. 79 | 80 | 81 | ## Important 82 | 83 | [Unplash](https://unsplash.com) is a registered trademark. This project is just for learning purposes and should be treated as such. 84 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-unsplash", 3 | "version": "1.0.0", 4 | "description": "A sample unsplash clone with react", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "parcel build src/index.html --out-dir public", 8 | "dev": "parcel src/index.html --open", 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "format": "prettier --write \"src/**/*.{js,jsx}\"", 11 | "clear": "rm -rf dist/ .cache/", 12 | "lint": "eslint **/*.{js,jsx} --quiet" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "aphrodite": "^2.4.0", 18 | "parcel-bundler": "^1.12.5", 19 | "react": "^16.13.1", 20 | "react-dom": "^16.13.1", 21 | "react-responsive-masonry": "^2.1.2" 22 | }, 23 | "devDependencies": { 24 | "axios": "^0.21.2", 25 | "babel-core": "^6.26.3", 26 | "babel-plugin-transform-class-properties": "^6.24.1", 27 | "eslint": "^5.16.0", 28 | "eslint-config-prettier": "^4.3.0", 29 | "postcss-modules": "^4.0.0", 30 | "prettier": "^1.19.1", 31 | "react-router-dom": "^5.2.0", 32 | "unsplash-js": "^7.0.8" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.export = { 2 | modules: true 3 | }; -------------------------------------------------------------------------------- /src/Api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * --------------------------------------------------------------------------------- 3 | * Importing Unsplash object and using for fetching image data using APP_ACCESS_KEY 4 | * 5 | * SignUp Yourself in `https://unsplash.com/` GO TO Threedots -> API/Devlopers 6 | * Follow the instruction and API USE restriction to use the APP_ACCESS_KEY 7 | * you need to create a .env file then add your key to work this. 8 | * --------------------------------------------------------------------------------- 9 | */ 10 | 11 | /** 12 | * Github Link for the unsplash-js (official javascript wrapper for unsplash API ) 13 | * `https://github.com/unsplash/unsplash-js` 14 | */ 15 | 16 | import { createApi } from "unsplash-js"; 17 | const APP_ACCESS_KEY = process.env.APP_ACCESS_KEY; 18 | export const api = createApi({ accessKey: APP_ACCESS_KEY }); 19 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useCallback } from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { api } from "./Api"; 4 | import Loader from "./Loader"; 5 | import Masonry from "react-responsive-masonry"; 6 | import Navbar from "./Navbar"; 7 | import Photo from "./Photo"; 8 | import { css } from "aphrodite"; 9 | import navStyle from "./Styles/NavbarStyle"; 10 | import Cover from "./Cover"; 11 | 12 | const App = () => { 13 | const [photosData, setPhotosData] = useState({ 14 | photos: [], 15 | page: 1, 16 | perPage: 50, 17 | isLoading: false 18 | }); 19 | 20 | const fetchPhotos = useCallback((page, perPage) => { 21 | api.photos.list({ page: page, perPage: perPage }).then(data => { 22 | if (data) { 23 | let paginatedData = data.response.results; 24 | setPhotosData(prev => ({ 25 | ...prev, 26 | photos: 27 | page === 1 28 | ? [...paginatedData] 29 | : prev.photos.concat([...paginatedData]), 30 | isLoading: false 31 | })); 32 | } 33 | }); 34 | }, []); 35 | 36 | useEffect(() => { 37 | fetchPhotos(1, 50); 38 | window.addEventListener("scroll", handleScroll); 39 | return () => { 40 | window.removeEventListener("scroll", handleScroll) 41 | } 42 | }, [fetchPhotos]); 43 | 44 | const handleScroll = () => { 45 | if ( 46 | window.innerHeight + window.scrollY >= document.body.offsetHeight - 300 && 47 | !photosData.isLoading 48 | ) { 49 | setPhotosData(prev => ({ 50 | ...prev, 51 | page: prev.page + 1, 52 | isLoading: true 53 | })); 54 | fetchPhotos(photosData.page + 1, 50); 55 | } 56 | }; 57 | 58 | const { photos, isLoading } = photosData; 59 | let loader; 60 | if (photos.length < 0 || isLoading) { 61 | loader = ; 62 | } 63 | 64 | return ( 65 |
66 | 67 | 68 |
69 | 70 | {photos.length && 71 | photos.map((photo, i) => ( 72 | 81 | ))} 82 | 83 |
84 | {loader} 85 |
86 | ); 87 | }; 88 | 89 | ReactDOM.render(React.createElement(App), document.getElementById("root")); 90 | -------------------------------------------------------------------------------- /src/Cover.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./Styles/Cover.css"; 3 | import { css, StyleSheet } from "aphrodite/no-important"; 4 | import commonStyle from "./Styles/CommonStyle"; 5 | 6 | const coverStyle = StyleSheet.create({ 7 | applyMargin: { 8 | "margin-left": "10px" 9 | }, 10 | hideDiv: { 11 | visibility: "hidden" 12 | }, 13 | title: { 14 | fontWeight: "700", 15 | "font-size": "46px", 16 | "line-height": "1.2", 17 | color: "#fff" 18 | }, 19 | textMargin: { 20 | color: "#fff", 21 | marginBottom: "25px", 22 | "font-size": "15px", 23 | "font-weight": "500" 24 | }, 25 | trendingText: { 26 | color: "#decdcd;" 27 | }, 28 | searchButton: { 29 | border: "none", 30 | padding: 0, 31 | "font-size": "18px", 32 | color: "#999", 33 | "background-color": "transparent", 34 | "text-align": "inherit", 35 | cursor: "pointer", 36 | position: "absolute", 37 | left: "20px", 38 | bottom: "42px", 39 | ":focus": { 40 | outline: "none", 41 | top: "17px", 42 | right: "71px" 43 | } 44 | } 45 | }); 46 | 47 | // have used hardcoded image source as unplash doesnot provide the apis for the photo of the day 48 | // you can use what ever you like. 49 | 50 | const imagesrc = "https://images.unsplash.com/photo-1617396900799-f4ec2b43c7ae"; 51 | 52 | const Cover = () => { 53 | return ( 54 |
55 | 56 |
57 |
58 |
Unsplash
59 |
60 | Beautiful, free photos. 61 |
62 |
63 | Gifted by the world’s most generous community of photographers. 🎁 64 |
65 |
66 |
67 | 70 | 75 |
76 | 77 |
78 | 79 | Trending searches:{" "} 80 | 81 | business, 82 | computer, 83 | nature, 84 | love, 85 | house 86 |
87 |
88 |
89 |
90 | 93 | Photo of the day by 94 | {" "} 95 | 96 | Gabriel 97 | 98 |
99 |
100 | 101 | Read more about the{" "} 102 | 103 | 104 | 109 | {" "} 110 | Unsplash License 111 | 112 | 113 |
114 |
115 | Extream Right Div No Content Displayed 116 |
117 |
118 |
119 | ); 120 | }; 121 | 122 | export default Cover; 123 | -------------------------------------------------------------------------------- /src/Loader.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { css, StyleSheet } from "aphrodite/no-important"; 3 | 4 | /** 5 | * Custom Loader in UI to show loading feature 6 | */ 7 | 8 | const keyFrame = { 9 | "0%": { 10 | transform: "rotate(0deg)" 11 | }, 12 | "100%": { 13 | transform: "rotate(360deg)" 14 | } 15 | }; 16 | 17 | const styles = StyleSheet.create({ 18 | loadingStyle: { 19 | borderRadius: "50%", 20 | border: "5px solid #f3f3f3", 21 | "border-top": "5px solid #6a62c1", 22 | width: "30px", 23 | height: "30px", 24 | animation: "spin 1s linear infinite", 25 | margin: "120px auto 0", 26 | animationName: keyFrame 27 | } 28 | }); 29 | 30 | const Loader = () => { 31 | return
; 32 | }; 33 | 34 | export default Loader; 35 | -------------------------------------------------------------------------------- /src/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { css } from "aphrodite/no-important"; 3 | import AvatarImg from "./images/avatar.jpg"; 4 | import navStyle from "./Styles/NavbarStyle"; 5 | import homeIcon from "./images/ms-icon.png"; 6 | 7 | const Navbar = () => { 8 | return ( 9 | 63 | ); 64 | }; 65 | 66 | export default Navbar; 67 | -------------------------------------------------------------------------------- /src/Photo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, css } from "aphrodite/no-important"; 3 | import buttonStyle from "./Styles/ButtonStyle"; 4 | import download from "./images/download_icon.png"; 5 | import "./Styles/hideStyle.css"; 6 | const phtoStyle = StyleSheet.create({ 7 | heartIcon: { 8 | color: "#f54b48" 9 | }, 10 | imageStyle: { 11 | width: "100%", 12 | display: "block", 13 | borderRadius: "2px" 14 | }, 15 | buttonMargin: { 16 | "margin-left": "8px" 17 | }, 18 | fullNameCss: { 19 | color: "white", 20 | position: "relative", 21 | top: "5px" 22 | }, 23 | userIcon: { 24 | "border-radius": "18px" 25 | }, 26 | downloadIcon: { 27 | width: "20px", 28 | height: "18px", 29 | "border-radius": "4px", 30 | "padding-top": "7px", 31 | "justify-content": "center" 32 | } 33 | }); 34 | const photo = ({ 35 | photoUrl, 36 | likes, 37 | profilePhoto, 38 | firstName, 39 | lastName, 40 | downloadUrl 41 | }) => { 42 | return ( 43 |
44 |
45 |
46 | 47 | 48 | {" "} 49 | {likes} 50 |
51 |
52 | Collect 53 |
54 |
55 | 56 |
57 | 58 |
59 | {`${firstName} ${lastName}`} 62 |
63 |
64 |
65 | 70 | 71 | 72 |
73 |
74 | ); 75 | }; 76 | export default photo; 77 | -------------------------------------------------------------------------------- /src/Styles/ButtonStyle.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "aphrodite/no-important"; 2 | 3 | const buttonStyle = StyleSheet.create({ 4 | button: { 5 | "font-size": "14px", 6 | "line-height": "30px", 7 | cursor: "pointer !important", 8 | "border-radius": "4px", 9 | color: "#777", 10 | "background-color": "#ddd!important", 11 | border: "1px solid transparent", 12 | height: "32px", 13 | padding: "0 11px", 14 | "font-size": "14px", 15 | "line-height": "30px" 16 | } 17 | }); 18 | 19 | export default buttonStyle; 20 | -------------------------------------------------------------------------------- /src/Styles/CommonStyle.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "aphrodite/no-important"; 2 | 3 | /** BASE STYLES 4 | * This stylesheet contain common style configuration across the project 5 | * Some common styling for linktag, inout box, searchicon has implmented 6 | * or we can refactor some styling to common base styles. 7 | */ 8 | 9 | const commonStyle = StyleSheet.create({ 10 | linkDecoration: { 11 | "text-decoration": "none", 12 | color: "rgb(255, 255, 255)" 13 | }, 14 | textColor: { 15 | color: "#fff" 16 | }, 17 | textWeight: { 18 | "font-weight": "400" 19 | }, 20 | highlightText: { 21 | color: "hsla(0,0%,100%,.55)", 22 | "text-shadow": "0 1px 8px rgba(0,0,0,.1)" 23 | } 24 | }); 25 | 26 | export default commonStyle; 27 | -------------------------------------------------------------------------------- /src/Styles/Cover.css: -------------------------------------------------------------------------------- 1 | 2 | .random { 3 | height: 600px; 4 | background-color: #000; 5 | color: #fff; 6 | /* margin-bottom: 48px; */ 7 | width: 100%; 8 | background-position: center; 9 | background-repeat: no-repeat; 10 | background-size: cover; 11 | } 12 | 13 | .cover-photo { 14 | width: 100vw; 15 | } 16 | .cover-content { 17 | position: absolute; 18 | top: 25%; 19 | right: 20%; 20 | } 21 | .coverSearchBox { 22 | width: 865px; 23 | height: 54px; 24 | border-radius: 4px; 25 | box-sizing: border-box; 26 | border: 1px solid #ccc; 27 | color: #111; 28 | padding-left: 55px; 29 | font-size: 14px; 30 | } 31 | .coverSearchBox:focus { 32 | outline: none; 33 | } 34 | .trending-search { 35 | margin-top: 5px; 36 | } 37 | .userName { 38 | text-decoration: none; 39 | } 40 | .footer-div{ 41 | display: flex; 42 | justify-content: space-between; 43 | height: 100%; 44 | font-size:12px; 45 | position: relative; 46 | bottom: 40px; 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/Styles/NavbarStyle.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "aphrodite/no-important"; 2 | 3 | const navStyle = StyleSheet.create({ 4 | navbar: { 5 | display: "flex", 6 | width: "100%", 7 | left: "0", 8 | top: "0", 9 | position: "fixed", 10 | "padding-right": "20px", 11 | "padding-left": "10px", 12 | "background-color": "#fff", 13 | "z-index": "1" 14 | }, 15 | homeElement: { 16 | display: "flex" 17 | }, 18 | inputBox: { 19 | "margin-top": "3px", 20 | width: "1022px", 21 | height: "40px", 22 | borderRadius: "20px", 23 | "box-sizing": "border-box", 24 | border: "1px solid #ccc", 25 | background: "none", 26 | "background-color": "#eee", 27 | border: "1px solid transparent", 28 | color: "#111", 29 | "align-items": "center", 30 | "padding-left": "42px", 31 | "font-size": "inherit", 32 | ":focus": { 33 | outline: "none" 34 | } 35 | }, 36 | 37 | listElement: { 38 | "list-style": "none", 39 | display: "inline-block", 40 | "padding-left": "20px" 41 | }, 42 | 43 | anchorDiv: { 44 | "text-decoration": "none", 45 | color: "#999" 46 | }, 47 | navElements: { 48 | display: "flex", 49 | "align-items": "center" 50 | }, 51 | inputDiv: { 52 | "padding-left": "16px", 53 | display: "flex" 54 | }, 55 | searchButton: { 56 | border: "none", 57 | padding: 0, 58 | color: "#999", 59 | "background-color": "transparent", 60 | "text-align": "inherit", 61 | cursor: "pointer", 62 | position: "absolute", 63 | top: "18px", 64 | left: "75px", 65 | ":focus": { 66 | outline: "none", 67 | top: "17px", 68 | right: "71px" 69 | } 70 | }, 71 | searchIcon: { 72 | "font-size": "1.4em", 73 | "font-style": "normal", 74 | content: "\f002" 75 | }, 76 | submitPhoto: { 77 | "padding-left": "46px" 78 | }, 79 | submitButton: { 80 | color: "#999", 81 | "background-color": "#fff", 82 | "border-color": "#ddd!important", 83 | display: "inline-block", 84 | height: "32px", 85 | padding: "0 11px", 86 | "font-size": "14px", 87 | "line-height": "30px", 88 | borderRadius: "4px", 89 | cursor: "pointer", 90 | border: "1px solid transparent", 91 | "box-shadow": "0 1px 1px rgba(0,0,0,.04)", 92 | transition: "all .2s ease-in-out", 93 | "text-align": "center", 94 | ":hover": { 95 | color: " #111", 96 | "border-color": "#999!important" 97 | }, 98 | ":focus": { 99 | outline: "none" 100 | } 101 | }, 102 | bell: { 103 | "padding-left": "20px" 104 | }, 105 | avatar: { 106 | "padding-left": "20px" 107 | }, 108 | bellIcon: { 109 | "text-decoration": "none", 110 | "font-size": "1.5em", 111 | color: "#999" 112 | }, 113 | homeIconImage: { 114 | width: "31px", 115 | height: "34px", 116 | "margin-top": "6px" 117 | }, 118 | avatarImg: { 119 | height: "34px", 120 | width: "34px", 121 | borderRadius: "18px", 122 | "margin-top": "3px" 123 | }, 124 | marginPhotos: { 125 | marginBottom: "20px", 126 | marginLeft: "50px", 127 | marginRight: "50px" 128 | } 129 | }); 130 | 131 | export default navStyle; 132 | -------------------------------------------------------------------------------- /src/Styles/hideStyle.css: -------------------------------------------------------------------------------- 1 | .likeDiv { 2 | display: flex; 3 | justify-content: flex-end; 4 | position: absolute; 5 | right: 20px; 6 | top: 20px; 7 | visibility: hidden; 8 | } 9 | .footerDiv { 10 | display: flex; 11 | position: absolute; 12 | bottom: 20px; 13 | left: 20px; 14 | visibility: hidden; 15 | } 16 | .downloadPhoto { 17 | display: flex; 18 | position: absolute; 19 | justify-content: flex-end; 20 | bottom: 20px; 21 | right: 20px; 22 | visibility: hidden; 23 | } 24 | 25 | .unplashPhtoDiv { 26 | width: 100%; 27 | overflow: hidden; 28 | position: relative; 29 | color: #999; 30 | transition: 2s ease-in-out; 31 | } 32 | 33 | .unplashPhtoDiv:hover { 34 | cursor: zoom-in; 35 | } 36 | 37 | .unplashPhtoDiv:hover .likeDiv{ 38 | visibility: visible; 39 | transition: 2s ease-in-out; 40 | } 41 | .unplashPhtoDiv:hover .downloadPhoto { 42 | visibility: visible; 43 | transition: 2s ease-in-out; 44 | } 45 | .unplashPhtoDiv:hover .footerDiv { 46 | visibility: visible; 47 | transition: 2s ease-in-out; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/src/images/avatar.jpg -------------------------------------------------------------------------------- /src/images/download_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/src/images/download_icon.png -------------------------------------------------------------------------------- /src/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/src/images/favicon-16x16.png -------------------------------------------------------------------------------- /src/images/ms-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junip/react-unsplash/677a4647a0b80b3990c0f3f5b7599f51fc50227d/src/images/ms-icon.png -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Beautiful Free Images Free & Pictures 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 |
22 | 23 | 24 | --------------------------------------------------------------------------------