web/satellite: applied styling updates for gallery view

Add "geographic distribution" item into three-dot menu.
On small screens, instead of showing three-dot menu + geographic distribution, show three-dot menu + download.
Allow the user to use left and right arrow keys to navigate through previews in gallery view.
Update "Do not share download link with other people" notification according to new designs.
Add hover styles and tooltips to icons according to designs.
In the "View Details" modal, change "Saved in" to "Bucket".
(not related to gallery view) - the three-dot-menu in the file list has a border radius, but when you hover over the last component ("Delete"), the border radius goes away.

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

Change-Id: I39bec2e630327d136cb2550dbbce4fcbf77399f9
This commit is contained in:
Vitalii 2023-06-19 15:35:33 +03:00 committed by Vitalii Shpital
parent 1712e69f0c
commit adbd4fbab2
11 changed files with 156 additions and 28 deletions

View File

@ -419,7 +419,13 @@ function openDropdown(): void {
async function download(): Promise<void> {
try {
await obStore.download(props.file);
notify.warning('Do not share download link with other people. If you want to share this data better use "Share" option.');
const message = `
<p class="message-title">Downloading...</p>
<p class="message-info">
Keep this download link private.<br>If you want to share, use the Share option.
</p>
`;
notify.success('', message);
} catch (error) {
notify.error('Can not download your file', AnalyticsErrorEventSource.FILE_BROWSER_ENTRY);
}
@ -500,7 +506,15 @@ function cancelDeletion(): void {
}
.dropdown-item.action.p-3.action {
font-family: 'Inter', sans-serif;
font-family: 'font_regular', sans-serif;
}
&:first-of-type {
border-radius: 6px 6px 0 0;
}
&:last-of-type {
border-radius: 0 0 6px 6px;
}
&__label {

View File

@ -2,18 +2,28 @@
// See LICENSE for copying information.
<template>
<VInfo>
<template #icon>
<div class="button-icon" :class="{ active: isActive }" @click="onPress">
<component :is="icon" />
</div>
</template>
<template #message>
<p class="message">{{ info }}</p>
</template>
</VInfo>
</template>
<script setup lang="ts">
import { Component } from 'vue';
import VInfo from '@/components/common/VInfo.vue';
const props = withDefaults(defineProps<{
isActive?: boolean
icon: string
onPress: () => void
info: string
}>(), {
isActive: false,
});
@ -28,9 +38,41 @@ const props = withDefaults(defineProps<{
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
background: rgb(255 255 255 / 10%);
}
}
.active {
background: rgb(255 255 255 / 10%);
}
.message {
font-family: 'font_medium', sans-serif;
font-size: 12px;
line-height: 18px;
color: var(--c-white);
white-space: nowrap;
}
:deep(.info__box) {
width: auto;
cursor: default;
top: 100%;
left: 50%;
}
:deep(.info__box__message) {
background: var(--c-grey-6);
border-radius: 4px;
padding: 10px 8px;
}
:deep(.info__box__arrow) {
background: var(--c-grey-6);
width: 10px;
height: 10px;
margin-bottom: -3px;
}
</style>

View File

@ -3,7 +3,7 @@
<template>
<Teleport to="#app">
<div ref="viewContainer" class="gallery" tabindex="0" @keydown.esc="closeModal">
<div ref="viewContainer" class="gallery" tabindex="0" @keydown.esc="closeModal" @keydown.right="onNext" @keydown.left="onPrevious">
<div class="gallery__header">
<LogoIcon class="gallery__header__logo" />
<SmallLogoIcon class="gallery__header__small-logo" />
@ -19,13 +19,33 @@
:icon="DotsIcon"
:on-press="toggleDropdown"
:is-active="isOptionsDropdown === true"
info="More"
/>
<ButtonIcon
class="gallery__header__functional__item"
:icon="MapIcon"
:on-press="() => setActiveModal(DistributionModal)"
info="Geographic Distribution"
/>
<ButtonIcon
:icon="DownloadIcon"
:on-press="download"
info="Download"
/>
<ButtonIcon
class="gallery__header__functional__item"
:icon="ShareIcon"
:on-press="() => setActiveModal(ShareModal)"
info="Share"
/>
<ButtonIcon
:icon="CloseIcon"
:on-press="closeModal"
info="Close"
/>
<ButtonIcon :icon="MapIcon" :on-press="() => setActiveModal(DistributionModal)" />
<ButtonIcon class="gallery__header__functional__item" :icon="DownloadIcon" :on-press="download" />
<ButtonIcon class="gallery__header__functional__item" :icon="ShareIcon" :on-press="() => setActiveModal(ShareModal)" />
<ButtonIcon :icon="CloseIcon" :on-press="closeModal" />
<OptionsDropdown
v-if="isOptionsDropdown"
:on-distribution="() => setActiveModal(DistributionModal)"
:on-view-details="() => setActiveModal(DetailsModal)"
:on-download="download"
:on-share="() => setActiveModal(ShareModal)"
@ -253,7 +273,6 @@ async function fetchPreviewAndMapUrl(): Promise<void> {
*/
async function onDelete(): Promise<void> {
try {
const objectsCount = obStore.sortedFiles.length;
let newFile: BrowserObject | undefined = obStore.sortedFiles[fileIndex.value + 1];
if (!newFile || newFile.type === folderType) {
newFile = obStore.sortedFiles.find(f => f.type !== folderType && f.Key !== file.value.Key);
@ -282,7 +301,13 @@ async function onDelete(): Promise<void> {
async function download(): Promise<void> {
try {
await obStore.download(file.value);
notify.warning('Do not share download link with other people. If you want to share this data better use "Share" option.');
const message = `
<p class="message-title">Downloading...</p>
<p class="message-info">
Keep this download link private.<br>If you want to share, use the Share option.
</p>
`;
notify.success('', message);
} catch (error) {
notify.error('Can not download your file', AnalyticsErrorEventSource.OBJECT_DETAILS_MODAL);
}
@ -500,6 +525,16 @@ watch(filePath, () => {
cursor: pointer;
min-width: 46px;
&:hover {
:deep(rect) {
&:first-of-type {
fill: rgb(255 255 255 / 10%);
}
}
}
@media screen and (width <= 600px) {
display: none;
}
@ -564,6 +599,16 @@ watch(filePath, () => {
svg {
width: 30px;
height: 30px;
&:hover {
:deep(rect) {
&:first-of-type {
fill: rgb(255 255 255 / 10%);
}
}
}
}
@media screen and (width <= 600px) {

View File

@ -3,16 +3,20 @@
<template>
<div class="options">
<div class="options__item" @click="onDistribution">
<MapIcon />
<p class="options__item__label">Distribution</p>
</div>
<div class="options__item" @click="onViewDetails">
<DetailsIcon />
<p class="options__item__label">View details</p>
</div>
<div class="options__item" @click="onDownload">
<SmallDownloadIcon />
<DownloadIcon />
<p class="options__item__label">Download</p>
</div>
<div class="options__item" @click="onShare">
<SmallShareIcon />
<ShareIcon />
<p class="options__item__label">Share</p>
</div>
<div class="options__item" @click="onDelete">
@ -24,11 +28,13 @@
<script setup lang="ts">
import DetailsIcon from '@/../static/images/browser/galleryView/details.svg';
import SmallDownloadIcon from '@/../static/images/browser/galleryView/downloadSmall.svg';
import SmallShareIcon from '@/../static/images/browser/galleryView/shareSmall.svg';
import DownloadIcon from '@/../static/images/browser/galleryView/download.svg';
import ShareIcon from '@/../static/images/browser/galleryView/share.svg';
import DeleteIcon from '@/../static/images/browser/galleryView/delete.svg';
import MapIcon from '@/../static/images/browser/galleryView/map.svg';
const props = defineProps<{
onDistribution: () => void
onViewDetails: () => void
onDownload: () => void
onShare: () => void
@ -59,6 +65,15 @@ const props = defineProps<{
cursor: pointer;
padding: 16px;
svg {
width: 18px;
height: 18px;
:deep(path) {
fill: var(--c-grey-6);
}
}
&__label {
margin-left: 16px;
font-size: 14px;

View File

@ -24,7 +24,7 @@
</p>
</div>
<div class="modal__item last">
<p class="modal__item__label">Saved in</p>
<p class="modal__item__label">Bucket</p>
<p class="modal__item__label right" :title="bucket">{{ bucket }}</p>
</div>
<VButton

View File

@ -8,7 +8,9 @@
<component :is="notification.icon" />
</div>
<div class="notification-wrap__content-area__message-area">
<p class="notification-wrap__content-area__message">{{ notification.message }}</p>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="notification.messageNode" v-html="notification.messageNode" />
<p v-else class="notification-wrap__content-area__message">{{ notification.message }}</p>
<p v-if="isTimeoutMentioned && notOnSettingsPage" class="notification-wrap__content-area__account-msg">
To change this go to your
@ -212,3 +214,16 @@ onMounted((): void => {
right: 0;
}
</style>
<style lang="scss">
.message-title,
.message-info {
font-family: 'font_medium', sans-serif;
font-size: 14px;
line-height: 20px;
}
.message-info {
font-family: 'font_regular', sans-serif;
}
</style>

View File

@ -51,11 +51,12 @@ export const useNotificationsStore = defineStore('notifications', () => {
}
}
function notifySuccess(message: string): void {
function notifySuccess(message: string, messageNode?: string): void {
const notification = new DelayedNotification(
() => deleteNotification(notification.id),
NOTIFICATION_TYPES.SUCCESS,
message,
messageNode,
);
addNotification(notification);

View File

@ -29,13 +29,15 @@ export class DelayedNotification {
public readonly type: string;
public readonly message: string;
public readonly messageNode: string | undefined;
public readonly style: { backgroundColor: string };
public readonly icon: string;
constructor(callback: () => void, type: string, message: string) {
constructor(callback: () => void, type: string, message: string, messageNode?: string) {
this.callback = callback;
this.type = type;
this.message = message;
this.messageNode = messageNode;
this.id = getId();
this.remainingTime = 3000;
this.start();

View File

@ -10,9 +10,9 @@ import { useNotificationsStore } from '@/store/modules/notificationsStore';
export class Notificator {
public constructor() {}
public success(message: string): void {
public success(message: string, messageNode?: string): void {
const notificationsStore = useNotificationsStore();
notificationsStore.notifySuccess(message);
notificationsStore.notifySuccess(message, messageNode);
}
public error(message: string, source: AnalyticsErrorEventSource | null): void {

View File

@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.34467 12.3291L8.32317 12.3084L4.51004 8.49529C4.22047 8.20572 4.22047 7.73624 4.51004 7.44668C4.79254 7.16417 5.24629 7.15728 5.53715 7.426L5.55865 7.44668L8.13077 10.0188V1.64147C8.13077 1.23197 8.46274 0.899994 8.87225 0.899994C9.27177 0.899994 9.59749 1.21597 9.61314 1.61165L9.61373 1.64147V9.96951L12.1363 7.44668C12.4188 7.16417 12.8725 7.15728 13.1634 7.426L13.1849 7.44668C13.4674 7.72918 13.4743 8.18293 13.2056 8.47378L13.1849 8.49529L9.37178 12.3084C9.08928 12.5909 8.63553 12.5978 8.34467 12.3291ZM17.0999 15.6399C17.0999 16.0494 16.7679 16.3814 16.3584 16.3814H1.66364C1.25413 16.3814 0.922161 16.0494 0.922161 15.6399C0.922161 15.2304 1.25413 14.8984 1.66364 14.8984H16.3584C16.7679 14.8984 17.0999 15.2304 17.0999 15.6399ZM1.64138 16.3251C1.23187 16.3251 0.899902 15.9932 0.899902 15.5836V12.6177C0.899902 12.2082 1.23187 11.8762 1.64138 11.8762C2.05089 11.8762 2.38286 12.2082 2.38286 12.6177V15.5836C2.38286 15.9932 2.05089 16.3251 1.64138 16.3251ZM16.3362 16.3251C15.9267 16.3251 15.5947 15.9932 15.5947 15.5836V12.6177C15.5947 12.2082 15.9267 11.8762 16.3362 11.8762C16.7457 11.8762 17.0776 12.2082 17.0776 12.6177V15.5836C17.0776 15.9932 16.7457 16.3251 16.3362 16.3251Z" fill="#56606D"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,3 +0,0 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.899902 10.2748L0.90046 10.0499C0.912227 8.17735 1.11148 7.2084 1.63376 6.22302C1.88564 5.7478 2.1999 5.32245 2.57213 4.95345C2.8578 4.67025 3.31897 4.67226 3.60217 4.95793C3.88537 5.24361 3.88336 5.70477 3.59769 5.98797C3.33072 6.25262 3.10436 6.55901 2.92085 6.90522C2.51381 7.67318 2.36139 8.43362 2.35673 10.1486L2.35661 10.2727L2.35756 10.4354C2.37118 11.9799 2.51601 12.7231 2.87188 13.4277L2.92085 13.5222C3.27705 14.1942 3.79503 14.7169 4.46009 15.0758L4.53351 15.1146C5.26816 15.4949 6.02413 15.6386 7.66549 15.6432L10.2833 15.6433L10.5226 15.6415C11.9718 15.6239 12.6929 15.482 13.3665 15.1434L13.4385 15.1064L13.496 15.0758C14.161 14.7169 14.679 14.1942 15.0352 13.5222C15.4423 12.7542 15.5947 11.9938 15.5993 10.2789L15.5995 10.1547L15.5985 9.99206C15.5849 8.44757 15.4401 7.70431 15.0842 6.99972L15.0352 6.90522C14.8776 6.60781 14.6883 6.3398 14.4689 6.10242C14.1959 5.80702 14.214 5.34621 14.5094 5.07316C14.8048 4.80012 15.2656 4.81823 15.5386 5.11363C15.8223 5.42048 16.0685 5.76244 16.2767 6.13895L16.3241 6.22645L16.3582 6.29151C16.8372 7.21947 17.0316 8.15897 17.0541 9.88337L17.0562 10.1526L17.0556 10.3776C17.0438 12.2501 16.8446 13.219 16.3223 14.2044C15.8444 15.1061 15.1445 15.8233 14.2567 16.3198L14.1843 16.3596L14.1198 16.3939L14.026 16.4422C13.1181 16.8995 12.1737 17.0823 10.465 17.0989L10.2854 17.1H7.7483L7.5658 17.0994C5.70918 17.0873 4.74662 16.8856 3.7683 16.3577C2.87375 15.875 2.16288 15.1688 1.67133 14.2739L1.63195 14.201L1.59792 14.1359C1.09449 13.1608 0.905433 12.1729 0.899902 10.2748ZM5.66171 3.94368L5.68201 3.92256L8.49125 1.11332C8.76875 0.835821 9.21447 0.829053 9.50018 1.09302L9.5213 1.11332L12.3305 3.92256C12.615 4.207 12.615 4.66817 12.3305 4.95261C12.053 5.23011 11.6073 5.23688 11.3216 4.97291L11.3005 4.95261L9.71029 3.36237V11.5915C9.71029 11.9937 9.3842 12.3198 8.98194 12.3198C8.58949 12.3198 8.26953 12.0094 8.25416 11.6208L8.25358 11.5915V3.41084L6.71207 4.95261C6.43456 5.23011 5.98885 5.23688 5.70314 4.97291L5.68201 4.95261C5.40451 4.6751 5.39774 4.22939 5.66171 3.94368Z" fill="#56606D"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB