major UI update
This commit is contained in:
parent
72cd5d20f9
commit
c8d11d0d11
269
css/main.css
269
css/main.css
@ -17,8 +17,8 @@ body {
|
||||
body {
|
||||
--accent-color: #256eff;
|
||||
--text-color: 20, 20, 20;
|
||||
--background-color: 240, 240, 240;
|
||||
--foreground-color: 250, 250, 250;
|
||||
--foreground-color: 252, 253, 255;
|
||||
--background-color: 241, 243, 248;
|
||||
--danger-color: rgb(255, 75, 75);
|
||||
--green: #1cad59;
|
||||
scrollbar-width: thin;
|
||||
@ -28,16 +28,13 @@ body {
|
||||
transition: background-color 0.3s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body[data-theme=dark] {
|
||||
--accent-color: #86afff;
|
||||
--accent-color: #90b8f8;
|
||||
--text-color: 220, 220, 220;
|
||||
--background-color: 10, 10, 10;
|
||||
--foreground-color: 24, 24, 24;
|
||||
--foreground-color: 27, 28, 29;
|
||||
--background-color: 21, 22, 22;
|
||||
--danger-color: rgb(255, 106, 106);
|
||||
--green: #00e676;
|
||||
}
|
||||
@ -65,6 +62,14 @@ a:focus-visible {
|
||||
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
||||
}
|
||||
|
||||
a.button {
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: 0.3rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
@ -458,6 +463,20 @@ h3 {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
|
||||
.page {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-layout {
|
||||
display: grid;
|
||||
gap: 1.5rem 0;
|
||||
grid-template-columns: 1.5rem minmax(0, 1fr) 1.5rem;
|
||||
align-content: flex-start;
|
||||
}
|
||||
.page-layout > * {
|
||||
grid-column: 2/3;
|
||||
}
|
||||
|
||||
#confirmation_popup,
|
||||
#prompt_popup {
|
||||
flex-direction: column;
|
||||
@ -492,7 +511,6 @@ h3 {
|
||||
width: 100%;
|
||||
padding: 0 1.5rem;
|
||||
align-items: center;
|
||||
grid-auto-flow: column;
|
||||
}
|
||||
|
||||
.popup__header__close {
|
||||
@ -501,17 +519,51 @@ h3 {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#landing > section {
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 8vw 0;
|
||||
}
|
||||
#landing h1 {
|
||||
font-size: clamp(2rem, 5vw, 5rem);
|
||||
}
|
||||
|
||||
#sign_in,
|
||||
#sign_up {
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
}
|
||||
#sign_in section,
|
||||
#sign_up section {
|
||||
margin-top: -8rem;
|
||||
width: min(24rem, 100%);
|
||||
}
|
||||
#sign_in sm-form,
|
||||
#sign_up sm-form {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
#sign_up .h2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
#sign_up .card {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
#sign_up h5 {
|
||||
font-weight: 500;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
#sign_up .warning {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
#main_header {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
#main_card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
transition: background-color 0.3s;
|
||||
#main_header a {
|
||||
color: rgba(var(--text-color), 1);
|
||||
}
|
||||
|
||||
#pages_container {
|
||||
@ -519,63 +571,6 @@ h3 {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#main_navbar {
|
||||
display: flex;
|
||||
background: rgba(var(--text-color), 0.03);
|
||||
}
|
||||
#main_navbar.hide-away {
|
||||
position: absolute;
|
||||
}
|
||||
#main_navbar ul {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#main_navbar ul li {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.5rem 0.3rem;
|
||||
color: var(--text-color);
|
||||
font-size: 0.7rem;
|
||||
border-radius: 0.3rem;
|
||||
}
|
||||
.nav-item .icon {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.nav-item__title {
|
||||
margin-top: 0.3rem;
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
}
|
||||
.nav-item--active {
|
||||
color: var(--accent-color);
|
||||
}
|
||||
.nav-item--active .icon {
|
||||
fill: var(--accent-color);
|
||||
transform: translateY(50%);
|
||||
}
|
||||
.nav-item--active .nav-item__title {
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
.nav-item__indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 2rem;
|
||||
height: 0.3rem;
|
||||
background: var(--accent-color);
|
||||
border-radius: 1rem 1rem 0 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.password-field label {
|
||||
display: flex;
|
||||
}
|
||||
@ -605,37 +600,70 @@ h3 {
|
||||
|
||||
.primary-action {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.8rem 1rem;
|
||||
gap: 0.5rem;
|
||||
white-space: normal;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: transparent;
|
||||
border: thin solid rgba(var(--text-color), 0.3);
|
||||
min-width: 5rem;
|
||||
max-width: 6rem;
|
||||
text-align: center;
|
||||
}
|
||||
.primary-action .icon {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
.primary-action:not(:last-of-type) {
|
||||
margin-right: 0.5rem;
|
||||
|
||||
#user {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
#saved_ids_list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.saved-id {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.saved-id__initials {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
align-content: flex-start;
|
||||
padding: 1.5rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
color: rgba(var(--background-color), 1);
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 1rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
.saved-id__title {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#wallet_section {
|
||||
background-color: rgba(var(--text-color), 0.03);
|
||||
.card {
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
#transactions_list {
|
||||
#history > *,
|
||||
#wallet_history > * {
|
||||
width: min(60ch, 100%);
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
#token_transactions {
|
||||
flex-direction: column;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
@ -681,6 +709,9 @@ h3 {
|
||||
.transaction__amount.sent::before {
|
||||
content: "-";
|
||||
}
|
||||
.transaction__amount.received {
|
||||
color: var(--green);
|
||||
}
|
||||
.transaction__amount.received::before {
|
||||
content: "+";
|
||||
}
|
||||
@ -814,67 +845,31 @@ h3 {
|
||||
--width: 24rem;
|
||||
}
|
||||
|
||||
.page-layout {
|
||||
grid-template-columns: 1fr 90vw 1fr;
|
||||
}
|
||||
|
||||
.popup__header {
|
||||
grid-column: 1/-1;
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
|
||||
#main_card {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-areas: "nav header" "nav main";
|
||||
position: relative;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05), 0 1rem 3rem rgba(0, 0, 0, 0.2);
|
||||
background-color: rgba(var(--foreground-color), 0.9);
|
||||
}
|
||||
|
||||
#main_header {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
#pages_container {
|
||||
grid-area: main;
|
||||
}
|
||||
|
||||
#main_navbar {
|
||||
grid-area: nav;
|
||||
border-top: none;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
#main_navbar ul {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem;
|
||||
}
|
||||
#main_navbar ul li:last-of-type {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
.nav-item__indicator {
|
||||
width: 0.25rem;
|
||||
height: 50%;
|
||||
left: 0;
|
||||
border-radius: 0 1rem 1rem 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
#user {
|
||||
padding: 1.5rem 8vmax;
|
||||
grid-template-columns: 1fr 20rem;
|
||||
align-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 56rem) {
|
||||
#main_card {
|
||||
height: 80vh;
|
||||
width: 56rem;
|
||||
|
||||
.saved-id {
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: rgba(var(--text-color), 0.03);
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
#wallet_section {
|
||||
grid-area: 1/2/3/3;
|
||||
}
|
||||
}
|
||||
@media (any-hover: hover) {
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
266
css/main.scss
266
css/main.scss
@ -17,8 +17,8 @@ body {
|
||||
body {
|
||||
--accent-color: #256eff;
|
||||
--text-color: 20, 20, 20;
|
||||
--background-color: 240, 240, 240;
|
||||
--foreground-color: 250, 250, 250;
|
||||
--foreground-color: 252, 253, 255;
|
||||
--background-color: 241, 243, 248;
|
||||
--danger-color: rgb(255, 75, 75);
|
||||
--green: #1cad59;
|
||||
scrollbar-width: thin;
|
||||
@ -28,16 +28,13 @@ body {
|
||||
transition: background-color 0.3s;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body[data-theme="dark"] {
|
||||
--accent-color: #86afff;
|
||||
--accent-color: #90b8f8;
|
||||
--text-color: 220, 220, 220;
|
||||
--background-color: 10, 10, 10;
|
||||
--foreground-color: 24, 24, 24;
|
||||
--foreground-color: 27, 28, 29;
|
||||
--background-color: 21, 22, 22;
|
||||
--danger-color: rgb(255, 106, 106);
|
||||
--green: #00e676;
|
||||
sm-popup::part(popup) {
|
||||
@ -63,6 +60,13 @@ a {
|
||||
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
||||
}
|
||||
}
|
||||
a.button {
|
||||
padding: 0.4rem 0.6rem;
|
||||
border-radius: 0.3rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
user-select: none;
|
||||
@ -426,6 +430,18 @@ h3 {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
}
|
||||
.page {
|
||||
height: 100%;
|
||||
}
|
||||
.page-layout {
|
||||
display: grid;
|
||||
gap: 1.5rem 0;
|
||||
grid-template-columns: 1.5rem minmax(0, 1fr) 1.5rem;
|
||||
align-content: flex-start;
|
||||
& > * {
|
||||
grid-column: 2/3;
|
||||
}
|
||||
}
|
||||
#confirmation_popup,
|
||||
#prompt_popup {
|
||||
flex-direction: column;
|
||||
@ -455,7 +471,6 @@ h3 {
|
||||
width: 100%;
|
||||
padding: 0 1.5rem;
|
||||
align-items: center;
|
||||
grid-auto-flow: column;
|
||||
}
|
||||
|
||||
.popup__header__close {
|
||||
@ -463,78 +478,57 @@ h3 {
|
||||
margin-left: -0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
#landing {
|
||||
& > section {
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 8vw 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: clamp(2rem, 5vw, 5rem);
|
||||
}
|
||||
}
|
||||
|
||||
#sign_in,
|
||||
#sign_up {
|
||||
justify-items: center;
|
||||
align-content: center;
|
||||
section {
|
||||
margin-top: -8rem;
|
||||
width: min(24rem, 100%);
|
||||
}
|
||||
sm-form {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
#sign_up {
|
||||
.h2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.card {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
h5 {
|
||||
font-weight: 500;
|
||||
color: rgba(var(--text-color), 0.8);
|
||||
}
|
||||
.warning {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
#main_header {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
#main_card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
transition: background-color 0.3s;
|
||||
a {
|
||||
color: rgba(var(--text-color), 1);
|
||||
}
|
||||
}
|
||||
#pages_container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#main_navbar {
|
||||
display: flex;
|
||||
background: rgba(var(--text-color), 0.03);
|
||||
&.hide-away {
|
||||
position: absolute;
|
||||
}
|
||||
ul {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
li {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.nav-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.5rem 0.3rem;
|
||||
color: var(--text-color);
|
||||
font-size: 0.7rem;
|
||||
border-radius: 0.3rem;
|
||||
.icon {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
&__title {
|
||||
margin-top: 0.3rem;
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
}
|
||||
&--active {
|
||||
color: var(--accent-color);
|
||||
.icon {
|
||||
fill: var(--accent-color);
|
||||
transform: translateY(50%);
|
||||
}
|
||||
.nav-item__title {
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
&__indicator {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 2rem;
|
||||
height: 0.3rem;
|
||||
background: var(--accent-color);
|
||||
border-radius: 1rem 1rem 0 0;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.password-field {
|
||||
label {
|
||||
display: flex;
|
||||
@ -562,37 +556,68 @@ h3 {
|
||||
}
|
||||
.primary-action {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.8rem 1rem;
|
||||
gap: 0.5rem;
|
||||
white-space: normal;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
// background-color: rgba(var(--text-color), 0.06);
|
||||
background-color: transparent;
|
||||
border: thin solid rgba(var(--text-color), 0.3);
|
||||
min-width: 5rem;
|
||||
max-width: 6rem;
|
||||
text-align: center;
|
||||
.icon {
|
||||
fill: var(--accent-color);
|
||||
}
|
||||
&:not(:last-of-type) {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
#user {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
#saved_ids_list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
.saved-id {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
padding: 0.5rem 0;
|
||||
&__initials {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
color: rgba(var(--background-color), 1);
|
||||
background-color: var(--accent-color);
|
||||
border-radius: 1rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
&__title {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
align-content: flex-start;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
#wallet_section {
|
||||
background-color: rgba(var(--text-color), 0.03);
|
||||
.card {
|
||||
background-color: rgba(var(--foreground-color), 1);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
#transactions_list {
|
||||
#history,
|
||||
#wallet_history {
|
||||
& > * {
|
||||
width: min(60ch, 100%);
|
||||
justify-self: center;
|
||||
}
|
||||
}
|
||||
#token_transactions {
|
||||
flex-direction: column;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
@ -638,6 +663,7 @@ h3 {
|
||||
}
|
||||
}
|
||||
&.received {
|
||||
color: var(--green);
|
||||
&::before {
|
||||
content: "+";
|
||||
}
|
||||
@ -751,65 +777,27 @@ h3 {
|
||||
sm-popup {
|
||||
--width: 24rem;
|
||||
}
|
||||
.page-layout {
|
||||
grid-template-columns: 1fr 90vw 1fr;
|
||||
}
|
||||
.popup__header {
|
||||
grid-column: 1/-1;
|
||||
padding: 1rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
#main_card {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-areas: "nav header" "nav main";
|
||||
position: relative;
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05),
|
||||
0 1rem 3rem rgba(0, 0, 0, 0.2);
|
||||
// backdrop-filter: blur(2rem);
|
||||
background-color: rgba(var(--foreground-color), 0.9);
|
||||
}
|
||||
#main_header {
|
||||
grid-area: header;
|
||||
}
|
||||
#pages_container {
|
||||
grid-area: main;
|
||||
}
|
||||
|
||||
#main_navbar {
|
||||
grid-area: nav;
|
||||
border-top: none;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
ul {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem;
|
||||
|
||||
li:last-of-type {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.nav-item {
|
||||
aspect-ratio: 1/1;
|
||||
&__indicator {
|
||||
width: 0.25rem;
|
||||
height: 50%;
|
||||
left: 0;
|
||||
border-radius: 0 1rem 1rem 0;
|
||||
bottom: auto;
|
||||
}
|
||||
}
|
||||
#user {
|
||||
padding: 1.5rem 8vmax;
|
||||
grid-template-columns: 1fr 20rem;
|
||||
align-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 56rem) {
|
||||
#main_card {
|
||||
height: 80vh;
|
||||
width: 56rem;
|
||||
.saved-id {
|
||||
padding: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
background-color: rgba(var(--text-color), 0.03);
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
#wallet_section {
|
||||
grid-area: 1/2/3/3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
385
index.html
385
index.html
@ -45,7 +45,7 @@
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="onLoadStartUp()">
|
||||
<body onload="onLoadStartUp()" class="hide">
|
||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||
<sm-popup id="confirmation_popup">
|
||||
<h4 id="confirm_title"></h4>
|
||||
@ -55,16 +55,11 @@
|
||||
<sm-button variant="no-outline" class="submit-btn">OK</sm-button>
|
||||
</div>
|
||||
</sm-popup>
|
||||
<div id="loader" class="grid gap-1 text-center">
|
||||
<sm-spinner></sm-spinner>
|
||||
<h4>Loading RanchiMall Pay</h4>
|
||||
</div>
|
||||
<div id="main_card" class="hide">
|
||||
<header id="main_header" class="flex align-center space-between">
|
||||
<div class="flex align-center">
|
||||
<svg class="icon" style="margin-right:0.3rem" viewBox="0 0 96 108"
|
||||
style="enable-background:new 0 0 90.5 106.3;" xml:space="preserve">
|
||||
<path d="M90.2,102.5c-2.4-8.2-9.9-14.5-27.4-23.1c-7.1-3.5-11.8-6.2-14-8.3c-1.7-1.6-3.5-4-4.2-5.5c-0.7-1.7-0.7-5.5,0-7.5
|
||||
<header id="main_header" class="flex align-center gap-1">
|
||||
<a href="#/home" class="flex align-center flex-1">
|
||||
<svg class="icon" style="margin-right:0.3rem" viewBox="0 0 96 108"
|
||||
style="enable-background:new 0 0 90.5 106.3;" xml:space="preserve">
|
||||
<path d="M90.2,102.5c-2.4-8.2-9.9-14.5-27.4-23.1c-7.1-3.5-11.8-6.2-14-8.3c-1.7-1.6-3.5-4-4.2-5.5c-0.7-1.7-0.7-5.5,0-7.5
|
||||
c1.3-3.6,2.6-5.2,12.9-15.1c6.2-5.9,9.3-10.3,11.1-15.5c0.7-2.1,0.8-7.6,0.2-9.4C66.5,12,61.7,6.7,53.7,1.6c-3-1.9-4.3-2.1-4.3-0.8
|
||||
c0,0.3-0.5,1.4-1,2.4l-1,1.8l-2.8-1.9c-1.5-1.1-3.4-2.2-4.1-2.6c-1.3-0.7-2.4-0.6-2.4,0.2c0,0.3-1.4,3.4-2,4.4
|
||||
c0,0.1-0.4-0.1-0.9-0.4c-6.1-4.4-8.7-5.5-8.7-3.9c0,0.7-1.8,4.2-4,7.9C16,19.5,9.4,24.9,2.6,24.9c-3,0-2.9-0.1-2,3.4
|
||||
@ -86,14 +81,79 @@
|
||||
c-1.2,1.7-6.5,5.7-8.6,6.5v0c-1.1,0.4-2.8,0.8-3.9,0.9L24.9,25l2.1-2.6c2.5-3.1,5.1-7,7-10.4c0.7-1.4,1.4-2.5,1.5-2.6
|
||||
c0.3-0.4,1.7,1.4,3,4.1l1.5,3L39.3,17.4z M44.6,10c-0.7,1.2-1.4,2.1-1.5,2.1c-0.1,0-1.5-1.4-3-3l-2.8-3l0.6-1.5
|
||||
c1.1-2.6,1.3-2.7,3.4-1c1.9,1.5,4.5,3.8,4.5,4.1C45.8,7.8,45.3,8.9,44.6,10z" />
|
||||
</svg>
|
||||
<h4>RanchiMall Pay</h4>
|
||||
</svg>
|
||||
<h4>RanchiMall Pay</h4>
|
||||
</a>
|
||||
<theme-toggle></theme-toggle>
|
||||
<a href="#/settings" class="icon-only">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M12 6c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2m0 10c2.7 0 5.8 1.29 6 2H6c.23-.72 3.31-2 6-2m0-12C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 10c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
|
||||
</svg>
|
||||
</a>
|
||||
</header>
|
||||
<section id="pages_container">
|
||||
<article id="landing" class="page page-layout hide">
|
||||
<section class="grid justify-center gap-1">
|
||||
<h1 class="h1">Send.request</h1>
|
||||
<div class="flex gap-0-5">
|
||||
<a href="#/sign_up" class="button">Sign up</a>
|
||||
<a href="#/sign_in" class="button button--primary">Sign in</a>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
<article id="sign_in" class="page page-layout hide">
|
||||
<section>
|
||||
<h1 class="h2">Sign In</h1>
|
||||
<p>Welcome back, glad to see you again</p>
|
||||
<sm-form>
|
||||
<sm-input id="private_key_field" type="password" placeholder="FLO private key"
|
||||
error-text="Private key is invalid" data-private-key required></sm-input>
|
||||
<sm-button id="sign_in_button" variant="primary" disabled>Sign In</sm-button>
|
||||
</sm-form>
|
||||
<p>
|
||||
New here? <a href="#/sign_up">get your FLO login credentials</a>
|
||||
</p>
|
||||
</section>
|
||||
</article>
|
||||
<article id="sign_up" class="page page-layout hide">
|
||||
<section class="grid">
|
||||
<h1 class="h2">FLO credentials</h1>
|
||||
<p>Get your FLO credentials to use RanchiMall Pay and all RanchiMall FLO apps. </p>
|
||||
<div class="grid gap-1-5 card">
|
||||
<div class="grid gap-0-5">
|
||||
<h5>FLO ID</h5>
|
||||
<sm-copy id="generated_flo_id"></sm-copy>
|
||||
</div>
|
||||
<div class="grid gap-0-5">
|
||||
<h5>Private key</h5>
|
||||
<sm-copy id="generated_private_key"></sm-copy>
|
||||
</div>
|
||||
</div>
|
||||
<sm-button id="sign_up_button" variant="primary">Sign in with these credentials</sm-button>
|
||||
<strong class="warning">
|
||||
Keep your private key secure and don't share with anyone.
|
||||
Once lost there is no way to recover private key.
|
||||
</strong>
|
||||
</section>
|
||||
</article>
|
||||
<div id="loading" class="page flex align-center justify-center">
|
||||
<div class="grid gap-1 text-center">
|
||||
<sm-spinner></sm-spinner>
|
||||
<h4>Loading RanchiMall Pay</h4>
|
||||
</div>
|
||||
<theme-toggle></theme-toggle>
|
||||
</header>
|
||||
<section id="pages_container" class="gap-2">
|
||||
<section id="home" class="page hide">
|
||||
<div id="user" class="hide grid gap-2 user-element">
|
||||
</div>
|
||||
<section id="home" class="page hide">
|
||||
<div id="user" class="hide grid gap-1-5 user-element">
|
||||
<div class="card grid gap-1-5">
|
||||
<div class="flex align-center space-between">
|
||||
<h4>Quick actions </h4>
|
||||
<a href="#/history" class="button flex align-center">
|
||||
See history
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<button class="button primary-action" onclick="showTokenTransfer('send')">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||
@ -117,7 +177,9 @@
|
||||
Request
|
||||
</button>
|
||||
</div>
|
||||
<section id="wallet_section" class="grid gap-1-5">
|
||||
</div>
|
||||
<section id="wallet_section" class="card grid gap-1-5">
|
||||
<div class="flex align-center space-between">
|
||||
<h4 class="flex align-center">
|
||||
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg"
|
||||
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
@ -132,156 +194,141 @@
|
||||
</svg>
|
||||
Wallet
|
||||
</h4>
|
||||
<div class="grid gap-0-5">
|
||||
<h5>Balance</h5>
|
||||
<h1 class="h1" id="rupee_balance"></h1>
|
||||
</div>
|
||||
<div class="grid gap-1">
|
||||
<sm-input id="request_cashier_amount" type="number" name="amount" placeholder="Amount"
|
||||
<a href="#/wallet_history" class="button">See History</a>
|
||||
</div>
|
||||
<div class="grid gap-0-5">
|
||||
<h5>Balance</h5>
|
||||
<h1 class="h1" id="rupee_balance"></h1>
|
||||
</div>
|
||||
<div class="grid gap-1">
|
||||
<!-- <sm-input id="request_cashier_amount" type="number" name="amount" placeholder="Amount"
|
||||
animate>
|
||||
</sm-input>
|
||||
<div class="flex">
|
||||
<button class="primary-action flex-1" onclick="userUI.requestTokenFromCashier()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg"
|
||||
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<rect fill="none" height="24" width="24" />
|
||||
<g>
|
||||
<path
|
||||
d="M19.83,7.5l-2.27-2.27c0.07-0.42,0.18-0.81,0.32-1.15C17.96,3.9,18,3.71,18,3.5C18,2.67,17.33,2,16.5,2 c-1.64,0-3.09,0.79-4,2l-5,0C4.46,4,2,6.46,2,9.5S4.5,21,4.5,21l5.5,0v-2h2v2l5.5,0l1.68-5.59L22,14.47V7.5H19.83z M13,9H8V7h5V9z M16,11c-0.55,0-1-0.45-1-1c0-0.55,0.45-1,1-1s1,0.45,1,1C17,10.55,16.55,11,16,11z" />
|
||||
</g>
|
||||
</svg>
|
||||
Deposit
|
||||
</button>
|
||||
<button class="primary-action flex-1" onclick="userUI.withdrawCashFromCashier()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
</sm-input> -->
|
||||
<div class="flex">
|
||||
<button class="flex gap-0-5 flex-1" onclick="userUI.requestTokenFromCashier()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
||||
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<rect fill="none" height="24" width="24" />
|
||||
<g>
|
||||
<path
|
||||
d="M19 14V6c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zm-9-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-6v11c0 1.1-.9 2-2 2H4v-2h17V7h2z" />
|
||||
</svg>
|
||||
Withdraw
|
||||
</button>
|
||||
</div>
|
||||
d="M19.83,7.5l-2.27-2.27c0.07-0.42,0.18-0.81,0.32-1.15C17.96,3.9,18,3.71,18,3.5C18,2.67,17.33,2,16.5,2 c-1.64,0-3.09,0.79-4,2l-5,0C4.46,4,2,6.46,2,9.5S4.5,21,4.5,21l5.5,0v-2h2v2l5.5,0l1.68-5.59L22,14.47V7.5H19.83z M13,9H8V7h5V9z M16,11c-0.55,0-1-0.45-1-1c0-0.55,0.45-1,1-1s1,0.45,1,1C17,10.55,16.55,11,16,11z" />
|
||||
</g>
|
||||
</svg>
|
||||
Deposit
|
||||
</button>
|
||||
<button class="flex gap-0-5 flex-1" onclick="userUI.withdrawCashFromCashier()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||
width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M19 14V6c0-1.1-.9-2-2-2H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zm-9-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm13-6v11c0 1.1-.9 2-2 2H4v-2h17V7h2z" />
|
||||
</svg>
|
||||
Withdraw
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<section id="cashier" class=" grid gap-1 hide admin-element">
|
||||
<h4>Requests</h4>
|
||||
<ul id="cashier_request_list" class="observe-empty-state"></ul>
|
||||
</div>
|
||||
</section>
|
||||
<div class="card">
|
||||
<div class="flex align-center space-between">
|
||||
<h4>Saved IDs</h4>
|
||||
<button class="button" onclick="showPopup('save_id_popup')">Save FLO ID</button>
|
||||
</div>
|
||||
<ul id="saved_ids_list" class="observe-empty-state"></ul>
|
||||
<div class="empty-state">
|
||||
<h4>No requests to process</h4>
|
||||
<h4>No saved FLO IDs</h4>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="history" class="page hide grid gap-1">
|
||||
<h4>Transactions history</h4>
|
||||
<ul id="token_transactions" class="observe-empty-state">
|
||||
</ul>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No transactions</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section id="activity" class="page hide grid gap-1">
|
||||
<h4>Activity</h4>
|
||||
<tab-header target="user_sections">
|
||||
<sm-tab>Wallet transactions</sm-tab>
|
||||
<sm-tab>Payment requests</sm-tab>
|
||||
</tab-header>
|
||||
<tab-panels id="user_sections">
|
||||
<section>
|
||||
<ul id="user-cashier-requests" class="observe-empty-state"></ul>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No transactions</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<ul id="user-money-requests" class="observe-empty-state"></ul>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No requests</h4>
|
||||
</div>
|
||||
</section>
|
||||
</tab-panels>
|
||||
</section>
|
||||
<section id="settings" class="page hide gap-2">
|
||||
<h4>Settings</h4>
|
||||
<section class="grid gap-1">
|
||||
<div class="grid">
|
||||
<h5>My FLO ID</h5>
|
||||
<sm-copy id="logged_in_user_id" style="font-size: 0.9rem;"></sm-copy>
|
||||
</div>
|
||||
<sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button>
|
||||
</section>
|
||||
<section class="admin-element grid gap-1">
|
||||
<h4>Change UPI ID</h4>
|
||||
<sm-form style="width: min(100%,24rem);">
|
||||
<sm-input id="upi_id" placeholder="UPI ID" pattern="[a-zA-Z0-9_]{3,}@[a-zA-Z]{3,}"
|
||||
error-text="Invalid UPI ID" animate required></sm-input>
|
||||
<button class="button button--primary cta justify-self-start" type="submit"
|
||||
onclick="changeUpi()">
|
||||
Change
|
||||
</button>
|
||||
</sm-form>
|
||||
</section>
|
||||
</div>
|
||||
<section id="cashier" class=" grid gap-1 hide admin-element">
|
||||
<h4>Requests</h4>
|
||||
<ul id="cashier_request_list" class="observe-empty-state"></ul>
|
||||
<div class="empty-state">
|
||||
<h4>No requests to process</h4>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<nav id="main_navbar">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#/home" class="nav-item interact">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||
width="24px" fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
|
||||
</svg>
|
||||
<span class="nav-item__title">Home</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/history" class="nav-item interact">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
||||
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<path d="M0,0h24v24H0V0z" fill="none" />
|
||||
<g>
|
||||
<path
|
||||
d="M19.5,3.5L18,2l-1.5,1.5L15,2l-1.5,1.5L12,2l-1.5,1.5L9,2L7.5,3.5L6,2v14H3v3c0,1.66,1.34,3,3,3h12c1.66,0,3-1.34,3-3V2 L19.5,3.5z M19,19c0,0.55-0.45,1-1,1s-1-0.45-1-1v-3H8V5h11V19z" />
|
||||
<rect height="2" width="6" x="9" y="7" />
|
||||
<rect height="2" width="2" x="16" y="7" />
|
||||
<rect height="2" width="6" x="9" y="10" />
|
||||
<rect height="2" width="2" x="16" y="10" />
|
||||
</g>
|
||||
</svg>
|
||||
<span class="nav-item__title">History</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/activity" class="nav-item interact user-element">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||
width="24px" fill="#000000">
|
||||
<path
|
||||
d="M11 21h-1l1-7H7.5c-.58 0-.57-.32-.38-.66.19-.34.05-.08.07-.12C8.48 10.94 10.42 7.54 13 3h1l-1 7h3.5c.49 0 .56.33.47.51l-.07.15C12.96 17.55 11 21 11 21z" />
|
||||
</svg>
|
||||
<span class="nav-item__title">Activity</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/settings" class="nav-item interact">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
||||
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||
<g>
|
||||
<path d="M0,0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z" />
|
||||
</g>
|
||||
</svg>
|
||||
<span class="nav-item__title">Settings</span>
|
||||
</button>
|
||||
</a>
|
||||
</li>
|
||||
<section id="history" class="page page-layout hide grid gap-1">
|
||||
<div class="grid gap-1" style="justify-items: flex-start;">
|
||||
<a href="#/home" class="button align-start">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
|
||||
</svg>
|
||||
</a>
|
||||
<h4>Transactions history</h4>
|
||||
</div>
|
||||
<ul id="token_transactions" class="observe-empty-state">
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No transactions</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section id="wallet_history" class="page page-layout hide">
|
||||
<div class="grid gap-1" style="justify-items: flex-start;">
|
||||
<a href="#/home" class="button align-start">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
|
||||
</svg>
|
||||
</a>
|
||||
<h4>Wallet history</h4>
|
||||
</div>
|
||||
<ul id="user-cashier-requests" class="observe-empty-state"></ul>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No transactions</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section id="activity" class="page page-layout hide">
|
||||
<h4>Activity</h4>
|
||||
<ul id="user-money-requests" class="observe-empty-state"></ul>
|
||||
<div class=" empty-state gap-1 justify-center text-center">
|
||||
<h4>No requests</h4>
|
||||
</div>
|
||||
</section>
|
||||
<section id="settings" class="page page-layout hide">
|
||||
<h4>Settings</h4>
|
||||
<section class="grid gap-1">
|
||||
<div class="grid">
|
||||
<h5>My FLO ID</h5>
|
||||
<sm-copy id="logged_in_user_id" style="font-size: 0.9rem;"></sm-copy>
|
||||
</div>
|
||||
<sm-button class="danger justify-self-start" onclick="signOut()">Sign out</sm-button>
|
||||
</section>
|
||||
<section class="admin-element grid gap-1">
|
||||
<h4>Change UPI ID</h4>
|
||||
<sm-form style="width: min(100%,24rem);">
|
||||
<sm-input id="upi_id" placeholder="UPI ID" pattern="[a-zA-Z0-9_]{3,}@[a-zA-Z]{3,}"
|
||||
error-text="Invalid UPI ID" animate required></sm-input>
|
||||
<button class="button button--primary cta justify-self-start" type="submit" onclick="changeUpi()">
|
||||
Change
|
||||
</button>
|
||||
</sm-form>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<!-- Popups -->
|
||||
<sm-popup id="save_id_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||
fill="#000000">
|
||||
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
||||
</svg>
|
||||
</button>
|
||||
<h4>Save FLO ID</h4>
|
||||
</header>
|
||||
<sm-form>
|
||||
<sm-input id="flo_id_to_save" placeholder="FLO ID" error-text="Invalid FLO ID" data-flo-id animate required
|
||||
autofocus>
|
||||
</sm-input>
|
||||
<sm-input id="flo_id_title_to_save" placeholder="Title" animate required></sm-input>
|
||||
<button class="button button--primary cta" onclick="userUI.saveId()" type="submit">Save</button>
|
||||
</sm-form>
|
||||
</sm-popup>
|
||||
<sm-popup id="token_transfer_popup">
|
||||
<header slot="header" class="popup__header">
|
||||
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
|
||||
@ -321,6 +368,15 @@
|
||||
</sm-popup>
|
||||
|
||||
<!-- templates -->
|
||||
<template id="saved_id_template">
|
||||
<li>
|
||||
<a class="saved-id interact" href="">
|
||||
<div class="saved-id__initials"></div>
|
||||
<span class="saved-id__title"></span>
|
||||
<!-- <sm-copy class="saved-id__flo-id"></sm-copy> -->
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
<template id="transaction_template">
|
||||
<li class="transaction grid">
|
||||
<div class="transaction__icon"></div>
|
||||
@ -370,7 +426,10 @@
|
||||
<script id="onLoadStartUp">
|
||||
function onLoadStartUp() {
|
||||
console.log("Starting the app! Please Wait!")
|
||||
floDapps.setCustomPrivKeyInput(getSignedIn)
|
||||
floDapps.setAppObjectStores({ savedIds: {} })
|
||||
floDapps.launchStartUp().then(result => {
|
||||
history.replaceState(null, null, " ")
|
||||
console.log(`Welcome ${myFloID}`);
|
||||
getRef('logged_in_user_id').value = myFloID;
|
||||
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
||||
@ -383,10 +442,10 @@
|
||||
console.log(result);
|
||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.remove('hide'))
|
||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.add('hide'))
|
||||
getRef('loader').classList.add('hide')
|
||||
getRef('main_card').classList.remove('hide')
|
||||
showPage(window.location.hash, { firstLoad: true })
|
||||
}).catch(error => console.error(error))
|
||||
} else {
|
||||
userUI.renderSavedIds()
|
||||
userUI.renderCashierRequests(User.cashierRequests);
|
||||
userUI.renderMoneyRequests(User.moneyRequests);
|
||||
User.init().then(result => {
|
||||
@ -394,12 +453,10 @@
|
||||
console.log("Cashiers:", cashierUPI);
|
||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hide'))
|
||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hide'))
|
||||
getRef('loader').classList.add('hide')
|
||||
getRef('main_card').classList.remove('hide')
|
||||
showPage(window.location.hash, { firstLoad: true })
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
renderAllTokenTransactions();
|
||||
showPage(window.location.hash, { firstLoad: true })
|
||||
}).catch(error => console.error(error))
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -885,9 +885,19 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
||||
push(message, options = {}) {
|
||||
const notification = this.createNotification(message, options);
|
||||
this.notificationPanel.append(notification);
|
||||
this.notificationPanel.animate(
|
||||
[
|
||||
{
|
||||
transform: `translateY(${notification.clientHeight}px)`,
|
||||
},
|
||||
{
|
||||
transform: `none`,
|
||||
},
|
||||
], this.animationOptions
|
||||
)
|
||||
notification.animate([
|
||||
{
|
||||
transform: `translateY(1rem)`,
|
||||
transform: `translateX(-1rem)`,
|
||||
opacity: '0'
|
||||
},
|
||||
{
|
||||
@ -905,7 +915,7 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
||||
opacity: '1'
|
||||
},
|
||||
{
|
||||
transform: `translateY(0.5rem)`,
|
||||
transform: `translateX(-1rem)`,
|
||||
opacity: '0'
|
||||
}
|
||||
], this.animationOptions).onfinish = () => {
|
||||
|
||||
175
scripts/fn_ui.js
175
scripts/fn_ui.js
@ -1,10 +1,10 @@
|
||||
/*jshint esversion: 6 */
|
||||
/*jshint esversion: 8 */
|
||||
const userUI = {};
|
||||
|
||||
userUI.requestTokenFromCashier = function () {
|
||||
let cashier = User.findCashier();
|
||||
if (!cashier)
|
||||
return alert("No cashier online");
|
||||
return notify("No cashier online", 'error');
|
||||
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
|
||||
//get UPI txid from user
|
||||
let upiTxID = prompt(`Send Rs. ${amount} to ${cashierUPI[cashier]} and enter UPI txid`);
|
||||
@ -19,7 +19,7 @@ userUI.requestTokenFromCashier = function () {
|
||||
userUI.withdrawCashFromCashier = function () {
|
||||
let cashier = User.findCashier();
|
||||
if (!cashier)
|
||||
return alert("No cashier online");
|
||||
return notify("No cashier online", 'error');
|
||||
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
|
||||
//get confirmation from user
|
||||
let upiID = prompt(`${amount} ${floGlobals.currency}# will be sent to ${cashier}. Enter UPI ID`);
|
||||
@ -86,6 +86,50 @@ userUI.renderMoneyRequests = function (requests, error = null) {
|
||||
getRef('user-money-requests').append(frag)
|
||||
}
|
||||
|
||||
userUI.renderSavedIds = async function () {
|
||||
floGlobals.savedIds = {}
|
||||
const frag = document.createDocumentFragment()
|
||||
const savedIds = await floCloudAPI.requestApplicationData('savedIds', { mostRecent: true, senderIDs: [myFloID], receiverID: myFloID });
|
||||
if (savedIds.length && await compactIDB.readData('savedIds', 'lastSyncTime') !== savedIds[0].time) {
|
||||
await compactIDB.clearData('savedIds');
|
||||
const dataToDecrypt = floCloudAPI.util.decodeMessage(savedIds[0].message)
|
||||
const data = JSON.parse(floCrypto.decryptData(dataToDecrypt, myPrivKey));
|
||||
console.log(data)
|
||||
for (let key in data) {
|
||||
floGlobals.savedIds[key] = data[key];
|
||||
compactIDB.addData('savedIds', data[key], key);
|
||||
}
|
||||
compactIDB.addData('savedIds', savedIds[0].time, 'lastSyncTime');
|
||||
} else {
|
||||
const idsToRender = await compactIDB.readAllData('savedIds');
|
||||
for (const key in idsToRender) {
|
||||
if (key !== 'lastSyncTime')
|
||||
floGlobals.savedIds[key] = idsToRender[key];
|
||||
}
|
||||
}
|
||||
console.log(floGlobals.savedIds)
|
||||
for (const key in floGlobals.savedIds) {
|
||||
frag.append(render.savedId(key, floGlobals.savedIds[key]));
|
||||
}
|
||||
getRef('saved_ids_list').append(frag);
|
||||
}
|
||||
|
||||
userUI.saveId = async function () {
|
||||
const floID = getRef('flo_id_to_save').value.trim();
|
||||
const title = getRef('flo_id_title_to_save').value.trim();
|
||||
const dataToSend = floCrypto.encryptData(JSON.stringify({ ...floGlobals.savedIds, [floID]: { title } }), myPubKey)
|
||||
floCloudAPI.sendApplicationData(dataToSend, 'savedIds', { receiverID: myFloID }).then(result => {
|
||||
console.log(result);
|
||||
floGlobals.savedIds[floID] = { title }
|
||||
notify(`Saved ${floID}`, 'success');
|
||||
getRef('saved_ids_list').append(render.savedId(floID, { title }));
|
||||
hidePopup();
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
notify(error, 'error');
|
||||
})
|
||||
}
|
||||
|
||||
userUI.payRequest = function (reqID) {
|
||||
let request = User.moneyRequests[reqID];
|
||||
getConfirmation('Pay?', { message: `Do you want to pay ${request.message.amount} to ${request.senderID}?` }).then(confirmation => {
|
||||
@ -188,66 +232,79 @@ function renderAllTokenTransactions() {
|
||||
getRef('token_transactions').innerHTML = ''
|
||||
const frag = document.createDocumentFragment();
|
||||
for (let txid in result.transactions) {
|
||||
frag.append(render.transactionCard(txid, tokenAPI.util.parseTxData(result.transactions[txid])))
|
||||
frag.append(render.transactionCard(txid, tokenAPI.util.parseTxData(result.transactions[txid])));
|
||||
}
|
||||
getRef('token_transactions').append(frag)
|
||||
}).catch(error => console.error(error))
|
||||
getRef('token_transactions').append(frag);
|
||||
}).catch(error => console.error(error));
|
||||
}
|
||||
|
||||
function getFloIdName(floID) {
|
||||
return floGlobals.savedIds[floID] ? floGlobals.savedIds[floID].title : floID;
|
||||
}
|
||||
|
||||
const render = {
|
||||
savedId(floID, details) {
|
||||
const { title } = details.hasOwnProperty('title') ? details : { title: details };
|
||||
const clone = getRef('saved_id_template').content.cloneNode(true).firstElementChild;
|
||||
clone.dataset.floId = floID;
|
||||
clone.querySelector('a').href = `#/saved&id=${floID}`;
|
||||
clone.querySelector('.saved-id__initials').textContent = title.charAt(0);
|
||||
clone.querySelector('.saved-id__title').textContent = title;
|
||||
return clone;
|
||||
},
|
||||
transactionCard(txid, transactionDetails) {
|
||||
const { time, sender, receiver, tokenAmount } = transactionDetails
|
||||
const { time, sender, receiver, tokenAmount } = transactionDetails;
|
||||
const clone = getRef('transaction_template').content.cloneNode(true).firstElementChild;
|
||||
clone.dataset.txid = txid
|
||||
clone.querySelector('.transaction__time').textContent = getFormattedTime(time * 1000)
|
||||
clone.querySelector('.transaction__amount').textContent = tokenAmount
|
||||
clone.dataset.txid = txid;
|
||||
clone.querySelector('.transaction__time').textContent = getFormattedTime(time * 1000);
|
||||
clone.querySelector('.transaction__amount').textContent = tokenAmount;
|
||||
if (sender === myFloID) {
|
||||
clone.querySelector('.transaction__amount').classList.add('sent')
|
||||
clone.querySelector('.transaction__receiver').textContent = `Sent to ${receiver || 'Myself'}`
|
||||
clone.querySelector('.transaction__icon').innerHTML = `<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5z"/></svg>`
|
||||
clone.querySelector('.transaction__amount').classList.add('sent');
|
||||
clone.querySelector('.transaction__receiver').textContent = `Sent to ${getFloIdName(receiver) || 'Myself'}`;
|
||||
clone.querySelector('.transaction__icon').innerHTML = `<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5z"/></svg>`;
|
||||
} else if (receiver === myFloID) {
|
||||
clone.querySelector('.transaction__amount').classList.add('received')
|
||||
clone.querySelector('.transaction__receiver').textContent = `Received from ${sender}`
|
||||
clone.querySelector('.transaction__icon').innerHTML = `<svg class="icon xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 5.41L18.59 4 7 15.59V9H5v10h10v-2H8.41z"/></svg>`
|
||||
clone.querySelector('.transaction__amount').classList.add('received');
|
||||
clone.querySelector('.transaction__receiver').textContent = `Received from ${getFloIdName(sender)}`;
|
||||
clone.querySelector('.transaction__icon').innerHTML = `<svg class="icon xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 5.41L18.59 4 7 15.59V9H5v10h10v-2H8.41z"/></svg>`;
|
||||
} else { //This should not happen unless API returns transaction that does not involve myFloID
|
||||
row.insertCell().textContent = tx.sender;
|
||||
row.insertCell().textContent = tx.receiver;
|
||||
}
|
||||
return clone
|
||||
return clone;
|
||||
},
|
||||
cashierRequestCard(details) {
|
||||
const { time, senderID, message: { mode }, note, tag, vectorClock } = details;
|
||||
const clone = getRef('cashier_request_template').content.cloneNode(true).firstElementChild;
|
||||
clone.id = vectorClock
|
||||
clone.id = vectorClock;
|
||||
const status = tag || note; //status tag for completed, note for rejected
|
||||
clone.querySelector('.cashier-request__requestor').textContent = senderID
|
||||
clone.querySelector('.cashier-request__time').textContent = getFormattedTime(time)
|
||||
clone.querySelector('.cashier-request__mode').textContent = mode
|
||||
clone.querySelector('.cashier-request__requestor').textContent = senderID;
|
||||
clone.querySelector('.cashier-request__time').textContent = getFormattedTime(time);
|
||||
clone.querySelector('.cashier-request__mode').textContent = mode;
|
||||
if (status)
|
||||
clone.querySelector('.cashier-request__status').textContent = status
|
||||
clone.querySelector('.cashier-request__status').textContent = status;
|
||||
else
|
||||
clone.querySelector('.cashier-request__status').innerHTML = `<button class="button" onclick="cashierUI.completeRequest('${vectorClock}')">Process</button>`
|
||||
return clone
|
||||
clone.querySelector('.cashier-request__status').innerHTML = `<button class="button" onclick="cashierUI.completeRequest('${vectorClock}')">Process</button>`;
|
||||
return clone;
|
||||
},
|
||||
walletRequestCard(details) {
|
||||
const { time, receiverID, message: { mode }, note, tag, vectorClock } = details;
|
||||
const clone = getRef('wallet_request_template').content.cloneNode(true).firstElementChild;
|
||||
clone.id = vectorClock
|
||||
clone.querySelector('.wallet-request__requestor').textContent = receiverID
|
||||
clone.querySelector('.wallet-request__time').textContent = getFormattedTime(time)
|
||||
clone.querySelector('.wallet-request__mode').textContent = mode === 'cash-to-token' ? 'Deposit' : 'Withdraw'
|
||||
clone.id = vectorClock;
|
||||
clone.querySelector('.wallet-request__requestor').textContent = receiverID;
|
||||
clone.querySelector('.wallet-request__time').textContent = getFormattedTime(time);
|
||||
clone.querySelector('.wallet-request__mode').textContent = mode === 'cash-to-token' ? 'Deposit' : 'Withdraw';
|
||||
let status = tag ? (tag + ":" + note) : (note || "PENDING");
|
||||
clone.querySelector('.wallet-request__status').textContent = status
|
||||
return clone
|
||||
clone.querySelector('.wallet-request__status').textContent = status;
|
||||
return clone;
|
||||
},
|
||||
paymentRequestCard(details) {
|
||||
const { time, senderID, message: { amount, remark }, note, vectorClock } = details;
|
||||
const clone = getRef('payment_request_template').content.cloneNode(true).firstElementChild;
|
||||
clone.id = vectorClock
|
||||
clone.querySelector('.payment-request__requestor').textContent = senderID
|
||||
clone.querySelector('.payment-request__time').textContent = getFormattedTime(time)
|
||||
clone.querySelector('.payment-request__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
|
||||
clone.querySelector('.payment-request__remark').textContent = remark
|
||||
clone.id = vectorClock;
|
||||
clone.querySelector('.payment-request__requestor').textContent = senderID;
|
||||
clone.querySelector('.payment-request__time').textContent = getFormattedTime(time);
|
||||
clone.querySelector('.payment-request__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' });
|
||||
clone.querySelector('.payment-request__remark').textContent = remark;
|
||||
|
||||
let status = note;
|
||||
if (status)
|
||||
@ -257,20 +314,20 @@ const render = {
|
||||
`<button class="button" onclick="userUI.payRequest('${vectorClock}')">Pay</button>
|
||||
<button class="button" onclick="userUI.declineRequest('${vectorClock}')">Decline</button>`;
|
||||
|
||||
return clone
|
||||
return clone;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let currentUserAction
|
||||
let currentUserAction;
|
||||
function showTokenTransfer(type) {
|
||||
getRef('tt_button').textContent = type;
|
||||
currentUserAction = type
|
||||
currentUserAction = type;
|
||||
if (type === 'send') {
|
||||
getRef('token_transfer__title').textContent = 'Send money to FLO ID';
|
||||
} else {
|
||||
getRef('token_transfer__title').textContent = 'Request money from FLO ID';
|
||||
}
|
||||
showPopup('token_transfer_popup')
|
||||
showPopup('token_transfer_popup');
|
||||
}
|
||||
|
||||
function executeUserAction() {
|
||||
@ -278,28 +335,46 @@ function executeUserAction() {
|
||||
amount = parseFloat(getRef('tt_amount').value),
|
||||
remark = getRef('tt_remark').value.trim();
|
||||
if (currentUserAction === 'send') {
|
||||
userUI.sendMoneyToUser(floID, amount, remark)
|
||||
userUI.sendMoneyToUser(floID, amount, remark);
|
||||
|
||||
} else {
|
||||
userUI.requestMoneyFromUser(floID, amount, remark)
|
||||
userUI.requestMoneyFromUser(floID, amount, remark);
|
||||
}
|
||||
}
|
||||
|
||||
function changeUpi() {
|
||||
const upiID = getRef('upi_id').value.trim()
|
||||
const upiID = getRef('upi_id').value.trim();
|
||||
Cashier.updateUPI(upiID).then(() => {
|
||||
notify('UPI ID updated successfully', 'success')
|
||||
notify('UPI ID updated successfully', 'success');
|
||||
}).catch(err => {
|
||||
notify(err, 'error')
|
||||
})
|
||||
notify(err, 'error');
|
||||
});
|
||||
}
|
||||
function getSignedIn() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
|
||||
showPage(window.location.hash);
|
||||
} else {
|
||||
location.hash = `#/sign_in`;
|
||||
}
|
||||
getRef('sign_in_button').onclick = () => {
|
||||
resolve(getRef('private_key_field').value.trim());
|
||||
getRef('private_key_field').value = '';
|
||||
showPage('loading');
|
||||
};
|
||||
getRef('sign_up_button').onclick = () => {
|
||||
resolve(getRef('generated_private_key').value.trim());
|
||||
getRef('generated_private_key').value = '';
|
||||
showPage('loading');
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave')
|
||||
.then(async (res) => {
|
||||
if (res) {
|
||||
await floDapps.clearCredentials()
|
||||
location.reload()
|
||||
await floDapps.clearCredentials();
|
||||
location.reload();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
@ -256,14 +256,17 @@ const pagesData = {
|
||||
params: {}
|
||||
}
|
||||
|
||||
let tempData
|
||||
async function showPage(targetPage, options = {}) {
|
||||
const { firstLoad, hashChange, isPreview } = options
|
||||
const { firstLoad, hashChange } = options
|
||||
let pageId
|
||||
let params = {}
|
||||
let searchParams
|
||||
if (targetPage === '') {
|
||||
pageId = 'home'
|
||||
if (typeof myFloID === "undefined") {
|
||||
pageId = 'sign_in'
|
||||
} else {
|
||||
pageId = 'home'
|
||||
}
|
||||
} else {
|
||||
if (targetPage.includes('/')) {
|
||||
if (targetPage.includes('?')) {
|
||||
@ -281,6 +284,7 @@ async function showPage(targetPage, options = {}) {
|
||||
pageId = targetPage
|
||||
}
|
||||
}
|
||||
if (typeof myFloID === "undefined" && !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
||||
if (searchParams) {
|
||||
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
||||
params = Object.fromEntries(urlSearchParams.entries());
|
||||
@ -291,126 +295,28 @@ async function showPage(targetPage, options = {}) {
|
||||
if (params)
|
||||
pagesData.params = params
|
||||
switch (pageId) {
|
||||
case 'sign_in':
|
||||
setTimeout(() => {
|
||||
getRef('private_key_field').focusIn()
|
||||
}, 0);
|
||||
targetPage = 'sign_in'
|
||||
break;
|
||||
case 'sign_up':
|
||||
const { floID, privKey } = floCrypto.generateNewID()
|
||||
getRef('generated_flo_id').value = floID
|
||||
getRef('generated_private_key').value = privKey
|
||||
targetPage = 'sign_up'
|
||||
break;
|
||||
case 'transactions':
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
const animOptions = {
|
||||
duration: 100,
|
||||
fill: 'forwards',
|
||||
}
|
||||
let previousActiveElement = getRef('main_navbar').querySelector('.nav-item--active')
|
||||
const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`)
|
||||
if (currentActiveElement) {
|
||||
if (getRef('main_navbar').classList.contains('hide')) {
|
||||
getRef('main_navbar').classList.remove('hide-away')
|
||||
getRef('main_navbar').classList.remove('hide')
|
||||
getRef('main_navbar').animate([
|
||||
{
|
||||
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
transform: `none`,
|
||||
opacity: 1,
|
||||
},
|
||||
], {
|
||||
duration: 100,
|
||||
fill: 'forwards',
|
||||
easing: 'ease'
|
||||
})
|
||||
}
|
||||
getRef('main_header').classList.remove('hide')
|
||||
const previousActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(previousActiveElement)
|
||||
const currentActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(currentActiveElement)
|
||||
const isOnTop = previousActiveElementIndex < currentActiveElementIndex
|
||||
const currentIndicator = createElement('div', { className: 'nav-item__indicator' });
|
||||
let previousIndicator = getRef('main_navbar').querySelector('.nav-item__indicator')
|
||||
if (!previousIndicator) {
|
||||
previousIndicator = currentIndicator.cloneNode(true)
|
||||
previousActiveElement = currentActiveElement
|
||||
previousActiveElement.append(previousIndicator)
|
||||
} else if (currentActiveElementIndex !== previousActiveElementIndex) {
|
||||
const indicatorDimensions = previousIndicator.getBoundingClientRect()
|
||||
const currentActiveElementDimensions = currentActiveElement.getBoundingClientRect()
|
||||
let moveBy
|
||||
if (isMobileView) {
|
||||
moveBy = ((currentActiveElementDimensions.width - indicatorDimensions.width) / 2) + indicatorDimensions.width
|
||||
} else {
|
||||
moveBy = ((currentActiveElementDimensions.height - indicatorDimensions.height) / 2) + indicatorDimensions.height
|
||||
}
|
||||
indicatorObserver.observe(previousIndicator)
|
||||
previousIndicator.animate([
|
||||
{
|
||||
transform: 'none',
|
||||
opacity: 1,
|
||||
},
|
||||
{
|
||||
transform: `translate${isMobileView ? 'X' : 'Y'}(${isOnTop ? `${moveBy}px` : `-${moveBy}px`})`,
|
||||
opacity: 0,
|
||||
},
|
||||
], { ...animOptions, easing: 'ease-in' }).onfinish = () => {
|
||||
previousIndicator.remove()
|
||||
}
|
||||
tempData = {
|
||||
currentActiveElement,
|
||||
currentIndicator,
|
||||
isOnTop,
|
||||
animOptions,
|
||||
moveBy
|
||||
}
|
||||
}
|
||||
previousActiveElement.classList.remove('nav-item--active');
|
||||
currentActiveElement.classList.add('nav-item--active')
|
||||
} else {
|
||||
if (!getRef('main_navbar').classList.contains('hide')) {
|
||||
getRef('main_navbar').classList.add('hide-away')
|
||||
getRef('main_navbar').animate([
|
||||
{
|
||||
transform: `none`,
|
||||
opacity: 1,
|
||||
},
|
||||
{
|
||||
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
|
||||
opacity: 0,
|
||||
},
|
||||
], {
|
||||
duration: 200,
|
||||
fill: 'forwards',
|
||||
easing: 'ease'
|
||||
}).onfinish = () => {
|
||||
getRef('main_navbar').classList.add('hide')
|
||||
}
|
||||
getRef('main_header').classList.add('hide')
|
||||
}
|
||||
}
|
||||
document.querySelectorAll('.page').forEach(page => page.classList.add('hide'))
|
||||
getRef(pageId).classList.remove('hide')
|
||||
getRef(pageId).animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300, fill: 'forwards', easing: 'ease' })
|
||||
}
|
||||
|
||||
const indicatorObserver = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (!entry.isIntersecting) {
|
||||
const { currentActiveElement, currentIndicator, isOnTop, animOptions, moveBy } = tempData
|
||||
currentActiveElement.append(currentIndicator)
|
||||
currentIndicator.animate([
|
||||
{
|
||||
transform: `translate${isMobileView ? 'X' : 'Y'}(${isOnTop ? `-${moveBy}px` : `${moveBy}px`})`,
|
||||
opacity: 0,
|
||||
},
|
||||
{
|
||||
transform: 'none',
|
||||
opacity: 1
|
||||
},
|
||||
], { ...animOptions, easing: 'ease-out' })
|
||||
}
|
||||
})
|
||||
}, {
|
||||
threshold: 1
|
||||
})
|
||||
|
||||
// class based lazy loading
|
||||
class LazyLoader {
|
||||
constructor(container, elementsToRender, renderFn, options = {}) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user