Skip to content

Commit 7f75f7c

Browse files
feat: customize file picker icon size
Signed-off-by: kristian-zendato <kristian.zendato@nextcloud.com>
1 parent 4030af4 commit 7f75f7c

5 files changed

Lines changed: 76 additions & 23 deletions

File tree

lib/components/FilePicker/FileList.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55
tr.file-picker__row {
6-
height: var(--row-height, 50px);
6+
// 18px vertical padding around the preview (50px at the default 32px icon size)
7+
height: var(--row-height, calc(var(--file-picker-preview-size, 32px) + 18px));
78

89
td {
910
cursor: pointer;

lib/components/FilePicker/FileList.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ const fileContainer = ref<HTMLDivElement>()
258258
<style scoped lang="scss">
259259
.file-picker {
260260
&__header-preview {
261-
width: 22px; // 32px - 16px padding of button + 6px padding in file list rows
262-
height: 32px;
261+
width: var(--file-picker-preview-size, 32px);
262+
height: var(--file-picker-preview-size, 32px);
263263
flex: 0 0 auto; // do not shrink or grow
264264
}
265265
@@ -308,7 +308,7 @@ const fileContainer = ref<HTMLDivElement>()
308308
flex-direction: row-reverse;
309309
}
310310
:deep(.button-vue) {
311-
padding-inline: 16px 4px;
311+
padding-inline: 4px;
312312
}
313313
}
314314
th.row-size :deep(.button-vue__wrapper) {

lib/components/FilePicker/FileListIcon.module.scss

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,46 @@
55
/**
66
* Icon styling of the file list row preview or fallback icon
77
* (leading icon on the name row and header)
8+
*
9+
* Thumbnail size can be overridden instance-wide via CSS:
10+
* :root { --file-picker-preview-size: 64px; }
811
*/
912
.file-picker__file-icon {
1013
position: relative;
11-
width: 32px;
12-
height: 32px;
13-
min-width: 32px;
14-
min-height: 32px;
14+
width: var(--file-picker-preview-size, 32px);
15+
height: var(--file-picker-preview-size, 32px);
16+
min-width: var(--file-picker-preview-size, 32px);
17+
min-height: var(--file-picker-preview-size, 32px);
1518
background-repeat: no-repeat;
1619
background-size: contain;
1720
border-radius: var(--border-radius-small);
1821
// for the fallback
1922
display: flex;
2023
justify-content: center;
24+
25+
:global(.material-design-icon),
26+
:global(.material-design-icon svg) {
27+
width: var(--file-picker-preview-size, 32px);
28+
height: var(--file-picker-preview-size, 32px);
29+
}
30+
31+
.file-picker__file-icon-overlay {
32+
color: var(--color-primary-element-text);
33+
position: absolute;
34+
// Center overlay on folder icon with slight offset to match material design folder glyph
35+
// ((preview - overlay) / 2) + 2px where overlay is half the preview size
36+
inset-block-start: calc(var(--file-picker-preview-size, 32px) * 0.25 + 2px);
37+
38+
// Overlay is half the preview size (beats NcIconSvgWrapper scoped svg rules)
39+
&:global(.icon-vue) :global(svg) {
40+
width: calc(var(--file-picker-preview-size, 32px) / 2);
41+
height: calc(var(--file-picker-preview-size, 32px) / 2);
42+
max-width: calc(var(--file-picker-preview-size, 32px) / 2);
43+
max-height: calc(var(--file-picker-preview-size, 32px) / 2);
44+
}
45+
}
2146
}
2247

2348
.file-picker__file-icon--primary {
2449
color: var(--color-primary-element);
2550
}
26-
27-
.file-picker__file-icon-overlay {
28-
color: var(--color-primary-element-text);
29-
position: absolute;
30-
// 32px icon size - 16px overlay size + 2px padding to align with folder icon
31-
inset-block-start: 10px;
32-
}

lib/components/FilePicker/FilePreview.vue

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
:style="previewLoaded ? { backgroundImage: `url(${previewURL})` } : undefined"
88
:class="fileListIconStyles['file-picker__file-icon']">
99
<template v-if="!previewLoaded">
10-
<IconFile v-if="isFile" :size="32" />
10+
<IconFile v-if="isFile" />
1111
<template v-else>
1212
<NcIconSvgWrapper
1313
v-if="folderDecorationIcon"
1414
:class="fileListIconStyles['file-picker__file-icon-overlay']"
1515
inline
1616
:path="folderDecorationIcon"
17-
:size="16" />
18-
<IconFolder
19-
:class="fileListIconStyles['file-picker__file-icon--primary']"
20-
:size="32" />
17+
size="auto" />
18+
<IconFolder :class="fileListIconStyles['file-picker__file-icon--primary']" />
2119
</template>
2220
</template>
2321
</div>

lib/composables/preview.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,41 @@ import { generateUrl } from '@nextcloud/router'
1111
import { ref, toValue, watchEffect } from 'vue'
1212
import { preloadImage } from '../utils/imagePreload.ts'
1313

14+
/**
15+
* CSS custom property controlling FilePicker thumbnail size.
16+
* Override on `:root` (e.g. via instance theming) to change size without a public API.
17+
*/
18+
const FILE_PICKER_PREVIEW_SIZE_VAR = '--file-picker-preview-size'
19+
20+
/** Default FilePicker thumbnail size in pixels when the CSS variable is unset. */
21+
const FILE_PICKER_PREVIEW_SIZE_DEFAULT = 32
22+
23+
/**
24+
* Resolve the FilePicker preview size from `:root` CSS (or the default).
25+
* Used only for preview *request* resolution so fetched images match display size.
26+
*/
27+
function getFilePickerPreviewSize(): number {
28+
if (typeof window === 'undefined' || typeof getComputedStyle === 'undefined') {
29+
return FILE_PICKER_PREVIEW_SIZE_DEFAULT
30+
}
31+
32+
const raw = getComputedStyle(document.documentElement)
33+
.getPropertyValue(FILE_PICKER_PREVIEW_SIZE_VAR)
34+
.trim()
35+
const parsed = Number.parseFloat(raw)
36+
if (Number.isFinite(parsed) && parsed > 0) {
37+
return Math.round(parsed)
38+
}
39+
40+
return FILE_PICKER_PREVIEW_SIZE_DEFAULT
41+
}
42+
1443
interface PreviewOptions {
1544
/**
16-
* Size of the previews in px
45+
* Size of the previews in px.
46+
* When omitted, uses `--file-picker-preview-size` from CSS (default 32).
1747
*
18-
* @default 32
48+
* @default value of `--file-picker-preview-size` or 32
1949
*/
2050
size?: number
2151
/**
@@ -39,7 +69,13 @@ interface PreviewOptions {
3969
* @param options Preview options
4070
*/
4171
export function getPreviewURL(node: INode, options: PreviewOptions = {}) {
42-
options = { size: 32, cropPreview: false, mimeFallback: true, ...options }
72+
options = {
73+
cropPreview: false,
74+
mimeFallback: true,
75+
...options,
76+
// Keep request resolution in sync with CSS display size (avoids blurry upscales)
77+
size: options.size ?? getFilePickerPreviewSize(),
78+
}
4379

4480
try {
4581
const previewUrl = node.attributes?.previewUrl

0 commit comments

Comments
 (0)