web/satellite: table responsiveness added
added Resizable wrapper to track screen dimensions changes items to render computable added TODO: implement file browser table resposiveness Change-Id: I913d5cdb5285d6f0fb7135183ff299c37f01ad4a
This commit is contained in:
parent
d1d98af098
commit
3c0fc3a530
@ -83,6 +83,7 @@ export default class App extends Vue {
|
||||
<style lang="scss">
|
||||
html {
|
||||
overflow: hidden;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<template>
|
||||
<table-item
|
||||
:item="{ name: itemData.name, date: itemData.localDate() }"
|
||||
:item="itemToRender"
|
||||
:on-click="onClick"
|
||||
>
|
||||
<th slot="options" v-click-outside="closeDropdown" class="grant-item__functional options overflow-visible" @click.stop="openDropdown">
|
||||
@ -19,8 +19,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop } from 'vue-property-decorator';
|
||||
import { AccessGrant } from '@/types/accessGrants';
|
||||
import Resizable from "@/components/common/Resizable.vue";
|
||||
import TableItem from "@/components/common/TableItem.vue";
|
||||
|
||||
import DeleteIcon from "../../../static/images/objects/delete.svg";
|
||||
@ -34,7 +35,7 @@ import DotsIcon from "../../../static/images/objects/dots.svg";
|
||||
DotsIcon,
|
||||
},
|
||||
})
|
||||
export default class AccessGrantsItem extends Vue {
|
||||
export default class AccessGrantsItem extends Resizable {
|
||||
@Prop({ default: new AccessGrant('', '', new Date(), '') })
|
||||
private readonly itemData: AccessGrant;
|
||||
@Prop({ default: () => () => {} })
|
||||
@ -44,6 +45,12 @@ export default class AccessGrantsItem extends Vue {
|
||||
@Prop({ default: -1 })
|
||||
public readonly dropdownKey: number;
|
||||
|
||||
public get itemToRender(): { [key: string]: string | string[] } {
|
||||
if (!this.isMobile) return { name: this.itemData.name, date: this.itemData.localDate() };
|
||||
|
||||
return { info: [ this.itemData.name, `Created ${this.itemData.localDate()}` ] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes dropdown.
|
||||
*/
|
||||
|
34
web/satellite/src/components/common/Resizable.vue
Normal file
34
web/satellite/src/components/common/Resizable.vue
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2022 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
// @vue/component
|
||||
@Component
|
||||
export default class Resizable extends Vue {
|
||||
public screenWidth: number = window.innerWidth;
|
||||
public screenHeight: number = window.innerHeight;
|
||||
|
||||
public get isMobile(): boolean {
|
||||
return this.screenWidth <= 550;
|
||||
}
|
||||
|
||||
public get isTablet(): boolean {
|
||||
return !this.isMobile && this.screenWidth <= 800;
|
||||
}
|
||||
|
||||
public mounted(): void {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
}
|
||||
|
||||
public beforeDestroy(): void {
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
}
|
||||
|
||||
private onResize(): void {
|
||||
this.screenWidth = window.innerWidth;
|
||||
this.screenHeight = window.innerHeight;
|
||||
}
|
||||
}
|
||||
</script>
|
@ -6,11 +6,14 @@
|
||||
:class="{ 'selected': selected }"
|
||||
@click="onClick"
|
||||
>
|
||||
<th v-if="selectable" class="icon">
|
||||
<th v-if="selectable" class="icon select">
|
||||
<v-table-checkbox :disabled="selectDisabled" :value="selected" @checkChange="onChange" />
|
||||
</th>
|
||||
<th v-for="(val, key, index) in item" :key="index" class="align-left data">
|
||||
<p>{{ val }}</p>
|
||||
<div v-if="Array.isArray(val)" class="few-items">
|
||||
<p v-for="str in val" :key="str" class="array-val">{{ str }}</p>
|
||||
</div>
|
||||
<p v-else>{{ val }}</p>
|
||||
</th>
|
||||
<slot name="options" />
|
||||
</tr>
|
||||
@ -53,4 +56,22 @@ export default class TableItem extends Vue {
|
||||
background: #f0f3f8;
|
||||
}
|
||||
}
|
||||
|
||||
.few-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.array-val {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.25rem;
|
||||
|
||||
&:first-of-type {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<table class="base-table" border="0" cellpadding="0" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-if="selectable" class="icon" />
|
||||
<th v-if="selectable" class="icon select" />
|
||||
<slot name="head" />
|
||||
</tr>
|
||||
</thead>
|
||||
@ -62,7 +62,7 @@ export default class VTable extends Vue {
|
||||
<style lang="scss">
|
||||
.table-wrapper {
|
||||
background: #fff;
|
||||
box-shadow: 0 4px 32px rgb(0 0 0 / 4%);
|
||||
box-shadow: 0 4px 2rem rgb(0 0 0 / 4%);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ export default class VTable extends Vue {
|
||||
|
||||
th {
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
padding: 1.125rem;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
@ -84,9 +84,13 @@ export default class VTable extends Vue {
|
||||
background: var(--c-block-gray);
|
||||
text-transform: uppercase;
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
tr {
|
||||
height: 52px;
|
||||
font-size: 12px;
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
@ -100,8 +104,13 @@ export default class VTable extends Vue {
|
||||
th {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
color: #111827;
|
||||
font-size: 14px;
|
||||
font-size: 1rem;
|
||||
border-top: solid 1px #e5e7eb;
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
border-top: none;
|
||||
border-bottom: solid 1px #e5e7eb;
|
||||
}
|
||||
}
|
||||
|
||||
.data {
|
||||
@ -132,9 +141,21 @@ export default class VTable extends Vue {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 15px 20px;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.7rem;
|
||||
color: rgb(44 53 58 / 60%);
|
||||
border-top: solid 1px #e5e7eb;
|
||||
font-family: 'font-medium', sans-serif;
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
|
||||
.select {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<template>
|
||||
<table-item
|
||||
:item="{ name: itemData.name, date: formattedDate }"
|
||||
:item="itemToRender"
|
||||
:on-click="onClick"
|
||||
>
|
||||
<th slot="options" v-click-outside="closeDropdown" class="bucket-item__functional options overflow-visible" @click.stop="openDropdown(dropdownKey)">
|
||||
@ -33,9 +33,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
import TableItem from "@/components/common/TableItem.vue";
|
||||
import Resizable from "@/components/common/Resizable.vue";
|
||||
import DeleteIcon from '@/../static/images/objects/delete.svg';
|
||||
import DetailsIcon from '@/../static/images/objects/details.svg';
|
||||
import DotsIcon from '@/../static/images/objects/dots.svg';
|
||||
@ -53,7 +54,7 @@ import { LocalData } from "@/utils/localData";
|
||||
DetailsIcon,
|
||||
},
|
||||
})
|
||||
export default class BucketItem extends Vue {
|
||||
export default class BucketItem extends Resizable {
|
||||
@Prop({ default: null })
|
||||
public readonly itemData: Bucket;
|
||||
@Prop({ default: () => () => {} })
|
||||
@ -82,8 +83,14 @@ export default class BucketItem extends Vue {
|
||||
/**
|
||||
* Returns formatted date.
|
||||
*/
|
||||
public get formattedDate(): string | undefined {
|
||||
return this.itemData.since.toLocaleString();
|
||||
public get formattedDate(): string {
|
||||
return this.itemData.since.toLocaleString() || '';
|
||||
}
|
||||
|
||||
public get itemToRender(): { [key: string]: string | string[] } {
|
||||
if (!this.isMobile) return { name: this.itemData.name, date: this.formattedDate };
|
||||
|
||||
return { info: [ this.itemData.name, `Created ${this.formattedDate}` ] };
|
||||
}
|
||||
|
||||
public hideGuide(): void {
|
||||
@ -121,9 +128,10 @@ export default class BucketItem extends Vue {
|
||||
name: RouteConfig.Buckets.with(RouteConfig.BucketsDetails).name,
|
||||
params: {
|
||||
bucketName: this.itemData.name,
|
||||
backRoute: this.$route.name ? this.$route.name : ''
|
||||
backRoute: this.$route.name || ''
|
||||
},
|
||||
});
|
||||
|
||||
this.closeDropdown();
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,18 @@
|
||||
|
||||
<template>
|
||||
<table-item
|
||||
:item="{ name: itemData.name, memberCount: itemData.memberCount, date: itemData.createdDate() }"
|
||||
:item="itemToRender"
|
||||
:on-click="onClick"
|
||||
class="container__item"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
import { Project } from '@/types/projects';
|
||||
import TableItem from "@/components/common/TableItem.vue";
|
||||
import Resizable from "@/components/common/Resizable.vue";
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
@ -21,11 +22,17 @@ import TableItem from "@/components/common/TableItem.vue";
|
||||
TableItem,
|
||||
},
|
||||
})
|
||||
export default class ProjectsListItem extends Vue {
|
||||
export default class ProjectsListItem extends Resizable {
|
||||
@Prop({default: () => new Project('123', 'name', 'desc')})
|
||||
private readonly itemData: Project;
|
||||
@Prop({ default: () => (_: string) => {} })
|
||||
public readonly onClick: (project: string) => void;
|
||||
|
||||
public get itemToRender(): { [key: string]: string | string[] } {
|
||||
if (!this.isMobile) return { name: this.itemData.name, memberCount: this.itemData.memberCount.toString(), date: this.itemData.createdDate() };
|
||||
|
||||
return { info: [ this.itemData.name, `Created ${this.itemData.createdDate()}` ] };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<template>
|
||||
<table-item
|
||||
:class="{ 'owner': isProjectOwner }"
|
||||
:item="{ name: itemData.name, date: itemData.localDate(), email: itemData.email }"
|
||||
:item="itemToRender"
|
||||
:selectable="true"
|
||||
:select-disabled="isProjectOwner"
|
||||
:selected="itemData.isSelected"
|
||||
@ -14,22 +14,30 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { Component, Prop } from 'vue-property-decorator';
|
||||
|
||||
import { ProjectMember } from '@/types/projectMembers';
|
||||
import TableItem from "@/components/common/TableItem.vue";
|
||||
import Resizable from "@/components/common/Resizable.vue";
|
||||
|
||||
// @vue/component
|
||||
@Component({
|
||||
components: {TableItem}
|
||||
components: { TableItem }
|
||||
})
|
||||
export default class ProjectMemberListItem extends Vue {
|
||||
export default class ProjectMemberListItem extends Resizable {
|
||||
@Prop({ default: new ProjectMember('', '', '', new Date(), '') })
|
||||
public itemData: ProjectMember;
|
||||
|
||||
public get isProjectOwner(): boolean {
|
||||
return this.itemData.user.id === this.$store.getters.selectedProject.ownerId;
|
||||
}
|
||||
|
||||
public get itemToRender(): { [key: string]: string | string[] } {
|
||||
if (!this.isMobile && !this.isTablet) return { name: this.itemData.name, date: this.itemData.localDate(), email: this.itemData.email };
|
||||
|
||||
// TODO: change after adding actions button to list item
|
||||
return { name: this.itemData.name, email: this.itemData.email };
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
>
|
||||
<template #head>
|
||||
<th class="align-left">Name</th>
|
||||
<th class="align-left">Date Added</th>
|
||||
<th class="align-left date-added">Date Added</th>
|
||||
<th class="align-left">Email</th>
|
||||
</template>
|
||||
<template #body>
|
||||
@ -221,4 +221,11 @@ export default class ProjectMembersArea extends Vue {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) and (min-width: 500px) {
|
||||
|
||||
.date-added {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
exports[` should render correctly 1`] = `
|
||||
<tr class="owner">
|
||||
<th class="icon"><label class="container"><input id="checkbox" disabled="disabled" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label></th>
|
||||
<th class="icon select"><label class="container"><input id="checkbox" disabled="disabled" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label></th>
|
||||
<th class="align-left data">
|
||||
<p>testShortName</p>
|
||||
</th>
|
||||
@ -17,7 +17,7 @@ exports[` should render correctly 1`] = `
|
||||
|
||||
exports[` should render correctly with item row highlighted 1`] = `
|
||||
<tr class="selected owner">
|
||||
<th class="icon"><label class="container"><input id="checkbox" disabled="disabled" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label></th>
|
||||
<th class="icon select"><label class="container"><input id="checkbox" disabled="disabled" type="checkbox" class="checkmark-input"> <span class="checkmark"></span></label></th>
|
||||
<th class="align-left data">
|
||||
<p>testShortName</p>
|
||||
</th>
|
||||
|
Loading…
Reference in New Issue
Block a user