commit
267265cb10
391
css/main.css
391
css/main.css
@ -17,29 +17,29 @@ body {
|
|||||||
body {
|
body {
|
||||||
--accent-color: #256eff;
|
--accent-color: #256eff;
|
||||||
--text-color: 20, 20, 20;
|
--text-color: 20, 20, 20;
|
||||||
--background-color: 240, 240, 240;
|
--foreground-color: 252, 253, 255;
|
||||||
--foreground-color: 250, 250, 250;
|
--background-color: 241, 243, 248;
|
||||||
--danger-color: rgb(255, 75, 75);
|
--danger-color: rgb(255, 75, 75);
|
||||||
--green: #1cad59;
|
--green: #1cad59;
|
||||||
|
--yellow: rgb(220, 165, 0);
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
color: rgba(var(--text-color), 1);
|
color: rgba(var(--text-color), 1);
|
||||||
background-color: rgba(var(--background-color), 1);
|
background-color: rgba(var(--background-color), 1);
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body[data-theme=dark] {
|
body[data-theme=dark] {
|
||||||
--accent-color: #86afff;
|
--accent-color: #90b8f8;
|
||||||
--text-color: 220, 220, 220;
|
--text-color: 220, 220, 220;
|
||||||
--background-color: 10, 10, 10;
|
--foreground-color: 27, 28, 29;
|
||||||
--foreground-color: 24, 24, 24;
|
--background-color: 21, 22, 22;
|
||||||
--danger-color: rgb(255, 106, 106);
|
--danger-color: rgb(255, 106, 106);
|
||||||
--green: #00e676;
|
--green: #00e676;
|
||||||
|
--yellow: rgb(255, 213, 5);
|
||||||
}
|
}
|
||||||
body[data-theme=dark] sm-popup::part(popup) {
|
body[data-theme=dark] sm-popup::part(popup) {
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
@ -65,6 +65,14 @@ a:focus-visible {
|
|||||||
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
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 {
|
button {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
@ -177,7 +185,7 @@ sm-textarea button .icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sm-button {
|
sm-button {
|
||||||
--padding: 0.6rem 0.8rem;
|
--padding: 0.8rem;
|
||||||
}
|
}
|
||||||
sm-button[variant=primary] .icon {
|
sm-button[variant=primary] .icon {
|
||||||
fill: rgba(var(--background-color), 1);
|
fill: rgba(var(--background-color), 1);
|
||||||
@ -458,6 +466,20 @@ h3 {
|
|||||||
fill: var(--accent-color);
|
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,
|
#confirmation_popup,
|
||||||
#prompt_popup {
|
#prompt_popup {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -492,7 +514,6 @@ h3 {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-auto-flow: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup__header__close {
|
.popup__header__close {
|
||||||
@ -501,8 +522,60 @@ h3 {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#secondary_pages {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#secondary_pages header {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
#secondary_pages .inner-page {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 {
|
#main_header {
|
||||||
padding: 1rem 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#main_card {
|
#main_card {
|
||||||
@ -514,11 +587,6 @@ h3 {
|
|||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pages_container {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main_navbar {
|
#main_navbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
background: rgba(var(--text-color), 0.03);
|
background: rgba(var(--text-color), 0.03);
|
||||||
@ -549,11 +617,11 @@ h3 {
|
|||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
}
|
}
|
||||||
.nav-item .icon {
|
.nav-item .icon {
|
||||||
transition: transform 0.2s;
|
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
.nav-item__title {
|
.nav-item__title {
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
transition: opacity 0.2s, transform 0.2s;
|
transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
.nav-item--active {
|
.nav-item--active {
|
||||||
color: var(--accent-color);
|
color: var(--accent-color);
|
||||||
@ -576,6 +644,13 @@ h3 {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inner-page {
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
.password-field label {
|
.password-field label {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -603,53 +678,202 @@ h3 {
|
|||||||
clip-path: circle(0);
|
clip-path: circle(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#home {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user {
|
||||||
|
position: relative;
|
||||||
|
gap: 0.5rem;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#quick_actions_container {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.primary-action {
|
.primary-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.8rem 1rem;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.8rem;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
background-color: transparent;
|
font-weight: 400;
|
||||||
border: thin solid rgba(var(--text-color), 0.3);
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.primary-action .icon {
|
.primary-action .icon {
|
||||||
fill: var(--accent-color);
|
fill: var(--accent-color);
|
||||||
}
|
}
|
||||||
.primary-action:not(:last-of-type) {
|
|
||||||
margin-right: 0.5rem;
|
#rupee_balance span:first-of-type {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
#rupee_balance span:last-of-type {
|
||||||
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.wallet-action {
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.wallet-action:nth-of-type(2) {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
.wallet-action .icon {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
fill: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#saved_ids_list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.saved-id {
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 0 0.8rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.saved-id.highlight {
|
||||||
|
box-shadow: 0 0 0.1rem 0.1rem var(--accent-color) inset;
|
||||||
|
}
|
||||||
|
.saved-id .edit-saved {
|
||||||
|
padding: 0.3rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
.saved-id .edit-saved .icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 1.2rem;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
background-color: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
.saved-id__initials {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 2.4rem;
|
||||||
|
width: 2.4rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
justify-self: flex-start;
|
||||||
|
border-radius: 2rem;
|
||||||
|
}
|
||||||
|
.saved-id__title {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#contact {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
#contact > * {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#contact__transactions {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
align-content: flex-start;
|
flex: 1;
|
||||||
padding: 1.5rem;
|
padding: 0 max(1rem, 8vw);
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
#wallet_section {
|
.transaction-message {
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
|
padding: 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1.5rem;
|
justify-self: flex-start;
|
||||||
|
border-radius: 0 1rem 1rem 1rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.transaction-message.received {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
.transaction-message.received + .transaction-message.received {
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
.transaction-message.sent {
|
||||||
|
margin-left: auto;
|
||||||
|
justify-self: flex-end;
|
||||||
|
border-radius: 1rem 1rem 0 1rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.transaction-message__amount {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
.transaction-message__time {
|
||||||
|
opacity: 0.8;
|
||||||
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#transactions_list {
|
#wallet_history_wrapper {
|
||||||
flex-direction: column;
|
margin-top: 1.5rem;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#payments_history {
|
||||||
|
display: grid;
|
||||||
|
gap: 2rem;
|
||||||
padding-bottom: 4rem;
|
padding-bottom: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction {
|
.transaction {
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
gap: 0.5rem 1rem;
|
gap: 0.5rem 1rem;
|
||||||
padding: 0.8rem;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
}
|
}
|
||||||
.transaction:not(:last-of-type) {
|
.transaction.sent .icon {
|
||||||
margin-bottom: 0.5rem;
|
fill: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
.transaction.sent .transaction__amount {
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
.transaction.sent .transaction__amount::before {
|
||||||
|
content: "- ";
|
||||||
|
}
|
||||||
|
.transaction.received .icon {
|
||||||
|
fill: var(--green);
|
||||||
|
}
|
||||||
|
.transaction.received .transaction__amount {
|
||||||
|
color: var(--green);
|
||||||
|
}
|
||||||
|
.transaction.received .transaction__amount::before {
|
||||||
|
content: "+ ";
|
||||||
}
|
}
|
||||||
.transaction__icon {
|
.transaction__icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -659,10 +883,7 @@ h3 {
|
|||||||
width: 2.5rem;
|
width: 2.5rem;
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
border-radius: 0.5rem;
|
border-radius: 2rem;
|
||||||
}
|
|
||||||
.transaction__icon .icon {
|
|
||||||
fill: var(--accent-color);
|
|
||||||
}
|
}
|
||||||
.transaction__receiver {
|
.transaction__receiver {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@ -678,12 +899,6 @@ h3 {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
grid-area: 1/3/3/4;
|
grid-area: 1/3/3/4;
|
||||||
}
|
}
|
||||||
.transaction__amount.sent::before {
|
|
||||||
content: "-";
|
|
||||||
}
|
|
||||||
.transaction__amount.received::before {
|
|
||||||
content: "+";
|
|
||||||
}
|
|
||||||
|
|
||||||
.fab {
|
.fab {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -699,6 +914,15 @@ h3 {
|
|||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#add_address_button {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
#add_address_button .icon {
|
||||||
|
fill: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#transaction_result {
|
#transaction_result {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
@ -809,36 +1033,78 @@ h3 {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wallet-request {
|
||||||
|
align-items: initial;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.wallet-request__details {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.wallet-request__status {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.wallet-request__status .icon {
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
}
|
||||||
|
.wallet-request__status.pending .icon {
|
||||||
|
fill: var(--yellow);
|
||||||
|
}
|
||||||
|
.wallet-request__status.completed .icon {
|
||||||
|
fill: var(--green);
|
||||||
|
}
|
||||||
|
.wallet-request__status.rejected .icon {
|
||||||
|
fill: var(--danger-color);
|
||||||
|
}
|
||||||
|
.wallet-request__note {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 40rem) {
|
||||||
|
#main_navbar.hide-away {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@media screen and (min-width: 40rem) {
|
@media screen and (min-width: 40rem) {
|
||||||
sm-popup {
|
sm-popup {
|
||||||
--width: 24rem;
|
--width: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-layout {
|
||||||
|
grid-template-columns: 1fr 90vw 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.popup__header {
|
.popup__header {
|
||||||
grid-column: 1/-1;
|
grid-column: 1/-1;
|
||||||
padding: 1rem 1.5rem 0 1.5rem;
|
padding: 1rem 1.5rem 0 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
#main_card {
|
#main_card {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
grid-template-rows: auto 1fr;
|
|
||||||
grid-template-areas: "nav header" "nav main";
|
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05), 0 1rem 3rem rgba(0, 0, 0, 0.2);
|
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_card:not(.nav-hidden) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-areas: "nav header" "nav .";
|
||||||
}
|
}
|
||||||
|
|
||||||
#main_header {
|
#main_header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pages_container {
|
|
||||||
grid-area: main;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main_navbar {
|
#main_navbar {
|
||||||
grid-area: nav;
|
grid-area: nav;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
@ -865,11 +1131,18 @@ h3 {
|
|||||||
bottom: auto;
|
bottom: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
#user {
|
#user {
|
||||||
grid-template-columns: 1fr 20rem;
|
gap: 1rem;
|
||||||
align-content: flex-start;
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#saved_ids_list {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 56rem) {
|
@media screen and (min-width: 56rem) {
|
||||||
#main_card {
|
#main_card {
|
||||||
@ -898,10 +1171,12 @@ h3 {
|
|||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:not([disabled]) {
|
button,
|
||||||
|
.button:not([disabled]) {
|
||||||
transition: background-color 0.3s, filter 0.3s;
|
transition: background-color 0.3s, filter 0.3s;
|
||||||
}
|
}
|
||||||
.button:not([disabled]):hover {
|
button:hover,
|
||||||
|
.button:not([disabled]):hover {
|
||||||
filter: contrast(2);
|
filter: contrast(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
389
css/main.scss
389
css/main.scss
@ -17,29 +17,29 @@ body {
|
|||||||
body {
|
body {
|
||||||
--accent-color: #256eff;
|
--accent-color: #256eff;
|
||||||
--text-color: 20, 20, 20;
|
--text-color: 20, 20, 20;
|
||||||
--background-color: 240, 240, 240;
|
--foreground-color: 252, 253, 255;
|
||||||
--foreground-color: 250, 250, 250;
|
--background-color: 241, 243, 248;
|
||||||
--danger-color: rgb(255, 75, 75);
|
--danger-color: rgb(255, 75, 75);
|
||||||
--green: #1cad59;
|
--green: #1cad59;
|
||||||
|
--yellow: rgb(220, 165, 0);
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
color: rgba(var(--text-color), 1);
|
color: rgba(var(--text-color), 1);
|
||||||
background-color: rgba(var(--background-color), 1);
|
background-color: rgba(var(--background-color), 1);
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body[data-theme="dark"] {
|
body[data-theme="dark"] {
|
||||||
--accent-color: #86afff;
|
--accent-color: #90b8f8;
|
||||||
--text-color: 220, 220, 220;
|
--text-color: 220, 220, 220;
|
||||||
--background-color: 10, 10, 10;
|
--foreground-color: 27, 28, 29;
|
||||||
--foreground-color: 24, 24, 24;
|
--background-color: 21, 22, 22;
|
||||||
--danger-color: rgb(255, 106, 106);
|
--danger-color: rgb(255, 106, 106);
|
||||||
--green: #00e676;
|
--green: #00e676;
|
||||||
|
--yellow: rgb(255, 213, 5);
|
||||||
sm-popup::part(popup) {
|
sm-popup::part(popup) {
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
}
|
}
|
||||||
@ -63,6 +63,13 @@ a {
|
|||||||
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
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 {
|
button {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -156,7 +163,7 @@ sm-textarea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sm-button {
|
sm-button {
|
||||||
--padding: 0.6rem 0.8rem;
|
--padding: 0.8rem;
|
||||||
&[variant="primary"] {
|
&[variant="primary"] {
|
||||||
.icon {
|
.icon {
|
||||||
fill: rgba(var(--background-color), 1);
|
fill: rgba(var(--background-color), 1);
|
||||||
@ -426,6 +433,18 @@ h3 {
|
|||||||
fill: var(--accent-color);
|
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,
|
#confirmation_popup,
|
||||||
#prompt_popup {
|
#prompt_popup {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -455,7 +474,6 @@ h3 {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 1.5rem;
|
padding: 0 1.5rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-auto-flow: column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup__header__close {
|
.popup__header__close {
|
||||||
@ -463,8 +481,60 @@ h3 {
|
|||||||
margin-left: -0.5rem;
|
margin-left: -0.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#secondary_pages {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
header {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
.inner-page {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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 {
|
#main_header {
|
||||||
padding: 1rem 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
#main_card {
|
#main_card {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -474,10 +544,6 @@ h3 {
|
|||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
}
|
}
|
||||||
#pages_container {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main_navbar {
|
#main_navbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -507,11 +573,12 @@ h3 {
|
|||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
.icon {
|
.icon {
|
||||||
transition: transform 0.2s;
|
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
&__title {
|
&__title {
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
transition: opacity 0.2s, transform 0.2s;
|
transition: opacity 0.2s,
|
||||||
|
transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
&--active {
|
&--active {
|
||||||
color: var(--accent-color);
|
color: var(--accent-color);
|
||||||
@ -534,6 +601,12 @@ h3 {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.inner-page {
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
.password-field {
|
.password-field {
|
||||||
label {
|
label {
|
||||||
@ -560,51 +633,194 @@ h3 {
|
|||||||
.clip {
|
.clip {
|
||||||
clip-path: circle(0);
|
clip-path: circle(0);
|
||||||
}
|
}
|
||||||
|
#home {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#user {
|
||||||
|
position: relative;
|
||||||
|
gap: 0.5rem;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
}
|
||||||
|
#quick_actions_container {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(4rem, 1fr));
|
||||||
|
}
|
||||||
.primary-action {
|
.primary-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0.8rem 1rem;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.8rem;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
background-color: transparent;
|
font-weight: 400;
|
||||||
border: thin solid rgba(var(--text-color), 0.3);
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
text-align: center;
|
||||||
.icon {
|
.icon {
|
||||||
fill: var(--accent-color);
|
fill: var(--accent-color);
|
||||||
}
|
}
|
||||||
&:not(:last-of-type) {
|
}
|
||||||
|
#rupee_balance {
|
||||||
|
span:first-of-type {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
span:last-of-type {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wallet-action {
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
flex: 1;
|
||||||
|
&:nth-of-type(2) {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
fill: var(--accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
#saved_ids_list {
|
||||||
position: relative;
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
.saved-id {
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 0 0.8rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
user-select: none;
|
||||||
|
align-items: center;
|
||||||
|
&.highlight {
|
||||||
|
box-shadow: 0 0 0.1rem 0.1rem var(--accent-color) inset;
|
||||||
|
}
|
||||||
|
.edit-saved {
|
||||||
|
padding: 0.3rem;
|
||||||
|
position: relative;
|
||||||
|
justify-self: center;
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 1.2rem;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
background-color: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__initials {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 2.4rem;
|
||||||
|
width: 2.4rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
justify-self: flex-start;
|
||||||
|
border-radius: 2rem;
|
||||||
|
}
|
||||||
|
&__title {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
#contact {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
& > * {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#contact__transactions {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
align-content: flex-start;
|
flex: 1;
|
||||||
padding: 1.5rem;
|
padding: 0 max(1rem, 8vw);
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
.transaction-message {
|
||||||
#wallet_section {
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
padding: 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1.5rem;
|
justify-self: flex-start;
|
||||||
|
border-radius: 0 1rem 1rem 1rem;
|
||||||
|
gap: 0.5rem;
|
||||||
|
&.received {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
& + & {
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.sent {
|
||||||
|
margin-left: auto;
|
||||||
|
justify-self: flex-end;
|
||||||
|
border-radius: 1rem 1rem 0 1rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__amount {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
&__time {
|
||||||
|
opacity: 0.8;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#transactions_list {
|
#wallet_history_wrapper {
|
||||||
flex-direction: column;
|
margin-top: 1.5rem;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
#payments_history {
|
||||||
|
display: grid;
|
||||||
|
gap: 2rem;
|
||||||
padding-bottom: 4rem;
|
padding-bottom: 4rem;
|
||||||
}
|
}
|
||||||
.transaction {
|
.transaction {
|
||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
gap: 0.5rem 1rem;
|
gap: 0.5rem 1rem;
|
||||||
padding: 0.8rem;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
|
||||||
border-radius: 0.3rem;
|
border-radius: 0.3rem;
|
||||||
&:not(:last-of-type) {
|
&.sent {
|
||||||
margin-bottom: 0.5rem;
|
.icon {
|
||||||
|
fill: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
.transaction__amount {
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
&::before {
|
||||||
|
content: "- ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.received {
|
||||||
|
.icon {
|
||||||
|
fill: var(--green);
|
||||||
|
}
|
||||||
|
.transaction__amount {
|
||||||
|
color: var(--green);
|
||||||
|
&::before {
|
||||||
|
content: "+ ";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__icon {
|
&__icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -614,10 +830,7 @@ h3 {
|
|||||||
width: 2.5rem;
|
width: 2.5rem;
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
background-color: rgba(var(--text-color), 0.03);
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
border-radius: 0.5rem;
|
border-radius: 2rem;
|
||||||
.icon {
|
|
||||||
fill: var(--accent-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&__receiver {
|
&__receiver {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@ -632,16 +845,6 @@ h3 {
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
grid-area: 1/3/3/4;
|
grid-area: 1/3/3/4;
|
||||||
&.sent {
|
|
||||||
&::before {
|
|
||||||
content: "-";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.received {
|
|
||||||
&::before {
|
|
||||||
content: "+";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fab {
|
.fab {
|
||||||
@ -656,6 +859,14 @@ h3 {
|
|||||||
border-radius: 3rem;
|
border-radius: 3rem;
|
||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
}
|
}
|
||||||
|
#add_address_button {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
color: rgba(var(--background-color), 1);
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
.icon {
|
||||||
|
fill: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#transaction_result {
|
#transaction_result {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -720,9 +931,6 @@ h3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#settings {
|
|
||||||
}
|
|
||||||
|
|
||||||
.cashier-request,
|
.cashier-request,
|
||||||
.wallet-request,
|
.wallet-request,
|
||||||
.payment-request {
|
.payment-request {
|
||||||
@ -747,33 +955,81 @@ h3 {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.wallet-request {
|
||||||
|
align-items: initial;
|
||||||
|
flex-direction: column;
|
||||||
|
&__details {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
&__status {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
font-weight: 500;
|
||||||
|
.icon {
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
}
|
||||||
|
&.pending {
|
||||||
|
.icon {
|
||||||
|
fill: var(--yellow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.completed {
|
||||||
|
.icon {
|
||||||
|
fill: var(--green);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.rejected {
|
||||||
|
.icon {
|
||||||
|
fill: var(--danger-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__note {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 40rem) {
|
||||||
|
#main_navbar {
|
||||||
|
&.hide-away {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@media screen and (min-width: 40rem) {
|
@media screen and (min-width: 40rem) {
|
||||||
sm-popup {
|
sm-popup {
|
||||||
--width: 24rem;
|
--width: 24rem;
|
||||||
}
|
}
|
||||||
|
.page-layout {
|
||||||
|
grid-template-columns: 1fr 90vw 1fr;
|
||||||
|
}
|
||||||
.popup__header {
|
.popup__header {
|
||||||
grid-column: 1/-1;
|
grid-column: 1/-1;
|
||||||
padding: 1rem 1.5rem 0 1.5rem;
|
padding: 1rem 1.5rem 0 1.5rem;
|
||||||
}
|
}
|
||||||
|
body {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
#main_card {
|
#main_card {
|
||||||
display: grid;
|
&:not(.nav-hidden) {
|
||||||
grid-template-columns: auto 1fr;
|
display: grid;
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
grid-template-areas: "nav header" "nav main";
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-areas: "nav header" "nav .";
|
||||||
|
}
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05),
|
box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05),
|
||||||
0 1rem 3rem rgba(0, 0, 0, 0.2);
|
0 1rem 3rem rgba(0, 0, 0, 0.2);
|
||||||
// backdrop-filter: blur(2rem);
|
|
||||||
background-color: rgba(var(--foreground-color), 0.9);
|
|
||||||
}
|
}
|
||||||
#main_header {
|
#main_header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
}
|
}
|
||||||
#pages_container {
|
|
||||||
grid-area: main;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main_navbar {
|
#main_navbar {
|
||||||
grid-area: nav;
|
grid-area: nav;
|
||||||
@ -800,11 +1056,16 @@ h3 {
|
|||||||
bottom: auto;
|
bottom: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.card {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
#user {
|
#user {
|
||||||
grid-template-columns: 1fr 20rem;
|
gap: 1rem;
|
||||||
align-content: flex-start;
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
#saved_ids_list {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media screen and (min-width: 56rem) {
|
@media screen and (min-width: 56rem) {
|
||||||
#main_card {
|
#main_card {
|
||||||
@ -812,7 +1073,6 @@ h3 {
|
|||||||
width: 56rem;
|
width: 56rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (any-hover: hover) {
|
@media (any-hover: hover) {
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 0.5rem;
|
width: 0.5rem;
|
||||||
@ -833,6 +1093,7 @@ h3 {
|
|||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
button,
|
||||||
.button:not([disabled]) {
|
.button:not([disabled]) {
|
||||||
transition: background-color 0.3s, filter 0.3s;
|
transition: background-color 0.3s, filter 0.3s;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|||||||
589
index.html
589
index.html
@ -45,7 +45,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="onLoadStartUp()">
|
<body onload="onLoadStartUp()" class="hide">
|
||||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||||
<sm-popup id="confirmation_popup">
|
<sm-popup id="confirmation_popup">
|
||||||
<h4 id="confirm_title"></h4>
|
<h4 id="confirm_title"></h4>
|
||||||
@ -55,55 +55,134 @@
|
|||||||
<sm-button variant="no-outline" class="submit-btn">OK</sm-button>
|
<sm-button variant="no-outline" class="submit-btn">OK</sm-button>
|
||||||
</div>
|
</div>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
<div id="loader" class="grid gap-1 text-center">
|
<div id="secondary_pages" class="page hide">
|
||||||
<sm-spinner></sm-spinner>
|
<header class="flex align-center gap-1">
|
||||||
<h4>Loading RanchiMall Pay</h4>
|
<div class="flex align-center flex-1">
|
||||||
</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"
|
<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">
|
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
|
<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
|
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.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
|
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
|
||||||
c0.7,2.8,1.1,3.1,3.6,2.3c2.3-0.7,3.9-1.5,5.8-2.9c0.8-0.6,1.5-0.9,1.6-0.9c0.1,0.1,0.5,1,0.7,2.1s0.7,2,0.9,2.1
|
c0.7,2.8,1.1,3.1,3.6,2.3c2.3-0.7,3.9-1.5,5.8-2.9c0.8-0.6,1.5-0.9,1.6-0.9c0.1,0.1,0.5,1,0.7,2.1s0.7,2,0.9,2.1
|
||||||
c0.8,0.3,5.1-1.3,7.5-2.9l2.3-1.5l0.5,1.8c0.6,2.4,1,2.7,3.3,2.1c3.9-1,7.7-3.7,11.5-8.2l2-2.4l-0.2,2.1c-0.6,5.4-4.3,11.4-11.3,18
|
c0.8,0.3,5.1-1.3,7.5-2.9l2.3-1.5l0.5,1.8c0.6,2.4,1,2.7,3.3,2.1c3.9-1,7.7-3.7,11.5-8.2l2-2.4l-0.2,2.1c-0.6,5.4-4.3,11.4-11.3,18
|
||||||
c-1.8,1.7-4.7,4.5-6.5,6.2c-10.7,10.2-10,18.6,2,26.5c2.7,1.8,10.3,5.8,15.3,8c0.9,0.4,3.3,1.7,5.3,2.9c11,6.5,16.4,13.1,16.4,19.7
|
c-1.8,1.7-4.7,4.5-6.5,6.2c-10.7,10.2-10,18.6,2,26.5c2.7,1.8,10.3,5.8,15.3,8c0.9,0.4,3.3,1.7,5.3,2.9c11,6.5,16.4,13.1,16.4,19.7
|
||||||
c0,1.3,0.1,2.4,0.2,2.6l0,0c0.3,0.3,0.1,0.3,3-0.5c1.4-0.4,2.6-0.9,2.8-1.1c0.4-0.6-0.6-3.7-1.8-6.1c-1.3-2.5-5.6-7-8.9-9.4
|
c0,1.3,0.1,2.4,0.2,2.6l0,0c0.3,0.3,0.1,0.3,3-0.5c1.4-0.4,2.6-0.9,2.8-1.1c0.4-0.6-0.6-3.7-1.8-6.1c-1.3-2.5-5.6-7-8.9-9.4
|
||||||
c-3.8-2.8-9.3-5.9-17-9.7c-8.5-4.2-11.8-6.2-14.7-9.1c-2.6-2.6-3.9-5.3-3.9-8.2c0-4.6,2.3-8.6,8.3-14.1c9.4-8.7,13-13,15.5-18.8
|
c-3.8-2.8-9.3-5.9-17-9.7c-8.5-4.2-11.8-6.2-14.7-9.1c-2.6-2.6-3.9-5.3-3.9-8.2c0-4.6,2.3-8.6,8.3-14.1c9.4-8.7,13-13,15.5-18.8
|
||||||
c1.3-3,1.4-3.4,1.4-6.7c0-3.1-0.1-3.8-1.1-6l-1.1-2.4l1-1.6c0.5-0.9,1.2-2.1,1.5-2.6l0.5-1l1.5,2.1c1.8,2.6,3.2,6.8,3.2,9.3
|
c1.3-3,1.4-3.4,1.4-6.7c0-3.1-0.1-3.8-1.1-6l-1.1-2.4l1-1.6c0.5-0.9,1.2-2.1,1.5-2.6l0.5-1l1.5,2.1c1.8,2.6,3.2,6.8,3.2,9.3
|
||||||
c0,1.7-0.6,4.7-1.4,6.4c-0.2,0.4-0.4,1-0.5,1.3c-0.1,0.3-1.1,2-2.2,3.7c-2,3-5.2,6.4-13.4,14.2c-5.7,5.4-7.6,8.6-7.8,13.1
|
c0,1.7-0.6,4.7-1.4,6.4c-0.2,0.4-0.4,1-0.5,1.3c-0.1,0.3-1.1,2-2.2,3.7c-2,3-5.2,6.4-13.4,14.2c-5.7,5.4-7.6,8.6-7.8,13.1
|
||||||
c-0.2,3.7,0.7,5.9,3.7,9.2c3.2,3.4,6.9,5.8,17.4,11c12.1,6,17.3,9.6,21.3,14.5c2.5,3.2,3.7,5.8,3.9,9.3c0.1,1.6,0.3,3,0.5,3
|
c-0.2,3.7,0.7,5.9,3.7,9.2c3.2,3.4,6.9,5.8,17.4,11c12.1,6,17.3,9.6,21.3,14.5c2.5,3.2,3.7,5.8,3.9,9.3c0.1,1.6,0.3,3,0.5,3
|
||||||
c0.1,0.1,0.8,0,1.4-0.2s1.9-0.5,2.7-0.7l1.5-0.4l-0.2-1.5c-0.7-5.1-5.4-10.8-13.1-16c-4.4-2.9-5.8-3.7-17.3-9.4
|
c0.1,0.1,0.8,0,1.4-0.2s1.9-0.5,2.7-0.7l1.5-0.4l-0.2-1.5c-0.7-5.1-5.4-10.8-13.1-16c-4.4-2.9-5.8-3.7-17.3-9.4
|
||||||
c-5.7-2.8-9.2-5.1-11.8-7.6c-4.3-4.2-5.1-8.8-2.7-13.9c1.4-2.8,2.7-4.4,12.5-13.8c8-7.7,11.4-13.7,11.4-20.1c0-5.1-2.3-9.9-6.9-14.3
|
c-5.7-2.8-9.2-5.1-11.8-7.6c-4.3-4.2-5.1-8.8-2.7-13.9c1.4-2.8,2.7-4.4,12.5-13.8c8-7.7,11.4-13.7,11.4-20.1c0-5.1-2.3-9.9-6.9-14.3
|
||||||
c-1.1-1-2-2-2.1-2.2c-0.2-0.4,1.5-3.9,1.9-3.9c1.2,0,7.8,6.3,9.7,9.2c2,3.3,2.5,5,2.5,8.9c0,3.9-0.6,5.9-2.9,9.8
|
c-1.1-1-2-2-2.1-2.2c-0.2-0.4,1.5-3.9,1.9-3.9c1.2,0,7.8,6.3,9.7,9.2c2,3.3,2.5,5,2.5,8.9c0,3.9-0.6,5.9-2.9,9.8
|
||||||
c-2.4,4.1-4.2,6-14.2,15.5c-3.4,3.2-5.7,6.1-6.9,8.7c-0.9,2-1.1,2.7-1.1,5.1c0,2.3,0.2,3.2,1,4.9c1.9,4,7.4,8.5,15.4,12.4
|
c-2.4,4.1-4.2,6-14.2,15.5c-3.4,3.2-5.7,6.1-6.9,8.7c-0.9,2-1.1,2.7-1.1,5.1c0,2.3,0.2,3.2,1,4.9c1.9,4,7.4,8.5,15.4,12.4
|
||||||
c12.5,6.1,15.1,7.6,19.4,10.7c7.2,5.3,10.6,10.5,10.6,16c0,1.3,0.1,2.4,0.3,2.5c0.4,0.3,4.8-0.8,5.5-1.3
|
c12.5,6.1,15.1,7.6,19.4,10.7c7.2,5.3,10.6,10.5,10.6,16c0,1.3,0.1,2.4,0.3,2.5c0.4,0.3,4.8-0.8,5.5-1.3
|
||||||
C90.7,104.4,90.7,104.3,90.2,102.5z M20.3,23.3L20.3,23.3c-2,1-3.3,1.4-4.8,1.5L13.3,25l2.3-2.8c3.7-4.5,6.4-8.9,10-16
|
C90.7,104.4,90.7,104.3,90.2,102.5z M20.3,23.3L20.3,23.3c-2,1-3.3,1.4-4.8,1.5L13.3,25l2.3-2.8c3.7-4.5,6.4-8.9,10-16
|
||||||
c0.9-1.8,1.8-3.5,2-3.6c0.4-0.4,2.6,1.1,5.1,3.4l2.1,1.9l-1.9,2.8C28.2,17.5,24.5,21.2,20.3,23.3z M39.3,17.4
|
c0.9-1.8,1.8-3.5,2-3.6c0.4-0.4,2.6,1.1,5.1,3.4l2.1,1.9l-1.9,2.8C28.2,17.5,24.5,21.2,20.3,23.3z M39.3,17.4
|
||||||
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
|
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
|
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" />
|
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>
|
</svg>
|
||||||
<h4>RanchiMall Pay</h4>
|
<h4>RanchiMall Pay</h4>
|
||||||
</div>
|
</div>
|
||||||
<theme-toggle></theme-toggle>
|
<theme-toggle></theme-toggle>
|
||||||
</header>
|
</header>
|
||||||
<section id="pages_container" class="gap-2">
|
<article id="landing" class="inner-page page-layout hide">
|
||||||
<section id="home" class="page hide">
|
<section class="grid justify-center gap-1">
|
||||||
<div id="user" class="hide grid gap-2 user-element">
|
<h1 class="h1">Send.request</h1>
|
||||||
<div class="flex">
|
<div class="flex gap-0-5">
|
||||||
<button class="button primary-action" onclick="showTokenTransfer('send')">
|
<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="inner-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="inner-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="inner-page flex align-center justify-center">
|
||||||
|
<div class="grid gap-1 text-center">
|
||||||
|
<sm-spinner></sm-spinner>
|
||||||
|
<h4>Loading RanchiMall Pay</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="main_card" class="page hide">
|
||||||
|
<header id="main_header" class="flex align-center space-between">
|
||||||
|
<div 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
|
||||||
|
c0.7,2.8,1.1,3.1,3.6,2.3c2.3-0.7,3.9-1.5,5.8-2.9c0.8-0.6,1.5-0.9,1.6-0.9c0.1,0.1,0.5,1,0.7,2.1s0.7,2,0.9,2.1
|
||||||
|
c0.8,0.3,5.1-1.3,7.5-2.9l2.3-1.5l0.5,1.8c0.6,2.4,1,2.7,3.3,2.1c3.9-1,7.7-3.7,11.5-8.2l2-2.4l-0.2,2.1c-0.6,5.4-4.3,11.4-11.3,18
|
||||||
|
c-1.8,1.7-4.7,4.5-6.5,6.2c-10.7,10.2-10,18.6,2,26.5c2.7,1.8,10.3,5.8,15.3,8c0.9,0.4,3.3,1.7,5.3,2.9c11,6.5,16.4,13.1,16.4,19.7
|
||||||
|
c0,1.3,0.1,2.4,0.2,2.6l0,0c0.3,0.3,0.1,0.3,3-0.5c1.4-0.4,2.6-0.9,2.8-1.1c0.4-0.6-0.6-3.7-1.8-6.1c-1.3-2.5-5.6-7-8.9-9.4
|
||||||
|
c-3.8-2.8-9.3-5.9-17-9.7c-8.5-4.2-11.8-6.2-14.7-9.1c-2.6-2.6-3.9-5.3-3.9-8.2c0-4.6,2.3-8.6,8.3-14.1c9.4-8.7,13-13,15.5-18.8
|
||||||
|
c1.3-3,1.4-3.4,1.4-6.7c0-3.1-0.1-3.8-1.1-6l-1.1-2.4l1-1.6c0.5-0.9,1.2-2.1,1.5-2.6l0.5-1l1.5,2.1c1.8,2.6,3.2,6.8,3.2,9.3
|
||||||
|
c0,1.7-0.6,4.7-1.4,6.4c-0.2,0.4-0.4,1-0.5,1.3c-0.1,0.3-1.1,2-2.2,3.7c-2,3-5.2,6.4-13.4,14.2c-5.7,5.4-7.6,8.6-7.8,13.1
|
||||||
|
c-0.2,3.7,0.7,5.9,3.7,9.2c3.2,3.4,6.9,5.8,17.4,11c12.1,6,17.3,9.6,21.3,14.5c2.5,3.2,3.7,5.8,3.9,9.3c0.1,1.6,0.3,3,0.5,3
|
||||||
|
c0.1,0.1,0.8,0,1.4-0.2s1.9-0.5,2.7-0.7l1.5-0.4l-0.2-1.5c-0.7-5.1-5.4-10.8-13.1-16c-4.4-2.9-5.8-3.7-17.3-9.4
|
||||||
|
c-5.7-2.8-9.2-5.1-11.8-7.6c-4.3-4.2-5.1-8.8-2.7-13.9c1.4-2.8,2.7-4.4,12.5-13.8c8-7.7,11.4-13.7,11.4-20.1c0-5.1-2.3-9.9-6.9-14.3
|
||||||
|
c-1.1-1-2-2-2.1-2.2c-0.2-0.4,1.5-3.9,1.9-3.9c1.2,0,7.8,6.3,9.7,9.2c2,3.3,2.5,5,2.5,8.9c0,3.9-0.6,5.9-2.9,9.8
|
||||||
|
c-2.4,4.1-4.2,6-14.2,15.5c-3.4,3.2-5.7,6.1-6.9,8.7c-0.9,2-1.1,2.7-1.1,5.1c0,2.3,0.2,3.2,1,4.9c1.9,4,7.4,8.5,15.4,12.4
|
||||||
|
c12.5,6.1,15.1,7.6,19.4,10.7c7.2,5.3,10.6,10.5,10.6,16c0,1.3,0.1,2.4,0.3,2.5c0.4,0.3,4.8-0.8,5.5-1.3
|
||||||
|
C90.7,104.4,90.7,104.3,90.2,102.5z M20.3,23.3L20.3,23.3c-2,1-3.3,1.4-4.8,1.5L13.3,25l2.3-2.8c3.7-4.5,6.4-8.9,10-16
|
||||||
|
c0.9-1.8,1.8-3.5,2-3.6c0.4-0.4,2.6,1.1,5.1,3.4l2.1,1.9l-1.9,2.8C28.2,17.5,24.5,21.2,20.3,23.3z M39.3,17.4
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
<theme-toggle></theme-toggle>
|
||||||
|
</header>
|
||||||
|
<section id="home" class="inner-page hide">
|
||||||
|
<div id="user" class="hide grid user-element">
|
||||||
|
<div class="flex direction-column gap-2 h-100">
|
||||||
|
<div id="quick_actions_container">
|
||||||
|
<button class="primary-action" onclick="showTokenTransfer('send')">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
<path d="M0 0h24v24H0z" fill="none" />
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
|
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
|
||||||
</svg>
|
</svg>
|
||||||
Send
|
Send rupee
|
||||||
</button>
|
</button>
|
||||||
<button class="button primary-action" onclick="showTokenTransfer('request')">
|
<button class="primary-action" onclick="showTokenTransfer('request')">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
<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">
|
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<g>
|
<g>
|
||||||
@ -114,115 +193,226 @@
|
|||||||
d="M20,2H4.01c-1.1,0-2,0.9-2,2L2,22l4-4h14c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M12,6c1.1,0,2,0.9,2,2s-0.9,2-2,2 s-2-0.9-2-2S10.9,6,12,6z M16,14H8v-0.57c0-0.81,0.48-1.53,1.22-1.85C10.07,11.21,11.01,11,12,11c0.99,0,1.93,0.21,2.78,0.58 C15.52,11.9,16,12.62,16,13.43V14z" />
|
d="M20,2H4.01c-1.1,0-2,0.9-2,2L2,22l4-4h14c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M12,6c1.1,0,2,0.9,2,2s-0.9,2-2,2 s-2-0.9-2-2S10.9,6,12,6z M16,14H8v-0.57c0-0.81,0.48-1.53,1.22-1.85C10.07,11.21,11.01,11,12,11c0.99,0,1.93,0.21,2.78,0.58 C15.52,11.9,16,12.62,16,13.43V14z" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
Request
|
Request rupee
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<button class="primary-action" onclick="">
|
||||||
<section id="wallet_section" class="grid gap-1-5">
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
||||||
<h4 class="flex align-center">
|
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<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"
|
|
||||||
fill="#000000">
|
|
||||||
<g>
|
<g>
|
||||||
<rect fill="none" height="24" width="24" />
|
<rect fill="none" height="24" width="24" />
|
||||||
</g>
|
</g>
|
||||||
<g>
|
<g>
|
||||||
<path
|
<g>
|
||||||
d="M18,4H6C3.79,4,2,5.79,2,8v8c0,2.21,1.79,4,4,4h12c2.21,0,4-1.79,4-4V8C22,5.79,20.21,4,18,4z M16.14,13.77 c-0.24,0.2-0.57,0.28-0.88,0.2L4.15,11.25C4.45,10.52,5.16,10,6,10h12c0.67,0,1.26,0.34,1.63,0.84L16.14,13.77z M6,6h12 c1.1,0,2,0.9,2,2v0.55C19.41,8.21,18.73,8,18,8H6C5.27,8,4.59,8.21,4,8.55V8C4,6.9,4.9,6,6,6z" />
|
<path d="M3,11h8V3H3V11z M5,5h4v4H5V5z" />
|
||||||
|
<path d="M3,21h8v-8H3V21z M5,15h4v4H5V15z" />
|
||||||
|
<path d="M13,3v8h8V3H13z M19,9h-4V5h4V9z" />
|
||||||
|
<rect height="2" width="2" x="19" y="19" />
|
||||||
|
<rect height="2" width="2" x="13" y="13" />
|
||||||
|
<rect height="2" width="2" x="15" y="15" />
|
||||||
|
<rect height="2" width="2" x="13" y="17" />
|
||||||
|
<rect height="2" width="2" x="15" y="19" />
|
||||||
|
<rect height="2" width="2" x="17" y="17" />
|
||||||
|
<rect height="2" width="2" x="17" y="13" />
|
||||||
|
<rect height="2" width="2" x="19" y="15" />
|
||||||
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
Wallet
|
Scan FLO QR
|
||||||
</h4>
|
</button>
|
||||||
<div class="grid gap-0-5">
|
</div>
|
||||||
<h5>Balance</h5>
|
<section class="flex direction-column h-100">
|
||||||
<h1 class="h1" id="rupee_balance"></h1>
|
<div class="grid align-center gap-0-5">
|
||||||
</div>
|
<div class="flex align-center">
|
||||||
<div class="grid gap-1">
|
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
<sm-input id="request_cashier_amount" type="number" name="amount" placeholder="Amount"
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
animate>
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
</sm-input>
|
<path
|
||||||
<div class="flex">
|
d="M21 5v14h2V5h-2zm-4 14h2V5h-2v14zM14 5H2c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h12c.55 0 1-.45 1-1V6c0-.55-.45-1-1-1zM8 7.75c1.24 0 2.25 1.01 2.25 2.25S9.24 12.25 8 12.25 5.75 11.24 5.75 10 6.76 7.75 8 7.75zM12.5 17h-9v-.75c0-1.5 3-2.25 4.5-2.25s4.5.75 4.5 2.25V17z" />
|
||||||
<button class="primary-action flex-1" onclick="userUI.requestTokenFromCashier()">
|
</svg>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg"
|
<h4>Saved FLO IDs</h4>
|
||||||
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" />
|
|
||||||
<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>
|
</div>
|
||||||
|
<p class="flex align-center">
|
||||||
|
<svg class="icon margin-right-0-5" style="fill: #ffc107;"
|
||||||
|
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 21c0 .5.4 1 1 1h4c.6 0 1-.5 1-1v-1H9v1zm3-19C8.1 2 5 5.1 5 9c0 2.4 1.2 4.5 3 5.7V17c0 .5.4 1 1 1h6c.6 0 1-.5 1-1v-2.3c1.8-1.3 3-3.4 3-5.7 0-3.9-3.1-7-7-7z" />
|
||||||
|
</svg>
|
||||||
|
<span id="saved_ids_tip">Click 'Add FLO ID' to add a new FLO ID.</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ul id="saved_ids_list" class="observe-empty-state grid"></ul>
|
||||||
|
<div class="empty-state justify-center text-center align-center h-100"
|
||||||
|
style="align-content: center;">
|
||||||
|
<svg class="justify-self-center" style="height: 12rem;"
|
||||||
|
id="bb7dac0d-c86d-4eae-9345-05ead570be6d" data-name="Layer 1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.e4b4c873-5e79-4c66-a530-269f7775150b {
|
||||||
|
fill: rgba(var(--text-color), 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.f8c35eef-c260-42fc-be6f-7c8afb0beeeb {
|
||||||
|
fill: rgba(var(--text-color), 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ee8c2e6d-b8f3-4b81-80ab-31d470d121b9 {
|
||||||
|
fill: rgba(var(--text-color), 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect class="e4b4c873-5e79-4c66-a530-269f7775150b" x="34.76" y="40.75" width="177.53"
|
||||||
|
height="41.42" rx="4" />
|
||||||
|
<circle class="f8c35eef-c260-42fc-be6f-7c8afb0beeeb" cx="57.21" cy="61.46" r="9.29" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="75.4" y="51.37" width="40.44"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="75.4" y="62.79" width="80.09"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
<rect class="e4b4c873-5e79-4c66-a530-269f7775150b" x="10" y="99.29" width="177.53"
|
||||||
|
height="41.42" rx="4" />
|
||||||
|
<circle class="f8c35eef-c260-42fc-be6f-7c8afb0beeeb" cx="32.45" cy="120" r="9.29" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="50.64" y="109.91" width="40.44"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="50.64" y="121.33" width="80.09"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
<rect class="e4b4c873-5e79-4c66-a530-269f7775150b" x="52.47" y="157.83" width="177.53"
|
||||||
|
height="41.42" rx="4" />
|
||||||
|
<circle class="f8c35eef-c260-42fc-be6f-7c8afb0beeeb" cx="74.93" cy="178.54" r="9.29" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="93.12" y="168.46" width="40.44"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
<rect class="ee8c2e6d-b8f3-4b81-80ab-31d470d121b9" x="93.12" y="179.87" width="80.09"
|
||||||
|
height="9.03" rx="1.92" />
|
||||||
|
</svg>
|
||||||
|
<h4>No Saved FLO ID</h4>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<section id="cashier" class=" grid gap-1 hide admin-element">
|
<button id="add_address_button" class="button interact fab" onclick="showPopup('add_address_popup')">
|
||||||
<h4>Requests</h4>
|
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
<ul id="cashier_request_list" class="observe-empty-state"></ul>
|
viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<div class="empty-state">
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
<h4>No requests to process</h4>
|
<path
|
||||||
</div>
|
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z" />
|
||||||
</section>
|
</svg>
|
||||||
|
Add FLO ID
|
||||||
|
</button>
|
||||||
|
</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>
|
||||||
<section id="history" class="page hide grid gap-1">
|
</section>
|
||||||
<h4>Transactions history</h4>
|
<section id="history" class="inner-page hide grid gap-1">
|
||||||
<ul id="token_transactions" class="observe-empty-state">
|
<h4>Payments history</h4>
|
||||||
</ul>
|
<ul id="payments_history" class="observe-empty-state"></ul>
|
||||||
|
<div class=" empty-state gap-1 justify-center text-center">
|
||||||
|
<h4>No transactions</h4>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="contact" class="inner-page hide">
|
||||||
|
<div class="flex align-center">
|
||||||
|
<a href="#/home" class="button icon-only margin-right-0-5">
|
||||||
|
<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 id="contact__title"></h4>
|
||||||
|
</div>
|
||||||
|
<ul id="contact__transactions"></ul>
|
||||||
|
<div class="flex">
|
||||||
|
<button class="button flex-1">Pay</button>
|
||||||
|
<button class="button flex-1">Request</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="requests" class="inner-page hide">
|
||||||
|
<h4>Payment requests</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="wallet" class="inner-page hide">
|
||||||
|
<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" fill="#000000">
|
||||||
|
<g>
|
||||||
|
<rect fill="none" height="24" width="24" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M18,4H6C3.79,4,2,5.79,2,8v8c0,2.21,1.79,4,4,4h12c2.21,0,4-1.79,4-4V8C22,5.79,20.21,4,18,4z M16.14,13.77 c-0.24,0.2-0.57,0.28-0.88,0.2L4.15,11.25C4.45,10.52,5.16,10,6,10h12c0.67,0,1.26,0.34,1.63,0.84L16.14,13.77z M6,6h12 c1.1,0,2,0.9,2,2v0.55C19.41,8.21,18.73,8,18,8H6C5.27,8,4.59,8.21,4,8.55V8C4,6.9,4.9,6,6,6z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Wallet
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<h5>Balance</h5>
|
||||||
|
<h1 class="h1" id="rupee_balance"></h1>
|
||||||
|
</div>
|
||||||
|
<div class="flex">
|
||||||
|
<button class="wallet-action" onclick="walletAction('deposit')">
|
||||||
|
<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="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" />
|
||||||
|
</svg>
|
||||||
|
Top-up wallet
|
||||||
|
</button>
|
||||||
|
<button class="wallet-action" onclick="walletAction('deposit')">
|
||||||
|
<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>
|
||||||
|
<rect fill="none" height="24" width="24" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<rect height="7" width="3" x="4" y="10" />
|
||||||
|
<rect height="7" width="3" x="10.5" y="10" />
|
||||||
|
<rect height="3" width="20" x="2" y="19" />
|
||||||
|
<rect height="7" width="3" x="17" y="10" />
|
||||||
|
<polygon points="12,1 2,6 2,8 22,8 22,6" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
Transfer to bank
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="wallet_history_wrapper" class="grid gap-0-5">
|
||||||
|
<h4>Wallet history</h4>
|
||||||
|
<ul id="wallet_history" class="observe-empty-state"></ul>
|
||||||
<div class=" empty-state gap-1 justify-center text-center">
|
<div class=" empty-state gap-1 justify-center text-center">
|
||||||
<h4>No transactions</h4>
|
<h4>No transactions</h4>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="settings" class="inner-page 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>
|
||||||
<section id="activity" class="page hide grid gap-1">
|
<section class="admin-element grid gap-1">
|
||||||
<h4>Activity</h4>
|
<h4>Change UPI ID</h4>
|
||||||
<tab-header target="user_sections">
|
<sm-form style="width: min(100%,24rem);">
|
||||||
<sm-tab>Wallet transactions</sm-tab>
|
<sm-input id="upi_id" placeholder="UPI ID" pattern="[a-zA-Z0-9_]{3,}@[a-zA-Z]{3,}"
|
||||||
<sm-tab>Payment requests</sm-tab>
|
error-text="Invalid UPI ID" animate required></sm-input>
|
||||||
</tab-header>
|
<button class="button button--primary cta justify-self-start" type="submit" onclick="changeUpi()">
|
||||||
<tab-panels id="user_sections">
|
Change
|
||||||
<section>
|
</button>
|
||||||
<ul id="user-cashier-requests" class="observe-empty-state"></ul>
|
</sm-form>
|
||||||
<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>
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<nav id="main_navbar">
|
<nav id="main_navbar">
|
||||||
@ -238,7 +428,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#/history" class="nav-item interact">
|
<a href="#/history" class="nav-item interact" title='View payment requests'>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
|
<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">
|
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
|
||||||
<path d="M0,0h24v24H0V0z" fill="none" />
|
<path d="M0,0h24v24H0V0z" fill="none" />
|
||||||
@ -255,13 +445,29 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#/activity" class="nav-item interact user-element">
|
<a href="#/requests" class="nav-item interact" title='View payment requests'>
|
||||||
|
<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>
|
||||||
|
<rect fill="none" height="24" width="24" />
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M20,2H4.01c-1.1,0-2,0.9-2,2L2,22l4-4h14c1.1,0,2-0.9,2-2V4C22,2.9,21.1,2,20,2z M12,6c1.1,0,2,0.9,2,2s-0.9,2-2,2 s-2-0.9-2-2S10.9,6,12,6z M16,14H8v-0.57c0-0.81,0.48-1.53,1.22-1.85C10.07,11.21,11.01,11,12,11c0.99,0,1.93,0.21,2.78,0.58 C15.52,11.9,16,12.62,16,13.43V14z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="nav-item__title">Requests</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#/wallet" class="nav-item interact" title='View payment requests'>
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
|
||||||
width="24px" fill="#000000">
|
width="24px" fill="#000000">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none" />
|
||||||
<path
|
<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" />
|
d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="nav-item__title">Activity</span>
|
<span class="nav-item__title">Wallet</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -282,6 +488,60 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<!-- Popups -->
|
<!-- Popups -->
|
||||||
|
<sm-popup id="add_address_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="saveId()" type="submit">Save</button>
|
||||||
|
</sm-form>
|
||||||
|
</sm-popup>
|
||||||
|
<sm-popup id="edit_saved_popup">
|
||||||
|
<header slot="header" class="popup__header">
|
||||||
|
<div class="flex align-center">
|
||||||
|
<button class="popup__header__close" 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>
|
||||||
|
<h3>Edit</h3>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section class="grid gap-1-5">
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<h5>FLO ID</h5>
|
||||||
|
<sm-copy id="edit_saved_id"></sm-copy>
|
||||||
|
</div>
|
||||||
|
<sm-form>
|
||||||
|
<sm-input id="newAddrLabel" placeholder="Name" autofocus animate required></sm-input>
|
||||||
|
<div class="flex align-center space-between">
|
||||||
|
<button class="button icon-only" title="Delete this FLO ID?" onclick="deleteSaved()">
|
||||||
|
<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="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="button button--primary cta" type="submit" onclick="saveChanges()">Save</button>
|
||||||
|
</div>
|
||||||
|
</sm-form>
|
||||||
|
</section>
|
||||||
|
</sm-popup>
|
||||||
<sm-popup id="token_transfer_popup">
|
<sm-popup id="token_transfer_popup">
|
||||||
<header slot="header" class="popup__header">
|
<header slot="header" class="popup__header">
|
||||||
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
|
<button class="popup__header__close justify-self-start" onclick="hidePopup()">
|
||||||
@ -319,8 +579,40 @@
|
|||||||
</sm-form>
|
</sm-form>
|
||||||
</section>
|
</section>
|
||||||
</sm-popup>
|
</sm-popup>
|
||||||
|
<sm-popup id="wallet_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 id="wallet_popup__title"></h4>
|
||||||
|
</header>
|
||||||
|
<sm-form>
|
||||||
|
<sm-input id="request_cashier_amount" type="number" name="amount" placeholder="Amount" animate>
|
||||||
|
</sm-input>
|
||||||
|
<button id="wallet_popup__cta" class="button button--primary cta" type="submit">Save</button>
|
||||||
|
</sm-form>
|
||||||
|
</sm-popup>
|
||||||
|
|
||||||
<!-- templates -->
|
<!-- templates -->
|
||||||
|
<template id="saved_id_template">
|
||||||
|
<li class="saved-id grid interact" tabindex="0">
|
||||||
|
<button class="interact edit-saved" title="Edit saved ID">
|
||||||
|
<div class="saved-id__initials"></div>
|
||||||
|
<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="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<h4 class="saved-id__title"></h4>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
<template id="transaction_template">
|
<template id="transaction_template">
|
||||||
<li class="transaction grid">
|
<li class="transaction grid">
|
||||||
<div class="transaction__icon"></div>
|
<div class="transaction__icon"></div>
|
||||||
@ -341,12 +633,13 @@
|
|||||||
</template>
|
</template>
|
||||||
<template id="wallet_request_template">
|
<template id="wallet_request_template">
|
||||||
<li class="wallet-request flex-wrap">
|
<li class="wallet-request flex-wrap">
|
||||||
<div class="grid gap-0-5 flex-1">
|
<div class="flex align-center space-between">
|
||||||
<div class="wallet-request__requestor breakable"></div>
|
|
||||||
<time class="wallet-request__time"></time>
|
<time class="wallet-request__time"></time>
|
||||||
|
<div class="wallet-request__status flex align-center"></div>
|
||||||
|
</div>
|
||||||
|
<div class="grid gap-0-5 flex-1">
|
||||||
|
<div class="wallet-request__details"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wallet-request__mode"></div>
|
|
||||||
<div class="wallet-request__status"></div>
|
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
<template id="payment_request_template">
|
<template id="payment_request_template">
|
||||||
@ -362,6 +655,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
<template id="transaction_message_template">
|
||||||
|
<li class="transaction-message grid">
|
||||||
|
<h3 class="transaction-message__amount"></h3>
|
||||||
|
<time class="transaction-message__time"></time>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
<script src="scripts/components.js"></script>
|
<script src="scripts/components.js"></script>
|
||||||
<script src="scripts/std_ui.js"></script>
|
<script src="scripts/std_ui.js"></script>
|
||||||
<script src="scripts/std_op.js"></script>
|
<script src="scripts/std_op.js"></script>
|
||||||
@ -369,13 +668,18 @@
|
|||||||
<script src="scripts/fn_ui.js"></script>
|
<script src="scripts/fn_ui.js"></script>
|
||||||
<script id="onLoadStartUp">
|
<script id="onLoadStartUp">
|
||||||
function onLoadStartUp() {
|
function onLoadStartUp() {
|
||||||
|
showPage('loading')
|
||||||
console.log("Starting the app! Please Wait!")
|
console.log("Starting the app! Please Wait!")
|
||||||
|
floDapps.setCustomPrivKeyInput(getSignedIn)
|
||||||
|
floDapps.setAppObjectStores({ savedIds: {} })
|
||||||
floDapps.launchStartUp().then(result => {
|
floDapps.launchStartUp().then(result => {
|
||||||
console.log(`Welcome ${myFloID}`);
|
console.log(`Welcome ${myFloID}`);
|
||||||
getRef('logged_in_user_id').value = myFloID;
|
getRef('logged_in_user_id').value = myFloID;
|
||||||
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
|
||||||
tokenAPI.getBalance(myFloID).then(balance => {
|
tokenAPI.getBalance(myFloID).then(balance => {
|
||||||
getRef('rupee_balance').textContent = balance.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
|
const formattedBalance = formatAmount(balance)
|
||||||
|
const [beforeDecimal, afterDecimal] = formattedBalance.split('.')
|
||||||
|
getRef('rupee_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
|
||||||
})
|
})
|
||||||
if (floGlobals.isSubAdmin) {
|
if (floGlobals.isSubAdmin) {
|
||||||
cashierUI.renderRequests(Cashier.Requests);
|
cashierUI.renderRequests(Cashier.Requests);
|
||||||
@ -383,10 +687,10 @@
|
|||||||
console.log(result);
|
console.log(result);
|
||||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.remove('hide'))
|
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.remove('hide'))
|
||||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.add('hide'))
|
document.querySelectorAll('.user-element').forEach(elem => elem.classList.add('hide'))
|
||||||
getRef('loader').classList.add('hide')
|
showPage(window.location.hash, { firstLoad: true })
|
||||||
getRef('main_card').classList.remove('hide')
|
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
} else {
|
} else {
|
||||||
|
userUI.renderSavedIds()
|
||||||
userUI.renderCashierRequests(User.cashierRequests);
|
userUI.renderCashierRequests(User.cashierRequests);
|
||||||
userUI.renderMoneyRequests(User.moneyRequests);
|
userUI.renderMoneyRequests(User.moneyRequests);
|
||||||
User.init().then(result => {
|
User.init().then(result => {
|
||||||
@ -394,12 +698,9 @@
|
|||||||
console.log("Cashiers:", cashierUPI);
|
console.log("Cashiers:", cashierUPI);
|
||||||
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hide'))
|
document.querySelectorAll('.admin-element').forEach(elem => elem.classList.add('hide'))
|
||||||
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hide'))
|
document.querySelectorAll('.user-element').forEach(elem => elem.classList.remove('hide'))
|
||||||
getRef('loader').classList.add('hide')
|
showPage(window.location.hash, { firstLoad: true })
|
||||||
getRef('main_card').classList.remove('hide')
|
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
renderAllTokenTransactions();
|
|
||||||
showPage(window.location.hash, { firstLoad: true })
|
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -689,148 +689,150 @@ customElements.define('sm-input',
|
|||||||
})
|
})
|
||||||
const smNotifications = document.createElement('template')
|
const smNotifications = document.createElement('template')
|
||||||
smNotifications.innerHTML = `
|
smNotifications.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
*{
|
*{
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
:host{
|
:host{
|
||||||
display: flex;
|
display: flex;
|
||||||
--icon-height: 1.5rem;
|
--icon-height: 1.5rem;
|
||||||
--icon-width: 1.5rem;
|
--icon-width: 1.5rem;
|
||||||
}
|
|
||||||
.hide{
|
|
||||||
opacity: 0 !important;
|
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
|
||||||
.notification-panel{
|
|
||||||
display: grid;
|
|
||||||
width: 100%;
|
|
||||||
gap: 0.5rem;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 100;
|
|
||||||
max-height: 100%;
|
|
||||||
padding: 1rem;
|
|
||||||
overflow: hidden auto;
|
|
||||||
-ms-scroll-chaining: none;
|
|
||||||
overscroll-behavior: contain;
|
|
||||||
}
|
|
||||||
.notification-panel:empty{
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
.notification{
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 0.3rem;
|
|
||||||
background: rgba(var(--background-color, (255,255,255)), 1);
|
|
||||||
overflow: hidden;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-wrap: break-word;
|
|
||||||
-ms-word-break: break-all;
|
|
||||||
word-break: break-all;
|
|
||||||
word-break: break-word;
|
|
||||||
-ms-hyphens: auto;
|
|
||||||
-webkit-hyphens: auto;
|
|
||||||
hyphens: auto;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 1rem;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.icon-container:not(:empty){
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
height: var(--icon-height);
|
|
||||||
width: var(--icon-width);
|
|
||||||
}
|
|
||||||
h4:first-letter,
|
|
||||||
p:first-letter{
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
h4{
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
p{
|
|
||||||
line-height: 1.6;
|
|
||||||
-webkit-box-flex: 1;
|
|
||||||
-ms-flex: 1;
|
|
||||||
flex: 1;
|
|
||||||
color: rgba(var(--text-color, (17,17,17)), 0.9);
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-wrap: break-word;
|
|
||||||
-ms-word-break: break-all;
|
|
||||||
word-break: break-all;
|
|
||||||
word-break: break-word;
|
|
||||||
-ms-hyphens: auto;
|
|
||||||
-webkit-hyphens: auto;
|
|
||||||
hyphens: auto;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
.notification:last-of-type{
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
fill: rgba(var(--text-color, (17,17,17)), 0.7);
|
|
||||||
}
|
|
||||||
.icon--success {
|
|
||||||
fill: var(--green);
|
|
||||||
}
|
|
||||||
.icon--failure,
|
|
||||||
.icon--error {
|
|
||||||
fill: var(--danger-color);
|
|
||||||
}
|
|
||||||
.close{
|
|
||||||
height: 2rem;
|
|
||||||
width: 2rem;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 1rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 0.3rem;
|
|
||||||
transition: background-color 0.3s, transform 0.3s;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
.close:active{
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 640px){
|
|
||||||
.notification-panel{
|
|
||||||
max-width: 28rem;
|
|
||||||
width: max-content;
|
|
||||||
}
|
|
||||||
.notification{
|
|
||||||
width: auto;
|
|
||||||
border: solid 1px rgba(var(--text-color, (17,17,17)), 0.2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (any-hover: hover){
|
|
||||||
::-webkit-scrollbar{
|
|
||||||
width: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb{
|
|
||||||
background: rgba(var(--text-color, (17,17,17)), 0.3);
|
|
||||||
border-radius: 1rem;
|
|
||||||
&:hover{
|
|
||||||
background: rgba(var(--text-color, (17,17,17)), 0.5);
|
|
||||||
}
|
}
|
||||||
}
|
.hide{
|
||||||
.close:hover{
|
opacity: 0 !important;
|
||||||
background-color: rgba(var(--text-color, (17,17,17)), 0.1);
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
}
|
.notification-panel{
|
||||||
</style>
|
display: grid;
|
||||||
<div class="notification-panel"></div>
|
width: 100%;
|
||||||
`;
|
gap: 0.5rem;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
max-height: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
overflow: hidden auto;
|
||||||
|
-ms-scroll-chaining: none;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.notification-panel:empty{
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.notification{
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
background: rgba(var(--foreground-color, (255,255,255)), 1);
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
.icon-container:not(:empty){
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
height: var(--icon-height);
|
||||||
|
width: var(--icon-width);
|
||||||
|
}
|
||||||
|
h4:first-letter,
|
||||||
|
p:first-letter{
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
h4{
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
p{
|
||||||
|
line-height: 1.6;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
color: rgba(var(--text-color, (17,17,17)), 0.9);
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.notification:last-of-type{
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
fill: rgba(var(--text-color, (17,17,17)), 0.7);
|
||||||
|
}
|
||||||
|
.icon--success {
|
||||||
|
fill: var(--green);
|
||||||
|
}
|
||||||
|
.icon--failure,
|
||||||
|
.icon--error {
|
||||||
|
fill: var(--danger-color);
|
||||||
|
}
|
||||||
|
.close{
|
||||||
|
height: 2rem;
|
||||||
|
width: 2rem;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 0.3rem;
|
||||||
|
transition: background-color 0.3s, transform 0.3s;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.close:active{
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 640px){
|
||||||
|
.notification-panel{
|
||||||
|
max-width: 28rem;
|
||||||
|
width: max-content;
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.notification{
|
||||||
|
width: auto;
|
||||||
|
border: solid 1px rgba(var(--text-color, (17,17,17)), 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (any-hover: hover){
|
||||||
|
::-webkit-scrollbar{
|
||||||
|
width: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb{
|
||||||
|
background: rgba(var(--text-color, (17,17,17)), 0.3);
|
||||||
|
border-radius: 1rem;
|
||||||
|
&:hover{
|
||||||
|
background: rgba(var(--text-color, (17,17,17)), 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.close:hover{
|
||||||
|
background-color: rgba(var(--text-color, (17,17,17)), 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="notification-panel"></div>
|
||||||
|
`;
|
||||||
customElements.define('sm-notifications', class extends HTMLElement {
|
customElements.define('sm-notifications', class extends HTMLElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -849,7 +851,23 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
this.createNotification = this.createNotification.bind(this)
|
this.createNotification = this.createNotification.bind(this)
|
||||||
this.removeNotification = this.removeNotification.bind(this)
|
this.removeNotification = this.removeNotification.bind(this)
|
||||||
this.clearAll = this.clearAll.bind(this)
|
this.clearAll = this.clearAll.bind(this)
|
||||||
|
this.handlePointerMove = this.handlePointerMove.bind(this)
|
||||||
|
|
||||||
|
|
||||||
|
this.startX = 0;
|
||||||
|
this.currentX = 0;
|
||||||
|
this.endX = 0;
|
||||||
|
this.swipeDistance = 0;
|
||||||
|
this.swipeDirection = '';
|
||||||
|
this.swipeThreshold = 0;
|
||||||
|
this.startTime = 0;
|
||||||
|
this.swipeTime = 0;
|
||||||
|
this.swipeTimeThreshold = 200;
|
||||||
|
this.currentTarget = null;
|
||||||
|
|
||||||
|
this.mediaQuery = window.matchMedia('(min-width: 640px)')
|
||||||
|
this.handleOrientationChange = this.handleOrientationChange.bind(this)
|
||||||
|
this.isLandscape = false
|
||||||
}
|
}
|
||||||
|
|
||||||
randString(length) {
|
randString(length) {
|
||||||
@ -867,16 +885,16 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
notification.classList.add('notification');
|
notification.classList.add('notification');
|
||||||
let composition = ``;
|
let composition = ``;
|
||||||
composition += `
|
composition += `
|
||||||
<div class="icon-container">${icon}</div>
|
<div class="icon-container">${icon}</div>
|
||||||
<p>${message}</p>
|
<p>${message}</p>
|
||||||
`;
|
`;
|
||||||
if (pinned) {
|
if (pinned) {
|
||||||
notification.classList.add('pinned');
|
notification.classList.add('pinned');
|
||||||
composition += `
|
composition += `
|
||||||
<button class="close">
|
<button class="close">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></svg>
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
notification.innerHTML = composition;
|
notification.innerHTML = composition;
|
||||||
return notification;
|
return notification;
|
||||||
@ -884,28 +902,45 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
|
|
||||||
push(message, options = {}) {
|
push(message, options = {}) {
|
||||||
const notification = this.createNotification(message, options);
|
const notification = this.createNotification(message, options);
|
||||||
this.notificationPanel.append(notification);
|
if (this.isLandscape)
|
||||||
|
this.notificationPanel.append(notification);
|
||||||
|
else
|
||||||
|
this.notificationPanel.prepend(notification);
|
||||||
|
this.notificationPanel.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: `translateY(${this.isLandscape ? '' : '-'}${notification.clientHeight}px)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transform: `none`,
|
||||||
|
},
|
||||||
|
], this.animationOptions
|
||||||
|
)
|
||||||
notification.animate([
|
notification.animate([
|
||||||
{
|
{
|
||||||
transform: `translateY(1rem)`,
|
transform: `translateY(-1rem)`,
|
||||||
opacity: '0'
|
opacity: '0'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transform: `none`,
|
transform: `none`,
|
||||||
opacity: '1'
|
opacity: '1'
|
||||||
},
|
},
|
||||||
], this.animationOptions);
|
], this.animationOptions).onfinish = (e) => {
|
||||||
|
e.target.commitStyles()
|
||||||
|
e.target.cancel()
|
||||||
|
}
|
||||||
return notification.id;
|
return notification.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeNotification(notification) {
|
removeNotification(notification, direction = 'left') {
|
||||||
|
const sign = direction === 'left' ? '-' : '+';
|
||||||
notification.animate([
|
notification.animate([
|
||||||
{
|
{
|
||||||
transform: `none`,
|
transform: this.currentX ? `translateX(${this.currentX}px)` : `none`,
|
||||||
opacity: '1'
|
opacity: '1'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
transform: `translateY(0.5rem)`,
|
transform: `translateX(calc(${sign}${Math.abs(this.currentX)}px ${sign} 1rem))`,
|
||||||
opacity: '0'
|
opacity: '0'
|
||||||
}
|
}
|
||||||
], this.animationOptions).onfinish = () => {
|
], this.animationOptions).onfinish = () => {
|
||||||
@ -919,7 +954,70 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePointerMove(e) {
|
||||||
|
this.currentX = e.clientX - this.startX;
|
||||||
|
this.currentTarget.style.transform = `translateX(${this.currentX}px)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOrientationChange(e) {
|
||||||
|
this.isLandscape = e.matches
|
||||||
|
if (e.matches) {
|
||||||
|
// landscape
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// portrait
|
||||||
|
}
|
||||||
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
|
||||||
|
this.handleOrientationChange(this.mediaQuery);
|
||||||
|
|
||||||
|
this.mediaQuery.addEventListener('change', this.handleOrientationChange);
|
||||||
|
this.notificationPanel.addEventListener('pointerdown', e => {
|
||||||
|
if (e.target.closest('.notification')) {
|
||||||
|
this.swipeThreshold = this.clientWidth / 2;
|
||||||
|
this.currentTarget = e.target.closest('.notification');
|
||||||
|
this.currentTarget.setPointerCapture(e.pointerId);
|
||||||
|
this.startTime = Date.now();
|
||||||
|
this.startX = e.clientX;
|
||||||
|
this.startY = e.clientY;
|
||||||
|
this.notificationPanel.addEventListener('pointermove', this.handlePointerMove);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.notificationPanel.addEventListener('pointerup', e => {
|
||||||
|
this.endX = e.clientX;
|
||||||
|
this.endY = e.clientY;
|
||||||
|
this.swipeDistance = Math.abs(this.endX - this.startX);
|
||||||
|
this.swipeTime = Date.now() - this.startTime;
|
||||||
|
if (this.endX > this.startX) {
|
||||||
|
this.swipeDirection = 'right';
|
||||||
|
} else {
|
||||||
|
this.swipeDirection = 'left';
|
||||||
|
}
|
||||||
|
if (this.swipeTime < this.swipeTimeThreshold) {
|
||||||
|
if (this.swipeDistance > 50)
|
||||||
|
this.removeNotification(this.currentTarget, this.swipeDirection);
|
||||||
|
} else {
|
||||||
|
if (this.swipeDistance > this.swipeThreshold) {
|
||||||
|
this.removeNotification(this.currentTarget, this.swipeDirection);
|
||||||
|
} else {
|
||||||
|
this.currentTarget.animate([
|
||||||
|
{
|
||||||
|
transform: `translateX(${this.currentX}px)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transform: `none`,
|
||||||
|
},
|
||||||
|
], this.animationOptions).onfinish = (e) => {
|
||||||
|
e.target.commitStyles()
|
||||||
|
e.target.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.notificationPanel.removeEventListener('pointermove', this.handlePointerMove)
|
||||||
|
this.notificationPanel.releasePointerCapture(e.pointerId);
|
||||||
|
this.currentX = 0;
|
||||||
|
});
|
||||||
this.notificationPanel.addEventListener('click', e => {
|
this.notificationPanel.addEventListener('click', e => {
|
||||||
if (e.target.closest('.close')) {
|
if (e.target.closest('.close')) {
|
||||||
this.removeNotification(e.target.closest('.notification'));
|
this.removeNotification(e.target.closest('.notification'));
|
||||||
@ -941,8 +1039,10 @@ customElements.define('sm-notifications', class extends HTMLElement {
|
|||||||
childList: true,
|
childList: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
mediaQueryList.removeEventListener('change', handleOrientationChange);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class Stack {
|
class Stack {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.items = [];
|
this.items = [];
|
||||||
@ -1830,7 +1930,6 @@ smCopy.innerHTML = `
|
|||||||
}
|
}
|
||||||
.copy{
|
.copy{
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 100%;
|
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
padding: var(--padding);
|
padding: var(--padding);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -1851,8 +1950,15 @@ smCopy.innerHTML = `
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
background-color: inherit;
|
background-color: rgba(var(--text-color, (17,17,17)), 0.06);
|
||||||
border-radius: var(--button-border-radius, 0.3rem);
|
border-radius: var(--button-border-radius, 0.3rem);
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
font-family: inherit;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05rem;
|
||||||
}
|
}
|
||||||
.copy-button:active{
|
.copy-button:active{
|
||||||
background-color: var(--button-background-color);
|
background-color: var(--button-background-color);
|
||||||
@ -1866,9 +1972,6 @@ smCopy.innerHTML = `
|
|||||||
.copy:hover .copy-button{
|
.copy:hover .copy-button{
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.copy-button{
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
.copy-button:hover{
|
.copy-button:hover{
|
||||||
background-color: var(--button-background-color);
|
background-color: var(--button-background-color);
|
||||||
}
|
}
|
||||||
@ -1878,7 +1981,7 @@ smCopy.innerHTML = `
|
|||||||
<p class="copy-content"></p>
|
<p class="copy-content"></p>
|
||||||
<button part="button" class="copy-button" title="copy">
|
<button part="button" class="copy-button" title="copy">
|
||||||
<slot name="copy-icon">
|
<slot name="copy-icon">
|
||||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z"/></svg>
|
COPY
|
||||||
</slot>
|
</slot>
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
@ -2265,14 +2368,19 @@ customElements.define('strip-select', class extends HTMLElement {
|
|||||||
this.slottedOptions = undefined;
|
this.slottedOptions = undefined;
|
||||||
this._value = undefined;
|
this._value = undefined;
|
||||||
this.scrollDistance = 0;
|
this.scrollDistance = 0;
|
||||||
|
this.assignedElements = [];
|
||||||
|
|
||||||
this.scrollLeft = this.scrollLeft.bind(this);
|
this.scrollLeft = this.scrollLeft.bind(this);
|
||||||
this.scrollRight = this.scrollRight.bind(this);
|
this.scrollRight = this.scrollRight.bind(this);
|
||||||
this.fireEvent = this.fireEvent.bind(this);
|
this.fireEvent = this.fireEvent.bind(this);
|
||||||
|
this.setSelectedOption = this.setSelectedOption.bind(this);
|
||||||
}
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
|
set value(val) {
|
||||||
|
this.setSelectedOption(val);
|
||||||
|
}
|
||||||
scrollLeft() {
|
scrollLeft() {
|
||||||
this.stripSelect.scrollBy({
|
this.stripSelect.scrollBy({
|
||||||
left: -this.scrollDistance,
|
left: -this.scrollDistance,
|
||||||
@ -2286,6 +2394,19 @@ customElements.define('strip-select', class extends HTMLElement {
|
|||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setSelectedOption(value) {
|
||||||
|
if (this._value === value) return
|
||||||
|
this._value = value;
|
||||||
|
this.assignedElements.forEach(elem => {
|
||||||
|
if (elem.value === value) {
|
||||||
|
elem.setAttribute('active', '');
|
||||||
|
elem.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elem.removeAttribute('active')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fireEvent() {
|
fireEvent() {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent("change", {
|
new CustomEvent("change", {
|
||||||
@ -2306,17 +2427,17 @@ customElements.define('strip-select', class extends HTMLElement {
|
|||||||
const navButtonLeft = this.shadowRoot.querySelector('.nav-button--left');
|
const navButtonLeft = this.shadowRoot.querySelector('.nav-button--left');
|
||||||
const navButtonRight = this.shadowRoot.querySelector('.nav-button--right');
|
const navButtonRight = this.shadowRoot.querySelector('.nav-button--right');
|
||||||
slot.addEventListener('slotchange', e => {
|
slot.addEventListener('slotchange', e => {
|
||||||
const assignedElements = slot.assignedElements();
|
this.assignedElements = slot.assignedElements();
|
||||||
assignedElements.forEach(elem => {
|
this.assignedElements.forEach(elem => {
|
||||||
if (elem.hasAttribute('selected')) {
|
if (elem.hasAttribute('selected')) {
|
||||||
elem.setAttribute('active', '');
|
elem.setAttribute('active', '');
|
||||||
this._value = elem.value;
|
this._value = elem.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!this.hasAttribute('multiline')) {
|
if (!this.hasAttribute('multiline')) {
|
||||||
if (assignedElements.length > 0) {
|
if (this.assignedElements.length > 0) {
|
||||||
firstOptionObserver.observe(slot.assignedElements()[0]);
|
firstOptionObserver.observe(this.assignedElements[0]);
|
||||||
lastOptionObserver.observe(slot.assignedElements()[slot.assignedElements().length - 1]);
|
lastOptionObserver.observe(this.assignedElements[this.assignedElements.length - 1]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
navButtonLeft.classList.add('hide');
|
navButtonLeft.classList.add('hide');
|
||||||
@ -2343,10 +2464,7 @@ customElements.define('strip-select', class extends HTMLElement {
|
|||||||
resObs.observe(this);
|
resObs.observe(this);
|
||||||
this.stripSelect.addEventListener('option-clicked', e => {
|
this.stripSelect.addEventListener('option-clicked', e => {
|
||||||
if (this._value !== e.target.value) {
|
if (this._value !== e.target.value) {
|
||||||
this._value = e.target.value;
|
this.setSelectedOption(e.target.value);
|
||||||
slot.assignedElements().forEach(elem => elem.removeAttribute('active'));
|
|
||||||
e.target.setAttribute('active', '');
|
|
||||||
e.target.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
|
||||||
this.fireEvent();
|
this.fireEvent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
334
scripts/fn_ui.js
334
scripts/fn_ui.js
@ -1,37 +1,47 @@
|
|||||||
/*jshint esversion: 6 */
|
/*jshint esversion: 8 */
|
||||||
|
/**
|
||||||
|
* @yaireo/relative-time - javascript function to transform timestamp or date to local relative-time
|
||||||
|
*
|
||||||
|
* @version v1.0.0
|
||||||
|
* @homepage https://github.com/yairEO/relative-time
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function (e, t) { var o = o || {}; "function" == typeof o && o.amd ? o([], t) : "object" == typeof exports && "object" == typeof module ? module.exports = t() : "object" == typeof exports ? exports.RelativeTime = t() : e.RelativeTime = t() }(this, (function () { const e = { year: 31536e6, month: 2628e6, day: 864e5, hour: 36e5, minute: 6e4, second: 1e3 }, t = "en", o = { numeric: "auto" }; function n(e) { e = { locale: (e = e || {}).locale || t, options: { ...o, ...e.options } }, this.rtf = new Intl.RelativeTimeFormat(e.locale, e.options) } return n.prototype = { from(t, o) { const n = t - (o || new Date); for (let t in e) if (Math.abs(n) > e[t] || "second" == t) return this.rtf.format(Math.round(n / e[t]), t) } }, n }));
|
||||||
|
|
||||||
|
const relativeTime = new RelativeTime({ style: 'narrow' });
|
||||||
const userUI = {};
|
const userUI = {};
|
||||||
|
|
||||||
userUI.requestTokenFromCashier = function () {
|
getRef('wallet_popup__cta').addEventListener('click', function () {
|
||||||
let cashier = User.findCashier();
|
let cashier = User.findCashier();
|
||||||
if (!cashier)
|
|
||||||
return alert("No cashier online");
|
|
||||||
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
|
let amount = parseFloat(getRef('request_cashier_amount').value.trim());
|
||||||
//get UPI txid from user
|
if (walletAction === 'deposit') {
|
||||||
let upiTxID = prompt(`Send Rs. ${amount} to ${cashierUPI[cashier]} and enter UPI txid`);
|
//get UPI txid from user
|
||||||
if (!upiTxID)
|
let upiTxID = prompt(`Send Rs. ${amount} to ${cashierUPI[cashier]} and enter UPI txid`);
|
||||||
return alert("Cancelled");
|
if (!upiTxID)
|
||||||
User.cashToToken(cashier, amount, upiTxID).then(result => {
|
return alert("Cancelled");
|
||||||
console.log(result);
|
User.cashToToken(cashier, amount, upiTxID).then(result => {
|
||||||
alert("Requested cashier. please wait!");
|
|
||||||
}).catch(error => console.error(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
userUI.withdrawCashFromCashier = function () {
|
|
||||||
let cashier = User.findCashier();
|
|
||||||
if (!cashier)
|
|
||||||
return alert("No cashier online");
|
|
||||||
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`);
|
|
||||||
if (!upiID)
|
|
||||||
return alert("Cancelled");
|
|
||||||
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
|
|
||||||
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
|
|
||||||
User.tokenToCash(cashier, amount, txid, upiID).then(result => {
|
|
||||||
console.log(result);
|
console.log(result);
|
||||||
alert("Requested cashier. please wait!");
|
alert("Requested cashier. please wait!");
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}).catch(error => console.error(error))
|
} else {
|
||||||
|
//get confirmation from user
|
||||||
|
let upiID = prompt(`${amount} ${floGlobals.currency}# will be sent to ${cashier}. Enter UPI ID`);
|
||||||
|
if (!upiID)
|
||||||
|
return alert("Cancelled");
|
||||||
|
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
|
||||||
|
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
|
||||||
|
User.tokenToCash(cashier, amount, txid, upiID).then(result => {
|
||||||
|
console.log(result);
|
||||||
|
alert("Requested cashier. please wait!");
|
||||||
|
}).catch(error => console.error(error))
|
||||||
|
}).catch(error => console.error(error))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
function walletAction(type) {
|
||||||
|
let cashier = User.findCashier();
|
||||||
|
if (!cashier)
|
||||||
|
return notify("No cashier online. Please try again in a while.", 'error');
|
||||||
|
showPopup('wallet_popup')
|
||||||
}
|
}
|
||||||
|
|
||||||
userUI.sendMoneyToUser = function (floID, amount, remark) {
|
userUI.sendMoneyToUser = function (floID, amount, remark) {
|
||||||
@ -63,13 +73,15 @@ userUI.renderCashierRequests = function (requests, error = null) {
|
|||||||
return console.error(error);
|
return console.error(error);
|
||||||
else if (typeof requests !== "object" || requests === null)
|
else if (typeof requests !== "object" || requests === null)
|
||||||
return;
|
return;
|
||||||
const frag = document.createDocumentFragment()
|
if (pagesData.lastPage === 'history' && pagesData.params.type === 'wallet') {
|
||||||
for (let r in requests) {
|
const frag = document.createDocumentFragment()
|
||||||
let oldCard = document.getElementById(r);
|
for (let transactionID in requests) {
|
||||||
if (oldCard) oldCard.remove();
|
let oldCard = getRef('wallet_history').querySelector(`#${transactionID}`);
|
||||||
frag.append(render.walletRequestCard(requests[r]))
|
if (oldCard) oldCard.remove();
|
||||||
|
frag.append(render.walletRequestCard(transactionID, requests[transactionID]))
|
||||||
|
}
|
||||||
|
getRef('wallet_history').prepend(frag)
|
||||||
}
|
}
|
||||||
getRef('user-cashier-requests').append(frag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userUI.renderMoneyRequests = function (requests, error = null) {
|
userUI.renderMoneyRequests = function (requests, error = null) {
|
||||||
@ -86,6 +98,32 @@ userUI.renderMoneyRequests = function (requests, error = null) {
|
|||||||
getRef('user-money-requests').append(frag)
|
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(Crypto.AES.decrypt(dataToDecrypt, myPrivKey));
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key in floGlobals.savedIds) {
|
||||||
|
frag.append(render.savedId(key, floGlobals.savedIds[key]));
|
||||||
|
}
|
||||||
|
getRef('saved_ids_list').append(frag);
|
||||||
|
}
|
||||||
|
|
||||||
userUI.payRequest = function (reqID) {
|
userUI.payRequest = function (reqID) {
|
||||||
let request = User.moneyRequests[reqID];
|
let request = User.moneyRequests[reqID];
|
||||||
getConfirmation('Pay?', { message: `Do you want to pay ${request.message.amount} to ${request.senderID}?` }).then(confirmation => {
|
getConfirmation('Pay?', { message: `Do you want to pay ${request.message.amount} to ${request.senderID}?` }).then(confirmation => {
|
||||||
@ -183,71 +221,116 @@ function completeTokenToCashRequest(request) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAllTokenTransactions() {
|
function getFloIdTitle(floID) {
|
||||||
tokenAPI.getAllTxs(myFloID).then(result => {
|
return floGlobals.savedIds[floID] ? floGlobals.savedIds[floID].title : floID;
|
||||||
getRef('token_transactions').innerHTML = ''
|
}
|
||||||
const frag = document.createDocumentFragment();
|
|
||||||
for (let txid in result.transactions) {
|
function formatAmount(amount) {
|
||||||
frag.append(render.transactionCard(txid, tokenAPI.util.parseTxData(result.transactions[txid])))
|
return amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
|
||||||
}
|
}
|
||||||
getRef('token_transactions').append(frag)
|
|
||||||
}).catch(error => console.error(error))
|
function getStatusIcon(status) {
|
||||||
|
switch (status) {
|
||||||
|
case 'PENDING':
|
||||||
|
return '<i class="fas fa-clock"></i>';
|
||||||
|
case 'COMPLETED':
|
||||||
|
return '<i class="fas fa-check"></i>';
|
||||||
|
case 'REJECTED':
|
||||||
|
return '<i class="fas fa-times"></i>';
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const render = {
|
const render = {
|
||||||
transactionCard(txid, transactionDetails) {
|
savedId(floID, details) {
|
||||||
const { time, sender, receiver, tokenAmount } = transactionDetails
|
const { title } = details.hasOwnProperty('title') ? details : { title: details };
|
||||||
|
const clone = getRef('saved_id_template').content.cloneNode(true).firstElementChild;
|
||||||
|
clone.dataset.floId = floID;
|
||||||
|
clone.querySelector('.saved-id__initials').textContent = title.charAt(0);
|
||||||
|
clone.querySelector('.saved-id__title').textContent = title;
|
||||||
|
return clone;
|
||||||
|
},
|
||||||
|
transactionCard(transactionDetails) {
|
||||||
|
const { txid, time, sender, receiver, tokenAmount } = transactionDetails;
|
||||||
const clone = getRef('transaction_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('transaction_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.dataset.txid = txid
|
clone.dataset.txid = txid;
|
||||||
clone.querySelector('.transaction__time').textContent = getFormattedTime(time * 1000)
|
clone.querySelector('.transaction__time').textContent = getFormattedTime(time * 1000);
|
||||||
clone.querySelector('.transaction__amount').textContent = tokenAmount
|
clone.querySelector('.transaction__amount').textContent = formatAmount(tokenAmount);
|
||||||
if (sender === myFloID) {
|
if (sender === myFloID) {
|
||||||
clone.querySelector('.transaction__amount').classList.add('sent')
|
clone.classList.add('sent');
|
||||||
clone.querySelector('.transaction__receiver').textContent = `Sent to ${receiver || 'Myself'}`
|
clone.querySelector('.transaction__receiver').textContent = `Sent to ${getFloIdTitle(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__icon').innerHTML = `<svg class="icon sent" 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="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>`;
|
||||||
} else if (receiver === myFloID) {
|
} else if (receiver === myFloID) {
|
||||||
clone.querySelector('.transaction__amount').classList.add('received')
|
clone.classList.add('received');
|
||||||
clone.querySelector('.transaction__receiver').textContent = `Received from ${sender}`
|
clone.querySelector('.transaction__receiver').textContent = `Received from ${getFloIdTitle(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__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 0h24v24H0V0z" fill="none"/><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"/></svg>`;
|
||||||
} else { //This should not happen unless API returns transaction that does not involve myFloID
|
} else { //This should not happen unless API returns transaction that does not involve myFloID
|
||||||
row.insertCell().textContent = tx.sender;
|
row.insertCell().textContent = tx.sender;
|
||||||
row.insertCell().textContent = tx.receiver;
|
row.insertCell().textContent = tx.receiver;
|
||||||
}
|
}
|
||||||
return clone
|
return clone;
|
||||||
},
|
},
|
||||||
cashierRequestCard(details) {
|
cashierRequestCard(details) {
|
||||||
const { time, senderID, message: { mode }, note, tag, vectorClock } = details;
|
const { time, senderID, message: { mode }, note, tag, vectorClock } = details;
|
||||||
const clone = getRef('cashier_request_template').content.cloneNode(true).firstElementChild;
|
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
|
const status = tag || note; //status tag for completed, note for rejected
|
||||||
clone.querySelector('.cashier-request__requestor').textContent = senderID
|
clone.querySelector('.cashier-request__requestor').textContent = senderID;
|
||||||
clone.querySelector('.cashier-request__time').textContent = getFormattedTime(time)
|
clone.querySelector('.cashier-request__time').textContent = getFormattedTime(time);
|
||||||
clone.querySelector('.cashier-request__mode').textContent = mode
|
clone.querySelector('.cashier-request__mode').textContent = mode;
|
||||||
if (status)
|
if (status)
|
||||||
clone.querySelector('.cashier-request__status').textContent = status
|
clone.querySelector('.cashier-request__status').textContent = status;
|
||||||
else
|
else
|
||||||
clone.querySelector('.cashier-request__status').innerHTML = `<button class="button" onclick="cashierUI.completeRequest('${vectorClock}')">Process</button>`
|
clone.querySelector('.cashier-request__status').innerHTML = `<button class="button" onclick="cashierUI.completeRequest('${vectorClock}')">Process</button>`;
|
||||||
return clone
|
return clone;
|
||||||
},
|
},
|
||||||
walletRequestCard(details) {
|
walletRequestCard(details) {
|
||||||
const { time, receiverID, message: { mode }, note, tag, vectorClock } = details;
|
const { time, message: { mode, amount }, note, tag, vectorClock } = details;
|
||||||
const clone = getRef('wallet_request_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('wallet_request_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.id = vectorClock
|
clone.id = vectorClock;
|
||||||
clone.querySelector('.wallet-request__requestor').textContent = receiverID
|
clone.querySelector('.wallet-request__details').textContent = `${mode === 'cash-to-token' ? 'Deposit' : 'Withdraw'} ${formatAmount(amount)}`;
|
||||||
clone.querySelector('.wallet-request__time').textContent = getFormattedTime(time)
|
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 ? 'REJECTED' : "PENDING");
|
||||||
let status = tag ? (tag + ":" + note) : (note || "PENDING");
|
let icon = '';
|
||||||
clone.querySelector('.wallet-request__status').textContent = status
|
switch (status) {
|
||||||
return clone
|
case 'COMPLETED':
|
||||||
|
clone.children[1].append(
|
||||||
|
createElement('div', {
|
||||||
|
className: 'flex flex-wrap align-center wallet-request__note',
|
||||||
|
innerHTML: `<b>Transaction ID:</b><sm-copy value="${note}"></sm-copy>`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
icon = `<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 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>`
|
||||||
|
break;
|
||||||
|
case 'REJECTED':
|
||||||
|
clone.children[1].append(
|
||||||
|
createElement('div', {
|
||||||
|
className: 'wallet-request__note',
|
||||||
|
innerHTML: note.split(':')[1]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
icon = `<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="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>`
|
||||||
|
break;
|
||||||
|
case 'PENDING':
|
||||||
|
icon = `<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><rect fill="none" height="24" width="24"/></g><g><g><g><path d="M12,2C6.5,2,2,6.5,2,12s4.5,10,10,10s10-4.5,10-10S17.5,2,12,2z M16.2,16.2L11,13V7h1.5v5.2l4.5,2.7L16.2,16.2z"/></g></g></g></svg>`
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clone.querySelector('.wallet-request__status').innerHTML = `${icon}${status}`;
|
||||||
|
clone.querySelector('.wallet-request__status').classList.add(status.toLowerCase());
|
||||||
|
return clone;
|
||||||
},
|
},
|
||||||
paymentRequestCard(details) {
|
paymentRequestCard(details) {
|
||||||
const { time, senderID, message: { amount, remark }, note, vectorClock } = details;
|
const { time, senderID, message: { amount, remark }, note, vectorClock } = details;
|
||||||
const clone = getRef('payment_request_template').content.cloneNode(true).firstElementChild;
|
const clone = getRef('payment_request_template').content.cloneNode(true).firstElementChild;
|
||||||
clone.id = vectorClock
|
clone.id = vectorClock;
|
||||||
clone.querySelector('.payment-request__requestor').textContent = senderID
|
clone.querySelector('.payment-request__requestor').textContent = senderID;
|
||||||
clone.querySelector('.payment-request__time').textContent = getFormattedTime(time)
|
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__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' });
|
||||||
clone.querySelector('.payment-request__remark').textContent = remark
|
clone.querySelector('.payment-request__remark').textContent = remark;
|
||||||
|
|
||||||
let status = note;
|
let status = note;
|
||||||
if (status)
|
if (status)
|
||||||
@ -257,20 +340,75 @@ const render = {
|
|||||||
`<button class="button" onclick="userUI.payRequest('${vectorClock}')">Pay</button>
|
`<button class="button" onclick="userUI.payRequest('${vectorClock}')">Pay</button>
|
||||||
<button class="button" onclick="userUI.declineRequest('${vectorClock}')">Decline</button>`;
|
<button class="button" onclick="userUI.declineRequest('${vectorClock}')">Decline</button>`;
|
||||||
|
|
||||||
return clone
|
return clone;
|
||||||
},
|
},
|
||||||
}
|
transactionMessage(details) {
|
||||||
|
const { tokenAmount, time, sender, receiver } = tokenAPI.util.parseTxData(details)
|
||||||
|
let messageType = sender === receiver ? 'self' : sender === myFloID ? 'sent' : 'received';
|
||||||
|
const clone = getRef('transaction_message_template').content.cloneNode(true).firstElementChild;
|
||||||
|
clone.classList.add(messageType);
|
||||||
|
clone.querySelector('.transaction-message__amount').textContent = formatAmount(tokenAmount);
|
||||||
|
clone.querySelector('.transaction-message__time').textContent = getFormattedTime(time * 1000);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let currentUserAction
|
let currentUserAction;
|
||||||
function showTokenTransfer(type) {
|
function showTokenTransfer(type) {
|
||||||
getRef('tt_button').textContent = type;
|
getRef('tt_button').textContent = type;
|
||||||
currentUserAction = type
|
currentUserAction = type;
|
||||||
if (type === 'send') {
|
if (type === 'send') {
|
||||||
getRef('token_transfer__title').textContent = 'Send money to FLO ID';
|
getRef('token_transfer__title').textContent = 'Send money to FLO ID';
|
||||||
} else {
|
} else {
|
||||||
getRef('token_transfer__title').textContent = 'Request money from FLO ID';
|
getRef('token_transfer__title').textContent = 'Request money from FLO ID';
|
||||||
}
|
}
|
||||||
showPopup('token_transfer_popup')
|
showPopup('token_transfer_popup');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveId() {
|
||||||
|
const floID = getRef('flo_id_to_save').value.trim();
|
||||||
|
const title = getRef('flo_id_title_to_save').value.trim();
|
||||||
|
floGlobals.savedIds[floID] = { title }
|
||||||
|
getRef('saved_ids_list').append(render.savedId(floID, { title }));
|
||||||
|
syncSavedIds().then(() => {
|
||||||
|
notify(`Saved ${floID}`, 'success');
|
||||||
|
hidePopup();
|
||||||
|
}).catch(error => {
|
||||||
|
notify(error, 'error');
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function syncSavedIds() {
|
||||||
|
const dataToSend = Crypto.AES.encrypt(JSON.stringify(floGlobals.savedIds), myPrivKey);
|
||||||
|
return floCloudAPI.sendApplicationData(dataToSend, 'savedIds', { receiverID: myFloID });
|
||||||
|
}
|
||||||
|
delegate(getRef('saved_ids_list'), 'click', '.saved-id', e => {
|
||||||
|
if (e.target.closest('.edit-saved')) {
|
||||||
|
const target = e.target.closest('.saved-id');
|
||||||
|
getRef('edit_saved_id').setAttribute('value', target.dataset.floId);
|
||||||
|
getRef('newAddrLabel').value = getFloIdTitle(target.dataset.floId);
|
||||||
|
showPopup('edit_saved_popup');
|
||||||
|
} else {
|
||||||
|
const target = e.target.closest('.saved-id');
|
||||||
|
window.location.hash = `#/contact?floId=${target.dataset.floId}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function deleteSaved() {
|
||||||
|
getConfirmation('Do you want delete this FLO ID?', {
|
||||||
|
confirmText: 'Delete',
|
||||||
|
}).then(res => {
|
||||||
|
if (res) {
|
||||||
|
const toDelete = getRef('saved_ids_list').querySelector(`.saved-id[data-flo-id="${getRef('edit_saved_id').value}"]`);
|
||||||
|
if (toDelete)
|
||||||
|
toDelete.remove();
|
||||||
|
delete floGlobals.savedIds[getRef('edit_saved_id').value];
|
||||||
|
hidePopup();
|
||||||
|
syncSavedIds().then(() => {
|
||||||
|
notify(`Deleted saved ID`, 'success');
|
||||||
|
}).catch(error => {
|
||||||
|
notify(error, 'error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeUserAction() {
|
function executeUserAction() {
|
||||||
@ -278,28 +416,46 @@ function executeUserAction() {
|
|||||||
amount = parseFloat(getRef('tt_amount').value),
|
amount = parseFloat(getRef('tt_amount').value),
|
||||||
remark = getRef('tt_remark').value.trim();
|
remark = getRef('tt_remark').value.trim();
|
||||||
if (currentUserAction === 'send') {
|
if (currentUserAction === 'send') {
|
||||||
userUI.sendMoneyToUser(floID, amount, remark)
|
userUI.sendMoneyToUser(floID, amount, remark);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
userUI.requestMoneyFromUser(floID, amount, remark)
|
userUI.requestMoneyFromUser(floID, amount, remark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeUpi() {
|
function changeUpi() {
|
||||||
const upiID = getRef('upi_id').value.trim()
|
const upiID = getRef('upi_id').value.trim();
|
||||||
Cashier.updateUPI(upiID).then(() => {
|
Cashier.updateUPI(upiID).then(() => {
|
||||||
notify('UPI ID updated successfully', 'success')
|
notify('UPI ID updated successfully', 'success');
|
||||||
}).catch(err => {
|
}).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() {
|
function signOut() {
|
||||||
getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave')
|
getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave')
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
await floDapps.clearCredentials()
|
await floDapps.clearCredentials();
|
||||||
location.reload()
|
location.reload();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
@ -2,6 +2,9 @@
|
|||||||
// Global variables
|
// Global variables
|
||||||
const domRefs = {};
|
const domRefs = {};
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
|
let paymentsHistoryLoader = null;
|
||||||
|
let walletHistoryLoader = null;
|
||||||
|
let contactHistoryLoader = null;
|
||||||
|
|
||||||
//Checks for internet connection status
|
//Checks for internet connection status
|
||||||
if (!navigator.onLine)
|
if (!navigator.onLine)
|
||||||
@ -186,7 +189,7 @@ function getFormattedTime(time, format) {
|
|||||||
return `${month} ${date}, ${year}`;
|
return `${month} ${date}, ${year}`;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return `${month} ${date} ${year}, ${finalHours}`;
|
return `${month} ${date}, ${year} at ${finalHours}`;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@ -253,17 +256,21 @@ function createRipple(event, target) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pagesData = {
|
const pagesData = {
|
||||||
params: {}
|
params: {},
|
||||||
|
openedPages: new Set(),
|
||||||
}
|
}
|
||||||
|
|
||||||
let tempData
|
|
||||||
async function showPage(targetPage, options = {}) {
|
async function showPage(targetPage, options = {}) {
|
||||||
const { firstLoad, hashChange, isPreview } = options
|
const { firstLoad, hashChange } = options
|
||||||
let pageId
|
let pageId
|
||||||
let params = {}
|
let params = {}
|
||||||
let searchParams
|
let searchParams
|
||||||
if (targetPage === '') {
|
if (targetPage === '') {
|
||||||
pageId = 'home'
|
if (typeof myFloID === "undefined") {
|
||||||
|
pageId = 'sign_in'
|
||||||
|
} else {
|
||||||
|
pageId = 'home'
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetPage.includes('/')) {
|
if (targetPage.includes('/')) {
|
||||||
if (targetPage.includes('?')) {
|
if (targetPage.includes('?')) {
|
||||||
@ -281,115 +288,216 @@ async function showPage(targetPage, options = {}) {
|
|||||||
pageId = targetPage
|
pageId = targetPage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (typeof myFloID === "undefined" && !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
||||||
|
else if (typeof myFloID !== "undefined" && (['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) {
|
||||||
|
history.replaceState(null, null, '#/home');
|
||||||
|
pageId = 'home'
|
||||||
|
}
|
||||||
if (searchParams) {
|
if (searchParams) {
|
||||||
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
||||||
params = Object.fromEntries(urlSearchParams.entries());
|
params = Object.fromEntries(urlSearchParams.entries());
|
||||||
}
|
}
|
||||||
|
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 'contact':
|
||||||
|
getRef('contact__title').textContent = getFloIdTitle(params.floId)
|
||||||
|
Promise.all([
|
||||||
|
tokenAPI.fetch_api(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${myFloID}&destFloAddress=${params.floId}`),
|
||||||
|
tokenAPI.fetch_api(`api/v1.0/getTokenTransactions?token=rupee&senderFloAddress=${params.floId}&destFloAddress=${myFloID}`)])
|
||||||
|
.then(([sentTransactions, receivedTransactions]) => {
|
||||||
|
const allTransactions = Object.values({ ...sentTransactions.transactions, ...receivedTransactions.transactions }).sort((a, b) => b.transactionDetails.time - a.transactionDetails.time)
|
||||||
|
if (contactHistoryLoader) {
|
||||||
|
contactHistoryLoader.update(allTransactions)
|
||||||
|
} else {
|
||||||
|
contactHistoryLoader = new LazyLoader('#contact__transactions', allTransactions, render.transactionMessage, { bottomFirst: true });
|
||||||
|
}
|
||||||
|
contactHistoryLoader.init()
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'history':
|
||||||
|
const paymentTransactions = []
|
||||||
|
if (paymentsHistoryLoader)
|
||||||
|
paymentsHistoryLoader.clear()
|
||||||
|
getRef('payments_history').innerHTML = '<sm-spinner></sm-spinner>'
|
||||||
|
tokenAPI.getAllTxs(myFloID).then(({ transactions }) => {
|
||||||
|
for (const transactionId in transactions) {
|
||||||
|
paymentTransactions.push({
|
||||||
|
...tokenAPI.util.parseTxData(transactions[transactionId]),
|
||||||
|
txid: transactionId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (paymentsHistoryLoader) {
|
||||||
|
paymentsHistoryLoader.update(paymentTransactions)
|
||||||
|
} else {
|
||||||
|
paymentsHistoryLoader = new LazyLoader('#payments_history', paymentTransactions, render.transactionCard);
|
||||||
|
}
|
||||||
|
paymentsHistoryLoader.init()
|
||||||
|
}).catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'wallet':
|
||||||
|
const walletTransactions = []
|
||||||
|
if (walletHistoryLoader)
|
||||||
|
walletHistoryLoader.clear()
|
||||||
|
getRef('wallet_history').innerHTML = '<sm-spinner></sm-spinner>'
|
||||||
|
const requests = User.cashierRequests;
|
||||||
|
for (const transactionId in requests) {
|
||||||
|
walletTransactions.push(User.cashierRequests[transactionId])
|
||||||
|
}
|
||||||
|
if (walletHistoryLoader) {
|
||||||
|
walletHistoryLoader.update(walletTransactions)
|
||||||
|
} else {
|
||||||
|
walletHistoryLoader = new LazyLoader('#wallet_history', walletTransactions, render.walletRequestCard);
|
||||||
|
}
|
||||||
|
walletHistoryLoader.init()
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pageId !== 'history') {
|
||||||
|
if (paymentsHistoryLoader)
|
||||||
|
paymentsHistoryLoader.clear()
|
||||||
|
}
|
||||||
|
if (pageId !== 'contact') {
|
||||||
|
if (contactHistoryLoader)
|
||||||
|
contactHistoryLoader.clear()
|
||||||
|
}
|
||||||
|
if (pageId !== 'wallet') {
|
||||||
|
if (walletHistoryLoader)
|
||||||
|
walletHistoryLoader.clear()
|
||||||
|
}
|
||||||
|
|
||||||
if (pagesData.lastPage !== pageId) {
|
if (pagesData.lastPage !== pageId) {
|
||||||
|
const animOptions = {
|
||||||
|
duration: 100,
|
||||||
|
fill: 'forwards',
|
||||||
|
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)'
|
||||||
|
}
|
||||||
|
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_card').classList.remove('nav-hidden')
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
], { ...animOptions, easing: 'ease-in' })
|
||||||
|
}
|
||||||
|
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_card').classList.add('nav-hidden')
|
||||||
|
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).closest('.page').classList.remove('hide')
|
||||||
|
document.querySelectorAll('.inner-page').forEach(page => page.classList.add('hide'))
|
||||||
|
getRef(pageId).classList.remove('hide')
|
||||||
|
getRef('main_card').style.overflowY = "hidden";
|
||||||
|
getRef(pageId).animate([
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateY(1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'translateY(0)'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 300,
|
||||||
|
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)'
|
||||||
|
}).onfinish = () => {
|
||||||
|
getRef('main_card').style.overflowY = "";
|
||||||
|
}
|
||||||
pagesData.lastPage = pageId
|
pagesData.lastPage = pageId
|
||||||
}
|
}
|
||||||
if (params)
|
if (params)
|
||||||
pagesData.params = params
|
pagesData.params = params
|
||||||
switch (pageId) {
|
pagesData.openedPages.add(pageId)
|
||||||
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 => {
|
const indicatorObserver = new IntersectionObserver(entries => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
if (!entry.isIntersecting) {
|
if (!entry.isIntersecting) {
|
||||||
@ -414,7 +522,7 @@ const indicatorObserver = new IntersectionObserver(entries => {
|
|||||||
// class based lazy loading
|
// class based lazy loading
|
||||||
class LazyLoader {
|
class LazyLoader {
|
||||||
constructor(container, elementsToRender, renderFn, options = {}) {
|
constructor(container, elementsToRender, renderFn, options = {}) {
|
||||||
const { batchSize = 10, freshRender } = options
|
const { batchSize = 10, freshRender, bottomFirst = false } = options
|
||||||
|
|
||||||
this.elementsToRender = elementsToRender
|
this.elementsToRender = elementsToRender
|
||||||
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||||
@ -423,6 +531,7 @@ class LazyLoader {
|
|||||||
|
|
||||||
this.batchSize = batchSize
|
this.batchSize = batchSize
|
||||||
this.freshRender = freshRender
|
this.freshRender = freshRender
|
||||||
|
this.bottomFirst = bottomFirst
|
||||||
|
|
||||||
this.lazyContainer = document.querySelector(container)
|
this.lazyContainer = document.querySelector(container)
|
||||||
|
|
||||||
@ -446,7 +555,11 @@ class LazyLoader {
|
|||||||
mutationList.forEach(mutation => {
|
mutationList.forEach(mutation => {
|
||||||
if (mutation.type === 'childList') {
|
if (mutation.type === 'childList') {
|
||||||
if (mutation.addedNodes.length) {
|
if (mutation.addedNodes.length) {
|
||||||
this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
|
if (this.bottomFirst)
|
||||||
|
this.intersectionObserver.observe(this.lazyContainer.firstElementChild)
|
||||||
|
else
|
||||||
|
this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -458,7 +571,6 @@ class LazyLoader {
|
|||||||
}
|
}
|
||||||
update(elementsToRender) {
|
update(elementsToRender) {
|
||||||
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||||
this.render()
|
|
||||||
}
|
}
|
||||||
render(options = {}) {
|
render(options = {}) {
|
||||||
let { lazyLoad = false } = options
|
let { lazyLoad = false } = options
|
||||||
@ -472,10 +584,21 @@ class LazyLoader {
|
|||||||
this.updateStartIndex = 0
|
this.updateStartIndex = 0
|
||||||
this.updateEndIndex = this.arrayOfElements.length > this.batchSize ? this.batchSize : this.arrayOfElements.length
|
this.updateEndIndex = this.arrayOfElements.length > this.batchSize ? this.batchSize : this.arrayOfElements.length
|
||||||
}
|
}
|
||||||
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
if (this.bottomFirst) {
|
||||||
frag.append(this.renderFn(this.arrayOfElements[index]))
|
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
||||||
|
frag.prepend(this.renderFn(this.arrayOfElements[index]))
|
||||||
|
}
|
||||||
|
this.lazyContainer.prepend(frag)
|
||||||
|
} else {
|
||||||
|
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
||||||
|
frag.append(this.renderFn(this.arrayOfElements[index]))
|
||||||
|
}
|
||||||
|
this.lazyContainer.append(frag)
|
||||||
}
|
}
|
||||||
this.lazyContainer.append(frag)
|
if (!lazyLoad && this.bottomFirst)
|
||||||
|
this.lazyContainer.scrollTo({
|
||||||
|
top: this.lazyContainer.scrollHeight,
|
||||||
|
})
|
||||||
// Callback to be called if elements are updated or rendered for first time
|
// Callback to be called if elements are updated or rendered for first time
|
||||||
if (!lazyLoad && this.freshRender)
|
if (!lazyLoad && this.freshRender)
|
||||||
this.freshRender()
|
this.freshRender()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user