浏览代码

Update components

Daniel Supernault 3 年之前
父节点
当前提交
942fdf5486

+ 27 - 1
resources/assets/js/app.js

@@ -103,6 +103,32 @@ window.App.util = {
 			}
 			}
 			return Math.floor(seconds) + "s";
 			return Math.floor(seconds) + "s";
 		}),
 		}),
+		timeAhead: (function(ts) {
+			let date = Date.parse(ts);
+			let diff = date - Date.parse(new Date());
+			let seconds = Math.floor((diff) / 1000);
+			let interval = Math.floor(seconds / 63072000);
+			if (interval >= 1) {
+				return interval + "y";
+			}
+			interval = Math.floor(seconds / 604800);
+			if (interval >= 1) {
+				return interval + "w";
+			}
+			interval = Math.floor(seconds / 86400);
+			if (interval >= 1) {
+				return interval + "d";
+			}
+			interval = Math.floor(seconds / 3600);
+			if (interval >= 1) {
+				return interval + "h";
+			}
+			interval = Math.floor(seconds / 60);
+			if (interval >= 1) {
+				return interval + "m";
+			}
+			return Math.floor(seconds) + "s";
+		}),
 		rewriteLinks: (function(i) {
 		rewriteLinks: (function(i) {
 
 
 			let tag = i.innerText;
 			let tag = i.innerText;
@@ -233,7 +259,7 @@ window.App.util = {
 			$('#navbarDropdown img').attr('src',window._sharedData.curUser.avatar)
 			$('#navbarDropdown img').attr('src',window._sharedData.curUser.avatar)
 			.removeClass('d-none')
 			.removeClass('d-none')
 			.addClass('rounded-circle border shadow')
 			.addClass('rounded-circle border shadow')
-			.attr('width', 34).attr('height', 34);
+			.attr('width', 38).attr('height', 38);
 	})
 	})
 
 
 };
 };

+ 15 - 0
resources/assets/js/components/Activity.vue

@@ -27,6 +27,21 @@
 									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" data-placement="bottom" data-toggle="tooltip" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="getPostUrl(n.status)">post</a>.
 									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" data-placement="bottom" data-toggle="tooltip" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="getPostUrl(n.status)">post</a>.
 								</p>
 								</p>
 							</div>
 							</div>
+							<div v-else-if="n.type == 'group:comment'">
+								<p class="my-0">
+									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="n.group_post_url">group post</a>.
+								</p>
+							</div>
+							<div v-else-if="n.type == 'story:react'">
+								<p class="my-0">
+									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> reacted to your <a class="font-weight-bold" v-bind:href="'/account/direct/t/'+n.account.id">story</a>.
+								</p>
+							</div>
+							<div v-else-if="n.type == 'story:comment'">
+								<p class="my-0">
+									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="'/account/direct/t/'+n.account.id">story</a>.
+								</p>
+							</div>
 							<div v-else-if="n.type == 'mention'">
 							<div v-else-if="n.type == 'mention'">
 								<p class="my-0">
 								<p class="my-0">
 									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" data-placement="bottom" data-toggle="tooltip" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> <a class="font-weight-bold" v-bind:href="mentionUrl(n.status)">mentioned</a> you.
 									<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" data-placement="bottom" data-toggle="tooltip" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> <a class="font-weight-bold" v-bind:href="mentionUrl(n.status)">mentioned</a> you.

+ 8 - 9
resources/assets/js/components/ComposeModal.vue

@@ -68,7 +68,7 @@
 				<div class="h-100 card-body p-0 border-top" style="width:100%; min-height: 400px;">
 				<div class="h-100 card-body p-0 border-top" style="width:100%; min-height: 400px;">
 					<div class="border-bottom mt-2">
 					<div class="border-bottom mt-2">
 						<div class="media px-3">
 						<div class="media px-3">
-							<img src="/storage/avatars/default.png" width="42px" height="42px" class="rounded-circle">
+							<img :src="profile.avatar" width="42px" height="42px" class="rounded-circle">
 							<div class="media-body">
 							<div class="media-body">
 								<div class="form-group">
 								<div class="form-group">
 									<label class="font-weight-bold text-muted small d-none">Caption</label>
 									<label class="font-weight-bold text-muted small d-none">Caption</label>
@@ -241,7 +241,7 @@
 								<div @click.prevent="addMedia" class="card-body py-2">
 								<div @click.prevent="addMedia" class="card-body py-2">
 									<div class="media">
 									<div class="media">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5">
-											<i class="fas fa-bolt text-white fa-lg"></i>
+											<i class="fal fa-bolt text-white fa-lg"></i>
 										</div>
 										</div>
 										<div class="media-body text-left">
 										<div class="media-body text-left">
 											<p class="mb-0">
 											<p class="mb-0">
@@ -253,7 +253,7 @@
 								</div>
 								</div>
 							</div>
 							</div>
 
 
-							<div v-if="config.ab.top == true && media.length == 0" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark">
+							<div v-if="1==0 && config.ab.top == true && media.length == 0" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark">
 								<div @click.prevent="addText" class="card-body py-2">
 								<div @click.prevent="addText" class="card-body py-2">
 									<div class="media">
 									<div class="media">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
@@ -275,7 +275,7 @@
 							<a v-if="config.features.stories == true" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/stories/new">
 							<a v-if="config.features.stories == true" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/stories/new">
 								<div class="card-body py-2">
 								<div class="card-body py-2">
 									<div class="media">
 									<div class="media">
-										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
+										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 1px solid #008DF5">
 											<i class="fas fa-history text-primary fa-lg"></i>
 											<i class="fas fa-history text-primary fa-lg"></i>
 										</div>
 										</div>
 										<div class="media-body text-left">
 										<div class="media-body text-left">
@@ -285,13 +285,13 @@
 													<span class="btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style="font-size:10px;line-height: 0.6">BETA</span>
 													<span class="btn btn-outline-lighter p-1 btn-sm font-weight-bold py-0" style="font-size:10px;line-height: 0.6">BETA</span>
 												</sup>
 												</sup>
 											</p>
 											</p>
-											<p class="mb-0 text-muted">Add Photo to Story</p>
+											<p class="mb-0 text-muted">Add to your story</p>
 										</div>
 										</div>
 									</div>
 									</div>
 								</div>
 								</div>
 							</a>
 							</a>
 
 
-							<a v-if="config.ab.polls == true" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="#" @click.prevent="newPoll">
+							<a v-if="1==0 && config.ab.polls == true" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="#" @click.prevent="newPoll">
 								<div class="card-body py-2">
 								<div class="card-body py-2">
 									<div class="media">
 									<div class="media">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
 										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
@@ -313,8 +313,8 @@
 							<a class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/collections/create">
 							<a class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/collections/create">
 								<div class="card-body py-2">
 								<div class="card-body py-2">
 									<div class="media">
 									<div class="media">
-										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 2px solid #008DF5">
-											<i class="fas fa-images text-primary fa-lg"></i>
+										<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;border: 1px solid #008DF5">
+											<i class="fal fa-images text-primary fa-lg"></i>
 										</div>
 										</div>
 										<div class="media-body text-left">
 										<div class="media-body text-left">
 											<p class="mb-0">
 											<p class="mb-0">
@@ -329,7 +329,6 @@
 								</div>
 								</div>
 							</a>
 							</a>
 
 
-
 							<p class="py-3">
 							<p class="py-3">
 								<a class="font-weight-bold" href="/site/help">Help</a>
 								<a class="font-weight-bold" href="/site/help">Help</a>
 							</p>
 							</p>

+ 93 - 57
resources/assets/js/components/DirectMessage.vue

@@ -80,14 +80,32 @@
 								<p v-else-if="convo.type == 'emoji'" class="p-0 emoji-msg">
 								<p v-else-if="convo.type == 'emoji'" class="p-0 emoji-msg">
 									{{convo.text}}
 									{{convo.text}}
 								</p>
 								</p>
+								<p v-else-if="convo.type == 'story:react'" class="pill-to p-0 shadow" style="width: 140px;margin-bottom: 10px;position:relative;">
+									<img :src="convo.meta.story_media_url" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
+									<span class="badge badge-light rounded-pill border" style="font-size: 20px;position: absolute;bottom:-10px;left:-10px;">
+										{{convo.meta.reaction}}
+									</span>
+								</p>
+								<span v-else-if="convo.type == 'story:comment'" class="p-0" style="display: flex;justify-content: flex-start;margin-bottom: 10px;position:relative;">
+									<span class="">
+										<img class="d-block pill-to p-0 mr-0 pr-0 mb-n1" :src="convo.meta.story_media_url" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
+										<span class="pill-to shadow text-break" style="width:fit-content;">{{convo.meta.caption}}</span>
+									</span>
+								</span>
 								<p v-else :class="[largerText ? 'pill-to shadow larger-text text-break':'pill-to shadow text-break']">
 								<p v-else :class="[largerText ? 'pill-to shadow larger-text text-break':'pill-to shadow text-break']">
 									{{convo.text}}
 									{{convo.text}}
 								</p>
 								</p>
-								<p v-if="!hideTimestamps" class="small text-muted font-weight-bold ml-2 d-flex align-items-center justify-content-start" data-timestamp="timestamp"> <span v-if="convo.hidden" class="mr-2 small" title="Filtered Message" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-lock"></i></span> {{convo.timeAgo}}</p>
+								<p v-if="convo.type == 'story:react'" class="small text-muted mb-0 ml-0">
+									<span class="font-weight-bold">{{ convo.meta.story_actor_username }}</span> reacted your story
+								</p>
+								<p v-if="convo.type == 'story:comment'" class="small text-muted mb-0 ml-0">
+									<span class="font-weight-bold">{{ convo.meta.story_actor_username }}</span> replied to your story
+								</p>
+								<p v-if="!hideTimestamps" class="small text-muted font-weight-bold d-flex align-items-center justify-content-start" data-timestamp="timestamp"> <span v-if="convo.hidden" class="mr-2 small" title="Filtered Message" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-lock"></i></span> {{convo.timeAgo}}</p>
 								<p v-else>&nbsp;</p>
 								<p v-else>&nbsp;</p>
 							</div>
 							</div>
 						</div>
 						</div>
-						<div v-else class="media d-inline-flex float-right mb-0">
+						<div v-else class="media d-inline-flex float-right mb-0 mr-2">
 							<div class="media-body">
 							<div class="media-body">
 								<p v-if="convo.type == 'photo'" class="pill-from p-0 shadow">
 								<p v-if="convo.type == 'photo'" class="pill-from p-0 shadow">
 									<img :src="convo.media" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
 									<img :src="convo.media" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
@@ -127,10 +145,28 @@
 								<p v-else-if="convo.type == 'emoji'" class="p-0 emoji-msg">
 								<p v-else-if="convo.type == 'emoji'" class="p-0 emoji-msg">
 									{{convo.text}}
 									{{convo.text}}
 								</p>
 								</p>
+								<p v-else-if="convo.type == 'story:react'" class="pill-from p-0 shadow" style="margin-bottom: 10px;position:relative;width:fit-content;">
+									<img :src="convo.meta.story_media_url" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
+									<span class="badge badge-light rounded-pill border" style="font-size: 20px;position: absolute;bottom:-10px;right:-10px;">
+										{{convo.meta.reaction}}
+									</span>
+								</p>
+								<span v-else-if="convo.type == 'story:comment'" class="p-0" style="display: flex;justify-content: flex-end;margin-bottom: 10px;position:relative;">
+									<span class="d-flex align-items-end flex-column">
+										<img class="d-block pill-from p-0 mr-0 pr-0 mb-n1" :src="convo.meta.story_media_url" width="140" style="border-radius:20px;" onerror="this.onerror=null;this.src='/storage/no-preview.png';">
+										<span class="pill-from shadow text-break" style="width:fit-content;">{{convo.meta.caption}}</span>
+									</span>
+								</span>
 								<p v-else :class="[largerText ? 'pill-from shadow larger-text text-break':'pill-from shadow text-break']">
 								<p v-else :class="[largerText ? 'pill-from shadow larger-text text-break':'pill-from shadow text-break']">
 									{{convo.text}}
 									{{convo.text}}
 								</p>
 								</p>
-								<p v-if="!hideTimestamps" class="small text-muted font-weight-bold text-right mr-2"> <span v-if="convo.hidden" class="mr-2 small" title="Filtered Message" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-lock"></i></span> {{convo.timeAgo}}
+								<p v-if="convo.type == 'story:react'" class="small text-muted text-right mb-0 mr-0">
+									You reacted to <span class="font-weight-bold">{{ convo.meta.story_username }}</span>'s story
+								</p>
+								<p v-if="convo.type == 'story:comment'" class="small text-muted text-right mb-0 mr-0">
+									You replied to <span class="font-weight-bold">{{ convo.meta.story_username }}</span>'s story
+								</p>
+								<p v-if="!hideTimestamps" class="small text-muted font-weight-bold text-right"> <span v-if="convo.hidden" class="mr-2 small" title="Filtered Message" data-toggle="tooltip" data-placement="bottom"><i class="fas fa-lock"></i></span> {{convo.timeAgo}}
 								</p>
 								</p>
 								<p v-else>&nbsp;</p>
 								<p v-else>&nbsp;</p>
 							</div>
 							</div>
@@ -262,60 +298,60 @@
 </template>
 </template>
 
 
 <style type="text/css" scoped>
 <style type="text/css" scoped>
-.reply-btn {
-	position: absolute;
-	bottom: 54px;
-	right: 20px;
-	width: 90px;
-	text-align: center;
-	border-radius: 0 3px 3px 0;
-}
-.media-body .bg-primary {
-	background: linear-gradient(135deg, #2EA2F4 0%, #0B93F6 100%) !important;
-}
-.pill-to {
-	background:#EDF2F7;
-	font-weight: 500;
-	border-radius: 20px !important;
-	padding-left: 1rem;
-	padding-right: 1rem;
-	padding-top: 0.5rem;
-	padding-bottom: 0.5rem;
-	margin-right: 3rem;
-	margin-bottom: 0.25rem;
-}
-.pill-from {
-	color: white !important;
-	text-align: right !important;
-	/*background: #53d769;*/
-	background: linear-gradient(135deg, #2EA2F4 0%, #0B93F6 100%) !important;
-	font-weight: 500;
-	border-radius: 20px !important;
-	padding-left: 1rem;
-	padding-right: 1rem;
-	padding-top: 0.5rem;
-	padding-bottom: 0.5rem;
-	margin-left: 3rem;
-	margin-bottom: 0.25rem;
-}
-.chat-msg:hover {
-	background: #f7fbfd;
-}
-.no-focus:focus {
-	outline: none !important;
-	outline-width: 0 !important;
-	box-shadow: none;
-	-moz-box-shadow: none;
-	-webkit-box-shadow: none;
-}
-.emoji-msg {
-	font-size: 4rem !important;
-	line-height: 30px !important;
-	margin-top: 10px !important;
-}
-.larger-text {
-	font-size: 22px;
-}
+	.reply-btn {
+		position: absolute;
+		bottom: 54px;
+		right: 20px;
+		width: 90px;
+		text-align: center;
+		border-radius: 0 3px 3px 0;
+	}
+	.media-body .bg-primary {
+		background: linear-gradient(135deg, #2EA2F4 0%, #0B93F6 100%) !important;
+	}
+	.pill-to {
+		background:#EDF2F7;
+		font-weight: 500;
+		border-radius: 20px !important;
+		padding-left: 1rem;
+		padding-right: 1rem;
+		padding-top: 0.5rem;
+		padding-bottom: 0.5rem;
+		margin-right: 3rem;
+		margin-bottom: 0.25rem;
+	}
+	.pill-from {
+		color: white !important;
+		text-align: right !important;
+		/*background: #53d769;*/
+		background: linear-gradient(135deg, #2EA2F4 0%, #0B93F6 100%) !important;
+		font-weight: 500;
+		border-radius: 20px !important;
+		padding-left: 1rem;
+		padding-right: 1rem;
+		padding-top: 0.5rem;
+		padding-bottom: 0.5rem;
+		margin-left: 3rem;
+		margin-bottom: 0.25rem;
+	}
+	.chat-msg:hover {
+		background: #f7fbfd;
+	}
+	.no-focus:focus {
+		outline: none !important;
+		outline-width: 0 !important;
+		box-shadow: none;
+		-moz-box-shadow: none;
+		-webkit-box-shadow: none;
+	}
+	.emoji-msg {
+		font-size: 4rem !important;
+		line-height: 30px !important;
+		margin-top: 10px !important;
+	}
+	.larger-text {
+		font-size: 22px;
+	}
 </style>
 </style>
 
 
 <script type="text/javascript">
 <script type="text/javascript">

+ 15 - 0
resources/assets/js/components/NotificationCard.vue

@@ -37,6 +37,21 @@
 								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="getPostUrl(n.status)">post</a>.
 								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="getPostUrl(n.status)">post</a>.
 							</p>
 							</p>
 						</div>
 						</div>
+						<div v-else-if="n.type == 'group:comment'">
+							<p class="my-0">
+								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="n.group_post_url">group post</a>.
+							</p>
+						</div>
+						<div v-else-if="n.type == 'story:react'">
+							<p class="my-0">
+								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> reacted to your <a class="font-weight-bold" v-bind:href="'/account/direct/t/'+n.account.id">story</a>.
+							</p>
+						</div>
+						<div v-else-if="n.type == 'story:comment'">
+							<p class="my-0">
+								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> commented on your <a class="font-weight-bold" v-bind:href="'/account/direct/t/'+n.account.id">story</a>.
+							</p>
+						</div>
 						<div v-else-if="n.type == 'mention'">
 						<div v-else-if="n.type == 'mention'">
 							<p class="my-0">
 							<p class="my-0">
 								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> <a class="font-weight-bold" v-bind:href="mentionUrl(n.status)">mentioned</a> you.
 								<a :href="getProfileUrl(n.account)" class="font-weight-bold text-dark word-break" :title="n.account.username">{{n.account.local == false ? '@':''}}{{truncate(n.account.username)}}</a> <a class="font-weight-bold" v-bind:href="mentionUrl(n.status)">mentioned</a> you.

+ 1 - 14
resources/assets/js/components/PostComponent.vue

@@ -981,20 +981,7 @@ export default {
 			}
 			}
 		},
 		},
 		beforeMount() {
 		beforeMount() {
-			let u = new URLSearchParams(window.location.search);
-			let forceMetro = localStorage.getItem('pf_metro_ui.exp.forceMetro') == 'true';
-			if(this.statusTemplate == 'text') {
-				this.layout = 'metro';
-				return;
-			}
-
-			if(u.has('ui') && u.get('ui') == 'moment' && this.layout != 'moment') {
-				this.layout = 'moment';
-			}
-
-			if(forceMetro == true || u.has('ui') && u.get('ui') == 'metro' && this.layout != 'metro') {
-				this.layout = 'metro';
-			}
+			this.layout = 'metro';
 		},
 		},
 
 
 		mounted() {
 		mounted() {

+ 9 - 10
resources/assets/js/components/Profile.vue

@@ -715,7 +715,7 @@
 				max_id: 0,
 				max_id: 0,
 				loading: true,
 				loading: true,
 				owner: false,
 				owner: false,
-				layout: this.profileLayout,
+				layout: 'metro',
 				mode: 'grid',
 				mode: 'grid',
 				modes: ['grid', 'collections', 'bookmarks', 'archives'],
 				modes: ['grid', 'collections', 'bookmarks', 'archives'],
 				modalStatus: false,
 				modalStatus: false,
@@ -748,7 +748,6 @@
 			}
 			}
 		},
 		},
 		beforeMount() {
 		beforeMount() {
-			this.fetchRelationships();
 			this.fetchProfile();
 			this.fetchProfile();
 			let u = new URLSearchParams(window.location.search);
 			let u = new URLSearchParams(window.location.search);
 			let forceMetro = localStorage.getItem('pf_metro_ui.exp.forceMetro') == 'true';
 			let forceMetro = localStorage.getItem('pf_metro_ui.exp.forceMetro') == 'true';
@@ -818,12 +817,7 @@
 					this.user = res.data;
 					this.user = res.data;
 					window._sharedData.curUser = res.data;
 					window._sharedData.curUser = res.data;
 					window.App.util.navatar();
 					window.App.util.navatar();
-					if(res.data.id == this.profileId || this.relationship.following == true) {
-						axios.get('/api/stories/v0/exists/' + this.profileId)
-						.then(res => {
-							this.hasStory = res.data == true;
-						})
-					}
+					this.fetchRelationships();
 				});
 				});
 			}
 			}
 		},
 		},
@@ -838,7 +832,6 @@
 					this.profile = res.data;
 					this.profile = res.data;
 				}).then(res => {
 				}).then(res => {
 					this.fetchPosts();
 					this.fetchPosts();
-
 				});
 				});
 			},
 			},
 
 
@@ -1063,6 +1056,12 @@
 							this.warning = true;
 							this.warning = true;
 						}
 						}
 					}
 					}
+					if(this.user.id == this.profileId || this.relationship.following == true) {
+						axios.get('/api/web/stories/v1/exists/' + this.profileId)
+						.then(res => {
+							this.hasStory = (res.data == true);
+						})
+					}
 				});
 				});
 			},
 			},
 
 
@@ -1380,7 +1379,7 @@
 			},
 			},
 
 
 			storyRedirect() {
 			storyRedirect() {
-				window.location.href = '/stories/' + this.profileUsername;
+				window.location.href = '/stories/' + this.profileUsername + '?t=4';
 			},
 			},
 
 
 			followingModalSearchHandler() {
 			followingModalSearchHandler() {

+ 93 - 63
resources/assets/js/components/StoryTimelineComponent.vue

@@ -1,27 +1,46 @@
 <template>
 <template>
 	<div>
 	<div>
 		<div v-if="show" class="card card-body p-0 border mt-md-4 mb-md-3 shadow-none">
 		<div v-if="show" class="card card-body p-0 border mt-md-4 mb-md-3 shadow-none">
-			<div id="storyContainer" :class="[list == true ? 'mt-1 mr-3 mb-0 ml-1':'mx-3 mt-3 mb-0 pb-0']"></div>
+			<div v-if="loading" class="w-100 h-100 d-flex align-items-center justify-content-center">
+				<div class="spinner-border spinner-border-sm text-lighter" role="status">
+					<span class="sr-only">Loading...</span>
+				</div>
+			</div>
+			<div v-else class="d-flex align-items-center justify-content-start scrolly">
+				<div
+					v-for="(story, index) in stories"
+					class="px-3 pt-3 text-center cursor-pointer"
+					:class="{ seen: story.seen }"
+					@click="showStory(index)">
+					<span
+						:class="[
+							story.seen ? 'not-seen' : '',
+							story.local ? '' : 'remote'
+						]"
+						class="mb-1 ring">
+						<img :src="story.avatar" width="60" height="60" class="rounded-circle border" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=2'">
+					</span>
+					<p
+						class="small font-weight-bold text-truncate"
+						:class="{ 'text-lighter': story.seen }"
+						style="max-width: 69px"
+						:title="story.username"
+						>
+						{{story.username}}
+					</p>
+				</div>
+			</div>
 		</div>
 		</div>
 	</div>
 	</div>
 </template>
 </template>
 
 
-<style type="text/css" scoped>
-	#storyContainer > .story {
-		margin-right: 3rem;
-	}
-</style>
-
 <script type="text/javascript">
 <script type="text/javascript">
-	import 'zuck.js/dist/zuck.css';
-	import 'zuck.js/dist/skins/snapgram.css';
-	let Zuck = require('zuck.js');
-
 	export default {
 	export default {
-		props: ['list'],
+		props: ['list', 'scope'],
 		data() {
 		data() {
 			return {
 			return {
-				show: false,
+				loading: true,
+				show: true,
 				stories: {},
 				stories: {},
 			}
 			}
 		},
 		},
@@ -32,71 +51,82 @@
 
 
 		methods: {
 		methods: {
 			fetchStories() {
 			fetchStories() {
-				axios.get('/api/stories/v0/recent')
+				axios.get('/api/web/stories/v1/recent')
 				.then(res => {
 				.then(res => {
 					let data = res.data;
 					let data = res.data;
 					if(!res.data.length) {
 					if(!res.data.length) {
 						this.show = false;
 						this.show = false;
 						return;
 						return;
 					}
 					}
-					let stories = new Zuck('storyContainer', {
-						list: this.list == true ? true : false,
-						stories: data,
-						localStorage: true,
-						callbacks:  {
-							onOpen (storyId, callback) {
-								document.body.style.overflow = "hidden";
-								callback()
-							},
+					this.stories = res.data;
+					this.loading = false;
+				}).catch(err => {
+					this.loading = false;
+					this.$bvToast.toast('Cannot load stories. Please try again later.', {
+						title: 'Error',
+						variant: 'danger',
+						autoHideDelay: 5000
+					});
+					this.show = false;
+				});
+			},
 
 
-							onEnd (storyId, callback) {
-								axios.post('/i/stories/viewed', {
-									id: storyId
-								});
-								callback();
-							},
+			showStory(index) {
+				let suffix;
 
 
-							onClose (storyId, callback) {
-								document.body.style.overflow = "auto";
-								callback();
-							},
-						}
-					});
+				switch(this.scope) {
+					case 'home':
+						suffix = '/?t=1';
+					break;
+					case 'local':
+						suffix = '/?t=2';
+					break;
+					case 'network':
+						suffix = '/?t=3';
+					break;
 
 
-					data.forEach(d => {
-						let url = '/api/stories/v0/fetch/' + d.pid;
-						axios.get(url)
-						.then(res => {
-							res.data.forEach(item => {
-								let img = new Image();
-								img.src = item.src;
-								stories.addItem(d.id, item);
-							});
-						});
-					});
-				});
-				this.show = true;
+				}
+				window.location.href = this.stories[index].url + suffix;
 			}
 			}
 		}
 		}
 	}
 	}
 </script>
 </script>
 
 
-<style type="text/css">
-	#storyContainer .story {
-		margin-right: 2rem;
-		width: 100%;
-		max-width: 60px;
-	}
-	.stories.carousel .story > .item-link > .item-preview {
-		height: 60px;
-	}
-	#zuck-modal.with-effects {
-		width: 100%;
+<style lang="scss" scoped>
+	.card {
+		height: 122px;
 	}
 	}
-	.stories.carousel .story > .item-link > .info .name {
-		font-weight: 500;
-		font-size: 11px;
+
+	.ring {
+		display: block;
+		width: 66px;
+		height: 66px;
+		border-radius: 50%;
+		padding: 3px;
+		background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%);
+
+		&.remote {
+			background: radial-gradient(ellipse at 70% 70%, #f64f59 8%, #c471ed 42%, #12c2e9 58%);
+		}
+
+		&.not-seen {
+			opacity: 0.55;
+			background: #ccc;
+		}
+
+		img {
+			background: #fff;
+			padding: 3px;
+		}
 	}
 	}
-	.stories.carousel .story > .item-link > .info {
+
+	.scrolly {
+		-ms-overflow-style: none;
+		scrollbar-width: none;
+		overflow-y: scroll;
+
+		&::-webkit-scrollbar {
+			display: none;
+		}
 	}
 	}
 </style>
 </style>

+ 3 - 2
resources/assets/js/components/Timeline.vue

@@ -10,7 +10,7 @@
 
 
 				<div class="col-md-8 col-lg-8 px-0 mb-sm-3 timeline order-2 order-md-1">
 				<div class="col-md-8 col-lg-8 px-0 mb-sm-3 timeline order-2 order-md-1">
 					<div style="margin-top:-2px;">
 					<div style="margin-top:-2px;">
-						<story-component v-if="config.features.stories"></story-component>
+						<story-component v-if="config.features.stories" :scope="scope"></story-component>
 					</div>
 					</div>
 					<div>
 					<div>
 						<div v-if="loading" class="text-center" style="padding-top:10px;">
 						<div v-if="loading" class="text-center" style="padding-top:10px;">
@@ -103,6 +103,7 @@
 								:class="{ 'border-top': index === 0 }"
 								:class="{ 'border-top': index === 0 }"
 								:status="status"
 								:status="status"
 								:reaction-bar="reactionBar"
 								:reaction-bar="reactionBar"
+								size="small"
 								v-on:status-delete="deleteStatus"
 								v-on:status-delete="deleteStatus"
 								v-on:comment-focus="commentFocus"
 								v-on:comment-focus="commentFocus"
 							/>
 							/>
@@ -942,7 +943,7 @@
 			},
 			},
 
 
 			hasStory() {
 			hasStory() {
-				axios.get('/api/stories/v0/exists/'+this.profile.id)
+				axios.get('/api/web/stories/v1/exists/'+this.profile.id)
 				.then(res => {
 				.then(res => {
 					this.userStory = res.data;
 					this.userStory = res.data;
 				})
 				})

+ 2 - 2
resources/assets/js/components/partials/StatusCard.vue

@@ -125,8 +125,8 @@
 			<div class="card-body">
 			<div class="card-body">
 				<div v-if="reactionBar" class="reactions my-1 pb-2">
 				<div v-if="reactionBar" class="reactions my-1 pb-2">
 					<h3 v-if="status.favourited" class="fas fa-heart text-danger pr-3 m-0 cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
 					<h3 v-if="status.favourited" class="fas fa-heart text-danger pr-3 m-0 cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
-					<h3 v-else class="far fa-heart pr-3 m-0 like-btn text-dark cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
-					<h3 v-if="!status.comments_disabled" class="far fa-comment text-dark pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
+					<h3 v-else class="fal fa-heart pr-3 m-0 like-btn text-dark cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
+					<h3 v-if="!status.comments_disabled" class="fal fa-comment text-dark pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
 					<span v-if="status.taggedPeople.length" class="float-right">
 					<span v-if="status.taggedPeople.length" class="float-right">
 						<span class="font-weight-light small" style="color:#718096">
 						<span class="font-weight-light small" style="color:#718096">
 							<i class="far fa-user" data-toggle="tooltip" title="Tagged People"></i>
 							<i class="far fa-user" data-toggle="tooltip" title="Tagged People"></i>