forked from DebaucheryLibrarian/traxxx
				
			Transitioning to Vue. Installed environment and restored homepage scene overview.
This commit is contained in:
		
							parent
							
								
									b8c2878fc3
								
							
						
					
					
						commit
						b8aa81b3f1
					
				
							
								
								
									
										29
									
								
								.eslintrc
								
								
								
								
							
							
						
						
									
										29
									
								
								.eslintrc
								
								
								
								
							|  | @ -1,23 +1,26 @@ | |||
| { | ||||
|     "root": true, | ||||
|     "parser": "babel-eslint", | ||||
|     "extends": ["airbnb", "plugin:react/recommended"], | ||||
|     "plugins": ["react"], | ||||
|     "extends": ["airbnb-base", "plugin:vue/recommended"], | ||||
|     "parserOptions": { | ||||
|         "sourceType": "script", | ||||
|         "ecmaFeatures": { | ||||
|             "jsx": true | ||||
|         } | ||||
|         "ecmaVersion": 2017, | ||||
|         "sourceType": "module" | ||||
|     }, | ||||
|     "rules": { | ||||
|         "strict": 0, | ||||
|         "no-unused-vars": ["error", {"argsIgnorePattern": "^_"}], | ||||
|         "no-console": 0, | ||||
|         "indent": ["error", 4], | ||||
|         "max-len": [2, {"code": 200, "tabWidth": 4, "ignoreUrls": true}], | ||||
|         "react/jsx-uses-vars": 2, | ||||
|         "react/jsx-indent": ["error", 4], | ||||
|         "react/jsx-indent-props": ["error", 4], | ||||
|         "react/jsx-one-expression-per-line": "off", | ||||
|         "max-len": [2, { | ||||
|             "code": 200, | ||||
|             "tabWidth": 4, | ||||
|             "ignoreUrls": true | ||||
|         }], | ||||
|         "vue/html-indent": ["error", 4], | ||||
|         "no-param-reassign": ["error", { | ||||
|             "props": true, | ||||
|             "ignorePropertyModificationsFor": ["state", "acc"] | ||||
|         }] | ||||
|     }, | ||||
|     "globals": { | ||||
|         "CONFIG": true | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| node_modules/ | ||||
| dist/ | ||||
| public/js/* | ||||
| public/css/* | ||||
| config/* | ||||
| !config/default.js | ||||
| db.sqlite | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| <template> | ||||
|     <div> | ||||
|         <h2>Actor</h2> | ||||
|     </div> | ||||
| </template> | ||||
|  | @ -0,0 +1,25 @@ | |||
| <template> | ||||
|     <div class="container"> | ||||
|         <Header /> | ||||
| 
 | ||||
|         <div class="content"> | ||||
|             <router-view /> | ||||
|         </div> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import Header from '../header/header.vue'; | ||||
| 
 | ||||
| export default { | ||||
|     components: { | ||||
|         Header, | ||||
|     }, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .content-inner { | ||||
|     padding: 1rem; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,5 @@ | |||
| <template> | ||||
|     <div> | ||||
|         <h1>404 - Not Found</h1> | ||||
|     </div> | ||||
| </template> | ||||
|  | @ -0,0 +1,19 @@ | |||
| <template> | ||||
|     <header class="header"> | ||||
|         <h1 class="logo">Porn Radar</h1> | ||||
|     </header> | ||||
| </template> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| @import 'theme'; | ||||
| 
 | ||||
| .header { | ||||
|     color: $text-contrast; | ||||
|     background: $primary; | ||||
|     padding: 1rem; | ||||
| } | ||||
| 
 | ||||
| .logo { | ||||
|     margin: 0; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,234 @@ | |||
| <template> | ||||
|     <div class="content-inner"> | ||||
|         <h2 class="heading">Latest releases</h2> | ||||
| 
 | ||||
|         <ul class="scenes nolist"> | ||||
|             <li | ||||
|                 v-for="release in releases" | ||||
|                 :key="release.id" | ||||
|                 class="scene" | ||||
|             > | ||||
|                 <span class="scene-banner"> | ||||
|                     <span class="scene-details"> | ||||
|                         <a | ||||
|                             :href="`/site/${release.site.id}`" | ||||
|                             :title="release.network.name" | ||||
|                             target="_blank" | ||||
|                             rel="noopener noreferrer" | ||||
|                             class="scene-site site-link" | ||||
|                         >{{ release.site.name }}</a> | ||||
| 
 | ||||
|                         <a | ||||
|                             :href="release.url" | ||||
|                             target="_blank" | ||||
|                             rel="noopener noreferrer" | ||||
|                             class="scene-date" | ||||
|                         >{{ formatDate(release.date, 'MMM D, YYYY') }}</a> | ||||
|                     </span> | ||||
| 
 | ||||
|                     <a | ||||
|                         :href="`/scene/${release.id}`" | ||||
|                         target="_blank" | ||||
|                         rel="noopener noreferrer" | ||||
|                         class="scene-link" | ||||
|                     > | ||||
|                         <img | ||||
|                             :src="`/${release.site.id}/${release.id}/0.jpg`" | ||||
|                             :alt="release.id" | ||||
|                             class="scene-thumbnail" | ||||
|                         > | ||||
|                     </a> | ||||
|                 </span> | ||||
| 
 | ||||
|                 <div class="scene-info"> | ||||
|                     <a | ||||
|                         :href="`/scene/${release.id}`" | ||||
|                         target="_blank" | ||||
|                         rel="noopener noreferrer" | ||||
|                         class="scene-row scene-link" | ||||
|                     > | ||||
|                         <h3 class="scene-title">{{ release.title }}</h3> | ||||
|                     </a> | ||||
| 
 | ||||
|                     <span class="scene-row"> | ||||
|                         <ul class="scene-actors nolist"> | ||||
|                             <li | ||||
|                                 v-for="actor in release.actors" | ||||
|                                 :key="actor.id" | ||||
|                                 class="scene-actor" | ||||
|                             > | ||||
|                                 <a | ||||
|                                     :href="`/actor/${actor.id}`" | ||||
|                                     target="_blank" | ||||
|                                     rel="noopener noreferrer" | ||||
|                                     class="actor-link" | ||||
|                                 >{{ actor.name }}</a> | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </span> | ||||
| 
 | ||||
|                     <span | ||||
|                         :title="release.tags.map(tag => tag.tag).join(', ')" | ||||
|                         class="scene-row" | ||||
|                     > | ||||
|                         <ul class="scene-tags nolist"> | ||||
|                             <li | ||||
|                                 v-for="tag in release.tags" | ||||
|                                 :key="tag.tag" | ||||
|                                 class="scene-tag" | ||||
|                             > | ||||
|                                 <a | ||||
|                                     :href="`/tag/${tag.tag}`" | ||||
|                                     target="_blank" | ||||
|                                     rel="noopener noreferrer" | ||||
|                                     class="tag-link" | ||||
|                                 >{{ tag.tag }}</a> | ||||
|                             </li> | ||||
|                         </ul> | ||||
|                     </span> | ||||
|                 </div> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| async function mounted() { | ||||
|     this.releases = await this.$store.dispatch('fetchReleases'); | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|     data() { | ||||
|         return { | ||||
|             releases: [], | ||||
|         }; | ||||
|     }, | ||||
|     mounted, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| @import 'theme'; | ||||
| 
 | ||||
| .scenes { | ||||
|     display: grid; | ||||
|     grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); | ||||
|     grid-gap: 1rem; | ||||
| } | ||||
| 
 | ||||
| .scene { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 0 .5rem 0;; | ||||
|     border-radius: .25rem; | ||||
|     overflow: hidden; | ||||
|     box-shadow: 0 0 3px rgba(0, 0, 0, .25); | ||||
| } | ||||
| 
 | ||||
| .scene-banner { | ||||
|     position: relative; | ||||
|     margin: 0 0 .5rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-thumbnail { | ||||
|     width: 100%; | ||||
|     height: 200px; | ||||
|     display: block; | ||||
|     background-position: center; | ||||
|     background-size: cover; | ||||
|     object-fit: cover; | ||||
| } | ||||
| 
 | ||||
| .scene-row { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 .5rem; | ||||
|     margin: 0 0 .25rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-details { | ||||
|     width: 100%; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     position: absolute; | ||||
| } | ||||
| 
 | ||||
| .scene-site, | ||||
| .scene-date { | ||||
|     color: #fff; | ||||
|     background: rgba(0, 0, 0, .5); | ||||
|     font-size: .8rem; | ||||
|     padding: .25rem; | ||||
|     text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .scene-site { | ||||
|     border-radius: 0 0 .25rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-date { | ||||
|     border-radius: 0 0 0 .25rem; | ||||
| } | ||||
| 
 | ||||
| .scene-info { | ||||
|     flex-grow: 1; | ||||
| } | ||||
| 
 | ||||
| .scene-link { | ||||
|     text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .scene-title { | ||||
|     color: #000; | ||||
|     margin: 0; | ||||
|     font-size: 1rem; | ||||
|     word-wrap: break-word; | ||||
|     overflow: hidden; | ||||
|     max-height: 3rem; | ||||
|     line-height: 1.5rem; | ||||
| } | ||||
| 
 | ||||
| .scene-network { | ||||
|     color: #555; | ||||
|     margin: 0 .25rem 0 0; | ||||
|     font-size: .8rem; | ||||
| } | ||||
| 
 | ||||
| .scene-tags { | ||||
|     word-wrap: break-word; | ||||
|     overflow: hidden; | ||||
|     max-height: 2.5rem; | ||||
|     line-height: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .scene-actor, | ||||
| .scene-tag { | ||||
|     margin: 0 .25rem 0 0; | ||||
| } | ||||
| 
 | ||||
| .scene-actor { | ||||
|     font-size: .9rem; | ||||
| } | ||||
| 
 | ||||
| .scene-tag { | ||||
|     font-size: .75rem; | ||||
| } | ||||
| 
 | ||||
| .scene-actor:not(:last-of-type)::after, | ||||
| .scene-tag:not(:last-of-type):after { | ||||
|     content: ","; | ||||
| } | ||||
| 
 | ||||
| .actor-link, | ||||
| .tag-link { | ||||
|     color: #000; | ||||
| } | ||||
| 
 | ||||
| .thumbnail { | ||||
|     width: 300px; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,5 @@ | |||
| <template> | ||||
|     <div> | ||||
|         <h2>Release</h2> | ||||
|     </div> | ||||
| </template> | ||||
|  | @ -0,0 +1,4 @@ | |||
| $primary: #ff886c; | ||||
| 
 | ||||
| $text: #222; | ||||
| $text-contrast: #fff; | ||||
|  | @ -0,0 +1,25 @@ | |||
| @import 'theme'; | ||||
| 
 | ||||
| html, | ||||
| body { | ||||
|     height: 100%; | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|     margin: 0; | ||||
| } | ||||
| 
 | ||||
| .nolist { | ||||
|     list-style: none; | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
| 
 | ||||
|     li { | ||||
|         display: inline-block; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| .heading { | ||||
|     color: $primary; | ||||
|     margin: 0 0 1rem 0; | ||||
| } | ||||
|  | @ -0,0 +1,41 @@ | |||
| import config from 'config'; | ||||
| 
 | ||||
| async function get(endpoint, query = {}) { | ||||
|     const queryString = Object.entries(query).reduce((acc, [key, value], index) => `${acc}${index > 0 ? '&' : ''}${key}=${value}`, '?'); | ||||
| 
 | ||||
|     const res = await fetch(`${config.api.url}${endpoint}${queryString}`, { | ||||
|         method: 'GET', | ||||
|         mode: 'cors', | ||||
|         credentials: 'same-origin', | ||||
|     }); | ||||
| 
 | ||||
|     if (res.ok) { | ||||
|         return res.json(); | ||||
|     } | ||||
| 
 | ||||
|     const errorMsg = await res.text(); | ||||
| 
 | ||||
|     throw new Error(errorMsg); | ||||
| } | ||||
| 
 | ||||
| async function post(endpoint, data) { | ||||
|     const res = await fetch(`${config.api.url}${endpoint}`, { | ||||
|         method: 'GET', | ||||
|         mode: 'cors', | ||||
|         headers: { | ||||
|             'Content-Type': 'application/json', | ||||
|         }, | ||||
|         credentials: 'same-origin', | ||||
|         body: JSON.stringify(data), | ||||
|     }); | ||||
| 
 | ||||
|     if (res.ok) { | ||||
|         return res.json(); | ||||
|     } | ||||
| 
 | ||||
|     const errorMsg = await res.text(); | ||||
| 
 | ||||
|     throw new Error(errorMsg); | ||||
| } | ||||
| 
 | ||||
| export { get, post }; | ||||
|  | @ -0,0 +1,3 @@ | |||
| function initAuthActions(_store, _router) {} | ||||
| 
 | ||||
| export default initAuthActions; | ||||
|  | @ -0,0 +1,13 @@ | |||
| import state from './state'; | ||||
| import mutations from './mutations'; | ||||
| import actions from './actions'; | ||||
| 
 | ||||
| function initAuthStore(store, router) { | ||||
|     return { | ||||
|         state, | ||||
|         mutations, | ||||
|         actions: actions(store, router), | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| export default initAuthStore; | ||||
|  | @ -0,0 +1 @@ | |||
| export default {}; | ||||
|  | @ -0,0 +1,4 @@ | |||
| export default { | ||||
|     authenticated: false, | ||||
|     user: null, | ||||
| }; | ||||
|  | @ -0,0 +1,5 @@ | |||
| export default { | ||||
|     api: { | ||||
|         url: `${window.location.origin}/api`, | ||||
|     }, | ||||
| }; | ||||
|  | @ -0,0 +1,30 @@ | |||
| import Vue from 'vue'; | ||||
| import dayjs from 'dayjs'; | ||||
| 
 | ||||
| import router from './router'; | ||||
| import initStore from './store'; | ||||
| 
 | ||||
| import '../css/style.scss'; | ||||
| 
 | ||||
| import Container from '../components/container/container.vue'; | ||||
| 
 | ||||
| function init() { | ||||
|     const store = initStore(router); | ||||
| 
 | ||||
|     Vue.mixin({ | ||||
|         methods: { | ||||
|             formatDate: (date, format) => dayjs(date).format(format), | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     new Vue({ // eslint-disable-line no-new
 | ||||
|         el: '#container', | ||||
|         store, | ||||
|         router, | ||||
|         render(createElement) { | ||||
|             return createElement(Container); | ||||
|         }, | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| init(); | ||||
|  | @ -0,0 +1,15 @@ | |||
| import { get } from '../api'; | ||||
| 
 | ||||
| function initReleasesActions(_store, _router) { | ||||
|     async function fetchReleases({ _commit }, releaseId) { | ||||
|         const releases = await get(`/releases/${releaseId || ''}`); | ||||
| 
 | ||||
|         return releases; | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|         fetchReleases, | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| export default initReleasesActions; | ||||
|  | @ -0,0 +1 @@ | |||
| export default {}; | ||||
|  | @ -0,0 +1,13 @@ | |||
| import state from './state'; | ||||
| import mutations from './mutations'; | ||||
| import actions from './actions'; | ||||
| 
 | ||||
| function initReleasesStore(store, router) { | ||||
|     return { | ||||
|         state, | ||||
|         mutations, | ||||
|         actions: actions(store, router), | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| export default initReleasesStore; | ||||
|  | @ -0,0 +1,4 @@ | |||
| export default { | ||||
|     authenticated: false, | ||||
|     user: null, | ||||
| }; | ||||
|  | @ -0,0 +1,39 @@ | |||
| import Vue from 'vue'; | ||||
| import VueRouter from 'vue-router'; | ||||
| 
 | ||||
| import Home from '../components/home/home.vue'; | ||||
| import Release from '../components/release/release.vue'; | ||||
| import Actor from '../components/actor/actor.vue'; | ||||
| import NotFound from '../components/errors/not-found.vue'; | ||||
| 
 | ||||
| Vue.use(VueRouter); | ||||
| 
 | ||||
| const routes = [ | ||||
|     { | ||||
|         path: '/', | ||||
|         component: Home, | ||||
|     }, | ||||
|     { | ||||
|         path: '/scene/:releaseId', | ||||
|         component: Release, | ||||
|     }, | ||||
|     { | ||||
|         path: '/movie/:releaseId', | ||||
|         component: Release, | ||||
|     }, | ||||
|     { | ||||
|         path: '/actor/:actorSlug', | ||||
|         component: Actor, | ||||
|     }, | ||||
|     { | ||||
|         path: '*', | ||||
|         component: NotFound, | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| const router = new VueRouter({ | ||||
|     mode: 'history', | ||||
|     routes, | ||||
| }); | ||||
| 
 | ||||
| export default router; | ||||
|  | @ -0,0 +1,18 @@ | |||
| import Vue from 'vue'; | ||||
| import Vuex from 'vuex'; | ||||
| 
 | ||||
| import initAuthStore from './auth/auth'; | ||||
| import initReleasesStore from './releases/releases'; | ||||
| 
 | ||||
| function initStore(router) { | ||||
|     Vue.use(Vuex); | ||||
| 
 | ||||
|     const store = new Vuex.Store(); | ||||
| 
 | ||||
|     store.registerModule('auth', initAuthStore(store, router)); | ||||
|     store.registerModule('releases', initReleasesStore(store, router)); | ||||
| 
 | ||||
|     return store; | ||||
| } | ||||
| 
 | ||||
| export default initStore; | ||||
|  | @ -0,0 +1,11 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| const React = require('react'); | ||||
| 
 | ||||
| const Header = () => ( | ||||
|     <header className="header"> | ||||
|         <h1>Porn Radar</h1> | ||||
|     </header> | ||||
| ); | ||||
| 
 | ||||
| module.exports = Header; | ||||
|  | @ -3,6 +3,8 @@ | |||
| const React = require('react'); | ||||
| const PropTypes = require('prop-types'); | ||||
| 
 | ||||
| const Header = require('./header.jsx'); | ||||
| 
 | ||||
| const Layout = ({ children, title }) => ( | ||||
|     <html lang="en"> | ||||
|         <head> | ||||
|  | @ -15,9 +17,7 @@ const Layout = ({ children, title }) => ( | |||
|         </head> | ||||
| 
 | ||||
|         <body> | ||||
|             <header> | ||||
|                 <h1>Porn Radar</h1> | ||||
|             </header> | ||||
|             <Header /> | ||||
| 
 | ||||
|             <div className="content"> | ||||
|                 {children} | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								package.json
								
								
								
								
							
							
						
						
									
										36
									
								
								package.json
								
								
								
								
							|  | @ -6,6 +6,9 @@ | |||
|     "scripts": { | ||||
|         "postinstall": "npm run migrate && npm run seed", | ||||
|         "start": "node src/app.js", | ||||
|         "webpack": "webpack --env=production --mode=production", | ||||
|         "webpack-dev": "webpack --env=development --mode=development", | ||||
|         "webpack-watch": "webpack --progress --colors --watch --env=development --mode=development", | ||||
|         "eslint": "eslint src/", | ||||
|         "eslint-watch": "esw --watch src/", | ||||
|         "knex": "knex", | ||||
|  | @ -29,23 +32,43 @@ | |||
|     "license": "ISC", | ||||
|     "devDependencies": { | ||||
|         "@babel/cli": "^7.2.3", | ||||
|         "@babel/core": "^7.3.4", | ||||
|         "@babel/preset-env": "^7.3.4", | ||||
|         "@babel/core": "^7.4.5", | ||||
|         "@babel/preset-env": "^7.4.5", | ||||
|         "autoprefixer": "^9.5.1", | ||||
|         "babel-cli": "^6.26.0", | ||||
|         "babel-eslint": "^10.0.1", | ||||
|         "babel-loader": "^8.0.6", | ||||
|         "babel-preset-airbnb": "^3.2.0", | ||||
|         "eslint": "^5.15.0", | ||||
|         "babel-register": "^6.26.0", | ||||
|         "css-loader": "^2.1.1", | ||||
|         "eslint": "^5.16.0", | ||||
|         "eslint-config-airbnb": "^17.1.0", | ||||
|         "eslint-plugin-import": "^2.16.0", | ||||
|         "eslint-config-airbnb-base": "^13.1.0", | ||||
|         "eslint-loader": "^2.1.2", | ||||
|         "eslint-plugin-import": "^2.17.3", | ||||
|         "eslint-plugin-jsx-a11y": "^6.2.1", | ||||
|         "eslint-plugin-react": "^7.13.0", | ||||
|         "eslint-watch": "^4.0.2" | ||||
|         "eslint-plugin-vue": "^5.2.2", | ||||
|         "eslint-watch": "^4.0.2", | ||||
|         "mini-css-extract-plugin": "^0.7.0", | ||||
|         "node-sass": "^4.12.0", | ||||
|         "postcss-loader": "^3.0.0", | ||||
|         "raw-loader": "^2.0.0", | ||||
|         "sass-loader": "^7.1.0", | ||||
|         "style-loader": "^0.23.1", | ||||
|         "vue-loader": "^15.7.0", | ||||
|         "vue-template-compiler": "^2.6.10", | ||||
|         "webpack": "^4.32.2", | ||||
|         "webpack-cli": "^3.3.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "bhttp": "^1.2.4", | ||||
|         "bluebird": "^3.5.4", | ||||
|         "body-parser": "^1.19.0", | ||||
|         "cheerio": "^1.0.0-rc.2", | ||||
|         "clipboardy": "^1.2.3", | ||||
|         "config": "^3.0.1", | ||||
|         "dayjs": "^1.8.14", | ||||
|         "express": "^4.16.4", | ||||
|         "express-promise-router": "^3.0.3", | ||||
|         "express-react-views": "^0.11.0", | ||||
|  | @ -62,6 +85,9 @@ | |||
|         "sqlite3": "^4.0.6", | ||||
|         "tough-cookie": "^3.0.1", | ||||
|         "tty-table": "^2.7.0", | ||||
|         "vue": "^2.6.10", | ||||
|         "vue-router": "^3.0.6", | ||||
|         "vuex": "^3.1.1", | ||||
|         "yargs": "^13.2.2" | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,138 +1,135 @@ | |||
| body { | ||||
|     margin: 0; | ||||
| .scenes[data-v-5533e378] { | ||||
|   display: grid; | ||||
|   grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); | ||||
|   grid-gap: 1rem; | ||||
| } | ||||
| .scene[data-v-5533e378] { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   box-sizing: border-box; | ||||
|   padding: 0 0 .5rem 0; | ||||
|   border-radius: .25rem; | ||||
|   overflow: hidden; | ||||
|   box-shadow: 0 0 3px rgba(0, 0, 0, 0.25); | ||||
| } | ||||
| .scene-banner[data-v-5533e378] { | ||||
|   position: relative; | ||||
|   margin: 0 0 .5rem 0; | ||||
| } | ||||
| .scene-thumbnail[data-v-5533e378] { | ||||
|   width: 100%; | ||||
|   height: 200px; | ||||
|   display: block; | ||||
|   background-position: center; | ||||
|   background-size: cover; | ||||
|   -o-object-fit: cover; | ||||
|      object-fit: cover; | ||||
| } | ||||
| .scene-row[data-v-5533e378] { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   box-sizing: border-box; | ||||
|   padding: 0 .5rem; | ||||
|   margin: 0 0 .25rem 0; | ||||
| } | ||||
| .scene-details[data-v-5533e378] { | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: space-between; | ||||
|   position: absolute; | ||||
| } | ||||
| .scene-site[data-v-5533e378], | ||||
| .scene-date[data-v-5533e378] { | ||||
|   color: #fff; | ||||
|   background: rgba(0, 0, 0, 0.5); | ||||
|   font-size: .8rem; | ||||
|   padding: .25rem; | ||||
|   text-decoration: none; | ||||
| } | ||||
| .scene-site[data-v-5533e378] { | ||||
|   border-radius: 0 0 .25rem 0; | ||||
| } | ||||
| .scene-date[data-v-5533e378] { | ||||
|   border-radius: 0 0 0 .25rem; | ||||
| } | ||||
| .scene-info[data-v-5533e378] { | ||||
|   flex-grow: 1; | ||||
| } | ||||
| .scene-link[data-v-5533e378] { | ||||
|   text-decoration: none; | ||||
| } | ||||
| .scene-title[data-v-5533e378] { | ||||
|   color: #000; | ||||
|   margin: 0; | ||||
|   font-size: 1rem; | ||||
|   word-wrap: break-word; | ||||
|   overflow: hidden; | ||||
|   max-height: 3rem; | ||||
|   line-height: 1.5rem; | ||||
| } | ||||
| .scene-network[data-v-5533e378] { | ||||
|   color: #555; | ||||
|   margin: 0 .25rem 0 0; | ||||
|   font-size: .8rem; | ||||
| } | ||||
| .scene-tags[data-v-5533e378] { | ||||
|   word-wrap: break-word; | ||||
|   overflow: hidden; | ||||
|   max-height: 2.5rem; | ||||
|   line-height: 1.25rem; | ||||
| } | ||||
| .scene-actor[data-v-5533e378], | ||||
| .scene-tag[data-v-5533e378] { | ||||
|   margin: 0 .25rem 0 0; | ||||
| } | ||||
| .scene-actor[data-v-5533e378] { | ||||
|   font-size: .9rem; | ||||
| } | ||||
| .scene-tag[data-v-5533e378] { | ||||
|   font-size: .75rem; | ||||
| } | ||||
| .scene-actor[data-v-5533e378]:not(:last-of-type)::after, | ||||
| .scene-tag[data-v-5533e378]:not(:last-of-type):after { | ||||
|   content: ","; | ||||
| } | ||||
| .actor-link[data-v-5533e378], | ||||
| .tag-link[data-v-5533e378] { | ||||
|   color: #000; | ||||
| } | ||||
| .thumbnail[data-v-5533e378] { | ||||
|   width: 300px; | ||||
| } | ||||
| 
 | ||||
| html, | ||||
| body { | ||||
|   height: 100%; } | ||||
| 
 | ||||
| body { | ||||
|   margin: 0; } | ||||
| 
 | ||||
| .nolist { | ||||
|     list-style: none; | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
|   margin: 0; } | ||||
|   .nolist li { | ||||
|     display: inline-block; } | ||||
| 
 | ||||
| .heading { | ||||
|   color: #ff886c; | ||||
|   margin: 0 0 1rem 0; } | ||||
| 
 | ||||
| .header[data-v-10b7ec04] { | ||||
|   color: #fff; | ||||
|   background: #ff886c; | ||||
|   padding: 1rem; | ||||
| } | ||||
| .logo[data-v-10b7ec04] { | ||||
|   margin: 0; | ||||
| } | ||||
| 
 | ||||
| .nolist li { | ||||
|     display: inline-block; | ||||
| .content-inner[data-v-4f86a868] { | ||||
|   padding: 1rem; | ||||
| } | ||||
| 
 | ||||
| .scenes { | ||||
|     display: grid; | ||||
|     grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); | ||||
|     list-style: none; | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
| } | ||||
| 
 | ||||
| .scene { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 0 .5rem 0;; | ||||
|     border-radius: .25rem; | ||||
|     margin: .5rem; | ||||
|     overflow: hidden; | ||||
|     box-shadow: 0 0 3px rgba(0, 0, 0, .25); | ||||
| } | ||||
| 
 | ||||
| .scene-banner { | ||||
|     position: relative; | ||||
|     margin: 0 0 .5rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-thumbnail { | ||||
|     width: 100%; | ||||
|     height: 200px; | ||||
|     display: block; | ||||
|     background-position: center; | ||||
|     background-size: cover; | ||||
|     object-fit: cover; | ||||
| } | ||||
| 
 | ||||
| .scene-row { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 .5rem; | ||||
|     margin: 0 0 .25rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-details { | ||||
|     width: 100%; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     position: absolute; | ||||
| } | ||||
| 
 | ||||
| .scene-site, | ||||
| .scene-date { | ||||
|     color: #fff; | ||||
|     background: rgba(0, 0, 0, .5); | ||||
|     font-size: .8rem; | ||||
|     padding: .25rem; | ||||
|     text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .scene-site { | ||||
|     border-radius: 0 0 .25rem 0; | ||||
| } | ||||
| 
 | ||||
| .scene-date { | ||||
|     border-radius: 0 0 0 .25rem; | ||||
| } | ||||
| 
 | ||||
| .scene-info { | ||||
|     flex-grow: 1; | ||||
| } | ||||
| 
 | ||||
| .scene-link { | ||||
|     text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .scene-title { | ||||
|     color: #000; | ||||
|     margin: 0; | ||||
|     font-size: 1rem; | ||||
|     word-wrap: break-word; | ||||
|     overflow: hidden; | ||||
|     max-height: 3rem; | ||||
|     line-height: 1.5rem; | ||||
| } | ||||
| 
 | ||||
| .scene-network { | ||||
|     color: #555; | ||||
|     margin: 0 .25rem 0 0; | ||||
|     font-size: .8rem; | ||||
| } | ||||
| 
 | ||||
| .scene-tags { | ||||
|     word-wrap: break-word; | ||||
|     overflow: hidden; | ||||
|     max-height: 2.5rem; | ||||
|     line-height: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .scene-actor, | ||||
| .scene-tag { | ||||
|     margin: 0 .25rem 0 0; | ||||
| } | ||||
| 
 | ||||
| .scene-actor { | ||||
|     font-size: .9rem; | ||||
| } | ||||
| 
 | ||||
| .scene-tag { | ||||
|     font-size: .75rem; | ||||
| } | ||||
| 
 | ||||
| .scene-actor:not(:last-of-type)::after, | ||||
| .scene-tag:not(:last-of-type):after { | ||||
|     content: ","; | ||||
| } | ||||
| 
 | ||||
| .actor-link, | ||||
| .tag-link { | ||||
|     color: #000; | ||||
| } | ||||
| 
 | ||||
| .thumbnail { | ||||
|     width: 300px; | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
|     <head> | ||||
|         <meta charset="UTF-8"> | ||||
|         <title>Porn Radar</title> | ||||
| 
 | ||||
|         <script src="/js/bundle.js" defer></script> | ||||
| 
 | ||||
|         <link href="/css/style.css" rel="stylesheet"> | ||||
|     </head> | ||||
|     <body> | ||||
|         <div id="container"></div> | ||||
|     </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,13 @@ | |||
| { | ||||
|     "extends": "airbnb-base", | ||||
|     "parserOptions": { | ||||
|         "sourceType": "script" | ||||
|     }, | ||||
|     "rules": { | ||||
|         "strict": 0, | ||||
|         "no-unused-vars": ["error", {"argsIgnorePattern": "^_"}], | ||||
|         "no-console": 0, | ||||
|         "indent": ["error", 4], | ||||
|         "max-len": [2, {"code": 200, "tabWidth": 4, "ignoreUrls": true}] | ||||
|     } | ||||
| } | ||||
|  | @ -42,12 +42,10 @@ function getMethod() { | |||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     return null; | ||||
|     return initServer(); | ||||
| } | ||||
| 
 | ||||
| async function init() { | ||||
|     initServer(); | ||||
| 
 | ||||
|     const screen = argv.render && !argv.filename && initScreen(); | ||||
| 
 | ||||
|     try { | ||||
|  |  | |||
|  | @ -47,6 +47,8 @@ function curateReleases(releases) { | |||
| } | ||||
| 
 | ||||
| async function fetchReleases(releaseId) { | ||||
|     // const thumbnails = await fs.readdir(path.join(config.thumbnailPath, release.site.id.toString(), release.id.toString()));
 | ||||
| 
 | ||||
|     const releases = await knex('releases') | ||||
|         .where(releaseId ? { 'releases.id': releaseId } : {}) | ||||
|         .select('releases.*', 'sites.name as site_name', 'sites.url as site_url', 'sites.network_id', 'networks.name as network_name', 'networks.url as network_url') | ||||
|  |  | |||
|  | @ -1,25 +1,13 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| const config = require('config'); | ||||
| const fs = require('fs').promises; | ||||
| const path = require('path'); | ||||
| 
 | ||||
| const { fetchReleases } = require('../releases'); | ||||
| 
 | ||||
| async function fetchReleasesApi(req, res) { | ||||
|     const releases = await fetchReleases(); | ||||
|     const releases = await fetchReleases(req.params.releaseId); | ||||
| 
 | ||||
|     res.render('home', { releases }); | ||||
| } | ||||
| 
 | ||||
| async function fetchReleaseApi(req, res) { | ||||
|     const [release] = await fetchReleases(req.params.id); | ||||
|     const thumbnails = await fs.readdir(path.join(config.thumbnailPath, release.site.id.toString(), release.id.toString())); | ||||
| 
 | ||||
|     res.render('release', { release, thumbnails }); | ||||
|     res.send(releases); | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|     fetchReleases: fetchReleasesApi, | ||||
|     fetchRelease: fetchReleaseApi, | ||||
| }; | ||||
|  |  | |||
|  | @ -4,23 +4,24 @@ const path = require('path'); | |||
| const config = require('config'); | ||||
| const express = require('express'); | ||||
| const Router = require('express-promise-router'); | ||||
| const { createEngine } = require('express-react-views'); | ||||
| const bodyParser = require('body-parser'); | ||||
| 
 | ||||
| const { fetchReleases, fetchRelease } = require('./releases'); | ||||
| const { fetchReleases } = require('./releases'); | ||||
| 
 | ||||
| function initServer() { | ||||
|     const app = express(); | ||||
|     const router = Router(); | ||||
| 
 | ||||
|     app.use(express.static(config.thumbnailPath)); | ||||
|     app.use(express.static('public')); | ||||
|     router.use(express.static(config.thumbnailPath)); | ||||
|     router.use(express.static('public')); | ||||
|     router.use(bodyParser.json({ strict: false })); | ||||
| 
 | ||||
|     app.set('views', path.join(__dirname, '../../assets/views')); | ||||
|     app.set('view engine', 'jsx'); | ||||
|     app.engine('jsx', createEngine()); | ||||
|     router.get('/api/releases', fetchReleases); | ||||
|     router.get('/api/releases/:releaseId', fetchReleases); | ||||
| 
 | ||||
|     router.get('/', fetchReleases); | ||||
|     router.get('/scene/:id', fetchRelease); | ||||
|     router.get('*', (req, res) => { | ||||
|         res.sendFile(path.join(__dirname, '../../public/index.html')); | ||||
|     }); | ||||
| 
 | ||||
|     app.use(router); | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,70 @@ | |||
| import path from 'path'; | ||||
| import VueLoaderPlugin from 'vue-loader/lib/plugin'; | ||||
| import MiniCssExtractPlugin from 'mini-css-extract-plugin'; | ||||
| import autoprefixer from 'autoprefixer'; | ||||
| 
 | ||||
| export default { | ||||
|     entry: './assets/js/main.js', | ||||
|     output: { | ||||
|         filename: 'bundle.js', | ||||
|         path: path.join(__dirname, 'public/js'), | ||||
|     }, | ||||
|     module: { | ||||
|         rules: [ | ||||
|             { | ||||
|                 test: /\.vue$/, | ||||
|                 include: [ | ||||
|                     path.resolve(__dirname, 'assets'), | ||||
|                 ], | ||||
|                 loader: 'vue-loader', | ||||
|             }, | ||||
|             { | ||||
|                 test: /\.js$/, | ||||
|                 exclude: /node_modules/, | ||||
|                 use: [ | ||||
|                     { | ||||
|                         loader: 'babel-loader', | ||||
|                         options: { | ||||
|                             babelrc: false, | ||||
|                             plugins: [ | ||||
|                                 '@babel/plugin-proposal-object-rest-spread', | ||||
|                             ], | ||||
|                         }, | ||||
|                     }, | ||||
|                     'eslint-loader', | ||||
|                 ], | ||||
|             }, | ||||
|             { | ||||
|                 test: /\.scss$/, | ||||
|                 use: [ | ||||
|                     MiniCssExtractPlugin.loader, | ||||
|                     'css-loader?sourceMap', | ||||
|                     { | ||||
|                         loader: 'postcss-loader', | ||||
|                         options: { | ||||
|                             plugins: [autoprefixer], | ||||
|                             sourceMap: true, | ||||
|                         }, | ||||
|                     }, | ||||
|                     'sass-loader?sourceMap', | ||||
|                 ], | ||||
|             }, | ||||
|             { | ||||
|                 test: /\.svg/, | ||||
|                 use: 'raw-loader', | ||||
|             }, | ||||
|         ], | ||||
|     }, | ||||
|     plugins: [ | ||||
|         new VueLoaderPlugin(), | ||||
|         new MiniCssExtractPlugin({ | ||||
|             filename: '../css/style.css', | ||||
|         }), | ||||
|     ], | ||||
|     resolve: { | ||||
|         alias: { | ||||
|             theme: path.join(__dirname, 'assets/css/_theme.scss'), | ||||
|             config: path.join(__dirname, `assets/js/config/${process.env.NODE_ENV || 'default'}.js`), | ||||
|         }, | ||||
|     }, | ||||
| }; | ||||
		Loading…
	
		Reference in New Issue