Testing out bottom align mobile navigation content
This commit is contained in:
		| @@ -1,12 +1,17 @@ | ||||
| <template> | ||||
|   <header :class="{ 'sticky': sticky }"> | ||||
|   <header :class="{ sticky: sticky }"> | ||||
|     <h2>{{ title }}</h2> | ||||
|  | ||||
|     <div v-if="info instanceof Array" class="flex flex-direction-column"> | ||||
|       <span v-for="item in info" class="info">{{ item }}</span> | ||||
|     </div> | ||||
|     <span v-else class="info">{{ info }}</span> | ||||
|     <router-link v-if="link" :to="link" class='view-more' :aria-label="`View all ${title}`"> | ||||
|     <router-link | ||||
|       v-if="link" | ||||
|       :to="link" | ||||
|       class="view-more" | ||||
|       :aria-label="`View all ${title}`" | ||||
|     > | ||||
|       View All | ||||
|     </router-link> | ||||
|   </header> | ||||
| @@ -33,31 +38,38 @@ export default { | ||||
|       required: false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import './src/scss/variables'; | ||||
| @import './src/scss/media-queries'; | ||||
| @import './src/scss/main'; | ||||
| @import "./src/scss/variables"; | ||||
| @import "./src/scss/media-queries"; | ||||
| @import "./src/scss/main"; | ||||
|  | ||||
| header { | ||||
|   width: 100%; | ||||
|   min-height: 80px; | ||||
|   min-height: 45px; | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
|   padding-left: 0.75rem; | ||||
|   padding-right: 0.75rem; | ||||
|  | ||||
|   @include tablet-min { | ||||
|     min-height: 65px; | ||||
|   } | ||||
|  | ||||
|   &.sticky { | ||||
|     background-color: $background-color; | ||||
|  | ||||
|     position: sticky; | ||||
|     position: -webkit-sticky; | ||||
|     top: $header-size; | ||||
|     top: 0; | ||||
|     z-index: 4; | ||||
|  | ||||
|     @include tablet-min { | ||||
|       top: $header-size; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   h2 { | ||||
| @@ -72,16 +84,16 @@ header { | ||||
|   .view-more { | ||||
|     font-size: 0.9rem; | ||||
|     font-weight: 300; | ||||
|     letter-spacing: .5px; | ||||
|     letter-spacing: 0.5px; | ||||
|     color: $text-color-70; | ||||
|     text-decoration: none; | ||||
|     transition: color .5s ease; | ||||
|     transition: color 0.5s ease; | ||||
|     cursor: pointer; | ||||
|  | ||||
|     &:after{ | ||||
|     &:after { | ||||
|       content: " →"; | ||||
|     } | ||||
|     &:hover{ | ||||
|     &:hover { | ||||
|       color: $text-color; | ||||
|     } | ||||
|   } | ||||
| @@ -89,18 +101,17 @@ header { | ||||
|   .info { | ||||
|     font-size: 13px; | ||||
|     font-weight: 300; | ||||
|     letter-spacing: .5px; | ||||
|     letter-spacing: 0.5px; | ||||
|     color: $text-color; | ||||
|     text-decoration: none; | ||||
|     text-align: right; | ||||
|   } | ||||
|  | ||||
|   @include tablet-min { | ||||
|     padding-left: 1.25rem;; | ||||
|     padding-left: 1.25rem; | ||||
|   } | ||||
|   @include desktop-lg-min { | ||||
|     padding-left: 1.75rem; | ||||
|   } | ||||
| } | ||||
|  | ||||
| </style> | ||||
| @@ -1,6 +1,5 @@ | ||||
|  | ||||
| <template> | ||||
|   <div> | ||||
|   <div class="page-container"> | ||||
|     <list-header :title="listTitle" :info="info" :sticky="true" /> | ||||
|  | ||||
|     <results-list :results="results" v-if="results" /> | ||||
| @@ -13,96 +12,107 @@ | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
|  | ||||
| <script> | ||||
| import ListHeader from '@/components/ListHeader' | ||||
| import ResultsList from '@/components/ResultsList' | ||||
| import SeasonedButton from '@/components/ui/SeasonedButton' | ||||
| import Loader from '@/components/ui/Loader' | ||||
| import { getTmdbMovieListByName, getRequests } from '@/api' | ||||
| import store from '@/store' | ||||
| import ListHeader from "@/components/ListHeader"; | ||||
| import ResultsList from "@/components/ResultsList"; | ||||
| import SeasonedButton from "@/components/ui/SeasonedButton"; | ||||
| import Loader from "@/components/ui/Loader"; | ||||
| import { getTmdbMovieListByName, getRequests } from "@/api"; | ||||
| import store from "@/store"; | ||||
|  | ||||
| export default { | ||||
|   components: { ListHeader, ResultsList, SeasonedButton, Loader }, | ||||
|   data() { | ||||
|     return { | ||||
|       legalTmdbLists: [ 'now_playing', 'upcoming', 'popular' ], | ||||
|       legalTmdbLists: ["now_playing", "upcoming", "popular"], | ||||
|       results: [], | ||||
|       page: 1, | ||||
|       totalPages: 0, | ||||
|       totalResults: 0, | ||||
|       loading: true | ||||
|     } | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     listTitle() { | ||||
|       if (this.results.length === 0) | ||||
|         return '' | ||||
|       if (this.results.length === 0) return ""; | ||||
|  | ||||
|       const routeListName = this.$route.params.name | ||||
|       console.log('routelistname', routeListName) | ||||
|       return routeListName.includes('_') ? routeListName.split('_').join(' ') : routeListName | ||||
|       const routeListName = this.$route.params.name; | ||||
|       console.log("routelistname", routeListName); | ||||
|       return routeListName.includes("_") | ||||
|         ? routeListName.split("_").join(" ") | ||||
|         : routeListName; | ||||
|     }, | ||||
|     info() { | ||||
|       if (this.results.length === 0) | ||||
|         return [null, null] | ||||
|       return [this.pageCount, this.resultCount] | ||||
|       if (this.results.length === 0) return [null, null]; | ||||
|       return [this.pageCount, this.resultCount]; | ||||
|     }, | ||||
|     resultCount() { | ||||
|       const loadedResults = this.results.length | ||||
|       const totalResults = this.totalResults < 10000 ? this.totalResults : '∞' | ||||
|       return `${loadedResults} of ${totalResults} results` | ||||
|       const loadedResults = this.results.length; | ||||
|       const totalResults = this.totalResults < 10000 ? this.totalResults : "∞"; | ||||
|       return `${loadedResults} of ${totalResults} results`; | ||||
|     }, | ||||
|     pageCount() { | ||||
|       return `Page ${this.page} of ${this.totalPages}` | ||||
|       return `Page ${this.page} of ${this.totalPages}`; | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     loadMore() { | ||||
|       console.log(this.$route) | ||||
|       console.log(this.$route); | ||||
|       this.loading = true; | ||||
|       this.page++ | ||||
|       this.page++; | ||||
|  | ||||
|       window.history.replaceState({}, 'search', `/#/${this.$route.fullPath}?page=${this.page}`) | ||||
|       this.init() | ||||
|       window.history.replaceState( | ||||
|         {}, | ||||
|         "search", | ||||
|         `/#/${this.$route.fullPath}?page=${this.page}` | ||||
|       ); | ||||
|       this.init(); | ||||
|     }, | ||||
|     init() { | ||||
|       const routeListName = this.$route.params.name | ||||
|       const routeListName = this.$route.params.name; | ||||
|  | ||||
|       if (routeListName === 'request') { | ||||
|         getRequests(this.page) | ||||
|           .then(results => { | ||||
|             this.results = this.results.concat(...results.results) | ||||
|             this.page = results.page | ||||
|             this.totalPages = results.total_pages | ||||
|             this.totalResults = results.total_results | ||||
|           }) | ||||
|       if (routeListName === "request") { | ||||
|         getRequests(this.page).then(results => { | ||||
|           this.results = this.results.concat(...results.results); | ||||
|           this.page = results.page; | ||||
|           this.totalPages = results.total_pages; | ||||
|           this.totalResults = results.total_results; | ||||
|         }); | ||||
|       } else if (this.legalTmdbLists.includes(routeListName)) { | ||||
|         getTmdbMovieListByName(routeListName, this.page) | ||||
|           .then(results => { | ||||
|             this.results = this.results.concat(...results.results) | ||||
|             this.page = results.page | ||||
|             this.totalPages = results.total_pages | ||||
|             this.totalResults = results.total_results | ||||
|           }) | ||||
|         getTmdbMovieListByName(routeListName, this.page).then(results => { | ||||
|           this.results = this.results.concat(...results.results); | ||||
|           this.page = results.page; | ||||
|           this.totalPages = results.total_pages; | ||||
|           this.totalResults = results.total_results; | ||||
|         }); | ||||
|       } else { | ||||
|         // TODO handle if list is not found | ||||
|         console.log('404 this is not a tmdb list') | ||||
|         console.log("404 this is not a tmdb list"); | ||||
|       } | ||||
|  | ||||
|       this.loading = false | ||||
|       this.loading = false; | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     if (this.results.length === 0) | ||||
|       this.init() | ||||
|     if (this.results.length === 0) this.init(); | ||||
|  | ||||
|     store.dispatch('documentTitle/updateTitle', `${this.$router.history.current.name} ${this.$route.params.name}`) | ||||
|     store.dispatch( | ||||
|       "documentTitle/updateTitle", | ||||
|       `${this.$router.history.current.name} ${this.$route.params.name}` | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "./src/scss/media-queries"; | ||||
|  | ||||
| @include mobile-only { | ||||
|   .page-container { | ||||
|     margin-top: 1rem; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .fullwidth-button { | ||||
|   width: 100%; | ||||
|   margin: 1rem 0; | ||||
|   | ||||
| @@ -1,7 +1,11 @@ | ||||
| <template> | ||||
|   <div> | ||||
|   <nav class="nav"> | ||||
|       <router-link class="nav__logo" :to="{name: 'home'}" exact title="Vue.js — TMDb App"> | ||||
|     <router-link | ||||
|       class="nav__logo" | ||||
|       :to="{ name: 'home' }" | ||||
|       exact | ||||
|       title="Vue.js — TMDb App" | ||||
|     > | ||||
|       <svg class="nav__logo-image"> | ||||
|         <use xlink:href="#svgLogo"></use> | ||||
|       </svg> | ||||
| @@ -23,8 +27,14 @@ | ||||
|         </router-link> | ||||
|       </li> | ||||
|  | ||||
|       <li class="nav__item mobile-only"></li> | ||||
|  | ||||
|       <li class="nav__item nav__item--profile"> | ||||
|           <router-link class="nav__link nav__link--profile" :to="{name: 'signin'}" v-if="!userLoggedIn"> | ||||
|         <router-link | ||||
|           class="nav__link nav__link--profile" | ||||
|           :to="{ name: 'signin' }" | ||||
|           v-if="!userLoggedIn" | ||||
|         > | ||||
|           <div class="nav__link-wrap"> | ||||
|             <svg class="nav__link-icon"> | ||||
|               <use xlink:href="#iconLogin"></use> | ||||
| @@ -33,7 +43,11 @@ | ||||
|           </div> | ||||
|         </router-link> | ||||
|  | ||||
|           <router-link class="nav__link nav__link--profile" :to="{name: 'profile'}" v-if="userLoggedIn"> | ||||
|         <router-link | ||||
|           class="nav__link nav__link--profile" | ||||
|           :to="{ name: 'profile' }" | ||||
|           v-if="userLoggedIn" | ||||
|         > | ||||
|           <div class="nav__link-wrap"> | ||||
|             <svg class="nav__link-icon"> | ||||
|               <use xlink:href="#iconLogin"></use> | ||||
| @@ -44,35 +58,36 @@ | ||||
|       </li> | ||||
|     </ul> | ||||
|   </nav> | ||||
|  | ||||
|     <div class="spacer"></div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import storage from '@/storage' | ||||
| import storage from "@/storage"; | ||||
|  | ||||
| export default { | ||||
|   data(){ | ||||
|   data() { | ||||
|     return { | ||||
|       listTypes: storage.homepageLists, | ||||
|       userLoggedIn: localStorage.getItem('token') ? true : false | ||||
|     } | ||||
|       userLoggedIn: localStorage.getItem("token") ? true : false | ||||
|     }; | ||||
|   }, | ||||
|   methods: { | ||||
|     setUserStatus(){ | ||||
|       this.userLoggedIn = localStorage.getItem('token') ? true : false; | ||||
|     setUserStatus() { | ||||
|       this.userLoggedIn = localStorage.getItem("token") ? true : false; | ||||
|     }, | ||||
|     toggleNav(){ | ||||
|       document.querySelector('.nav__hamburger').classList.toggle('nav__hamburger--active'); | ||||
|       document.querySelector('.nav__list').classList.toggle('nav__list--active'); | ||||
|     toggleNav() { | ||||
|       document | ||||
|         .querySelector(".nav__hamburger") | ||||
|         .classList.toggle("nav__hamburger--active"); | ||||
|       document | ||||
|         .querySelector(".nav__list") | ||||
|         .classList.toggle("nav__list--active"); | ||||
|     } | ||||
|   }, | ||||
|   created(){ | ||||
|   created() { | ||||
|     // TODO move this to state manager | ||||
|     eventHub.$on('setUserStatus', this.setUserStatus); | ||||
|     eventHub.$on("setUserStatus", this.setUserStatus); | ||||
|   } | ||||
| } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @@ -83,17 +98,10 @@ export default { | ||||
|   width: 30px; | ||||
| } | ||||
|  | ||||
| .spacer { | ||||
|   @include mobile-only { | ||||
|     width: 100%; | ||||
|     height: $header-size; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .nav { | ||||
|   transition: background .5s ease; | ||||
|   transition: background 0.5s ease; | ||||
|   position: fixed; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   width: 100%; | ||||
|   height: 50px; | ||||
| @@ -102,7 +110,9 @@ export default { | ||||
|   color: $text-color; | ||||
|   background-color: $background-color-secondary; | ||||
|  | ||||
|   @include tablet-min{ | ||||
|   @include tablet-min { | ||||
|     top: 0; | ||||
|     bottom: unset; | ||||
|     width: 95px; | ||||
|     height: 100vh; | ||||
|   } | ||||
| @@ -113,15 +123,15 @@ export default { | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     background: $background-nav-logo; | ||||
|     @include tablet-min{ | ||||
|     @include tablet-min { | ||||
|       width: 95px; | ||||
|     } | ||||
|     &-image{ | ||||
|     &-image { | ||||
|       width: 35px; | ||||
|       height: 31px; | ||||
|       fill: $green; | ||||
|       transition: transform 0.5s ease; | ||||
|       @include tablet-min{ | ||||
|       @include tablet-min { | ||||
|         width: 45px; | ||||
|         height: 40px; | ||||
|       } | ||||
| @@ -135,12 +145,12 @@ export default { | ||||
|     position: fixed; | ||||
|     width: 55px; | ||||
|     height: 50px; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     right: 0; | ||||
|     cursor: pointer; | ||||
|     z-index: 10; | ||||
|     border-left: 1px solid $background-color; | ||||
|     @include tablet-min{ | ||||
|     @include tablet-min { | ||||
|       display: none; | ||||
|     } | ||||
|     .bar { | ||||
| @@ -172,9 +182,9 @@ export default { | ||||
|       } | ||||
|     } | ||||
|     &--active { | ||||
|       .bar{ | ||||
|       .bar { | ||||
|         &:nth-child(1), | ||||
|         &:nth-child(3){ | ||||
|         &:nth-child(3) { | ||||
|           width: 0; | ||||
|         } | ||||
|         &:nth-child(2) { | ||||
| @@ -198,15 +208,21 @@ export default { | ||||
|     left: 0; | ||||
|     top: 50px; | ||||
|     border-top: 1px solid $background-color; | ||||
|  | ||||
|     @include mobile-only { | ||||
|       display: flex; | ||||
|       position: absolute; | ||||
|       top: unset; | ||||
|       bottom: var(--header-size); | ||||
|       height: min-content; | ||||
|       flex-wrap: wrap; | ||||
|       font-size: 0; | ||||
|       opacity: 0; | ||||
|       visibility: hidden; | ||||
|       background-color: $background-95; | ||||
|       text-align: left; | ||||
|       &--active{ | ||||
|  | ||||
|       &--active { | ||||
|         opacity: 1; | ||||
|         visibility: visible; | ||||
|       } | ||||
| @@ -221,15 +237,15 @@ export default { | ||||
|     } | ||||
|   } | ||||
|   &__item { | ||||
|     transition: background .5s ease, color .5s ease, border .5s ease; | ||||
|     transition: background 0.5s ease, color 0.5s ease, border 0.5s ease; | ||||
|     background-color: $background-color-secondary; | ||||
|     color: $text-color-70; | ||||
|  | ||||
|     @include mobile-only { | ||||
|       flex: 0 0 50%; | ||||
|       flex: 0 0 33.3%; | ||||
|       text-align: center; | ||||
|       border-bottom: 1px solid $background-color; | ||||
|       &:nth-child(odd){ | ||||
|       &:nth-child(odd) { | ||||
|         border-right: 1px solid $background-color; | ||||
|  | ||||
|         &:last-child { | ||||
| @@ -251,7 +267,8 @@ export default { | ||||
|         border-left: 1px solid $background-color; | ||||
|       } | ||||
|     } | ||||
|     &:hover, .is-active { | ||||
|     &:hover, | ||||
|     .is-active { | ||||
|       color: $text-color; | ||||
|       background-color: $background-color; | ||||
|     } | ||||
| @@ -299,14 +316,14 @@ export default { | ||||
|         height: 20px; | ||||
|         margin-bottom: 5px; | ||||
|       } | ||||
|  | ||||
|     } | ||||
|     &-title { | ||||
|       margin-top: 5px; | ||||
|       display: block; | ||||
|       width: 100%; | ||||
|     } | ||||
|     &:hover &-icon, &.is-active &-icon { | ||||
|     &:hover &-icon, | ||||
|     &.is-active &-icon { | ||||
|       fill: $text-color; | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div> | ||||
|   <div class="page-container"> | ||||
|     <list-header :title="title" :info="resultCount" :sticky="true" /> | ||||
|  | ||||
|     <results-list :results="results" /> | ||||
| @@ -9,7 +9,9 @@ | ||||
|     </div> | ||||
|  | ||||
|     <div class="notFound" v-if="results.length == 0 && loading == false"> | ||||
|       <h1 class="notFound-title">No results for search: <b>{{ query }}</b></h1> | ||||
|       <h1 class="notFound-title"> | ||||
|         No results for search: <b>{{ query }}</b> | ||||
|       </h1> | ||||
|     </div> | ||||
|  | ||||
|     <loader v-if="loading" /> | ||||
| @@ -29,11 +31,11 @@ | ||||
| </style> | ||||
|  | ||||
| <script> | ||||
| import { searchTmdb } from '@/api' | ||||
| import ListHeader from '@/components/ListHeader' | ||||
| import ResultsList from '@/components/ResultsList' | ||||
| import SeasonedButton from '@/components/ui/SeasonedButton' | ||||
| import Loader from '@/components/ui/Loader' | ||||
| import { searchTmdb } from "@/api"; | ||||
| import ListHeader from "@/components/ListHeader"; | ||||
| import ResultsList from "@/components/ResultsList"; | ||||
| import SeasonedButton from "@/components/ui/SeasonedButton"; | ||||
| import Loader from "@/components/ui/Loader"; | ||||
|  | ||||
| export default { | ||||
|   components: { ListHeader, ResultsList, SeasonedButton, Loader }, | ||||
| @@ -58,59 +60,74 @@ export default { | ||||
|       totalPages: 0, | ||||
|       results: [], | ||||
|       totalResults: [] | ||||
|     } | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     resultCount() { | ||||
|       const loadedResults = this.results.length | ||||
|       const totalResults = this.totalResults < 10000 ? this.totalResults : '∞' | ||||
|       return `${loadedResults} of ${totalResults} results` | ||||
|       const loadedResults = this.results.length; | ||||
|       const totalResults = this.totalResults < 10000 ? this.totalResults : "∞"; | ||||
|       return `${loadedResults} of ${totalResults} results`; | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     search(query=this.query, page=this.page, adult=this.adult, mediaType=this.mediaType) { | ||||
|       searchTmdb(query, page, adult, mediaType) | ||||
|         .then(this.parseResponse) | ||||
|     search( | ||||
|       query = this.query, | ||||
|       page = this.page, | ||||
|       adult = this.adult, | ||||
|       mediaType = this.mediaType | ||||
|     ) { | ||||
|       searchTmdb(query, page, adult, mediaType).then(this.parseResponse); | ||||
|     }, | ||||
|     parseResponse(data) { | ||||
|       if (this.results.length > 0) { | ||||
|         this.results.push(...data.results) | ||||
|         this.results.push(...data.results); | ||||
|       } else { | ||||
|         this.results = data.results | ||||
|         this.results = data.results; | ||||
|       } | ||||
|  | ||||
|       this.totalPages = data.total_pages | ||||
|       this.totalResults = data.total_results || data.results.length | ||||
|       this.totalPages = data.total_pages; | ||||
|       this.totalResults = data.total_results || data.results.length; | ||||
|  | ||||
|       this.loading = false | ||||
|       this.loading = false; | ||||
|     }, | ||||
|     loadMore() { | ||||
|       this.page++ | ||||
|       this.page++; | ||||
|  | ||||
|       window.history.replaceState({}, 'search', `/#/search?query=${this.query}&page=${this.page}`) | ||||
|       this.search() | ||||
|       window.history.replaceState( | ||||
|         {}, | ||||
|         "search", | ||||
|         `/#/search?query=${this.query}&page=${this.page}` | ||||
|       ); | ||||
|       this.search(); | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     const { query, page, adult, media_type } = this.$route.query | ||||
|     const { query, page, adult, media_type } = this.$route.query; | ||||
|  | ||||
|     if (!query) { | ||||
|       // abort | ||||
|       console.error('abort, no query') | ||||
|       console.error("abort, no query"); | ||||
|     } | ||||
|     this.query = decodeURIComponent(query) | ||||
|     this.page = page || 1 | ||||
|     this.adult = adult || this.adult | ||||
|     this.mediaType = media_type || this.mediaType | ||||
|     this.title = `Search results: ${this.query}` | ||||
|     this.query = decodeURIComponent(query); | ||||
|     this.page = page || 1; | ||||
|     this.adult = adult || this.adult; | ||||
|     this.mediaType = media_type || this.mediaType; | ||||
|     this.title = `Search results: ${this.query}`; | ||||
|  | ||||
|     this.search() | ||||
|     this.search(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "./src/scss/media-queries"; | ||||
|  | ||||
| @include mobile-only { | ||||
|   .page-container { | ||||
|     margin-top: 1rem; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .fullwidth-button { | ||||
|   width: 100%; | ||||
|   margin: 1rem 0; | ||||
| @@ -118,5 +135,4 @@ export default { | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
| } | ||||
|  | ||||
| </style> | ||||
| @@ -15,9 +15,12 @@ | ||||
|         @keydown.escape="handleEscape" | ||||
|         @keyup.enter="handleSubmit" | ||||
|         @keydown.up="navigateUp" | ||||
|         @keydown.down="navigateDown" /> | ||||
|         @keydown.down="navigateDown" | ||||
|       /> | ||||
|  | ||||
|       <svg class="search-icon" fill="currentColor" @click="handleSubmit"><use xlink:href="#iconSearch"></use></svg> | ||||
|       <svg class="search-icon" fill="currentColor" @click="handleSubmit"> | ||||
|         <use xlink:href="#iconSearch"></use> | ||||
|       </svg> | ||||
|     </div> | ||||
|  | ||||
|     <transition name="fade"> | ||||
| @@ -26,10 +29,14 @@ | ||||
|           <h2>Filter your search:</h2> | ||||
|  | ||||
|           <div class="filter-items"> | ||||
|             <toggle-button :options="searchTypes" :selected.sync="selectedSearchType" /> | ||||
|             <toggle-button | ||||
|               :options="searchTypes" | ||||
|               :selected.sync="selectedSearchType" | ||||
|             /> | ||||
|  | ||||
|             <label>Adult | ||||
|               <input type="checkbox" value="adult" v-model="adult"> | ||||
|             <label | ||||
|               >Adult | ||||
|               <input type="checkbox" value="adult" v-model="adult" /> | ||||
|             </label> | ||||
|           </div> | ||||
|         </div> | ||||
| @@ -37,49 +44,57 @@ | ||||
|         <hr /> | ||||
|  | ||||
|         <div class="dropdown-results" v-if="elasticSearchResults.length"> | ||||
|           <ul v-for="(item, index) in elasticSearchResults" | ||||
|           <ul | ||||
|             v-for="(item, index) in elasticSearchResults" | ||||
|             @click="openResult(item, index + 1)" | ||||
|               :class="{ active: index + 1 === selectedResult}"> | ||||
|                  | ||||
|               {{ item.name }} | ||||
|             :class="{ active: index + 1 === selectedResult }" | ||||
|           > | ||||
|             {{ | ||||
|               item.name | ||||
|             }} | ||||
|           </ul> | ||||
|         </div> | ||||
|  | ||||
|         <div v-else class="dropdown"> | ||||
|           <div class="dropdown-results"> | ||||
|             <h2 class="not-found">No results for query: <b>{{ query }}</b></h2> | ||||
|             <h2 class="not-found"> | ||||
|               No results for query: <b>{{ query }}</b> | ||||
|             </h2> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <seasoned-button class="end-section" fullWidth="true"  | ||||
|           @click="focus = false" :active="elasticSearchResults.length + 1 === selectedResult"> | ||||
|         <seasoned-button | ||||
|           class="end-section" | ||||
|           fullWidth="true" | ||||
|           @click="focus = false" | ||||
|           :active="elasticSearchResults.length + 1 === selectedResult" | ||||
|         > | ||||
|           close | ||||
|         </seasoned-button> | ||||
|       </div> | ||||
|  | ||||
|     </transition> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import SeasonedButton from '@/components/ui/SeasonedButton' | ||||
| import ToggleButton from '@/components/ui/ToggleButton'; | ||||
| import SeasonedButton from "@/components/ui/SeasonedButton"; | ||||
| import ToggleButton from "@/components/ui/ToggleButton"; | ||||
|  | ||||
| import { elasticSearchMoviesAndShows } from '@/api' | ||||
| import config from '@/config.json' | ||||
| import { elasticSearchMoviesAndShows } from "@/api"; | ||||
| import config from "@/config.json"; | ||||
|  | ||||
| export default { | ||||
|   name: 'SearchInput', | ||||
|   name: "SearchInput", | ||||
|   components: { | ||||
|     SeasonedButton, | ||||
|     ToggleButton | ||||
|   }, | ||||
|   props: ['value'], | ||||
|   props: ["value"], | ||||
|   data() { | ||||
|     return { | ||||
|       adult: true, | ||||
|       searchTypes: ['all', 'movie', 'show', 'person'], | ||||
|       selectedSearchType: 'all', | ||||
|       searchTypes: ["all", "movie", "show", "person"], | ||||
|       selectedSearchType: "all", | ||||
|  | ||||
|       query: this.value, | ||||
|       focus: false, | ||||
| @@ -87,144 +102,150 @@ export default { | ||||
|       scrollListener: undefined, | ||||
|       scrollDistance: 0, | ||||
|       elasticSearchResults: [], | ||||
|       selectedResult: 0, | ||||
|     } | ||||
|       selectedResult: 0 | ||||
|     }; | ||||
|   }, | ||||
|   watch: { | ||||
|     focus: function(val) { | ||||
|     focus: function (val) { | ||||
|       if (val === true) { | ||||
|         window.addEventListener('scroll', this.disableFocus) | ||||
|         window.addEventListener("scroll", this.disableFocus); | ||||
|       } else { | ||||
|         window.removeEventListener('scroll', this.disableFocus) | ||||
|         this.scrollDistance = 0 | ||||
|         window.removeEventListener("scroll", this.disableFocus); | ||||
|         this.scrollDistance = 0; | ||||
|       } | ||||
|     }, | ||||
|     adult: function(value) { | ||||
|       this.handleInput() | ||||
|     adult: function (value) { | ||||
|       this.handleInput(); | ||||
|     } | ||||
|   }, | ||||
|   beforeMount() { | ||||
|     const elasticUrl = config.ELASTIC_URL | ||||
|     if (elasticUrl === undefined || elasticUrl === false || elasticUrl === '') { | ||||
|       this.disabled = true | ||||
|     const elasticUrl = config.ELASTIC_URL; | ||||
|     if (elasticUrl === undefined || elasticUrl === false || elasticUrl === "") { | ||||
|       this.disabled = true; | ||||
|     } | ||||
|   }, | ||||
|   beforeDestroy() { | ||||
|     console.log('scroll eventlistener not removed, destroying!') | ||||
|     window.removeEventListener('scroll', this.disableFocus) | ||||
|     console.log("scroll eventlistener not removed, destroying!"); | ||||
|     window.removeEventListener("scroll", this.disableFocus); | ||||
|   }, | ||||
|   methods: { | ||||
|     navigateDown() { | ||||
|       this.focus = true | ||||
|       this.selectedResult++ | ||||
|       this.focus = true; | ||||
|       this.selectedResult++; | ||||
|     }, | ||||
|     navigateUp() { | ||||
|       this.focus = true | ||||
|       this.selectedResult-- | ||||
|       this.focus = true; | ||||
|       this.selectedResult--; | ||||
|       const input = this.$refs.input; | ||||
|       const textLength = input.value.length | ||||
|       const textLength = input.value.length; | ||||
|  | ||||
|       setTimeout(() => { | ||||
|         input.focus() | ||||
|         input.setSelectionRange(textLength, textLength + 1) | ||||
|       }, 1) | ||||
|         input.focus(); | ||||
|         input.setSelectionRange(textLength, textLength + 1); | ||||
|       }, 1); | ||||
|     }, | ||||
|     openResult(item, index) { | ||||
|       this.selectedResult = index; | ||||
|       this.$popup.open(item.id, item.type) | ||||
|       this.$popup.open(item.id, item.type); | ||||
|     }, | ||||
|     handleInput(e){ | ||||
|       this.selectedResult = 0 | ||||
|       this.$emit('input', this.query); | ||||
|     handleInput(e) { | ||||
|       this.selectedResult = 0; | ||||
|       this.$emit("input", this.query); | ||||
|  | ||||
|       if (! this.focus) { | ||||
|       if (!this.focus) { | ||||
|         this.focus = true; | ||||
|       } | ||||
|  | ||||
|       elasticSearchMoviesAndShows(this.query) | ||||
|       .then(resp => { | ||||
|         const data = resp.hits.hits | ||||
|       elasticSearchMoviesAndShows(this.query).then(resp => { | ||||
|         const data = resp.hits.hits; | ||||
|  | ||||
|         let results = data.map(item => { | ||||
|           const index = item._index.slice(0, -1) | ||||
|           if (index === 'movie' || item._source.original_title) { | ||||
|           const index = item._index.slice(0, -1); | ||||
|           if (index === "movie" || item._source.original_title) { | ||||
|             return { | ||||
|               name: item._source.original_title, | ||||
|               id: item._source.id, | ||||
|               adult: item._source.adult, | ||||
|               type: 'movie' | ||||
|             } | ||||
|           } else if (index === 'show' || item._source.original_name) { | ||||
|               type: "movie" | ||||
|             }; | ||||
|           } else if (index === "show" || item._source.original_name) { | ||||
|             return { | ||||
|               name: item._source.original_name, | ||||
|               id: item._source.id, | ||||
|               adult: item._source.adult, | ||||
|               type: 'show' | ||||
|               type: "show" | ||||
|             }; | ||||
|           } | ||||
|           } | ||||
|         }) | ||||
|         results = this.removeDuplicates(results) | ||||
|         this.elasticSearchResults = results | ||||
|       }) | ||||
|         }); | ||||
|         results = this.removeDuplicates(results); | ||||
|         this.elasticSearchResults = results; | ||||
|       }); | ||||
|     }, | ||||
|     removeDuplicates(searchResults) { | ||||
|       let filteredResults = [] | ||||
|       let filteredResults = []; | ||||
|       searchResults.map(result => { | ||||
|         const numberOfDuplicates = filteredResults.filter(filterItem => filterItem.id == result.id) | ||||
|         const numberOfDuplicates = filteredResults.filter( | ||||
|           filterItem => filterItem.id == result.id | ||||
|         ); | ||||
|         if (numberOfDuplicates.length >= 1) { | ||||
|           return null | ||||
|           return null; | ||||
|         } | ||||
|         filteredResults.push(result) | ||||
|       }) | ||||
|         filteredResults.push(result); | ||||
|       }); | ||||
|  | ||||
|       if (this.adult == false) { | ||||
|         filteredResults = filteredResults.filter(result => result.adult == false) | ||||
|         filteredResults = filteredResults.filter( | ||||
|           result => result.adult == false | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       return filteredResults | ||||
|       return filteredResults; | ||||
|     }, | ||||
|     handleSubmit() { | ||||
|       let searchResults = this.elasticSearchResults | ||||
|       let searchResults = this.elasticSearchResults; | ||||
|  | ||||
|       if (this.selectedResult > searchResults.length) { | ||||
|         this.focus = false | ||||
|         this.selectedResult = 0 | ||||
|         this.focus = false; | ||||
|         this.selectedResult = 0; | ||||
|       } else if (this.selectedResult > 0) { | ||||
|         const resultItem = searchResults[this.selectedResult - 1] | ||||
|         this.$popup.open(resultItem.id, resultItem.type) | ||||
|         const resultItem = searchResults[this.selectedResult - 1]; | ||||
|         this.$popup.open(resultItem.id, resultItem.type); | ||||
|       } else { | ||||
|         const encodedQuery = encodeURI(this.query.replace('/ /g, "+"')) | ||||
|         const media_type = this.selectedSearchType !== 'all' ? this.selectedSearchType : null | ||||
|         this.$router.push({ name: 'search', query: { query: encodedQuery, adult: this.adult, media_type }}); | ||||
|         this.focus = false | ||||
|         this.selectedResult = 0 | ||||
|         const encodedQuery = encodeURI(this.query.replace('/ /g, "+"')); | ||||
|         const media_type = | ||||
|           this.selectedSearchType !== "all" ? this.selectedSearchType : null; | ||||
|         this.$router.push({ | ||||
|           name: "search", | ||||
|           query: { query: encodedQuery, adult: this.adult, media_type } | ||||
|         }); | ||||
|         this.focus = false; | ||||
|         this.selectedResult = 0; | ||||
|       } | ||||
|     }, | ||||
|     handleEscape() { | ||||
|       if (this.$popup.isOpen) { | ||||
|         console.log('THIS WAS FUCKOING OPEN!') | ||||
|         console.log("THIS WAS FUCKOING OPEN!"); | ||||
|       } else { | ||||
|         this.focus = false | ||||
|         this.focus = false; | ||||
|       } | ||||
|     }, | ||||
|     disableFocus(_) { | ||||
|       this.focus = false | ||||
|       this.focus = false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "./src/scss/variables"; | ||||
| @import "./src/scss/media-queries"; | ||||
| @import './src/scss/main'; | ||||
|  | ||||
| @import "./src/scss/main"; | ||||
|  | ||||
| .fade-enter-active { | ||||
|   transition: opacity .2s; | ||||
|   transition: opacity 0.2s; | ||||
| } | ||||
| .fade-leave-active { | ||||
|   transition: opacity .2s; | ||||
|   transition: opacity 0.2s; | ||||
| } | ||||
| .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { | ||||
|   opacity: 0; | ||||
| @@ -311,7 +332,9 @@ hr { | ||||
|       overflow: hidden; | ||||
|       color: $text-color-50; | ||||
|  | ||||
|       &.active, &:hover, &:active { | ||||
|       &.active, | ||||
|       &:hover, | ||||
|       &:active { | ||||
|         color: $text-color; | ||||
|         border-bottom: 2px solid $text-color; | ||||
|       } | ||||
| @@ -330,10 +353,10 @@ hr { | ||||
|  | ||||
|   // TODO check if this is for mobile | ||||
|   width: calc(100% - 110px); | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
|   right: 55px; | ||||
|  | ||||
|   @include tablet-min{ | ||||
|   @include tablet-min { | ||||
|     position: relative; | ||||
|     width: 100%; | ||||
|     right: 0px; | ||||
| @@ -350,14 +373,14 @@ hr { | ||||
|     font-weight: 300; | ||||
|     font-size: 19px; | ||||
|     color: $text-color; | ||||
|     transition: background-color .5s ease, color .5s ease; | ||||
|     transition: background-color 0.5s ease, color 0.5s ease; | ||||
|  | ||||
|     @include tablet-min { | ||||
|       padding: 13px 30px 13px 60px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   &-icon{ | ||||
|   &-icon { | ||||
|     width: 20px; | ||||
|     height: 20px; | ||||
|     fill: $text-color-50; | ||||
| @@ -367,7 +390,7 @@ hr { | ||||
|     left: 15px; | ||||
|     top: 15px; | ||||
|  | ||||
|     @include tablet-min{ | ||||
|     @include tablet-min { | ||||
|       top: 27px; | ||||
|       left: 25px; | ||||
|     } | ||||
|   | ||||
| @@ -1,42 +1,38 @@ | ||||
| <template> | ||||
|  | ||||
|   <div class="darkToggle"> | ||||
|     <span @click="toggleDarkmode()">{{ darkmodeToggleIcon }}</span> | ||||
|   </div> | ||||
|  | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       darkmode: this.supported | ||||
|     } | ||||
|     }; | ||||
|   }, | ||||
|   methods: { | ||||
|     toggleDarkmode() { | ||||
|       this.darkmode = !this.darkmode; | ||||
|       document.body.className = this.darkmode ? 'dark' : 'light' | ||||
|       document.body.className = this.darkmode ? "dark" : "light"; | ||||
|     }, | ||||
|     supported() { | ||||
|       const computedStyle = window.getComputedStyle(document.body) | ||||
|       if (computedStyle['colorScheme'] != null) | ||||
|         return computedStyle.colorScheme.includes('dark') | ||||
|       return false | ||||
|       const computedStyle = window.getComputedStyle(document.body); | ||||
|       if (computedStyle["colorScheme"] != null) | ||||
|         return computedStyle.colorScheme.includes("dark"); | ||||
|       return false; | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     darkmodeToggleIcon() { | ||||
|       return this.darkmode ? '🌝' : '🌚' | ||||
|       return this.darkmode ? "🌝" : "🌚"; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }; | ||||
| </script> | ||||
|  | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| @import "./src/scss/media-queries"; | ||||
| .darkToggle { | ||||
|   height: 25px; | ||||
|   width: 25px; | ||||
| @@ -49,6 +45,10 @@ export default { | ||||
|   right: 0; | ||||
|   z-index: 10; | ||||
|  | ||||
|   @include mobile-only { | ||||
|     margin-bottom: 3.5rem; | ||||
|   } | ||||
|  | ||||
|   -webkit-user-select: none; | ||||
|   -moz-user-select: none; | ||||
|   -ms-user-select: none; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user