kopia lustrzana https://github.com/pixelfed/pixelfed
				
				
				
			
						commit
						4fab7d6968
					
				|  | @ -56,6 +56,7 @@ | |||
| - Update ApiV1Controller, return empty statuses feed for private accounts instead of 403 response ([cce657d9c](https://github.com/pixelfed/pixelfed/commit/cce657d9c)) | ||||
| - Update DM config, allow new users to send DMs by default, with a new env variable to enforce a 72h limit ([717f17cde](https://github.com/pixelfed/pixelfed/commit/717f17cde)) | ||||
| - Update ApiV1Controller, add pagination to conversations endpoint with min/max/since id pagination and link header support ([244e86bad](https://github.com/pixelfed/pixelfed/commit/244e86bad)) | ||||
| - Update Direct message component, fix pagination ([e6ef64857](https://github.com/pixelfed/pixelfed/commit/e6ef64857)) | ||||
| -  ([](https://github.com/pixelfed/pixelfed/commit/)) | ||||
| 
 | ||||
| ## [v0.12.4 (2024-11-08)](https://github.com/pixelfed/pixelfed/compare/v0.12.4...dev) | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -1 +1 @@ | |||
| (()=>{"use strict";var e,r,o,a={},t={};function n(e){var r=t[e];if(void 0!==r)return r.exports;var o=t[e]={id:e,loaded:!1,exports:{}};return a[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}n.m=a,e=[],n.O=(r,o,a,t)=>{if(!o){var d=1/0;for(f=0;f<e.length;f++){for(var[o,a,t]=e[f],s=!0,c=0;c<o.length;c++)(!1&t||d>=t)&&Object.keys(n.O).every((e=>n.O[e](o[c])))?o.splice(c--,1):(s=!1,t<d&&(d=t));if(s){e.splice(f--,1);var i=a();void 0!==i&&(r=i)}}return r}t=t||0;for(var f=e.length;f>0&&e[f-1][2]>t;f--)e[f]=e[f-1];e[f]=[o,a,t]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var o in r)n.o(r,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((r,o)=>(n.f[o](e,r),r)),[])),n.u=e=>"js/"+{529:"groups-page",1179:"daci.chunk",1240:"discover~myhashtags.chunk",1645:"profile~following.bundle",2156:"dms.chunk",2822:"group.create",2966:"discover~hashtag.bundle",3688:"discover~serverfeed.chunk",4951:"home.chunk",6250:"discover~settings.chunk",6438:"groups-page-media",6535:"discover.chunk",6740:"discover~memories.chunk",6791:"groups-page-members",7206:"groups-page-topics",7342:"groups-post",7399:"dms~message.chunk",7413:"error404.bundle",7521:"discover~findfriends.chunk",7744:"notifications.chunk",8087:"profile.chunk",8119:"i18n.bundle",8257:"groups-page-about",8408:"post.chunk",8977:"profile~followers.bundle",9124:"compose.chunk",9231:"groups-profile",9919:"changelog.bundle"}[e]+"."+{529:"4a77f2a4e0024224",1179:"8cf1cb07ac8a9100",1240:"f4257bc65189fde3",1645:"8ebe39a19638db1b",2156:"602ea23f0f63b894",2822:"38102523ebf4cde9",2966:"c8eb86fb63ede45e",3688:"4e135dd1c07c17dd",4951:"3d9801a7722f4dfb",6250:"295935b63f9c0971",6438:"526b66b27a0bd091",6535:"0ca404627af971f2",6740:"9621c5ecf4482f0a",6791:"c59de89c3b8e3a02",7206:"d279a2438ee20311",7342:"e160e406bdb4a1b0",7399:"f0d6ccb6f2f1cbf7",7413:"f5958c1713b4ab7c",7521:"bf787612b58e5473",7744:"bd37ed834e650fd7",8087:"239231da0003f8d9",8119:"85976a3b9d6b922a",8257:"16d96a32748daa93",8408:"c699382772550b42",8977:"9d2008cfa13a6f17",9124:"80e32f21442c8a91",9231:"58b5bf1af4d0722e",9919:"efd3d17aee17020e"}[e]+".js",n.miniCssF=e=>({2305:"css/portfolio",2540:"css/landing",3364:"css/admin",4370:"css/profile",6952:"css/appdark",8252:"css/app",8759:"css/spa"}[e]+".css"),n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},o="pixelfed:",n.l=(e,a,t,d)=>{if(r[e])r[e].push(a);else{var s,c;if(void 0!==t)for(var i=document.getElementsByTagName("script"),f=0;f<i.length;f++){var u=i[f];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==o+t){s=u;break}}s||(c=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,n.nc&&s.setAttribute("nonce",n.nc),s.setAttribute("data-webpack",o+t),s.src=e),r[e]=[a];var l=(o,a)=>{s.onerror=s.onload=null,clearTimeout(p);var t=r[e];if(delete r[e],s.parentNode&&s.parentNode.removeChild(s),t&&t.forEach((e=>e(a))),o)return o(a)},p=setTimeout(l.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=l.bind(null,s.onerror),s.onload=l.bind(null,s.onload),c&&document.head.appendChild(s)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n.p="/",(()=>{var e={461:0,6952:0,8252:0,2305:0,3364:0,2540:0,4370:0,8759:0};n.f.j=(r,o)=>{var a=n.o(e,r)?e[r]:void 0;if(0!==a)if(a)o.push(a[2]);else if(/^((69|82)52|2305|2540|3364|4370|461|8759)$/.test(r))e[r]=0;else{var t=new Promise(((o,t)=>a=e[r]=[o,t]));o.push(a[2]=t);var d=n.p+n.u(r),s=new Error;n.l(d,(o=>{if(n.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var t=o&&("load"===o.type?"missing":o.type),d=o&&o.target&&o.target.src;s.message="Loading chunk "+r+" failed.\n("+t+": "+d+")",s.name="ChunkLoadError",s.type=t,s.request=d,a[1](s)}}),"chunk-"+r,r)}},n.O.j=r=>0===e[r];var r=(r,o)=>{var a,t,[d,s,c]=o,i=0;if(d.some((r=>0!==e[r]))){for(a in s)n.o(s,a)&&(n.m[a]=s[a]);if(c)var f=c(n)}for(r&&r(o);i<d.length;i++)t=d[i],n.o(e,t)&&e[t]&&e[t][0](),e[t]=0;return n.O(f)},o=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];o.forEach(r.bind(null,0)),o.push=r.bind(null,o.push.bind(o))})(),n.nc=void 0})(); | ||||
| (()=>{"use strict";var e,r,o,a={},t={};function n(e){var r=t[e];if(void 0!==r)return r.exports;var o=t[e]={id:e,loaded:!1,exports:{}};return a[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}n.m=a,e=[],n.O=(r,o,a,t)=>{if(!o){var d=1/0;for(f=0;f<e.length;f++){for(var[o,a,t]=e[f],s=!0,c=0;c<o.length;c++)(!1&t||d>=t)&&Object.keys(n.O).every((e=>n.O[e](o[c])))?o.splice(c--,1):(s=!1,t<d&&(d=t));if(s){e.splice(f--,1);var i=a();void 0!==i&&(r=i)}}return r}t=t||0;for(var f=e.length;f>0&&e[f-1][2]>t;f--)e[f]=e[f-1];e[f]=[o,a,t]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var o in r)n.o(r,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:r[o]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((r,o)=>(n.f[o](e,r),r)),[])),n.u=e=>"js/"+{529:"groups-page",1179:"daci.chunk",1240:"discover~myhashtags.chunk",1645:"profile~following.bundle",2156:"dms.chunk",2822:"group.create",2966:"discover~hashtag.bundle",3688:"discover~serverfeed.chunk",4951:"home.chunk",6250:"discover~settings.chunk",6438:"groups-page-media",6535:"discover.chunk",6740:"discover~memories.chunk",6791:"groups-page-members",7206:"groups-page-topics",7342:"groups-post",7399:"dms~message.chunk",7413:"error404.bundle",7521:"discover~findfriends.chunk",7744:"notifications.chunk",8087:"profile.chunk",8119:"i18n.bundle",8257:"groups-page-about",8408:"post.chunk",8977:"profile~followers.bundle",9124:"compose.chunk",9231:"groups-profile",9919:"changelog.bundle"}[e]+"."+{529:"4a77f2a4e0024224",1179:"8cf1cb07ac8a9100",1240:"f4257bc65189fde3",1645:"8ebe39a19638db1b",2156:"13449036a5b769e6",2822:"38102523ebf4cde9",2966:"c8eb86fb63ede45e",3688:"4e135dd1c07c17dd",4951:"3d9801a7722f4dfb",6250:"295935b63f9c0971",6438:"526b66b27a0bd091",6535:"0ca404627af971f2",6740:"9621c5ecf4482f0a",6791:"c59de89c3b8e3a02",7206:"d279a2438ee20311",7342:"e160e406bdb4a1b0",7399:"f0d6ccb6f2f1cbf7",7413:"f5958c1713b4ab7c",7521:"bf787612b58e5473",7744:"bd37ed834e650fd7",8087:"239231da0003f8d9",8119:"85976a3b9d6b922a",8257:"16d96a32748daa93",8408:"c699382772550b42",8977:"9d2008cfa13a6f17",9124:"80e32f21442c8a91",9231:"58b5bf1af4d0722e",9919:"efd3d17aee17020e"}[e]+".js",n.miniCssF=e=>({2305:"css/portfolio",2540:"css/landing",3364:"css/admin",4370:"css/profile",6952:"css/appdark",8252:"css/app",8759:"css/spa"}[e]+".css"),n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},o="pixelfed:",n.l=(e,a,t,d)=>{if(r[e])r[e].push(a);else{var s,c;if(void 0!==t)for(var i=document.getElementsByTagName("script"),f=0;f<i.length;f++){var u=i[f];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==o+t){s=u;break}}s||(c=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,n.nc&&s.setAttribute("nonce",n.nc),s.setAttribute("data-webpack",o+t),s.src=e),r[e]=[a];var l=(o,a)=>{s.onerror=s.onload=null,clearTimeout(p);var t=r[e];if(delete r[e],s.parentNode&&s.parentNode.removeChild(s),t&&t.forEach((e=>e(a))),o)return o(a)},p=setTimeout(l.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=l.bind(null,s.onerror),s.onload=l.bind(null,s.onload),c&&document.head.appendChild(s)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n.p="/",(()=>{var e={461:0,6952:0,8252:0,2305:0,3364:0,2540:0,4370:0,8759:0};n.f.j=(r,o)=>{var a=n.o(e,r)?e[r]:void 0;if(0!==a)if(a)o.push(a[2]);else if(/^((69|82)52|2305|2540|3364|4370|461|8759)$/.test(r))e[r]=0;else{var t=new Promise(((o,t)=>a=e[r]=[o,t]));o.push(a[2]=t);var d=n.p+n.u(r),s=new Error;n.l(d,(o=>{if(n.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var t=o&&("load"===o.type?"missing":o.type),d=o&&o.target&&o.target.src;s.message="Loading chunk "+r+" failed.\n("+t+": "+d+")",s.name="ChunkLoadError",s.type=t,s.request=d,a[1](s)}}),"chunk-"+r,r)}},n.O.j=r=>0===e[r];var r=(r,o)=>{var a,t,[d,s,c]=o,i=0;if(d.some((r=>0!==e[r]))){for(a in s)n.o(s,a)&&(n.m[a]=s[a]);if(c)var f=c(n)}for(r&&r(o);i<d.length;i++)t=d[i],n.o(e,t)&&e[t]&&e[t][0](),e[t]=0;return n.O(f)},o=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];o.forEach(r.bind(null,0)),o.push=r.bind(null,o.push.bind(o))})(),n.nc=void 0})(); | ||||
|  | @ -27,7 +27,7 @@ | |||
|     "/js/groups.js": "/js/groups.js?id=9728981e8c4a6c7bf52c6695aa3e3b2a", | ||||
|     "/js/group-status.js": "/js/group-status.js?id=c5a4b95b4b180f70fa10e01760f8c999", | ||||
|     "/js/group-topic-feed.js": "/js/group-topic-feed.js?id=587c552bb4d1a9f329ac5ed4a5827e61", | ||||
|     "/js/manifest.js": "/js/manifest.js?id=42e3f7346e5d3955ed1af35d23658a0a", | ||||
|     "/js/manifest.js": "/js/manifest.js?id=d57720236163c3aa1414d071dd7e4ff4", | ||||
|     "/js/home.chunk.3d9801a7722f4dfb.js": "/js/home.chunk.3d9801a7722f4dfb.js?id=248276b7039aa622ea3882c13fdbac04", | ||||
|     "/js/compose.chunk.80e32f21442c8a91.js": "/js/compose.chunk.80e32f21442c8a91.js?id=c27c7ab6f212ffbdbf58f532133ef610", | ||||
|     "/js/post.chunk.c699382772550b42.js": "/js/post.chunk.c699382772550b42.js?id=8439251d319cc91821c534baccb06981", | ||||
|  | @ -40,7 +40,7 @@ | |||
|     "/js/discover~settings.chunk.295935b63f9c0971.js": "/js/discover~settings.chunk.295935b63f9c0971.js?id=b74753937401ff97936daed7af0aa47f", | ||||
|     "/js/discover.chunk.0ca404627af971f2.js": "/js/discover.chunk.0ca404627af971f2.js?id=fb662f204f0a3d50ce8e7ee65f5499d1", | ||||
|     "/js/notifications.chunk.bd37ed834e650fd7.js": "/js/notifications.chunk.bd37ed834e650fd7.js?id=ecd148f74f4b559bf7783b4ac2032454", | ||||
|     "/js/dms.chunk.602ea23f0f63b894.js": "/js/dms.chunk.602ea23f0f63b894.js?id=f364b1289215d74c4f13468c156a3ef2", | ||||
|     "/js/dms.chunk.13449036a5b769e6.js": "/js/dms.chunk.13449036a5b769e6.js?id=e78688a49ad274ca3bc4cc7bc54a20c4", | ||||
|     "/js/dms~message.chunk.f0d6ccb6f2f1cbf7.js": "/js/dms~message.chunk.f0d6ccb6f2f1cbf7.js?id=e130002bd287f084ffca6de9dd758e9d", | ||||
|     "/js/profile~followers.bundle.9d2008cfa13a6f17.js": "/js/profile~followers.bundle.9d2008cfa13a6f17.js?id=6e9c0c2c42d55c4c3db48aacda336e69", | ||||
|     "/js/profile~following.bundle.8ebe39a19638db1b.js": "/js/profile~following.bundle.8ebe39a19638db1b.js?id=239a879240723ec8cef74958f10167e9", | ||||
|  |  | |||
|  | @ -1,301 +1,311 @@ | |||
| <template> | ||||
| 	<div class="dms-page-component"> | ||||
| 		<div v-if="isLoaded" class="container-fluid mt-3"> | ||||
| 			<div class="row"> | ||||
| 				<div class="col-md-3 d-md-block"> | ||||
| 					<sidebar :user="profile" /> | ||||
| 				</div> | ||||
|     <div class="dms-page-component"> | ||||
|         <div v-if="isLoaded" class="container-fluid mt-3"> | ||||
|             <div class="row"> | ||||
|                 <div class="col-md-3 d-md-block"> | ||||
|                     <sidebar :user="profile" /> | ||||
|                 </div> | ||||
| 
 | ||||
| 				<div class="col-md-5 offset-md-1 mb-5 order-2 order-md-1"> | ||||
| 					<h1 class="font-weight-bold mb-4">Direct Messages</h1> | ||||
| 					<div v-if="threadsLoaded"> | ||||
| 						<div v-for="(thread, idx) in threads" class="card shadow-sm mb-1" style="border-radius:15px;"> | ||||
| 							<div class="card-body p-3"> | ||||
| 								<div class="media"> | ||||
| 									<img :src="thread.accounts[0].avatar" width="45" height="45" class="shadow-sm mr-3" style="border-radius: 15px;" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';"> | ||||
|                 <div class="col-md-5 offset-md-1 mb-5 order-2 order-md-1"> | ||||
|                     <h1 class="font-weight-bold mb-4">Direct Messages</h1> | ||||
|                     <div v-if="threadsLoaded"> | ||||
|                         <div v-for="(thread, idx) in threads" class="card shadow-sm mb-1" style="border-radius:15px;"> | ||||
|                             <div class="card-body p-3"> | ||||
|                                 <div class="media"> | ||||
|                                     <img :src="thread.accounts[0].avatar" width="45" height="45" class="shadow-sm mr-3" style="border-radius: 15px;" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';"> | ||||
| 
 | ||||
| 									<div class="media-body"> | ||||
| 										<!-- <p class="lead mb-n2">{{ thread.accounts[0].display_name }}</p> --> | ||||
| 										<div class="d-flex justify-content-between align-items-start mb-1"> | ||||
| 											<p class="dm-display-name font-weight-bold mb-0">@{{ thread.accounts[0].acct }}</p> | ||||
| 											<p class="font-weight-bold small text-muted mb-0">{{ timeago(thread.last_status.created_at) }} ago</p> | ||||
| 										</div> | ||||
|                                     <div class="media-body"> | ||||
|                                         <!-- <p class="lead mb-n2">{{ thread.accounts[0].display_name }}</p> --> | ||||
|                                         <div class="d-flex justify-content-between align-items-start mb-1"> | ||||
|                                             <p class="dm-display-name font-weight-bold mb-0">@{{ thread.accounts[0].acct }}</p> | ||||
|                                             <p class="font-weight-bold small text-muted mb-0">{{ timeago(thread.last_status.created_at) }} ago</p> | ||||
|                                         </div> | ||||
| 
 | ||||
| 										<p class="dm-thread-summary text-muted mr-4" v-html="threadSummary(thread.last_status)"></p> | ||||
| 									</div> | ||||
|                                         <p class="dm-thread-summary text-muted mr-4" v-html="threadSummary(thread.last_status)"></p> | ||||
|                                     </div> | ||||
| 
 | ||||
| 									<router-link class="btn btn-link stretched-link align-self-center mr-n3" :to="`/i/web/direct/thread/${thread.accounts[0].id}`"> | ||||
| 										<i class="fal fa-chevron-right fa-lg text-lighter"></i> | ||||
| 									</router-link> | ||||
| 								</div> | ||||
| 							</div> | ||||
| 						</div> | ||||
|                                     <router-link class="btn btn-link stretched-link align-self-center mr-n3" :to="`/i/web/direct/thread/${thread.accounts[0].id}`"> | ||||
|                                         <i class="fal fa-chevron-right fa-lg text-lighter"></i> | ||||
|                                     </router-link> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
| 
 | ||||
| 						<div v-if="!threads || !threads.length" class="row justify-content-center"> | ||||
| 							<div class="col-12 text-center"> | ||||
| 								<img src="/img/illustrations/dk-nature-man-monochrome.svg" class="img-fluid" style="opacity: 0.6;"> | ||||
| 								<p class="lead text-muted font-weight-bold">Your inbox is empty</p> | ||||
| 							</div> | ||||
| 						</div> | ||||
|                         <div v-if="!threads || !threads.length" class="row justify-content-center"> | ||||
|                             <div class="col-12 text-center"> | ||||
|                                 <img src="/img/illustrations/dk-nature-man-monochrome.svg" class="img-fluid" style="opacity: 0.6;"> | ||||
|                                 <p class="lead text-muted font-weight-bold">Your inbox is empty</p> | ||||
|                             </div> | ||||
|                         </div> | ||||
| 
 | ||||
| 						<div v-if="canLoadMore"> | ||||
| 							<intersect @enter="enterIntersect"> | ||||
| 								<dm-placeholder /> | ||||
| 							</intersect> | ||||
| 						</div> | ||||
| 					</div> | ||||
|                         <div v-if="canLoadMore"> | ||||
|                             <intersect @enter="enterIntersect"> | ||||
|                                 <dm-placeholder /> | ||||
|                             </intersect> | ||||
|                         </div> | ||||
|                     </div> | ||||
| 
 | ||||
| 					<div v-else> | ||||
| 						<dm-placeholder /> | ||||
| 					</div> | ||||
| 				</div> | ||||
|                     <div v-else> | ||||
|                         <dm-placeholder /> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
| 				<div class="col-md-3 d-md-block order-1 order-md-2 mb-4"> | ||||
| 					<button class="btn btn-dark shadow-sm font-weight-bold btn-block" @click="openCompose"><i class="far fa-envelope mr-1"></i> Compose</button> | ||||
| 					<hr> | ||||
| 					<div class="d-flex d-md-block"> | ||||
| 						<button | ||||
| 							v-for="(tab, index) in tabs" | ||||
| 							class="btn shadow-sm font-weight-bold btn-block text-capitalize mt-0 mt-md-2 mx-1 mx-md-0" | ||||
| 							:class="[ index === tabIndex ? 'btn-primary' : 'btn-light' ]" | ||||
| 							@click="toggleTab(index)" | ||||
| 							> | ||||
| 								{{ $t('directMessages.' + tab) }} | ||||
| 						</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
|                 <div class="col-md-3 d-md-block order-1 order-md-2 mb-4"> | ||||
|                     <button class="btn btn-dark shadow-sm font-weight-bold btn-block" @click="openCompose"><i class="far fa-envelope mr-1"></i> Compose</button> | ||||
|                     <hr> | ||||
|                     <div class="d-flex d-md-block"> | ||||
|                         <button | ||||
|                             v-for="(tab, index) in tabs" | ||||
|                             class="btn shadow-sm font-weight-bold btn-block text-capitalize mt-0 mt-md-2 mx-1 mx-md-0" | ||||
|                             :class="[ index === tabIndex ? 'btn-primary' : 'btn-light' ]" | ||||
|                             @click="toggleTab(index)" | ||||
|                             > | ||||
|                                 {{ $t('directMessages.' + tab) }} | ||||
|                         </button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
| 
 | ||||
| 			<drawer /> | ||||
| 		</div> | ||||
| 		<div v-else class="d-flex justify-content-center align-items-center" style="height:calc(100vh - 58px);"> | ||||
| 			<b-spinner /> | ||||
| 		</div> | ||||
|             <drawer /> | ||||
|         </div> | ||||
|         <div v-else class="d-flex justify-content-center align-items-center" style="height:calc(100vh - 58px);"> | ||||
|             <b-spinner /> | ||||
|         </div> | ||||
| 
 | ||||
| 		<b-modal | ||||
| 			ref="compose" | ||||
| 			hide-header | ||||
| 			hide-footer | ||||
| 			centered | ||||
| 			rounded | ||||
| 			size="md" | ||||
| 		> | ||||
| 			<div class="card shadow-none mt-4"> | ||||
| 				<div class="card-body d-flex align-items-center justify-content-between flex-column" style="min-height: 50vh;"> | ||||
| 					<h3 class="font-weight-bold">New Direct Message</h3> | ||||
| 					<div> | ||||
| 						<p class="mb-0 font-weight-bold">Select Recipient</p> | ||||
| 						<autocomplete | ||||
| 							:search="composeSearch" | ||||
| 							:disabled="composeLoading" | ||||
| 							placeholder="@dansup" | ||||
| 							aria-label="Search usernames" | ||||
| 							:get-result-value="getTagResultValue" | ||||
| 							@submit="onTagSubmitLocation" | ||||
| 							:debounce-time="500" | ||||
| 							ref="autocomplete" | ||||
| 						> | ||||
| 						</autocomplete> | ||||
| 						<p class="small text-muted">Search by username, or webfinger (@dansup@pixelfed.social)</p> | ||||
| 						<div style="width:300px;"></div> | ||||
| 					</div> | ||||
| 					<div> | ||||
| 						<button class="btn btn-outline-dark rounded-pill font-weight-bold px-5 py-1" @click="closeCompose">Cancel</button> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</b-modal> | ||||
| 	</div> | ||||
|         <b-modal | ||||
|             ref="compose" | ||||
|             hide-header | ||||
|             hide-footer | ||||
|             centered | ||||
|             rounded | ||||
|             size="md" | ||||
|         > | ||||
|             <div class="card shadow-none mt-4"> | ||||
|                 <div class="card-body d-flex align-items-center justify-content-between flex-column" style="min-height: 50vh;"> | ||||
|                     <h3 class="font-weight-bold">New Direct Message</h3> | ||||
|                     <div> | ||||
|                         <p class="mb-0 font-weight-bold">Select Recipient</p> | ||||
|                         <autocomplete | ||||
|                             :search="composeSearch" | ||||
|                             :disabled="composeLoading" | ||||
|                             placeholder="@dansup" | ||||
|                             aria-label="Search usernames" | ||||
|                             :get-result-value="getTagResultValue" | ||||
|                             @submit="onTagSubmitLocation" | ||||
|                             :debounce-time="500" | ||||
|                             ref="autocomplete" | ||||
|                         > | ||||
|                         </autocomplete> | ||||
|                         <p class="small text-muted">Search by username, or webfinger (@dansup@pixelfed.social)</p> | ||||
|                         <div style="width:300px;"></div> | ||||
|                     </div> | ||||
|                     <div> | ||||
|                         <button class="btn btn-outline-dark rounded-pill font-weight-bold px-5 py-1" @click="closeCompose">Cancel</button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </b-modal> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <script type="text/javascript"> | ||||
| 	import Drawer from './partials/drawer.vue'; | ||||
| 	import Sidebar from './partials/sidebar.vue'; | ||||
| 	import Placeholder from './partials/placeholders/DirectMessagePlaceholder.vue'; | ||||
| 	import Intersect from 'vue-intersect' | ||||
| 	import Autocomplete from '@trevoreyre/autocomplete-vue' | ||||
| 	import '@trevoreyre/autocomplete-vue/dist/style.css'; | ||||
|     import Drawer from './partials/drawer.vue'; | ||||
|     import Sidebar from './partials/sidebar.vue'; | ||||
|     import Placeholder from './partials/placeholders/DirectMessagePlaceholder.vue'; | ||||
|     import Intersect from 'vue-intersect' | ||||
|     import Autocomplete from '@trevoreyre/autocomplete-vue' | ||||
|     import '@trevoreyre/autocomplete-vue/dist/style.css'; | ||||
|     import { parseLinkHeader } from '@web3-storage/parse-link-header'; | ||||
| 
 | ||||
| 	export default { | ||||
| 		components: { | ||||
| 			"drawer": Drawer, | ||||
| 			"sidebar": Sidebar, | ||||
| 			"intersect": Intersect, | ||||
| 			"dm-placeholder": Placeholder, | ||||
| 			"autocomplete": Autocomplete | ||||
| 		}, | ||||
|     export default { | ||||
|         components: { | ||||
|             "drawer": Drawer, | ||||
|             "sidebar": Sidebar, | ||||
|             "intersect": Intersect, | ||||
|             "dm-placeholder": Placeholder, | ||||
|             "autocomplete": Autocomplete | ||||
|         }, | ||||
| 
 | ||||
| 		data() { | ||||
| 			return { | ||||
| 				isLoaded: false, | ||||
| 				profile: undefined, | ||||
| 				canLoadMore: true, | ||||
| 				threadsLoaded: false, | ||||
| 				composeLoading: false, | ||||
| 				threads: [], | ||||
| 				tabIndex: 0, | ||||
| 				tabs: [ | ||||
| 					'inbox', | ||||
| 					'sent', | ||||
| 					'requests' | ||||
| 				], | ||||
| 				page: 1, | ||||
| 				ids: [], | ||||
| 				isIntersecting: false | ||||
| 			} | ||||
| 		}, | ||||
|         data() { | ||||
|             return { | ||||
|                 isLoaded: false, | ||||
|                 profile: undefined, | ||||
|                 canLoadMore: true, | ||||
|                 threadsLoaded: false, | ||||
|                 composeLoading: false, | ||||
|                 threads: [], | ||||
|                 tabIndex: 0, | ||||
|                 tabs: [ | ||||
|                     'inbox', | ||||
|                     'sent', | ||||
|                     'requests' | ||||
|                 ], | ||||
|                 nextUrl: false, | ||||
|                 ids: [], | ||||
|                 isIntersecting: false | ||||
|             } | ||||
|         }, | ||||
| 
 | ||||
| 		mounted() { | ||||
| 			this.profile = window._sharedData.user; | ||||
| 			this.isLoaded = true; | ||||
| 			this.fetchThreads(); | ||||
|         mounted() { | ||||
|             this.profile = window._sharedData.user; | ||||
|             this.isLoaded = true; | ||||
|             this.fetchThreads(); | ||||
|         }, | ||||
| 
 | ||||
|         methods: { | ||||
|         	fetchThreads() { | ||||
|         		axios.get('/api/v1/conversations', { | ||||
|         			params: { | ||||
|         				scope: this.tabs[this.tabIndex] | ||||
|         			} | ||||
|         		}) | ||||
|         		.then(res => { | ||||
|         			let data = res.data.filter(m => { | ||||
|         				return m && m.hasOwnProperty('last_status') && m.last_status; | ||||
|         			}) | ||||
|         			let ids = data.map(dm => dm.accounts[0].id); | ||||
|         			this.ids = ids; | ||||
|         			this.threads = data; | ||||
|         			this.threadsLoaded = true; | ||||
|         			this.page++; | ||||
|         		}); | ||||
|         	}, | ||||
|             fetchThreads() { | ||||
|                 axios.get('/api/v1/conversations', { | ||||
|                     params: { | ||||
|                         scope: this.tabs[this.tabIndex] | ||||
|                     } | ||||
|                 }) | ||||
|                 .then(res => { | ||||
|                     let data = res.data.filter(m => { | ||||
|                         return m && m.hasOwnProperty('last_status') && m.last_status; | ||||
|                     }) | ||||
|                     if(res.headers && res.headers.link) { | ||||
|                         const links = parseLinkHeader(res.headers.link); | ||||
|                         if(links.next && links.next.url) { | ||||
|                             this.nextUrl = links.next.url | ||||
|                         } else { | ||||
|                             this.nextUrl = false; | ||||
|                         } | ||||
|                     } | ||||
|                     let ids = data.map(dm => dm.accounts[0].id); | ||||
|                     this.ids = ids; | ||||
|                     this.threads = data; | ||||
|                     this.threadsLoaded = true; | ||||
|                 }); | ||||
|             }, | ||||
| 
 | ||||
|         	timeago(ts) { | ||||
|         		return App.util.format.timeAgo(ts); | ||||
|         	}, | ||||
|             timeago(ts) { | ||||
|                 return App.util.format.timeAgo(ts); | ||||
|             }, | ||||
| 
 | ||||
|         	enterIntersect() { | ||||
|         		if(this.isIntersecting) { | ||||
|         			return; | ||||
|         		} | ||||
|             enterIntersect() { | ||||
|                 if(this.isIntersecting || !this.nextUrl) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|         		this.isIntersecting = true; | ||||
|                 this.isIntersecting = true; | ||||
| 
 | ||||
|         		axios.get('/api/v1/conversations', { | ||||
|         			params: { | ||||
|         				scope: this.tabs[this.tabIndex], | ||||
|         				page: this.page | ||||
|         			} | ||||
|         		}) | ||||
|         		.then(res => { | ||||
|         			let data = res.data.filter(m => { | ||||
|         				return m && m.hasOwnProperty('last_status') && m.last_status; | ||||
|         			}) | ||||
|         			data.forEach(dm => { | ||||
|         				if(this.ids.indexOf(dm.accounts[0].id) == -1) { | ||||
|         					this.ids.push(dm.accounts[0].id); | ||||
|         					this.threads.push(dm); | ||||
|         				} | ||||
|         			}) | ||||
|         			// this.threads.push(...res.data); | ||||
|         			if(!res.data.length || res.data.length < 5) { | ||||
|         				this.canLoadMore = false; | ||||
|         				this.isIntersecting = false; | ||||
|         				return; | ||||
|         			} | ||||
|         			this.page++; | ||||
|         			this.isIntersecting = false; | ||||
|         		}); | ||||
|         	}, | ||||
|                 axios.get(this.nextUrl) | ||||
|                 .then(res => { | ||||
|                     if(res.headers && res.headers.link) { | ||||
|                         const links = parseLinkHeader(res.headers.link); | ||||
|                         if(links.next && links.next.url) { | ||||
|                             this.nextUrl = links.next.url | ||||
|                         } else { | ||||
|                             this.nextUrl = false; | ||||
|                         } | ||||
|                     } | ||||
|                     let data = res.data.filter(m => { | ||||
|                         return m && m.hasOwnProperty('last_status') && m.last_status; | ||||
|                     }) | ||||
|                     data.forEach(dm => { | ||||
|                         if(this.ids.indexOf(dm.accounts[0].id) == -1) { | ||||
|                             this.ids.push(dm.accounts[0].id); | ||||
|                             this.threads.push(dm); | ||||
|                         } | ||||
|                     }) | ||||
|                     // this.threads.push(...res.data); | ||||
|                     if(!res.data.length || res.data.length < 5) { | ||||
|                         this.canLoadMore = false; | ||||
|                         this.isIntersecting = false; | ||||
|                         return; | ||||
|                     } | ||||
|                     this.isIntersecting = false; | ||||
|                 }); | ||||
|             }, | ||||
| 
 | ||||
|         	toggleTab(index) { | ||||
|         		event.currentTarget.blur(); | ||||
|         		this.threadsLoaded = false; | ||||
|         		this.page = 1; | ||||
|         		this.tabIndex = index; | ||||
|         		this.fetchThreads(); | ||||
|         	}, | ||||
|             toggleTab(index) { | ||||
|                 event.currentTarget.blur(); | ||||
|                 this.threadsLoaded = false; | ||||
|                 this.nextUrl = false; | ||||
|                 this.tabIndex = index; | ||||
|                 this.fetchThreads(); | ||||
|             }, | ||||
| 
 | ||||
|         	threadSummary(status, len = 50) { | ||||
|         		if(status.pf_type == 'photo') { | ||||
|         			let sender = this.profile.id == status.account.id; | ||||
|         			let icon = '<div class="' + (sender ? 'text-muted' : 'text-primary') + ' border px-2 py-1 mt-1 rounded" style="font-size:11px;width: fit-content"><i class="far fa-image mr-1"></i> <span>'; | ||||
|         			icon += sender ? 'Sent a photo' : 'Received a photo'; | ||||
|         			return icon + '</span></div>'; | ||||
|         		} | ||||
|             threadSummary(status, len = 50) { | ||||
|                 if(status.pf_type == 'photo') { | ||||
|                     let sender = this.profile.id == status.account.id; | ||||
|                     let icon = '<div class="' + (sender ? 'text-muted' : 'text-primary') + ' border px-2 py-1 mt-1 rounded" style="font-size:11px;width: fit-content"><i class="far fa-image mr-1"></i> <span>'; | ||||
|                     icon += sender ? 'Sent a photo' : 'Received a photo'; | ||||
|                     return icon + '</span></div>'; | ||||
|                 } | ||||
| 
 | ||||
|         		if(status.pf_type == 'video') { | ||||
|         			let sender = this.profile.id == status.account.id; | ||||
|         			let icon = '<div class="' + (sender ? 'text-muted' : 'text-primary') + ' border px-2 py-1 mt-1 rounded" style="font-size:11px;width: fit-content"><i class="far fa-video mr-1"></i> <span>'; | ||||
|         			icon += sender ? 'Sent a video' : 'Received a video'; | ||||
|         			return icon + '</span></div>'; | ||||
|         		} | ||||
|                 if(status.pf_type == 'video') { | ||||
|                     let sender = this.profile.id == status.account.id; | ||||
|                     let icon = '<div class="' + (sender ? 'text-muted' : 'text-primary') + ' border px-2 py-1 mt-1 rounded" style="font-size:11px;width: fit-content"><i class="far fa-video mr-1"></i> <span>'; | ||||
|                     icon += sender ? 'Sent a video' : 'Received a video'; | ||||
|                     return icon + '</span></div>'; | ||||
|                 } | ||||
| 
 | ||||
|         		let res = ''; | ||||
|                 let res = ''; | ||||
| 
 | ||||
|         		if(this.profile.id == status.account.id) { | ||||
|         			res += '<i class="far fa-reply-all fa-flip-both"></i> '; | ||||
|         		} | ||||
|                 if(this.profile.id == status.account.id) { | ||||
|                     res += '<i class="far fa-reply-all fa-flip-both"></i> '; | ||||
|                 } | ||||
| 
 | ||||
|         		let content = status.content; | ||||
|         		let text = content.replace(/(<([^>]+)>)/gi, ""); | ||||
|                 let content = status.content; | ||||
|                 let text = content.replace(/(<([^>]+)>)/gi, ""); | ||||
| 
 | ||||
|         		if(text.length > len) { | ||||
|         			return res + text.slice(0, len) + '...'; | ||||
|         		} | ||||
|                 if(text.length > len) { | ||||
|                     return res + text.slice(0, len) + '...'; | ||||
|                 } | ||||
| 
 | ||||
|         		return res + text; | ||||
|         	}, | ||||
|                 return res + text; | ||||
|             }, | ||||
| 
 | ||||
|         	openCompose() { | ||||
|         		this.$refs.compose.show(); | ||||
|         	}, | ||||
|             openCompose() { | ||||
|                 this.$refs.compose.show(); | ||||
|             }, | ||||
| 
 | ||||
|         	composeSearch(input) { | ||||
| 				if (input.length < 1) { return []; }; | ||||
| 				let self = this; | ||||
| 				let results = []; | ||||
| 				return axios.post('/api/direct/lookup', { | ||||
| 					q: input | ||||
| 				}).then(res => { | ||||
| 					return res.data; | ||||
| 				}); | ||||
| 			}, | ||||
|             composeSearch(input) { | ||||
|                 if (input.length < 1) { return []; }; | ||||
|                 let self = this; | ||||
|                 let results = []; | ||||
|                 return axios.post('/api/direct/lookup', { | ||||
|                     q: input | ||||
|                 }).then(res => { | ||||
|                     return res.data; | ||||
|                 }); | ||||
|             }, | ||||
| 
 | ||||
| 			getTagResultValue(result) { | ||||
| 				// return '@' + result.name; | ||||
| 				return result.local ? '@' + result.name : result.name; | ||||
| 			}, | ||||
|             getTagResultValue(result) { | ||||
|                 // return '@' + result.name; | ||||
|                 return result.local ? '@' + result.name : result.name; | ||||
|             }, | ||||
| 
 | ||||
| 			onTagSubmitLocation(result) { | ||||
| 				//this.$refs.autocomplete.value = ''; | ||||
| 				this.composeLoading = true; | ||||
| 				window.location.href = '/i/web/direct/thread/' + result.id; | ||||
| 				return; | ||||
| 			}, | ||||
|             onTagSubmitLocation(result) { | ||||
|                 //this.$refs.autocomplete.value = ''; | ||||
|                 this.composeLoading = true; | ||||
|                 window.location.href = '/i/web/direct/thread/' + result.id; | ||||
|                 return; | ||||
|             }, | ||||
| 
 | ||||
| 			closeCompose() { | ||||
| 				this.$refs.compose.hide(); | ||||
| 			} | ||||
|             closeCompose() { | ||||
|                 this.$refs.compose.hide(); | ||||
|             } | ||||
|         } | ||||
| 	} | ||||
|     } | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| 	.dms-page-component { | ||||
| 		font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | ||||
|     .dms-page-component { | ||||
|         font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | ||||
| 
 | ||||
| 		.dm { | ||||
| 			&-thread-summary { | ||||
| 				margin-bottom: 0; | ||||
| 				font-size: 12px; | ||||
| 				line-height: 12px; | ||||
| 			} | ||||
|         .dm { | ||||
|             &-thread-summary { | ||||
|                 margin-bottom: 0; | ||||
|                 font-size: 12px; | ||||
|                 line-height: 12px; | ||||
|             } | ||||
| 
 | ||||
| 			&-display-name { | ||||
| 				font-size: 16px; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|             &-display-name { | ||||
|                 font-size: 16px; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| </style> | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 daniel
						daniel