web/satellite: responsiveness and accessibility fixes for new access grant flow
Fixed responsiveness and accessibility for new access grant flow. Change-Id: Ie39c807a702995610d240e19cf5dfd2c8a51d860
This commit is contained in:
parent
4362761fc7
commit
e9c4d1151f
@ -607,12 +607,22 @@ onMounted(async () => {
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
width: 280px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--c-grey-2);
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin-left: 16px;
|
||||
font-family: 'font_bold', sans-serif;
|
||||
@ -620,6 +630,11 @@ onMounted(async () => {
|
||||
line-height: 31px;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--c-black);
|
||||
text-align: left;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,12 @@ const props = withDefaults(defineProps<{
|
||||
align-items: center;
|
||||
column-gap: 16px;
|
||||
display: flex;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
flex-direction: column-reverse;
|
||||
column-gap: unset;
|
||||
row-gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -4,12 +4,24 @@
|
||||
<template>
|
||||
<div v-click-outside="closePicker" class="date-picker">
|
||||
<ul class="date-picker__column">
|
||||
<li class="date-picker__column__item" @click="onOneDayClick">24 Hours</li>
|
||||
<li class="date-picker__column__item" @click="onOneWeekClick">1 Week</li>
|
||||
<li class="date-picker__column__item" @click="onOneMonthClick">1 month</li>
|
||||
<li class="date-picker__column__item" @click="onSixMonthsClick">6 Months</li>
|
||||
<li class="date-picker__column__item" @click="onOneYearClick">1 Year</li>
|
||||
<li class="date-picker__column__item" @click="onForeverClick">No end date</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onOneDayClick" @keyup.space="onOneDayClick">
|
||||
24 Hours
|
||||
</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onOneWeekClick" @keyup.space="onOneWeekClick">
|
||||
1 Week
|
||||
</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onOneMonthClick" @keyup.space="onOneMonthClick">
|
||||
1 month
|
||||
</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onSixMonthsClick" @keyup.space="onSixMonthsClick">
|
||||
6 Months
|
||||
</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onOneYearClick" @keyup.space="onOneYearClick">
|
||||
1 Year
|
||||
</li>
|
||||
<li class="date-picker__column__item" tabindex="0" @click="onForeverClick" @keyup.space="onForeverClick">
|
||||
No end date
|
||||
</li>
|
||||
</ul>
|
||||
<VDatePicker :on-date-pick="onCustomDatePick" />
|
||||
</div>
|
||||
@ -132,11 +144,26 @@ function onOneYearClick(): void {
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
left: -90px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
flex-direction: column;
|
||||
width: 320px;
|
||||
left: -78px;
|
||||
}
|
||||
|
||||
&__column {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
columns: 2;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__item {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
@ -151,9 +178,5 @@ function onOneYearClick(): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -5,8 +5,10 @@
|
||||
<div class="date-select">
|
||||
<div
|
||||
class="date-select__toggle-container"
|
||||
tabindex="0"
|
||||
aria-roledescription="select-date"
|
||||
@click.stop="togglePicker"
|
||||
@keyup.space="togglePicker"
|
||||
>
|
||||
<h1 class="date-select__toggle-container__label">{{ notAfterLabel }}</h1>
|
||||
<ExpandIcon />
|
||||
|
@ -57,5 +57,9 @@ const props = withDefaults(defineProps<{
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid #376fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
<template>
|
||||
<div class="radio">
|
||||
<input :id="id || label" :checked="checked" type="radio" @change="onCheck">
|
||||
<input :id="id || label" tabindex="0" :checked="checked" type="radio" @change="onCheck">
|
||||
<label class="radio__label" :for="id || label">{{ label }}</label>
|
||||
<VInfo class="radio__info">
|
||||
<template #icon>
|
||||
<InfoIcon class="radio__info__icon" />
|
||||
<template #icon="{onSpace}">
|
||||
<InfoIcon tabindex="0" class="radio__info__icon" @keyup.space="onSpace" />
|
||||
</template>
|
||||
<template #message>
|
||||
<p class="radio__info__message">{{ info }}</p>
|
||||
@ -50,6 +50,7 @@ const props = withDefaults(defineProps<{
|
||||
line-height: 20px;
|
||||
color: var(--c-black);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__info {
|
||||
@ -74,6 +75,11 @@ const props = withDefaults(defineProps<{
|
||||
cursor: default;
|
||||
filter: none;
|
||||
transform: rotate(-180deg);
|
||||
|
||||
@media screen and (max-width: 530px) {
|
||||
left: unset;
|
||||
right: -5px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.info__box__message) {
|
||||
@ -88,5 +94,9 @@ const props = withDefaults(defineProps<{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-bottom: -3px;
|
||||
|
||||
@media screen and (max-width: 530px) {
|
||||
margin-right: 245px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -9,11 +9,17 @@
|
||||
</label>
|
||||
<label class="toggle__label" :for="id || label">{{ label }}</label>
|
||||
<template v-if="onShowHideAll">
|
||||
<ChevronIcon class="toggle__chevron" :class="{'toggle__chevron--up': allShown}" @click="onShowHideAll" />
|
||||
<ChevronIcon
|
||||
tabindex="0"
|
||||
class="toggle__chevron"
|
||||
:class="{'toggle__chevron--up': allShown}"
|
||||
@click="onShowHideAll"
|
||||
@keyup.space="onShowHideAll"
|
||||
/>
|
||||
</template>
|
||||
<VInfo v-if="slots.infoMessage" class="toggle__info">
|
||||
<template #icon>
|
||||
<InfoIcon class="toggle__info__icon" />
|
||||
<template #icon="{onSpace}">
|
||||
<InfoIcon tabindex="0" class="toggle__info__icon" @keyup.space="onSpace" />
|
||||
</template>
|
||||
<template #message>
|
||||
<slot name="infoMessage" />
|
||||
@ -67,6 +73,10 @@ const props = withDefaults(defineProps<{
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
&:focus + span {
|
||||
outline: 2px solid #376fff;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@ -117,6 +127,7 @@ const props = withDefaults(defineProps<{
|
||||
line-height: 20px;
|
||||
color: var(--c-black);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__info {
|
||||
@ -147,6 +158,11 @@ const props = withDefaults(defineProps<{
|
||||
cursor: default;
|
||||
filter: none;
|
||||
transform: rotate(-180deg);
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
left: unset;
|
||||
right: -83px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.info__box__message) {
|
||||
@ -161,5 +177,9 @@ const props = withDefaults(defineProps<{
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-bottom: -3px;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
margin-right: 88px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -15,9 +15,15 @@
|
||||
</VInfo>
|
||||
</div>
|
||||
<div class="blured-container__wrap" :class="{justify: !isMnemonic}">
|
||||
<p v-if="isMnemonic" class="blured-container__wrap__mnemonic">{{ value }}</p>
|
||||
<p v-else class="blured-container__wrap__text">{{ value }}</p>
|
||||
<div v-if="!isMnemonic" v-clipboard:copy="value" class="blured-container__wrap__copy" @click="onCopy">
|
||||
<p v-if="isMnemonic" tabindex="0" class="blured-container__wrap__mnemonic" @keyup.space="onCopy">{{ value }}</p>
|
||||
<p v-else tabindex="0" class="blured-container__wrap__text" @keyup.space="onCopy">{{ value }}</p>
|
||||
<div
|
||||
v-if="!isMnemonic"
|
||||
tabindex="0"
|
||||
class="blured-container__wrap__copy"
|
||||
@click="onCopy"
|
||||
@keyup.space="onCopy"
|
||||
>
|
||||
<CopyIcon />
|
||||
</div>
|
||||
<div v-if="!isValueShown" class="blured-container__wrap__blur">
|
||||
@ -76,6 +82,7 @@ function showValue(): void {
|
||||
* Holds on copy click logic.
|
||||
*/
|
||||
function onCopy(): void {
|
||||
navigator.clipboard.writeText(props.value);
|
||||
analytics.eventTriggered(AnalyticsEvent.COPY_TO_CLIPBOARD_CLICKED);
|
||||
notify.success(`${props.title} was copied successfully`);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
<ButtonsContainer label="Save your access grant">
|
||||
<template #leftButton>
|
||||
<VButton
|
||||
v-clipboard:copy="accessGrant"
|
||||
:label="isCopied ? 'Copied' : 'Copy'"
|
||||
width="100%"
|
||||
height="40px"
|
||||
@ -104,6 +103,7 @@ const hasNextStep = computed((): boolean => {
|
||||
* Saves passphrase to clipboard.
|
||||
*/
|
||||
function onCopy(): void {
|
||||
navigator.clipboard.writeText(props.accessGrant);
|
||||
isCopied.value = true;
|
||||
analytics.eventTriggered(AnalyticsEvent.COPY_TO_CLIPBOARD_CLICKED);
|
||||
notify.success(`Access Grant was copied successfully`);
|
||||
|
@ -25,31 +25,31 @@
|
||||
you use for this project. This allows you to manage existing data you have uploaded with the
|
||||
same passphrase."
|
||||
/>
|
||||
<div class="encryption__radios__advanced" @click="toggleAdvanced">
|
||||
<div tabindex="0" class="encryption__radios__advanced" @click="toggleAdvanced" @keyup.space="toggleAdvanced">
|
||||
<h2 class="encryption__radios__advanced__label">Advanced</h2>
|
||||
<ChevronIcon
|
||||
class="encryption__radios__advanced__chevron"
|
||||
:class="{'encryption__radios__advanced__chevron--up': advancedShown}"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="advancedShown">
|
||||
<Radio
|
||||
id="newPassphrase"
|
||||
:checked="isSelectedOption(_PassphraseOption.EnterNewPassphrase)"
|
||||
:on-check="() => setOption(_PassphraseOption.EnterNewPassphrase)"
|
||||
label="Enter a new passphrase"
|
||||
info="Create this access with a new encryption passphrase that you can enter on the next step.
|
||||
The access will not be able to manage any existing data."
|
||||
/>
|
||||
<Radio
|
||||
id="generatePassphrase"
|
||||
:checked="isSelectedOption(_PassphraseOption.GenerateNewPassphrase)"
|
||||
:on-check="() => setOption(_PassphraseOption.GenerateNewPassphrase)"
|
||||
label="Generate 12-word passphrase"
|
||||
info="Create this access with a new encryption passphrase that will be generated for you on
|
||||
the next step. The access will not be able to manage any existing data."
|
||||
/>
|
||||
</template>
|
||||
<Radio
|
||||
v-show="advancedShown"
|
||||
id="new passphrase"
|
||||
:checked="isSelectedOption(_PassphraseOption.EnterNewPassphrase)"
|
||||
:on-check="() => setOption(_PassphraseOption.EnterNewPassphrase)"
|
||||
label="Enter a new passphrase"
|
||||
info="Create this access with a new encryption passphrase that you can enter on the next step.
|
||||
The access will not be able to manage any existing data."
|
||||
/>
|
||||
<Radio
|
||||
v-show="advancedShown"
|
||||
id="generate passphrase"
|
||||
:checked="isSelectedOption(_PassphraseOption.GenerateNewPassphrase)"
|
||||
:on-check="() => setOption(_PassphraseOption.GenerateNewPassphrase)"
|
||||
label="Generate 12-word passphrase"
|
||||
info="Create this access with a new encryption passphrase that will be generated for you on
|
||||
the next step. The access will not be able to manage any existing data."
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #info>
|
||||
@ -193,9 +193,17 @@ function isSelectedOption(option: PassphraseOption): boolean {
|
||||
align-items: flex-start;
|
||||
margin-top: 16px;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
min-width: 32px;
|
||||
margin-right: 16px;
|
||||
|
||||
@media screen and (max-width: 460px) {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&__message {
|
||||
|
@ -9,7 +9,6 @@
|
||||
<ButtonsContainer label="Save your CLI access">
|
||||
<template #leftButton>
|
||||
<VButton
|
||||
v-clipboard:copy="`${satelliteAddress} ${apiKey}`"
|
||||
:label="isCopied ? 'Copied' : 'Copy all'"
|
||||
width="100%"
|
||||
height="40px"
|
||||
@ -102,6 +101,7 @@ const satelliteAddress = MetaUtils.getMetaContent('satellite-nodeurl');
|
||||
* Saves CLI access to clipboard.
|
||||
*/
|
||||
function onCopy(): void {
|
||||
navigator.clipboard.writeText(`${satelliteAddress} ${props.apiKey}`);
|
||||
isCopied.value = true;
|
||||
analytics.eventTriggered(AnalyticsEvent.COPY_TO_CLIPBOARD_CLICKED);
|
||||
notify.success(`CLI access was copied successfully`);
|
||||
|
@ -53,7 +53,7 @@
|
||||
<div v-if="selectedBuckets.length" class="choose__selected-container">
|
||||
<div v-for="bucket in selectedBuckets" :key="bucket" class="choose__selected-container__item">
|
||||
<p class="choose__selected-container__item__label">{{ bucket }}</p>
|
||||
<CloseIcon @click="() => onUnselectBucket(bucket)" />
|
||||
<CloseIcon tabindex="0" @click="() => onUnselectBucket(bucket)" @keyup.space="() => onUnselectBucket(bucket)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="choose__search-container">
|
||||
@ -65,8 +65,10 @@
|
||||
<p
|
||||
v-for="bucket in bucketsList"
|
||||
:key="bucket"
|
||||
tabindex="0"
|
||||
class="choose__bucket-results__item"
|
||||
@click="() => selectBucket(bucket)"
|
||||
@keyup.space="() => selectBucket(bucket)"
|
||||
>
|
||||
{{ bucket }}
|
||||
</p>
|
||||
@ -81,7 +83,13 @@
|
||||
<ContainerWithIcon :icon-and-title="FUNCTIONAL_CONTAINER_ICON_AND_TITLE[FunctionalContainer.EndDate]">
|
||||
<template #functional>
|
||||
<div class="choose__date-selection">
|
||||
<p v-if="!settingDate && !notAfter" class="choose__date-selection__label" @click="toggleSettingDate">
|
||||
<p
|
||||
v-if="!settingDate && !notAfter"
|
||||
tabindex="0"
|
||||
class="choose__date-selection__label"
|
||||
@click="toggleSettingDate"
|
||||
@keyup.space="toggleSettingDate"
|
||||
>
|
||||
Add Date (optional)
|
||||
</p>
|
||||
<EndDateSelection
|
||||
|
@ -15,6 +15,7 @@
|
||||
<p class="create__toggles__info">
|
||||
Keys to upload, delete, and view your project's data.
|
||||
<a
|
||||
tabindex="0"
|
||||
class="create__toggles__info__link"
|
||||
href="https://docs.storj.io/dcs/concepts/access/access-grants"
|
||||
target="_blank"
|
||||
@ -32,6 +33,7 @@
|
||||
<p class="create__toggles__info">
|
||||
Generates access key, secret key, and endpoint to use in your S3-supporting application.
|
||||
<a
|
||||
tabindex="0"
|
||||
class="create__toggles__info__link"
|
||||
href="https://docs.storj.io/dcs/api-reference/s3-compatible-gateway"
|
||||
target="_blank"
|
||||
@ -49,6 +51,7 @@
|
||||
<p class="create__toggles__info">
|
||||
Creates access grant to run in the command line.
|
||||
<a
|
||||
tabindex="0"
|
||||
class="create__toggles__info__link"
|
||||
href="https://docs.storj.io/dcs/getting-started/quickstart-uplink-cli/generate-access-grants-and-tokens/generate-a-token"
|
||||
target="_blank"
|
||||
@ -140,6 +143,10 @@ const isButtonDisabled = computed((): boolean => {
|
||||
&:visited {
|
||||
color: var(--c-white);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
<ButtonsContainer label="Save your S3 credentials">
|
||||
<template #leftButton>
|
||||
<VButton
|
||||
v-clipboard:copy="`${credentials.accessKeyId} ${credentials.secretKey} ${credentials.endpoint}`"
|
||||
:label="isCopied ? 'Copied' : 'Copy all'"
|
||||
width="100%"
|
||||
height="40px"
|
||||
@ -108,6 +107,9 @@ const analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
|
||||
* Saves CLI access to clipboard.
|
||||
*/
|
||||
function onCopy(): void {
|
||||
const { credentials } = props;
|
||||
navigator.clipboard.writeText(`${credentials.accessKeyId} ${credentials.secretKey} ${credentials.endpoint}`);
|
||||
|
||||
isCopied.value = true;
|
||||
analytics.eventTriggered(AnalyticsEvent.COPY_TO_CLIPBOARD_CLICKED);
|
||||
notify.success(`S3 credentials were copied successfully`);
|
||||
|
@ -32,8 +32,8 @@
|
||||
:class="containerClassName"
|
||||
:style="style"
|
||||
tabindex="0"
|
||||
@click="onPress"
|
||||
@keyup.enter="onPress"
|
||||
@click="handleClick"
|
||||
@keyup.enter="handleClick"
|
||||
>
|
||||
<slot name="icon" />
|
||||
<div v-if="isWhiteGreen" class="greenCheck">✓</div>
|
||||
@ -135,6 +135,15 @@ const containerClassName = computed((): string => {
|
||||
const style = computed(() => {
|
||||
return { width: props.width, height: props.height, borderRadius: props.borderRadius, fontSize: props.fontSize };
|
||||
});
|
||||
|
||||
/**
|
||||
* This wrapper handles button's disabled state for accessibility purposes.
|
||||
*/
|
||||
function handleClick(): void {
|
||||
if (!props.isDisabled) {
|
||||
props.onPress();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<template>
|
||||
<div class="info" @mouseenter="toggleVisibility" @mouseleave="toggleVisibility">
|
||||
<slot name="icon" />
|
||||
<slot name="icon" :on-space="toggleVisibility" />
|
||||
<div v-if="isVisible" class="info__box">
|
||||
<div class="info__box__arrow" />
|
||||
<div class="info__box__message">
|
||||
|
Loading…
Reference in New Issue
Block a user