adding all aggregate visual design files
This commit is contained in:
parent
fabb5a21ba
commit
a9148a691c
712
aggregate.css
Normal file
712
aggregate.css
Normal file
@ -0,0 +1,712 @@
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
--primary-color: #303F9F;
|
||||
--text: 17, 17, 17;
|
||||
--text-light: 85, 85, 85;
|
||||
--foreground: 255, 255, 255;
|
||||
--background: #e8e8e8;
|
||||
--dark-shade: #dadada;
|
||||
background: var(--foreground);
|
||||
color: rgba(var(--text), 1);
|
||||
font-size: 16px;
|
||||
margin: 1.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.dark-text {
|
||||
color: #111;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
display: -webkit-inline-box;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
padding: 0.6rem 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border-radius: 0.2em;
|
||||
color: var(--primary-color);
|
||||
-webkit-transition: -webkit-transform 0.3s, -webkit-clip-path 0.3s;
|
||||
transition: -webkit-transform 0.3s, -webkit-clip-path 0.3s;
|
||||
transition: transform 0.3s, clip-path 0.3s;
|
||||
transition: transform 0.3s, clip-path 0.3s, -webkit-transform 0.3s, -webkit-clip-path 0.3s;
|
||||
border: none;
|
||||
-webkit-clip-path: circle(100%);
|
||||
clip-path: circle(100%);
|
||||
background: rgba(var(--text), 0.1);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: thin solid rgba(var(--text-light), 0.4);
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
cursor: default;
|
||||
background: rgba(var(--text-light), 1);
|
||||
}
|
||||
|
||||
button:disabled ~ .loader {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=text]::-ms-clear {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
input[type=text]::-ms-reveal {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
input[type="search"]::-webkit-search-decoration,
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-results-button,
|
||||
input[type="search"]::-webkit-search-results-decoration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
outline: none;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.bottom-padding {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
.top-padding {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.bottom-margin {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.top-margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: -ms-grid;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.grid-2 {
|
||||
-ms-grid-columns: auto auto;
|
||||
grid-template-columns: auto auto;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.light-text {
|
||||
color: rgba(var(--text-light), 1);
|
||||
}
|
||||
|
||||
.hide {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hide-completely {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.breakable {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.separator {
|
||||
padding: .1em;
|
||||
}
|
||||
|
||||
.no-transformations {
|
||||
-webkit-transform: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.loader {
|
||||
fill: none;
|
||||
stroke-width: 10;
|
||||
stroke: var(--primary-color);
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
overflow: visible;
|
||||
stroke-dashoffset: 230;
|
||||
stroke-dasharray: 230;
|
||||
padding: 2px;
|
||||
-ms-grid-column-align: center;
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotate {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes load {
|
||||
50% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: -210;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes load {
|
||||
50% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: -210;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-loader {
|
||||
-webkit-animation: load 2.6s infinite, rotate 1s infinite linear;
|
||||
animation: load 2.6s infinite, rotate 1s infinite linear;
|
||||
}
|
||||
|
||||
.expand {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fade-left {
|
||||
-webkit-animation: fadeleft 0.3s;
|
||||
animation: fadeleft 0.3s;
|
||||
}
|
||||
|
||||
.fade-right {
|
||||
-webkit-animation: faderight 0.3s;
|
||||
animation: faderight 0.3s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes faderight {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(-1em);
|
||||
transform: translateX(-1em);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes faderight {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(-1em);
|
||||
transform: translateX(-1em);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeleft {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(1em);
|
||||
transform: translateX(1em);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeleft {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(1em);
|
||||
transform: translateX(1em);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: -ms-inline-grid;
|
||||
display: inline-grid;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-ms-grid-columns: auto 1fr;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0.6rem 0.2rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
#logo h4 {
|
||||
letter-spacing: 0.06rem;
|
||||
word-spacing: 0.12rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
#logo h5 {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
#logo #main_logo {
|
||||
height: 1.4rem;
|
||||
width: 1.4rem;
|
||||
fill: rgba(var(--text), 1);
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.input {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 0.8em;
|
||||
margin-bottom: 1.5em;
|
||||
border-radius: 0.2em;
|
||||
background: rgba(var(--text), 0.1);
|
||||
border: 0.1em solid transparent;
|
||||
}
|
||||
|
||||
.input:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.input:focus-within {
|
||||
border: 0.1em solid var(--primary-color);
|
||||
}
|
||||
|
||||
.input label {
|
||||
opacity: .7;
|
||||
font-weight: 500;
|
||||
font-size: 1em;
|
||||
position: absolute;
|
||||
-webkit-transition: -webkit-transform 0.3s ease;
|
||||
transition: -webkit-transform 0.3s ease;
|
||||
transition: transform 0.3s ease;
|
||||
transition: transform 0.3s ease, -webkit-transform 0.3s ease;
|
||||
-webkit-transform-origin: left;
|
||||
transform-origin: left;
|
||||
pointer-events: none;
|
||||
will-change: contents;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.input input {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
color: rgba(var(--text), 1);
|
||||
}
|
||||
|
||||
.animate-label input {
|
||||
-webkit-transform: translateY(0.5em);
|
||||
transform: translateY(0.5em);
|
||||
}
|
||||
|
||||
.animate-label label {
|
||||
-webkit-transform: translateY(-60%) scale(0.7);
|
||||
transform: translateY(-60%) scale(0.7);
|
||||
opacity: 1;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.solid-background {
|
||||
background: var(--background) !important;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.popup-container {
|
||||
display: -ms-grid;
|
||||
display: grid;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
place-items: center;
|
||||
background: rgba(0, 0, 0, 0.24);
|
||||
z-index: 10;
|
||||
-webkit-transition: opacity 0.3s ease;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.popup-container .popup {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-ms-flex-item-align: end;
|
||||
align-self: flex-end;
|
||||
-webkit-box-align: start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
width: calc(100% - 2rem);
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.5rem;
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
background: rgba(var(--foreground), 1);
|
||||
-webkit-transform: translateY(100%);
|
||||
transform: translateY(100%);
|
||||
-webkit-transition: -webkit-transform 0.3s;
|
||||
transition: -webkit-transform 0.3s;
|
||||
transition: transform 0.3s;
|
||||
transition: transform 0.3s, -webkit-transform 0.3s;
|
||||
-webkit-box-shadow: 0 2rem 2rem rgba(0, 0, 0, 0.24);
|
||||
box-shadow: 0 2rem 2rem rgba(0, 0, 0, 0.24);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-container .popup h5 {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.popup-container .popup button:first-of-type {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.popup-container .popup .container-header {
|
||||
display: -ms-grid;
|
||||
display: grid;
|
||||
-ms-grid-columns: auto 1fr auto;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.popup-container .popup .container-header .icon {
|
||||
cursor: pointer;
|
||||
padding-right: 0.4rem;
|
||||
stroke-width: 8;
|
||||
}
|
||||
|
||||
.popup-container .popup .container-header .btn {
|
||||
padding: 0.6em 1.2em;
|
||||
}
|
||||
|
||||
.popup-container .popup p {
|
||||
margin-bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
#show_message {
|
||||
-webkit-transform: translate(0, -100%);
|
||||
transform: translate(0, -100%);
|
||||
-webkit-transition: opacity 0.3s, -webkit-transform 0.3s;
|
||||
transition: opacity 0.3s, -webkit-transform 0.3s;
|
||||
transition: transform 0.3s, opacity 0.3s;
|
||||
transition: transform 0.3s, opacity 0.3s, -webkit-transform 0.3s;
|
||||
-webkit-box-shadow: 0 0.4rem 0.8rem rgba(0, 0, 0, 0.16);
|
||||
box-shadow: 0 0.4rem 0.8rem rgba(0, 0, 0, 0.16);
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
color: rgba(var(--text), 1);
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: calc(100% - 2rem);
|
||||
margin: 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: solid 1px rgba(var(--text), 0.2);
|
||||
max-width: 100%;
|
||||
z-index: 40;
|
||||
background: rgba(var(--foreground), 1);
|
||||
}
|
||||
|
||||
#show_message #error_icon {
|
||||
fill: #E53935;
|
||||
}
|
||||
|
||||
#show_message #done_icon {
|
||||
fill: #00C853;
|
||||
}
|
||||
|
||||
#show_message .notification-icon {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
margin: 1em 0 1em 1em;
|
||||
fill: rgba(var(--text), 1);
|
||||
}
|
||||
|
||||
#show_message div {
|
||||
padding: 1em;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#show_message div h5 {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
#show_message span {
|
||||
font-weight: 500;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#show_message button {
|
||||
padding: 1rem;
|
||||
margin: 0 1em 0 0;
|
||||
border: none;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#show_message button svg {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
stroke: rgba(var(--text), 1);
|
||||
stroke-width: 6;
|
||||
}
|
||||
|
||||
#confirmation, #prompt {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
#confirmation p, #prompt p {
|
||||
margin: 1rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
color: rgba(var(--rgb-bw), 1) !important;
|
||||
}
|
||||
|
||||
#confirmation h4, #prompt h4 {
|
||||
font-weight: 500;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#confirmation .input, #prompt .input {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
#confirmation .btns, #prompt .btns {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: right;
|
||||
-ms-flex-pack: right;
|
||||
justify-content: right;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#confirmation .btns button, #prompt .btns button {
|
||||
background: none;
|
||||
}
|
||||
|
||||
#confirmation .btns button:first-of-type, #prompt .btns button:first-of-type {
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
.primary-btn {
|
||||
background: var(--primary-color);
|
||||
padding: 0.8em 1.6em;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
color: rgba(var(--foreground), 1);
|
||||
}
|
||||
.icon {
|
||||
height: 1.2rem;
|
||||
width: 1.2rem;
|
||||
fill: none;
|
||||
stroke: rgba(var(--text), 0.8);
|
||||
stroke-width: 6;
|
||||
overflow: visible;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.notification-dot::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 0.6em;
|
||||
width: 0.6em;
|
||||
background-color: #E53935;
|
||||
border-radius: 0.4em;
|
||||
-webkit-transition: -webkit-transform 0.3s;
|
||||
transition: -webkit-transform 0.3s;
|
||||
transition: transform 0.3s;
|
||||
transition: transform 0.3s, -webkit-transform 0.3s;
|
||||
}
|
||||
|
||||
.shrink.notification-dot::after {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
}
|
||||
#textCopied {
|
||||
padding: 1rem;
|
||||
border-radius: 2rem;
|
||||
background: rgba(var(--foreground), 1);
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
margin: 2rem 0;
|
||||
left: 50%;
|
||||
-webkit-transform: translateX(-50%);
|
||||
transform: translateX(-50%);
|
||||
-webkit-transition: 0.3s opacity ease;
|
||||
transition: 0.3s opacity ease;
|
||||
z-index: 20;
|
||||
}
|
||||
.tabs {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding: 1rem 0 1rem 0;
|
||||
background: rgba(var(--foreground), 1);
|
||||
z-index: 2;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.tabs .tab {
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
margin-right: 1.5rem;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
white-space: nowrap;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.tabs .tab:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.tabs .tab.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tabs .line {
|
||||
position: absolute;
|
||||
height: 0.12rem;
|
||||
background: rgba(var(--text), 1);
|
||||
width: 1px;
|
||||
bottom: 0;
|
||||
-webkit-transition: width 0.4s, -webkit-transform 0.4s;
|
||||
transition: width 0.4s, -webkit-transform 0.4s;
|
||||
transition: transform 0.4s, width 0.4s;
|
||||
transition: transform 0.4s, width 0.4s, -webkit-transform 0.4s;
|
||||
}
|
||||
@media only screen and (min-width: 640px) {
|
||||
.popup-container .popup {
|
||||
width: 24rem;
|
||||
-ms-flex-item-align: center;
|
||||
-ms-grid-row-align: center;
|
||||
align-self: center;
|
||||
border-radius: 0.2rem;
|
||||
height: auto;
|
||||
-webkit-transform: translateY(1rem);
|
||||
transform: translateY(1rem);
|
||||
}
|
||||
#show_message {
|
||||
-webkit-transform: translate(100%, 0);
|
||||
transform: translate(100%, 0);
|
||||
margin: 1rem;
|
||||
max-width: 60vw;
|
||||
width: -webkit-max-content;
|
||||
width: -moz-max-content;
|
||||
width: max-content;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
}
|
||||
349
aggregate.js
Normal file
349
aggregate.js
Normal file
@ -0,0 +1,349 @@
|
||||
//Checks for internet connection status
|
||||
if (!navigator.onLine)
|
||||
notify('There seems to be a problem connecting to the internet.', 'error', 'fixed', true)
|
||||
window.addEventListener('offline', () => {
|
||||
notify('There seems to be a problem connecting to the internet.', 'error', 'fixed', true)
|
||||
})
|
||||
window.addEventListener('online', () => {
|
||||
notify('We are back online.', '', '', true)
|
||||
})
|
||||
|
||||
// **** requires HTML****
|
||||
let themeToggler = document.getElementById("theme_toggle"),
|
||||
body = document.querySelector("body");
|
||||
if (localStorage.theme === "dark") {
|
||||
nightlight();
|
||||
themeToggler.checked = true;
|
||||
} else {
|
||||
daylight();
|
||||
themeToggler.checked = false;
|
||||
}
|
||||
|
||||
function daylight() {
|
||||
body.setAttribute("data-theme", "light");
|
||||
}
|
||||
|
||||
function nightlight() {
|
||||
body.setAttribute("data-theme", "dark");
|
||||
}
|
||||
themeToggler.addEventListener("change", () => {
|
||||
if (themeToggler.checked) {
|
||||
nightlight();
|
||||
localStorage.setItem("theme", "dark");
|
||||
} else {
|
||||
daylight();
|
||||
localStorage.setItem("theme", "light");
|
||||
}
|
||||
});
|
||||
// function required for popups or modals to appear
|
||||
class Stack {
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
push(element) {
|
||||
this.items.push(element);
|
||||
}
|
||||
pop() {
|
||||
if (this.items.length == 0)
|
||||
return "Underflow";
|
||||
return this.items.pop();
|
||||
}
|
||||
peek() {
|
||||
return this.items[this.items.length - 1];
|
||||
}
|
||||
}
|
||||
let popupStack = new Stack(),
|
||||
zIndex = 10;
|
||||
function showPopup(popup, permission) {
|
||||
let thisPopup = document.getElementById(popup);
|
||||
thisPopup.parentNode.classList.remove('hide');
|
||||
thisPopup.classList.add('no-transformations');
|
||||
popupStack.push({ popup, permission })
|
||||
zIndex++;
|
||||
thisPopup.parentNode.setAttribute('style', `z-index: ${zIndex}`)
|
||||
document.getElementById('main_page')
|
||||
if (popup === 'main_loader') {
|
||||
loader.classList.add('animate-loader')
|
||||
document.querySelector('main').classList.add('hide-completely')
|
||||
}
|
||||
}
|
||||
|
||||
// hides the popup or modal
|
||||
function hidePopup() {
|
||||
if (popupStack.peek() === undefined)
|
||||
return
|
||||
let { popup, permission } = popupStack.pop();
|
||||
thisPopup = document.getElementById(popup);
|
||||
thisPopup.closest('.popup-container').classList.add('hide');
|
||||
thisPopup.closest('.popup').classList.remove('no-transformations');
|
||||
setTimeout(() => {
|
||||
clearAllInputs(thisPopup)
|
||||
zIndex--;
|
||||
thisPopup.parentNode.setAttribute('style', `z-index: ${zIndex}`)
|
||||
}, 400)
|
||||
if (popup === 'main_loader' || popup === 'sign_in_popup') {
|
||||
//loader.classList.remove('animate-loader')
|
||||
document.querySelector('main').classList.remove('hide-completely')
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('mousedown', e => {
|
||||
if (e.target.classList.contains('popup-container') && popupStack.peek() !== undefined && popupStack.peek().permission !== 'no') {
|
||||
hidePopup()
|
||||
}
|
||||
})
|
||||
|
||||
function setAttributes(el, attrs) {
|
||||
for (var key in attrs) {
|
||||
el.setAttribute(key, attrs[key]);
|
||||
}
|
||||
}
|
||||
|
||||
function clearAllInputs(parent) {
|
||||
parent.querySelectorAll("input").forEach((field) => {
|
||||
if (field.getAttribute('type') !== 'radio') {
|
||||
field.value = '';
|
||||
if (field.closest('.input')) {
|
||||
field.closest('.input').classList.remove('animate-label')
|
||||
}
|
||||
}
|
||||
else
|
||||
field.checked = false
|
||||
})
|
||||
if (parent.querySelector("button[type='submit']"))
|
||||
parent.querySelector("button[type='submit']").disabled = true;
|
||||
}
|
||||
|
||||
//Function for displaying toast notifications.
|
||||
// **** requires HTML****
|
||||
/*options
|
||||
message - notifiation body text.
|
||||
mode - error or normal notification. only error has to be specified.
|
||||
fixed - if set true notification will not fade after 4s;
|
||||
sound - set true to enable notification sound. ! should only be used for important tasks.
|
||||
setAside - set true to add notification inside notification panel
|
||||
*/
|
||||
function notify(message, mode, behavior, sound) {
|
||||
let banner = document.getElementById('show_message'),
|
||||
back;
|
||||
if (mode === 'error') {
|
||||
banner.querySelector('#error_icon').classList.remove('hide-completely')
|
||||
banner.querySelector('#done_icon').classList.add('hide-completely')
|
||||
}
|
||||
else {
|
||||
banner.querySelector('#error_icon').classList.add('hide-completely')
|
||||
banner.querySelector('#done_icon').classList.remove('hide-completely')
|
||||
}
|
||||
|
||||
banner.style.background = back;
|
||||
banner.classList.add('no-transformations')
|
||||
banner.classList.remove('hide')
|
||||
banner.querySelector('#notification_text').textContent = message.charAt(0).toUpperCase() + message.slice(1);
|
||||
if (navigator.onLine && sound) {
|
||||
notificationSound.currentTime = 0;
|
||||
notificationSound.play();
|
||||
}
|
||||
banner.querySelector('#hide_banner_btn').onclick = function () {
|
||||
banner.classList.add('hide')
|
||||
banner.classList.remove('no-transformations')
|
||||
}
|
||||
clearTimeout(currentTimeout)
|
||||
if (behavior === 'fixed') return;
|
||||
currentTimeout = setTimeout(() => {
|
||||
banner.classList.add('hide')
|
||||
banner.classList.remove('no-transformations')
|
||||
}, 4000)
|
||||
}
|
||||
// **** requires HTML****
|
||||
// displays a popup for asking permission. Use this instead of JS confirm
|
||||
let askConfirmation = function (message) {
|
||||
return new Promise(resolve => {
|
||||
let popup = document.getElementById('confirmation');
|
||||
showPopup('confirmation')
|
||||
popup.querySelector('#confirm_message').textContent = message;
|
||||
popup.querySelector('.submit-btn').onclick = () => {
|
||||
hidePopup()
|
||||
resolve(true);
|
||||
}
|
||||
})
|
||||
}
|
||||
// **** requires HTML****
|
||||
// displays a popup for asking user input. Use this instead of JS prompt
|
||||
let askPrompt = function (message, defaultVal) {
|
||||
return new Promise(resolve => {
|
||||
let popup = document.getElementById('prompt'),
|
||||
input = popup.querySelector('input');
|
||||
input.value = defaultVal;
|
||||
showPopup('prompt')
|
||||
popup.querySelector('#prompt_message').textContent = message;
|
||||
popup.querySelector('.submit-btn').onclick = () => {
|
||||
hidePopup()
|
||||
resolve(input.value);
|
||||
}
|
||||
popup.querySelector('.cancel-btn').onclick = () => {
|
||||
hidePopup()
|
||||
resolve(null);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// prevents non numerical input on firefox
|
||||
function preventNonNumericalInput(e) {
|
||||
e = e || window.event;
|
||||
let charCode = (typeof e.which == "undefined") ? e.keyCode : e.which,
|
||||
charStr = String.fromCharCode(charCode);
|
||||
|
||||
if (!charStr.match(/[+-]?([0-9]*[.])?[0-9]+/))
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function areInputsEmpty(parent) {
|
||||
let allInputs = parent.querySelectorAll(".input input");
|
||||
return [...allInputs].every(input => input.checkValidity())
|
||||
}
|
||||
|
||||
function formValidation(formElement, e) {
|
||||
if (formElement.getAttribute('type') === 'number')
|
||||
preventNonNumericalInput(e);
|
||||
let parent = formElement.closest('.popup'),
|
||||
submitBtn = parent.querySelector("button[type='submit']");
|
||||
if (areInputsEmpty(parent))
|
||||
submitBtn.disabled = false;
|
||||
else
|
||||
submitBtn.disabled = true;
|
||||
}
|
||||
// **** requires HTML****
|
||||
let allForms = document.querySelectorAll('form');
|
||||
allForms.forEach((form) => {
|
||||
form.addEventListener('input', (e) => {
|
||||
if (e.target.closest('.input')) {
|
||||
let parent = e.target.closest('.input');
|
||||
if (parent.firstElementChild.value !== '')
|
||||
parent.classList.add('animate-label')
|
||||
else
|
||||
parent.classList.remove('animate-label')
|
||||
formValidation(parent.firstElementChild, e)
|
||||
if (e.key === 'Enter') {
|
||||
parent.closest('form').querySelector("button[type='submit']").click();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
allForms.forEach((form) => {
|
||||
form.addEventListener('blur', (e) => {
|
||||
if (e.target.closest('.input')) {
|
||||
let parent = e.target.closest('.input');
|
||||
if (parent.firstElementChild.value === '')
|
||||
parent.classList.remove('animate-label')
|
||||
}
|
||||
}, true)
|
||||
})
|
||||
|
||||
// **** requires HTML****
|
||||
let tabMounted = false;
|
||||
function showTab(tab) {
|
||||
let targetTab = tab.getAttribute('data-target'),
|
||||
activeTabRank = parseInt(tab.parentNode.querySelector('.active').dataset.rank),
|
||||
currentTabRank = parseInt(tab.dataset.rank),
|
||||
currentBody = document.getElementById(tab.parentNode.querySelector('.active').dataset.target),
|
||||
targetBody = document.getElementById(targetTab),
|
||||
targetGroup = targetBody.dataset.tabGroup,
|
||||
tabGroupMembers = document.querySelectorAll(`[data-tab-group = '${targetGroup}']`),
|
||||
allTabs = tab.parentNode.querySelectorAll('.tab'),
|
||||
line = tab.parentNode.querySelector('.line')
|
||||
if (tabMounted && currentBody.isEqualNode(targetBody))
|
||||
return
|
||||
if (activeTabRank < currentTabRank) {
|
||||
targetBody.classList.add('fly-in-from-right')
|
||||
currentBody.classList.add('fly-out-to-left')
|
||||
} else {
|
||||
targetBody.classList.add('fly-in-from-left')
|
||||
currentBody.classList.add('fly-out-to-right')
|
||||
}
|
||||
setTimeout(() => {
|
||||
tabGroupMembers.forEach(member => {
|
||||
member.classList.add('hide-completely')
|
||||
})
|
||||
targetBody.classList.remove('hide-completely')
|
||||
currentBody.classList.remove('fly-out-to-right', 'fly-out-to-left')
|
||||
}, 200)
|
||||
setTimeout(() => {
|
||||
targetBody.classList.remove('fly-in-from-right', 'fly-in-from-left')
|
||||
}, 400)
|
||||
allTabs.forEach(thisTab => {
|
||||
thisTab.classList.remove('active')
|
||||
})
|
||||
tab.classList.add('active')
|
||||
line.setAttribute('style', `transform: translateX(${tab.offsetLeft}px); width: ${tab.getBoundingClientRect().width}px`)
|
||||
tabMounted = true;
|
||||
}
|
||||
|
||||
let loader = document.getElementById("loader_page");
|
||||
|
||||
function loading(status) {
|
||||
if (status) loader.classList.remove("hide-completely");
|
||||
else loader.classList.add("hide-completely");
|
||||
}
|
||||
// **** requires HTML****
|
||||
function copyToClipboard(parent) {
|
||||
let input = document.createElement('textarea'),
|
||||
toast = document.getElementById('textCopied'),
|
||||
textToCopy = parent.querySelector('.copy');
|
||||
input.setAttribute('readonly', '');
|
||||
input.setAttribute('style', 'position: absolute; left: -9999px');
|
||||
document.body.appendChild(input);
|
||||
input.value = textToCopy.textContent;
|
||||
input.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(input);
|
||||
toast.classList.remove('hide');
|
||||
setTimeout(() => {
|
||||
toast.classList.add('hide');
|
||||
}, 2000)
|
||||
}
|
||||
// **** requires HTML****
|
||||
let loader = document.getElementById("loader_page");
|
||||
|
||||
function loading(status) {
|
||||
if (status) loader.classList.remove("hide-completely");
|
||||
else loader.classList.add("hide-completely");
|
||||
}
|
||||
|
||||
//show or hide element group from a group
|
||||
|
||||
function showElement(elem, classGroup) {
|
||||
let allGroups = document.querySelectorAll(`.${classGroup}`),
|
||||
thisElement = elem;
|
||||
if (typeof elem === 'string')
|
||||
thisElement = document.getElementById(elem);
|
||||
allGroups.forEach(group => {
|
||||
group.classList.add('hide-completely')
|
||||
})
|
||||
thisElement.classList.remove('hide-completely')
|
||||
}
|
||||
// **** requires HTML****
|
||||
let tips = [
|
||||
'Loading Local Bitcoin++',
|
||||
'wash your hands often',
|
||||
`Don't shake hands with others`,
|
||||
'Stay inside'
|
||||
], currentIndex = 0, tipsLength = tips.length,
|
||||
tipContainer = document.getElementById('tip_container');
|
||||
|
||||
function changeTips() {
|
||||
if (tipsLength > currentIndex)
|
||||
currentIndex++
|
||||
if (tipsLength === currentIndex)
|
||||
currentIndex = 0
|
||||
tipContainer.textContent = tips[currentIndex]
|
||||
}
|
||||
window.addEventListener('load', () => {
|
||||
document.querySelectorAll('textarea').forEach((textArea) => {
|
||||
textArea.setAttribute('style', 'height:' + (textArea.scrollHeight) + 'px;overflow-y:hidden;');
|
||||
textArea.addEventListener("input", OnInput, false);
|
||||
})
|
||||
})
|
||||
function OnInput(e) {
|
||||
this.style.height = 'auto';
|
||||
this.style.height = (this.scrollHeight) + 'px';
|
||||
}
|
||||
323
aggregate.svg
Normal file
323
aggregate.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 33 KiB |
886
components.js
Normal file
886
components.js
Normal file
@ -0,0 +1,886 @@
|
||||
//Button
|
||||
|
||||
const smBtn = document.createElement('template')
|
||||
smBtn.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
display: inline-flex;
|
||||
}
|
||||
:host([disabled='true']) .sm-btn{
|
||||
cursor: default;
|
||||
opacity: 0.6;
|
||||
background: rgba(var(--text), 0.2) !important;
|
||||
}
|
||||
:host([disabled='true']) button{
|
||||
color: rgba(var(--text), 1) !important;
|
||||
}
|
||||
:host([type='primary']) .sm-btn{
|
||||
background: var(--primary-color);
|
||||
}
|
||||
:host([type='secondary']) button{
|
||||
color: var(--primary-color);
|
||||
}
|
||||
:host([type='secondary']) .sm-btn{
|
||||
border: solid 1px var(--primary-color);
|
||||
background: rgba(var(--foreground), 1);
|
||||
}
|
||||
.sm-btn {
|
||||
display: flex;
|
||||
padding: 0.6rem 0.8rem;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border-radius: 0.2rem;
|
||||
justify-content: center;
|
||||
transition: transform 0.3s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
}
|
||||
.sm-btn:hover{
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sm-btn:active{
|
||||
transform: scale(0.9)
|
||||
}
|
||||
button{
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06rem;
|
||||
word-spacing: 0.1rem;
|
||||
font-family: var(--font-family);
|
||||
font-weight: 600;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--background);
|
||||
outline: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<div class="sm-btn">
|
||||
<slot name="icon"></slot>
|
||||
<button id="main_button"></button>
|
||||
</div>`;
|
||||
customElements.define('sm-btn',
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' }).append(smBtn.content.cloneNode(true))
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['disabled']
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
return this.getAttribute('disabled')
|
||||
}
|
||||
|
||||
set disabled(val) {
|
||||
this.setAttribute('disabled', val)
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
let disabledEvent = new CustomEvent('disabled', {
|
||||
bubbles: true,
|
||||
composed: true
|
||||
})
|
||||
let clicked = new CustomEvent('clicked', {
|
||||
bubbles: true,
|
||||
composed: true
|
||||
})
|
||||
this.shadowRoot.querySelector('button').textContent = this.getAttribute('value')
|
||||
this.addEventListener('click', (e) => {
|
||||
if (this.getAttribute('disabled') === 'true') {
|
||||
this.dispatchEvent(disabledEvent)
|
||||
}
|
||||
else
|
||||
this.dispatchEvent(clicked)
|
||||
})
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
}
|
||||
})
|
||||
|
||||
//Input
|
||||
const smInput = document.createElement('template')
|
||||
smInput.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input[type="search"]::-webkit-search-decoration,
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-results-button,
|
||||
input[type="search"]::-webkit-search-results-decoration { display: none; }
|
||||
input[type=number] {
|
||||
-moz-appearance:textfield;
|
||||
}
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
input:invalid{
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
::-moz-focus-inner{
|
||||
border: none;
|
||||
}
|
||||
:host{
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
}
|
||||
.hide{
|
||||
opacity: 0 !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
.icon {
|
||||
fill: none;
|
||||
height: 1.6rem;
|
||||
width: 1.6rem;
|
||||
padding: 0.5rem;
|
||||
stroke: rgba(var(--text), 0.7);
|
||||
stroke-width: 10;
|
||||
overflow: visible;
|
||||
stroke-linecap: round;
|
||||
border-radius: 1rem;
|
||||
stroke-linejoin: round;
|
||||
cursor: pointer;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
.icon:hover{
|
||||
background: rgba(var(--text), 0.1);
|
||||
}
|
||||
.input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
gap: 1rem;
|
||||
padding: 0.6rem 1rem;
|
||||
border-radius: 0.2em;
|
||||
transition: opacity 0.3s;
|
||||
background: rgba(var(--text), 0.1);
|
||||
font-family: var(--font-family);
|
||||
width: 100%
|
||||
}
|
||||
|
||||
/*.input:focus-within{
|
||||
box-shadow: 0 0 0 0.1rem var(--primary-color);
|
||||
}*/
|
||||
|
||||
input:focus{
|
||||
caret-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.label {
|
||||
user-select: none;
|
||||
opacity: .7;
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transition: transform 0.3s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
-webkit-transform-origin: left;
|
||||
transform-origin: left;
|
||||
pointer-events: none;
|
||||
will-change: transform;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.container{
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
input{
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
background: transparent;
|
||||
outline: none;
|
||||
color: rgba(var(--text), 1);
|
||||
width: 100%;
|
||||
}
|
||||
.animate-label .container input {
|
||||
-webkit-transform: translateY(0.5rem);
|
||||
transform: translateY(0.5rem);
|
||||
}
|
||||
|
||||
.animate-label .container .label {
|
||||
-webkit-transform: translateY(-60%) scale(0.7);
|
||||
transform: translateY(-60%) scale(0.7);
|
||||
opacity: 1;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
<label class="input">
|
||||
<slot name = "icon"></slot>
|
||||
<div class="container">
|
||||
<input required/>
|
||||
<div class="label"></div>
|
||||
</div>
|
||||
<svg class="icon clear hide" viewBox="0 0 64 64">
|
||||
<title>clear</title>
|
||||
<line x1="63.65" y1="0.35" x2="0.35" y2="63.65"/>
|
||||
<line x1="63.65" y1="63.65" x2="0.35" y2="0.35"/>
|
||||
</svg>
|
||||
</label>
|
||||
`;
|
||||
customElements.define('sm-input',
|
||||
class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' }).append(smInput.content.cloneNode(true))
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['placeholder']
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this.shadowRoot.querySelector('input').value
|
||||
}
|
||||
|
||||
set value(val) {
|
||||
this.shadowRoot.querySelector('input').value = val;
|
||||
}
|
||||
|
||||
get placeholder() {
|
||||
return this.getAttribute('placeholder')
|
||||
}
|
||||
|
||||
set placeholder(val) {
|
||||
this.setAttribute('placeholder', val)
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this.getAttribute('type')
|
||||
}
|
||||
|
||||
get isValid() {
|
||||
return this.shadowRoot.querySelector('input').checkValidity()
|
||||
}
|
||||
|
||||
preventNonNumericalInput(e) {
|
||||
let keyCode = e.keyCode;
|
||||
if (!((keyCode > 47 && keyCode < 56) || (keyCode > 36 && keyCode < 39) || (keyCode > 95 && keyCode < 104) || keyCode === 110 || (keyCode > 7 && keyCode < 19))) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
checkInput(input, label, inputParent, clear) {
|
||||
if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '')
|
||||
return;
|
||||
if (input.value !== '') {
|
||||
if (this.animate)
|
||||
inputParent.classList.add('animate-label')
|
||||
else
|
||||
label.classList.add('hide')
|
||||
clear.classList.remove('hide')
|
||||
}
|
||||
else {
|
||||
if (this.animate)
|
||||
inputParent.classList.remove('animate-label')
|
||||
else
|
||||
label.classList.remove('hide')
|
||||
clear.classList.add('hide')
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
let input = this.shadowRoot.querySelector('input'),
|
||||
inputParent = this.shadowRoot.querySelector('.input'),
|
||||
clearBtn = this.shadowRoot.querySelector('.clear'),
|
||||
label = this.shadowRoot.querySelector('.label')
|
||||
this.animate = this.hasAttribute('animate')
|
||||
this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder')
|
||||
if (this.hasAttribute('value')) {
|
||||
input.value = this.getAttribute('value')
|
||||
this.checkInput(input, inputParent, clearBtn)
|
||||
}
|
||||
if (this.hasAttribute('type')) {
|
||||
if (this.getAttribute('type') === 'number') {
|
||||
input.setAttribute('inputmode', 'numeric')
|
||||
}
|
||||
else
|
||||
input.setAttribute('type', this.getAttribute('type'))
|
||||
}
|
||||
else
|
||||
input.setAttribute('type', 'text')
|
||||
input.addEventListener('keydown', e => {
|
||||
if (this.getAttribute('type') === 'number')
|
||||
this.preventNonNumericalInput(e);
|
||||
})
|
||||
input.addEventListener('input', e => {
|
||||
this.checkInput(input, label, inputParent, clearBtn)
|
||||
})
|
||||
clearBtn.addEventListener('click', e => {
|
||||
input.value = ''
|
||||
this.checkInput(input, label, inputParent, clearBtn)
|
||||
})
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
if (name === 'placeholder')
|
||||
this.shadowRoot.querySelector('.label').textContent = newValue;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// tab-header
|
||||
|
||||
const smTabHeader = document.createElement('template')
|
||||
smTabHeader.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
display: inline-flex;
|
||||
}
|
||||
.tab-header{
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
.indicator{
|
||||
position: absolute;
|
||||
display: flexbox;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: var(--primary-color);
|
||||
}
|
||||
:host([type="line"]) .indicator{
|
||||
height: 0.12rem;
|
||||
}
|
||||
:host([type="tab"]) .indicator{
|
||||
height: 100%;
|
||||
border-radius: 0.2rem
|
||||
}
|
||||
:host([type="line"]) .tab-header{
|
||||
border-bottom: solid 1px rgba(var(--text), .1);
|
||||
}
|
||||
:host([type="tab"]) .tab-header{
|
||||
border-radius: 0.2rem;
|
||||
grid-auto-columns: 1fr;
|
||||
}
|
||||
.transition{
|
||||
transition: transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86), width 0.4s;
|
||||
}
|
||||
</style>
|
||||
<div class="tab-header">
|
||||
<slot>Nothing to see here</slot>
|
||||
<div class="indicator"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
customElements.define('sm-tab-header', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' }).append(smTabHeader.content.cloneNode(true))
|
||||
|
||||
this.indicator = this.shadowRoot.querySelector('.indicator');
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['type']
|
||||
}
|
||||
connectedCallback() {
|
||||
this.prevTab = ''
|
||||
this.type = this.getAttribute('type')
|
||||
this.addEventListener('switchTab', e => {
|
||||
if (e.target === this.prevTab)
|
||||
return
|
||||
if (this.type === 'tab') {
|
||||
if (this.prevTab)
|
||||
this.prevTab.classList.remove('tab-active')
|
||||
setTimeout(() => {
|
||||
e.target.classList.add('tab-active')
|
||||
}, 200);
|
||||
}
|
||||
else {
|
||||
if (this.prevTab)
|
||||
this.prevTab.classList.remove('line-active')
|
||||
setTimeout(() => {
|
||||
e.target.classList.add('line-active')
|
||||
}, 200);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.indicator.classList.add('transition')
|
||||
}, 100);
|
||||
this.indicator.setAttribute('style', `width: ${e.detail.width}px; transform: translateX(${e.detail.left - 1}px)`)
|
||||
e.target.scrollIntoView({behavior: 'smooth', inline: 'center'})
|
||||
this.prevTab = e.target;
|
||||
})
|
||||
}
|
||||
})
|
||||
// tab
|
||||
|
||||
const smTab = document.createElement('template')
|
||||
smTab.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
display: inline-flex;
|
||||
z-index: 2;
|
||||
}
|
||||
.tab{
|
||||
user-select: none;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
white-space: nowrap;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.4rem 0.6rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.06em;
|
||||
word-spacing: 0.1em;
|
||||
text-align: center;
|
||||
transition: color 0.3s;
|
||||
text-transform: uppercase;
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
:host(.tab-active) .tab{
|
||||
color: rgba(var(--foreground), 1);
|
||||
}
|
||||
:host(.line-active) .tab{
|
||||
color: var(--primary-color);
|
||||
|
||||
</style>
|
||||
<div class="tab">
|
||||
<slot></slot>
|
||||
</div>
|
||||
`;
|
||||
|
||||
customElements.define('sm-tab', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.shadow = this.attachShadow({ mode: 'open' }).append(smTab.content.cloneNode(true))
|
||||
}
|
||||
connectedCallback() {
|
||||
let width = 0, left = 0;
|
||||
if ('ResizeObserver' in window) {
|
||||
let resizeObserver = new ResizeObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
width = entry.contentRect.width;
|
||||
left = this.getBoundingClientRect().left - this.parentNode.offsetLeft
|
||||
})
|
||||
})
|
||||
resizeObserver.observe(this)
|
||||
}
|
||||
else {
|
||||
let observer = new IntersectionObserver((entries, observer) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
width = entry.contentRect.width;
|
||||
left = this.getBoundingClientRect().left - this.parentNode.offsetLeft
|
||||
}
|
||||
}, {
|
||||
threshold: 1
|
||||
})
|
||||
observer.observe(this)
|
||||
}
|
||||
let switchTab = new CustomEvent('switchTab', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
panel: this.getAttribute('panel'),
|
||||
}
|
||||
})
|
||||
this.addEventListener('click', () => {
|
||||
switchTab.detail.width = width;
|
||||
switchTab.detail.left = left;
|
||||
this.dispatchEvent(switchTab)
|
||||
})
|
||||
if (this.hasAttribute('active')) {
|
||||
setTimeout(() => {
|
||||
switchTab.detail.width = width;
|
||||
switchTab.detail.left = left;
|
||||
this.dispatchEvent(switchTab)
|
||||
}, 0);
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//chcekbox
|
||||
|
||||
const smCheckbox = document.createElement('template')
|
||||
smCheckbox.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host{
|
||||
display: inline-flex;
|
||||
}
|
||||
.checkbox {
|
||||
diplay:flex;
|
||||
border-radius: 2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox:active svg {
|
||||
-webkit-transform: scale(0.9);
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.checkbox input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkbox .checkmark {
|
||||
stroke-dashoffset: -65;
|
||||
stroke-dasharray: 65;
|
||||
-webkit-transition: stroke-dashoffset 0.3s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition: stroke-dashoffset 0.3s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
}
|
||||
|
||||
.checkbox input:checked ~ svg .checkmark {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
.checkbox input:checked ~ svg {
|
||||
stroke: var(--primary-color)
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: none;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
stroke: rgba(var(--text), 0.7);
|
||||
stroke-width: 6;
|
||||
overflow: visible;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox">
|
||||
<svg class="icon" viewBox="0 0 64 64">
|
||||
<title>checkbox</title>
|
||||
<rect class="box" x="0" y="0" width="64" height="64" rx="4" />
|
||||
<path class="checkmark" d="M50.52,19.56,26,44.08,13.48,31.56" />
|
||||
</svg>
|
||||
</label>`
|
||||
customElements.define('sm-checkbox', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' }).append(smCheckbox.content.cloneNode(true))
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['disabled']
|
||||
}
|
||||
|
||||
get disabled() {
|
||||
return this.getAttribute('disabled')
|
||||
}
|
||||
|
||||
set disabled(val) {
|
||||
this.setAttribute('disabled', val)
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.checkbox = this.shadowRoot.querySelector('.checkbox');
|
||||
if (this.hasAttribute('disabled')) {
|
||||
this.checkbox.classList.add('disabled')
|
||||
}
|
||||
else {
|
||||
this.checkbox.classList.remove('disabled')
|
||||
}
|
||||
}
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
this.checkbox = this.shadowRoot.querySelector('.checkbox');
|
||||
if (oldValue !== newValue) {
|
||||
if (name === 'disabled') {
|
||||
if (newValue === 'true') {
|
||||
this.checkbox.classList.add('disabled')
|
||||
}
|
||||
else {
|
||||
this.checkbox.classList.remove('disabled')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
//sm-audio
|
||||
|
||||
const smAudio = document.createElement('template')
|
||||
smAudio.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:host{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.audio{
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
padding: 0.6rem;
|
||||
border-radius: 0.2rem;
|
||||
background: rgba(var(--text), 0.08);
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon{
|
||||
stroke: rgba(var(--text), 1);
|
||||
stroke-width: 6;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
fill: none;
|
||||
overflow: visible;
|
||||
height: 2.1rem;
|
||||
width: 2.1rem;
|
||||
padding: 0.6rem;
|
||||
cursor: pointer;
|
||||
border-radius: 2rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.icon:hover{
|
||||
background: rgba(var(--text), 0.1);
|
||||
}
|
||||
|
||||
audio {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.track {
|
||||
position: absolute;
|
||||
height: 0.2rem;
|
||||
bottom: 0;
|
||||
background: var(--primary-color);
|
||||
left: 0;
|
||||
-webkit-transition: width 0.2s;
|
||||
transition: width 0.2s;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<div class="audio">
|
||||
<svg class="icon play" viewBox="-6 0 64 64">
|
||||
<title>play</title>
|
||||
<path d="M57.12,26.79,12.88,1.31a6,6,0,0,0-9,5.21v51a6,6,0,0,0,9,5.21L57.12,37.21A6,6,0,0,0,57.12,26.79Z"/>
|
||||
</svg>
|
||||
<svg class="icon pause hide" viewBox="0 0 64 64">
|
||||
<title>pause</title>
|
||||
<line x1="17.5" x2="17.5" y2="64"/>
|
||||
<line x1="46.5" x2="46.5" y2="64"/>
|
||||
</svg>
|
||||
<h5 class="current-time"></h5> / <h5 class="duration"></h5>
|
||||
<audio src=""></audio>
|
||||
<div class="track"></div>
|
||||
</audio>
|
||||
`;
|
||||
|
||||
customElements.define('sm-audio', class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' }).append(smAudio.content.cloneNode(true))
|
||||
|
||||
this.playing = false;
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['src']
|
||||
}
|
||||
play() {
|
||||
this.audio.play()
|
||||
this.playing = false;
|
||||
this.pauseBtn.classList.remove('hide')
|
||||
this.playBtn.classList.add('hide')
|
||||
}
|
||||
pause() {
|
||||
this.audio.pause()
|
||||
this.playing = true;
|
||||
this.pauseBtn.classList.add('hide')
|
||||
this.playBtn.classList.remove('hide')
|
||||
}
|
||||
|
||||
get isPlaying() {
|
||||
return this.playing;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.playBtn = this.shadowRoot.querySelector('.play');
|
||||
this.pauseBtn = this.shadowRoot.querySelector('.pause');
|
||||
this.audio = this.shadowRoot.querySelector('audio')
|
||||
this.playBtn.addEventListener('click', e => {
|
||||
this.play()
|
||||
})
|
||||
this.pauseBtn.addEventListener('click', e => {
|
||||
this.pause()
|
||||
})
|
||||
this.audio.addEventListener('ended', e => {
|
||||
this.pause()
|
||||
})
|
||||
let width;
|
||||
if ('ResizeObserver' in window) {
|
||||
let resizeObserver = new ResizeObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
width = entry.contentRect.width;
|
||||
})
|
||||
})
|
||||
resizeObserver.observe(this)
|
||||
}
|
||||
else {
|
||||
let observer = new IntersectionObserver((entries, observer) => {
|
||||
if (entries[0].isIntersecting)
|
||||
width = this.shadowRoot.querySelector('.audio').offsetWidth;
|
||||
}, {
|
||||
threshold: 1
|
||||
})
|
||||
observer.observe(this)
|
||||
}
|
||||
this.audio.addEventListener('timeupdate', e => {
|
||||
let time = this.audio.currentTime,
|
||||
minutes = Math.floor(time / 60),
|
||||
seconds = Math.floor(time - minutes * 60),
|
||||
y = seconds < 10 ? "0" + seconds : seconds;
|
||||
this.shadowRoot.querySelector('.current-time').textContent = `${minutes}:${y}`
|
||||
this.shadowRoot.querySelector('.track').style.width = (width / this.audio.duration) * this.audio.currentTime + 'px'
|
||||
})
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
if (name === 'src') {
|
||||
if (this.hasAttribute('src') && newValue.trim() !== '') {
|
||||
this.shadowRoot.querySelector('audio').src = newValue;
|
||||
this.shadowRoot.querySelector('audio').onloadedmetadata = () => {
|
||||
let duration = this.audio.duration,
|
||||
minutes = Math.floor(duration / 60),
|
||||
seconds = Math.floor(duration - minutes * 60),
|
||||
y = seconds < 10 ? "0" + seconds : seconds;
|
||||
this.shadowRoot.querySelector('.duration').textContent = `${minutes}:${y}`;
|
||||
}
|
||||
}
|
||||
else
|
||||
this.classList.add('disabled')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//sm-switch
|
||||
|
||||
const smSwitch = document.createElement('template')
|
||||
smSwitch.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
:host{
|
||||
display: inline-flex;
|
||||
}
|
||||
.switch {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: -webkit-inline-box;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
-webkit-box-align: center;
|
||||
align-items: center;
|
||||
border-radius: 1rem;
|
||||
width: 2.4rem;
|
||||
padding: 0.2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.switch .track {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
-webkit-transition: background 0.4s;
|
||||
transition: background 0.4s;
|
||||
background: rgba(var(--text), 0.6);
|
||||
}
|
||||
|
||||
.switch .btn {
|
||||
position: relative;
|
||||
display: -webkit-inline-box;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
border-radius: 1rem;
|
||||
-webkit-transition: -webkit-transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition: -webkit-transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition: transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
transition: transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86), -webkit-transform 0.4s cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
border: solid 0.3rem rgba(var(--foreground), 1);
|
||||
}
|
||||
|
||||
.switch input:checked ~ .btn {
|
||||
-webkit-transform: translateX(100%);
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.switch input:checked ~ .track {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
</style>
|
||||
<label class="switch">
|
||||
<input type="checkbox">
|
||||
<div class="track"></div>
|
||||
<div class="btn"></div>
|
||||
</label>`
|
||||
|
||||
customElements.define('sm-switch', class extends HTMLElement{
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({mode: 'open'}).append(smSwitch.content.cloneNode(true))
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
||||
}
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user