WIP torrent search list
This commit is contained in:
		| @@ -1,90 +1,123 @@ | |||||||
| <template> | <template> | ||||||
|   <div v-if="show" class="container"> |   <div v-if="show" class="container"> | ||||||
|     <h2 class="torrentHeader-text">Searching for: {{ editedSearchQuery || query }}</h2> |     <h2 class="torrentHeader-text editable"> | ||||||
| <!--     <div class="torrentHeader"> |       Searching for: | ||||||
|       <span class="torrentHeader-text">Searching for: </span> |       <span :contenteditable="!edit" @input="this.handleInput">{{ | ||||||
|  |         query | ||||||
|  |       }}</span> | ||||||
|  |  | ||||||
|  |       <IconSearch | ||||||
|  |         class="icon" | ||||||
|  |         v-if="editedSearchQuery && editedSearchQuery.length" | ||||||
|  |       /> | ||||||
|  |       <IconEdit v-else class="icon" @click="() => (this.edit = !this.edit)" /> | ||||||
|  |     </h2> | ||||||
|  |  | ||||||
|       <span id="search" :contenteditable="editSearchQuery ? true : false" class="torrentHeader-text editable">{{ editedSearchQuery || query }}</span> |     <div v-if="!loading"> | ||||||
|  |  | ||||||
|  |  | ||||||
|       <svg v-if="!editSearchQuery" class="torrentHeader-editIcon" @click="toggleEditSearchQuery"> |  | ||||||
|         <use xlink:href="#icon_radar"></use> |  | ||||||
|       </svg> |  | ||||||
|  |  | ||||||
|       <svg v-else class="torrentHeader-editIcon" @click="toggleEditSearchQuery"> |  | ||||||
|         <use xlink:href="#icon_check"></use> |  | ||||||
|       </svg> |  | ||||||
|  |  | ||||||
|     </div> --> |  | ||||||
|  |  | ||||||
|     <div v-if="listLoaded"> |  | ||||||
|       <div v-if="torrents.length > 0"> |       <div v-if="torrents.length > 0"> | ||||||
|         <!-- <ul class="filter"> |  | ||||||
|           <li class="filter-item" v-for="(item, index) in release_types" @click="applyFilter(item, index)" :class="{'active': item === selectedRelaseType}">{{ item }}</li> |  | ||||||
|         </ul> --> |  | ||||||
|  |  | ||||||
|         <toggle-button :options="release_types" :selected.sync="selectedRelaseType" class="toggle"></toggle-button> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         <table> |         <table> | ||||||
|           <tr class="table__header noselect"> |           <thead class="table__header noselect"> | ||||||
|             <th @click="sortTable('name')" :class="selectedSortableClass('name')"> |             <tr> | ||||||
|  |               <th | ||||||
|  |                 v-for="column in columns" | ||||||
|  |                 :key="column" | ||||||
|  |                 @click="sortTable(column)" | ||||||
|  |                 :class="column === this.selectedColumn ? 'active' : null" | ||||||
|  |               > | ||||||
|  |                 {{ column }} | ||||||
|  |                 <span v-if="prevCol === column && direction">↑</span> | ||||||
|  |                 <span v-if="prevCol === column && !direction">↓</span> | ||||||
|  |               </th> | ||||||
|  |             </tr> | ||||||
|  |             <!--             <th | ||||||
|  |               @click="sortTable('name')" | ||||||
|  |               :class="selectedSortableClass('name')" | ||||||
|  |             > | ||||||
|               <span>Name</span> |               <span>Name</span> | ||||||
|               <span v-if="prevCol === 'name' && direction">↑</span> |               <span v-if="prevCol === 'name' && direction">↑</span> | ||||||
|               <span v-if="prevCol === 'name' && !direction">↓</span> |               <span v-if="prevCol === 'name' && !direction">↓</span> | ||||||
|             </th> |             </th> | ||||||
|             <th @click="sortTable('seed')" :class="selectedSortableClass('seed')"> |             <th | ||||||
|  |               @click="sortTable('seed')" | ||||||
|  |               :class="selectedSortableClass('seed')" | ||||||
|  |             > | ||||||
|               <span>Seed</span> |               <span>Seed</span> | ||||||
|               <span v-if="prevCol === 'seed' && direction">↑</span> |               <span v-if="prevCol === 'seed' && direction">↑</span> | ||||||
|               <span v-if="prevCol === 'seed' && !direction">↓</span> |               <span v-if="prevCol === 'seed' && !direction">↓</span> | ||||||
|             </th> |             </th> | ||||||
|             <th @click="sortTable('size')" :class="selectedSortableClass('size')"> |             <th | ||||||
|  |               @click="sortTable('size')" | ||||||
|  |               :class="selectedSortableClass('size')" | ||||||
|  |             > | ||||||
|               <span>Size</span> |               <span>Size</span> | ||||||
|               <span v-if="prevCol === 'size' && direction">↑</span> |               <span v-if="prevCol === 'size' && direction">↑</span> | ||||||
|               <span v-if="prevCol === 'size' && !direction">↓</span> |               <span v-if="prevCol === 'size' && !direction">↓</span> | ||||||
|  |             </th> | ||||||
|  |  | ||||||
|             <th> |             <th> | ||||||
|               <span>Magnet</span> |               <span>Magnet</span> | ||||||
|             </th> |             </th> --> | ||||||
|           </tr> |           </thead> | ||||||
|           <tr v-for="torrent in torrents" class="table__content"> |  | ||||||
|  |           <tbody> | ||||||
|  |             <tr | ||||||
|  |               v-for="torrent in torrents" | ||||||
|  |               class="table__content" | ||||||
|  |               :key="torrent.magnet" | ||||||
|  |             > | ||||||
|               <td @click="expand($event, torrent.name)">{{ torrent.name }}</td> |               <td @click="expand($event, torrent.name)">{{ torrent.name }}</td> | ||||||
|               <td @click="expand($event, torrent.name)">{{ torrent.seed }}</td> |               <td @click="expand($event, torrent.name)">{{ torrent.seed }}</td> | ||||||
|               <td @click="expand($event, torrent.name)">{{ torrent.size }}</td> |               <td @click="expand($event, torrent.name)">{{ torrent.size }}</td> | ||||||
|             <td @click="sendTorrent(torrent.magnet, torrent.name, $event)" class="download"> |               <td | ||||||
|               <svg class="download__icon"><use xlink:href="#iconUnmatched"></use></svg> |                 @click="sendTorrent(torrent.magnet, torrent.name, $event)" | ||||||
|  |                 class="download" | ||||||
|  |               > | ||||||
|  |                 <IconMagnet /> | ||||||
|               </td> |               </td> | ||||||
|             </tr> |             </tr> | ||||||
|  |           </tbody> | ||||||
|         </table> |         </table> | ||||||
|  |  | ||||||
|         <div style=" |         <div style="display: flex; justify-content: center; padding: 1rem"> | ||||||
|           display: flex; |           <seasonedButton @click="resetTorrentsAndToggleEditSearchQuery" | ||||||
|           justify-content: center; |             >Edit search query</seasonedButton | ||||||
|           padding: 1rem; |           > | ||||||
|         "> |  | ||||||
|           <seasonedButton @click="resetTorrentsAndToggleEditSearchQuery">Edit search query</seasonedButton> |  | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|     <div v-else style="display: flex; |       <div | ||||||
|  |         v-else | ||||||
|  |         style=" | ||||||
|  |           display: flex; | ||||||
|           padding-bottom: 2rem; |           padding-bottom: 2rem; | ||||||
|           justify-content: center; |           justify-content: center; | ||||||
|           flex-direction: column; |           flex-direction: column; | ||||||
|           width: 100%; |           width: 100%; | ||||||
|                        align-items: center;"> |           align-items: center; | ||||||
|  |         " | ||||||
|  |       > | ||||||
|         <h2>No results found</h2> |         <h2>No results found</h2> | ||||||
|         <br /> |         <br /> | ||||||
|  |  | ||||||
|         <div class="editQuery" v-if="editSearchQuery"> |         <div class="editQuery" v-if="editSearchQuery"> | ||||||
|  |           <seasonedInput | ||||||
|  |             placeholder="Torrent query" | ||||||
|  |             :value.sync="editedSearchQuery" | ||||||
|  |             @enter="fetchTorrents(editedSearchQuery)" | ||||||
|  |           /> | ||||||
|  |  | ||||||
|         <seasonedInput placeholder="Torrent query" icon="_torrents" :value.sync="editedSearchQuery" @enter="fetchTorrents(editedSearchQuery)" /> |           <div style="height: 45px; width: 5px"></div> | ||||||
|  |  | ||||||
|         <div style="height: 45px; width: 5px;"></div> |           <seasonedButton @click="fetchTorrents(editedSearchQuery)" | ||||||
|  |             >Search</seasonedButton | ||||||
|         <seasonedButton @click="fetchTorrents(editedSearchQuery)">Search</seasonedButton> |           > | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|       <seasonedButton @click="toggleEditSearchQuery" :active="editSearchQuery ? true : false">Edit search query</seasonedButton> |         <seasonedButton | ||||||
|  |           @click="toggleEditSearchQuery" | ||||||
|  |           :active="editSearchQuery ? true : false" | ||||||
|  |           >Edit search query</seasonedButton | ||||||
|  |         > | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|     <div v-else class="torrentloader"><i></i></div> |     <div v-else class="torrentloader"><i></i></div> | ||||||
| @@ -92,17 +125,28 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import storage from '@/storage' | import storage from "@/storage"; | ||||||
| import store from '@/store' | import store from "@/store"; | ||||||
| import { sortableSize } from '@/utils' | import { sortableSize } from "@/utils"; | ||||||
| import { searchTorrents, addMagnet } from '@/api' | import { searchTorrents, addMagnet } from "@/api"; | ||||||
|  |  | ||||||
| import SeasonedButton from '@/components/ui/SeasonedButton' | import IconMagnet from "../icons/IconMagnet"; | ||||||
| import SeasonedInput from '@/components/ui/SeasonedInput' | import IconEdit from "../icons/IconEdit"; | ||||||
| import ToggleButton from '@/components/ui/ToggleButton' | import IconSearch from "../icons/IconSearch"; | ||||||
|  |  | ||||||
|  | import SeasonedButton from "@/components/ui/SeasonedButton"; | ||||||
|  | import SeasonedInput from "@/components/ui/SeasonedInput"; | ||||||
|  | import ToggleButton from "@/components/ui/ToggleButton"; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { SeasonedButton, SeasonedInput, ToggleButton }, |   components: { | ||||||
|  |     IconMagnet, | ||||||
|  |     IconEdit, | ||||||
|  |     IconSearch, | ||||||
|  |     SeasonedButton, | ||||||
|  |     SeasonedInput, | ||||||
|  |     ToggleButton | ||||||
|  |   }, | ||||||
|   props: { |   props: { | ||||||
|     query: { |     query: { | ||||||
|       type: String, |       type: String, | ||||||
| @@ -118,171 +162,204 @@ export default { | |||||||
|   }, |   }, | ||||||
|   data() { |   data() { | ||||||
|     return { |     return { | ||||||
|       listLoaded: false, |       edit: true, | ||||||
|  |       loading: false, | ||||||
|       torrents: [], |       torrents: [], | ||||||
|       torrentResponse: undefined, |       torrentResponse: undefined, | ||||||
|       currentPage: 0, |       currentPage: 0, | ||||||
|       prevCol: '', |       prevCol: "", | ||||||
|       direction: false, |       direction: false, | ||||||
|       release_types: ['all'], |       release_types: ["all"], | ||||||
|       selectedRelaseType: 'all', |       selectedRelaseType: "all", | ||||||
|       editSearchQuery: false, |       editSearchQuery: false, | ||||||
|       editedSearchQuery: '' |       editedSearchQuery: "", | ||||||
|     } |  | ||||||
|  |       columns: ["name", "seed", "size", "magnet"], | ||||||
|  |       selectedColumn: null | ||||||
|  |     }; | ||||||
|   }, |   }, | ||||||
|   beforeMount() { |   created() { | ||||||
|     if (localStorage.getItem('admin')) { |     this.fetchTorrents().then(_ => this.sortTable("size")); | ||||||
|       this.fetchTorrents() |  | ||||||
|     } |  | ||||||
|     store.dispatch('torrentModule/reset') |  | ||||||
|   }, |   }, | ||||||
|   watch: { |   watch: { | ||||||
|     selectedRelaseType: function(newValue) { |     selectedRelaseType: function (newValue) { | ||||||
|       this.applyFilter(newValue) |       this.applyFilter(newValue); | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     selectedSortableClass(headerName) { |     selectedSortableClass(headerName) { | ||||||
|       return headerName === this.prevCol ? 'active' : '' |       return headerName === this.prevCol ? "active" : ""; | ||||||
|     }, |     }, | ||||||
|     resetTorrentsAndToggleEditSearchQuery() { |     resetTorrentsAndToggleEditSearchQuery() { | ||||||
|       this.torrents = [] |       this.torrents = []; | ||||||
|       this.toggleEditSearchQuery() |       this.toggleEditSearchQuery(); | ||||||
|     }, |     }, | ||||||
|     toggleEditSearchQuery() { |     toggleEditSearchQuery() { | ||||||
|       this.editSearchQuery = !this.editSearchQuery; |       this.editSearchQuery = !this.editSearchQuery; | ||||||
|     }, |     }, | ||||||
|     expand(event, name) { |     expand(event, name) { | ||||||
|       const existingExpandedElement = document.getElementsByClassName('expanded')[0] |       const existingExpandedElement = | ||||||
|  |         document.getElementsByClassName("expanded")[0]; | ||||||
|  |  | ||||||
|       const clickedElement = event.target.parentNode; |       const clickedElement = event.target.parentNode; | ||||||
|       const scopedStyleDataVariable = Object.keys(clickedElement.dataset)[0] |       const scopedStyleDataVariable = Object.keys(clickedElement.dataset)[0]; | ||||||
|  |  | ||||||
|       if (existingExpandedElement) { |       if (existingExpandedElement) { | ||||||
|         const expandedSibling = event.target.parentNode.nextSibling.className === 'expanded' |         const expandedSibling = | ||||||
|  |           event.target.parentNode.nextSibling.className === "expanded"; | ||||||
|  |  | ||||||
|         existingExpandedElement.remove() |         existingExpandedElement.remove(); | ||||||
|         const table = document.getElementsByTagName('table')[0] |         const table = document.getElementsByTagName("table")[0]; | ||||||
|         table.style.display = 'block' |         table.style.display = "block"; | ||||||
|  |  | ||||||
|         if (expandedSibling) { |         if (expandedSibling) { | ||||||
|           return |           return; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       const nameRow = document.createElement('tr') |       const nameRow = document.createElement("tr"); | ||||||
|       const nameCol = document.createElement('td') |       const nameCol = document.createElement("td"); | ||||||
|       nameRow.className = 'expanded' |       nameRow.className = "expanded"; | ||||||
|       nameRow.dataset[scopedStyleDataVariable] = ""; |       nameRow.dataset[scopedStyleDataVariable] = ""; | ||||||
|       nameCol.innerText = name |       nameCol.innerText = name; | ||||||
|       nameCol.dataset[scopedStyleDataVariable] = ""; |       nameCol.dataset[scopedStyleDataVariable] = ""; | ||||||
|  |  | ||||||
|       nameRow.appendChild(nameCol) |       nameRow.appendChild(nameCol); | ||||||
|  |  | ||||||
|       clickedElement.insertAdjacentElement('afterend', nameRow) |       clickedElement.insertAdjacentElement("afterend", nameRow); | ||||||
|     }, |     }, | ||||||
|     sendTorrent(magnet, name, event){ |     sendTorrent(magnet, name, event) { | ||||||
|       this.$notifications.info({ |       this.$notifications.info({ | ||||||
|         title: 'Adding torrent 🦜', |         title: "Adding torrent 🦜", | ||||||
|         description: this.query, |         description: this.query, | ||||||
|         timeout: 3000 |         timeout: 3000 | ||||||
|       }) |       }); | ||||||
|  |  | ||||||
|       event.target.parentNode.classList.add('active') |       event.target.parentNode.classList.add("active"); | ||||||
|       addMagnet(magnet, name, this.tmdb_id) |       addMagnet(magnet, name, this.tmdb_id) | ||||||
|       .catch((resp) => { console.log('error:', resp.data) }) |         .catch(resp => { | ||||||
|       .then((resp) => { |           console.log("error:", resp.data); | ||||||
|         console.log('addTorrent resp: ', resp) |         }) | ||||||
|  |         .then(resp => { | ||||||
|  |           console.log("addTorrent resp: ", resp); | ||||||
|           this.$notifications.success({ |           this.$notifications.success({ | ||||||
|           title: 'Torrent added 🎉', |             title: "Torrent added 🎉", | ||||||
|             description: this.query, |             description: this.query, | ||||||
|             timeout: 3000 |             timeout: 3000 | ||||||
|         }) |           }); | ||||||
|       }) |         }); | ||||||
|     }, |     }, | ||||||
|     sortTable(col, sameDirection=false) { |     sortTable(col, sameDirection = false) { | ||||||
|       if (this.prevCol === col && sameDirection === false) { |       if (this.prevCol === col && sameDirection === false) { | ||||||
|         this.direction = !this.direction |         this.direction = !this.direction; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       switch (col) { |       if (col === "name") this.sortName(); | ||||||
|         case 'name': |       else if (col === "seed") this.sortSeed(); | ||||||
|           this.sortName() |       else if (col === "size") this.sortSize(); | ||||||
|           break |  | ||||||
|         case 'seed': |       this.prevCol = col; | ||||||
|           this.sortSeed() |  | ||||||
|           break |  | ||||||
|         case 'size': |  | ||||||
|           this.sortSize() |  | ||||||
|           break |  | ||||||
|       } |  | ||||||
|       this.prevCol = col |  | ||||||
|     }, |     }, | ||||||
|     sortName() { |     sortName() { | ||||||
|       const torrentsCopy = [...this.torrents] |       const torrentsCopy = [...this.torrents]; | ||||||
|       if (this.direction) { |       if (this.direction) { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => (a.name < b.name) ? 1 : -1) |         this.torrents = torrentsCopy.sort((a, b) => (a.name < b.name ? 1 : -1)); | ||||||
|       } else { |       } else { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => (a.name > b.name) ? 1 : -1) |         this.torrents = torrentsCopy.sort((a, b) => (a.name > b.name ? 1 : -1)); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     sortSeed() { |     sortSeed() { | ||||||
|       const torrentsCopy = [...this.torrents] |       const torrentsCopy = [...this.torrents]; | ||||||
|       if (this.direction) { |       if (this.direction) { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => parseInt(a.seed) - parseInt(b.seed)); |         this.torrents = torrentsCopy.sort( | ||||||
|  |           (a, b) => parseInt(a.seed) - parseInt(b.seed) | ||||||
|  |         ); | ||||||
|       } else { |       } else { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => parseInt(b.seed) - parseInt(a.seed)); |         this.torrents = torrentsCopy.sort( | ||||||
|  |           (a, b) => parseInt(b.seed) - parseInt(a.seed) | ||||||
|  |         ); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     sortSize() { |     sortSize() { | ||||||
|       const torrentsCopy = [...this.torrents] |       const torrentsCopy = [...this.torrents]; | ||||||
|       if (this.direction) { |       if (this.direction) { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => parseInt(sortableSize(a.size)) - parseInt(sortableSize(b.size))); |         this.torrents = torrentsCopy.sort( | ||||||
|  |           (a, b) => | ||||||
|  |             parseInt(sortableSize(a.size)) - parseInt(sortableSize(b.size)) | ||||||
|  |         ); | ||||||
|       } else { |       } else { | ||||||
|         this.torrents = torrentsCopy.sort((a, b) => parseInt(sortableSize(b.size)) - parseInt(sortableSize(a.size))); |         this.torrents = torrentsCopy.sort( | ||||||
|  |           (a, b) => | ||||||
|  |             parseInt(sortableSize(b.size)) - parseInt(sortableSize(a.size)) | ||||||
|  |         ); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     findRelaseTypes() { |     findRelaseTypes() { | ||||||
|       this.torrents.forEach(item => this.release_types.push(...item.release_type)) |       this.torrents.forEach(item => | ||||||
|       this.release_types = [...new Set(this.release_types)] |         this.release_types.push(...item.release_type) | ||||||
|  |       ); | ||||||
|  |       this.release_types = [...new Set(this.release_types)]; | ||||||
|     }, |     }, | ||||||
|     applyFilter(item, index) { |     applyFilter(item, index) { | ||||||
|       this.selectedRelaseType = item; |       this.selectedRelaseType = item; | ||||||
|       const torrents = [...this.torrentResponse] |       const torrents = [...this.torrentResponse]; | ||||||
|  |  | ||||||
|       if (item === 'all') { |       if (item === "all") { | ||||||
|         this.torrents = torrents |         this.torrents = torrents; | ||||||
|         this.sortTable(this.prevCol, true) |         this.sortTable(this.prevCol, true); | ||||||
|         return |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       this.torrents = torrents.filter(torrent => torrent.release_type.includes(item)) |       this.torrents = torrents.filter(torrent => | ||||||
|       this.sortTable(this.prevCol, true) |         torrent.release_type.includes(item) | ||||||
|  |       ); | ||||||
|  |       this.sortTable(this.prevCol, true); | ||||||
|     }, |     }, | ||||||
|     updateResultCountInStore() { |     updateResultCountInStore() { | ||||||
|       store.dispatch('torrentModule/setResults', this.torrents) |       store.dispatch("torrentModule/setResults", this.torrents); | ||||||
|       store.dispatch('torrentModule/setResultCount', this.torrentResponse.length) |       store.dispatch( | ||||||
|  |         "torrentModule/setResultCount", | ||||||
|  |         this.torrentResponse.length | ||||||
|  |       ); | ||||||
|     }, |     }, | ||||||
|     fetchTorrents(query=undefined){ |     filterDeadTorrents(torrents) { | ||||||
|       this.listLoaded = false; |       return torrents.filter(torrent => { | ||||||
|  |         if (isNaN(torrent.seed)) return false; | ||||||
|  |         return parseInt(torrent.seed) > 0; | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     fetchTorrents(query = undefined) { | ||||||
|  |       this.loading = true; | ||||||
|       this.editSearchQuery = false; |       this.editSearchQuery = false; | ||||||
|  |  | ||||||
|       searchTorrents(query || this.query, 'all', this.currentPage, storage.token) |       return searchTorrents(query || this.query) | ||||||
|         .then(data => { |         .then(data => { | ||||||
|             this.torrentResponse = [...data.results]; |           const { results } = data; | ||||||
|             this.torrents = data.results; |           if (results) { | ||||||
|             this.listLoaded = true; |             this.torrentResponse = results; | ||||||
|  |             this.torrents = this.filterDeadTorrents(results); | ||||||
|  |           } else { | ||||||
|  |             this.torrents = []; | ||||||
|  |           } | ||||||
|         }) |         }) | ||||||
|         .then(this.updateResultCountInStore) |         .then(this.updateResultCountInStore) | ||||||
|         .then(this.findRelaseTypes) |         .then(this.findRelaseTypes) | ||||||
|         .catch(e => { |         .catch(e => { | ||||||
|           const error = e.toString() |           console.log("e:", e); | ||||||
|           this.errorMessage = error.indexOf('401') != -1 ? 'Permission denied' : 'Nothing found'; |           const error = e.toString(); | ||||||
|           this.listLoaded = true; |           this.errorMessage = | ||||||
|  |             error.indexOf("401") != -1 ? "Permission denied" : "Nothing found"; | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           this.loading = false; | ||||||
|         }); |         }); | ||||||
|     }, |     }, | ||||||
|  |     handleInput(event) { | ||||||
|  |       this.editedSearchQuery = event.target.innerText; | ||||||
|  |       console.log("edit text:", this.editedSearchQuery); | ||||||
|     } |     } | ||||||
| } |   } | ||||||
|  | }; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
| @@ -301,11 +378,153 @@ export default { | |||||||
|     width: 100%; |     width: 100%; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | $checkboxSize: 20px; | ||||||
|  | $ui-border-width: 2px; | ||||||
|  |  | ||||||
|  | .checkbox { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: row; | ||||||
|  |   margin-bottom: $checkboxSize * 0.5; | ||||||
|  |  | ||||||
|  |   input[type="checkbox"] { | ||||||
|  |     display: block; | ||||||
|  |     opacity: 0; | ||||||
|  |     position: absolute; | ||||||
|  |  | ||||||
|  |     + div { | ||||||
|  |       position: relative; | ||||||
|  |       display: inline-block; | ||||||
|  |       padding-left: 1.25rem; | ||||||
|  |       font-size: 20px; | ||||||
|  |       line-height: $checkboxSize + $ui-border-width * 2; | ||||||
|  |       left: $checkboxSize; | ||||||
|  |       cursor: pointer; | ||||||
|  |  | ||||||
|  |       &::before { | ||||||
|  |         content: ""; | ||||||
|  |         display: inline-block; | ||||||
|  |         position: absolute; | ||||||
|  |         left: -$checkboxSize; | ||||||
|  |         border: $ui-border-width solid var(--color-green); | ||||||
|  |         width: $checkboxSize; | ||||||
|  |         height: $checkboxSize; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &::after { | ||||||
|  |         transition: all 0.3s ease; | ||||||
|  |         content: ""; | ||||||
|  |         position: absolute; | ||||||
|  |         display: inline-block; | ||||||
|  |         left: -$checkboxSize + $ui-border-width; | ||||||
|  |         top: $ui-border-width; | ||||||
|  |         width: $checkboxSize + $ui-border-width; | ||||||
|  |         height: $checkboxSize + $ui-border-width; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:checked { | ||||||
|  |       + div::after { | ||||||
|  |         background-color: var(--color-green); | ||||||
|  |         opacity: 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:hover:not(checked) { | ||||||
|  |       + div::after { | ||||||
|  |         background-color: var(--color-green); | ||||||
|  |         opacity: 0.4; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:focus { | ||||||
|  |       + div::before { | ||||||
|  |         outline: 2px solid Highlight; | ||||||
|  |         outline-style: auto; | ||||||
|  |         outline-color: -webkit-focus-ring-color; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
| @import "./src/scss/variables"; | @import "src/scss/variables"; | ||||||
| @import "./src/scss/media-queries"; | @import "src/scss/media-queries"; | ||||||
| @import "./src/scss/elements"; | @import "src/scss/elements"; | ||||||
|  |  | ||||||
|  | h2 { | ||||||
|  |   font-size: 20px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | thead { | ||||||
|  |   user-select: none; | ||||||
|  |   -webkit-user-select: none; | ||||||
|  |   color: var(--background-color); | ||||||
|  |   text-transform: uppercase; | ||||||
|  |   cursor: pointer; | ||||||
|  |   background-color: var(--text-color); | ||||||
|  |   letter-spacing: 0.8px; | ||||||
|  |   font-size: 1rem; | ||||||
|  |   border: 1px solid var(--text-color-90); | ||||||
|  |  | ||||||
|  |   th:first-of-type { | ||||||
|  |     border-top-left-radius: 8px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   th:last-of-type { | ||||||
|  |     border-top-right-radius: 8px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | tbody { | ||||||
|  |   tr > td:first-of-type { | ||||||
|  |     white-space: unset; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr > td:not(td:first-of-type) { | ||||||
|  |     text-align: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr > td:last-of-type { | ||||||
|  |     cursor: pointer; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr td:first-of-type { | ||||||
|  |     border-left: 1px solid var(--text-color-90); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr td:last-of-type { | ||||||
|  |     border-right: 1px solid var(--text-color-90); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr:last-of-type { | ||||||
|  |     td { | ||||||
|  |       border-bottom: 1px solid var(--text-color-90); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     td:first-of-type { | ||||||
|  |       border-bottom-left-radius: 8px; | ||||||
|  |     } | ||||||
|  |     td:last-of-type { | ||||||
|  |       border-bottom-right-radius: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   tr:nth-child(even) { | ||||||
|  |     background-color: var(--background-70); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | th, | ||||||
|  | td { | ||||||
|  |   padding: 0.35rem 0.25rem; | ||||||
|  |   white-space: nowrap; | ||||||
|  |  | ||||||
|  |   svg { | ||||||
|  |     width: 24px; | ||||||
|  |     fill: var(--text-color); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| .toggle { | .toggle { | ||||||
|   max-width: unset !important; |   max-width: unset !important; | ||||||
| @@ -323,17 +542,21 @@ export default { | |||||||
|   justify-content: center; |   justify-content: center; | ||||||
|   padding-bottom: 20px; |   padding-bottom: 20px; | ||||||
|  |  | ||||||
|  |  | ||||||
|   &-text { |   &-text { | ||||||
|     font-weight: 400; |     font-weight: 400; | ||||||
|     text-transform: uppercase; |     text-transform: uppercase; | ||||||
|     font-size: 14px; |     font-size: 20px; | ||||||
|     color: $green; |     // color: $green; | ||||||
|     text-align: center; |     text-align: center; | ||||||
|     margin: 0; |     margin: 0; | ||||||
|  |  | ||||||
|     @include tablet-min { |     .icon { | ||||||
|       font-size: 16px |       vertical-align: text-top; | ||||||
|  |       margin-left: 1rem; | ||||||
|  |       fill: var(--text-color); | ||||||
|  |       width: 22px; | ||||||
|  |       height: 22px; | ||||||
|  |       // stroke: white !important; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     &.editable { |     &.editable { | ||||||
| @@ -355,59 +578,67 @@ export default { | |||||||
| } | } | ||||||
|  |  | ||||||
| table { | table { | ||||||
|   border-collapse: collapse; |   // border-collapse: collapse; | ||||||
|  |   border-spacing: 0; | ||||||
|  |   margin-top: 1rem; | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   table-layout: fixed; |   // table-layout: fixed; | ||||||
| } | } | ||||||
|  |  | ||||||
| .table__content, .table__header { | // .table__content, | ||||||
|   display: flex; | // .table__header { | ||||||
|   padding: 0; | //   display: flex; | ||||||
|   border-left: 1px solid $text-color; | //   padding: 0; | ||||||
|   border-right: 1px solid $text-color; | //   border-left: 1px solid $text-color; | ||||||
|   border-bottom: 1px solid $text-color; | //   border-right: 1px solid $text-color; | ||||||
|  | //   border-bottom: 1px solid $text-color; | ||||||
|  |  | ||||||
|   th, td { | //   th, | ||||||
|     display: flex; | //   td { | ||||||
|     flex-direction: column; | //     display: flex; | ||||||
|     flex-basis: 100%; | //     flex-direction: column; | ||||||
|  | //     flex-basis: 100%; | ||||||
|  |  | ||||||
|     padding: 0.4rem; | //     padding: 0.4rem; | ||||||
|  |  | ||||||
|     white-space: nowrap; | //     white-space: nowrap; | ||||||
|     text-overflow: ellipsis; | //     text-overflow: ellipsis; | ||||||
|     overflow: hidden; | //     overflow: hidden; | ||||||
|     min-width: 75px; | //     min-width: 75px; | ||||||
|   } | //   } | ||||||
|  |  | ||||||
|   th:first-child, td:first-child { | //   th:first-child, | ||||||
|     flex: 1; | //   td:first-child { | ||||||
|   } | //     flex: 1; | ||||||
|  | //   } | ||||||
|  |  | ||||||
|   th:not(:first-child), td:not(:first-child) { | //   th:not(:first-child), | ||||||
|     flex: 0.2; | //   td:not(:first-child) { | ||||||
|   } | //     flex: 0.2; | ||||||
|  | //   } | ||||||
|  |  | ||||||
|   th:nth-child(2), td:nth-child(2) { | //   th:nth-child(2), | ||||||
|     flex: 0.1; | //   td:nth-child(2) { | ||||||
|   } | //     flex: 0.1; | ||||||
|  | //   } | ||||||
|  |  | ||||||
|   @include mobile-only { | //   @include mobile-only { | ||||||
|     th:first-child, td:first-child { | //     th:first-child, | ||||||
|       display: none; | //     td:first-child { | ||||||
|  | //       display: none; | ||||||
|  |  | ||||||
|       &.show { | //       &.show { | ||||||
|         display: block; | //         display: block; | ||||||
|         align: flex-end; | //         align: flex-end; | ||||||
|       } | //       } | ||||||
|     } | //     } | ||||||
|  |  | ||||||
|     th:not(:first-child), td:not(:first-child) { | //     th:not(:first-child), | ||||||
|       flex: 1; | //     td:not(:first-child) { | ||||||
|     } | //       flex: 1; | ||||||
|   } | //     } | ||||||
|  | //   } | ||||||
| } | // } | ||||||
|  |  | ||||||
| .table__content { | .table__content { | ||||||
|   td:not(:last-child) { |   td:not(:last-child) { | ||||||
| @@ -422,58 +653,54 @@ table { | |||||||
|   border-bottom-right-radius: 3px; |   border-bottom-right-radius: 3px; | ||||||
| } | } | ||||||
|  |  | ||||||
| .table__header { | // .table__header { | ||||||
|   color: $text-color; | //   color: $text-color; | ||||||
|   text-transform: uppercase; | //   text-transform: uppercase; | ||||||
|   cursor: pointer; | //   cursor: pointer; | ||||||
|   background-color: $background-color-secondary; | //   background-color: $background-color-secondary; | ||||||
|  |  | ||||||
|   border-top: 1px solid $text-color; | //   border-top: 1px solid $text-color; | ||||||
|   border-top-left-radius: 3px; | //   border-top-left-radius: 3px; | ||||||
|   border-top-right-radius: 3px; | //   border-top-right-radius: 3px; | ||||||
|  |  | ||||||
|   th { | //   th { | ||||||
|     display: flex; | //     display: flex; | ||||||
|     flex-direction: row; | //     flex-direction: row; | ||||||
|     font-weight: 400; | //     font-weight: 400; | ||||||
|     letter-spacing: 0.7px; | //     letter-spacing: 0.7px; | ||||||
|     // font-size: 1.08rem; | //     // font-size: 1.08rem; | ||||||
|     font-size: 15px; | //     font-size: 15px; | ||||||
|  |  | ||||||
|     &::before { | //     &::before { | ||||||
|       content: ''; | //       content: ""; | ||||||
|       min-width: 0.2rem; | //       min-width: 0.2rem; | ||||||
|     } | //     } | ||||||
|  |  | ||||||
|     span:first-child { |  | ||||||
|       margin-right: 0.6rem; |  | ||||||
|     } |  | ||||||
|     span:nth-child(2) { |  | ||||||
|       margin-right: 0.1rem; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   th:not(:last-child) { |  | ||||||
|     border-right: 1px solid $text-color; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | //     span:first-child { | ||||||
|  | //       margin-right: 0.6rem; | ||||||
|  | //     } | ||||||
|  | //     span:nth-child(2) { | ||||||
|  | //       margin-right: 0.1rem; | ||||||
|  | //     } | ||||||
|  | //   } | ||||||
|  |  | ||||||
|  | //   th:not(:last-child) { | ||||||
|  | //     border-right: 1px solid $text-color; | ||||||
|  | //   } | ||||||
|  | // } | ||||||
|  |  | ||||||
| .editQuery { | .editQuery { | ||||||
|   display: flex; |   display: flex; | ||||||
|   width: 70%; |   width: 70%; | ||||||
|   justify-content: center; |   justify-content: center; | ||||||
|  |   margin-bottom: 1rem; | ||||||
|  |  | ||||||
|   @include mobile-only { |   @include mobile-only { | ||||||
|     width: 90%; |     width: 90%; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| .download { | .download { | ||||||
|  |  | ||||||
|   &__icon { |   &__icon { | ||||||
|     fill: $text-color-70; |     fill: $text-color-70; | ||||||
|     height: 1.2rem; |     height: 1.2rem; | ||||||
| @@ -506,7 +733,7 @@ table { | |||||||
|     &:after { |     &:after { | ||||||
|       border: 5px solid $green; |       border: 5px solid $green; | ||||||
|       border-radius: 50%; |       border-radius: 50%; | ||||||
|       content: ''; |       content: ""; | ||||||
|       left: 10px; |       left: 10px; | ||||||
|       position: absolute; |       position: absolute; | ||||||
|       top: 16px; |       top: 16px; | ||||||
| @@ -514,6 +741,8 @@ table { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| @keyframes load { | @keyframes load { | ||||||
|   100% { transform: rotate(360deg); } |   100% { | ||||||
|  |     transform: rotate(360deg); | ||||||
|  |   } | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user