You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TemplatePreview.vue 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <!--
  2. - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
  3. -
  4. - @author John Molakvoæ <skjnldsv@protonmail.com>
  5. -
  6. - @license GNU AGPL version 3 or any later version
  7. -
  8. - This program is free software: you can redistribute it and/or modify
  9. - it under the terms of the GNU Affero General Public License as
  10. - published by the Free Software Foundation, either version 3 of the
  11. - License, or (at your option) any later version.
  12. -
  13. - This program is distributed in the hope that it will be useful,
  14. - but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. - GNU Affero General Public License for more details.
  17. -
  18. - You should have received a copy of the GNU Affero General Public License
  19. - along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. -
  21. -->
  22. <template>
  23. <li class="template-picker__item">
  24. <input :id="id"
  25. :checked="checked"
  26. type="radio"
  27. class="radio"
  28. name="template-picker"
  29. @change="onCheck">
  30. <label :for="id" class="template-picker__label">
  31. <div class="template-picker__preview"
  32. :class="failedPreview ? 'template-picker__preview--failed' : ''">
  33. <img class="template-picker__image"
  34. :src="realPreviewUrl"
  35. alt=""
  36. draggable="false"
  37. @error="onFailure">
  38. </div>
  39. <span class="template-picker__title">
  40. {{ nameWithoutExt }}
  41. </span>
  42. </label>
  43. </li>
  44. </template>
  45. <script>
  46. import { generateUrl } from '@nextcloud/router'
  47. import { encodeFilePath } from '../utils/fileUtils.js'
  48. import { getToken, isPublic } from '../utils/davUtils.js'
  49. // preview width generation
  50. const previewWidth = 256
  51. export default {
  52. name: 'TemplatePreview',
  53. inheritAttrs: false,
  54. props: {
  55. basename: {
  56. type: String,
  57. required: true,
  58. },
  59. checked: {
  60. type: Boolean,
  61. default: false,
  62. },
  63. fileid: {
  64. type: [String, Number],
  65. required: true,
  66. },
  67. filename: {
  68. type: String,
  69. required: true,
  70. },
  71. previewUrl: {
  72. type: String,
  73. default: null,
  74. },
  75. hasPreview: {
  76. type: Boolean,
  77. default: true,
  78. },
  79. mime: {
  80. type: String,
  81. required: true,
  82. },
  83. ratio: {
  84. type: Number,
  85. default: null,
  86. },
  87. },
  88. data() {
  89. return {
  90. failedPreview: false,
  91. }
  92. },
  93. computed: {
  94. /**
  95. * Strip away extension from name
  96. *
  97. * @return {string}
  98. */
  99. nameWithoutExt() {
  100. return this.basename.indexOf('.') > -1 ? this.basename.split('.').slice(0, -1).join('.') : this.basename
  101. },
  102. id() {
  103. return `template-picker-${this.fileid}`
  104. },
  105. realPreviewUrl() {
  106. // If original preview failed, fallback to mime icon
  107. if (this.failedPreview && this.mimeIcon) {
  108. return this.mimeIcon
  109. }
  110. if (this.previewUrl) {
  111. return this.previewUrl
  112. }
  113. // TODO: find a nicer standard way of doing this?
  114. if (isPublic()) {
  115. return generateUrl(`/apps/files_sharing/publicpreview/${getToken()}?fileId=${this.fileid}&file=${encodeFilePath(this.filename)}&x=${previewWidth}&y=${previewWidth}&a=1`)
  116. }
  117. return generateUrl(`/core/preview?fileId=${this.fileid}&x=${previewWidth}&y=${previewWidth}&a=1`)
  118. },
  119. mimeIcon() {
  120. return OC.MimeType.getIconUrl(this.mime)
  121. },
  122. },
  123. methods: {
  124. onCheck() {
  125. this.$emit('check', this.fileid)
  126. },
  127. onFailure() {
  128. this.failedPreview = true
  129. },
  130. },
  131. }
  132. </script>
  133. <style lang="scss" scoped>
  134. .template-picker {
  135. &__item {
  136. display: flex;
  137. }
  138. &__label {
  139. display: flex;
  140. // Align in the middle of the grid
  141. align-items: center;
  142. flex: 1 1;
  143. flex-direction: column;
  144. &, * {
  145. cursor: pointer;
  146. user-select: none;
  147. }
  148. &::before {
  149. display: none !important;
  150. }
  151. }
  152. &__preview {
  153. display: block;
  154. overflow: hidden;
  155. // Stretch so all entries are the same width
  156. flex: 1 1;
  157. width: var(--width);
  158. min-height: var(--height);
  159. max-height: var(--height);
  160. padding: 0;
  161. border: var(--border) solid var(--color-border);
  162. border-radius: var(--border-radius-large);
  163. input:checked + label > & {
  164. border-color: var(--color-primary);
  165. }
  166. &--failed {
  167. // Make sure to properly center fallback icon
  168. display: flex;
  169. }
  170. }
  171. &__image {
  172. max-width: 100%;
  173. background-color: var(--color-main-background);
  174. object-fit: cover;
  175. }
  176. // Failed preview, fallback to mime icon
  177. &__preview--failed &__image {
  178. width: calc(var(--margin) * 8);
  179. // Center mime icon
  180. margin: auto;
  181. background-color: transparent !important;
  182. object-fit: initial;
  183. }
  184. &__title {
  185. overflow: hidden;
  186. // also count preview border
  187. max-width: calc(var(--width) + 2*2px);
  188. padding: var(--margin);
  189. white-space: nowrap;
  190. text-overflow: ellipsis;
  191. }
  192. }
  193. </style>