diff --git a/.gitignore b/.gitignore index 53ffa91..e85cd5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .DS_Store env +shows.db yarn.lock */yarn.lock diff --git a/client/app/components/MovieObject.jsx b/client/app/components/MovieObject.jsx deleted file mode 100644 index 64ea04c..0000000 --- a/client/app/components/MovieObject.jsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; - -import Notifications, {notify} from 'react-notify-toast'; - -// StyleComponents -import movieStyle from './styles/movieObjectStyle.jsx'; - -var MediaQuery = require('react-responsive'); - -import RequestButton from './buttons/request_button.jsx'; - -import { fetchJSON } from './http.jsx'; - -class MovieObject { - constructor(object) { - this.id = object.id; - this.title = object.title; - this.year = object.year; - this.type = object.type; - // Check if object.poster != undefined - this.rating = object.rating; - this.poster = object.poster; - this.background = object.background; - this.matchedInPlex = object.matchedInPlex; - this.summary = object.summary; - } - - requestExisting(movie) { - console.log('Exists', movie); - } - - requestMovie() { - // fetch('http://localhost:31459/api/v1/plex/request/' + this.id + '?type='+this.type, { - // fetch('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, { - // method: 'POST' - // }); - fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, 'POST') - .then((response) => { - console.log(response); - }) - - notify.show(this.title + ' requested!', 'success', 3000); - } - - getElement(index) { - const element_key = index + this.id; - - // TODO set the poster image async by updating the dom after this is returned - if (this.poster == null || this.poster == undefined) { - var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' - } else { - var posterPath = 'https://image.tmdb.org/t/p/w300' + this.poster; - } - var backgroundPath = 'https://image.tmdb.org/t/p/w640_and_h360_bestv2/' + this.background; - - var foundInPlex; - if (this.matchedInPlex) { - foundInPlex = ; - } else { - foundInPlex = ; - } - - if (this.type === 'movie') - var themoviedbLink = 'https://www.themoviedb.org/movie/' + this.id - else if (this.type === 'show') - var themoviedbLink = 'https://www.themoviedb.org/tv/' + this.id - - - - // TODO add request button class - return ( -
- -
- -
- -
-
-
- - {this.title} -

- Released: { this.year } | Rating: {this.rating} -

- {this.summary} -

-
- - - - - {this.title} -

- Released: {this.year} | Rating: {this.rating} -
- - - - - - -
- {foundInPlex} - - - -
-
-
- -

-
-
-
-
-
) - - } -} - -export default MovieObject; \ No newline at end of file diff --git a/client/app/components/SearchObject.jsx b/client/app/components/SearchObject.jsx new file mode 100644 index 0000000..2be95d3 --- /dev/null +++ b/client/app/components/SearchObject.jsx @@ -0,0 +1,137 @@ +import React from 'react'; + +import Notifications, {notify} from 'react-notify-toast'; + +// StyleComponents +import searchObjectCSS from './styles/searchObject.jsx'; +import buttonsCSS from './styles/buttons.jsx'; + +var MediaQuery = require('react-responsive'); + +import { fetchJSON } from './http.jsx'; + +import Interactive from 'react-interactive'; + + +class SearchObject { + constructor(object) { + this.id = object.id; + this.title = object.title; + this.year = object.year; + this.type = object.type; + this.rating = object.rating; + this.poster = object.poster; + this.background = object.background; + this.matchedInPlex = object.matchedInPlex; + this.summary = object.summary; + } + + requestExisting(movie) { + console.log('Exists', movie); + } + + requestMovie() { + fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, 'POST') + .then((response) => { + console.log(response); + notify.show(this.title + ' requested!', 'success', 3000); + }) + .catch((e) => { + console.error('Request movie fetch went wrong: '+ e); + }) + + } + + getElement(index) { + const element_key = index + this.id; + + if (this.poster == null || this.poster == undefined) { + var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' + } else { + var posterPath = 'https://image.tmdb.org/t/p/w300' + this.poster; + } + var backgroundPath = 'https://image.tmdb.org/t/p/w640_and_h360_bestv2/' + this.background; + + var foundInPlex; + if (this.matchedInPlex) { + foundInPlex = {this.requestExisting(this)}} + style={buttonsCSS.submit} + focus={buttonsCSS.submit_hover} + hover={buttonsCSS.submit_hover}> + + Request Anyway + ; + } else { + foundInPlex = {this.requestMovie()}} + style={buttonsCSS.submit} + focus={buttonsCSS.submit_hover} + hover={buttonsCSS.submit_hover}> + + + Request + ; + } + + if (this.type === 'movie') + var themoviedbLink = 'https://www.themoviedb.org/movie/' + this.id + else if (this.type === 'show') + var themoviedbLink = 'https://www.themoviedb.org/tv/' + this.id + + // TODO go away from using mediaQuery, and create custom resizer + return ( +
+ + +
+ +
+ +
+ {this.title} +

+ Released: { this.year } | Rating: {this.rating} +

+ {this.summary} +

+
+ + + + {this.title} +

+ Released: {this.year} | Rating: {this.rating} +
+ +
+ {foundInPlex} + + + + + Info + + +
+
+ + +
+
+ +
+
+
+
+ ) + + } +} + +export default SearchObject; \ No newline at end of file diff --git a/client/app/components/SearchRequest.jsx b/client/app/components/SearchRequest.jsx index dcd1cdd..39cdce2 100644 --- a/client/app/components/SearchRequest.jsx +++ b/client/app/components/SearchRequest.jsx @@ -1,14 +1,14 @@ import React from 'react'; -import MovieObject from './MovieObject.jsx'; - -// StyleComponents -import searchStyle from './styles/searchRequestStyle.jsx'; -import movieStyle from './styles/movieObjectStyle.jsx'; - import URI from 'urijs'; import InfiniteScroll from 'react-infinite-scroller'; +// StyleComponents +import searchRequestCSS from './styles/searchRequestStyle.jsx'; + +import SearchObject from './SearchObject.jsx'; +import Loading from './images/loading.jsx' + import { fetchJSON } from './http.jsx'; import { getCookie } from './Cookie.jsx'; @@ -29,7 +29,8 @@ class SearchRequest extends React.Component { page: 1, resultHeader: '', loadResults: false, - scrollHasMore: true + scrollHasMore: true, + loading: false, } this.allowedListTypes = ['discover', 'popular', 'nowplaying', 'upcoming'] @@ -88,9 +89,9 @@ class SearchRequest extends React.Component { this.state.page = 1; } - writeLoading() { + setLoading(value) { this.setState({ - responseMovieList: 'Loading...' + loading: value }); } @@ -122,10 +123,7 @@ class SearchRequest extends React.Component { // Here we first call api for a search with the input uri, handle any errors // and fill the reponseData from api into the state of reponseMovieList as movieObjects - callSearchFillMovieList(uri) { - // Write loading animation - // this.writeLoading(); - + callSearchFillMovieList(uri) { Promise.resolve() .then(() => this.callURI(uri, 'GET')) .then(response => { @@ -152,7 +150,7 @@ class SearchRequest extends React.Component { } // Convert to json and update the state of responseMovieList with the results of the api call - // mapped as a movieObject. + // mapped as a SearchObject. response.json() .then(responseData => { if (this.state.page === 1) { @@ -180,7 +178,6 @@ class SearchRequest extends React.Component { callListFillMovieList(uri) { // Write loading animation - // this.writeLoading(); Promise.resolve() .then(() => this.callURI(uri, 'GET', undefined)) @@ -198,7 +195,7 @@ class SearchRequest extends React.Component { } // Convert to json and update the state of responseMovieList with the results of the api call - // mapped as a movieObject. + // mapped as a SearchObject. response.json() .then(responseData => { if (this.state.page === 1) { @@ -218,6 +215,7 @@ class SearchRequest extends React.Component { }) .catch((error) => { console.log('Something went wrong when fetching query.', error) + }) } @@ -287,10 +285,10 @@ class SearchRequest extends React.Component { } } - // When called passes the variable to MovieObject and calls it's interal function for + // When called passes the variable to SearchObject and calls it's interal function for // generating the wanted HTML createMovieObjects(item, index) { - let movie = new MovieObject(item); + let movie = new SearchObject(item); return movie.getElement(index); } @@ -345,12 +343,12 @@ class SearchRequest extends React.Component { movieToggle() { if (this.state.movieFilter) - return {this.toggleFilter('movies')}} id="category_active">Movies else - return {this.toggleFilter('movies')}} id="category_active">Movies @@ -358,12 +356,12 @@ class SearchRequest extends React.Component { showToggle() { if (this.state.showFilter) - return {this.toggleFilter('shows')}} id="category_active">TV Shows else - return {this.toggleFilter('shows')}} id="category_active">TV Shows @@ -379,21 +377,21 @@ class SearchRequest extends React.Component { pageStart={0} loadMore={this.pageForwards.bind(this)} hasMore={this.state.scrollHasMore} - loader={loader} + loader={} initialLoad={this.state.loadResults}> -
-
-
- Request new content +
+
+
+ Request new content
-
-
- +
+
+ - this._handleQueryKeyPress(event)} onChange={event => this.updateQueryState(event)} value={this.state.searchQuery}/> @@ -402,27 +400,27 @@ class SearchRequest extends React.Component {
-
- {this.state.resultHeader} -



- - {this.state.responseMovieList} +
+ {this.state.resultHeader} +



+ + {this.state.responseMovieList}
-
-
-
- Request new content +
+
+
+ Request new content
-
-
- +
+
+ - this._handleQueryKeyPress(event)} onChange={event => this.updateQueryState(event)} value={this.state.searchQuery}/> @@ -431,11 +429,11 @@ class SearchRequest extends React.Component {
-
- {this.state.resultHeader} +
+ {this.state.resultHeader}



- {this.state.responseMovieList} + {this.state.responseMovieList}
@@ -446,4 +444,4 @@ class SearchRequest extends React.Component { } -export default SearchRequest; \ No newline at end of file +export default SearchRequest; diff --git a/client/app/components/admin/Admin.jsx b/client/app/components/admin/Admin.jsx index 47d941a..50047b1 100644 --- a/client/app/components/admin/Admin.jsx +++ b/client/app/components/admin/Admin.jsx @@ -1,10 +1,5 @@ -/* - ./app/components/App.jsx - - -*/ + import React from 'react'; -import { HashRouter as Router, Route, Switch, IndexRoute } from 'react-router-dom'; import LoginForm from './LoginForm/LoginForm.jsx'; import { Provider } from 'react-redux'; @@ -16,6 +11,8 @@ import { fetchJSON } from '../http.jsx'; import Sidebar from './Sidebar.jsx'; import AdminRequestInfo from './AdminRequestInfo.jsx'; +import adminCSS from '../styles/adminComponent.jsx' + class AdminComponent extends React.Component { constructor(props) { @@ -25,6 +22,7 @@ class AdminComponent extends React.Component { } } + // Fetches all requested elements and updates the state with response componentWillMount() { fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/requests/all', 'GET') .then(result => { @@ -34,16 +32,9 @@ class AdminComponent extends React.Component { }) } + // Displays loginform if not logged in and passes response from + // api call to sidebar and infoPanel through props verifyLoggedIn() { - let adminComponentStyle = { - sidebar: { - float: 'left', - }, - selectedObjectPanel: { - float: 'left', - } - } - const logged_in = getCookie('logged_in'); if (!logged_in) { return @@ -53,20 +44,21 @@ class AdminComponent extends React.Component { let listItemSelected = undefined; const requestParam = this.props.match.params.request; + if (requestParam && this.state.requested_objects !== '') { selectedRequest = this.state.requested_objects[requestParam] - listItemSelected = requestParam + listItemSelected = requestParam; } return (
-
+
+ />
-
+
this.updateRequestStatus(event) } value={this.state.statusValue}> + + + + + ) + } + + updateRequestStatus(event) { + const eventValue = event.target.value; + const itemID = this.requestInfo.id; + + const apiData = { + type: this.requestInfo.type, + status: eventValue, + } + + fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + itemID, 'PUT', apiData) + .then((response) => { + console.log('Response, updateRequestStatus: ', response) + }) + + this.setState({ + statusValue: eventValue + }) + } + requested_by_user(request_user) { if (request_user === 'NULL') return undefined @@ -28,57 +78,52 @@ class AdminRequestInfo extends Component { ) } - displayInfo() { - let adminIndexStyle = { - wrapper: { - width: '100%', - }, - headerWrapper: { - width: '100%', - }, - poster: { - float: 'left', - minHeight: '450px', - }, - info: { - float: 'left', - minHeight: '450px', - } - } - const request = this.props.selectedRequest; + displayInfo() { + const request = this.props.selectedRequest; - if (request) { - return ( -
-
- {request.name} - {request.year} -
-
- -
-
- type: {request.type}
- status: {request.status}
- ip: {request.ip}
- user_agent: {this.userAgent(request.user_agent)}
- request_date: {request.requested_date}
- { this.requested_by_user(request.requested_by) } -
- - - -
- ) - } - } + if (request) { + return ( +
+
+ {request.name} + {request.year} +
- render() { - return ( -
{this.displayInfo()}
- ); - } +
+ type: {request.type}
+ + {this.generateStatusDropdown()}
+ + status: {request.status}
+ ip: {request.ip}
+ user_agent: {this.userAgent(request.user_agent)}
+ request_date: {request.requested_date}
+ { this.requested_by_user(request.requested_by) } +
+ +
+ {}} + style={buttonsCSS.edit} + focus={buttonsCSS.edit_hover} + hover={buttonsCSS.edit_hover}> + + Show info + + + +
+
+ ) + } + } + + render() { + return ( +
{this.displayInfo()}
+ ); + } } export default AdminRequestInfo; \ No newline at end of file diff --git a/client/app/components/admin/PirateSearch.jsx b/client/app/components/admin/PirateSearch.jsx index b1d5191..25917fa 100644 --- a/client/app/components/admin/PirateSearch.jsx +++ b/client/app/components/admin/PirateSearch.jsx @@ -1,18 +1,25 @@ import React, { Component } from 'react'; import { fetchJSON } from '../http.jsx'; +// Stylesheets +import btnStylesheet from '../styles/buttons.jsx'; + +// Interactive button +import Interactive from 'react-interactive'; + +import Loading from '../images/loading.jsx' + class PirateSearch extends Component { constructor() { super(); this.state = { response: [], name: '', + loading: '', } } sendToDownload(torrent) { - console.log(torrent.magnet) - let data = {magnet: torrent.magnet} fetchJSON('https://apollo.kevinmidboe.com/api/v1/pirate/add', 'POST', data) .then((response) => { @@ -24,10 +31,15 @@ class PirateSearch extends Component { const query = this.props.name; const type = this.props.type; + this.setState({ + loading: + }) + fetchJSON('https://apollo.kevinmidboe.com/api/v1/pirate/search?query='+query+'&type='+type, 'GET') .then((response) => { console.log(response.torrents) this.setState({ + loading: '', response: response.torrents.map((torrent, index) => { return (
@@ -46,8 +58,20 @@ class PirateSearch extends Component { render() { return (
- {this.props.name} - +
+ {this.searchTheBay()}} + style={btnStylesheet.submit} + focus={btnStylesheet.submit_hover} + hover={btnStylesheet.submit_hover}> + + Search for torrents + +
+ + { this.state.loading } + {this.state.response}
) diff --git a/client/app/components/admin/Sidebar.jsx b/client/app/components/admin/Sidebar.jsx index 5d001b0..7d48397 100644 --- a/client/app/components/admin/Sidebar.jsx +++ b/client/app/components/admin/Sidebar.jsx @@ -1,57 +1,213 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; +import Interactive from 'react-interactive'; + +import sidebarCSS from '../styles/adminSidebar.jsx' + class SidebarComponent extends Component { - generateListElements(index, item) { - if (index == this.props.listItemSelected) - return ( - {item.name} - ) - else - return ( - {item.name} - ) - } - - displayRequestedElementsInfo() { - if (this.props.requested_objects) { - let requestedElement = this.props.requested_objects.map((item, index) => { - return ( - - { this.generateListElements(index, item) } - {item.status} - {item.requested_date} - - ) - }) - - return ( - - - - - - - - - - {requestedElement} - -
NameStatusDate
- ) + constructor(props){ + super(props) + // Constructor with states holding the search query and the element of reponse. + this.state = { + filterValue: '', + filterQuery: '', + requestItemsToBeDisplayed: [], + listItemSelected: '', } } - render() { - console.log('sidebar: ', this.props.requested_objects) - return ( -
-

Hello from the sidebar:

- { this.displayRequestedElementsInfo() } -
- ); - } + // Where we wait for api response to be delivered from parent through props + componentWillReceiveProps(props) { + this.state.listItemSelected = props.listItemSelected; + this.displayRequestedElementsInfo(props.requested_objects); + } + + // Inputs a date and returns a text string that matches how long it was since + convertDateToDaysSince(date) { + var oneDay = 24*60*60*1000; + var firstDate = new Date(date); + var secondDate = new Date(); + + var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime()) / oneDay)); + + switch (diffDays) { + case 0: + return 'Today'; + case 1: + return '1 day ago' + default: + return diffDays + ' days ago' + } + } + + // Called from our dropdown, receives a filter string and checks it with status field + // of our request objects. + filterItems(filterValue) { + let filteredRequestElements = this.props.requested_objects.map((item, index) => { + if (item.status === filterValue || filterValue === 'all') + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: filteredRequestElements, + filterValue: filterValue, + }) + } + + + // Updates the internal state of the query filter and updates the list to only + // display names matching the query. This is real-time filtering. + updateFilterQuery(event) { + const query = event.target.value; + + let filteredByQuery = this.props.requested_objects.map((item, index) => { + if (item.name.toLowerCase().indexOf(query.toLowerCase()) != -1) + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: filteredByQuery, + filterQuery: query, + }); + } + + + generateFilterDropdown() { + return ( + + ) + } + + generateFilterSearchbar() { + return ( + this.updateFilterQuery(event)} + value={this.state.filterQuery}/> + ) + } + + // A colored bar indicating the status of a item by color. + generateRequestIndicator(status) { + let statusColor; + + switch (status) { + case 'requested': + // Yellow + statusColor = '#ffe14d'; + break; + case 'downloading': + // Blue + statusColor = '#3fc3f3'; + break; + case 'downloaded': + // Green + statusColor = '#6be682'; + break; + default: + statusColor = 'grey'; + } + + const indicatorCSS = { + width: '100%', + height: '4px', + marginTop: '3px', + backgroundColor: statusColor, + } + + return ( +
+ ) + } + + + generateListElements(index, item) { + if (index == this.state.listItemSelected) { + return ( +
+
+ {item.name } +
+ { this.convertDateToDaysSince(item.requested_date) } +
+
+ Status: { item.status } +
+ Matches found: 0 + { this.generateRequestIndicator(item.status) } +
+ ) + } + else + return ( + + + + {item.name } +
+ { this.convertDateToDaysSince(item.requested_date) } +
+
+ { this.generateRequestIndicator(item.status) } +
+ + ) + } + + // This is our main loader that gets called when we receive api response through props from parent + displayRequestedElementsInfo(requested_objects) { + let requestedElement = requested_objects.map((item, index) => { + if (['requested', 'downloading', 'downloaded'].indexOf(this.state.filterValue) != -1) { + if (item.status === this.state.filterValue){ + return this.generateListElements(index, item); + } + } + + else if (this.state.filterQuery !== '') { + if (item.name.toLowerCase().indexOf(this.state.filterQuery.toLowerCase()) != -1) + return this.generateListElements(index, item); + } + + else + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: requestedElement, + }) + } + + render() { + let bodyCSS = sidebarCSS.body; + if (typeof InstallTrigger !== 'undefined') + bodyCSS.width = '-moz-min-content'; + + return ( +
+

Hello from the sidebar:

+ { this.generateFilterDropdown() } + { this.generateFilterSearchbar() } +
+ { this.state.requestItemsToBeDisplayed } +
+
+ ); + } } export default SidebarComponent; \ No newline at end of file diff --git a/client/app/components/images/loading.jsx b/client/app/components/images/loading.jsx new file mode 100644 index 0000000..455e39c --- /dev/null +++ b/client/app/components/images/loading.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +function Loading() { + return ( +
+ + + + + + +
+ + ) +} + +export default Loading; \ No newline at end of file diff --git a/client/app/components/styles/adminComponent.jsx b/client/app/components/styles/adminComponent.jsx new file mode 100644 index 0000000..9e131aa --- /dev/null +++ b/client/app/components/styles/adminComponent.jsx @@ -0,0 +1,8 @@ +export default { + sidebar: { + float: 'left', + }, + selectedObjectPanel: { + float: 'left', + } +} \ No newline at end of file diff --git a/client/app/components/styles/adminRequestInfo.jsx b/client/app/components/styles/adminRequestInfo.jsx new file mode 100644 index 0000000..0d13af2 --- /dev/null +++ b/client/app/components/styles/adminRequestInfo.jsx @@ -0,0 +1,11 @@ +export default { + wrapper: { + width: '100%', + }, + headerWrapper: { + width: '100%', + }, + poster: { + minHeight: '450px', + }, +} \ No newline at end of file diff --git a/client/app/components/styles/adminSidebar.jsx b/client/app/components/styles/adminSidebar.jsx new file mode 100644 index 0000000..c10fe49 --- /dev/null +++ b/client/app/components/styles/adminSidebar.jsx @@ -0,0 +1,50 @@ +export default { + body: { + backgroundColor: 'white', + width: 'min-content', + }, + + parentElement: { + display: 'inline-block', + width: '300px', + border: '1px solid black', + borderRadius: '2px', + padding: '4px', + margin: '4px', + marginLeft: '4px', + backgroundColor: 'white', + }, + + parentElement_hover: { + marginLeft: '10px', + }, + + parentElement_active: { + textDecoration: 'none', + }, + + parentElement_selected: { + display: 'inline-block', + width: '300px', + border: '1px solid black', + borderRadius: '2px', + padding: '4px', + margin: '4px 0px 4px 4px', + marginLeft: '10px', + backgroundColor: 'white', + }, + + title: { + maxWidth: '70%', + display: 'inline-flex', + }, + + link: { + color: 'black', + textDecoration: 'none', + }, + + rightContainer: { + float: 'right', + }, +} \ No newline at end of file diff --git a/client/app/components/styles/buttons.jsx b/client/app/components/styles/buttons.jsx new file mode 100644 index 0000000..a27fdba --- /dev/null +++ b/client/app/components/styles/buttons.jsx @@ -0,0 +1,80 @@ + +export default { + + submit: { + color: '#e9a131', + marginRight: '10px', + backgroundColor: 'white', + border: '#e9a131 2px solid', + borderColor: '#e9a131', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + submit_hover: { + backgroundColor: '#e9a131', + color: 'white', + }, + + info: { + color: '#00d17c', + marginRight: '10px', + backgroundColor: 'white', + border: '#00d17c 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + info_hover: { + backgroundColor: '#00d17c', + color: 'white', + }, + + edit: { + color: '#4a95da', + marginRight: '10px', + backgroundColor: 'white', + border: '#4a95da 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + edit_small: { + color: '#4a95da', + marginRight: '10px', + backgroundColor: 'white', + border: '#4a95da 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '4px', + minWidth: '50px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + edit_hover: { + backgroundColor: '#4a95da', + color: 'white', + }, + +} \ No newline at end of file diff --git a/client/app/components/styles/movieObjectStyle.jsx b/client/app/components/styles/movieObjectStyle.jsx deleted file mode 100644 index 627d7dd..0000000 --- a/client/app/components/styles/movieObjectStyle.jsx +++ /dev/null @@ -1,101 +0,0 @@ - -export default { - resultItem: { - maxWidth: '95%', - margin: '0 auto', - minHeight: '230px' - }, - - movie_content: { - marginLeft: '15px' - }, - - resultTitleLarge: { - color: 'black', - fontSize: '2em', - }, - - resultTitleSmall: { - color: 'black', - fontSize: '22px', - }, - - yearRatingLarge: { - fontSize: '0.8em' - }, - - resultPoster: { - float: 'left', - zIndex: '3', - position: 'relative', - marginRight: '30px' - }, - - background: { - width: '100%' - }, - - yearRatingSmall: { - marginTop: '5px', - fontSize: '0.8em' - }, - - resultPosterImg: { - border: '2px none', - borderRadius: '2px', - width: '150px' - }, - - cornerRibbon: { - position: 'absolute', - width: '450px', - }, - - summary: { - fontSize: '15px', - }, - - buttons: { - paddingTop: '20px' - }, - - requestButton: { - color: '#e9a131', - marginRight: '10px', - background: 'white', - border: '#e9a131 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - }, - - tmdbButton: { - color: '#00d17c', - marginRight: '10px', - background: 'white', - border: '#00d17c 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - }, - - row: { - width: '100%' - }, - - itemDivider: { - width: '90%', - borderBottom: '1px solid grey', - margin: '2rem auto' - } -} \ No newline at end of file diff --git a/client/app/components/styles/searchObject.jsx b/client/app/components/styles/searchObject.jsx new file mode 100644 index 0000000..4d4ed72 --- /dev/null +++ b/client/app/components/styles/searchObject.jsx @@ -0,0 +1,58 @@ + +export default { + container: { + maxWidth: '95%', + margin: '0 auto', + minHeight: '230px' + }, + + title_large: { + color: 'black', + fontSize: '2em', + }, + + title_small: { + color: 'black', + fontSize: '22px', + }, + + stats_large: { + fontSize: '0.8em' + }, + + stats_small: { + marginTop: '5px', + fontSize: '0.8em' + }, + + posterContainer: { + float: 'left', + zIndex: '3', + position: 'relative', + marginRight: '30px' + }, + + posterImage: { + border: '2px none', + borderRadius: '2px', + width: '150px' + }, + + backgroundImage: { + width: '100%' + }, + + summary: { + fontSize: '15px', + }, + + dividerRow: { + width: '100%' + }, + + itemDivider: { + width: '90%', + borderBottom: '1px solid grey', + margin: '2rem auto' + } +} \ No newline at end of file diff --git a/client/app/components/styles/searchRequestStyle.jsx b/client/app/components/styles/searchRequestStyle.jsx index 45d5cff..17b5b11 100644 --- a/client/app/components/styles/searchRequestStyle.jsx +++ b/client/app/components/styles/searchRequestStyle.jsx @@ -11,12 +11,13 @@ export default { backgroundLargeHeader: { width: '100%', minHeight: '400px', - backgroundColor: '#011c23', + backgroundColor: 'rgb(1, 28, 35)', + // backgroundImage: 'radial-gradient(circle, #004c67 0, #005771 120%)', zIndex: 1, marginBottom: '-100px' }, - backgroundSmallHeader: { + backgroundSmallHeader: { width: '100%', minHeight: '300px', backgroundColor: '#011c23', @@ -31,7 +32,7 @@ export default { backgroundColor: 'white', position: 'relative', zIndex: '10', - boxShadow: '0 4px 2px black' + boxShadow: '0 1px 2px grey', }, pageTitle: { @@ -43,7 +44,7 @@ export default { pageTitleLargeSpan: { color: 'white', - fontSize: '3em', + fontSize: '4em', marginTop: '4vh', marginBottom: '6vh' }, @@ -133,70 +134,4 @@ export default { color: 'black', fontSize: '1.4em', }, - - row: { - width: '100%' - }, - - itemDivider: { - width: '90%', - borderBottom: '1px solid grey', - margin: '1rem auto' - }, - - - pageNavigationBar: { - width: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center' - }, - - pageNavigationButton: { - margin: '0 auto', - }, - - hvrUnderlineFromCenter: { - color: 'white', - fontSize: '1em', - paddingTop: '12px', - marginBottom: '12px', - marginLeft: '10px', - cursor: 'pointer', - display: 'inline-block', - verticalAlign: 'middle', - WebkitTransform: 'perspective(1px) translateZ(0)', - transform: 'perspective(1px) translateZ(0)', - boxShadow: '0 0 1px transparent', - position: 'relative', - overflow: 'hidden', - ':before': { - content: "", - position: 'absolute', - zIndex: '-1', - left: '50%', - right: '50%', - bottom: '0', - background: '#00d17c', - height: '2px', - WebkitTransitionProperty: 'left, right', - transitionProperty: 'left, right', - WebkitTransitionDuration: '0.3s', - transitionDuration: '0.3s', - WebkitTransitionTimingFunction: 'ease-out', - transitionTimingFunction: 'ease-out' - }, - ':hover:before': { - left: 0, - right: 0 - }, - 'focus:before': { - left: 0, - right: 0 - }, - 'active:before': { - left: 0, - right: 0 - } - } } \ No newline at end of file diff --git a/client/app/index.html b/client/app/index.html index 3ab7f3f..3ec9c02 100644 --- a/client/app/index.html +++ b/client/app/index.html @@ -4,7 +4,7 @@ - + seasoned Shows diff --git a/client/package.json b/client/package.json index 7d36795..f166ff8 100644 --- a/client/package.json +++ b/client/package.json @@ -19,6 +19,7 @@ "react-burger-menu": "^2.1.6", "react-dom": "^15.5.4", "react-infinite-scroller": "^1.0.15", + "react-interactive": "^0.8.1", "react-notify-toast": "^0.3.2", "react-redux": "^5.0.6", "react-responsive": "^1.3.4", diff --git a/client/webpack.common.js b/client/webpack.common.js index 114c775..0fd9a5f 100644 --- a/client/webpack.common.js +++ b/client/webpack.common.js @@ -21,8 +21,7 @@ module.exports = { ], module: { loaders: [ - { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, - { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }, + { test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /node_modules/ }, ] },