Skip to content

Commit

Permalink
Fix ResourceTiles on mobile and add basic resize slider for tiles (#8372
Browse files Browse the repository at this point in the history
)
  • Loading branch information
pascalwengerter authored Feb 8, 2023
1 parent ba1e414 commit 13fcb72
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 23 deletions.
4 changes: 4 additions & 0 deletions changelog/unreleased/enhancement-resources-tiles-view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ Enhancement: Add tiles view for resource display

We've added a switch to change from the known resource table to a tiles view.
The change gets saved to the url and persisted across resource navigation.
Tiles can be dynamically resized on screens bigger than mobile, using the "display customization options" dropdown.

https://github.com/owncloud/web/pull/7991
https://github.com/owncloud/web/pull/8372
https://github.com/owncloud/web/issues/6378
https://github.com/owncloud/web/issues/6379
https://github.com/owncloud/web/issues/6380
https://github.com/owncloud/web/issues/8367
https://github.com/owncloud/web/issues/8368
5 changes: 5 additions & 0 deletions packages/design-system/src/tokens/ods/size.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ size:
value: 22px
form-check-default:
value: 14px
tiles:
resize-step:
value: 12rem
default:
value: 14rem
63 changes: 63 additions & 0 deletions packages/web-app-files/src/components/AppBar/ViewOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@
@change="itemsPerPage = $event"
/>
</li>
<li
v-if="viewModeCurrent === ViewModeConstants.tilesView.name"
class="files-view-options-list-item oc-mt-m oc-visible@s oc-flex oc-flex-between"
>
<label for="tiles-size-slider" v-text="resizeTilesLabel" />
<input
v-model="viewSizeCurrent"
type="range"
min="1"
max="6"
name="tiles-size-slider"
class="oc-range"
@input="setTilesViewSize"
/>
</li>
</oc-list>
</oc-drop>
</div>
Expand Down Expand Up @@ -91,6 +106,10 @@ export default defineComponent({
name: ViewModeConstants.queryName,
defaultValue: ViewModeConstants.defaultModeName
})
const viewSizeQuery = useRouteQueryPersisted({
name: ViewModeConstants.tilesSizeQueryName,
defaultValue: ViewModeConstants.tilesSizeDefault.toString()
})
watch(
[perPageQuery, viewModeQuery],
(params) => {
Expand All @@ -102,6 +121,7 @@ export default defineComponent({
return {
ViewModeConstants,
viewModeCurrent: viewModeQuery,
viewSizeCurrent: viewSizeQuery,
itemsPerPage: perPageQuery,
queryParamsLoading
}
Expand All @@ -112,6 +132,9 @@ export default defineComponent({
viewOptionsButtonLabel() {
return this.$gettext('Display customization options of the files list')
},
resizeTilesLabel() {
return this.$gettext('Tile size')
},
hiddenFilesShownModel: {
get() {
Expand All @@ -137,6 +160,11 @@ export default defineComponent({
setViewMode(mode) {
this.viewModeCurrent = mode.name
},
setTilesViewSize() {
document
.querySelector(':root')
.style.setProperty(`--oc-size-tiles-resize-step`, `${this.viewSizeCurrent * 12}rem`)
},
updateHiddenFilesShownModel(event) {
this.hiddenFilesShownModel = event
},
Expand Down Expand Up @@ -170,4 +198,39 @@ export default defineComponent({
margin-top: var(--oc-space-small);
}
}
.oc-range {
-webkit-appearance: none;
-webkit-transition: 0.2s;
border-radius: 0.3rem;
background: var(--oc-color-input-border);
height: 0.5rem;
opacity: 0.7;
outline: none;
transition: opacity 0.2s;
width: 100%;
max-width: 50%;
&:hover {
opacity: 1;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
background: var(--oc-color-swatch-primary-default);
border-radius: 50%;
cursor: pointer;
height: 1rem;
width: 1rem;
}
&::-moz-range-thumb {
background: var(--oc-color-swatch-primary-default);
border-radius: 50%;
cursor: pointer;
height: 1rem;
width: 1rem;
}
}
</style>
44 changes: 26 additions & 18 deletions packages/web-app-files/src/components/FilesList/ResourceTiles.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
<template>
<div>
<oc-list class="oc-tiles oc-flex" :class="tileWidth === 'small' ? 'small-tiles' : ''">
<li v-for="(resource, index) in data" :key="resource.id" class="oc-tiles-item">
<oc-list class="oc-tiles oc-flex" :class="resizable ? 'resizableTiles' : ''">
<li v-for="resource in data" :key="resource.id" class="oc-tiles-item">
<oc-tile
:ref="
(el) => {
tileRefs.tiles[index] = el
}
"
:ref="(el) => (tileRefs.tiles[resource.id] = el)"
:resource="resource"
:resource-route="getRoute(resource)"
@vue:mounted="$emit('rowMounted', resource, tileRefs.tiles[index], ImageDimension.Tile)"
@contextmenu="showContextMenu($event, index, tileRefs.tiles[index])"
@vue:mounted="
$emit('rowMounted', resource, tileRefs.tiles[resource.id], ImageDimension.Tile)
"
@contextmenu="showContextMenu($event, resource.id, tileRefs.tiles[resource.id])"
@click="emitTileClick(resource)"
>
<template #imageField>
Expand All @@ -26,20 +24,20 @@
:id="`space-context-btn-${resource.getDomSelector()}`"
:ref="
(el) => {
tileRefs.dropBtns[index] = el
tileRefs.dropBtns[resource.id] = el
}
"
v-oc-tooltip="contextMenuLabel"
:aria-label="contextMenuLabel"
appearance="raw"
@click="resetDropPosition($event, index, tileRefs.dropBtns[index])"
@click="resetDropPosition($event, resource.id, tileRefs.dropBtns[resource.id])"
>
<oc-icon name="more-2" />
</oc-button>
<oc-drop
:ref="
(el) => {
tileRefs.dropEls[index] = el
tileRefs.dropEls[resource.id] = el
}
"
:drop-id="`space-context-drop-${resource.getDomSelector()}`"
Expand Down Expand Up @@ -85,9 +83,9 @@ export default defineComponent({
type: Array as PropType<Resource[]>,
default: () => []
},
tileWidth: {
type: String,
default: ''
resizable: {
type: Boolean,
default: false
},
targetRouteCallback: {
type: Function,
Expand Down Expand Up @@ -210,12 +208,22 @@ export default defineComponent({
.oc-tiles {
column-gap: 1rem;
display: grid;
grid-template-columns: repeat(auto-fill, 14rem);
grid-template-columns: repeat(auto-fill, var(--oc-size-tiles-default));
justify-content: flex-start;
row-gap: 1rem;
&.small-tiles {
grid-template-columns: repeat(auto-fill, 12rem);
&.resizableTiles {
grid-template-columns: repeat(auto-fill, var(--oc-size-tiles-resize-step));
}
@media only screen and (max-width: 640px) {
grid-template-columns: 80%;
justify-content: center;
padding: var(--oc-space-medium) 0;
&.resizableTiles {
grid-template-columns: 80%;
}
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Resource } from 'web-client'
import { useSelectedResources, SelectedResourcesResult } from '../selection'
import { ReadOnlyRef } from 'web-pkg'
import { ScrollToResult, useScrollTo } from '../scrollTo'
import { useViewMode, ViewModeConstants } from '../viewMode'
import { useViewMode, useViewSize, ViewModeConstants } from '../viewMode'

interface ResourcesViewDefaultsOptions<T, U extends any[]> {
loadResourcesTask?: Task<T, U>
Expand All @@ -37,7 +37,7 @@ type ResourcesViewDefaultsResult<T, TT, TU extends any[]> = {
sortBy: ReadOnlyRef<string>
sortDir: ReadOnlyRef<SortDir>
viewMode: ReadOnlyRef<string>

viewSize: ReadOnlyRef<string>
selectedResources: Ref<Resource[]>
selectedResourcesIds: Ref<(string | number)[]>
isResourceInSelection(resource: Resource): boolean
Expand Down Expand Up @@ -72,6 +72,10 @@ export const useResourcesViewDefaults = <T, TT, TU extends any[]>(
const currentViewMode = computed((): string => queryItemAsString(currentViewModeQuery.value))
const viewMode = useViewMode(currentViewMode)

const currentTilesSizeQuery = useRouteQuery('tiles-size', '1')
const currentTilesSize = computed((): string => String(currentTilesSizeQuery.value))
const viewSize = useViewSize(currentTilesSize)

const paginationPageQuery = useRouteQuery('page', '1')
const paginationPage = computed((): number => parseInt(String(paginationPageQuery.value)))
const { items: paginatedResources, total: paginationPages } = usePagination({
Expand All @@ -92,6 +96,7 @@ export const useResourcesViewDefaults = <T, TT, TU extends any[]>(
storeItems,
fields,
viewMode,
viewSize,
paginatedResources,
paginationPages,
paginationPage,
Expand Down
2 changes: 2 additions & 0 deletions packages/web-app-files/src/composables/viewMode/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ export abstract class ViewModeConstants {
}
}
static readonly queryName: string = 'view-mode'
static readonly tilesSizeDefault: number = 1
static readonly tilesSizeQueryName: string = 'tiles-size'
}
12 changes: 12 additions & 0 deletions packages/web-app-files/src/composables/viewMode/useViewMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ export function useViewMode(options: ComputedRef<string>): ComputedRef<string> {
})
return computed(() => queryItemAsString(unref(viewModeQuery)))
}

export function useViewSize<T>(options: ComputedRef<string>): ComputedRef<string> {
if (options) {
return computed(() => unref(options))
}

const viewModeSize = useRouteQueryPersisted({
name: ViewModeConstants.tilesSizeQueryName,
defaultValue: ViewModeConstants.tilesSizeDefault.toString()
})
return computed(() => String(unref(viewModeSize)))
}
2 changes: 1 addition & 1 deletion packages/web-app-files/src/views/spaces/GenericSpace.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
v-else-if="viewMode === ViewModeConstants.tilesView.name"
:data="paginatedResources"
class="oc-px-m oc-pt-l"
tile-width="small"
:resizable="true"
:target-route-callback="resourceTargetRouteCallback"
:space="space"
@rowMounted="rowMounted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const useResourcesViewDefaultsMock = (
scrollToResource: jest.fn(),
scrollToResourceFromRoute: jest.fn(),
viewMode: ref('resource-table'),
viewSize: ref('1'),
...options
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,32 @@ describe('ViewOptions component', () => {
const viewModeSwitchButtons = wrapper.find('.viewmode-switch-buttons')
expect(viewModeSwitchButtons.html()).toMatchSnapshot()
})
it('displays a tile-resize range slider in dropdown if currentViewMode is resource-tiles', async () => {
const { wrapper } = getWrapper(
{},
{
viewModes: [ViewModeConstants.condensedTable, ViewModeConstants.default]
},
'resource-tiles'
)

const filesViewOptions = wrapper.find('#files-view-options-drop')
expect(filesViewOptions.html()).toMatchSnapshot()
})
})

function getWrapper(
{ perPage = '100' } = {},
props?: {
viewModes: ViewMode[]
}
},
currentViewMode = ''
) {
jest.mocked(useRouteQueryPersisted).mockImplementation(() => ref(perPage))

const storeOptions = { ...defaultStoreMockOptions }
const store = createStore(storeOptions)
const mocks = defaultComponentMocks()
const mocks = { ...defaultComponentMocks(), viewModeCurrent: currentViewMode }
return {
storeOptions,
mocks,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ViewOptions component displays a tile-resize range slider in dropdown if currentViewMode is resource-tiles 1`] = `
<div class="oc-drop oc-box-shadow-medium oc-rounded oc-width-auto" id="files-view-options-drop">
<div class="oc-card oc-card-body oc-background-secondary oc-p-m">
<ul class="oc-list oc-my-rm oc-mx-rm">
<li class="files-view-options-list-item oc-mb-m">
<span class="oc-switch">
<span id="oc-switch-label-21">Show hidden files</span>
<button aria-checked="false" aria-labelledby="oc-switch-label-21" class="oc-switch-btn" role="switch"></button>
</span>
</li>
<li class="files-view-options-list-item oc-my-m">
<span class="oc-switch">
<span id="oc-switch-label-22">Show file extensions</span>
<button aria-checked="false" aria-labelledby="oc-switch-label-22" class="oc-switch-btn" role="switch"></button>
</span>
</li>
<li class="files-view-options-list-item oc-mt-m">
<div class="oc-page-size files-pagination-size">
<label class="oc-page-size-label" for="oc-page-size-23">Items per page</label>
<oc-select-stub class="oc-page-size-select" clearable="false" disabled="false" filter="[Function]" id="oc-select-24" input-id="oc-page-size-23" loading="false" model-value="100" options="100,500" searchable="false"></oc-select-stub>
</div>
</li>
<li class="files-view-options-list-item oc-mt-m oc-visible@s oc-flex oc-flex-between">
<label for="tiles-size-slider">Tile size</label>
<input class="oc-range" max="6" min="1" name="tiles-size-slider" type="range">
</li>
</ul>
</div>
</div>
`;
exports[`ViewOptions component sets the correct initial files page limit 1`] = `
<div class="oc-flex oc-flex-middle">
<!--v-if-->
Expand All @@ -25,6 +56,7 @@ exports[`ViewOptions component sets the correct initial files page limit 1`] = `
<oc-select-stub class="oc-page-size-select" clearable="false" disabled="false" filter="[Function]" id="oc-select-4" input-id="oc-page-size-3" loading="false" model-value="100" options="100,500" searchable="false"></oc-select-stub>
</div>
</li>
<!--v-if-->
</ul>
</div>
</div>
Expand Down

0 comments on commit 13fcb72

Please sign in to comment.