From e2bae85b676b6573fb519bd5e321521b1494faaf Mon Sep 17 00:00:00 2001 From: SumanthBA Date: Tue, 10 Sep 2019 13:46:57 +0530 Subject: [PATCH] configs search suggestions and so on --- README.md | 5 + configs.js | 4 + src/actions/searchBar/searchBarActionTypes.js | 12 ++ src/actions/searchBar/searchBarActions.js | 14 ++ src/assets/images/common/index.js | 2 + src/assets/images/common/search.png | Bin 0 -> 10712 bytes .../groupsPage.jsx} | 7 +- src/components/searchBar/searchBar.jsx | 71 ++++++++++ src/components/topBar/topBar.jsx | 22 ++++ src/configs.js | 3 - src/reducers/index.js | 4 +- .../landingPage/landingPageReducer.js | 4 +- src/reducers/searchBar/searchBarReducer.js | 17 +++ src/routes.jsx | 30 ++++- src/routes/WelcomeScreen.jsx | 1 + src/routes/groupsPage/GroupsPageContainer.jsx | 28 ++++ .../landingPage/LandingPageContainer.jsx | 34 ----- src/scripts/debounce.js | 44 +++++++ src/scripts/urlConstructor.js | 22 ++++ src/services/flicker.js | 24 ++-- src/styles/components/searchBar.scss | 63 +++++++++ src/styles/components/topBar.scss | 17 +++ src/styles/index.scss | 7 +- src/styles/landingPage/landingPage.scss | 121 ------------------ src/styles/variables.scss | 17 ++- src/styles/welcomeScreen/welcomeScreen.scss | 2 +- 26 files changed, 385 insertions(+), 190 deletions(-) create mode 100644 configs.js create mode 100644 src/actions/searchBar/searchBarActionTypes.js create mode 100644 src/actions/searchBar/searchBarActions.js create mode 100644 src/assets/images/common/search.png rename src/components/{landingPage/landingPage.jsx => groupsPage/groupsPage.jsx} (75%) create mode 100644 src/components/searchBar/searchBar.jsx create mode 100644 src/components/topBar/topBar.jsx delete mode 100644 src/configs.js create mode 100644 src/reducers/searchBar/searchBarReducer.js create mode 100644 src/routes/groupsPage/GroupsPageContainer.jsx delete mode 100644 src/routes/landingPage/LandingPageContainer.jsx create mode 100644 src/scripts/debounce.js create mode 100644 src/scripts/urlConstructor.js create mode 100644 src/styles/components/searchBar.scss create mode 100644 src/styles/components/topBar.scss diff --git a/README.md b/README.md index abca7a2..fc71685 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ An simple version of the Flickr website using the Flickr API. [click here](https://google.com) - _**Refreshing page would not work here**_ as they are just static files (without served from a server) and because of frontend routing, it wont be able to resolve files and you would get a 404 on refreshing and that is expected. +## Configurations +Following are the configurations that can be made to this project, all the configurations exist in route directory configs.js (./configs.js) +1. flickerApiKey - Define your own flicker api key here _**[params - api key in string]**_ +2. searchNetworkCallDelay - Define the delay to be present before making network call for search auto-complete suggestions _**[params - Milliseconds key in number]**_ + ## NPM Scripts #### To install the required npm packages ( Required only once ) diff --git a/configs.js b/configs.js new file mode 100644 index 0000000..6c761b6 --- /dev/null +++ b/configs.js @@ -0,0 +1,4 @@ +export default { + flickerApiKey : '19047cf8f892417333e03b550bd901a6', + searchNetworkCallDelay : 500, +} \ No newline at end of file diff --git a/src/actions/searchBar/searchBarActionTypes.js b/src/actions/searchBar/searchBarActionTypes.js new file mode 100644 index 0000000..5d6de8c --- /dev/null +++ b/src/actions/searchBar/searchBarActionTypes.js @@ -0,0 +1,12 @@ +const searchBarActionTypes = { + ON_CHANGE : 'searchBarActions/ON_CHANGE', + ON_BLUR : 'searchBarActions/ON_BLUR', + TRIGGER_SEARCH : 'searchBarActions/TRIGGER_SEARCH', + HIDE_SUGGESTIONS: 'searchBarActions/HIDE_SUGGESTIONS', + SHOW_SUGGESTIONS: 'searchBarActions/SHOW_SUGGESTIONS', + SELECT_SUGGESTION: 'searchBarActions/SELECT_SUGGESTION', + SET_SUGGESTIONS: 'searchBarActions/SET_SUGGESTIONS', + SET_SEARCH_PARAM: 'searchBarActions/SET_SEARCH_PARAM', +}; + +export default searchBarActionTypes; \ No newline at end of file diff --git a/src/actions/searchBar/searchBarActions.js b/src/actions/searchBar/searchBarActions.js new file mode 100644 index 0000000..7f19081 --- /dev/null +++ b/src/actions/searchBar/searchBarActions.js @@ -0,0 +1,14 @@ +import services from '../../services/flicker' +import debounce from '../../scripts/debounce'; +const searchBarActions = { + showSuggestions: (payload) => () => { + console.log('searching for suggestions with param: ', payload); + + services.searchForGroups(payload) + .then(response =>{ + console.log('Response received is: ', response); + }); + } +}; + +export default searchBarActions; \ No newline at end of file diff --git a/src/assets/images/common/index.js b/src/assets/images/common/index.js index 8b00ffe..e6dcf4f 100644 --- a/src/assets/images/common/index.js +++ b/src/assets/images/common/index.js @@ -1,5 +1,7 @@ import rightArrow from './right-arrow.png'; +import searchIcon from './search.png'; export { rightArrow, + searchIcon } \ No newline at end of file diff --git a/src/assets/images/common/search.png b/src/assets/images/common/search.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6adc5a8d11a16b29dff6b74c2ac45ce5bfc5aa GIT binary patch literal 10712 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 rlV5{ + if(this.state.callNetworkFlag){ + this.props.showSuggestions(e.target.value); + this.setState({ + callNetworkFlag: false + }); + } + setTimeout(() =>{ + this.setState({ + callNetworkFlag: true + }); + }, configs.searchNetworkCallDelay); + }; + + onEnterHandler = () =>{ + + }; + + render(){ + return( +
+
+
+
+
+
+ +
+
+ +
+ + +
+
+ ); + } +} + +const mapStateToProps = state =>({ + searchBar : state.searchBar, +}); + +const mapDispatchToProps = dispatch =>({ + showSuggestions : searchParam => dispatch(searchBarActions.showSuggestions(searchParam)), +}); +export default connect(mapStateToProps, mapDispatchToProps)(SearchBar); diff --git a/src/components/topBar/topBar.jsx b/src/components/topBar/topBar.jsx new file mode 100644 index 0000000..3394dd2 --- /dev/null +++ b/src/components/topBar/topBar.jsx @@ -0,0 +1,22 @@ +import React,{ Component } from 'react'; +import PropTypes from 'prop-types'; +import '../../styles/components/topBar.scss'; + +class TopBar extends Component{ + + static propTypes = { + + }; + + render(){ + return( +
+
+ {this.props.children} +
+
+ ); + } +} + +export default TopBar; diff --git a/src/configs.js b/src/configs.js deleted file mode 100644 index ea8a3f5..0000000 --- a/src/configs.js +++ /dev/null @@ -1,3 +0,0 @@ -export default { - flickerApiKey : '19047cf8f892417333e03b550bd901a6' -} \ No newline at end of file diff --git a/src/reducers/index.js b/src/reducers/index.js index ebe46e5..c2ea290 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,9 +1,9 @@ import { combineReducers } from 'redux'; -import landingPageReducer from './landingPage/landingPageReducer'; +import searchBarReducer from './searchBar/searchBarReducer'; const allReducers = combineReducers({ - landingPage : landingPageReducer, + searchBar : searchBarReducer, }); export default allReducers; \ No newline at end of file diff --git a/src/reducers/landingPage/landingPageReducer.js b/src/reducers/landingPage/landingPageReducer.js index 0da5cd0..3922145 100644 --- a/src/reducers/landingPage/landingPageReducer.js +++ b/src/reducers/landingPage/landingPageReducer.js @@ -1,11 +1,11 @@ -// import SignupPageActionTypes from "../../actions/signupPage/signupPageActionTypes"; +import searchBarActionTypes from "../../actions/searchBar/searchBarActionTypes"; const intialState = { + } const landingPageReducer = (state = intialState, action) => { switch(action.type){ - default: return state; }; } diff --git a/src/reducers/searchBar/searchBarReducer.js b/src/reducers/searchBar/searchBarReducer.js new file mode 100644 index 0000000..831d645 --- /dev/null +++ b/src/reducers/searchBar/searchBarReducer.js @@ -0,0 +1,17 @@ +import searchBarActionTypes from "../../actions/searchBar/searchBarActionTypes"; + +const intialState = { + searchParam : '', + showSuggestions: 'false', + suggestionsList : [] +} + +const searchBarReducer = (state = intialState, action) => { + switch(action.type){ + case searchBarActionTypes.SET_SUGGESTIONS : return {...state, suggestionsList: action.payload}; + case searchBarActionTypes.SET_SEARCH_PARAM : return {...state, searchParam: action.payload}; + default: return state; + }; +} + +export default searchBarReducer; \ No newline at end of file diff --git a/src/routes.jsx b/src/routes.jsx index e66bc5d..bcf8f6b 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -1,17 +1,23 @@ import React,{ Component } from 'react'; import { Router, Switch, Route, Redirect } from 'react-router-dom'; import { useRouterHistory } from 'react-router'; +import Loadable from 'react-loadable'; + +import services from './services/flicker'; + +import TopBar from './components/topBar/topBar.jsx'; +import SearchBar from './components/searchBar/searchBar.jsx'; + import history from './routes/history'; import WelcomeScreen from './routes/WelcomeScreen.jsx'; -import Loadable from 'react-loadable'; - import './styles/index.scss'; +import './styles/index.scss'; function MyLoadingComponent() { return
Loading...
; } -const LandingPage = Loadable({ +const GroupsPage = Loadable({ loader: () => import('./routes/landingPage/LandingPageContainer.jsx'), loading: MyLoadingComponent, }); @@ -32,13 +38,23 @@ class Routes extends Component{ }; render(){ + services.searchForGroups('Hello World') + .then(response =>{ + console.log('Response received is :', response); + }); return( - { this.state.showModal ? :
} + {/*{ this.state.showModal ? :
}*/} + + +
+ +
Show Stats
+
- ( )}/> - - ( )}/> + ( )}/> + + ( )}/>
) diff --git a/src/routes/WelcomeScreen.jsx b/src/routes/WelcomeScreen.jsx index 59a5bcf..207d87e 100644 --- a/src/routes/WelcomeScreen.jsx +++ b/src/routes/WelcomeScreen.jsx @@ -125,6 +125,7 @@ class WelcomeScreen extends Component{
  • This project was built from scratch, using personally built boilerplate. No create-react-app used !
  • Lazing loading of images for performance optimisation and cost reduction !
  • Code splitting in order to make the static script files light weight and load only on need!
  • +
  • Search suggestion network calls are throttled!
  • No css frameworks used, all the styles and animations are handwritten !
  • diff --git a/src/routes/groupsPage/GroupsPageContainer.jsx b/src/routes/groupsPage/GroupsPageContainer.jsx new file mode 100644 index 0000000..fad06ea --- /dev/null +++ b/src/routes/groupsPage/GroupsPageContainer.jsx @@ -0,0 +1,28 @@ +import React,{ Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import GroupsPage from '../../components/groupsPage/groupsPage.jsx'; +class GroupsPageContainer extends Component{ + + componentDidMount(){ + + } + + render(){ + return( +
    + +
    + ); + } +} + +const mapStateToProps = state =>({ + +}); + +const mapDispatchToProps = dispatch => ({ +}); + +export default connect(mapStateToProps, mapDispatchToProps)(GroupsPageContainer); diff --git a/src/routes/landingPage/LandingPageContainer.jsx b/src/routes/landingPage/LandingPageContainer.jsx deleted file mode 100644 index 10cae93..0000000 --- a/src/routes/landingPage/LandingPageContainer.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import React,{ Component } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; - -import LandingPage from '../../components/landingPage/landingPage.jsx'; -class LandingPageContainer extends Component{ - - navigationHandler = (direction) =>{ - this.props.history.push(`${this.props.location.pathname}/${direction}`); - }; - - componentDidMount(){ - - } - - render(){ - return( -
    - -
    - ); - } -} - -const mapStateToProps = state =>({ - -}); - -const mapDispatchToProps = dispatch => ({ -}); - -export default connect(mapStateToProps, mapDispatchToProps)(LandingPageContainer); diff --git a/src/scripts/debounce.js b/src/scripts/debounce.js new file mode 100644 index 0000000..89d41f5 --- /dev/null +++ b/src/scripts/debounce.js @@ -0,0 +1,44 @@ +function debounce(func, wait, immediate) { + // 'private' variable for instance + // The returned function will be able to reference this due to closure. + // Each call to the returned function will share this common timer. + var timeout; + + // Calling debounce returns a new anonymous function + return function() { + // reference the context and args for the setTimeout function + var context = this, + args = arguments; + + // Should the function be called now? If immediate is true + // and not already in a timeout then the answer is: Yes + var callNow = immediate && !timeout; + + // This is the basic debounce behaviour where you can call this + // function several times, but it will only execute once + // [before or after imposing a delay]. + // Each time the returned function is called, the timer starts over. + clearTimeout(timeout); + + // Set the new timeout + timeout = setTimeout(function() { + + // Inside the timeout function, clear the timeout variable + // which will let the next execution run when in 'immediate' mode + timeout = null; + + // Check if the function already ran with the immediate flag + if (!immediate) { + // Call the original function with apply + // apply lets you define the 'this' object as well as the arguments + // (both captured before setTimeout) + func.apply(context, args); + } + }, wait); + + // Immediate mode and no wait timer? Execute the function.. + if (callNow) func.apply(context, args); + } +} + +export default debounce; \ No newline at end of file diff --git a/src/scripts/urlConstructor.js b/src/scripts/urlConstructor.js new file mode 100644 index 0000000..af438b4 --- /dev/null +++ b/src/scripts/urlConstructor.js @@ -0,0 +1,22 @@ +/* + PHOTO URL CONSTRUCTOR + --------------------- + mock - https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}_{size}.jpg + + example - https://farm1.staticflickr.com/2/1418878_1e92283336_m.jpg + + legend -> farm-id: 1 + server-id: 2 + photo-id: 1418878 + secret: 1e92283336 + size: m + + [read more] -> https://www.flickr.com/services/api/misc.urls.html +*/ + + +export default { + getsearchForGroup: (flickerApiKey, searchParam) => (`https://www.flickr.com/services/rest/?method=flickr.groups.search&api_key=${flickerApiKey}&text=${searchParam}&per_page=500&format=json&nojsoncallback=1`), + getBrowseGroupPhotosUrl : (flickerApiKey, groupId, perPage, pageNum) => (`https://www.flickr.com/services/rest/?method=flickr.groups.pools.getPhotos&api_key=${flickerApiKey}&group_id=${groupId}&per_page${perPage}=&page=${pageNum}&format=json&nojsoncallback=1`), + getPhotoUrl: (farmId, serverId, photoId, secret, size = 'm') => (`https://farm${farmId}.staticflickr.com/${serverId}/${photoId}_${secret}_${size}.jpg`), +} \ No newline at end of file diff --git a/src/services/flicker.js b/src/services/flicker.js index 3fad1fb..9f77f9c 100644 --- a/src/services/flicker.js +++ b/src/services/flicker.js @@ -1,17 +1,21 @@ -import configs from '../configs'; - +import configs from '../../configs'; +import urlContructor from '../scripts/urlConstructor'; const flickr = { - fetchAllGroups : () =>{ - console.log('api key is :', configs.flickerApiKey); - return 'fetchAllGroups'; + searchForGroups : (searchParam) =>{ // API Doc -> https://www.flickr.com/services/api/explore/flickr.groups.search + const url = urlContructor.getsearchForGroup(configs.flickerApiKey, searchParam); + return fetch(url) + .then(response =>{ + return response.json() + }); }, - fetchGroupDetails : (...args) =>{ - return 'fetchGroupDetails'; + browseGroupPhotos : (groupId, perPage, pageNum) =>{ // API Doc -> https://www.flickr.com/services/api/explore/flickr.groups.search + const url = urlContructor.getBrowseGroupPhotosUrl(configs.flickerApiKey, groupId, perPage, pageNum); + return fetch(url) + .then(response =>{ + return response.json() + }); }, - searchForGroup : (param) =>{ - return 'searchForGroup'; - } }; export default flickr; \ No newline at end of file diff --git a/src/styles/components/searchBar.scss b/src/styles/components/searchBar.scss new file mode 100644 index 0000000..6f2bdd8 --- /dev/null +++ b/src/styles/components/searchBar.scss @@ -0,0 +1,63 @@ +@import '../variables'; + +.FF_searchbar-wrapper{ + flex-grow: 0.5; + height: 50px; + border-radius: 100px; + box-shadow: inset 0 0 17px -8px; + background: #f9f9f9; + cursor: pointer; +} + +.FF_searchbar-container{ + display: flex; + height: 100%; + align-items: center; + justify-content: flex-start; + padding: 0px 15px; +} + +.FF_searchbar-icon-container{ + padding: 0 15px 0px 5px; + transition: $transition_mid; + backface-visibility: hidden; +} + +.FF_searchbar-icon{ + height: 18px; +} + + +.FF_searchbar-container:focus-within .FF_searchbar-icon-container{ + transform: scale(1.35); + //transform: ; +} + + +.FF_searchbar-input{ + height: 90%; + background: #0000; + border: none; + width: 100%; + font-size: 14pt; +} + +.FF_searchbar-input:focus{ + outline: none !important; + border: none; +} + +.FF_searchbar-suggestions-wrapper{ + height: 100%; + position: absolute; + width: 53%; + padding-left: 25px; + bottom: -55px; +} + +.FF_searchbar-suggestions-container{ + background: $color_white; + height: 100%; + width: 100%; + box-shadow: $shadow_L2; +} diff --git a/src/styles/components/topBar.scss b/src/styles/components/topBar.scss new file mode 100644 index 0000000..3191a59 --- /dev/null +++ b/src/styles/components/topBar.scss @@ -0,0 +1,17 @@ +@import "../variables"; + +.FF_topBar-wrapper{ + background: $color_white; + height: 60px; + width: 100%; + box-shadow: $shadow_L1; + position: absolute; +} + +.FF_topBar-container{ + display: flex; + justify-content: space-between; + align-items: center; + height: 100%; + padding: 0px 20px; +} \ No newline at end of file diff --git a/src/styles/index.scss b/src/styles/index.scss index 4dd782e..2504570 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -1,3 +1,5 @@ +@import "./variables"; + * { margin: 0; padding: 0; @@ -7,10 +9,11 @@ html, body { height: 100%; width: 100%; - background: #ecececbd; + background: $color_white2; margin: 0px; padding: 0px; - box-shadow: inset 0px 1px 210px -82px rgba(0,0,0,0.33); + //box-shadow: inset 0px 1px 210px -82px rgba(0,0,0,0.33); + -webkit-font-smoothing: antialiased; font-family: 'Rubik', sans-serif; } #root{ diff --git a/src/styles/landingPage/landingPage.scss b/src/styles/landingPage/landingPage.scss index 63902f9..d57eb37 100644 --- a/src/styles/landingPage/landingPage.scss +++ b/src/styles/landingPage/landingPage.scss @@ -3,124 +3,3 @@ .BCN-landingPage{ height:100%; } - -.BCN-container{ - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-evenly; -} - -.BCN-cards-container{ - display: flex; - width: 100%; - flex-wrap: wrap; - justify-content: space-around; -} - -.BCN-container-header{ - font-size: 50pt; - text-shadow: 3px 7px 16px rgb(31, 31, 31); - color: #ffffff; -} - -.BCN-container-cards{ - cursor: pointer; - margin-bottom: 5%; - background: #fff; - height: 225px; - width: 225px; - min-height: 225px; - min-width: 225px; - box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); - transition: $fastTransition; - display: flex; - justify-content: center; - background-size: contain; - background-position: center; - align-items: center; - color: #fff; - user-select: none; - border-radius: 3px; - overflow: hidden; -} - -.BCN-container-cards:hover{ - transform: scale(1.05); - box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); -} - -.BCN-container-card-text{ - height: 100%; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba(0, 0, 0, 0.70); - font-size: 34pt; - transition: $midTransition; -} - -.BCN-container-card-text:hover{ - font-size: 35pt; - - background: rgba(0, 0, 0, 0.20); -} - - - - - -.BCN-container-innerPage-cards{ - flex: 0 1 20%; - cursor: pointer; - margin-bottom: 5%; - margin: 0px 20px 5% 10px; - background: #fff; - height: 70px; - width: 160px; - min-height: 70px; - min-width: 160px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); - transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); - display: flex; - justify-content: center; - background-size: cover; - background-position: center; - align-items: center; - color: #fff; - user-select: none; - font-size: 10pt; - border-radius: 40px; - overflow: hidden; -} - -.BCN-container-innerPage-card-text{ - height: 100%; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - background: rgba(0, 0, 0, 0.7); - font-size: 10pt; - transition: all 0.5s -} - -.BCN-container-innerPage-card-text:hover{ - font-size: 16pt; - background: rgba(0, 0, 0, 0.35); -} - -.BCN-container-innerPage-cards:hover{ - transform: scale(1.05); - box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); -} - -.BCN-cards-container { - display: flex; - width: 80%; - flex-wrap: wrap; - justify-content: space-around; -} \ No newline at end of file diff --git a/src/styles/variables.scss b/src/styles/variables.scss index d5b255b..566e15c 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1,7 +1,16 @@ +// Colors +$color_white : #fff; +$color_white2 : #efefef; - +// Shadows +$shadow_L1 : 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); +$shadow_L2 : 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); +$shadow_L3 : 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); +$shadow_L4 : 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); +$shadow_L5 : 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22); +$shadow_Lifted : 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); // Transition Speeds -$fastTransition : all 0.3s cubic-bezier(.25,.8,.25,1); -$midTransition : all 0.5s cubic-bezier(.25,.8,.25,1); -$slowTransition : all 0.7s cubic-bezier(.25,.8,.25,1); \ No newline at end of file +$transition_fast : all 0.3s cubic-bezier(.25,.8,.25,1); +$transition_mid : all 0.5s cubic-bezier(.25,.8,.25,1); +$transition_slow : all 0.7s cubic-bezier(.25,.8,.25,1); diff --git a/src/styles/welcomeScreen/welcomeScreen.scss b/src/styles/welcomeScreen/welcomeScreen.scss index 7661f19..174d0a9 100644 --- a/src/styles/welcomeScreen/welcomeScreen.scss +++ b/src/styles/welcomeScreen/welcomeScreen.scss @@ -153,7 +153,7 @@ a.nostyle:visited { padding: 15px; border-radius: 10px; cursor: pointer; - transition: $slowTransition; + transition: all 0.7s cubic-bezier(.25,.8,.25,1); } .modalCloseBtn:hover{