-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extract Spaces-Projects tiles to design-system/oc-tiles component
- Loading branch information
1 parent
c2ec30b
commit fff34d0
Showing
14 changed files
with
503 additions
and
310 deletions.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
packages/design-system/changelog/unreleased/enhancement-oc-tiles-component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Enhancement: Add tiles component | ||
|
||
We have added a new component to display resources as tiles. | ||
|
||
https://github.com/owncloud/web/pull/8137 |
56 changes: 56 additions & 0 deletions
56
packages/design-system/src/components/OcTiles/OcTiles.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { shallowMount } from 'web-test-helpers' | ||
import OcList from '../OcList/OcList.vue' | ||
import OcTiles from './OcTiles.vue' | ||
|
||
const stubs = { | ||
'oc-list': OcList | ||
} | ||
|
||
const spacesResources = [ | ||
{ | ||
name: 'Space 1', | ||
path: '', | ||
type: 'space', | ||
isFolder: true, | ||
getDriveAliasAndItem: () => '1' | ||
}, | ||
{ | ||
name: 'Space 2', | ||
path: '', | ||
type: 'space', | ||
isFolder: true, | ||
getDriveAliasAndItem: () => '2' | ||
} | ||
] | ||
|
||
describe('OcTiles component', () => { | ||
it('renders an array of spaces correctly', () => { | ||
const wrapper = getWrapper({ data: spacesResources }) | ||
expect(wrapper.html()).toMatchSnapshot() | ||
}) | ||
|
||
it('renders a footer slot', () => { | ||
const wrapper = getWrapper({}, { footer: 'Hello, OcTiles footer!' }) | ||
expect(wrapper.html()).toMatchSnapshot() | ||
}) | ||
|
||
it('emits context menu event upon right click on tile', async () => { | ||
const wrapper = getWrapper({ data: spacesResources }) | ||
await wrapper.find('oc-tile-stub').trigger('contextmenu') | ||
expect(wrapper.emitted().contextmenuClicked.length).toBe(1) | ||
}) | ||
|
||
function getWrapper(props = {}, slots = {}) { | ||
return shallowMount(OcTiles, { | ||
props: { | ||
...props | ||
}, | ||
slots: { | ||
...slots | ||
}, | ||
global: { | ||
stubs | ||
} | ||
}) | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<template> | ||
<div> | ||
<oc-list class="oc-tiles oc-flex"> | ||
<li v-for="(resource, index) in data" :key="resource.id" class="oc-tiles-item"> | ||
<oc-tile | ||
:ref="`row-${index}`" | ||
:resource="resource" | ||
@contextmenu.native=" | ||
$emit(constants.EVENT_TROW_CONTEXTMENU, $refs[`row-${index}`][0], $event, resource) | ||
" | ||
> | ||
<template #imageField="{ item }"> | ||
<slot name="image" :item="item" /> | ||
</template> | ||
<template #actions="{ item }"> | ||
<slot name="actions" :item="item" /> | ||
</template> | ||
</oc-tile> | ||
</li> | ||
</oc-list> | ||
<!-- @slot Footer of the tiles list --> | ||
<slot name="footer" /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { defineComponent, PropType } from 'vue' | ||
import { Resource } from 'web-client' | ||
import OcList from '../OcList/OcList.vue' | ||
import OcTile from '../_OcTile/OcTile.vue' | ||
// Constants should match what is being used in OcTable/ResourceTable | ||
// Alignment regarding naming would be an API-breaking change and can | ||
// Be done at a later point in time? | ||
import { EVENT_TROW_CLICKED, EVENT_TROW_CONTEXTMENU } from '../../helpers/constants' | ||
export default defineComponent({ | ||
name: 'OcTiles', | ||
status: 'prototype', | ||
release: 'unreleased', | ||
components: { | ||
OcList, | ||
OcTile | ||
}, | ||
props: { | ||
/** | ||
* Array of resources (spaces, folders, files) to be displayed as tiles | ||
*/ | ||
data: { | ||
type: Array as PropType<Resource[]>, | ||
default: () => [] | ||
} | ||
}, | ||
data() { | ||
return { | ||
constants: { | ||
EVENT_TROW_CLICKED, | ||
EVENT_TROW_CONTEXTMENU | ||
} | ||
} | ||
} | ||
}) | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
.oc-tiles { | ||
flex-wrap: wrap; | ||
gap: 15px; | ||
justify-content: flex-start; | ||
.oc-tiles-item { | ||
width: 252px; | ||
@media (max-width: $oc-breakpoint-xsmall-max) { | ||
width: 100%; | ||
} | ||
} | ||
} | ||
</style> |
20 changes: 20 additions & 0 deletions
20
packages/design-system/src/components/OcTiles/__snapshots__/OcTiles.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`OcTiles component renders a footer slot 1`] = ` | ||
<div> | ||
<ul class="oc-list oc-my-rm oc-mx-rm oc-tiles oc-flex"></ul> Hello, OcTiles footer! | ||
</div> | ||
`; | ||
|
||
exports[`OcTiles component renders an array of spaces correctly 1`] = ` | ||
<div> | ||
<ul class="oc-list oc-my-rm oc-mx-rm oc-tiles oc-flex"> | ||
<li class="oc-tiles-item"> | ||
<oc-tile-stub resource="[object Object]"></oc-tile-stub> | ||
</li> | ||
<li class="oc-tiles-item"> | ||
<oc-tile-stub resource="[object Object]"></oc-tile-stub> | ||
</li> | ||
</ul> | ||
</div> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/design-system/src/components/_OcTableCell/__snapshots__/OcTableCell.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`OcTableCell Uses correct element 1`] = `<th class="oc-table-cell oc-table-cell-align-right oc-table-cell-align-bottom oc-table-cell-width-shrink"></th>`; | ||
exports[`OcTableCell Uses correct element 1`] = `<th class="oc-table-cell oc-table-cell-align-right oc-table-cell-align-bottom oc-table-cell-width-shrink">Hello world!</th>`; |
41 changes: 41 additions & 0 deletions
41
packages/design-system/src/components/_OcTile/OcTile.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { shallowMount } from 'web-test-helpers' | ||
import OcTile from './OcTile.vue' | ||
|
||
const defaultSpace = { | ||
name: 'Space 1', | ||
path: '', | ||
type: 'space', | ||
isFolder: true, | ||
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 }) | ||
expect(wrapper).toMatchSnapshot() | ||
}) | ||
it('renders disabled space correctly', () => { | ||
const wrapper = getWrapper({ resource: disabledSpace }) | ||
expect(wrapper).toMatchSnapshot() | ||
}) | ||
|
||
function getWrapper(props = {}, slots = {}) { | ||
return shallowMount(OcTile, { | ||
props: { | ||
...props | ||
}, | ||
slots: { | ||
actions: '', | ||
imageField: '' | ||
} | ||
}) | ||
} | ||
}) |
159 changes: 159 additions & 0 deletions
159
packages/design-system/src/components/_OcTile/OcTile.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
<template> | ||
<div | ||
class="oc-tile-card oc-card oc-card-default oc-rounded" | ||
:data-item-id="resource.id" | ||
:class="resource.disabled ? 'state-trashed' : ''" | ||
> | ||
<oc-resource-link | ||
class="oc-card-media-top oc-border-b oc-flex oc-flex-center oc-flex-middle" | ||
:resource="resource" | ||
:folder-link="getResourceRoute" | ||
@click.stop.native="tileResourceClicked" | ||
> | ||
<oc-tag | ||
v-if="resource.disabled" | ||
class="resource-disabled-indicator oc-position-absolute" | ||
type="span" | ||
> | ||
<span v-translate>Disabled</span> | ||
</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" :src="resource.thumbnail" /> | ||
<oc-resource-icon | ||
v-else | ||
:resource="resource" | ||
size="xxlarge" | ||
class="tile-default-image oc-p-m" | ||
/> | ||
</slot> | ||
</oc-resource-link> | ||
<div class="oc-card-body oc-p-s"> | ||
<div class="oc-flex oc-flex-between oc-flex-middle"> | ||
<div class="oc-flex oc-flex-middle oc-text-truncate"> | ||
<oc-resource | ||
:resource="resource" | ||
:folder-link="getResourceRoute" | ||
:is-resource-clickable="!resource.disabled" | ||
@click.stop.native="tileResourceClicked" | ||
/> | ||
</div> | ||
<div class="oc-flex oc-flex-middle"> | ||
<!-- Slot for individual actions --> | ||
<slot name="actions" :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" | ||
> | ||
<small v-text="resource.description" /> | ||
</p> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { defineComponent, PropType } from 'vue' | ||
import { Resource } from 'web-client' | ||
import OcImg from '../OcImage/OcImage.vue' | ||
import OcResource from '../OcResource/OcResource.vue' | ||
import OcResourceIcon from '../OcResourceIcon/OcResourceIcon.vue' | ||
import OcResourceLink from '../OcResourceLink/OcResourceLink.vue' | ||
import OcTag from '../OcTag/OcTag.vue' | ||
import { createLocationSpaces } from '../../../../web-app-files/src/router' | ||
import { createFileRouteOptions } from '../../../../web-pkg/src/helpers/router' | ||
export default defineComponent({ | ||
name: 'OcTile', | ||
status: 'prototype', | ||
release: 'unreleased', | ||
components: { | ||
OcImg, | ||
OcResource, | ||
OcResourceIcon, | ||
OcResourceLink, | ||
OcTag | ||
}, | ||
props: { | ||
/** | ||
* Resource to be displayed within the tile | ||
*/ | ||
resource: { | ||
type: Object as PropType<Resource>, | ||
default: () => {} | ||
} | ||
}, | ||
computed: { | ||
getResourceRoute() { | ||
if (this.resource.type === 'space') { | ||
return this.resource.disabled | ||
? { path: '#' } | ||
: createLocationSpaces( | ||
'files-spaces-generic', | ||
createFileRouteOptions(this.resource, { path: '', fileId: this.resource.fileId }) | ||
) | ||
} | ||
if (this.resource.type === 'folder') { | ||
// return { path: this.resource.path } | ||
} | ||
return { path: '#' } | ||
} | ||
}, | ||
methods: { | ||
tileResourceClicked() { | ||
// Needs to handle file actions and potentially disabled folders also | ||
if (this.resource.disabled && this.resource.type === 'space') { | ||
this.showMessage({ | ||
title: this.$gettext('Disabled spaces cannot be entered'), | ||
status: 'warning' | ||
}) | ||
} | ||
} | ||
} | ||
}) | ||
</script> | ||
|
||
<style lang="scss" scoped> | ||
.oc-tile-card { | ||
box-shadow: none !important; | ||
background-color: var(--oc-color-background-highlight) !important; | ||
height: 100%; | ||
&.state-trashed { | ||
cursor: pointer; | ||
.tile-image, | ||
.tile-default-image > svg { | ||
filter: grayscale(100%); | ||
opacity: 80%; | ||
} | ||
} | ||
.oc-card-media-top { | ||
aspect-ratio: 16/9; | ||
.oc-tag { | ||
color: var(--oc-color-text-default); | ||
&.resource-disabled-indicator { | ||
z-index: 1; | ||
} | ||
} | ||
.tile-preview { | ||
min-width: 252px; | ||
height: auto; | ||
aspect-ratio: 16/9; | ||
object-fit: cover; | ||
} | ||
} | ||
.resource-name { | ||
overflow: hidden; | ||
color: var(--oc-color-text-default); | ||
} | ||
} | ||
</style> |
Oops, something went wrong.