First/Base commit
This commit is contained in:
commit
b88bf3e58f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.DS_Store
|
||||||
|
.vscode/
|
||||||
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Economic System for FLOBNB
|
||||||
|
|
||||||
|
Homepage to find all the details related to FLOBnb project
|
||||||
|
# economicsystem-mining
|
||||||
536
css/main.css
Normal file
536
css/main.css
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
/*
|
||||||
|
Add CSS variables here to change CSS of components
|
||||||
|
Suppose you want to customize button from component, just add
|
||||||
|
|
||||||
|
sm-button {
|
||||||
|
--background : #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Roboto", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-size: clamp(1rem, 1.2vmax, 3rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: rgba(var(--text-color), 1);
|
||||||
|
background: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
body,
|
||||||
|
body * {
|
||||||
|
--accent-color: #0d7377;
|
||||||
|
--text-color: 17, 17, 17;
|
||||||
|
--background-color: 255, 255, 255;
|
||||||
|
--danger-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
body[data-theme="dark"],
|
||||||
|
body[data-theme="dark"] * {
|
||||||
|
--accent-color: #32e0c4;
|
||||||
|
--text-color: 240, 240, 240;
|
||||||
|
--text-color-light: 170, 170, 170;
|
||||||
|
--background-color: 10, 10, 10;
|
||||||
|
--danger-color: rgb(255, 106, 106);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.8;
|
||||||
|
max-width: 65ch;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
p:not(:last-of-type) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:focus-visible {
|
||||||
|
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: inline-flex;
|
||||||
|
border: none;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:any-link:focus-visible {
|
||||||
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sm-button {
|
||||||
|
--border-radius: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-transformations {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-ellipsis {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakable {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-bleed {
|
||||||
|
grid-column: 1/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h2 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h3 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h4 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h5 {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uppercase {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.capitalize {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-3 {
|
||||||
|
grid-template-columns: 1fr auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-column {
|
||||||
|
grid-auto-flow: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-0-5 {
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-1 {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-1-5 {
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-2 {
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-3 {
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-start {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-start {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-right {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-self-center {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-self-center {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-self-start {
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-self-end {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.direction-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-0-8 {
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.weight-400 {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weight-500 {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ripple {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: scale(0);
|
||||||
|
background: rgba(var(--text-color), 0.16);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.interact {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.observe-empty-state:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.observe-empty-state:not(:empty) ~ .empty-state {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
fill: rgba(var(--text-color), 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button__icon {
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 1.2rem;
|
||||||
|
}
|
||||||
|
.button__icon--left {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
.button__icon--right {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#confirmation_popup,
|
||||||
|
#prompt_popup {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
#confirmation_popup h4,
|
||||||
|
#prompt_popup h4 {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
#confirmation_popup sm-button,
|
||||||
|
#prompt_popup sm-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#confirmation_popup .flex,
|
||||||
|
#prompt_popup .flex {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
#confirmation_popup .flex sm-button:first-of-type,
|
||||||
|
#prompt_popup .flex sm-button:first-of-type {
|
||||||
|
margin-right: 0.6rem;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4.h5 {
|
||||||
|
font-family: "Poppins", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 3rem 0 1rem 0;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-areas: "main-header" "." "side-nav";
|
||||||
|
}
|
||||||
|
|
||||||
|
#main_header {
|
||||||
|
grid-area: main-header;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-bottom: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
gap:0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 0 0.5rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
#logo h4 {
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
#logo #main_logo {
|
||||||
|
height: 1.4rem;
|
||||||
|
width: 1.4rem;
|
||||||
|
fill: rgba(var(--text-color), 1);
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#side_nav {
|
||||||
|
grid-area: side-nav;
|
||||||
|
}
|
||||||
|
#side_nav h4 {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
.nav-list li {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list__item {
|
||||||
|
display: flex;
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.nav-list__item--active {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
.nav-list__item--active .icon {
|
||||||
|
fill: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
.right h1 {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
padding: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup__header {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 1.5rem 0 0.8rem;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: auto 1fr auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup__header__close {
|
||||||
|
padding: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media screen and (max-width: 640px) {
|
||||||
|
main {
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list__item {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.4rem;
|
||||||
|
}
|
||||||
|
.nav-list__item span {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 640px) {
|
||||||
|
sm-popup {
|
||||||
|
--width: 32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
grid-template-columns: 14rem minmax(0, 1fr);
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-areas: "main-header main-header" "side-nav .";
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list__item {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
.nav-list__item--active {
|
||||||
|
background: rgba(var(--text-color), 0.06);
|
||||||
|
}
|
||||||
|
.nav-list__item .icon {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 90% 1fr;
|
||||||
|
}
|
||||||
|
.right > * {
|
||||||
|
grid-column: 2/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page__title {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup__header {
|
||||||
|
grid-column: 1/-1;
|
||||||
|
padding: 1rem 1.5rem 0 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (any-hover: hover) {
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(var(--text-color), 0.3);
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(var(--text-color), 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-list__item:hover {
|
||||||
|
background: rgba(var(--text-color), 0.1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
css/main.css.map
Normal file
9
css/main.css.map
Normal file
File diff suppressed because one or more lines are too long
1
css/main.min.css
vendored
Normal file
1
css/main.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
407
css/main.scss
Normal file
407
css/main.scss
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
*{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
}
|
||||||
|
:root{
|
||||||
|
font-size: clamp(1rem, 1.2vmax, 3rem);
|
||||||
|
}
|
||||||
|
html, body{
|
||||||
|
height: 100%;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
&,
|
||||||
|
*{
|
||||||
|
--accent-color: #0D7377;
|
||||||
|
--text-color: 17, 17, 17;
|
||||||
|
--background-color: 255, 255, 255;
|
||||||
|
--danger-color: red;
|
||||||
|
}
|
||||||
|
color: rgba(var(--text-color), 1);
|
||||||
|
background: rgba(var(--background-color), 1);
|
||||||
|
}
|
||||||
|
body[data-theme='dark']{
|
||||||
|
&,
|
||||||
|
*{
|
||||||
|
--accent-color: #32E0C4;
|
||||||
|
--text-color: 240, 240, 240;
|
||||||
|
--text-color-light: 170, 170, 170;
|
||||||
|
--background-color: 10, 10, 10;
|
||||||
|
--danger-color: rgb(255, 106, 106);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 0.8;
|
||||||
|
max-width: 65ch;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
&:not(:last-of-type){
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img{
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
a{
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
&:focus-visible{
|
||||||
|
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button{
|
||||||
|
display: inline-flex;
|
||||||
|
border: none;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:any-link:focus-visible{
|
||||||
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
|
}
|
||||||
|
sm-button{
|
||||||
|
--border-radius: 0.3rem;
|
||||||
|
}
|
||||||
|
ul{
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.flex{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.grid{
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.hide{
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.hide-completely{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.no-transformations{
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
.overflow-ellipsis{
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.breakable{
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
-ms-hyphens: auto;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
hyphens: auto;
|
||||||
|
}
|
||||||
|
.full-bleed{
|
||||||
|
grid-column: 1/4;
|
||||||
|
}
|
||||||
|
.h1{
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
.h2{
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
.h3{
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.h4{
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.h5{
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uppercase{
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.capitalize{
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.flex{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.grid{
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.grid-3{
|
||||||
|
grid-template-columns: 1fr auto auto;
|
||||||
|
}
|
||||||
|
.flow-column{
|
||||||
|
grid-auto-flow: column;
|
||||||
|
}
|
||||||
|
.gap-0-5{
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.gap-1{
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
.gap-1-5{
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
.gap-2{
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
.gap-3{
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
.text-align-right{
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.align-start{
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.align-center{
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.text-center{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.justify-start{
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
.justify-center{
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.justify-right{
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.align-self-center{
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.justify-self-center{
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
.justify-self-start{
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
.justify-self-end{
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
.direction-column{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.space-between{
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.w-100{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.color-0-8{
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
}
|
||||||
|
.weight-400{
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.weight-500{
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.ripple{
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: scale(0);
|
||||||
|
background: rgba(var(--text-color), 0.16);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.interact{
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
.observe-empty-state:empty{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.observe-empty-state:not(:empty) ~ .empty-state{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
fill: rgba(var(--text-color), 0.9);
|
||||||
|
}
|
||||||
|
.button__icon{
|
||||||
|
height: 1.2rem;
|
||||||
|
width: 1.2rem;
|
||||||
|
&--left{
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
&--right{
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#confirmation_popup,
|
||||||
|
#prompt_popup {
|
||||||
|
flex-direction: column;
|
||||||
|
h4 {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
sm-button{
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.flex {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 1rem;
|
||||||
|
sm-button:first-of-type {
|
||||||
|
margin-right: 0.6rem;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h1,h2,h3,h4.h5{
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
}
|
||||||
|
h2{
|
||||||
|
margin: 3rem 0 1rem 0;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
main{
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
grid-template-areas: 'main-header' '.' 'side-nav';
|
||||||
|
|
||||||
|
}
|
||||||
|
#main_header{
|
||||||
|
grid-area: main-header;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-bottom: 1px solid rgba(var(--text-color), .1);
|
||||||
|
}
|
||||||
|
#logo{
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 0 0.5rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
h4{
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
#main_logo{
|
||||||
|
height: 1.4rem;
|
||||||
|
width: 1.4rem;
|
||||||
|
fill: rgba(var(--text-color), 1);
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
#side_nav{
|
||||||
|
grid-area: side-nav;
|
||||||
|
h4{
|
||||||
|
font-size: 0.9rem;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-list{
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
li{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-list__item{
|
||||||
|
display: flex;
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
text-transform: capitalize;
|
||||||
|
&--active{
|
||||||
|
color: var(--accent-color);
|
||||||
|
.icon{
|
||||||
|
fill: var(--accent-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
padding: 1.5rem;
|
||||||
|
h1{
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.page{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 640px){
|
||||||
|
main{
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.nav-list__item{
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.4rem;
|
||||||
|
span{
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (min-width: 640px){
|
||||||
|
sm-popup{
|
||||||
|
--width: 32rem;
|
||||||
|
}
|
||||||
|
main{
|
||||||
|
grid-template-columns: 14rem minmax(0, 1fr);
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-areas: 'main-header main-header' 'side-nav .';
|
||||||
|
}
|
||||||
|
.nav-list{
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.nav-list__item{
|
||||||
|
align-items: center;
|
||||||
|
justify-content: start;
|
||||||
|
&--active{
|
||||||
|
background: rgba(var(--text-color), .06);
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.right{
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 90% 1fr;
|
||||||
|
& > * {
|
||||||
|
grid-column: 2/3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.page__title{
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (any-hover: hover){
|
||||||
|
::-webkit-scrollbar{
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb{
|
||||||
|
background: rgba(var(--text-color), 0.3);
|
||||||
|
border-radius: 1rem;
|
||||||
|
&:hover{
|
||||||
|
background: rgba(var(--text-color), 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-list__item:hover{
|
||||||
|
background: rgba(var(--text-color), .1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
11727
index.html
Normal file
11727
index.html
Normal file
File diff suppressed because it is too large
Load Diff
1176
js/components.min.js
vendored
Normal file
1176
js/components.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1110
js/floExchangeAPI.js
Normal file
1110
js/floExchangeAPI.js
Normal file
File diff suppressed because it is too large
Load Diff
53
js/floTokenAPI.js
Normal file
53
js/floTokenAPI.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* Token Operator to send/receive tokens from blockchain using API calls*/
|
||||||
|
(function(GLOBAL) {
|
||||||
|
const floTokenAPI = GLOBAL.floTokenAPI = {
|
||||||
|
fetch_api: function(apicall) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(floGlobals.tokenURL + apicall);
|
||||||
|
fetch(floGlobals.tokenURL + apicall).then(response => {
|
||||||
|
if (response.ok)
|
||||||
|
response.json().then(data => resolve(data));
|
||||||
|
else
|
||||||
|
reject(response)
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getBalance: function(floID, token = floGlobals.currency) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`)
|
||||||
|
.then(result => resolve(result.balance || 0))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getTx: function(txID) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.fetch_api(`api/v1.0/getTransactionDetails/${txID}`).then(res => {
|
||||||
|
if (res.result === "error")
|
||||||
|
reject(res.description);
|
||||||
|
else if (!res.parsedFloData)
|
||||||
|
reject("Data piece (parsedFloData) missing");
|
||||||
|
else if (!res.transactionDetails)
|
||||||
|
reject("Data piece (transactionDetails) missing");
|
||||||
|
else
|
||||||
|
resolve(res);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sendToken: function(privKey, amount, receiverID, message = "", token = floGlobals.currency) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let senderID = floCrypto.getFloID(privKey);
|
||||||
|
if (typeof amount !== "number" || amount <= 0)
|
||||||
|
return reject("Invalid amount");
|
||||||
|
this.getBalance(senderID, token).then(bal => {
|
||||||
|
if (amount > bal)
|
||||||
|
return reject("Insufficiant token balance");
|
||||||
|
floBlockchainAPI.writeData(senderID, `send ${amount} ${token}# ${message}`, privKey, receiverID)
|
||||||
|
.then(txid => resolve(txid))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(typeof global !== "undefined" ? global : window);
|
||||||
370
js/main_UI.js
Normal file
370
js/main_UI.js
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
// Global variables
|
||||||
|
const appPages = ['dashboard', 'userinfo', 'subadmin', 'settings'];
|
||||||
|
const domRefs = {};
|
||||||
|
let timerId;
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
|
//Checks for internet connection status
|
||||||
|
if (!navigator.onLine)
|
||||||
|
notify(
|
||||||
|
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
||||||
|
"error",
|
||||||
|
{ sound: true }
|
||||||
|
);
|
||||||
|
window.addEventListener("online", () => {
|
||||||
|
getRef("notification_drawer").clearAll();
|
||||||
|
notify("We are back online.", "success");
|
||||||
|
});
|
||||||
|
window.addEventListener("offline", () => {
|
||||||
|
notify(
|
||||||
|
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
||||||
|
"error",
|
||||||
|
{ pinned: true, sound: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use instead of document.getElementById
|
||||||
|
function getRef(elementId) {
|
||||||
|
if (!domRefs.hasOwnProperty(elementId)) {
|
||||||
|
domRefs[elementId] = {
|
||||||
|
count: 1,
|
||||||
|
ref: null,
|
||||||
|
};
|
||||||
|
return document.getElementById(elementId);
|
||||||
|
} else {
|
||||||
|
if (domRefs[elementId].count < 3) {
|
||||||
|
domRefs[elementId].count = domRefs[elementId].count + 1;
|
||||||
|
return document.getElementById(elementId);
|
||||||
|
} else {
|
||||||
|
if (!domRefs[elementId].ref)
|
||||||
|
domRefs[elementId].ref = document.getElementById(elementId);
|
||||||
|
return domRefs[elementId].ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns dom with specified element
|
||||||
|
function createElement(tagName, options) {
|
||||||
|
const { className, textContent, innerHTML, attributes = {} } = options
|
||||||
|
const elem = document.createElement(tagName)
|
||||||
|
for (let attribute in attributes) {
|
||||||
|
elem.setAttribute(attribute, attributes[attribute])
|
||||||
|
}
|
||||||
|
if (className)
|
||||||
|
elem.className = className
|
||||||
|
if (textContent)
|
||||||
|
elem.textContent = textContent
|
||||||
|
if (innerHTML)
|
||||||
|
elem.innerHTML = innerHTML
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use when a function needs to be executed after user finishes changes
|
||||||
|
const debounce = (callback, wait) => {
|
||||||
|
let timeoutId = null;
|
||||||
|
return (...args) => {
|
||||||
|
window.clearTimeout(timeoutId);
|
||||||
|
timeoutId = window.setTimeout(() => {
|
||||||
|
callback.apply(null, args);
|
||||||
|
}, wait);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limits the rate of function execution
|
||||||
|
function throttle(func, delay) {
|
||||||
|
// If setTimeout is already scheduled, no need to do anything
|
||||||
|
if (timerId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule a setTimeout after delay seconds
|
||||||
|
timerId = setTimeout(function () {
|
||||||
|
func();
|
||||||
|
|
||||||
|
// Once setTimeout function execution is finished, timerId = undefined so that in
|
||||||
|
// the next scroll event function execution can be scheduled by the setTimeout
|
||||||
|
timerId = undefined;
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
let zIndex = 10
|
||||||
|
// function required for popups or modals to appear
|
||||||
|
function showPopup(popupId, pinned) {
|
||||||
|
zIndex++
|
||||||
|
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
||||||
|
getRef(popupId).show({ pinned })
|
||||||
|
return getRef(popupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hides the popup or modal
|
||||||
|
function hidePopup() {
|
||||||
|
if (popupStack.peek() === undefined)
|
||||||
|
return;
|
||||||
|
popupStack.peek().popup.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// displays a popup for asking permission. Use this instead of JS confirm
|
||||||
|
const getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
showPopup('confirmation_popup', true)
|
||||||
|
getRef('confirm_title').textContent = title;
|
||||||
|
getRef('confirm_message').textContent = message;
|
||||||
|
let cancelButton = getRef('confirmation_popup').children[2].children[0],
|
||||||
|
submitButton = getRef('confirmation_popup').children[2].children[1]
|
||||||
|
submitButton.textContent = confirmText
|
||||||
|
cancelButton.textContent = cancelText
|
||||||
|
submitButton.onclick = () => {
|
||||||
|
hidePopup()
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
cancelButton.onclick = () => {
|
||||||
|
hidePopup()
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// displays a popup for asking user input. Use this instead of JS prompt
|
||||||
|
async function getPromptInput(title, message = '', isPassword = true, cancelText = 'Cancel', confirmText = 'OK') {
|
||||||
|
showPopup('prompt_popup', true)
|
||||||
|
getRef('prompt_title').textContent = title;
|
||||||
|
let input = getRef('prompt_input');
|
||||||
|
input.setAttribute("placeholder", message)
|
||||||
|
let buttons = getRef('prompt_popup').querySelectorAll("sm-button");
|
||||||
|
if (isPassword)
|
||||||
|
input.setAttribute("type", "text")
|
||||||
|
else
|
||||||
|
input.setAttribute("type", "password")
|
||||||
|
input.focusIn()
|
||||||
|
buttons[0].textContent = cancelText;
|
||||||
|
buttons[1].textContent = confirmText;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
buttons[0].onclick = () => {
|
||||||
|
hidePopup()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buttons[1].onclick = () => {
|
||||||
|
let value = input.value;
|
||||||
|
hidePopup()
|
||||||
|
resolve(value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Function for displaying toast notifications. pass in error for mode param if you want to show an error.
|
||||||
|
function notify(message, type, options = {}) {
|
||||||
|
const { pinned = false, sound = false } = options
|
||||||
|
let icon
|
||||||
|
switch (type) {
|
||||||
|
case 'success':
|
||||||
|
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="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"/></svg>`
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
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="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>`
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
getRef("notification_drawer").push(message, { pinned, icon });
|
||||||
|
if (navigator.onLine && sound) {
|
||||||
|
getRef("notification_sound").currentTime = 0;
|
||||||
|
getRef("notification_sound").play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFormatedTime(time, relative) {
|
||||||
|
try {
|
||||||
|
if (String(time).indexOf("_")) time = String(time).split("_")[0];
|
||||||
|
const intTime = parseInt(time);
|
||||||
|
if (String(intTime).length < 13) time *= 1000;
|
||||||
|
let timeFrag = new Date(intTime).toString().split(" "),
|
||||||
|
day = timeFrag[0],
|
||||||
|
month = timeFrag[1],
|
||||||
|
date = timeFrag[2],
|
||||||
|
year = timeFrag[3],
|
||||||
|
minutes = new Date(intTime).getMinutes(),
|
||||||
|
hours = new Date(intTime).getHours(),
|
||||||
|
currentTime = new Date().toString().split(" ");
|
||||||
|
|
||||||
|
minutes = minutes < 10 ? `0${minutes}` : minutes;
|
||||||
|
let finalHours = ``;
|
||||||
|
if (hours > 12) finalHours = `${hours - 12}:${minutes}`;
|
||||||
|
else if (hours === 0) finalHours = `12:${minutes}`;
|
||||||
|
else finalHours = `${hours}:${minutes}`;
|
||||||
|
|
||||||
|
finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`;
|
||||||
|
if (relative) {
|
||||||
|
return `${date} ${month} ${year}`;
|
||||||
|
} else return `${finalHours} ${month} ${date} ${year}`;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', e => showPage(window.location.hash))
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
document.body.classList.remove('hide')
|
||||||
|
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateAddr)
|
||||||
|
document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex)
|
||||||
|
showPage(window.location.hash)
|
||||||
|
document.addEventListener('keyup', (e) => {
|
||||||
|
if (e.code === 'Escape') {
|
||||||
|
hidePopup()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.addEventListener("pointerdown", (e) => {
|
||||||
|
if (e.target.closest("button, sm-button:not([disabled]), .interact")) {
|
||||||
|
createRipple(e, e.target.closest("button, sm-button, .interact"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener('copy', () => {
|
||||||
|
notify('copied', 'success')
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
function createRipple(event, target) {
|
||||||
|
const circle = document.createElement("span");
|
||||||
|
const diameter = Math.max(target.clientWidth, target.clientHeight);
|
||||||
|
const radius = diameter / 2;
|
||||||
|
const targetDimensions = target.getBoundingClientRect();
|
||||||
|
circle.style.width = circle.style.height = `${diameter}px`;
|
||||||
|
circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`;
|
||||||
|
circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`;
|
||||||
|
circle.classList.add("ripple");
|
||||||
|
const rippleAnimation = circle.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: "scale(3)",
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 1000,
|
||||||
|
fill: "forwards",
|
||||||
|
easing: "ease-out",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
target.append(circle);
|
||||||
|
rippleAnimation.onfinish = () => {
|
||||||
|
circle.remove();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPage(targetPage, options = {}) {
|
||||||
|
const { firstLoad, hashChange } = options
|
||||||
|
let pageId
|
||||||
|
if (targetPage === '') {
|
||||||
|
pageId = 'overview_page'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pageId = targetPage.includes('#') ? targetPage.split('#')[1] : targetPage
|
||||||
|
}
|
||||||
|
if (!appPages.includes(pageId)) return
|
||||||
|
document.querySelector('.page:not(.hide)').classList.add('hide')
|
||||||
|
document.querySelector('.nav-list__item--active').classList.remove('nav-list__item--active')
|
||||||
|
getRef(pageId).classList.remove('hide')
|
||||||
|
getRef(pageId).animate([
|
||||||
|
{
|
||||||
|
opacity: 0,
|
||||||
|
transform: 'translateX(-1rem)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
transform: 'none'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
duration: 300,
|
||||||
|
easing: 'ease'
|
||||||
|
})
|
||||||
|
const targetListItem = document.querySelector(`.nav-list__item[href="#${pageId}"]`)
|
||||||
|
targetListItem.classList.add('nav-list__item--active')
|
||||||
|
if (firstLoad && window.innerWidth > 640 && targetListItem.getBoundingClientRect().top > getRef('side_nav').getBoundingClientRect().height) {
|
||||||
|
getRef('side_nav').scrollTo({
|
||||||
|
top: (targetListItem.getBoundingClientRect().top - getRef('side_nav').getBoundingClientRect().top + getRef('side_nav').scrollTop),
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (hashChange && window.innerWidth < 640) {
|
||||||
|
getRef('side_nav').close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// class based lazy loading
|
||||||
|
class LazyLoader {
|
||||||
|
constructor(container, elementsToRender, renderFn, options = {}) {
|
||||||
|
const { batchSize = 10, freshRender } = options
|
||||||
|
|
||||||
|
this.elementsToRender = elementsToRender
|
||||||
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||||
|
this.renderFn = renderFn
|
||||||
|
this.intersectionObserver
|
||||||
|
|
||||||
|
this.batchSize = batchSize
|
||||||
|
this.freshRender = freshRender
|
||||||
|
|
||||||
|
this.lazyContainer = document.querySelector(container)
|
||||||
|
|
||||||
|
this.update = this.update.bind(this)
|
||||||
|
this.render = this.render.bind(this)
|
||||||
|
this.init = this.init.bind(this)
|
||||||
|
this.clear = this.clear.bind(this)
|
||||||
|
}
|
||||||
|
init() {
|
||||||
|
this.intersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
observer.disconnect()
|
||||||
|
this.render({ lazyLoad: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, {
|
||||||
|
threshold: 0.3
|
||||||
|
})
|
||||||
|
this.mutationObserver = new MutationObserver(mutationList => {
|
||||||
|
mutationList.forEach(mutation => {
|
||||||
|
if (mutation.type === 'childList') {
|
||||||
|
if (mutation.addedNodes.length) {
|
||||||
|
this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.mutationObserver.observe(this.lazyContainer, {
|
||||||
|
childList: true,
|
||||||
|
})
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
update(elementsToRender) {
|
||||||
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
render(options = {}) {
|
||||||
|
let { lazyLoad = false } = options
|
||||||
|
const frag = document.createDocumentFragment();
|
||||||
|
if (lazyLoad) {
|
||||||
|
this.updateStartIndex = this.updateEndIndex
|
||||||
|
this.updateEndIndex = this.arrayOfElements.length > this.updateEndIndex + this.batchSize ? this.updateEndIndex + this.batchSize : this.arrayOfElements.length
|
||||||
|
} else {
|
||||||
|
this.intersectionObserver.disconnect()
|
||||||
|
this.lazyContainer.innerHTML = ``;
|
||||||
|
this.updateStartIndex = 0
|
||||||
|
this.updateEndIndex = this.arrayOfElements.length > this.batchSize ? this.batchSize : this.arrayOfElements.length
|
||||||
|
}
|
||||||
|
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
||||||
|
frag.append(this.renderFn(this.arrayOfElements[index]))
|
||||||
|
}
|
||||||
|
this.lazyContainer.append(frag)
|
||||||
|
// Callback to be called if elements are updated or rendered for first time
|
||||||
|
if (!lazyLoad && this.freshRender)
|
||||||
|
this.freshRender()
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
this.intersectionObserver.disconnect()
|
||||||
|
this.mutationObserver.disconnect()
|
||||||
|
this.lazyContainer.innerHTML = ``;
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.arrayOfElements = (typeof this.elementsToRender === 'function') ? this.elementsToRender() : this.elementsToRender || []
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user