Skip to content

Commit

Permalink
web/satellite/vuetify-poc: add authentication pages
Browse files Browse the repository at this point in the history
This change copies over the new authentication UIs from the static
vuetify repository.

Change-Id: I06ea7dabbde2a091f524fbcdc8cb1eff08c90a74
  • Loading branch information
wilfred-asomanii committed Nov 3, 2023
1 parent 48877c0 commit 52b3ffd
Show file tree
Hide file tree
Showing 12 changed files with 662 additions and 0 deletions.
16 changes: 16 additions & 0 deletions web/satellite/vuetify-poc/src/layouts/default/Auth.vue
@@ -0,0 +1,16 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-app>
<auth-bar />
<default-view />
</v-app>
</template>

<script setup lang="ts">
import { VApp } from 'vuetify/components';
import AuthBar from './AuthBar.vue';
import DefaultView from './View.vue';
</script>
90 changes: 90 additions & 0 deletions web/satellite/vuetify-poc/src/layouts/default/AuthBar.vue
@@ -0,0 +1,90 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-app-bar :elevation="0">
<v-app-bar-title class="mr-1">
<v-img
v-if="theme.global.current.value.dark"
src="@poc/assets/logo-dark.svg"
width="120"
alt="Storj Logo"
/>
<v-img
v-else
src="@poc/assets/logo.svg"
width="120"
alt="Storj Logo"
/>
</v-app-bar-title>

<template #append>
<!-- Theme Toggle Light/Dark Mode -->
<v-btn-toggle
v-model="activeTheme"
mandatory
border
inset
density="comfortable"
class="pa-1"
>
<v-tooltip text="Light Theme" location="bottom">
<template #activator="{ props }">
<v-btn
v-bind="props"
rounded="xl"
density="comfortable"
size="small"
class="px-4"
icon
aria-label="Toggle Light Theme"
@click="toggleTheme('light')"
>
<v-icon icon="mdi-weather-sunny" height="24" width="24" />
</v-btn>
</template>
</v-tooltip>

<v-tooltip text="Dark Theme" location="bottom">
<template #activator="{ props }">
<v-btn
v-bind="props"
rounded="xl"
density="comfortable"
size="small"
class="px-4"
icon
aria-label="Toggle Dark Theme"
@click="toggleTheme('dark')"
>
<v-icon icon="mdi-weather-night" height="24" width="24" />
</v-btn>
</template>
</v-tooltip>
</v-btn-toggle>
</template>
</v-app-bar>
</template>

<script setup lang="ts">
import { useTheme } from 'vuetify';
import { ref, watch } from 'vue';
import { VAppBar, VAppBarTitle, VBtn, VBtnToggle, VIcon, VImg, VMenu, VTooltip } from 'vuetify/components';
const theme = useTheme();
const activeTheme = ref(0);
const drawer = ref(true);
const menu = ref(false);
function toggleTheme(newTheme: string): void {
if ((newTheme === 'dark' && theme.global.current.value.dark) || (newTheme === 'light' && !theme.global.current.value.dark)) {
return;
}
theme.global.name.value = newTheme;
localStorage.setItem('theme', newTheme); // Store the selected theme in localStorage
}
watch(() => theme.global.current.value.dark, (newVal: boolean) => {
activeTheme.value = newVal ? 1 : 0;
});
</script>
51 changes: 51 additions & 0 deletions web/satellite/vuetify-poc/src/router/index.ts
Expand Up @@ -27,6 +27,57 @@ const routes: RouteRecordRaw[] = [
path: '/',
redirect: { path: '/projects' }, // redirect
},
{
path: '/',
component: () => import('@poc/layouts/default/Auth.vue'),
children: [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "Login" */ '@poc/views/Login.vue'),
},
{
path: '/login-2fa',
name: 'Login 2FA',
component: () => import(/* webpackChunkName: "Login 2FA" */ '@poc/views/Login2FA.vue'),
},
{
path: '/login-2fa-recovery',
name: 'Login 2FA Recovery Code',
component: () => import(/* webpackChunkName: "Login 2FA Recovery Code" */ '@poc/views/Login2FARecovery.vue'),
},
{
path: '/signup',
name: 'Signup',
component: () => import(/* webpackChunkName: "Signup" */ '@poc/views/Signup.vue'),
},
{
path: '/signup-confirmation',
name: 'Signup Confirmation',
component: () => import(/* webpackChunkName: "SignupConfirmation" */ '@poc/views/SignupConfirmation.vue'),
},
{
path: '/password-reset',
name: 'Password Reset',
component: () => import(/* webpackChunkName: "PasswordReset" */ '@poc/views/PasswordReset.vue'),
},
{
path: '/password-reset-confirmation',
name: 'Password Reset Confirmation',
component: () => import(/* webpackChunkName: "PasswordResetConfirmation" */ '@poc/views/PasswordResetConfirmation.vue'),
},
{
path: '/password-reset-new',
name: 'Password Reset New',
component: () => import(/* webpackChunkName: "PasswordResetNew" */ '@poc/views/PasswordResetNew.vue'),
},
{
path: '/password-reset-new-confirmation',
name: 'Password Reset New Confirmation',
component: () => import(/* webpackChunkName: "PasswordResetNewConfirmation" */ '@poc/views/PasswordResetNewConfirmation.vue'),
},
],
},
{
path: '/account',
component: () => import('@poc/layouts/default/Account.vue'),
Expand Down
89 changes: 89 additions & 0 deletions web/satellite/vuetify-poc/src/views/Login.vue
@@ -0,0 +1,89 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-container class="fill-height">
<v-row align="top" justify="center">
<v-col cols="12" sm="9" md="7" lg="5">
<v-card title="Log into your account" rounded="xlg" class="pa-2 pa-sm-7">
<v-card-text>
<v-form class="pt-4">
<v-select
v-model="select"
label="Satellite"
:items="items"
item-title="satellite"
:hint="`Recommended for ${select.hint}.`"
persistent-hint
return-object
chips
class="mb-5"
>
<!-- <template v-slot:prepend-inner>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 1C12.6387 1 15.0122 2.13558 16.6584 3.94469C16.2663 3.78243 15.8365 3.69291 15.3858 3.69291C15.2442 3.69291 15.1046 3.70176 14.9676 3.71892C13.6027 2.63772 11.8767 1.99213 10 1.99213C7.56843 1.99213 5.38999 3.07588 3.92135 4.78671L6.65807 4.7867C8.12561 4.7867 9.31529 5.97638 9.31529 7.44392C9.31529 8.89649 8.14976 10.0768 6.7029 10.1008L6.65807 10.1011H5.49148C5.13354 10.1011 4.84338 10.3913 4.84338 10.7492C4.84338 11.0978 5.11847 11.382 5.46337 11.3968L5.49148 11.3974H5.71832C6.97472 11.3974 7.9959 12.4044 8.01869 13.6554L8.01908 13.7305C8.01908 15.0048 6.99757 16.0404 5.72877 16.0633L5.68591 16.0637L4.76948 16.0638C6.17266 17.2752 8.00077 18.0079 10 18.0079C11.5512 18.0079 12.9994 17.5668 14.226 16.8032L13.4719 16.8032C11.8673 16.8032 10.5664 15.5023 10.5664 13.8976C10.5664 12.3093 11.8408 11.0187 13.4229 10.9925L13.4719 10.9921H15.8814C16.2728 10.9921 16.59 10.6748 16.59 10.2835C16.59 10.2329 16.5847 10.1835 16.5747 10.136C16.8942 10.0138 17.1903 9.84377 17.4539 9.63464C17.5366 9.83469 17.5822 10.0539 17.5822 10.2835C17.5822 11.2083 16.8439 11.9608 15.9246 11.9837L15.8814 11.9843L13.4801 11.9842L13.4393 11.9845C12.3966 12.0018 11.5585 12.853 11.5585 13.8976C11.5585 14.9397 12.3916 15.7872 13.428 15.8105L13.4719 15.811H14.8362L15.6005 15.7237C17.086 14.27 18.0079 12.2427 18.0079 10C18.0079 9.70782 17.9922 9.4193 17.9617 9.13523C18.3221 8.69615 18.5725 8.1632 18.6705 7.57862C18.8852 8.34894 19 9.16106 19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10C1 5.02944 5.02944 1 10 1ZM6.65807 5.77883L3.61383 5.77893L3.59538 5.78299C3.43495 5.81918 3.27795 5.85566 3.12436 5.8924C2.40541 7.09338 1.99213 8.49842 1.99213 10C1.99213 11.9246 2.6711 13.6907 3.80259 15.0717L5.7109 15.0713C6.4279 15.0584 7.00634 14.4827 7.02643 13.7738L7.02697 13.7357L7.02673 13.6734C7.01399 12.9741 6.45254 12.4099 5.75642 12.39L5.71832 12.3895H5.49148L5.44224 12.3887L5.42106 12.388C4.54466 12.3506 3.85125 11.6287 3.85125 10.7492C3.85125 9.85731 4.56318 9.13166 5.44979 9.10954L5.49148 9.10902L6.64986 9.10905L6.68649 9.10878C7.59384 9.09377 8.32316 8.35301 8.32316 7.44392C8.32316 6.53847 7.60043 5.80181 6.70038 5.77936L6.65807 5.77883ZM15.3858 5.46457C16.2469 5.46457 16.9449 6.16258 16.9449 7.02362C16.9449 7.88466 16.2469 8.58268 15.3858 8.58268C14.5248 8.58268 13.8268 7.88466 13.8268 7.02362C13.8268 6.16258 14.5248 5.46457 15.3858 5.46457Z" fill="currentColor"/>
</svg>
</template> -->
</v-select>

<v-text-field
label="Email address"
placeholder="Enter your email"
name="email"
type="email"
flat
clearable
required
>
<!-- <template v-slot:prepend-inner>
<v-icon
icon="mdi-email-outline"
/>
</template> -->
</v-text-field>

<v-text-field
v-model="password"
label="Password"
placeholder="Enter your password"
color="secondary"
:type="showPassword ? 'text' : 'password'"
:append-inner-icon="showPassword ? 'mdi-eye-outline' : 'mdi-eye-off-outline'"
@click:append-inner="showPassword = !showPassword"
>
<!-- <template v-slot:prepend-inner>
<v-icon
icon="mdi-key-outline"
/>
</template> -->
</v-text-field>

<v-btn color="primary" size="large" block router-link to="/login-2fa">
Continue
</v-btn>
</v-form>
</v-card-text>
</v-card>
<p class="mt-7 text-center text-body-2">Forgot your password? <router-link class="link" to="/password-reset">Reset password</router-link></p>
<p class="mt-5 text-center text-body-2">Don't have an account? <router-link class="link" to="/signup">Sign Up</router-link></p>
</v-col>
</v-row>
</v-container>
</template>

<script setup lang="ts">
import { VBtn, VCard, VCardText, VCol, VContainer, VForm, VRow, VSelect, VTextField } from 'vuetify/components';
import { ref } from 'vue';
const valid = ref(false);
const checked = ref(false);
const showPassword = ref(false);
const email = ref('');
const password = ref('');
const select = ref({ satellite: 'US1', hint: 'North and South America' });
const items = ref([
{ satellite: 'US1', hint: 'North and South America' },
{ satellite: 'EU1', hint: 'Europe and Africa' },
{ satellite: 'AP1', hint: 'Asia and Australia' },
]);
</script>
50 changes: 50 additions & 0 deletions web/satellite/vuetify-poc/src/views/Login2FA.vue
@@ -0,0 +1,50 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-container class="fill-height">
<v-row align="top" justify="center">
<v-col cols="12" sm="10" md="7" lg="5">
<v-card title="Enter your 2FA code" class="pa-2 pa-sm-7">
<v-card-text>
<p>Enter the 6 digit code from your two factor authenticator application to continue.</p>
<v-form>
<v-card class="my-4" rounded="lg" color="secondary" variant="outlined">
<v-otp-input v-model="otp" :loading="loading" autofocus class="my-2" />
</v-card>

<v-btn
router-link to="/projects"
:disabled="otp.length < 6"
color="primary"
block
>
<span v-if="otp.length === 0">6 digits left</span>

<span v-else-if="otp.length < 6">
{{ 6 - otp.length }}
digits left
</span>

<span v-else>
Verify
</span>
</v-btn>
</v-form>
</v-card-text>
</v-card>
<p class="pt-9 text-center text-body-2">Or use a <router-link class="link" to="/login-2fa-recovery">recovery code</router-link></p>
<p class="pt-6 text-center text-body-2">Not a member? <router-link class="link" to="/signup">Signup</router-link></p>
</v-col>
</v-row>
</v-container>
</template>

<script setup lang="ts">
import { VBtn, VCard, VCardText, VCol, VContainer, VForm, VRow } from 'vuetify/components';
import { VOtpInput } from 'vuetify/labs/components';
import { ref } from 'vue';
const loading = ref(false);
const otp = ref('');
</script>
30 changes: 30 additions & 0 deletions web/satellite/vuetify-poc/src/views/Login2FARecovery.vue
@@ -0,0 +1,30 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

<template>
<v-container class="fill-height">
<v-row align="top" justify="center">
<v-col cols="12" sm="10" md="7" lg="5">
<v-card title="Enter your recovery code" class="pa-2 pa-sm-7">
<v-card-text>
<p>Enter one of your recovery codes to continue.</p>
<v-form>
<v-text-field
label="Recovery Code"
class="mt-5"
/>
<v-btn color="primary" size="large" block router-link to="/projects">
Continue
</v-btn>
</v-form>
</v-card-text>
</v-card>
<p class="pt-6 text-center text-body-2">Not a member? <router-link class="link" to="/signup">Signup</router-link></p>
</v-col>
</v-row>
</v-container>
</template>

<script setup lang="ts">
import { VBtn, VCard, VCardText, VCol, VContainer, VForm, VRow, VTextField } from 'vuetify/components';
</script>

0 comments on commit 52b3ffd

Please sign in to comment.