diff --git a/src/components/Table.vue b/src/components/Table.vue index 68d54d42f64efca56717c09a2a0661c83320c31f..83ec35240162db6ff234f48954bac8ec6f42f711 100644 --- a/src/components/Table.vue +++ b/src/components/Table.vue @@ -392,4 +392,8 @@ table.episodeTable { table.episodeTable tr.selected .eq-animation { display: flex; } + +.inline { + display: inline; +} </style> diff --git a/src/views/BrowseAll.vue b/src/views/BrowseAll.vue new file mode 100644 index 0000000000000000000000000000000000000000..3b06a9d45c5e209d5eb874eca255269c0366ad8c --- /dev/null +++ b/src/views/BrowseAll.vue @@ -0,0 +1,164 @@ +<!-- + - @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> + <div class="mainContent"> + <div class="podcastSection"> + <div class="podcastSectionHeader"> + <h1>Hot podcasts</h1> + </div> + <div class="podcastSliderAll"> + <div + v-for="(podcast, idx) in podcasts" + :key="idx" + class="podcastCard"> + <router-link :to="{ path: `/browse/show/${podcast.id}`}"> + <div + class="podcastImage" + :style="{ backgroundImage: `url(${podcast.smallImageURL})` }" /> + <span class="title"> + {{ podcast.title }} + </span> + <span class="subtitle"> + {{ podcast.author }} + </span> + </router-link> + </div> + </div> + </div> + </div> +</template> + +<script> +import { showError } from '@nextcloud/dialogs' +import axios from '@nextcloud/axios' + +export default { + name: 'BrowseAll', + data: () => ({ + podcasts: {}, + }), + mounted() { + this.queryPodcasts() + }, + methods: { + + async queryPodcasts() { + + const vm = this + + const queryURI = this.$apiUrl + '/feature/podcast/hot' + try { + delete axios.defaults.headers.requesttoken + await axios.get(queryURI) + .then(function(response) { + vm.podcasts = response.data.data + }) + } catch (error) { + showError(t('podcast', 'Could not fetch podcasts from remote API')) + } + + }, + + }, +} +</script> + +<style lang="scss"> +.mainContent { + padding: 30px; +} + +.podcastSection { + margin-bottom: 30px; +} + +.podcastSectionHeader { + padding: 10px 0px; + z-index: 60; + position: sticky; + top: 50px; + background: white; + display: flex; + align-items: center; + margin-bottom: 10px; + + h1 { + flex-grow: 1; + font-size: 1.6em; + margin-bottom: 0px; + } + a { + color: #1976d2; + cursor: pointer; + } +} + +.podcastSliderAll { + width: 100%; + display: flex; + flex-wrap: wrap; +} + +.podcastCard { + width: 170px; + height: 220px; + margin-right: 15px; + flex-shrink: 0; + background: rgba(241, 241, 241, 0.6); + border-radius: 3px; + padding: 15px; + transition: all 0.2s ease-in-out; + + * { + cursor: pointer; + } + + .podcastImage { + background-size: cover; + background-position: center; + box-shadow: 1px 1px 2px rgba(0,0,0,.5); + border: 1px solid rgba(0,0,0,.5); + border-radius: 5px; + width: 140px; + height: 140px; + margin-bottom: 5px; + } + + span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: block; + } + span.title { + font-size: 1em; + } + span.subtitle { + font-size: 0.9em; + color: #b5b1b1; + } +} + +.podcastCard:hover { + background: rgb(236, 236, 236); +} +</style> diff --git a/src/views/Episode.vue b/src/views/Episode.vue index c2857893f2910ae55a0ee3e4a8aef16344ad230f..37211edf17d57f759ce67e235b0ed5b082fbbe7c 100644 --- a/src/views/Episode.vue +++ b/src/views/Episode.vue @@ -40,7 +40,7 @@ </span> <span> <b>Publication date:</b> - <span :title="readableDate(episode.pubdate)"> + <span class="inline" :title="readableDate(episode.pubdate)"> {{ readableTimeAgo(episode.pubdate) }} </span> </span> diff --git a/src/views/placeholder/Browse.vue b/src/views/placeholder/Browse.vue new file mode 100644 index 0000000000000000000000000000000000000000..5cf930216e7df13d1aa03659ea83497e3799449f --- /dev/null +++ b/src/views/placeholder/Browse.vue @@ -0,0 +1,154 @@ +<!-- + - @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> + <div class="mainContent"> + <div + v-for="mainIndex in 3" + :key="mainIndex" + class="podcastSection"> + <div class="podcastSectionHeader"> + <div + class="podcastDescriptionSubTitle" + style="max-width: 300px; width: 100%; height: 30px;" /> + </div> + <div class="podcastSlider"> + <div + v-for="index in 3" + :key="index" + class="podcastCard"> + <div class="podcastImageEmpty" /> + <div + class="episodeDescription" + style="width: 120px; margin-top: 10px;" /> + </div> + </div> + </div> + </div> +</template> + +<script> + +export default { + name: 'Browse', +} +</script> + +<style lang="scss"> + +$base-color: #ddd; +$shine-color: #e8e8e8; +$animation-duration: 1.6s; +$avatar-offset: 52 + 16; + +@mixin background-gradient { + background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px); + background-size: 600px; +} + +.podcastHeaderEmpty { + width: 100%; + min-height: 300px; + display: flex; + justify-content: center; + padding: 40px 20px; + background-color: #f2f2f2; +} + +.podcastImageEmpty { + width: 140px; + height: 140px; + flex-shrink: 0; + background-color: #ccc; + margin-right: 25px; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.podcastDescriptionEmpty { + max-width: 500px; + width: 100%; +} + +.podcastDescriptionTitle { + max-width: 500px; + width: 100%; + height: 35px; + border-radius: 5px; + margin-bottom: 30px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.podcastDescriptionSubTitle { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.episodeImageEmpty { + width: 74px; + height: 74px; + background-color: #ccc; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.episodeDescription { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +@keyframes shine-lines { + 0% { + background-position: -100px; + } + 60%, 100% { + background-position: 500px; + } +} + +@keyframes shine-avatar { + 0% { + background-position: -100px + $avatar-offset; + } + 40%, 100% { + background-position: 140px + $avatar-offset; + } +} + +</style> diff --git a/src/views/placeholder/Episode.vue b/src/views/placeholder/Episode.vue new file mode 100644 index 0000000000000000000000000000000000000000..395b3b740852f8c5d1ecdfab3500c85ebb6a700e --- /dev/null +++ b/src/views/placeholder/Episode.vue @@ -0,0 +1,183 @@ +<!-- + - @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> + <div> + <div class="podcastHeaderEmpty"> + <div class="podcastImageEmpty" /> + <div class="podcastDescriptionEmpty"> + <div class="podcastDescriptionTitle" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 300px; width: 100%;" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 400px; width: 100%;" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 200px; width: 100%;" /> + </div> + </div> + <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="index in 3" :key="index"> + <td class="iconColumn"> + <div class="episodeImageEmpty" /> + </td> + <td class="nameColumn"> + <div + class="episodeDescription" + style="width: 500px;" /> + <div + class="episodeDescription" + style="width: 400px;" /> + </td> + <td class="actionColumn" /> + <td class="durationColumn" /> + <td class="dateColumn" /> + </tr> + </tbody> + </table> + </div> +</template> + +<script> + +export default { + name: 'Episode', +} +</script> + +<style lang="scss"> + +$base-color: #ddd; +$shine-color: #e8e8e8; +$animation-duration: 1.6s; +$avatar-offset: 52 + 16; + +@mixin background-gradient { + background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px); + background-size: 600px; +} + +.podcastHeaderEmpty { + width: 100%; + min-height: 300px; + display: flex; + justify-content: center; + padding: 40px 20px; + background-color: #f2f2f2; +} + +.podcastImageEmpty { + width: 200px; + height: 200px; + flex-shrink: 0; + background-color: #ccc; + margin-right: 25px; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.podcastDescriptionEmpty { + max-width: 500px; + width: 100%; +} + +.podcastDescriptionTitle { + max-width: 500px; + width: 100%; + height: 35px; + border-radius: 5px; + margin-bottom: 30px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.podcastDescriptionSubTitle { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.episodeImageEmpty { + width: 74px; + height: 74px; + background-color: #ccc; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.episodeDescription { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +@keyframes shine-lines { + 0% { + background-position: -100px; + } + 60%, 100% { + background-position: 500px; + } +} + +@keyframes shine-avatar { + 0% { + background-position: -100px + $avatar-offset; + } + 40%, 100% { + background-position: 140px + $avatar-offset; + } +} + +</style> diff --git a/src/views/placeholder/Show.vue b/src/views/placeholder/Show.vue new file mode 100644 index 0000000000000000000000000000000000000000..e7cb27d48b71283b4493c502c9d096ad566b630d --- /dev/null +++ b/src/views/placeholder/Show.vue @@ -0,0 +1,183 @@ +<!-- + - @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> + <div> + <div class="podcastHeaderEmpty"> + <div class="podcastImageEmpty" /> + <div class="podcastDescriptionEmpty"> + <div class="podcastDescriptionTitle" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 300px; width: 100%;" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 400px; width: 100%;" /> + <div + class="podcastDescriptionSubTitle" + style="max-width: 200px; width: 100%;" /> + </div> + </div> + <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="index in 3" :key="index"> + <td class="iconColumn"> + <div class="episodeImageEmpty" /> + </td> + <td class="nameColumn"> + <div + class="episodeDescription" + style="width: 500px;" /> + <div + class="episodeDescription" + style="width: 400px;" /> + </td> + <td class="actionColumn" /> + <td class="durationColumn" /> + <td class="dateColumn" /> + </tr> + </tbody> + </table> + </div> +</template> + +<script> + +export default { + name: 'Show', +} +</script> + +<style lang="scss"> + +$base-color: #ddd; +$shine-color: #e8e8e8; +$animation-duration: 1.6s; +$avatar-offset: 52 + 16; + +@mixin background-gradient { + background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px); + background-size: 600px; +} + +.podcastHeaderEmpty { + width: 100%; + min-height: 300px; + display: flex; + justify-content: center; + padding: 40px 20px; + background-color: #f2f2f2; +} + +.podcastImageEmpty { + width: 200px; + height: 200px; + flex-shrink: 0; + background-color: #ccc; + margin-right: 25px; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.podcastDescriptionEmpty { + max-width: 500px; + width: 100%; +} + +.podcastDescriptionTitle { + max-width: 500px; + width: 100%; + height: 35px; + border-radius: 5px; + margin-bottom: 30px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.podcastDescriptionSubTitle { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +.episodeImageEmpty { + width: 74px; + height: 74px; + background-color: #ccc; + border-radius: 5px; + + @include background-gradient; + animation: shine-avatar $animation-duration infinite linear; +} + +.episodeDescription { + height: 20px; + border-radius: 5px; + margin-bottom: 10px; + background-color: #ddd; + + @include background-gradient; + animation: shine-lines $animation-duration infinite linear; +} + +@keyframes shine-lines { + 0% { + background-position: -100px; + } + 60%, 100% { + background-position: 500px; + } +} + +@keyframes shine-avatar { + 0% { + background-position: -100px + $avatar-offset; + } + 40%, 100% { + background-position: 140px + $avatar-offset; + } +} + +</style>