Selaa lähdekoodia

Refactor Hashtag component from #5427

Daniel Supernault 6 kuukautta sitten
vanhempi
commit
0a73094d82
1 muutettua tiedostoa jossa 319 lisäystä ja 308 poistoa
  1. 319 308
      resources/assets/components/Hashtag.vue

+ 319 - 308
resources/assets/components/Hashtag.vue

@@ -1,325 +1,336 @@
 <template>
-	<div class="hashtag-component">
-		<div class="container-fluid mt-3">
-			<div class="row">
-				<div class="col-md-3 d-md-block">
-					<sidebar :user="profile" />
-				</div>
-				<div class="col-md-9">
-					<div class="card border-0 shadow-sm mb-3" style="border-radius: 18px;">
-						<div class="card-body">
-							<div class="media align-items-center py-3">
-								<div class="media-body">
-									<p class="h3 text-break mb-0">
-										<span class="text-lighter">#</span>{{ hashtag.name }}
-									</p>
-									<p v-if="hashtag.count && hashtag.count > 100" class="mb-0 text-muted font-weight-bold">
-										{{ formatCount(hashtag.count) }} Posts
-									</p>
-								</div>
-								<template v-if="hashtag && hashtag.hasOwnProperty('following') && feed && feed.length">
-									<button
-										v-if="hashtag.following"
-										:disabled="followingLoading"
-										class="btn btn-light hashtag-follow border rounded-pill font-weight-bold py-1 px-4"
-										@click="unfollowHashtag()"
-										>
-										<b-spinner v-if="followingLoading" small />
-										<span v-else>
-											{{ $t('profile.unfollow') }}
-										</span>
-									</button>
-
-									<button
-										v-else
-										:disabled="followingLoading"
-										class="btn btn-primary hashtag-follow font-weight-bold rounded-pill py-1 px-4"
-										@click="followHashtag()"
-										>
-										<b-spinner v-if="followingLoading" small />
-										<span v-else>
-											{{ $t('profile.follow') }}
-										</span>
-									</button>
-								</template>
-							</div>
-
-						</div>
-					</div>
-
-					<template v-if="isLoaded && feedLoaded">
-						<div class="row mx-0 hashtag-feed">
-							<div class="col-6 col-md-4 col-lg-3 p-1" v-for="(status, index) in feed" :key="'tlob:'+index">
-								<a
-									class="card info-overlay card-md-border-0"
-									:href="statusUrl(status)"
-									@click.prevent="goToPost(status)">
-									<div class="square">
-										<div v-if="status.sensitive" class="square-content">
-											<div class="info-overlay-text-label">
-												<h5 class="text-white m-auto font-weight-bold">
-													<span>
-														<span class="far fa-eye-slash fa-lg p-2 d-flex-inline"></span>
-													</span>
-												</h5>
-											</div>
-											<blur-hash-canvas
-												width="32"
-												height="32"
-												:hash="status.media_attachments[0].blurhash"
-												/>
-										</div>
-										<div v-else class="square-content">
-											<blur-hash-image
-												width="32"
-												height="32"
-												:hash="status.media_attachments[0].blurhash"
-												:src="status.media_attachments[0].preview_url"
-												/>
-										</div>
-										<span v-if="status.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x"></i></span>
-										<span v-if="status.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x"></i></span>
-										<span v-if="status.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
-										<div class="info-overlay-text">
-											<h5 class="text-white m-auto font-weight-bold">
-												<span>
-													<span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
-													<span class="d-flex-inline">{{formatCount(status.reply_count)}}</span>
-												</span>
-											</h5>
-										</div>
-									</div>
-								</a>
-							</div>
-
-							<div v-if="canLoadMore" class="col-12">
-								<intersect @enter="enterIntersect">
-									<div class="d-flex justify-content-center py-5">
-										<b-spinner />
-									</div>
-								</intersect>
-
-								<!-- <div v-else class="ph-item">
-									<div class="ph-picture big"></div>
-								</div> -->
-							</div>
-						</div>
-
-						<div v-if="feedLoaded && !feed.length" class="row mx-0 hashtag-feed justify-content-center">
-							<div class="col-12 col-md-8 text-center">
-								<img src="/img/illustrations/dk-nature-man-monochrome.svg" class="img-fluid" style="opacity: 0.6;max-width:400px">
-								<p class="lead text-muted font-weight-bold">{{ $t('hashtags.emptyFeed') }}</p>
-							</div>
-						</div>
-					</template>
-
-					<template v-else>
-						<div class="row justify-content-center align-items-center pt-5 mt-5">
-							<b-spinner />
-						</div>
-					</template>
-				</div>
-			</div>
-			<drawer />
-		</div>
-	</div>
+    <div class="hashtag-component">
+        <div class="container-fluid mt-3">
+            <div class="row">
+                <div class="col-md-3 d-md-block">
+                    <sidebar :user="profile" />
+                </div>
+                <div class="col-md-9">
+                    <div class="card border-0 shadow-sm mb-3" style="border-radius: 18px;">
+                        <div class="card-body">
+                            <div class="media align-items-center py-3">
+                                <div class="media-body">
+                                    <p class="h3 text-break mb-0">
+                                        <span class="text-lighter">#</span>{{ hashtag.name }}
+                                    </p>
+                                    <p v-if="hashtag.count && hashtag.count > 100" class="mb-0 text-muted font-weight-bold">
+                                        {{ formatCount(hashtag.count) }} Posts
+                                    </p>
+                                </div>
+                                <template v-if="hashtag && hashtag.hasOwnProperty('following') && feed && feed.length">
+                                    <button
+                                    v-if="hashtag.following"
+                                    :disabled="followingLoading"
+                                    class="btn btn-light hashtag-follow border rounded-pill font-weight-bold py-1 px-4"
+                                    @click="unfollowHashtag()"
+                                    >
+                                    <b-spinner v-if="followingLoading" small />
+                                    <span v-else>
+                                        {{ $t('profile.unfollow') }}
+                                    </span>
+                                    </button>
+
+                                    <button
+                                        v-else
+                                        :disabled="followingLoading"
+                                        class="btn btn-primary hashtag-follow font-weight-bold rounded-pill py-1 px-4"
+                                        @click="followHashtag()">
+                                        <b-spinner v-if="followingLoading" small />
+                                        <span v-else>
+                                            {{ $t('profile.follow') }}
+                                        </span>
+                                    </button>
+                                </template>
+                            </div>
+                        </div>
+                    </div>
+
+                    <template v-if="isLoaded && feedLoaded">
+                        <div class="row mx-0 hashtag-feed">
+                            <div class="col-6 col-md-4 col-lg-3 p-1" v-for="(status, index) in feed" :key="'tlob:'+index">
+                                <a
+                                class="card info-overlay card-md-border-0"
+                                :href="statusUrl(status)"
+                                @click.prevent="goToPost(status)">
+                                <div class="square">
+                                    <div v-if="status.sensitive" class="square-content">
+                                        <div class="info-overlay-text-label">
+                                            <h5 class="text-white m-auto font-weight-bold">
+                                                <span>
+                                                    <span class="far fa-eye-slash fa-lg p-2 d-flex-inline"></span>
+                                                </span>
+                                            </h5>
+                                        </div>
+                                        <blur-hash-canvas
+                                        width="32"
+                                        height="32"
+                                        :hash="status.media_attachments[0].blurhash"
+                                        />
+                                    </div>
+                                    <div v-else class="square-content">
+                                        <blur-hash-image
+                                        width="32"
+                                        height="32"
+                                        :hash="status.media_attachments[0].blurhash"
+                                        :src="getMediaSource(status)"
+                                        />
+                                    </div>
+                                    <span v-if="status.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x"></i></span>
+                                    <span v-if="status.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x"></i></span>
+                                    <span v-if="status.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
+                                    <div class="info-overlay-text">
+                                        <h5 class="text-white m-auto font-weight-bold">
+                                            <span>
+                                                <span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
+                                                <span class="d-flex-inline">{{formatCount(status.reply_count)}}</span>
+                                            </span>
+                                        </h5>
+                                    </div>
+                                </div>
+                            </a>
+                        </div>
+
+                        <div v-if="canLoadMore" class="col-12">
+                            <intersect @enter="enterIntersect">
+                                <div class="d-flex justify-content-center py-5">
+                                    <b-spinner />
+                                </div>
+                            </intersect>
+
+
+                        </div>
+                        </div>
+
+                        <div v-if="feedLoaded && !feed.length" class="row mx-0 hashtag-feed justify-content-center">
+                            <div class="col-12 col-md-8 text-center">
+                                <img src="/img/illustrations/dk-nature-man-monochrome.svg" class="img-fluid" style="opacity: 0.6;max-width:400px">
+                                <p class="lead text-muted font-weight-bold">{{ $t('hashtags.emptyFeed') }}</p>
+                            </div>
+                        </div>
+                    </template>
+
+                    <template v-else>
+                        <div class="row justify-content-center align-items-center pt-5 mt-5">
+                            <b-spinner />
+                        </div>
+                    </template>
+                </div>
+            </div>
+
+            <drawer />
+        </div>
+    </div>
 </template>
 
 <script type="text/javascript">
-	import Drawer from './partials/drawer.vue';
-	import Intersect from 'vue-intersect'
-	import Sidebar from './partials/sidebar.vue';
-	import Rightbar from './partials/rightbar.vue';
-
-	export default {
-		props: {
-			id: {
-				type: String
-			}
-		},
-
-		components: {
-			"drawer": Drawer,
-			"intersect": Intersect,
+    import Drawer from './partials/drawer.vue';
+    import Intersect from 'vue-intersect'
+    import Sidebar from './partials/sidebar.vue';
+    import Rightbar from './partials/rightbar.vue';
+
+    export default {
+        props: {
+            id: {
+                type: String
+            }
+        },
+
+        components: {
+            "drawer": Drawer,
+            "intersect": Intersect,
             "sidebar": Sidebar,
             "rightbar": Rightbar,
         },
 
         data() {
-        	return {
-        		isLoaded: false,
-        		profile: undefined,
-        		canLoadMore: false,
-        		isIntersecting: false,
-        		feedLoaded: false,
-        		feed: [],
-        		page: 1,
-        		hashtag: {
-        			name: this.id,
-        			count: 0
-        		},
-        		followingLoading: false,
-        		maxId: undefined,
-        	};
+            return {
+                isLoaded: false,
+                profile: undefined,
+                canLoadMore: false,
+                isIntersecting: false,
+                feedLoaded: false,
+                feed: [],
+                page: 1,
+                hashtag: {
+                    name: this.id,
+                    count: 0
+                },
+                followingLoading: false,
+                maxId: undefined,
+            };
+        },
+
+        mounted() {
+            this.init();
         },
 
-		mounted() {
-			this.init();
-		},
-
-		watch: {
-			'$route': 'init'
-		},
-
-		methods: {
-			init() {
-				this.profile = window._sharedData.user;
-				axios.get('/api/v1/tags/' + this.id, {
-					params: {
-						'_pe': 1
-					}
-				})
-				.then(res => {
-					this.hashtag = res.data;
-				})
-				.catch(err => {
-					swal('Error', 'Something went wrong, please try again later!', 'error');
-					this.isLoaded = true;
-					this.feedLoaded = true;
-				})
-				.finally(() => {
-					this.fetchFeed();
-				})
-			},
-
-			fetchFeed() {
-				axios.get('/api/v1/timelines/tag/' + this.id, {
-					params: {
-						limit: 80,
-					}
-				})
-				.then(res => {
-					if(res.data && res.data.length) {
-						this.feed = res.data;
-						this.maxId = res.data[res.data.length - 1].id;
-					    this.canLoadMore = true;
-					} else {
-						this.feedLoaded = true;
-						this.isLoaded = true;
-					}
-				})
-				.finally(() => {
-					this.feedLoaded = true;
-					this.isLoaded = true;
-				})
-			},
-
-			statusUrl(status) {
-				return '/i/web/post/' + status.id;
-			},
-
-			formatCount(val) {
-				return App.util.format.count(val);
-			},
-
-			enterIntersect() {
-				if(this.isIntersecting) {
-					return;
-				}
-
-				this.isIntersecting = true;
-				axios.get('/api/v1/timelines/tag/' + this.id, {
-					params: {
-						max_id: this.maxId,
-						limit: 40,
-					}
-				})
-				.then(res => {
-					if(res.data && res.data.length) {
-						this.feed.push(...res.data);
-						this.maxId = res.data[res.data.length - 1].id;
+        watch: {
+            '$route': 'init'
+        },
+
+        methods: {
+            init() {
+                this.profile = window._sharedData.user;
+                axios.get('/api/v1/tags/' + this.id, {
+                    params: {
+                        '_pe': 1
+                    }
+                })
+                .then(res => {
+                    this.hashtag = res.data;
+                })
+                .catch(err => {
+                    swal('Error', 'Something went wrong, please try again later!', 'error');
+                    this.isLoaded = true;
+                    this.feedLoaded = true;
+                })
+                .finally(() => {
+                    this.fetchFeed();
+                })
+            },
+
+            fetchFeed() {
+                axios.get('/api/v1/timelines/tag/' + this.id, {
+                    params: {
+                        limit: 80,
+                    }
+                })
+                .then(res => {
+                    if(res.data && res.data.length) {
+                        this.feed = res.data;
+                        this.maxId = res.data[res.data.length - 1].id;
                         this.canLoadMore = true;
-					} else {
+                    } else {
+                        this.feedLoaded = true;
+                        this.isLoaded = true;
+                    }
+                })
+                .finally(() => {
+                    this.feedLoaded = true;
+                    this.isLoaded = true;
+                })
+            },
+
+            statusUrl(status) {
+                return '/i/web/post/' + status.id;
+            },
+
+            formatCount(val) {
+                return App.util.format.count(val);
+            },
+
+            enterIntersect() {
+                if(this.isIntersecting) {
+                    return;
+                }
+
+                this.isIntersecting = true;
+                axios.get('/api/v1/timelines/tag/' + this.id, {
+                    params: {
+                        max_id: this.maxId,
+                        limit: 40,
+                    }
+                })
+                .then(res => {
+                    if(res.data && res.data.length) {
+                        this.feed.push(...res.data);
+                        this.maxId = res.data[res.data.length - 1].id;
+                        this.canLoadMore = true;
+                    } else {
                         this.canLoadMore = false;
-					}
-				})
-				.finally(() => {
-					this.isIntersecting = false;
-				})
-			},
-
-			goToPost(status) {
-				this.$router.push({
-					name: 'post',
-					path: `/i/web/post/${status.id}`,
-					params: {
-						id: status.id,
-						cachedStatus: status,
-						cachedProfile: this.profile
-					}
-				})
-			},
-
-			followHashtag() {
-				this.followingLoading = true;
-				axios.post('/api/v1/tags/' + this.id + '/follow')
-				.then(res => {
-					setTimeout(() => {
-						this.hashtag.following = true;
-						this.followingLoading = false;
-					}, 500);
-				});
-			},
-
-			unfollowHashtag() {
-				this.followingLoading = true;
-				axios.post('/api/v1/tags/' + this.id + '/unfollow')
-				.then(res => {
-					setTimeout(() => {
-						this.hashtag.following = false;
-						this.followingLoading = false;
-					}, 500);
-				});
-			},
-		}
-	}
+                    }
+                })
+                .finally(() => {
+                    this.isIntersecting = false;
+                })
+            },
+
+            goToPost(status) {
+                this.$router.push({
+                    name: 'post',
+                    path: `/i/web/post/${status.id}`,
+                    params: {
+                        id: status.id,
+                        cachedStatus: status,
+                        cachedProfile: this.profile
+                    }
+                })
+            },
+
+            followHashtag() {
+                this.followingLoading = true;
+                axios.post('/api/v1/tags/' + this.id + '/follow')
+                .then(res => {
+                    setTimeout(() => {
+                        this.hashtag.following = true;
+                        this.followingLoading = false;
+                    }, 500);
+                });
+            },
+
+            unfollowHashtag() {
+                this.followingLoading = true;
+                axios.post('/api/v1/tags/' + this.id + '/unfollow')
+                .then(res => {
+                    setTimeout(() => {
+                        this.hashtag.following = false;
+                        this.followingLoading = false;
+                    }, 500);
+                });
+            },
+
+            getMediaSource(status) {
+                let media = status.media_attachments[0];
+
+                if(media.preview_url && media.preview_url.endsWith('storage/no-preview.png')) {
+                    return media.url;
+                }
+
+                if(media.preview_url && media.preview_url.length) {
+                    return media.url;
+                }
+
+                return media.url;
+            }
+        }
+    }
 </script>
 
 <style lang="scss">
-	.hashtag-component {
-		.hashtag-feed {
-			.card,
-			.info-overlay-text,
-			.info-overlay-text-label,
-			img,
-			canvas {
-				border-radius: 18px !important;
-			}
-		}
-
-		.hashtag-follow {
-			width: 200px;
-		}
-
-		.ph-wrapper {
-			padding: 0.25rem;
-
-			.ph-item {
-				margin: 0;
-				padding: 0;
-				border: none;
-				background-color: transparent;
-
-				.ph-picture {
-					height: auto;
-					padding-bottom: 100%;
-					border-radius: 18px;
-				}
-
-				& > * {
-					margin-bottom: 0;
-				}
-			}
-		}
-	}
+.hashtag-component {
+    .hashtag-feed {
+        .card,
+        .info-overlay-text,
+        .info-overlay-text-label,
+        img,
+        canvas {
+            border-radius: 18px !important;
+        }
+    }
+
+    .hashtag-follow {
+        width: 200px;
+    }
+
+    .ph-wrapper {
+        padding: 0.25rem;
+
+        .ph-item {
+            margin: 0;
+            padding: 0;
+            border: none;
+            background-color: transparent;
+
+            .ph-picture {
+                height: auto;
+                padding-bottom: 100%;
+                border-radius: 18px;
+            }
+
+            & > * {
+                margin-bottom: 0;
+            }
+        }
+    }
+}
 </style>