Merge pull request #2 from void-57/main
Some checks failed
Workflow push to Dappbundle / Build (push) Has been cancelled
Some checks failed
Workflow push to Dappbundle / Build (push) Has been cancelled
Add transaction details and transaction history features
This commit is contained in:
commit
89838522a5
467
css/main.css
467
css/main.css
@ -28,7 +28,7 @@ body {
|
|||||||
background-color: rgba(var(--foreground-color), 1);
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
body[data-theme=dark] {
|
body[data-theme="dark"] {
|
||||||
--accent-color: #92a2ff;
|
--accent-color: #92a2ff;
|
||||||
--accent-color-rgb: 160, 182, 255;
|
--accent-color-rgb: 160, 182, 255;
|
||||||
--secondary-color: #d60739;
|
--secondary-color: #d60739;
|
||||||
@ -39,7 +39,7 @@ body[data-theme=dark] {
|
|||||||
--green: #00e676;
|
--green: #00e676;
|
||||||
--yellow: rgb(255, 213, 5);
|
--yellow: rgb(255, 213, 5);
|
||||||
}
|
}
|
||||||
body[data-theme=dark] ::-webkit-calendar-picker-indicator {
|
body[data-theme="dark"] ::-webkit-calendar-picker-indicator {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ strong {
|
|||||||
|
|
||||||
img {
|
img {
|
||||||
-o-object-fit: cover;
|
-o-object-fit: cover;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:where([class]) {
|
a:where([class]) {
|
||||||
@ -90,7 +90,7 @@ a:any-link:focus-visible {
|
|||||||
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
outline: rgba(var(--text-color), 1) 0.1rem solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=datetime-local] {
|
input[type="datetime-local"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.8rem 0.6rem;
|
padding: 0.8rem 0.6rem;
|
||||||
border: none;
|
border: none;
|
||||||
@ -101,7 +101,7 @@ input[type=datetime-local] {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
background-color: rgba(var(--text-color), 0.06);
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
}
|
}
|
||||||
input[type=datetime-local]:focus {
|
input[type="datetime-local"]:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: 0 0 0 0.1rem var(--accent-color);
|
box-shadow: 0 0 0 0.1rem var(--accent-color);
|
||||||
}
|
}
|
||||||
@ -109,8 +109,8 @@ input[type=datetime-local]:focus {
|
|||||||
button,
|
button,
|
||||||
.button {
|
.button {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
border: none;
|
border: none;
|
||||||
@ -224,8 +224,8 @@ a:any-link:focus-visible {
|
|||||||
details summary {
|
details summary {
|
||||||
display: flex;
|
display: flex;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
@ -264,8 +264,8 @@ sm-chip {
|
|||||||
--padding: 0.5rem 0.8rem;
|
--padding: 0.5rem 0.8rem;
|
||||||
--background: rgba(var(--text-color), 0.06);
|
--background: rgba(var(--text-color), 0.06);
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
sm-chip[selected] {
|
sm-chip[selected] {
|
||||||
@ -604,7 +604,11 @@ ul {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
background: radial-gradient(circle, rgba(var(--text-color), 0.3) 0%, rgba(0, 0, 0, 0) 50%);
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
rgba(var(--text-color), 0.3) 0%,
|
||||||
|
rgba(0, 0, 0, 0) 50%
|
||||||
|
);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,17 +703,17 @@ ul {
|
|||||||
justify-self: flex-start;
|
justify-self: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul[type=circle],
|
ul[type="circle"],
|
||||||
menu[type=circle] {
|
menu[type="circle"] {
|
||||||
padding: 1.5rem 2.5rem;
|
padding: 1.5rem 2.5rem;
|
||||||
list-style: circle;
|
list-style: circle;
|
||||||
}
|
}
|
||||||
ul[type=circle] li,
|
ul[type="circle"] li,
|
||||||
menu[type=circle] li {
|
menu[type="circle"] li {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
ul[type=circle] li:last-of-type,
|
ul[type="circle"] li:last-of-type,
|
||||||
menu[type=circle] li:last-of-type {
|
menu[type="circle"] li:last-of-type {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
ul,
|
ul,
|
||||||
@ -773,13 +777,13 @@ menu {
|
|||||||
#meta_mask_status_button .icon-wrapper > * {
|
#meta_mask_status_button .icon-wrapper > * {
|
||||||
grid-area: 1/1;
|
grid-area: 1/1;
|
||||||
}
|
}
|
||||||
#meta_mask_status_button[data-status=connected] {
|
#meta_mask_status_button[data-status="connected"] {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
#meta_mask_status_button[data-status=connected] .icon-wrapper::after {
|
#meta_mask_status_button[data-status="connected"] .icon-wrapper::after {
|
||||||
background-color: var(--green);
|
background-color: var(--green);
|
||||||
}
|
}
|
||||||
#meta_mask_status_button[data-status=disconnected] .icon-wrapper::after {
|
#meta_mask_status_button[data-status="disconnected"] .icon-wrapper::after {
|
||||||
background-color: var(--danger-color);
|
background-color: var(--danger-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,7 +851,8 @@ main {
|
|||||||
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
.nav-item__title {
|
.nav-item__title {
|
||||||
transition: opacity 0.2s, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
transition: opacity 0.2s,
|
||||||
|
transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
}
|
}
|
||||||
.nav-item--active {
|
.nav-item--active {
|
||||||
color: var(--accent-color);
|
color: var(--accent-color);
|
||||||
@ -870,17 +875,17 @@ main {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
grid-area: pages;
|
grid-area: pages;
|
||||||
}
|
}
|
||||||
#page_container[data-page=home] > :nth-child(2) {
|
#page_container[data-page="home"] > :nth-child(2) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
#page_container[data-page=send] {
|
#page_container[data-page="send"] {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
#page_container[data-page=send] > * {
|
#page_container[data-page="send"] > * {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
#page_container[data-page=create] {
|
#page_container[data-page="create"] {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 4vw 1rem;
|
padding: 4vw 1rem;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
@ -951,6 +956,19 @@ aside h4 {
|
|||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#address_transactions {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transaction {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#transactions_list {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#error_section {
|
#error_section {
|
||||||
display: grid;
|
display: grid;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -978,6 +996,7 @@ aside h4 {
|
|||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction__phase:not(:last-of-type)::after {
|
.transaction__phase:not(:last-of-type)::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -1004,7 +1023,7 @@ aside h4 {
|
|||||||
width: 4rem;
|
width: 4rem;
|
||||||
border-radius: 5rem;
|
border-radius: 5rem;
|
||||||
-webkit-animation: popup 1s;
|
-webkit-animation: popup 1s;
|
||||||
animation: popup 1s;
|
animation: popup 1s;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
.user-action-result__icon.pending {
|
.user-action-result__icon.pending {
|
||||||
@ -1068,17 +1087,24 @@ aside h4 {
|
|||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||||
}
|
}
|
||||||
|
.create-buttons {
|
||||||
|
display: flex;
|
||||||
|
max-width: 400px;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
@media only screen and (max-width: 640px) {
|
@media only screen and (max-width: 640px) {
|
||||||
.hide-on-small {
|
.hide-on-small {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#page_container[data-page=home] {
|
#page_container[data-page="home"] {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
#page_container[data-page=home] > :first-child {
|
#page_container[data-page="home"] > :first-child {
|
||||||
order: 1;
|
order: 1;
|
||||||
}
|
}
|
||||||
|
.create-buttons {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media only screen and (min-width: 640px) {
|
@media only screen and (min-width: 640px) {
|
||||||
sm-popup {
|
sm-popup {
|
||||||
@ -1166,9 +1192,384 @@ aside h4 {
|
|||||||
}
|
}
|
||||||
@media (prefers-reduced-motion) {
|
@media (prefers-reduced-motion) {
|
||||||
::view-transition-group(*),
|
::view-transition-group(*),
|
||||||
::view-transition-old(*),
|
::view-transition-old(*),
|
||||||
::view-transition-new(*) {
|
::view-transition-new(*) {
|
||||||
-webkit-animation: none !important;
|
-webkit-animation: none !important;
|
||||||
animation: none !important;
|
animation: none !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-details-container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 1rem auto;
|
||||||
|
padding: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header styling */
|
||||||
|
.tx-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(var(--text-color), 0.95);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-card {
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
border: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-status-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
border-bottom: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.confirmed {
|
||||||
|
background-color: var(--color-success);
|
||||||
|
box-shadow: 0 0 0 4px rgba(var(--color-success-rgb), 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.pending {
|
||||||
|
background-color: var(--color-warning);
|
||||||
|
box-shadow: 0 0 0 4px rgba(var(--color-warning-rgb), 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-details {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-title {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(var(--text-color), 0.95);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-subtext {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(var(--text-color), 0.7);
|
||||||
|
margin: 0.25rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-info-grid {
|
||||||
|
padding: 1.25rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-address-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 1rem;
|
||||||
|
background: rgba(var(--text-color), 0.02);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-card {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(var(--text-color), 0.6);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.address-value {
|
||||||
|
font-family: "Roboto Mono", monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(var(--text-color), 0.9);
|
||||||
|
word-break: break-all;
|
||||||
|
background: rgba(var(--text-color), 0.05);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-arrow {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: rgba(var(--text-color), 0.4);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-hash-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(var(--text-color), 0.6);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hash-value {
|
||||||
|
background-color: rgba(var(--text-color), 0.05);
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-family: "Roboto Mono", monospace;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(var(--text-color), 0.9);
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-metrics-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid rgba(var(--text-color), 0.08);
|
||||||
|
transition: background-color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card:hover {
|
||||||
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-label {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(var(--text-color), 0.6);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-value {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(var(--text-color), 0.95);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1.25rem;
|
||||||
|
border-top: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-actions .button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.tx-address-section {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-metrics-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.tx-header {
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-status-header {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-info-grid {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-address-section {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-metrics-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Valuation toggle styles */
|
||||||
|
.valuation-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 3rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(var(--text-color), 0.2);
|
||||||
|
transition: 0.4s;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 1.1rem;
|
||||||
|
width: 1.1rem;
|
||||||
|
left: 0.2rem;
|
||||||
|
bottom: 0.2rem;
|
||||||
|
background-color: white;
|
||||||
|
transition: 0.4s;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .toggle-slider {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .toggle-slider:before {
|
||||||
|
transform: translateX(1.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.transaction-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: rgba(var(--text-color), 0.03);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid rgba(var(--text-color), 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-control {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-control label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: rgba(var(--text-color), 0.8);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-control select {
|
||||||
|
padding: 0.4rem 0.6rem;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
border: 1px solid rgba(var(--text-color), 0.1);
|
||||||
|
background-color: rgba(var(--foreground-color), 1);
|
||||||
|
color: rgba(var(--text-color), 0.9);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.margin-left-auto + .margin-left-auto {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-control select:focus {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading state for transaction details */
|
||||||
|
.loading-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 300px;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
color: rgba(var(--text-color), 0.7);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sol_balance_wrapper {
|
||||||
|
background-color: rgba(var(--text-color), 0.06);
|
||||||
|
padding: max(1rem, 1.5vw);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#sol_balance_wrapper li:not(:last-of-type) {
|
||||||
|
border-bottom: solid thin rgba(var(--text-color), 0.3);
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
4496
index.html
4496
index.html
File diff suppressed because it is too large
Load Diff
492
scripts/components.min.js
vendored
492
scripts/components.min.js
vendored
@ -28,8 +28,11 @@ const smChips = document.createElement("template");
|
|||||||
get value() {
|
get value() {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
set value(t) {
|
set value(val) {
|
||||||
this.setSelectedOption(t);
|
this.setSelectedOption(val);
|
||||||
|
}
|
||||||
|
get isValid() {
|
||||||
|
return void 0 !== this._value;
|
||||||
}
|
}
|
||||||
scrollLeft() {
|
scrollLeft() {
|
||||||
this.chipsWrapper.scrollBy({
|
this.chipsWrapper.scrollBy({
|
||||||
@ -43,18 +46,18 @@ const smChips = document.createElement("template");
|
|||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setSelectedOption(t) {
|
setSelectedOption(value) {
|
||||||
this._value !== t &&
|
this._value !== value &&
|
||||||
((this._value = t),
|
((this._value = value),
|
||||||
this.assignedElements.forEach((e) => {
|
this.assignedElements.forEach((elem) => {
|
||||||
e.value == t
|
elem.value == value
|
||||||
? (e.setAttribute("selected", ""),
|
? (elem.setAttribute("selected", ""),
|
||||||
e.scrollIntoView({
|
elem.scrollIntoView({
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
block: "nearest",
|
block: "nearest",
|
||||||
inline: "center",
|
inline: "center",
|
||||||
}))
|
}))
|
||||||
: e.removeAttribute("selected");
|
: elem.removeAttribute("selected");
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
fireEvent() {
|
fireEvent() {
|
||||||
@ -68,54 +71,51 @@ const smChips = document.createElement("template");
|
|||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.setAttribute("role", "listbox");
|
this.setAttribute("role", "listbox");
|
||||||
const t = this.shadowRoot.querySelector("slot");
|
const slot = this.shadowRoot.querySelector("slot");
|
||||||
t.addEventListener("slotchange", (e) => {
|
slot.addEventListener("slotchange", (e) => {
|
||||||
n.disconnect(),
|
firstOptionObserver.disconnect(),
|
||||||
i.disconnect(),
|
lastOptionObserver.disconnect(),
|
||||||
this.observeSelf.disconnect(),
|
this.observeSelf.disconnect(),
|
||||||
clearTimeout(this.slotChangeTimeout),
|
clearTimeout(this.slotChangeTimeout),
|
||||||
(this.slotChangeTimeout = setTimeout(() => {
|
(this.slotChangeTimeout = setTimeout(() => {
|
||||||
(this.assignedElements = t.assignedElements()),
|
(this.assignedElements = slot.assignedElements()),
|
||||||
this.assignedElements.forEach((t) => {
|
|
||||||
t.hasAttribute("selected") && (this._value = t.value);
|
|
||||||
}),
|
|
||||||
this.observeSelf.observe(this);
|
this.observeSelf.observe(this);
|
||||||
}, 0));
|
}, 0));
|
||||||
});
|
}),
|
||||||
const e = new ResizeObserver((t) => {
|
new ResizeObserver((entries) => {
|
||||||
t.forEach((t) => {
|
entries.forEach((entry) => {
|
||||||
if (t.contentBoxSize) {
|
if (entry.contentBoxSize) {
|
||||||
const e = Array.isArray(t.contentBoxSize)
|
const contentBoxSize = Array.isArray(entry.contentBoxSize)
|
||||||
? t.contentBoxSize[0]
|
? entry.contentBoxSize[0]
|
||||||
: t.contentBoxSize;
|
: entry.contentBoxSize;
|
||||||
this.scrollDistance = 0.6 * e.inlineSize;
|
this.scrollDistance = 0.6 * contentBoxSize.inlineSize;
|
||||||
} else this.scrollDistance = 0.6 * t.contentRect.width;
|
} else this.scrollDistance = 0.6 * entry.contentRect.width;
|
||||||
});
|
});
|
||||||
});
|
}).observe(this),
|
||||||
e.observe(this),
|
|
||||||
(this.observeSelf = new IntersectionObserver(
|
(this.observeSelf = new IntersectionObserver(
|
||||||
(t, e) => {
|
(entries, observer) => {
|
||||||
t.forEach((t) => {
|
entries.forEach((entry) => {
|
||||||
t.isIntersecting &&
|
entry.isIntersecting &&
|
||||||
!this.hasAttribute("multiline") &&
|
!this.hasAttribute("multiline") &&
|
||||||
this.assignedElements.length > 0 &&
|
this.assignedElements.length > 0 &&
|
||||||
(n.observe(this.assignedElements[0]),
|
(firstOptionObserver.observe(this.assignedElements[0]),
|
||||||
i.observe(
|
lastOptionObserver.observe(
|
||||||
this.assignedElements[this.assignedElements.length - 1]
|
this.assignedElements[this.assignedElements.length - 1]
|
||||||
),
|
),
|
||||||
e.unobserve(this));
|
observer.unobserve(this));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{ threshold: 1 }
|
{ threshold: 1 }
|
||||||
)),
|
)),
|
||||||
this.chipsWrapper.addEventListener("option-clicked", (t) => {
|
this.chipsWrapper.addEventListener("option-clicked", (e) => {
|
||||||
this._value !== t.target.value &&
|
e.stopPropagation(),
|
||||||
(this.setSelectedOption(t.target.value), this.fireEvent());
|
this._value !== e.detail.value &&
|
||||||
|
(this.setSelectedOption(e.detail.value), this.fireEvent());
|
||||||
});
|
});
|
||||||
const n = new IntersectionObserver(
|
const firstOptionObserver = new IntersectionObserver(
|
||||||
(t) => {
|
(entries) => {
|
||||||
t.forEach((t) => {
|
entries.forEach((entry) => {
|
||||||
t.isIntersecting
|
entry.isIntersecting
|
||||||
? (this.navButtonLeft.classList.add("hide"),
|
? (this.navButtonLeft.classList.add("hide"),
|
||||||
this.coverLeft.classList.add("hide"))
|
this.coverLeft.classList.add("hide"))
|
||||||
: (this.navButtonLeft.classList.remove("hide"),
|
: (this.navButtonLeft.classList.remove("hide"),
|
||||||
@ -124,10 +124,10 @@ const smChips = document.createElement("template");
|
|||||||
},
|
},
|
||||||
{ threshold: 1, root: this }
|
{ threshold: 1, root: this }
|
||||||
),
|
),
|
||||||
i = new IntersectionObserver(
|
lastOptionObserver = new IntersectionObserver(
|
||||||
(t) => {
|
(entries) => {
|
||||||
t.forEach((t) => {
|
entries.forEach((entry) => {
|
||||||
t.isIntersecting
|
entry.isIntersecting
|
||||||
? (this.navButtonRight.classList.add("hide"),
|
? (this.navButtonRight.classList.add("hide"),
|
||||||
this.coverRight.classList.add("hide"))
|
this.coverRight.classList.add("hide"))
|
||||||
: (this.navButtonRight.classList.remove("hide"),
|
: (this.navButtonRight.classList.remove("hide"),
|
||||||
@ -156,11 +156,14 @@ const smChip = document.createElement("template");
|
|||||||
this.attachShadow({ mode: "open" }).append(
|
this.attachShadow({ mode: "open" }).append(
|
||||||
smChip.content.cloneNode(!0)
|
smChip.content.cloneNode(!0)
|
||||||
),
|
),
|
||||||
(this._value = void 0),
|
(this._value = this.getAttribute("value")),
|
||||||
(this.radioButton = this.shadowRoot.querySelector("input")),
|
(this.radioButton = this.shadowRoot.querySelector("input")),
|
||||||
(this.fireEvent = this.fireEvent.bind(this)),
|
(this.fireEvent = this.fireEvent.bind(this)),
|
||||||
(this.handleKeyDown = this.handleKeyDown.bind(this));
|
(this.handleKeyDown = this.handleKeyDown.bind(this));
|
||||||
}
|
}
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ["selected"];
|
||||||
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
@ -173,16 +176,25 @@ const smChip = document.createElement("template");
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
handleKeyDown(t) {
|
handleKeyDown(e) {
|
||||||
("Enter" !== t.key && "Space" !== t.key) || this.fireEvent();
|
("Enter" !== e.key && "Space" !== e.key) || this.fireEvent();
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.setAttribute("role", "option"),
|
this.setAttribute("role", "option"),
|
||||||
this.setAttribute("tabindex", "0"),
|
this.setAttribute("tabindex", "0"),
|
||||||
(this._value = this.getAttribute("value")),
|
this.hasAttribute("value") ||
|
||||||
|
console.error("sm-chip must have a value attribute"),
|
||||||
|
this.hasAttribute("selected") && this.fireEvent(),
|
||||||
this.addEventListener("click", this.fireEvent),
|
this.addEventListener("click", this.fireEvent),
|
||||||
this.addEventListener("keydown", this.handleKeyDown);
|
this.addEventListener("keydown", this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
|
"selected" === name
|
||||||
|
? this.hasAttribute("selected")
|
||||||
|
? (this.fireEvent(), this.setAttribute("aria-selected", "true"))
|
||||||
|
: this.removeAttribute("aria-selected")
|
||||||
|
: "value" === name && (this._value = newValue);
|
||||||
|
}
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.removeEventListener("click", this.fireEvent),
|
this.removeEventListener("click", this.fireEvent),
|
||||||
this.removeEventListener("keydown", this.handleKeyDown);
|
this.removeEventListener("keydown", this.handleKeyDown);
|
||||||
@ -354,11 +366,6 @@ const smForm = document.createElement("template");
|
|||||||
this.resetButton.addEventListener("click", this.reset),
|
this.resetButton.addEventListener("click", this.reset),
|
||||||
this._checkValidity();
|
this._checkValidity();
|
||||||
};
|
};
|
||||||
checkIfSupported = (elem) =>
|
|
||||||
1 === elem.nodeType &&
|
|
||||||
(elem.tagName.includes("-") ||
|
|
||||||
"input" === elem.tagName ||
|
|
||||||
elem.querySelector(this.supportedElements));
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const updateFormDecedents = this.debounce(this.elementsChanged, 100);
|
const updateFormDecedents = this.debounce(this.elementsChanged, 100);
|
||||||
this.addEventListener("input", this.debounce(this._checkValidity, 100)),
|
this.addEventListener("input", this.debounce(this._checkValidity, 100)),
|
||||||
@ -372,11 +379,15 @@ const smForm = document.createElement("template");
|
|||||||
(this.mutationObserver = new MutationObserver((mutations) => {
|
(this.mutationObserver = new MutationObserver((mutations) => {
|
||||||
mutations.forEach((mutation) => {
|
mutations.forEach((mutation) => {
|
||||||
(("childList" === mutation.type &&
|
(("childList" === mutation.type &&
|
||||||
[...mutation.addedNodes].some((node) =>
|
[...mutation.addedNodes].some(
|
||||||
this.checkIfSupported(node)
|
(node) =>
|
||||||
|
1 === node.nodeType &&
|
||||||
|
node.querySelector(this.supportedElements)
|
||||||
)) ||
|
)) ||
|
||||||
[...mutation.removedNodes].some((node) =>
|
[...mutation.removedNodes].some(
|
||||||
this.checkIfSupported(node)
|
(node) =>
|
||||||
|
1 === node.nodeType &&
|
||||||
|
node.querySelector(this.supportedElements)
|
||||||
)) &&
|
)) &&
|
||||||
updateFormDecedents();
|
updateFormDecedents();
|
||||||
});
|
});
|
||||||
@ -384,8 +395,7 @@ const smForm = document.createElement("template");
|
|||||||
this.mutationObserver.observe(this, { childList: !0, subtree: !0 });
|
this.mutationObserver.observe(this, { childList: !0, subtree: !0 });
|
||||||
}
|
}
|
||||||
attributeChangedCallback(name, oldValue, newValue) {
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
"skip-submit" === name &&
|
"skip-submit" === name && (this.skipSubmit = null !== newValue);
|
||||||
(this.skipSubmit = this.hasAttribute("skip-submit"));
|
|
||||||
}
|
}
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.removeEventListener(
|
this.removeEventListener(
|
||||||
@ -535,7 +545,7 @@ const smInput = document.createElement("template");
|
|||||||
let _validity = { isValid: !0, errorText: "" };
|
let _validity = { isValid: !0, errorText: "" };
|
||||||
return (
|
return (
|
||||||
this.validationFunction &&
|
this.validationFunction &&
|
||||||
(_validity = this.validationFunction(this.input.value)),
|
(_validity = this.validationFunction(this.input.value, this)),
|
||||||
_isValid && _validity.isValid
|
_isValid && _validity.isValid
|
||||||
? (this.setAttribute("valid", ""),
|
? (this.setAttribute("valid", ""),
|
||||||
this.removeAttribute("invalid"),
|
this.removeAttribute("invalid"),
|
||||||
@ -1493,6 +1503,362 @@ const popupStack = new Stack(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const smSwitch = document.createElement("template");
|
||||||
|
(smSwitch.innerHTML =
|
||||||
|
'\t<style> *{ box-sizing: border-box; padding: 0; margin: 0; } :host{ display: inline-flex; } :host(:active) .thumb{ box-shadow: 0 0.1rem 0.4rem #00000060, 0 0 0 0.2rem white inset; } label{ display: flex; align-items: center; width: 100%; outline: none; cursor: pointer; -webkit-tap-highlight-color: transparent; } :host([disabled]) { cursor: not-allowed; opacity: 0.6; pointer-events: none; } .switch { position: relative; display: flex; align-items: center; width: 2.4rem; flex-shrink: 0; margin-left: auto; padding: 0.2rem; cursor: pointer; border-radius: 2rem; } input { display: none; } .track { position: absolute; left: 0; right: 0; height: 1.4rem; transition: background 0.3s; background: rgba(var(--text-color,inherit), 0.4); box-shadow: 0 0.1rem 0.3rem #00000040 inset; border-radius: 1rem; } label:focus-visible .thumb::after{ opacity: 1; } .thumb::after{ content: \'\'; display: flex; position: absolute; height: 2.6rem; width: 2.6rem; background: rgba(var(--text-color,inherit), 0.2); border-radius: 2rem; opacity: 0; transition: opacity 0.3s; } .thumb { position: relative; display: inline-flex; height: 1rem; width: 1rem; justify-content: center; align-items: center; border-radius: 1rem; box-shadow: 0 0.1rem 0.4rem #00000060, 0 0 0 0.2rem white inset; transition: 0.3s ease; background-color: inherit; } input:checked ~ .thumb { transform: translateX(100%); } input:checked ~ .track { background: var(--accent-color, teal); }</style><label tabindex="0"> <slot name="left"></slot> <div part="switch" class="switch"> <input type="checkbox"> <div class="track"></div> <div class="thumb"></div> </div> <slot name="right"></slot></label>'),
|
||||||
|
customElements.define(
|
||||||
|
"sm-switch",
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super(),
|
||||||
|
this.attachShadow({ mode: "open" }).append(
|
||||||
|
smSwitch.content.cloneNode(!0)
|
||||||
|
),
|
||||||
|
(this.switch = this.shadowRoot.querySelector(".switch")),
|
||||||
|
(this.input = this.shadowRoot.querySelector("input")),
|
||||||
|
(this.isChecked = !1),
|
||||||
|
(this.isDisabled = !1);
|
||||||
|
}
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ["disabled", "checked"];
|
||||||
|
}
|
||||||
|
get disabled() {
|
||||||
|
return this.isDisabled;
|
||||||
|
}
|
||||||
|
set disabled(val) {
|
||||||
|
val
|
||||||
|
? this.setAttribute("disabled", "")
|
||||||
|
: this.removeAttribute("disabled");
|
||||||
|
}
|
||||||
|
get checked() {
|
||||||
|
return this.isChecked;
|
||||||
|
}
|
||||||
|
set checked(value) {
|
||||||
|
value
|
||||||
|
? this.setAttribute("checked", "")
|
||||||
|
: this.removeAttribute("checked");
|
||||||
|
}
|
||||||
|
get value() {
|
||||||
|
return this.isChecked;
|
||||||
|
}
|
||||||
|
reset() {}
|
||||||
|
dispatch = () => {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("change", {
|
||||||
|
bubbles: !0,
|
||||||
|
composed: !0,
|
||||||
|
detail: { value: this.isChecked },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
connectedCallback() {
|
||||||
|
this.addEventListener("keydown", (e) => {
|
||||||
|
" " !== e.key ||
|
||||||
|
this.isDisabled ||
|
||||||
|
(e.preventDefault(), this.input.click());
|
||||||
|
}),
|
||||||
|
this.input.addEventListener("click", (e) => {
|
||||||
|
this.input.checked ? (this.checked = !0) : (this.checked = !1),
|
||||||
|
this.dispatch();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
attributeChangedCallback(name, oldValue, newValue) {
|
||||||
|
oldValue !== newValue &&
|
||||||
|
("disabled" === name
|
||||||
|
? this.hasAttribute("disabled")
|
||||||
|
? ((this.disabled = !0), (this.inert = !0))
|
||||||
|
: ((this.disabled = !1), (this.inert = !1))
|
||||||
|
: "checked" === name &&
|
||||||
|
(this.hasAttribute("checked")
|
||||||
|
? ((this.isChecked = !0), (this.input.checked = !0))
|
||||||
|
: ((this.isChecked = !1), (this.input.checked = !1))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const smSelect = document.createElement("template");
|
||||||
|
(smSelect.innerHTML =
|
||||||
|
'<style> *{ padding: 0; margin: 0; box-sizing: border-box;} :host{ display: flex;}:host([disabled]) .select{ opacity: 0.6; cursor: not-allowed;}:host([readonly]) .select{ cursor: default; pointer-events: none;}.select{ position: relative; display: flex; flex-direction: column; cursor: pointer; width: 100%; -webkit-tap-highlight-color: transparent;}.icon { height: 1.2rem; width: 1.2rem; margin-left: 0.5rem; fill: rgba(var(--text-color, (17,17,17)), 0.7);} .selected-option-text{ font-size: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500;}.selection{ border-radius: var(--select-border-radius,0.5rem); display: grid; grid-template-columns: 1fr auto; grid-template-areas: \'heading heading\' \'. .\'; padding: var(--padding,0.6rem 0.8rem); background: var(--background, rgba(var(--text-color,(17,17,17)), 0.06)); align-items: center; outline: none; z-index: 2; height: 100%; align-content: center;}.selection:focus{ box-shadow: 0 0 0 0.1rem var(--accent-color, teal) inset; }:host([align-select="left"]) .options{ left: 0;}:host([align-select="right"]) .options{ right: 0;}.options{ top: 100%; padding: var(--options-padding, 0.3rem); margin-top: 0.2rem; overflow: hidden auto; position: absolute; grid-area: options; display: flex; flex-direction: column; width: var(--options-width, 100%); min-width: var(--min-width, auto); max-height: var(--max-height, auto); background: rgba(var(--foreground-color,(255,255,255)), 1); border: solid 1px rgba(var(--text-color,(17,17,17)), 0.2); border-radius: var(--options-border-radius, 0.5rem); z-index: 1; box-shadow: 0 1rem 1.5rem rgba(0 0 0 /0.2);}:host([isUnder]) .options{ top: auto; bottom: 100%; margin-top: 0; margin-bottom: 0.2rem; box-shadow: 0 -1rem 1.5rem rgba(0 0 0 /0.2);}:host([open]) .icon--expand{ display: none;}:host([open]) .icon--collapse{ display: block;}.icon--expand{ display: block;}.icon--collapse{ display: none;}.hidden{ display: none;}@media (any-hover: hover){ ::-webkit-scrollbar{ width: 0.5rem; height: 0.5rem; } ::-webkit-scrollbar-thumb{ background: rgba(var(--text-color,(17,17,17)), 0.3); border-radius: 1rem; &:hover{ background: rgba(var(--text-color,(17,17,17)), 0.5); } }}</style><div class="select"> <div class="selection" part="button"> <div class="selected-option-text"></div> <svg class="icon icon--expand" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z"/></svg> <svg class="icon icon--collapse" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M24 0v24H0V0h24z" fill="none" opacity=".87"/><path d="M7.41 18.59L8.83 20 12 16.83 15.17 20l1.41-1.41L12 14l-4.59 4.59zm9.18-13.18L15.17 4 12 7.17 8.83 4 7.41 5.41 12 10l4.59-4.59z"/></svg> </div> <div part="options" class="options hidden"> <slot></slot> </div></div>'),
|
||||||
|
customElements.define(
|
||||||
|
"sm-select",
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super(),
|
||||||
|
this.attachShadow({ mode: "open" }).append(
|
||||||
|
smSelect.content.cloneNode(!0)
|
||||||
|
),
|
||||||
|
(this.focusIn = this.focusIn.bind(this)),
|
||||||
|
(this.reset = this.reset.bind(this)),
|
||||||
|
(this.open = this.open.bind(this)),
|
||||||
|
(this.collapse = this.collapse.bind(this)),
|
||||||
|
(this.toggle = this.toggle.bind(this)),
|
||||||
|
(this.handleOptionsNavigation =
|
||||||
|
this.handleOptionsNavigation.bind(this)),
|
||||||
|
(this.handleOptionSelection = this.handleOptionSelection.bind(this)),
|
||||||
|
(this.handleKeydown = this.handleKeydown.bind(this)),
|
||||||
|
(this.handleClickOutside = this.handleClickOutside.bind(this)),
|
||||||
|
(this.selectOption = this.selectOption.bind(this)),
|
||||||
|
(this.debounce = this.debounce.bind(this)),
|
||||||
|
(this.elementsChanged = this.elementsChanged.bind(this)),
|
||||||
|
(this.availableOptions = []),
|
||||||
|
this.previousOption,
|
||||||
|
(this.isOpen = !1),
|
||||||
|
(this.label = ""),
|
||||||
|
(this.defaultSelected = ""),
|
||||||
|
(this.isUnderViewport = !1),
|
||||||
|
(this.animationOptions = {
|
||||||
|
duration: 300,
|
||||||
|
fill: "forwards",
|
||||||
|
easing: "ease",
|
||||||
|
}),
|
||||||
|
(this.optionList = this.shadowRoot.querySelector(".options")),
|
||||||
|
(this.selection = this.shadowRoot.querySelector(".selection")),
|
||||||
|
(this.selectedOptionText = this.shadowRoot.querySelector(
|
||||||
|
".selected-option-text"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
static get observedAttributes() {
|
||||||
|
return ["disabled", "label", "readonly"];
|
||||||
|
}
|
||||||
|
get value() {
|
||||||
|
return this.getAttribute("value");
|
||||||
|
}
|
||||||
|
set value(t) {
|
||||||
|
const e = this.availableOptions.find(
|
||||||
|
(e) => e.getAttribute("value") === t
|
||||||
|
);
|
||||||
|
e
|
||||||
|
? (this.setAttribute("value", t), this.selectOption(e))
|
||||||
|
: console.warn(`There is no option with ${t} as value`);
|
||||||
|
}
|
||||||
|
debounce(t, e) {
|
||||||
|
let n = null;
|
||||||
|
return (...i) => {
|
||||||
|
window.clearTimeout(n),
|
||||||
|
(n = window.setTimeout(() => {
|
||||||
|
t.apply(null, i);
|
||||||
|
}, e));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
reset(t = !0) {
|
||||||
|
if (
|
||||||
|
this.availableOptions[0] &&
|
||||||
|
this.previousOption !== this.availableOptions[0]
|
||||||
|
) {
|
||||||
|
const e =
|
||||||
|
this.availableOptions.find((t) => t.hasAttribute("selected")) ||
|
||||||
|
this.availableOptions[0];
|
||||||
|
(this.value = e.getAttribute("value")), t && this.fireEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectOption(t) {
|
||||||
|
this.previousOption !== t &&
|
||||||
|
(this.querySelectorAll("[selected").forEach((t) =>
|
||||||
|
t.removeAttribute("selected")
|
||||||
|
),
|
||||||
|
(this.selectedOptionText.textContent = `${this.label}${t.textContent}`),
|
||||||
|
t.setAttribute("selected", ""),
|
||||||
|
(this.previousOption = t));
|
||||||
|
}
|
||||||
|
focusIn() {
|
||||||
|
this.selection.focus();
|
||||||
|
}
|
||||||
|
open() {
|
||||||
|
this.availableOptions.forEach((t) => t.setAttribute("tabindex", 0)),
|
||||||
|
this.optionList.classList.remove("hidden"),
|
||||||
|
(this.isUnderViewport =
|
||||||
|
this.getBoundingClientRect().bottom +
|
||||||
|
this.optionList.getBoundingClientRect().height >
|
||||||
|
window.innerHeight),
|
||||||
|
this.isUnderViewport
|
||||||
|
? this.setAttribute("isUnder", "")
|
||||||
|
: this.removeAttribute("isUnder"),
|
||||||
|
this.optionList.animate(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
transform: `translateY(${
|
||||||
|
this.isUnderViewport ? "" : "-"
|
||||||
|
}0.5rem)`,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
{ transform: "translateY(0)", opacity: 1 },
|
||||||
|
],
|
||||||
|
this.animationOptions
|
||||||
|
),
|
||||||
|
this.setAttribute("open", ""),
|
||||||
|
(this.style.zIndex = 1e3),
|
||||||
|
(
|
||||||
|
this.availableOptions.find((t) => t.hasAttribute("selected")) ||
|
||||||
|
this.availableOptions[0]
|
||||||
|
).focus(),
|
||||||
|
document.addEventListener("mousedown", this.handleClickOutside),
|
||||||
|
(this.isOpen = !0);
|
||||||
|
}
|
||||||
|
collapse() {
|
||||||
|
this.removeAttribute("open"),
|
||||||
|
(this.optionList.animate(
|
||||||
|
[
|
||||||
|
{ transform: "translateY(0)", opacity: 1 },
|
||||||
|
{
|
||||||
|
transform: `translateY(${
|
||||||
|
this.isUnderViewport ? "" : "-"
|
||||||
|
}0.5rem)`,
|
||||||
|
opacity: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
this.animationOptions
|
||||||
|
).onfinish = () => {
|
||||||
|
this.availableOptions.forEach((t) => t.removeAttribute("tabindex")),
|
||||||
|
document.removeEventListener(
|
||||||
|
"mousedown",
|
||||||
|
this.handleClickOutside
|
||||||
|
),
|
||||||
|
this.optionList.classList.add("hidden"),
|
||||||
|
(this.isOpen = !1),
|
||||||
|
(this.style.zIndex = "auto");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
toggle() {
|
||||||
|
this.isOpen || this.hasAttribute("disabled")
|
||||||
|
? this.collapse()
|
||||||
|
: this.open();
|
||||||
|
}
|
||||||
|
fireEvent() {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("change", {
|
||||||
|
bubbles: !0,
|
||||||
|
composed: !0,
|
||||||
|
detail: { value: this.value },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
handleOptionsNavigation(t) {
|
||||||
|
"ArrowUp" === t.key
|
||||||
|
? (t.preventDefault(),
|
||||||
|
document.activeElement.previousElementSibling
|
||||||
|
? document.activeElement.previousElementSibling.focus()
|
||||||
|
: this.availableOptions[this.availableOptions.length - 1].focus())
|
||||||
|
: "ArrowDown" === t.key &&
|
||||||
|
(t.preventDefault(),
|
||||||
|
document.activeElement.nextElementSibling
|
||||||
|
? document.activeElement.nextElementSibling.focus()
|
||||||
|
: this.availableOptions[0].focus());
|
||||||
|
}
|
||||||
|
handleOptionSelection(t) {
|
||||||
|
this.previousOption !== document.activeElement &&
|
||||||
|
((this.value = document.activeElement.getAttribute("value")),
|
||||||
|
this.fireEvent());
|
||||||
|
}
|
||||||
|
handleClick(t) {
|
||||||
|
t.target === this
|
||||||
|
? this.toggle()
|
||||||
|
: (this.handleOptionSelection(), this.collapse());
|
||||||
|
}
|
||||||
|
handleKeydown(t) {
|
||||||
|
t.target === this
|
||||||
|
? this.isOpen && "ArrowDown" === t.key
|
||||||
|
? (t.preventDefault(),
|
||||||
|
(
|
||||||
|
this.availableOptions.find((t) => t.hasAttribute("selected")) ||
|
||||||
|
this.availableOptions[0]
|
||||||
|
).focus(),
|
||||||
|
this.handleOptionSelection(t))
|
||||||
|
: " " === t.key && (t.preventDefault(), this.toggle())
|
||||||
|
: (this.handleOptionsNavigation(t),
|
||||||
|
this.handleOptionSelection(t),
|
||||||
|
["Enter", " ", "Escape", "Tab"].includes(t.key) &&
|
||||||
|
(t.preventDefault(), this.collapse(), this.focusIn()));
|
||||||
|
}
|
||||||
|
handleClickOutside(t) {
|
||||||
|
this.isOpen && !this.contains(t.target) && this.collapse();
|
||||||
|
}
|
||||||
|
elementsChanged() {
|
||||||
|
(this.availableOptions = [...this.querySelectorAll("sm-option")]),
|
||||||
|
this.reset(!1),
|
||||||
|
(this.defaultSelected = this.value);
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.setAttribute("role", "listbox"),
|
||||||
|
this.hasAttribute("disabled") ||
|
||||||
|
this.hasAttribute("readonly") ||
|
||||||
|
(this.selection.setAttribute("tabindex", "0"),
|
||||||
|
this.addEventListener("click", this.handleClick),
|
||||||
|
this.addEventListener("keydown", this.handleKeydown));
|
||||||
|
const t = this.debounce(this.elementsChanged, 100);
|
||||||
|
this.shadowRoot.querySelector("slot").addEventListener("slotchange", t),
|
||||||
|
(this.mutationObserver = new MutationObserver((e) => {
|
||||||
|
let n = !1;
|
||||||
|
if (
|
||||||
|
(e.forEach((e) => {
|
||||||
|
switch (e.type) {
|
||||||
|
case "childList":
|
||||||
|
t();
|
||||||
|
break;
|
||||||
|
case "attributes":
|
||||||
|
n = !0;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
n)
|
||||||
|
) {
|
||||||
|
const t =
|
||||||
|
this.availableOptions.find((t) => t.hasAttribute("selected")) ||
|
||||||
|
this.availableOptions[0];
|
||||||
|
(this.selectedOptionText.textContent = `${this.label}${t.textContent}`),
|
||||||
|
this.setAttribute("value", t.getAttribute("value"));
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
this.mutationObserver.observe(this, {
|
||||||
|
subtree: !0,
|
||||||
|
childList: !0,
|
||||||
|
attributeFilter: ["selected"],
|
||||||
|
}),
|
||||||
|
new IntersectionObserver((t, e) => {
|
||||||
|
t.forEach((t) => {
|
||||||
|
if (t.isIntersecting) {
|
||||||
|
this.selection.getBoundingClientRect().left <
|
||||||
|
window.innerWidth / 2
|
||||||
|
? this.setAttribute("align-select", "left")
|
||||||
|
: this.setAttribute("align-select", "right");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).observe(this);
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
this.removeEventListener("click", this.handleClick),
|
||||||
|
this.removeEventListener("keydown", this.handleKeydown);
|
||||||
|
}
|
||||||
|
attributeChangedCallback(t) {
|
||||||
|
"disabled" === t || "readonly" === t
|
||||||
|
? this.hasAttribute("disabled") || this.hasAttribute("readonly")
|
||||||
|
? (this.selection.removeAttribute("tabindex"),
|
||||||
|
this.removeEventListener("click", this.handleClick),
|
||||||
|
this.removeEventListener("keydown", this.handleKeydown))
|
||||||
|
: (this.selection.setAttribute("tabindex", "0"),
|
||||||
|
this.addEventListener("click", this.handleClick),
|
||||||
|
this.addEventListener("keydown", this.handleKeydown))
|
||||||
|
: "label" === t &&
|
||||||
|
(this.label = this.hasAttribute("label")
|
||||||
|
? `${this.getAttribute("label")} `
|
||||||
|
: "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const smOption = document.createElement("template");
|
||||||
|
(smOption.innerHTML =
|
||||||
|
'<style> *{ padding: 0; margin: 0; -webkit-box-sizing: border-box; box-sizing: border-box;} :host{ display: -webkit-box; display: -ms-flexbox; display: flex; overflow: hidden; border-radius: var(--border-radius, 0.3rem);}.option{ position: relative; display: flex; -webkit-box-align: center; -ms-flex-align: center; align-items: center; width: 100%; gap: 0.5rem; padding: var(--padding, 0.6rem 1rem); cursor: pointer; outline: none; user-select: none;}.option::before{ position: absolute; content: \'\'; display: block; width: 0.2rem; height: 1em; left: 0; border-radius: 0 1em 1em 0; background: rgba(var(--text-color,(17,17,17)), 0.5); transition: all 0.2s ease-in-out; opacity: 0;}:host(:focus){ outline: none; background: rgba(var(--text-color,(17,17,17)), 0.1);}:host(:focus) .option::before{ opacity: 1}:host([selected]) .option::before{ opacity: 1; background: var(--accent-color, teal);}@media (hover: hover){ .option:hover{ background: rgba(var(--text-color,(17,17,17)), 0.1); } :host(:not([selected]):hover) .option::before{ opacity: 1 }}</style><div class="option" part="option"> <slot></slot> </div>'),
|
||||||
|
customElements.define(
|
||||||
|
"sm-option",
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super(),
|
||||||
|
this.attachShadow({ mode: "open" }).append(
|
||||||
|
smOption.content.cloneNode(!0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.setAttribute("role", "option");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
const spinner = document.createElement("template");
|
const spinner = document.createElement("template");
|
||||||
spinner.innerHTML =
|
spinner.innerHTML =
|
||||||
'<style> *{ padding: 0; margin: 0; -webkit-box-sizing: border-box; box-sizing: border-box;}.loader { display: flex; height: var(--size, 1.5rem); width: var(--size, 1.5rem); stroke-width: 8; overflow: visible; stroke: var(--accent-color, teal); fill: none; stroke-dashoffset: 180; stroke-dasharray: 180; animation: load 2s infinite, spin 1s linear infinite;}@keyframes load { 50% { stroke-dashoffset: 0; } 100%{ stroke-dashoffset: -180; }}@keyframes spin { 100% { transform: rotate(360deg); }}</style><svg viewBox="0 0 64 64" class="loader"><circle cx="32" cy="32" r="32" /></svg>';
|
'<style> *{ padding: 0; margin: 0; -webkit-box-sizing: border-box; box-sizing: border-box;}.loader { display: flex; height: var(--size, 1.5rem); width: var(--size, 1.5rem); stroke-width: 8; overflow: visible; stroke: var(--accent-color, teal); fill: none; stroke-dashoffset: 180; stroke-dasharray: 180; animation: load 2s infinite, spin 1s linear infinite;}@keyframes load { 50% { stroke-dashoffset: 0; } 100%{ stroke-dashoffset: -180; }}@keyframes spin { 100% { transform: rotate(360deg); }}</style><svg viewBox="0 0 64 64" class="loader"><circle cx="32" cy="32" r="32" /></svg>';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user