PostContent.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <template>
  2. <div class="timeline-status-component-content">
  3. <div v-if="status.pf_type === 'poll'" class="postPresenterContainer" style="background: #000;">
  4. </div>
  5. <div v-else-if="!fixedHeight" class="postPresenterContainer" style="background: #000;">
  6. <div v-if="status.pf_type === 'photo'" class="w-100">
  7. <photo-presenter
  8. :status="status"
  9. :is-filtered="isFiltered"
  10. @lightbox="toggleLightbox"
  11. @togglecw="toggleContentWarning" />
  12. </div>
  13. <div v-else-if="status.pf_type === 'video'" class="w-100">
  14. <video-player
  15. :status="statusRender"
  16. :fixed-height="fixedHeight"
  17. @togglecw="toggleContentWarning" />
  18. </div>
  19. <div v-else-if="status.pf_type === 'photo:album'" class="w-100">
  20. <photo-album-presenter
  21. :status="status"
  22. @lightbox="toggleLightbox"
  23. @togglecw="toggleContentWarning" />
  24. </div>
  25. <div v-else-if="status.pf_type === 'video:album'" class="w-100">
  26. <video-album-presenter
  27. :status="status"
  28. @togglecw="toggleContentWarning" />
  29. </div>
  30. <div v-else-if="status.pf_type === 'photo:video:album'" class="w-100">
  31. <mixed-album-presenter
  32. :status="status"
  33. @lightbox="toggleLightbox"
  34. @togglecw="toggleContentWarning" />
  35. </div>
  36. </div>
  37. <div v-else class="card-body p-0">
  38. <div v-if="status.pf_type === 'photo'" :class="{ fixedHeight: fixedHeight }">
  39. <div v-if="statusRender.sensitive == true" class="content-label-wrapper">
  40. <div class="text-light content-label">
  41. <p class="text-center">
  42. <i class="far fa-eye-slash fa-2x"></i>
  43. </p>
  44. <p class="h4 font-weight-bold text-center">
  45. {{ isFiltered ? 'Filtered Content' : $t('common.sensitiveContent') }}
  46. </p>
  47. <p class="text-center py-2 content-label-text">
  48. {{ status.spoiler_text ? status.spoiler_text : $t('common.sensitiveContentWarning') }}
  49. </p>
  50. <p class="mb-0">
  51. <button class="btn btn-outline-light btn-block btn-sm font-weight-bold" @click="toggleContentWarning()">See Post</button>
  52. </p>
  53. </div>
  54. <blur-hash-image
  55. width="32"
  56. height="32"
  57. :punch="1"
  58. class="blurhash-wrapper"
  59. :hash="status.media_attachments[0].blurhash"
  60. />
  61. </div>
  62. <div
  63. v-else
  64. class="content-label-wrapper"
  65. @click.prevent="toggleLightbox"
  66. >
  67. <img
  68. :src="status.media_attachments[0].url"
  69. class="content-label-wrapper-img" />
  70. <blur-hash-image
  71. :key="key"
  72. width="32"
  73. height="32"
  74. :punch="1"
  75. :hash="status.media_attachments[0].blurhash"
  76. :src="status.media_attachments[0].url"
  77. class="blurhash-wrapper"
  78. :alt="status.media_attachments[0].description"
  79. :title="status.media_attachments[0].description"
  80. style="width: 100%;position: absolute;z-index:9;top:0:left:0"
  81. />
  82. <p
  83. v-if="!status.sensitive && sensitive"
  84. class="sensitive-curtain"
  85. @click="status.sensitive = true">
  86. <i class="fas fa-eye-slash fa-lg"></i>
  87. </p>
  88. </div>
  89. </div>
  90. <video-player
  91. v-else-if="status.pf_type === 'video'"
  92. :status="status"
  93. :fixed-height="fixedHeight"
  94. />
  95. <div v-else-if="status.pf_type === 'photo:album'" class="card-img-top shadow" style="border-radius: 15px;">
  96. <photo-album-presenter
  97. :status="status"
  98. class="photo-presenter"
  99. :class="{ fixedHeight: fixedHeight }"
  100. @lightbox="toggleLightbox"
  101. @togglecw="toggleContentWarning()" />
  102. </div>
  103. <div v-else-if="status.pf_type === 'photo:video:album'" class="card-img-top shadow" style="border-radius: 15px;">
  104. <mixed-album-presenter
  105. :status="status"
  106. class="mixed-presenter"
  107. :class="{ fixedHeight: fixedHeight }"
  108. @lightbox="toggleLightbox"
  109. @togglecw="status.sensitive = false" />
  110. </div>
  111. <div v-else-if="status.pf_type === 'text'">
  112. <div v-if="status.sensitive" class="border m-3 p-5 rounded-lg">
  113. <p class="text-center">
  114. <i class="far fa-eye-slash fa-2x"></i>
  115. </p>
  116. <p class="text-center lead font-weight-bold mb-0">Sensitive Content</p>
  117. <p class="text-center">{{ status.spoiler_text && status.spoiler_text.length ? status.spoiler_text : 'This post may contain sensitive content' }}</p>
  118. <p class="text-center mb-0">
  119. <button class="btn btn-primary btn-sm font-weight-bold" @click="status.sensitive = false">See post</button>
  120. </p>
  121. </div>
  122. </div>
  123. <div v-else class="bg-light rounded-lg d-flex align-items-center justify-content-center" style="height: 400px;">
  124. <div>
  125. <p class="text-center">
  126. <i class="fas fa-exclamation-triangle fa-4x"></i>
  127. </p>
  128. <p class="lead text-center mb-0">
  129. Cannot display post
  130. </p>
  131. <p class="small text-center mb-0">
  132. {{ status.pf_type }}:{{ status.id }}
  133. </p>
  134. </div>
  135. </div>
  136. </div>
  137. <div
  138. v-if="status.content && !status.sensitive"
  139. class="card-body status-text"
  140. :class="[ status.pf_type === 'text' ? 'py-0' : 'pb-0']">
  141. <p>
  142. <read-more :status="status" :cursor-limit="300" />
  143. </p>
  144. </div>
  145. </div>
  146. </template>
  147. <script type="text/javascript">
  148. import BigPicture from "bigpicture";
  149. import ReadMore from "./ReadMore.vue";
  150. import VideoPlayer from "@/presenter/VideoPlayer.vue";
  151. export default {
  152. components: {
  153. "read-more": ReadMore,
  154. "video-player": VideoPlayer
  155. },
  156. props: {
  157. status: {
  158. type: Object
  159. },
  160. isFiltered: {
  161. type: Boolean
  162. },
  163. filters: {
  164. type: Array
  165. }
  166. },
  167. data() {
  168. return {
  169. key: 1,
  170. sensitive: false
  171. };
  172. },
  173. computed: {
  174. statusRender: {
  175. get() {
  176. if (this.isFiltered) {
  177. this.status.spoiler_text = "Filtered because it contains the following keywords: " + this.status.filtered.map(f => f.keyword_matches).flat(1).join(", ");
  178. this.status.sensitive = true;
  179. }
  180. return this.status;
  181. }
  182. },
  183. fixedHeight: {
  184. get() {
  185. return this.$store.state.fixedHeight == true;
  186. }
  187. }
  188. },
  189. methods: {
  190. toggleLightbox(e) {
  191. BigPicture({
  192. el: e.target
  193. });
  194. },
  195. toggleContentWarning() {
  196. this.key++;
  197. this.sensitive = true;
  198. this.status.sensitive = !this.status.sensitive;
  199. },
  200. getPoster(status) {
  201. let url = status.media_attachments[0].preview_url;
  202. if (url.endsWith("no-preview.jpg") || url.endsWith("no-preview.png")) {
  203. return;
  204. }
  205. return url;
  206. }
  207. }
  208. };
  209. </script>
  210. <style scoped>
  211. .sensitive-curtain {
  212. margin-top: 0;
  213. padding: 10px;
  214. color: #000;
  215. font-size: 10px;
  216. text-align: right;
  217. position: absolute;
  218. top: 0;
  219. right: 0;
  220. border-radius: 11px;
  221. cursor: pointer;
  222. background: rgba(255, 255, 255,.5);
  223. }
  224. .content-label-wrapper {
  225. position: relative;
  226. width:100%;
  227. height: 400px;
  228. overflow: hidden;
  229. z-index:1
  230. }
  231. .content-label-wrapper-img {
  232. position: absolute;
  233. width: 105%;height: 410px;
  234. object-fit: cover;
  235. z-index: 1;
  236. top:0;
  237. left:0;
  238. filter: brightness(0.35) blur(6px);
  239. margin:-5px;
  240. }
  241. .photo-presenter {
  242. border-radius:15px !important;
  243. object-fit: contain;
  244. background-color: #000;
  245. overflow: hidden;
  246. }
  247. .mixed-presenter {
  248. border-radius:15px !important;
  249. object-fit: contain;
  250. background-color: #000;
  251. overflow: hidden;
  252. align-items:center;
  253. }
  254. </style>