From e8b30ed89860fc4305dc61f58009a9a392b37172 Mon Sep 17 00:00:00 2001 From: Daniel Supernault <danielsupernault@gmail.com> Date: Thu, 2 Jan 2020 15:13:47 -0700 Subject: [PATCH] Add StoryViewer Component --- resources/assets/js/components/Profile.vue | 39 ++++++- .../assets/js/components/StoryViewer.vue | 106 ++++++++++++++++++ 2 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 resources/assets/js/components/StoryViewer.vue diff --git a/resources/assets/js/components/Profile.vue b/resources/assets/js/components/Profile.vue index ecec7cc18..eff47cec8 100644 --- a/resources/assets/js/components/Profile.vue +++ b/resources/assets/js/components/Profile.vue @@ -35,7 +35,12 @@ <div class="d-block d-md-none mt-n3 mb-3"> <div class="row"> <div class="col-4"> - <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle border mr-2" :src="profile.avatar" width="77px" height="77px"> + <div v-if="hasStory" class="has-story cursor-pointer shadow-sm" @click="storyRedirect()"> + <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle" :src="profile.avatar" width="77px" height="77px"> + </div> + <div v-else> + <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle border" :src="profile.avatar" width="77px" height="77px"> + </div> </div> <div class="col-8"> <div class="d-block d-md-none mt-3 py-2"> @@ -72,7 +77,12 @@ <!-- DESKTOP PROFILE PICTURE --> <div class="d-none d-md-block pb-5"> - <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle box-shadow" :src="profile.avatar" width="150px" height="150px"> + <div v-if="hasStory" class="has-story-lg cursor-pointer shadow-sm" @click="storyRedirect()"> + <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle box-shadow" :src="profile.avatar" width="150px" height="150px"> + </div> + <div v-else> + <img :alt="profileUsername + '\'s profile picture'" class="rounded-circle box-shadow" :src="profile.avatar" width="150px" height="150px"> + </div> <p v-if="sponsorList.patreon || sponsorList.liberapay || sponsorList.opencollective" class="text-center mt-3"> <button type="button" @click="showSponsorModal" class="btn btn-outline-secondary font-weight-bold py-0"> <i class="fas fa-heart text-danger"></i> @@ -523,6 +533,20 @@ .nav-topbar .nav-link .small { font-weight: 600; } + .has-story { + width: 83px; + height: 83px; + border-radius: 50%; + padding: 3px; + background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%); + } + .has-story-lg { + width: 156px; + height: 156px; + border-radius: 50%; + padding: 3px; + background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%); + } </style> <script type="text/javascript"> import VueMasonry from 'vue-masonry-css' @@ -565,7 +589,8 @@ collectionsPage: 2, isMobile: false, ctxEmbedPayload: null, - copiedEmbed: false + copiedEmbed: false, + hasStory: null } }, beforeMount() { @@ -620,6 +645,10 @@ this.profile = res.data; }).then(res => { this.fetchPosts(); + axios.get('/api/stories/v1/exists/' + this.profileId) + .then(res => { + this.hasStory = res.data == true; + }) }); }, @@ -1133,6 +1162,10 @@ this.$refs.embedModal.hide(); this.$refs.visitorContextMenu.hide(); }, + + storyRedirect() { + window.location.href = '/stories/' + this.profileUsername; + } } } </script> diff --git a/resources/assets/js/components/StoryViewer.vue b/resources/assets/js/components/StoryViewer.vue new file mode 100644 index 000000000..25bb67390 --- /dev/null +++ b/resources/assets/js/components/StoryViewer.vue @@ -0,0 +1,106 @@ +<template> +<div class="container"> + <div v-if="loading" class="row"> + <div class="col-12 mt-5 pt-5"> + <div class="text-center"> + <div class="spinner-border" role="status"> + <span class="sr-only">Loading...</span> + </div> + </div> + </div> + </div> + <div v-if="stories.length != 0"> + <div id="storyContainer" class="d-none m-3"></div> + </div> +</div> +</template> + +<style type="text/css" scoped> + #storyContainer > .story { + margin-right: 3rem; + } +</style> + +<script type="text/javascript"> + import 'zuck.js/dist/zuck.css'; + import 'zuck.js/dist/skins/snapgram.css'; + window.Zuck = require('zuck.js'); + + export default { + props: ['pid'], + + data() { + return { + loading: true, + stories: {}, + } + }, + + beforeMount() { + this.fetchStories(); + }, + + methods: { + fetchStories() { + axios.get('/api/stories/v1/profile/' + this.pid) + .then(res => { + let data = res.data; + if(data.length == 0) { + window.location.href = '/'; + return; + } + window._storyData = data; + window.stories = new Zuck('storyContainer', { + stories: data, + localStorage: true, + callbacks: { + onOpen (storyId, callback) { + document.body.style.overflow = "hidden"; + callback() + }, + + onEnd (storyId, callback) { + axios.post('/i/stories/viewed', { + id: storyId + }); + callback(); + }, + + onClose (storyId, callback) { + document.body.style.overflow = "auto"; + callback(); + window.location.href = '/'; + }, + } + }); + this.loading = false; + document.querySelectorAll('#storyContainer .story')[0].click() + }) + .catch(err => { + window.location.href = '/'; + return; + }); + } + } + } +</script> + +<style type="text/css"> + #storyContainer .story { + margin-right: 2rem; + width: 100%; + max-width: 64px; + } + .stories.carousel .story > .item-link > .item-preview { + height: 64px; + } + #zuck-modal.with-effects { + width: 100%; + } + .stories.carousel .story > .item-link > .info .name { + font-weight: 600; + font-size: 12px; + } + .stories.carousel .story > .item-link > .info { + } +</style> \ No newline at end of file