Skip to content

Commit

Permalink
Add selection model to tiles view (#8392)
Browse files Browse the repository at this point in the history
* Add selection model to tiles view

* Add outline to selected tiles

* Add unit tests, fix snapshots

* Fix checkbox label translation

* Exclude spec-files from SonarCloud coverage

* Rename setSelection to toggleSelection

* Fix initial tile size loading

* Improve tile size slider background in dark mode

* Use oc-font-size-default instead of rem
  • Loading branch information
JammingBen authored Feb 9, 2023
1 parent d7f44ff commit 9a64098
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 140 deletions.
2 changes: 2 additions & 0 deletions changelog/unreleased/enhancement-resources-tiles-view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ Tiles can be dynamically resized on screens bigger than mobile, using the "displ

https://github.com/owncloud/web/pull/7991
https://github.com/owncloud/web/pull/8372
https://github.com/owncloud/web/pull/8392
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
https://github.com/owncloud/web/issues/8365
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ export default defineComponent({
'oc-checkbox',
'oc-rounded',
'oc-checkbox-' + getSizeClass(this.size),
{ 'oc-checkbox-outline': this.outline }
{ 'oc-checkbox-outline': this.outline },
{ 'oc-checkbox-checked': this.modelValue }
]
},
labelClasses() {
Expand Down Expand Up @@ -180,12 +181,14 @@ export default defineComponent({
cursor: pointer;
}
&:checked,
&-checked,
:checked,
&:indeterminate {
background-color: var(--oc-color-swatch-inverse-default);
}
&:checked {
&-checked,
:checked {
@include svg-fill($internal-form-checkbox-image, '#000', $form-radio-checked-icon-color);
}
Expand Down
31 changes: 13 additions & 18 deletions packages/design-system/src/components/OcTile/OcTile.spec.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
import { shallowMount } from 'web-test-helpers'
import { defaultPlugins, shallowMount } from 'web-test-helpers'
import OcTile from './OcTile.vue'

const defaultSpace = {
const getSpaceMock = (disabled = false) => ({
name: 'Space 1',
path: '',
type: 'space',
isFolder: true,
disabled,
getDriveAliasAndItem: () => '1'
}
const disabledSpace = {
name: 'Space 1',
path: '',
type: 'space',
isFolder: true,
disabled: true,
getDriveAliasAndItem: () => '1'
}
})

describe('OcTile component', () => {
it('renders default space correctly', () => {
const wrapper = getWrapper({ resource: defaultSpace })
const wrapper = getWrapper({ resource: getSpaceMock() })
expect(wrapper.html()).toMatchSnapshot()
})
it('renders disabled space correctly', () => {
const wrapper = getWrapper({ resource: disabledSpace })
const wrapper = getWrapper({ resource: getSpaceMock(true) })
expect(wrapper.html()).toMatchSnapshot()
})
it('renders selected resource correctly', () => {
const wrapper = getWrapper({ resource: getSpaceMock(), isResourceSelected: true })
expect(wrapper.find('.oc-tile-card-selected').exists()).toBeTruthy()
})

function getWrapper(props = {}, slots = {}) {
function getWrapper(props = {}) {
return shallowMount(OcTile, {
props: {
...props
},
global: { renderStubDefaultSlot: true }
props,
global: { plugins: [...defaultPlugins()], renderStubDefaultSlot: true }
})
}
})
113 changes: 89 additions & 24 deletions packages/design-system/src/components/OcTile/OcTile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,40 @@
<div
class="oc-tile-card oc-card oc-card-default oc-rounded"
:data-item-id="resource.id"
:class="resource.disabled ? 'state-trashed' : ''"
:class="{
'oc-tile-card-selected': isResourceSelected,
'state-trashed': resource.disabled
}"
@contextmenu="$emit('contextmenu', $event)"
>
<oc-resource-link
class="oc-card-media-top oc-border-b oc-flex oc-flex-center oc-flex-middle"
class="oc-card-media-top oc-flex oc-flex-center oc-flex-middle oc-m-rm"
:resource="resource"
:folder-link="resourceRoute"
@click="$emit('click')"
>
<div class="oc-tile-card-selection">
<slot name="selection" :item="resource" />
</div>
<oc-tag
v-if="resource.disabled"
class="resource-disabled-indicator oc-position-absolute"
type="span"
>
<span v-translate>Disabled</span>
<span v-text="$gettext('Disabled')" />
</oc-tag>
<!-- Slot for resource image, renders resource type icon by default -->
<slot name="imageField" :item="resource">
<oc-img
v-if="resource.thumbnail"
class="tile-preview oc-rounded-top"
:src="resource.thumbnail"
/>
<oc-resource-icon
v-else
:resource="resource"
size="xxlarge"
class="tile-default-image oc-pt-s"
/>
</slot>
<div class="oc-tile-card-preview oc-flex oc-flex-middle oc-flex-center">
<div class="oc-tile-card-hover"></div>
<slot name="imageField" :item="resource">
<oc-img v-if="resource.thumbnail" class="tile-preview" :src="resource.thumbnail" />
<oc-resource-icon
v-else
:resource="resource"
size="xlarge"
class="tile-default-image oc-pt-xs"
/>
</slot>
</div>
</oc-resource-link>
<div class="oc-card-body oc-p-s">
<div class="oc-flex oc-flex-between oc-flex-middle">
Expand All @@ -50,10 +54,7 @@
<slot name="contextMenu" :item="resource" />
</div>
</div>
<p
v-if="resource.description"
class="oc-text-left oc-ml-xs oc-mt-xs oc-mb-rm oc-text-truncate"
>
<p v-if="resource.description" class="oc-text-left oc-my-rm oc-text-truncate">
<small v-text="resource.description" />
</p>
</div>
Expand Down Expand Up @@ -92,17 +93,24 @@ export default defineComponent({
resourceRoute: {
type: Object,
default: () => {}
},
isResourceSelected: {
type: Boolean,
required: false,
default: false
}
},
emits: ['click', 'contextmenu']
})
</script>

<style lang="scss" scoped>
<style lang="scss">
.oc-tile-card {
background-color: var(--oc-color-background-highlight) !important;
box-shadow: none !important;
box-shadow: none;
height: 100%;
display: flex;
flex-flow: column;
outline: 1px solid var(--oc-color-border);
&.state-trashed {
Expand All @@ -116,6 +124,7 @@ export default defineComponent({
}
.oc-card-media-top {
position: relative;
aspect-ratio: 16/9;
justify-content: center;
width: 100%;
Expand All @@ -130,12 +139,68 @@ export default defineComponent({
.tile-preview {
aspect-ratio: 16/9;
height: auto;
height: 100%;
object-fit: cover;
width: 100%;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
&:hover {
.oc-tile-card-hover {
opacity: 15%;
}
}
}
&-selected {
outline: 2px solid var(--oc-color-swatch-primary-hover);
.oc-tile-card-preview {
width: calc(100% - var(--oc-space-medium));
height: calc(100% - var(--oc-space-medium));
.tile-preview,
.oc-tile-card-hover {
border-radius: 5px !important;
}
.oc-tile-card-hover {
opacity: 10%;
}
}
}
&-selection {
z-index: 1;
position: absolute;
top: 0;
left: 0;
input {
background-color: var(--oc-color-background-muted);
}
input.oc-checkbox-checked {
background-color: var(--oc-color-swatch-inverse-default);
}
}
&-preview {
position: absolute;
height: 100%;
width: 100%;
text-align: center;
}
&-hover {
position: absolute;
width: 100%;
height: 100%;
background: #000;
opacity: 0;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.resource-name-wrapper {
color: var(--oc-color-text-default);
max-width: 70%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

exports[`OcTile component renders default space correctly 1`] = `
<div class="oc-tile-card oc-card oc-card-default oc-rounded">
<oc-resource-link-stub class="oc-card-media-top oc-border-b oc-flex oc-flex-center oc-flex-middle" isresourceclickable="true" resource="[object Object]">
<oc-resource-link-stub class="oc-card-media-top oc-flex oc-flex-center oc-flex-middle oc-m-rm" isresourceclickable="true" resource="[object Object]">
<div class="oc-tile-card-selection"></div>
<!--v-if-->
<!-- Slot for resource image, renders resource type icon by default -->
<oc-resource-icon-stub class="tile-default-image oc-pt-s" resource="[object Object]" size="xxlarge"></oc-resource-icon-stub>
<div class="oc-tile-card-preview oc-flex oc-flex-middle oc-flex-center">
<div class="oc-tile-card-hover"></div>
<oc-resource-icon-stub class="tile-default-image oc-pt-xs" resource="[object Object]" size="xlarge"></oc-resource-icon-stub>
</div>
</oc-resource-link-stub>
<div class="oc-card-body oc-p-s">
<div class="oc-flex oc-flex-between oc-flex-middle">
Expand All @@ -24,11 +27,15 @@ exports[`OcTile component renders default space correctly 1`] = `

exports[`OcTile component renders disabled space correctly 1`] = `
<div class="oc-tile-card oc-card oc-card-default oc-rounded state-trashed">
<oc-resource-link-stub class="oc-card-media-top oc-border-b oc-flex oc-flex-center oc-flex-middle" isresourceclickable="true" resource="[object Object]">
<oc-resource-link-stub class="oc-card-media-top oc-flex oc-flex-center oc-flex-middle oc-m-rm" isresourceclickable="true" resource="[object Object]">
<div class="oc-tile-card-selection"></div>
<oc-tag-stub class="resource-disabled-indicator oc-position-absolute" rounded="false" size="medium" type="span">
<span>Disabled</span>
</oc-tag-stub> <!-- Slot for resource image, renders resource type icon by default -->
<oc-resource-icon-stub class="tile-default-image oc-pt-s" resource="[object Object]" size="xxlarge"></oc-resource-icon-stub>
</oc-tag-stub>
<div class="oc-tile-card-preview oc-flex oc-flex-middle oc-flex-center">
<div class="oc-tile-card-hover"></div>
<oc-resource-icon-stub class="tile-default-image oc-pt-xs" resource="[object Object]" size="xlarge"></oc-resource-icon-stub>
</div>
</oc-resource-link-stub>
<div class="oc-card-body oc-p-s">
<div class="oc-flex oc-flex-between oc-flex-middle">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ exports[`SpacesList should render all spaces in a table 1`] = `
<span class="oc-icon oc-icon-m oc-icon-passive">
<!---->
</span>
<div class="oc-drop oc-box-shadow-medium oc-rounded" id="context-menu-drop-1">
<div class="oc-drop oc-box-shadow-medium oc-rounded oc-overflow-hidden" id="context-menu-drop-1">
<div class="oc-card oc-card-body oc-background-secondary oc-p-s"></div>
</div>
</button>
Expand Down
17 changes: 12 additions & 5 deletions packages/web-app-files/src/components/AppBar/ViewOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,13 @@ export default defineComponent({
name: ViewModeConstants.queryName,
defaultValue: ViewModeConstants.defaultModeName
})
const viewSizeQuery = useRouteQueryPersisted({
name: ViewModeConstants.tilesSizeQueryName,
defaultValue: ViewModeConstants.tilesSizeDefault.toString()
})
watch(
[perPageQuery, viewModeQuery],
[perPageQuery, viewModeQuery, viewSizeQuery],
(params) => {
queryParamsLoading.value = params.some((p) => !p)
},
Expand All @@ -126,6 +127,11 @@ export default defineComponent({
queryParamsLoading
}
},
mounted() {
if (!this.queryParamsLoading) {
this.setTilesViewSize()
}
},
computed: {
...mapState('Files', ['areHiddenFilesShown', 'areFileExtensionsShown']),
Expand Down Expand Up @@ -161,9 +167,10 @@ export default defineComponent({
this.viewModeCurrent = mode.name
},
setTilesViewSize() {
document
.querySelector(':root')
.style.setProperty(`--oc-size-tiles-resize-step`, `${this.viewSizeCurrent * 12}rem`)
;(document.querySelector(':root') as HTMLElement).style.setProperty(
`--oc-size-tiles-resize-step`,
`${this.viewSizeCurrent * 12}rem`
)
},
updateHiddenFilesShownModel(event) {
this.hiddenFilesShownModel = event
Expand Down Expand Up @@ -203,7 +210,7 @@ export default defineComponent({
-webkit-appearance: none;
-webkit-transition: 0.2s;
border-radius: 0.3rem;
background: var(--oc-color-input-border);
background: var(--oc-color-border);
height: 0.5rem;
opacity: 0.7;
outline: none;
Expand Down
Loading

0 comments on commit 9a64098

Please sign in to comment.