web/satellite: update team page design

This change the projects members (team) page to match the figma.

Issue: https://github.com/storj/storj/issues/5742

Change-Id: I5d4ef4478612a5c397b795c9b0b9b364fd16e4a4
This commit is contained in:
Wilfred Asomani 2023-04-27 13:29:01 +00:00 committed by Wilfred Asomani
parent ee28103b29
commit bf630b7efa
6 changed files with 147 additions and 82 deletions

View File

@ -105,7 +105,7 @@
:key="index"
>
<!-- using <th> to comply with common Vtable.vue-->
<th class="hide-mobile" />
<th class="hide-mobile icon" />
<th
class="align-left"
aria-roledescription="file-uploading"
@ -140,7 +140,7 @@
</tr>
<tr v-if="filesUploading.length" class="files-uploading-count">
<th class="hide-mobile files-uploading-count__content" />
<th class="hide-mobile files-uploading-count__content icon" />
<th class="align-left files-uploading-count__content" aria-roledescription="files-uploading-count">
{{ formattedFilesWaitingToBeUploaded }}
waiting to be uploaded...

View File

@ -52,6 +52,7 @@
<script setup lang="ts">
import { computed, VueConstructor } from 'vue';
import WhitePlusIcon from '@/../static/images/common/plusWhite.svg';
import AddCircleIcon from '@/../static/images/common/addCircle.svg';
import CopyIcon from '@/../static/images/common/copyButtonIcon.svg';
import TrashIcon from '@/../static/images/accessGrants/trashIcon.svg';
@ -114,6 +115,7 @@ const icons = new Map<string, VueConstructor>([
['folder', FolderIcon],
['resources', ResourcesIcon],
['addcircle', AddCircleIcon],
['add', WhitePlusIcon],
]);
const iconComponent = computed((): VueConstructor | undefined => icons.get(props.icon.toLowerCase()));

View File

@ -42,6 +42,8 @@ function clearSearch(): void {
async function processSearchQuery(): Promise<void> {
await props.search(searchQuery.value);
}
defineExpose({ clearSearch });
</script>
<style scoped lang="scss">
@ -54,7 +56,7 @@ async function processSearchQuery(): Promise<void> {
outline: none;
border: 1px solid var(--c-grey-3);
border-radius: 10px;
height: 56px;
height: 40px;
width: 250px;
font-family: 'font_regular', sans-serif;
font-size: 16px;
@ -62,7 +64,7 @@ async function processSearchQuery(): Promise<void> {
background-image: url('../../../static/images/common/search-gray.png');
background-repeat: no-repeat;
background-size: 22px 22px;
background-position: top 16px left 16px;
background-position: top 8px left 14px;
@media screen and (max-width: 1150px) {
width: 100%;

View File

@ -107,11 +107,11 @@ const emit = defineEmits(['selectAllClicked']);
font-family: 'font_regular', sans-serif;
color: #111827;
font-size: 1rem;
border-top: solid 1px #e5e7eb;
border-top: solid 1px var(--c-grey-2);
@media screen and (max-width: 550px) {
border-top: none;
border-bottom: solid 1px #e5e7eb;
border-bottom: solid 1px var(--c-grey-2);
}
}
@ -136,7 +136,7 @@ const emit = defineEmits(['selectAllClicked']);
.icon {
width: 50px;
overflow: visible !important;
background: var(--c-grey-1);
border-right: 1px solid var(--c-grey-2);
}
.table-footer {

View File

@ -52,7 +52,7 @@ function selectClicked(event: Event): void {
position: absolute;
height: 20px;
width: 20px;
border: 2px solid rgb(56 75 101 / 40%);
border: 1px solid var(--c-grey-4);
border-radius: 4px;
box-sizing: border-box;
}

View File

@ -4,51 +4,61 @@
<template>
<div class="team-header-container">
<div class="team-header-container__title-area">
<h1 class="team-header-container__title-area__title" aria-roledescription="title">Team</h1>
<VInfo class="team-header-container__title-area__info-button">
<template #icon>
<InfoIcon />
</template>
<template #message>
<p class="team-header-container__title-area__info-button__message">
The only project role currently available is Admin, which gives full access to the project.
</p>
</template>
</VInfo>
<div class="team-header-container__title-area__titles">
<span class="team-header-container__title-area__titles__title" aria-roledescription="title">Team</span>
<VInfo class="team-header-container__title-area__titles__info-button">
<template #icon>
<InfoIcon />
</template>
<template #message>
<p class="team-header-container__title-area__info-button__message">
The only project role currently available is Admin, which gives full access to the project.
</p>
</template>
</VInfo>
<p class="team-header-container__title-area__titles__subtitle" aria-roledescription="subtitle">
Manage the team members of "{{ projectName }}"
</p>
</div>
<VButton
class="team-header-container__title-area__button"
label="Add Members"
width="160px"
height="40px"
font-size="13px"
border-radius="8px"
:on-press="toggleTeamMembersModal"
icon="add"
:is-disabled="isAddButtonDisabled"
/>
</div>
<div class="team-header-container__divider" />
<div class="team-header-container__wrapper">
<VHeader
ref="headerComponent"
placeholder="Team Members"
<VSearchAlternateStyling
ref="searchInput"
class="team-header-container__wrapper__search"
placeholder="members"
:search="processSearchQuery"
>
<div v-if="isDefaultState" class="header-default-state">
<VButton
class="button"
label="+ Add"
width="122px"
height="48px"
:on-press="toggleTeamMembersModal"
:is-disabled="isAddButtonDisabled"
/>
</div>
/>
<div>
<div v-if="areProjectMembersSelected" class="header-selected-members">
<VButton
class="button deletion"
label="Delete"
width="122px"
height="48px"
height="40px"
:on-press="onFirstDeleteClick"
/>
<VButton
class="button"
label="Cancel"
width="122px"
height="48px"
height="40px"
:is-transparent="true"
:on-press="onClearSelection"
/>
<span class="header-selected-members__info-text"><b>{{ selectedProjectMembersCount }}</b> users selected</span>
</div>
<div v-if="areSelectedProjectMembersBeingDeleted" class="header-after-delete-click">
<span class="header-after-delete-click__delete-confirmation">Are you sure you want to delete <b>{{ selectedProjectMembersCount }}</b> {{ userCountTitle }}?</span>
@ -57,20 +67,20 @@
class="button deletion"
label="Delete"
width="122px"
height="48px"
height="40px"
:on-press="onDelete"
/>
<VButton
class="button"
label="Cancel"
width="122px"
height="48px"
height="40px"
:is-transparent="true"
:on-press="onClearSelection"
/>
</div>
</div>
</VHeader>
</div>
<div v-if="isDeleteClicked" class="blur-content" />
<div v-if="isDeleteClicked" class="blur-search" />
</div>
@ -93,8 +103,8 @@ import { useProjectsStore } from '@/store/modules/projectsStore';
import { useConfigStore } from '@/store/modules/configStore';
import VInfo from '@/components/common/VInfo.vue';
import VHeader from '@/components/common/VHeader.vue';
import VButton from '@/components/common/VButton.vue';
import VSearchAlternateStyling from '@/components/common/VSearchAlternateStyling.vue';
import InfoIcon from '@/../static/images/team/infoTooltip.svg';
@ -125,7 +135,14 @@ const FIRST_PAGE = 1;
const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
const isDeleteClicked = ref<boolean>(false);
const headerComponent = ref<typeof VHeader & ClearSearch>();
const searchInput = ref<typeof VSearchAlternateStyling & ClearSearch>();
/**
* Returns the name of the selected project from store.
*/
const projectName = computed((): string => {
return projectsStore.state.selectedProject.name;
});
const isDefaultState = computed((): boolean => {
return props.headerState === 0;
@ -211,7 +228,7 @@ async function setProjectState(): Promise<void> {
}
await pmStore.getProjectMembers(FIRST_PAGE, projectsStore.state.selectedProject.id);
headerComponent.value?.clearSearch();
searchInput.value?.clearSearch();
}
/**
@ -228,40 +245,73 @@ onBeforeUnmount((): void => {
.team-header-container {
&__title-area {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
&__title {
font-family: 'font_bold', sans-serif;
font-size: 32px;
line-height: 39px;
color: #263549;
margin: 0;
}
@media screen and (max-width: 1150px) {
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
row-gap: 10px;
&__info-button {
max-height: 20px;
cursor: pointer;
margin-left: 10px;
&:hover {
.team-header-svg-path {
fill: #fff;
}
.team-header-svg-rect {
fill: #2683ff;
}
}
&__message {
color: #586c86;
font-family: 'font_regular', sans-serif;
font-size: 16px;
line-height: 18px;
&__button {
width: 100% !important;
}
}
&__titles {
&__title {
font-family: 'font_medium', sans-serif;
font-weight: 600;
font-size: 28px;
line-height: 34px;
color: #232b34;
text-align: left;
display: inline;
}
&__subtitle {
font-size: 14px;
line-height: 20px;
font-weight: bold;
margin-top: 10px;
}
&__info-button {
max-height: 20px;
cursor: pointer;
margin-left: 10px;
display: inline;
&:hover {
.team-header-svg-path {
fill: #fff;
}
.team-header-svg-rect {
fill: #2683ff;
}
}
&__message {
color: #586c86;
font-family: 'font_regular', sans-serif;
font-size: 16px;
line-height: 18px;
}
}
}
}
&__divider {
width: 100%;
height: 1px;
background: #dadfe7;
margin: 24px 0;
}
}
@ -270,7 +320,6 @@ onBeforeUnmount((): void => {
display: flex;
flex-direction: column;
justify-content: center;
height: 85px;
&__info-text {
font-family: 'font_medium', sans-serif;
@ -286,17 +335,12 @@ onBeforeUnmount((): void => {
&__button-area {
display: flex;
.deletion {
margin-top: 2px;
}
}
}
.header-selected-members {
display: flex;
align-items: center;
height: 85px;
justify-content: center;
&__info-text {
@ -310,11 +354,22 @@ onBeforeUnmount((): void => {
}
.team-header-container__wrapper {
margin-bottom: 4px;
position: relative;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: flex-start;
position: relative;
justify-content: space-between;
@media screen and (max-width: 1150px) {
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
row-gap: 10px;
}
&__search {
position: static;
}
.blur-content {
position: absolute;
@ -330,12 +385,18 @@ onBeforeUnmount((): void => {
.blur-search {
position: absolute;
bottom: 0;
right: 0;
width: 540px;
height: 56px;
left: 0;
width: 300px;
height: 40px;
z-index: 100;
opacity: 0.3;
background-color: #f5f6fa;
@media screen and (max-width: 1150px) {
bottom: unset;
right: 0;
width: unset;
}
}
}