<!-- - @copyright Copyright (c) 2020 Jonas Heinrich - - @author Jonas Heinrich <onny@project-insanity.org> - - @license GNU AGPL version 3 or any later version - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - --> <template> <table class="episodeTable"> <thead> <tr> <th class="iconColumn" /> <th class="nameColumn"> {{ t('podcast', 'Name') }} </th> <th class="actionColumn" /> <th class="durationColumn"> {{ t('podcast', 'Duration') }} </th> <th class="dateColumn"> {{ t('podcast', 'Date') }} </th> </tr> </thead> <tbody> <tr v-for="(episode, idx) in episodes" :key="idx" :class="{ selected: idx === activeItem}"> <td class="iconColumn"> <div class="episodeImage" :style="{ backgroundImage: `url(${episode.imgURL})` }" /> </td> <td class="nameColumn" @click="changeRoute(`/browse/show/${episode.podcast_id}/${episode.id}`)"> <i-amp-video-eq> <div class="-amp-video-eq-col"> <div class="-amp-video-eq-1-1" /> <div class="-amp-video-eq-1-2" /> </div> <div class="-amp-video-eq-col"> <div class="-amp-video-eq-2-1" /> <div class="-amp-video-eq-2-2" /> </div> <div class="-amp-video-eq-col"> <div class="-amp-video-eq-3-1" /> <div class="-amp-video-eq-3-2" /> </div> <div class="-amp-video-eq-col"> <div class="-amp-video-eq-4-1" /> <div class="-amp-video-eq-4-2" /> </div> </i-amp-video-eq> <b>{{ episode.title }}</b> <vue-show-more-text :text="escapedEpisodeDescription(episode.description)" :lines="2" :has-more="false" additional-container-css="padding: 0px;" /> </td> <td class="actionColumn"> <Actions> <ActionButton icon="icon-play" :close-after-click="true" @click="doPlay(idx, episode)"> {{ t('podcast', 'Play') }} </ActionButton> <ActionButton icon="icon-info" :close-after-click="true" @click="changeRoute(`/browse/show/${episode.podcast_id}/${episode.id}`)"> {{ t('podcast', 'Show') }} </ActionButton> <ActionButton icon="icon-download" :close-after-click="true" @click="downloadFile(episode.enclosure)"> {{ t('podcast', 'Download') }} </ActionButton> <ActionButton icon="icon-shared" :close-after-click="true"> {{ t('podcast', 'Share') }} </ActionButton> </Actions> </td> <td class="durationColumn" @click="changeRoute(`/browse/show/${episode.podcast_id}/${episode.id}`)"> {{ episode.duration_string }} </td> <td class="dateColumn" @click="changeRoute(`/browse/show/${episode.podcast_id}/${episode.id}`)"> {{ readableTime(episode.inserted) }} </td> </tr> </tbody> </table> </template> <script> import Actions from '@nextcloud/vue/dist/Components/Actions' import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' import TimeAgo from 'javascript-time-ago' import en from 'javascript-time-ago/locale/en' import vueShowMoreText from 'vue-show-more-text' TimeAgo.addDefaultLocale(en) const timeAgo = new TimeAgo('en-US') export default { name: 'Table', components: { Actions, ActionButton, vueShowMoreText, }, props: { episodes: { type: Array, default() { return [] }, }, }, data: () => ({ activeItem: null, }), methods: { escapedEpisodeDescription(episodeDescription) { episodeDescription = episodeDescription.replace(/\n/g, '') return episodeDescription }, readableTime(datetime) { return timeAgo.format(Date.parse(datetime), 'twitter-minute-now') }, downloadFile(episodeURL) { window.open(episodeURL, 'download') }, doPlay(idx, episode) { this.activeItem = idx this.$emit('doPlay', episode) }, changeRoute(path) { this.$router.push({ path }) }, }, } </script> <style lang="scss"> /* Workaround wrong positioning actions popover menu https://github.com/nextcloud/nextcloud-vue/issues/1384 */ body { min-height: 100%; height: auto; } table.episodeTable { width: 100%; min-width: 250px; table-layout:fixed; position: relative; thead { background-color: var(--color-main-background-translucent); z-index: 60; position: sticky; top: 50px; th { border-bottom: 1px solid var(--color-border); padding: 15px; height: 50px; color: var(--color-text-maxcontrast); } th.iconColumn { padding: 0px; width: 115px; } th.nameColumn { width: 100%; } th.actionColumn { width: 72px; } th.durationColumn { width: 90px; } th.dateColumn { width: 130px; } } tbody { tr { height: 91px; background: var(--color-background-light); transition: opacity 500ms ease 0s; .selected { background: var(--color-primary-light); } * { cursor: pointer; } } td { padding: 0 15px; font-style: normal; border-bottom: 1px solid var(--color-border); } td.iconColumn { padding-right: 0px; padding-left: 35px; div { width: 74px; height: 74px; } } td.nameColumn { overflow: hidden; text-overflow: ellipsis; padding-right: 0px; b { color: var(--color-main-text); user-select: none; cursor: pointer; font-size: 1.05em; } } tr:hover td { background: var(--color-background-hover); } } } @media only screen and (max-width: 500px) { table { thead { th.iconColumn { width: 85px; } th.nameColumn { padding-left: 0px; } th.actionColumn { padding-left: 5px; padding-right: 5px; width: 50px; } th.durationColumn, th.dateColumn { display: none; } } tbody { td.iconColumn { padding-left: 10px; } td.nameColumn { padding-left: 0px; } td.actionColumn { padding-left: 5px; padding-right: 5px; width: 50px; } td.durationColumn, td.dateColumn { display: none; } } } } i-amp-video-eq { align-items: flex-end; display: none; width: 20px; height: 12px; overflow: hidden; opacity: 0.8; position: relative; float: left; top: 5px; margin-right: 5px; } i-amp-video-eq .-amp-video-eq-col { flex: 1; position: relative; height: 100%; margin-right: 1px; } i-amp-video-eq .-amp-video-eq-col div { animation-name: amp-video-eq-animation; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; background-color: rgb(0, 130, 201); position: absolute; width: 100%; height: 100%; transform: translateY(100%); will-change: transform; } .-amp-video-eq-1-1 { animation-duration: 0.3s; } .-amp-video-eq-1-2 { animation-duration: 0.45s; } .-amp-video-eq-2-1 { animation-duration: 0.5s; } .-amp-video-eq-2-2 { animation-duration: 0.4s; } .-amp-video-eq-3-1 { animation-duration: 0.3s; } .-amp-video-eq-3-2 { animation-duration: 0.35s; } .-amp-video-eq-4-1 { animation-duration: 0.4s; } .-amp-video-eq-4-2 { animation-duration: 0.25s; } @keyframes amp-video-eq-animation { 0% { transform: translateY(100%); } 100% { transform: translateY(0); } } table.episodeTable tr.selected i-amp-video-eq { display: flex; } </style>