Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/components/FilePicker/FileList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
tr.file-picker__row {
height: var(--row-height, 50px);
// 18px vertical padding around the preview (50px at the default 32px icon size)
height: var(--row-height, calc(var(--file-picker-preview-size, 32px) + 18px));

td {
cursor: pointer;
Expand Down
6 changes: 3 additions & 3 deletions lib/components/FilePicker/FileList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ const fileContainer = ref<HTMLDivElement>()
<style scoped lang="scss">
.file-picker {
&__header-preview {
width: 22px; // 32px - 16px padding of button + 6px padding in file list rows
height: 32px;
width: var(--file-picker-preview-size, 32px);
height: var(--file-picker-preview-size, 32px);
flex: 0 0 auto; // do not shrink or grow
}

Expand Down Expand Up @@ -308,7 +308,7 @@ const fileContainer = ref<HTMLDivElement>()
flex-direction: row-reverse;
}
:deep(.button-vue) {
padding-inline: 16px 4px;
padding-inline: 4px;
}
}
th.row-size :deep(.button-vue__wrapper) {
Expand Down
40 changes: 29 additions & 11 deletions lib/components/FilePicker/FileListIcon.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,46 @@
/**
* Icon styling of the file list row preview or fallback icon
* (leading icon on the name row and header)
*
* Thumbnail size can be overridden instance-wide via CSS:
* :root { --file-picker-preview-size: 64px; }
*/
.file-picker__file-icon {
position: relative;
width: 32px;
height: 32px;
min-width: 32px;
min-height: 32px;
width: var(--file-picker-preview-size, 32px);
height: var(--file-picker-preview-size, 32px);
min-width: var(--file-picker-preview-size, 32px);
min-height: var(--file-picker-preview-size, 32px);
background-repeat: no-repeat;
background-size: contain;
border-radius: var(--border-radius-small);
// for the fallback
display: flex;
justify-content: center;

:global(.material-design-icon),
:global(.material-design-icon svg) {
width: var(--file-picker-preview-size, 32px);
height: var(--file-picker-preview-size, 32px);
}

.file-picker__file-icon-overlay {
color: var(--color-primary-element-text);
position: absolute;
// Center overlay on folder icon with slight offset to match material design folder glyph
// ((preview - overlay) / 2) + 2px where overlay is half the preview size
inset-block-start: calc(var(--file-picker-preview-size, 32px) * 0.25 + 2px);

// Overlay is half the preview size (beats NcIconSvgWrapper scoped svg rules)
&:global(.icon-vue) :global(svg) {
width: calc(var(--file-picker-preview-size, 32px) / 2);
height: calc(var(--file-picker-preview-size, 32px) / 2);
max-width: calc(var(--file-picker-preview-size, 32px) / 2);
max-height: calc(var(--file-picker-preview-size, 32px) / 2);
}
}
}

.file-picker__file-icon--primary {
color: var(--color-primary-element);
}

.file-picker__file-icon-overlay {
color: var(--color-primary-element-text);
position: absolute;
// 32px icon size - 16px overlay size + 2px padding to align with folder icon
inset-block-start: 10px;
}
8 changes: 3 additions & 5 deletions lib/components/FilePicker/FilePreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@
:style="previewLoaded ? { backgroundImage: `url(${previewURL})` } : undefined"
:class="fileListIconStyles['file-picker__file-icon']">
<template v-if="!previewLoaded">
<IconFile v-if="isFile" :size="32" />
<IconFile v-if="isFile" />
<template v-else>
<NcIconSvgWrapper
v-if="folderDecorationIcon"
:class="fileListIconStyles['file-picker__file-icon-overlay']"
inline
:path="folderDecorationIcon"
:size="16" />
<IconFolder
:class="fileListIconStyles['file-picker__file-icon--primary']"
:size="32" />
size="auto" />
<IconFolder :class="fileListIconStyles['file-picker__file-icon--primary']" />
</template>
</template>
</div>
Expand Down
42 changes: 39 additions & 3 deletions lib/composables/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,41 @@ import { generateUrl } from '@nextcloud/router'
import { ref, toValue, watchEffect } from 'vue'
import { preloadImage } from '../utils/imagePreload.ts'

/**
* CSS custom property controlling FilePicker thumbnail size.
* Override on `:root` (e.g. via instance theming) to change size without a public API.
*/
const FILE_PICKER_PREVIEW_SIZE_VAR = '--file-picker-preview-size'

/** Default FilePicker thumbnail size in pixels when the CSS variable is unset. */
const FILE_PICKER_PREVIEW_SIZE_DEFAULT = 32

/**
* Resolve the FilePicker preview size from `:root` CSS (or the default).
* Used only for preview *request* resolution so fetched images match display size.
*/
function getFilePickerPreviewSize(): number {
if (typeof window === 'undefined' || typeof getComputedStyle === 'undefined') {
return FILE_PICKER_PREVIEW_SIZE_DEFAULT
}

const raw = getComputedStyle(document.documentElement)
.getPropertyValue(FILE_PICKER_PREVIEW_SIZE_VAR)
.trim()
const parsed = Number.parseFloat(raw)
if (Number.isFinite(parsed) && parsed > 0) {
return Math.round(parsed)
}

return FILE_PICKER_PREVIEW_SIZE_DEFAULT
}

interface PreviewOptions {
/**
* Size of the previews in px
* Size of the previews in px.
* When omitted, uses `--file-picker-preview-size` from CSS (default 32).
*
* @default 32
* @default value of `--file-picker-preview-size` or 32
*/
size?: number
/**
Expand All @@ -39,7 +69,13 @@ interface PreviewOptions {
* @param options Preview options
*/
export function getPreviewURL(node: INode, options: PreviewOptions = {}) {
options = { size: 32, cropPreview: false, mimeFallback: true, ...options }
options = {
cropPreview: false,
mimeFallback: true,
...options,
// Keep request resolution in sync with CSS display size (avoids blurry upscales)
size: options.size ?? getFilePickerPreviewSize(),
}

try {
const previewUrl = node.attributes?.previewUrl
Expand Down