diff --git a/Layouts/boxes layout/css/main.css b/Layouts/boxes layout/css/main.css index d5b8015..b007d04 100644 --- a/Layouts/boxes layout/css/main.css +++ b/Layouts/boxes layout/css/main.css @@ -1,65 +1,88 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap"); * { - -webkit-box-sizing: border-box; - box-sizing: border-box; padding: 0; margin: 0; - font-family: 'Roboto', sans-serif; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } :root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, body { + height: 100%; scroll-behavior: smooth; } -html { - margin-left: calc(100vw - 100%); -} - body { - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; } -body[data-theme="dark"] { - --accent-color: #4a5cd3; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; -} - -h1, h2, h3, h4, h5 { - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} - -h1 { - font-size: 3rem; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -h4 { - font-size: 1rem; -} - -h5 { - font-size: 0.8rem; +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); } p { - margin: 1.5rem 0; + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); } +p:not(:last-of-type) { + margin-bottom: 1rem; +} + +img { + object-fit: cover; +} + +a { + color: inherit; + text-decoration: none; +} +a:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +button { + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} .hide { opacity: 0; @@ -70,102 +93,263 @@ p { display: none !important; } -.icon { - height: 1.2rem; - width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; +.no-transformations { + transform: none !important; } -#navbar { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: space-evenly; - -ms-flex-pack: space-evenly; - justify-content: space-evenly; - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: auto; - border-top: solid 1px rgba(var(--text-color), 0.2); - border-right: none; - z-index: 3; - background: rgba(var(--foreground-color), 1); +.overflow-ellipsis { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -#navbar .navbar-item { - position: relative; - text-align: center; - cursor: pointer; - padding: 0.3em; - margin: 0.3em; - border-radius: 0.4em; - color: rgba(var(--text-color), 0.8); - font-size: 0.9em; +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { text-transform: uppercase; - width: 100%; - letter-spacing: 0.08em; - -webkit-tap-highlight-color: transparent; } -#navbar .navbar-item h5 { - font-size: 0.6em; - margin-top: 0.4em; - font-weight: 700; -} - -#navbar .active { - color: var(--accent-color); -} - -#navbar .active .icon { - stroke: var(--accent-color); -} - -#main_header { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - padding: 1rem 0; -} - -#logo { - display: -ms-grid; - display: grid; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - width: 100%; - -ms-grid-columns: auto 1fr; - grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; - margin-right: 1rem; -} - -#logo h4 { +.capitalize { text-transform: capitalize; - font-size: 1.2rem; - font-weight: 600; } -#logo h5 { - font-family: 'Roboto', sans-serif; +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { font-weight: 400; } +.weight-500 { + font-weight: 500; +} + +.ripple { + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} + +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.observe-empty-state:empty { + display: none; +} + +.observe-empty-state:not(:empty) ~ .empty-state { + display: none; +} + +.icon { + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; +} +#confirmation_popup h4, +#prompt_popup h4 { + font-weight: 500; + margin-bottom: 0.5rem; +} +#confirmation_popup sm-button, +#prompt_popup sm-button { + margin: 0; +} +#confirmation_popup .flex, +#prompt_popup .flex { + padding: 0; + margin-top: 1rem; +} +#confirmation_popup .flex sm-button:first-of-type, +#prompt_popup .flex sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; +} + +h1, h2, h3, h4.h5 { + font-family: "Poppins", sans-serif; +} + +h2 { + margin: 3rem 0 1rem 0; + text-transform: capitalize; +} + +main { + display: grid; + height: 100%; + grid-template-rows: auto 1fr auto; + grid-template-areas: "main-header" "." "side-nav"; +} + +#main_header { + grid-area: main-header; + padding: 1rem 1.5rem; + border-bottom: 1px solid rgba(var(--text-color), 0.1); +} + +#logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.5rem; + margin-right: 1rem; +} +#logo h4 { + text-transform: capitalize; + font-size: 1rem; + font-weight: 600; +} #logo #main_logo { height: 1.4rem; width: 1.4rem; @@ -173,175 +357,126 @@ p { stroke: none; } -.toggle { - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; +.right { + max-height: 100%; + overflow-y: auto; } -.toggle input[type='checkbox'] { - display: none; +#side_nav { + grid-area: side-nav; +} +#side_nav h4 { + font-size: 0.9rem; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 1.5rem; } -.toggle .switch { - overflow: hidden; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; +.nav-list { + list-style: none; + display: flex; + justify-content: space-evenly; +} +.nav-list li { + width: 100%; } -.toggle .circle { - border-radius: 0.5rem; - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; +.nav-list__item { + display: flex; + padding: 0.8rem 1.5rem; + text-transform: capitalize; +} +.nav-list__item--active { + color: var(--accent-color); +} +.nav-list__item--active .icon { + fill: var(--accent-color); } -.toggle .circle:first-of-type { - margin-bottom: 0.4rem; +.right { + padding: 1.5rem; } - -.toggle .circle line { - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; -} - -.toggle input:checked ~ .switch .circle { - -webkit-transform: translateY(-1.7rem); - transform: translateY(-1.7rem); +.right h1 { + margin-bottom: 1.5rem; } .page { - padding: 2rem 0; - padding-bottom: 4rem; -} - -.options-tab { - display: -webkit-box; - display: -ms-flexbox; display: flex; - margin-top: 1rem; - margin-bottom: 1rem; - -ms-flex-wrap: wrap; - flex-wrap: wrap; + flex-direction: column; + padding-bottom: 3rem; } -.options-tab .option { - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - border-radius: 0.4rem; - padding: 1.5rem; - margin-right: 1rem; - margin-bottom: 1rem; - width: 9rem; - border: solid 1px rgba(var(--text-color), 0.2); - text-transform: capitalize; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} +@media screen and (max-width: 640px) { + main { + grid-template-rows: auto 1fr; + grid-template-columns: 1fr; + } -.options-tab .option .icon { - background: rgba(var(--text-color), 0.1); - height: 2.8rem; - width: 2.8rem; - padding: 0.8rem; - border-radius: 2rem; - margin-bottom: 1rem; - stroke: rgba(var(--text-color), 0.4); + .nav-list__item { + flex-direction: column; + justify-content: center; + align-items: center; + padding: 0.4rem; + } + .nav-list__item span { + font-size: 0.8rem; + margin-top: 0.3rem; + } } +@media screen and (min-width: 640px) { + sm-popup { + --width: 32rem; + } -.options-tab .option h4 { - font-weight: 400; - font-size: 0.9rem; -} + main { + grid-template-columns: 14rem minmax(0, 1fr); + grid-template-rows: auto 1fr; + grid-template-areas: "main-header main-header" "side-nav ."; + } -#home_page h1 { - margin-top: 3vw; - font-weight: 600; -} + .nav-list { + flex-direction: column; + } -#home_page p { - margin-bottom: 3rem; -} + .nav-list__item { + align-items: center; + justify-content: start; + } + .nav-list__item--active { + background: rgba(var(--text-color), 0.06); + } + .nav-list__item .icon { + margin-right: 0.5rem; + } -#home_page h2 { - margin-bottom: 1rem; -} + .right { + display: grid; + grid-template-columns: 1fr 90% 1fr; + } + .right > * { + grid-column: 2/3; + } -@media only screen and (min-width: 640px) { - body { - padding: 1rem 6vw; - margin-left: 6rem; - } - p { - max-width: 40rem; - } - #navbar { - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: stretch; - -ms-flex-align: stretch; - align-items: stretch; - left: 0; - bottom: 0; - top: 0; - right: auto; - width: 6rem; - border-top: none; - border-right: solid 1px rgba(var(--text-color), 0.2); - } - #navbar .navbar-item { - width: auto; - padding: 1.4em 0; - margin: 0.6em; - } - #navbar .navbar-item .icon { - height: 1.4rem; - width: 1.4rem; - } - #navbar .navbar-item h5 { - font-size: 0.8em; - } - #navbar .navbar-item:hover .icon { - stroke: rgba(var(--text-color), 1); - } - #navbar .navbar-item:hover h5 { - color: rgba(var(--text-color), 1); - } - #navbar .navbar-item.active:hover .icon { - stroke: var(--accent-color); - } - #navbar .navbar-item.active:hover h5 { - color: var(--accent-color); + .page__title { + font-size: 2.5rem; } } -/*# sourceMappingURL=main.css.map */ \ No newline at end of file +@media (any-hover: hover) { + ::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; + } + + ::-webkit-scrollbar-thumb { + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(var(--text-color), 0.5); + } + + .nav-list__item:hover { + background: rgba(var(--text-color), 0.1); + cursor: pointer; + } +} \ No newline at end of file diff --git a/Layouts/boxes layout/css/main.min.css b/Layouts/boxes layout/css/main.min.css new file mode 100644 index 0000000..5982293 --- /dev/null +++ b/Layouts/boxes layout/css/main.min.css @@ -0,0 +1 @@ +.hide,.ripple{pointer-events:none}.nav-list,ul{list-style:none}*{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;max-width:65ch;line-height:1.7;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}.hide{opacity:0}.hide-completely{display:none!important}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}#logo h4,.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}#logo h4,.capitalize,h2{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.direction-column{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16)}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}#logo,main{display:grid}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}h1,h2,h3,h4.h5{font-family:Poppins,sans-serif}h2{margin:3rem 0 1rem}main{height:100%;grid-template-rows:auto 1fr auto;grid-template-areas:"main-header" "." "side-nav"}#main_header{grid-area:main-header;padding:1rem 1.5rem;border-bottom:1px solid rgba(var(--text-color),.1)}#logo{align-items:center;width:100%;grid-template-columns:auto 1fr;gap:0 .5rem;margin-right:1rem}#logo h4{font-weight:600}#logo #main_logo{height:1.4rem;width:1.4rem;fill:rgba(var(--text-color),1);stroke:none}#side_nav{grid-area:side-nav}#side_nav h4{font-size:.9rem;letter-spacing:.08em;text-transform:uppercase;padding:1.5rem}.nav-list{display:flex;justify-content:space-evenly}.nav-list li{width:100%}.nav-list__item{display:flex;padding:.8rem 1.5rem;text-transform:capitalize}.nav-list__item--active{color:var(--accent-color)}.nav-list__item--active .icon{fill:var(--accent-color)}.right{max-height:100%;overflow-y:auto;padding:1.5rem}.right h1{margin-bottom:1.5rem}.page{display:flex;flex-direction:column;padding-bottom:3rem}@media screen and (max-width:640px){main{grid-template-rows:auto 1fr;grid-template-columns:1fr}.nav-list__item{flex-direction:column;justify-content:center;align-items:center;padding:.4rem}.nav-list__item span{font-size:.8rem;margin-top:.3rem}}@media screen and (min-width:640px){sm-popup{--width:32rem}main{grid-template-columns:14rem minmax(0,1fr);grid-template-rows:auto 1fr;grid-template-areas:"main-header main-header" "side-nav ."}.nav-list{flex-direction:column}.nav-list__item{align-items:center;justify-content:start}.nav-list__item--active{background:rgba(var(--text-color),.06)}.nav-list__item .icon{margin-right:.5rem}.right{display:grid;grid-template-columns:1fr 90% 1fr}.right>*{grid-column:2/3}.page__title{font-size:2.5rem}}@media (any-hover:hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.nav-list__item:hover{background:rgba(var(--text-color),.1);cursor:pointer}} \ No newline at end of file diff --git a/Layouts/boxes layout/css/main.scss b/Layouts/boxes layout/css/main.scss index cd9d2cd..dacfd5b 100644 --- a/Layouts/boxes layout/css/main.scss +++ b/Layouts/boxes layout/css/main.scss @@ -1,52 +1,79 @@ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap'); *{ - box-sizing: border-box; padding: 0; margin: 0; + box-sizing: border-box; font-family: 'Roboto', sans-serif; } :root{ + font-size: clamp(1rem, 1.2vmax, 3rem); +} +html, body{ + height: 100%; scroll-behavior: smooth; } -html{ - margin-left: calc(100vw - 100%); -} -body{ - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); +body { + &, + *{ + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; + } color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); } -body[data-theme="dark"]{ - --accent-color: #4a5cd3; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; +body[data-theme='dark']{ + &, + *{ + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); + } } -h1, h2, h3, h4, h5{ - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} -h1{ - font-size: 3rem; -} -h2{ - font-size: 2rem; -} -h3{ - font-size: 1.5rem; -} -h4{ - font-size: 1rem; -} -h5{ - font-size: 0.8rem; -} -p{ - margin: 1.5rem 0; +p { + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); + &:not(:last-of-type){ + margin-bottom: 1rem; + } +} +img{ + object-fit: cover; +} + +a{ + color: inherit; + text-decoration: none; + &:focus-visible{ + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} + +button{ + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible{ + outline: rgba(var(--text-color), 1) 0.1rem solid; +} +sm-button{ + --border-radius: 0.3rem; +} +ul{ + list-style: none; +} +.flex{ + display: flex; +} +.grid{ + display: grid; } .hide{ opacity: 0; @@ -55,76 +82,212 @@ p{ .hide-completely{ display: none !important; } +.no-transformations{ + transform: none !important; +} +.overflow-ellipsis{ + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.breakable{ + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +.full-bleed{ + grid-column: 1/4; +} +.h1{ + font-size: 2.5rem; +} +.h2{ + font-size: 2rem; +} +.h3{ + font-size: 1.4rem; +} +.h4{ + font-size: 1rem; +} +.h5{ + font-size: 0.8rem; +} + +.uppercase{ + text-transform: uppercase; +} +.capitalize{ + text-transform: capitalize; +} +.flex{ + display: flex; +} +.grid{ + display: grid; +} +.grid-3{ + grid-template-columns: 1fr auto auto; +} +.flow-column{ + grid-auto-flow: column; +} +.gap-0-5{ + gap: 0.5rem; +} +.gap-1{ + gap: 1rem; +} +.gap-1-5{ + gap: 1.5rem; +} +.gap-2{ + gap: 2rem; +} +.gap-3{ + gap: 3rem; +} +.text-align-right{ + text-align: right; +} +.align-start{ + align-items: flex-start; +} +.align-center{ + align-items: center; +} +.text-center{ + text-align: center; +} +.justify-start{ + justify-content: start; +} +.justify-center{ + justify-content: center; +} +.justify-right{ + margin-left: auto; +} +.align-self-center{ + align-self: center; +} +.justify-self-center{ + justify-self: center; +} +.justify-self-start{ + justify-self: start; +} +.justify-self-end{ + justify-self: end; +} +.direction-column{ + flex-direction: column; +} +.space-between{ + justify-content: space-between; +} +.w-100{ + width: 100%; +} +.color-0-8{ + color: rgba(var(--text-color), 0.8); +} +.weight-400{ + font-weight: 400; +} +.weight-500{ + font-weight: 500; +} +.ripple{ + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} +.interact{ + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.observe-empty-state:empty{ + display: none; +} +.observe-empty-state:not(:empty) ~ .empty-state{ + display: none; +} .icon{ + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} +.button__icon{ height: 1.2rem; width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; + &--left{ + margin-right: 0.5rem; + } + &--right{ + margin-left: 0.5rem; + } } -#navbar{ - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-evenly; - position: fixed; - left: 0; - right: 0; - bottom: 0; - top: auto; - border-top: solid 1px rgba(var(--text-color), 0.2); - border-right: none; - z-index: 3; - background: rgba(var(--foreground-color), 1); - .navbar-item{ - position: relative; - text-align: center; - cursor: pointer; - padding: 0.3em; - margin: 0.3em; - border-radius: 0.4em; - color: rgba(var(--text-color), 0.8); - font-size: 0.9em; - text-transform: uppercase; - width: 100%; - letter-spacing: 0.08em; - -webkit-tap-highlight-color: transparent; - h5{ - font-size: 0.6em; - margin-top: 0.4em; - font-weight: 700; - } - } - .active{ - color: var(--accent-color); - .icon{ - stroke: var(--accent-color); +#confirmation_popup, +#prompt_popup { + flex-direction: column; + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + sm-button{ + margin: 0; + } + .flex { + padding: 0; + margin-top: 1rem; + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; } } } +h1,h2,h3,h4.h5{ + font-family: 'Poppins', sans-serif; +} +h2{ + margin: 3rem 0 1rem 0; + text-transform: capitalize; +} +main{ + display: grid; + height: 100%; + grid-template-rows: auto 1fr auto; + grid-template-areas: 'main-header' '.' 'side-nav'; + +} #main_header{ - display: flex; - padding: 1rem 0; + grid-area: main-header; + padding: 1rem 1.5rem; + border-bottom: 1px solid rgba(var(--text-color), .1); } #logo{ display: grid; align-items: center; width: 100%; grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; + gap: 0 0.5rem; margin-right: 1rem; h4{ text-transform: capitalize; - font-size: 1.2rem; + font-size: 1rem; font-weight: 600; } - h5{ - font-family: 'Roboto', sans-serif; - font-weight: 400; - } #main_logo{ height: 1.4rem; width: 1.4rem; @@ -132,141 +295,113 @@ p{ stroke: none; } } -.toggle{ - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; - input[type='checkbox']{ - display: none; +.right{ + max-height: 100%; + overflow-y: auto; +} +#side_nav{ + grid-area: side-nav; + h4{ + font-size: 0.9rem; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 1.5rem; } - .switch{ - overflow: hidden; - display: inline-flex; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; +} +.nav-list{ + list-style: none; + display: flex; + justify-content: space-evenly; + li{ + width: 100%; } - .circle{ - border-radius: 0.5rem; - transition: transform 0.3s; - &:first-of-type{ - margin-bottom: 0.4rem; - } - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; - line{ - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; +} +.nav-list__item{ + display: flex; + padding: 0.8rem 1.5rem; + text-transform: capitalize; + &--active{ + color: var(--accent-color); + .icon{ + fill: var(--accent-color); } } - input:checked ~ .switch .circle{ - transform: translateY(-1.7rem); +} +.right{ + padding: 1.5rem; + h1{ + margin-bottom: 1.5rem; } } .page{ - padding: 2rem 0; - padding-bottom: 4rem; -} -.options-tab{ display: flex; - margin-top: 1rem; - margin-bottom: 1rem; - flex-wrap: wrap; - .option{ - display: inline-flex; + flex-direction: column; + padding-bottom: 3rem; +} +@media screen and (max-width: 640px){ + main{ + grid-template-rows: auto 1fr; + grid-template-columns: 1fr; + } + .nav-list__item{ flex-direction: column; - border-radius: 0.4rem; - padding: 1.5rem; - margin-right: 1rem; - margin-bottom: 1rem; - width: 9rem; - border: solid 1px rgba(var(--text-color), 0.2); - text-transform: capitalize; - cursor: pointer; - -webkit-tap-highlight-color: transparent; - .icon{ - background: rgba(var(--text-color), 0.1); - height: 2.8rem; - width: 2.8rem; - padding: 0.8rem; - border-radius: 2rem; - margin-bottom: 1rem; - stroke: rgba(var(--text-color), 0.4); - } - h4{ - font-weight: 400; - font-size: 0.9rem; - } - } -} -#home_page{ - h1{ - margin-top: 3vw; - font-weight: 600; - } - p{ - margin-bottom: 3rem; - } - h2{ - margin-bottom: 1rem; - } -} -@media only screen and (min-width: 640px){ - body{ - padding: 1rem 6vw; - margin-left: 6rem; - } - p{ - max-width: 40rem; - } - #navbar{ justify-content: center; - flex-direction: column; - align-items: stretch; - left: 0; - bottom: 0; - top: 0; - right: auto; - width: 6rem; - border-top: none; - border-right: solid 1px rgba(var(--text-color), 0.2); - .navbar-item{ - width: auto; - padding: 1.4em 0; - margin: 0.6em; - .icon{ - height: 1.4rem; - width: 1.4rem; - } - h5{ - font-size: 0.8em; - } - &:hover{ - .icon{ - stroke: rgba(var(--text-color), 1); - } - h5{ - color: rgba(var(--text-color), 1); - } - } - &.active:hover{ - .icon{ - stroke: var(--accent-color); - } - h5{ - color: var(--accent-color); - } - } + align-items: center; + padding: 0.4rem; + span{ + font-size: 0.8rem; + margin-top: 0.3rem; } } +} +@media screen and (min-width: 640px){ + sm-popup{ + --width: 32rem; + } + main{ + grid-template-columns: 14rem minmax(0, 1fr); + grid-template-rows: auto 1fr; + grid-template-areas: 'main-header main-header' 'side-nav .'; + } + .nav-list{ + flex-direction: column; + } + .nav-list__item{ + align-items: center; + justify-content: start; + &--active{ + background: rgba(var(--text-color), .06); + } + .icon{ + margin-right: 0.5rem; + } + } + .right{ + display: grid; + grid-template-columns: 1fr 90% 1fr; + & > * { + grid-column: 2/3; + } + } + .page__title{ + font-size: 2.5rem; + } +} +@media (any-hover: hover){ + ::-webkit-scrollbar{ + width: 0.5rem; + height: 0.5rem; + } + + ::-webkit-scrollbar-thumb{ + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + &:hover{ + background: rgba(var(--text-color), 0.5); + } + } + .nav-list__item:hover{ + background: rgba(var(--text-color), .1); + cursor: pointer; + } } \ No newline at end of file diff --git a/Layouts/boxes layout/index.html b/Layouts/boxes layout/index.html index 682a063..3042abe 100644 --- a/Layouts/boxes layout/index.html +++ b/Layouts/boxes layout/index.html @@ -6,131 +6,82 @@ Document + + + - -
-
- +
-
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi excepturi eius voluptate quod quasi - dolore, quisquam, voluptatem repellendus sapiente consectetur similique ducimus dicta magni harum, - perspiciatis unde debitis? Eveniet, temporibus! -

- -

Options

- -
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
+
+ -
-
-

User Settings

-
+ + + +
+
+

Dashboard

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Esse, sint. Aperiam ipsum expedita tenetur quasi, repellat ea. Laboriosam, earum ratione!

+
+ +
+

Settings

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Excepturi nihil distinctio dolore molestias ullam architecto ipsam qui possimus aliquam. Odio.

+
+
- - - + + \ No newline at end of file diff --git a/Layouts/boxes layout/js/components.js b/Layouts/boxes layout/js/components.js deleted file mode 100644 index 30d8c2f..0000000 --- a/Layouts/boxes layout/js/components.js +++ /dev/null @@ -1,2918 +0,0 @@ -//Button - -const smButton = document.createElement('template') -smButton.innerHTML = ` - -
- -
`; -customElements.define('sm-button', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smButton.content.cloneNode(true)) - } - static get observedAttributes() { - return ['disabled'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - dispatch = () => { - if (this.getAttribute('disabled') === 'true') { - this.dispatchEvent(new CustomEvent('disabled', { - bubbles: true, - composed: true - })) - } - else { - this.dispatchEvent(new CustomEvent('clicked', { - bubbles: true, - composed: true - })) - } - } - - connectedCallback() { - this.addEventListener('click', (e) => { - this.dispatch() - }) - this.addEventListener('keyup', (e) => { - if (e.code === "Enter" || e.code === "Space") - this.dispatch() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - - -
-`; -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 = () => { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; - if (this.input.value !== '') { - if (this.animate) - this.inputParent.classList.add('animate-label') - else - this.label.classList.add('hide') - this.clearBtn.classList.remove('hide') - } - else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - this.clearBtn.classList.add('hide') - } - if (this.valueChanged) { - if (this.input.checkValidity()) { - this.helperText.classList.add('hide') - this.inputParent.style.boxShadow = `` - } - else { - this.helperText.classList.remove('hide') - this.inputParent.style.boxShadow = `0 0 0 0.1rem ${this.computedStyle.getPropertyValue('--error-color')}` - } - } - } - - connectedCallback() { - this.inputParent = this.shadowRoot.querySelector('.input') - this.computedStyle = window.getComputedStyle(this.inputParent) - this.clearBtn = this.shadowRoot.querySelector('.clear') - this.label = this.shadowRoot.querySelector('.label') - this.helperText = this.shadowRoot.querySelector('.helper-text') - this.valueChanged = false; - this.animate = this.hasAttribute('animate') - this.input = this.shadowRoot.querySelector('input') - this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') - if (this.hasAttribute('value')) { - this.input.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('helper-text')) { - this.helperText.textContent = this.getAttribute('helper-text') - } - if (this.hasAttribute('type')) { - if (this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric') - } - else - this.input.setAttribute('type', this.getAttribute('type')) - } - else - this.input.setAttribute('type', 'text') - this.input.addEventListener('keydown', e => { - if (this.getAttribute('type') === 'number') - this.preventNonNumericalInput(e); - }) - this.input.addEventListener('input', e => { - this.checkInput() - }) - this.input.addEventListener('change', e => { - this.valueChanged = true; - if (this.input.checkValidity()) - this.helperText.classList.add('hide') - else - this.helperText.classList.remove('hide') - }) - this.clearBtn.addEventListener('click', e => { - this.input.value = '' - this.checkInput() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'placeholder') - this.shadowRoot.querySelector('.label').textContent = newValue; - } - } - }) - -// tab-header - -const smTabs = document.createElement('template') -smTabs.innerHTML = ` - -
-
- Nothing to see here -
-
-
- Nothing to see here -
-
-`; - -customElements.define('sm-tabs', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smTabs.content.cloneNode(true)) - this.indicator = this.shadowRoot.querySelector('.indicator'); - this.tabSlot = this.shadowRoot.querySelector('slot[name="tab"]'); - this.panelSlot = this.shadowRoot.querySelector('slot[name="panel"]'); - this.tabHeader = this.shadowRoot.querySelector('.tab-header'); - } - connectedCallback() { - - //animations - let flyInLeft = [ - { - opacity: 0, - transform: 'translateX(-1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyInRight = [ - { - opacity: 0, - transform: 'translateX(1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyOutLeft = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(-1rem)' - } - ], - flyOutRight = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(1rem)' - } - ], - animationOptions = { - duration: 300, - fill: 'forwards', - easing: 'ease' - } - this.prevTab - this.allTabs - - this.shadowRoot.querySelector('slot[name="panel"]').addEventListener('slotchange', () => { - this.shadowRoot.querySelector('slot[name="panel"]').assignedElements().forEach((panel, index) => { - panel.classList.add('hide-completely') - }) - }) - this.shadowRoot.querySelector('slot[name="tab"]').addEventListener('slotchange', () => { - this.allTabs = this.shadowRoot.querySelector('slot[name="tab"]').assignedElements(); - this.shadowRoot.querySelector('slot[name="tab"]').assignedElements().forEach((panel, index) => { - panel.setAttribute('rank', index + 1) - }) - }) - this._targetBodyFlyRight = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInRight, animationOptions) - } - this._targetBodyFlyLeft = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInLeft, animationOptions) - } - this.tabSlot.addEventListener('click', e => { - if (e.target === this.prevTab || !e.target.closest('sm-tab')) - return - if (this.prevTab) - this.prevTab.classList.remove('active') - e.target.classList.add('active') - - e.target.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) - this.indicator.setAttribute('style', `width: ${e.target.getBoundingClientRect().width}px; transform: translateX(${e.target.getBoundingClientRect().left - e.target.parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - - if (this.prevTab) { - let targetBody = e.target.nextElementSibling, - currentBody = this.prevTab.nextElementSibling; - - if (this.prevTab.getAttribute('rank') < e.target.getAttribute('rank')) { - if (currentBody && !targetBody) - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyRight(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyRight(targetBody) - } - } - } else { - if (currentBody && !targetBody) - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyLeft(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyLeft(targetBody) - } - } - } - } else { - e.target.nextElementSibling.classList.remove('hide-completely') - } - this.prevTab = e.target; - }) - let resizeObserver = new ResizeObserver(entries => { - entries.forEach((entry) => { - if (this.prevTab) { - let tabDimensions = this.prevTab.getBoundingClientRect(); - this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - }) - }) - resizeObserver.observe(this) - let observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - let activeElement = this.tabSlot.assignedElements().filter(element => { - if (element.classList.contains('active')) - return true - }) - if (activeElement.length) { - let tabDimensions = activeElement[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - activeElement[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - else { - this.tabSlot.assignedElements()[0].classList.add('active') - this.panelSlot.assignedElements()[0].classList.remove('hide-completely') - let tabDimensions = this.tabSlot.assignedElements()[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - this.prevTab = this.tabSlot.assignedElements()[0]; - } - } - }) - }, - { threshold: 1.0 }) - observer.observe(this) - if (this.hasAttribute('enable-flick') && this.getAttribute('enable-flick') == 'true') { - let touchStartTime = 0, - touchEndTime = 0, - swipeTimeThreshold = 200, - swipeDistanceThreshold = 20, - startingPointX = 0, - endingPointX = 0, - currentIndex = 0; - this.addEventListener('touchstart', e => { - touchStartTime = e.timeStamp - startingPointX = e.changedTouches[0].clientX - }) - this.panelSlot.addEventListener('touchend', e => { - touchEndTime = e.timeStamp - endingPointX = e.changedTouches[0].clientX - if (touchEndTime - touchStartTime < swipeTimeThreshold) { - currentIndex = this.allTabs.findIndex(element => element.classList.contains('active')) - if (startingPointX > endingPointX && startingPointX - endingPointX > swipeDistanceThreshold && currentIndex < this.allTabs.length) { - this.allTabs[currentIndex + 1].click() - } - else if (startingPointX < endingPointX && endingPointX - startingPointX > swipeDistanceThreshold && currentIndex > 0) { - this.allTabs[currentIndex - 1].click() - } - } - }) - } - } -}) - -// tab -const smTab = document.createElement('template') -smTab.innerHTML = ` - -
- -
-`; - -customElements.define('sm-tab', class extends HTMLElement { - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smTab.content.cloneNode(true)) - } -}) - -//chcekbox - -const smCheckbox = document.createElement('template') -smCheckbox.innerHTML = ` - -` -customElements.define('sm-checkbox', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smCheckbox.content.cloneNode(true)) - - this.checkbox = this.shadowRoot.querySelector('.checkbox'); - this.input = this.shadowRoot.querySelector('input') - - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.getAttribute('checked') - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.checkbox.classList.add('disabled') - this.isDisabled = true - } - else { - this.checkbox.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } - -}) - -//audio - -const smAudio = document.createElement('template') -smAudio.innerHTML = ` - -
- - play - - - - pause - - - -
/
- -
- -`; - -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') - } - } - } -}) - -//switch - -const smSwitch = document.createElement('template') -smSwitch.innerHTML = ` - -` - -customElements.define('sm-switch', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSwitch.content.cloneNode(true)) - this.switch = this.shadowRoot.querySelector('.switch'); - this.input = this.shadowRoot.querySelector('input') - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.isChecked - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.switch.classList.add('disabled') - this.isDisabled = true - } - else { - this.switch.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } -}) - -// select -const smSelect = document.createElement('template') -smSelect.innerHTML = ` - -
-
-
- - - -
-
- -
-
`; -customElements.define('sm-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - - collapse = () => { - this.optionList.animate(this.slideUp, this.animationOptions) - this.optionList.classList.add('hide') - this.chevron.classList.remove('rotate') - this.open = false - } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [ - { transform: `translateY(-0.5rem)` }, - { transform: `translateY(0)` } - ], - this.slideUp = [ - { transform: `translateY(0)` }, - { transform: `translateY(-0.5rem)` } - ], - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' - } - selection.addEventListener('click', e => { - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { - this.setAttribute('value', e.detail.value) - this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - if (previousOption) { - previousOption.classList.remove('check-selected') - } - previousOption = e.target; - } - if(!e.detail.switching) - this.collapse() - - e.target.classList.add('check-selected') - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); - document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { - this.collapse() - } - }) - } -}) - -// option -const smOption = document.createElement('template') -smOption.innerHTML = ` - -
- - - - -
`; -customElements.define('sm-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smOption.content.cloneNode(true)) - } - - sendDetails = (switching) => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value'), - switching: switching - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - let validKey = [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight' - ] - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - if (validKey.includes(e.code)) { - e.preventDefault() - this.sendDetails(true) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -// select -const smStripSelect = document.createElement('template') -smStripSelect.innerHTML = ` - -
-
- - Previous - - -
- -
- - Next - - -
-
`; -customElements.define('sm-strip-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - scrollLeft = () => { - this.select.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.select.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - connectedCallback() { - let previousOption, - slot = this.shadowRoot.querySelector('slot'); - this.selectContainer = this.shadowRoot.querySelector('.select-container') - this.select = this.shadowRoot.querySelector('.select') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.selectOptions - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.previousArrow.classList.add('hide') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.remove('hide') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.nextArrow.classList.add('hide') - this.nextGradient.classList.add('hide') - } - else { - this.nextArrow.classList.remove('hide') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - - const selectObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - } - }) - - selectObserver.observe(this.selectContainer) - this.addEventListener('optionSelected', e => { - if (previousOption === e.target) return; - if (previousOption) - previousOption.classList.remove('active') - e.target.classList.add('active') - e.target.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }) - this.setAttribute('value', e.detail.value) - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - previousOption = e.target; - }) - slot.addEventListener('slotchange', e => { - this.selectOptions = slot.assignedElements() - firstElementObserver.observe(this.selectOptions[0]) - lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) - if (this.selectOptions[0]) { - let firstElement = this.selectOptions[0]; - this.setAttribute('value', firstElement.getAttribute('value')) - firstElement.classList.add('active') - previousOption = firstElement; - } - }); - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -// option -const smStripOption = document.createElement('template') -smStripOption.innerHTML = ` - -
- -
`; -customElements.define('sm-strip-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripOption.content.cloneNode(true)) - } - sendDetails = () => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value') - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -//popup -const smPopup = document.createElement('template') -smPopup.innerHTML = ` - - -`; -customElements.define('sm-popup', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smPopup.content.cloneNode(true)) - } - - resumeScrolling = () => { - const scrollY = document.body.style.top; - window.scrollTo(0, parseInt(scrollY || '0') * -1); - setTimeout(() => { - document.body.setAttribute('style', `overflow: auto; top: initial`) - }, 300); - } - - show(pinned, popupStack) { - this.pinned = pinned - this.popupStack = popupStack - this.popupContainer.classList.remove('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(0)'; - else - this.popup.style.transform = 'scale(1)'; - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - } - hide() { - this.popupContainer.classList.add('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(100%)'; - else - this.popup.style.transform = 'scale(0.9)'; - if (typeof this.popupStack !== 'undefined') { - this.popupStack.pop() - if (this.popupStack.items.length === 0) { - this.resumeScrolling() - } - } - else { - this.resumeScrolling() - } - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartY < e.changedTouches[0].clientY) { - this.offset = e.changedTouches[0].clientY - this.touchStartY; - this.touchEndAnimataion = window.requestAnimationFrame(this.movePopup) - } - /*else { - offset = touchStartY - e.changedTouches[0].clientY; - this.popup.style.transform = `translateY(-${offset}px)` - }*/ - } - - handleTouchEnd = (e) => { - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.3s' - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndY - this.touchStartY > this.threshold) { - this.hide() - } - else { - this.show() - } - } - else { - if (this.touchEndY > this.touchStartY) - this.hide() - } - } - - movePopup = () => { - this.popup.style.transform = `translateY(${this.offset}px)` - } - - connectedCallback() { - this.pinned = false - this.popupStack - this.popupContainer = this.shadowRoot.querySelector('.popup-container') - this.popup = this.shadowRoot.querySelector('.popup') - this.offset - this.popupHeader = this.shadowRoot.querySelector('.popup-top') - this.touchStartY = 0 - this.touchEndY = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - this.touchEndAnimataion; - - if (this.hasAttribute('heading')) - this.shadowRoot.querySelector('.heading').textContent = this.getAttribute('heading') - - this.popupContainer.addEventListener('mousedown', e => { - if (e.target === this.popupContainer && !this.pinned) { - this.hide() - } - }) - - this.shadowRoot.querySelector('.close').addEventListener('click', e => { - this.hide() - }) - - this.popupHeader.addEventListener('touchstart', this.handleTouchStart) - this.popupHeader.addEventListener('touchmove', this.handleTouchMove) - this.popupHeader.addEventListener('touchend', this.handleTouchEnd) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd) - } -}) - -//carousel - -const smCarousel = document.createElement('template') -smCarousel.innerHTML = ` - - -`; - -customElements.define('sm-carousel', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smCarousel.content.cloneNode(true)) - } - - scrollLeft = () => { - this.carousel.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.carousel.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - - connectedCallback() { - this.carousel = this.shadowRoot.querySelector('.carousel') - this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') - this.carouselSlot = this.shadowRoot.querySelector('slot') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.carouselItems - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width/3 - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.previousArrow.classList.remove('expand') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.add('expand') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.nextArrow.classList.remove('expand') - this.nextGradient.classList.add('hide') - } - else{ - this.nextArrow.classList.add('expand') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - - const carouselObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 - } - }) - - carouselObserver.observe(this.carouselContainer) - - this.carouselSlot.addEventListener('slotchange', e => { - this.carouselItems = this.carouselSlot.assignedElements() - firstElementObserver.observe(this.carouselItems[0]) - lastElementObserver.observe(this.carouselItems[this.carouselItems.length - 1]) - }) - - this.addEventListener('keyup', e => { - if (e.code === 'ArrowLeft') - this.scrollRight() - else - this.scrollRight() - }) - - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -//notifications - -const smNotifications = document.createElement('template') -smNotifications.innerHTML = ` - -
-
-` - -customElements.define('sm-notifications', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smNotifications.content.cloneNode(true)) - } - - handleTouchStart = (e) => { - this.notification = e.target.closest('.notification') - this.touchStartX = e.changedTouches[0].clientX - this.notification.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartX < e.changedTouches[0].clientX) { - this.offset = e.changedTouches[0].clientX - this.touchStartX; - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - else { - this.offset = -(this.touchStartX - e.changedTouches[0].clientX); - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - } - - handleTouchEnd = (e) => { - this.notification.style.transition = 'height 0.3s, transform 0.3s, opacity 0.3s' - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndX = e.changedTouches[0].clientX - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndX - this.touchStartX > this.threshold) { - this.removeNotification(this.notification) - } - else if (this.touchStartX - this.touchEndX > this.threshold) { - this.removeNotification(this.notification, true) - } - else { - this.resetPosition() - } - } - else { - if (this.touchEndX > this.touchStartX) { - this.removeNotification(this.notification) - } - else { - this.removeNotification(this.notification, true) - } - } - } - - movePopup = () => { - this.notification.style.transform = `translateX(${this.offset}px)` - } - - resetPosition = () => { - this.notification.style.transform = `translateX(0)` - } - - push = (messageHeader, messageBody, options) => { - let notification = document.createElement('div'), - composition = ``, - { pinned, type } = options; - notification.classList.add('notification') - if (pinned) - notification.classList.add('pinned') - composition += ` -
-
- ` - if (type === 'error') { - composition += ` - - - - - ` - } - else if (type === 'success') { - composition += ` - - - - ` - } - composition += ` -

${messageHeader}

- - Close - - - -
-

${messageBody}

-
` - notification.innerHTML = composition - this.notificationPanel.prepend(notification) - if (window.innerWidth > 640) { - notification.animate([ - { - transform: `translateX(1rem)`, - opacity: '0' - }, - { - transform: 'translateX(0)', - opacity: '1' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `transform: none;`); - } - } - else { - notification.setAttribute('style', `transform: translateY(0); opacity: 1`) - } - notification.addEventListener('touchstart', this.handleTouchStart) - notification.addEventListener('touchmove', this.handleTouchMove) - notification.addEventListener('touchend', this.handleTouchEnd) - } - - removeNotification = (notification, toLeft) => { - notification.style.height = notification.scrollHeight + 'px'; - if (!this.offset) - this.offset = 0; - - if (toLeft) - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(-100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - else { - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - } - setTimeout( () => { - notification.remove() - }, this.animationOptions.duration*2) - } - - connectedCallback() { - this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: "ease" - } - this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) - this.notification - this.offset - this.touchStartX = 0 - this.touchEndX = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 - this.touchEndAnimataion; - - this.notificationPanel.addEventListener('click', e => { - if (e.target.closest('.close'))( - this.removeNotification(e.target.closest('.notification')) - ) - }) - - const observer = new MutationObserver(mutationList => { - mutationList.forEach(mutation => { - if (mutation.type === 'childList') { - if (mutation.addedNodes.length) { - if (!mutation.addedNodes[0].classList.contains('pinned')) - setTimeout(() => { - this.removeNotification(mutation.addedNodes[0]) - }, 4000); - if (window.innerWidth > 640) - this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; - else - this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; - } - else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { - this.notificationPanel.style.padding = 0; - } - } - }) - }) - observer.observe(this.notificationPanel, { - attributes: true, - childList: true, - subtree: true - }) - } -}) -// sm-menu -const smMenu = document.createElement('template') -smMenu.innerHTML = ` - -
- -
- -
-
`; -customElements.define('sm-menu', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenu.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - expand = () => { - if (!this.open) { - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - this.optionList.classList.remove('hide') - this.optionList.classList.add('no-transformations') - this.open = true - this.icon.classList.add('focused') - } - } - collapse = () => { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - } - } - connectedCallback() { - this.availableOptions - this.containerDimensions - this.optionList = this.shadowRoot.querySelector('.options') - let slot = this.shadowRoot.querySelector('.options slot'), - menu = this.shadowRoot.querySelector('.menu') - this.icon = this.shadowRoot.querySelector('.icon') - this.open = false; - menu.addEventListener('click', e => { - if (!this.open) { - this.expand() - } else { - this.collapse() - } - }) - menu.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - if (!this.open) { - this.expand() - } else { - this.collapse() - } - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.optionList.addEventListener('click', e => { - this.collapse() - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - this.containerDimensions = this.optionList.getBoundingClientRect() - this.menuDimensions = menu.getBoundingClientRect() - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - if (this.hasAttribute('set-context') && this.getAttribute('set-context') === 'true') { - this.parentNode.setAttribute('oncontextmenu', 'return false') - this.parentNode.addEventListener('mouseup', e => { - if (e.button === 2) { - this.expand() - } - }) - } - const intersectionObserver = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (!entry.isIntersecting && this.open) { - if(window.innerHeight - entry.intersectionRect.top < this.containerDimensions.height) - this.optionList.classList.add('moveUp') - else - this.optionList.classList.remove('moveUp') - if (entry.intersectionRect.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - } - }) - }, { - threshold: 1 - }) - intersectionObserver.observe(this.optionList) - } -}) - -// option -const smMenuOption = document.createElement('template') -smMenuOption.innerHTML = ` - -
- -
`; -customElements.define('sm-menu-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenuOption.content.cloneNode(true)) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.click() - } - }) - this.setAttribute('tabindex', '0') - } -}) \ No newline at end of file diff --git a/Layouts/boxes layout/js/components.min.js b/Layouts/boxes layout/js/components.min.js new file mode 100644 index 0000000..4f0c4e7 --- /dev/null +++ b/Layouts/boxes layout/js/components.min.js @@ -0,0 +1,7 @@ +const smButton=document.createElement("template");smButton.innerHTML="\n\n
\n \n
",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}handleKeyDown(e){this.hasAttribute("disabled")||"Enter"!==e.key&&"Space"!==e.code||(e.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,n){"disabled"===e?(this.removeAttribute("tabindex"),this.setAttribute("aria-disabled","true")):(this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled","false"))}}); +const hamburgerMenu=document.createElement("template");hamburgerMenu.innerHTML='\n\n
\n\n';class HamburgerMenu extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(hamburgerMenu.content.cloneNode(!0)),this.resumeScrolling=this.resumeScrolling.bind(this),this.open=this.open.bind(this),this.close=this.close.bind(this),this.sideNav=this.shadowRoot.querySelector(".side-nav"),this.backdrop=this.shadowRoot.querySelector(".backdrop"),this.isOpen=!1,this.animeOptions={duration:300,easing:"ease"}}static get observedAttributes(){return["open"]}resumeScrolling(){const n=document.body.style.top;window.scrollTo(0,-1*parseInt(n||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}open(){this.isOpen||(document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.classList.remove("hide"),this.sideNav.classList.add("reveal"),this.backdrop.classList.remove("hide"),this.backdrop.animate([{opacity:0},{opacity:1}],this.animeOptions).onfinish=(()=>{this.isOpen=!0,this.setAttribute("open","")}))}close(){this.isOpen&&(this.sideNav.classList.remove("reveal"),this.backdrop.animate([{opacity:1},{opacity:0}],this.animeOptions).onfinish=(()=>{this.backdrop.classList.add("hide"),this.classList.add("hide"),this.isOpen=!1,this.removeAttribute("open")}))}connectedCallback(){this.backdrop.addEventListener("click",this.close);const n=new ResizeObserver(n=>{window.innerWidth<640&&this.isOpen?this.classList.remove("hide"):this.classList.add("hide"),window.innerWidth>640&&this.classList.remove("hide")});n.observe(this)}disconnectedCallback(){this.backdrop.removeEventListener("click",this.close)}attributeChangedCallback(n,e,t){"open"===n&&this.hasAttribute("open")&&this.open()}}window.customElements.define("hamburger-menu",HamburgerMenu); +const smInput=document.createElement("template");smInput.innerHTML='\n\n
\n \n \n
\n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),this.inputParent=this.shadowRoot.querySelector(".input"),this.input=this.shadowRoot.querySelector("input"),this.clearBtn=this.shadowRoot.querySelector(".clear"),this.label=this.shadowRoot.querySelector(".label"),this.feedbackText=this.shadowRoot.querySelector(".feedback-text"),this._helperText,this._errorText,this.isRequired=!1,this.validationFunction,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.focusOut=this.focusOut.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get isValid(){const t=this.input.checkValidity();let e=!0;return this.customValidation&&(e=this.validationFunction(this.input.value)),t&&e}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required")),this.isValid?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n \n ${this._errorText}\n `)),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):this.label.classList.remove("hide"))}connectedCallback(){this.animate=this.hasAttribute("animate"),this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.reset)}attributeChangedCallback(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.feedbackText.textContent="* required"):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); +const smMenu=document.createElement("template");smMenu.innerHTML='\n\n
\n \n
\n \n
\n
',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n
\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}}); +const smNotifications=document.createElement("template");smNotifications.innerHTML='\n\n
\n',customElements.define("sm-notifications",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smNotifications.content.cloneNode(!0)),this.notificationPanel=this.shadowRoot.querySelector(".notification-panel"),this.animationOptions={duration:300,fill:"forwards",easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)"},this.push=this.push.bind(this),this.createNotification=this.createNotification.bind(this),this.removeNotification=this.removeNotification.bind(this),this.clearAll=this.clearAll.bind(this)}randString(n){let t="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let o=0;o${o}
\n

${n}

\n `,i&&(e.classList.add("pinned"),a+='\n \n '),e.innerHTML=a,e}push(n,t={}){const i=this.createNotification(n,t);return this.notificationPanel.append(i),i.animate([{transform:"translateY(1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animationOptions),i.id}removeNotification(n){n.animate([{transform:"none",opacity:"1"},{transform:"translateY(0.5rem)",opacity:"0"}],this.animationOptions).onfinish=(()=>{n.remove()})}clearAll(){Array.from(this.notificationPanel.children).forEach(n=>{this.removeNotification(n)})}connectedCallback(){this.notificationPanel.addEventListener("click",n=>{n.target.closest(".close")&&this.removeNotification(n.target.closest(".notification"))});const n=new MutationObserver(n=>{n.forEach(n=>{"childList"===n.type&&n.addedNodes.length&&!n.addedNodes[0].classList.contains("pinned")&&setTimeout(()=>{this.removeNotification(n.addedNodes[0])},5e3)})});n.observe(this.notificationPanel,{childList:!0})}}); +const smPopup=document.createElement("template");smPopup.innerHTML='\n\n\n',customElements.define("sm-popup",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smPopup.content.cloneNode(!0)),this.allowClosing=!1,this.isOpen=!1,this.pinned=!1,this.popupStack,this.offset,this.touchStartY=0,this.touchEndY=0,this.touchStartTime=0,this.touchEndTime=0,this.touchEndAnimataion,this.popupContainer=this.shadowRoot.querySelector(".popup-container"),this.popup=this.shadowRoot.querySelector(".popup"),this.popupBodySlot=this.shadowRoot.querySelector(".popup-body slot"),this.popupHeader=this.shadowRoot.querySelector(".popup-top"),this.resumeScrolling=this.resumeScrolling.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.handleTouchStart=this.handleTouchStart.bind(this),this.handleTouchMove=this.handleTouchMove.bind(this),this.handleTouchEnd=this.handleTouchEnd.bind(this),this.movePopup=this.movePopup.bind(this)}static get observedAttributes(){return["open"]}get open(){return this.isOpen}resumeScrolling(){const t=document.body.style.top;window.scrollTo(0,-1*parseInt(t||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}show(t={}){const{pinned:e=!1,popupStack:n}=t;return n&&(this.popupStack=n),this.popupStack&&!this.hasAttribute("open")&&(this.popupStack.push({popup:this,permission:e}),this.popupStack.items.length>1&&this.popupStack.items[this.popupStack.items.length-2].popup.classList.add("stacked"),this.dispatchEvent(new CustomEvent("popupopened",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.setAttribute("open",""),this.pinned=e,this.isOpen=!0),this.popupContainer.classList.remove("hide"),this.popup.style.transform="none",document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.popupStack}hide(){window.innerWidth<640?this.popup.style.transform="translateY(100%)":this.popup.style.transform="translateY(3rem)",this.popupContainer.classList.add("hide"),this.removeAttribute("open"),void 0!==this.popupStack?(this.popupStack.pop(),this.popupStack.items.length?this.popupStack.items[this.popupStack.items.length-1].popup.classList.remove("stacked"):this.resumeScrolling()):this.resumeScrolling(),this.forms.length&&setTimeout(()=>{this.forms.forEach(t=>t.reset())},300),setTimeout(()=>{this.dispatchEvent(new CustomEvent("popupclosed",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.isOpen=!1},300)}handleTouchStart(t){this.touchStartY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.1s",this.touchStartTime=t.timeStamp}handleTouchMove(t){this.touchStartYthis.movePopup()))}handleTouchEnd(t){if(this.touchEndTime=t.timeStamp,cancelAnimationFrame(this.touchEndAnimataion),this.touchEndY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.3s",this.threshold=.3*this.popup.getBoundingClientRect().height,this.touchEndTime-this.touchStartTime>200)if(this.touchEndY-this.touchStartY>this.threshold){if(this.pinned)return void this.show();this.hide()}else this.show();else if(this.touchEndY>this.touchStartY){if(this.pinned)return void this.show();this.hide()}}movePopup(){this.popup.style.transform=`translateY(${this.offset}px)`}connectedCallback(){this.popupBodySlot.addEventListener("slotchange",()=>{this.forms=this.querySelectorAll("sm-form")}),this.popupContainer.addEventListener("mousedown",t=>{t.target!==this.popupContainer||this.pinned||(this.pinned?this.show():this.hide())});const t=new ResizeObserver(t=>{for(let e of t)if(e.contentBoxSize){Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.threshold=.3*e.blockSize.height}else this.threshold=.3*e.contentRect.height});t.observe(this),this.popupHeader.addEventListener("touchstart",t=>{this.handleTouchStart(t)},{passive:!0}),this.popupHeader.addEventListener("touchmove",t=>{this.handleTouchMove(t)},{passive:!0}),this.popupHeader.addEventListener("touchend",t=>{this.handleTouchEnd(t)},{passive:!0})}disconnectedCallback(){this.popupHeader.removeEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.popupHeader.removeEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.popupHeader.removeEventListener("touchend",this.handleTouchEnd,{passive:!0}),resizeObserver.unobserve()}attributeChangedCallback(t,e,n){"open"===t&&this.hasAttribute("open")&&this.show()}}); +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/Layouts/boxes layout/js/helper.js b/Layouts/boxes layout/js/helper.js deleted file mode 100644 index a7c51ee..0000000 --- a/Layouts/boxes layout/js/helper.js +++ /dev/null @@ -1,133 +0,0 @@ -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) -}) -let themeToggler = document.getElementById("theme_toggle") -if (localStorage.theme === "dark") { - darkTheme() - themeToggler.checked = true; -} else { - lightTheme() - themeToggler.checked = false; -} - -function lightTheme() { - document.body.setAttribute("data-theme", "light"); -} - -function darkTheme() { - document.body.setAttribute("data-theme", "dark"); -} -themeToggler.addEventListener("change", () => { - if (themeToggler.checked) { - darkTheme() - localStorage.setItem("theme", "dark"); - } else { - lightTheme() - 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(index) { - let newIndex = index ? index : 1 - return this.items[this.items.length - index]; - } -} -let popupStack = new Stack(), - zIndex = 10; -function showPopup(popup, permission) { - let thisPopup = document.getElementById(popup); - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - popupStack.push({ thisPopup, permission }) - thisPopup.show(permission, popupStack) - zIndex++; - thisPopup.setAttribute('style', `z-index: ${zIndex}`) - return thisPopup; -} -function setAttributes(el, attrs) { - for (var key in attrs) { - el.setAttribute(key, attrs[key]); - } -} -// displays a popup for asking permission. Use this instead of JS confirm -let confirmation = 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); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(false); - } - }) -} - -// 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'); - if (defaultVal) - input.value = defaultVal; - showPopup('prompt') - input.focus() - input.addEventListener('keyup', e => { - if (e.key === 'Enter') { - resolve(input.value); - hidePopup() - } - }) - popup.querySelector('#prompt_message').textContent = message; - popup.querySelector('.submit-btn').onclick = () => { - hidePopup() - resolve(input.value); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(null); - } - }) -} - -function formatedTime(time) { - let timeFrag = new Date(parseInt(time)).toString().split(' '), - day = timeFrag[0], - month = timeFrag[1], - date = timeFrag[2], - year = timeFrag[3], - hours = timeFrag[4].slice(0, timeFrag[4].lastIndexOf(':')), - finalTime = ''; - parseInt(hours.split(':')[0]) > 12 ? finalTime = 'PM' : finalTime = 'AM' - return `${hours} ${finalTime} ${day} ${date} ${month} ${year}` -} - -function copyToClipboard(parent) { - let toast = document.getElementById('textCopied'), - textToCopy = parent.querySelector('.copy').textContent; - navigator.clipboard.writeText(textToCopy) - toast.classList.remove('hide'); - setTimeout(() => { - toast.classList.add('hide'); - }, 2000) -} \ No newline at end of file diff --git a/Layouts/boxes layout/js/main_UI.js b/Layouts/boxes layout/js/main_UI.js new file mode 100644 index 0000000..e60c9a9 --- /dev/null +++ b/Layouts/boxes layout/js/main_UI.js @@ -0,0 +1,309 @@ +// Global variables +const domRefs = {}; +const appPages = ['dashboard', 'settings'] + + +//Checks for internet connection status +if (!navigator.onLine) + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { sound: true } + ); +window.addEventListener("offline", () => { + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { pinned: true, sound: true } + ); +}); +window.addEventListener("online", () => { + getRef("notification_drawer").clearAll(); + notify("We are back online.", "success"); +}); + +// Use instead of document.getElementById +function getRef(elementId) { + if (!domRefs.hasOwnProperty(elementId)) { + domRefs[elementId] = { + count: 1, + ref: null, + }; + return document.getElementById(elementId); + } else { + if (domRefs[elementId].count < 3) { + domRefs[elementId].count = domRefs[elementId].count + 1; + return document.getElementById(elementId); + } else { + if (!domRefs[elementId].ref) + domRefs[elementId].ref = document.getElementById(elementId); + return domRefs[elementId].ref; + } + } +} + +// returns dom with specified element +function createElement(tagName, obj) { + const { className, textContent, innerHTML, attributes = {} } = obj + const elem = document.createElement(tagName) + for (let attribute in attributes) { + elem.setAttribute(attribute, attributes[attribute]) + } + if (className) + elem.className = className + if (textContent) + elem.textContent = textContent + if (innerHTML) + elem.innerHTML = innerHTML + return elem +} + +// Use when a function needs to be executed after user finishes changes +const debounce = (callback, wait) => { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; +} + +// Limits the rate of function execution +let timerId; +function throttle(func, delay) { + // If setTimeout is already scheduled, no need to do anything + if (timerId) { + return; + } + + // Schedule a setTimeout after delay seconds + timerId = setTimeout(function () { + func(); + + // Once setTimeout function execution is finished, timerId = undefined so that in + // the next scroll event function execution can be scheduled by the setTimeout + timerId = undefined; + }, delay); +} + +// 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; + +async function showPopup(popup, pinned) { + zIndex++ + getRef(popup).setAttribute('style', `z-index: ${zIndex}`) + popupStack = getRef(popup).show({ pinned, popupStack }) + return getRef(popup); +} + +// hides the popup or modal +function hidePopup() { + if (popupStack.peek() === undefined) + return; + popupStack.peek().popup.hide() +} + +// displays a popup for asking permission. Use this instead of JS confirm +let getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => { + return new Promise(resolve => { + showPopup('confirmation_popup', true) + getRef('confirm_title').textContent = title; + getRef('confirm_message').textContent = message; + let cancelButton = getRef('confirmation_popup').children[2].children[0], + submitButton = getRef('confirmation_popup').children[2].children[1] + submitButton.textContent = confirmText + cancelButton.textContent = cancelText + submitButton.onclick = () => { + hidePopup() + resolve(true); + } + cancelButton.onclick = () => { + hidePopup() + resolve(false); + } + }) +} + +// displays a popup for asking user input. Use this instead of JS prompt +async function getPromptInput(title, message = '', showText = true, trueBtn = "Ok", falseBtn = "Cancel") { + showPopup('prompt_popup', true) + getRef('prompt_title').textContent = title; + let input = getRef('prompt_input'); + input.setAttribute("placeholder", message) + let buttons = getRef('prompt_popup').querySelectorAll("sm-button"); + if (showText) + input.setAttribute("type", "text") + else + input.setAttribute("type", "password") + input.focusIn() + buttons[0].textContent = falseBtn; + buttons[1].textContent = trueBtn; + return new Promise((resolve, reject) => { + buttons[0].onclick = () => { + hidePopup() + return; + } + buttons[1].onclick = () => { + let value = input.value; + hidePopup() + resolve(value) + } + }) +} + +//Function for displaying toast notifications. pass in error for mode param if you want to show an error. +function notify(message, mode, options = {}) { + const { pinned = false, sound } = options + if (mode === "error") console.error(message); + let icon + switch (mode) { + case 'success': + icon = `` + break; + case 'error': + icon = `` + break; + } + getRef("notification_drawer").push(message, { pinned, icon }); + if (navigator.onLine && sound) { + getRef("notification_sound").currentTime = 0; + getRef("notification_sound").play(); + } +} + +const currentYear = new Date().getFullYear(); +function getFormatedTime(time, relative) { + try { + if (String(time).indexOf("_")) time = String(time).split("_")[0]; + const intTime = parseInt(time); + if (String(intTime).length < 13) time *= 1000; + let timeFrag = new Date(intTime).toString().split(" "), + day = timeFrag[0], + month = timeFrag[1], + date = timeFrag[2], + year = timeFrag[3], + minutes = new Date(intTime).getMinutes(), + hours = new Date(intTime).getHours(), + currentTime = new Date().toString().split(" "); + + minutes = minutes < 10 ? `0${minutes}` : minutes; + let finalHours = ``; + if (hours > 12) finalHours = `${hours - 12}:${minutes}`; + else if (hours === 0) finalHours = `12:${minutes}`; + else finalHours = `${hours}:${minutes}`; + + finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`; + if (relative) { + return `${date} ${month} ${year}`; + } else return `${finalHours} ${month} ${date} ${year}`; + } catch (e) { + console.error(e); + return time; + } +} + +window.addEventListener('hashchange', e => showPage(window.location.hash)) +window.addEventListener("load", () => { + document.body.classList.remove('hide-completely') + showPage(window.location.hash) + // document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = validateAddr) + document.addEventListener('keyup', (e) => { + if (e.code === 'Escape') { + hidePopup() + } + }) + document.addEventListener("pointerdown", (e) => { + if (e.target.closest("button, sm-button:not([disabled]), .interact")) { + createRipple(e, e.target.closest("button, sm-button, .interact")); + } + }); + document.addEventListener('copy', () => { + notify('copied', 'success') + }) +}); + +function createRipple(event, target) { + const circle = document.createElement("span"); + const diameter = Math.max(target.clientWidth, target.clientHeight); + const radius = diameter / 2; + const targetDimensions = target.getBoundingClientRect(); + circle.style.width = circle.style.height = `${diameter}px`; + circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`; + circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`; + circle.classList.add("ripple"); + const rippleAnimation = circle.animate( + [ + { + transform: "scale(3)", + opacity: 0, + }, + ], + { + duration: 1000, + fill: "forwards", + easing: "ease-out", + } + ); + target.append(circle); + rippleAnimation.onfinish = () => { + circle.remove(); + }; +} + +function showPage(targetPage, options = {}) { + const { firstLoad, hashChange } = options + let pageId + if (targetPage === '') { + pageId = 'overview_page' + } + else { + pageId = targetPage.includes('#') ? targetPage.split('#')[1] : targetPage + } + if(!appPages.includes(pageId)) return + document.querySelector('.page:not(.hide-completely)').classList.add('hide-completely') + document.querySelector('.nav-list__item--active').classList.remove('nav-list__item--active') + getRef(pageId).classList.remove('hide-completely') + getRef(pageId).animate([ + { + opacity: 0, + transform: 'translateX(-1rem)' + }, + { + opacity: 1, + transform: 'none' + }, + ], + { + duration: 300, + easing: 'ease' + }) + const targetListItem = document.querySelector(`.nav-list__item[href="#${pageId}"]`) + targetListItem.classList.add('nav-list__item--active') + if (firstLoad && window.innerWidth > 640 && targetListItem.getBoundingClientRect().top > getRef('side_nav').getBoundingClientRect().height) { + getRef('side_nav').scrollTo({ + top: (targetListItem.getBoundingClientRect().top - getRef('side_nav').getBoundingClientRect().top + getRef('side_nav').scrollTop), + behavior: 'smooth' + }) + } + if (hashChange && window.innerWidth < 640) { + getRef('side_nav').close() + } +} \ No newline at end of file diff --git a/Layouts/many sections layout/css/main.css b/Layouts/many sections layout/css/main.css index ed1d7e7..d7ca143 100644 --- a/Layouts/many sections layout/css/main.css +++ b/Layouts/many sections layout/css/main.css @@ -1,64 +1,88 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap"); * { - -webkit-box-sizing: border-box; - box-sizing: border-box; padding: 0; margin: 0; - font-family: 'Roboto', sans-serif; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } :root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, body { + height: 100%; scroll-behavior: smooth; } body { - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; } -body[data-theme="dark"] { - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; -} - -main { - margin: 1.5rem; -} - -h1, h2, h3, h4, h5 { - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} - -h1 { - font-size: 3rem; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -h4 { - font-size: 1rem; -} - -h5 { - font-size: 0.8rem; +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); } p { - margin: 1.5rem 0; + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); } +p:not(:last-of-type) { + margin-bottom: 1rem; +} + +img { + object-fit: cover; +} + +a { + color: inherit; + text-decoration: none; +} +a:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +button { + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} .hide { opacity: 0; @@ -69,124 +93,258 @@ p { display: none !important; } -.flex { - display: -webkit-box; - display: -ms-flexbox; - display: flex; +.no-transformations { + transform: none !important; } -.icon { - height: 1.2rem; - width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; -} - -.toggle { - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; -} - -.toggle input[type='checkbox'] { - display: none; -} - -.toggle .switch { - overflow: hidden; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; -} - -.toggle .circle { - border-radius: 0.5rem; - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; -} - -.toggle .circle:first-of-type { - margin-bottom: 0.4rem; -} - -.toggle .circle line { - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; -} - -.toggle input:checked ~ .switch .circle { - -webkit-transform: translateY(-1.7rem); - transform: translateY(-1.7rem); -} - -#navbar { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - position: -webkit-sticky; - position: sticky; - padding: 1.5rem 2rem; - left: 0; - right: 0; - top: 0; - background: rgba(var(--foreground-color), 1); - border-bottom: solid 1px rgba(var(--text-color), 0.16); - -webkit-box-shadow: 0 0.2rem 0.6rem rgba(0, 0, 0, 0.06); - box-shadow: 0 0.2rem 0.6rem rgba(0, 0, 0, 0.06); - z-index: 3; -} - -#logo { - display: -ms-grid; - display: grid; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; +.overflow-ellipsis { width: 100%; - -ms-grid-columns: auto 1fr; - grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; - margin-right: 1rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -#logo h4 { +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { text-transform: capitalize; - font-size: 1.2rem; - font-weight: 600; } -#logo h5 { - font-family: 'Roboto', sans-serif; +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { font-weight: 400; } +.weight-500 { + font-weight: 500; +} + +.ripple { + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} + +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.observe-empty-state:empty { + display: none; +} + +.observe-empty-state:not(:empty) ~ .empty-state { + display: none; +} + +.icon { + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; +} +#confirmation_popup h4, +#prompt_popup h4 { + font-weight: 500; + margin-bottom: 0.5rem; +} +#confirmation_popup sm-button, +#prompt_popup sm-button { + margin: 0; +} +#confirmation_popup .flex, +#prompt_popup .flex { + padding: 0; + margin-top: 1rem; +} +#confirmation_popup .flex sm-button:first-of-type, +#prompt_popup .flex sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; +} + +#main_header { + display: flex; + gap: 1rem; + align-items: center; + position: sticky; + padding: 1rem 1.5rem; + background: rgba(var(--background-color), 1); + border-bottom: solid 1px rgba(var(--text-color), 0.16); + z-index: 2; +} + +#logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.5rem; + margin-right: 1rem; +} +#logo h4 { + text-transform: capitalize; + font-size: 1rem; + font-weight: 600; + margin-top: 0.2rem; +} +#logo h5 { + font-size: 0.8rem; + font-family: "Roboto", sans-serif; + font-weight: 400; +} #logo #main_logo { height: 1.4rem; width: 1.4rem; @@ -195,46 +353,36 @@ p { } .section { + display: flex; + flex-direction: column; margin-top: 3rem; + padding: 0 1.5rem; } - -.section h3 + p { - margin-top: 1rem; -} - .section:first-of-type { margin-top: 0; } +.section__header { + display: flex; + padding: 1rem 0; + justify-content: space-between; +} + .card { padding: 1.5rem; - display: -webkit-box; - display: -ms-flexbox; display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; + flex-direction: column; min-width: 20rem; border-radius: 0.5rem; margin-right: 1.5rem; - border: solid 1px rgba(var(--text-color), 0.2); + background-color: rgba(var(--text-color), 0.06); } - .card h3 { font-weight: 500; } -sm-menu { - margin-left: auto; -} - -@media only screen and (min-width: 640px) { - main { - margin: 1.5rem 4vw; +@media screen and (min-width: 640px) { + sm-popup { + --width: 24rem; } - p { - max-width: 40rem; - } -} -/*# sourceMappingURL=main.css.map */ \ No newline at end of file +} \ No newline at end of file diff --git a/Layouts/many sections layout/css/main.min.css b/Layouts/many sections layout/css/main.min.css new file mode 100644 index 0000000..ff9cf05 --- /dev/null +++ b/Layouts/many sections layout/css/main.min.css @@ -0,0 +1 @@ +#logo h5,*{font-family:Roboto,sans-serif}*{padding:0;margin:0;box-sizing:border-box}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;max-width:65ch;line-height:1.7;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}ul{list-style:none}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}#logo h4,.capitalize{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}#main_header,.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.direction-column{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}#main_header{display:flex;gap:1rem;position:sticky;padding:1rem 1.5rem;background:rgba(var(--background-color),1);border-bottom:solid 1px rgba(var(--text-color),.16);z-index:2}#logo{display:grid;align-items:center;width:100%;grid-template-columns:auto 1fr;gap:0 .5rem;margin-right:1rem}#logo h4{font-size:1rem;font-weight:600;margin-top:.2rem}#logo h5{font-size:.8rem;font-weight:400}#logo #main_logo{height:1.4rem;width:1.4rem;fill:rgba(var(--text-color),1);stroke:none}.section{display:flex;flex-direction:column;margin-top:3rem;padding:0 1.5rem}.section:first-of-type{margin-top:0}.section__header{display:flex;padding:1rem 0;justify-content:space-between}.card{padding:1.5rem;display:flex;flex-direction:column;min-width:20rem;border-radius:.5rem;margin-right:1.5rem;background-color:rgba(var(--text-color),.06)}.card h3{font-weight:500}@media screen and (min-width:640px){sm-popup{--width:24rem}} \ No newline at end of file diff --git a/Layouts/many sections layout/css/main.scss b/Layouts/many sections layout/css/main.scss index 5127a65..39d1731 100644 --- a/Layouts/many sections layout/css/main.scss +++ b/Layouts/many sections layout/css/main.scss @@ -1,51 +1,79 @@ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap'); *{ - box-sizing: border-box; padding: 0; margin: 0; + box-sizing: border-box; font-family: 'Roboto', sans-serif; } :root{ + font-size: clamp(1rem, 1.2vmax, 3rem); +} +html, body{ + height: 100%; scroll-behavior: smooth; } -body{ - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); +body { + &, + *{ + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; + } color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); } -body[data-theme="dark"]{ - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; +body[data-theme='dark']{ + &, + *{ + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); + } } -main{ - margin: 1.5rem; -} -h1, h2, h3, h4, h5{ - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} -h1{ - font-size: 3rem; -} -h2{ - font-size: 2rem; -} -h3{ - font-size: 1.5rem; -} -h4{ - font-size: 1rem; -} -h5{ - font-size: 0.8rem; -} -p{ - margin: 1.5rem 0; +p { + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); + &:not(:last-of-type){ + margin-bottom: 1rem; + } +} +img{ + object-fit: cover; +} + +a{ + color: inherit; + text-decoration: none; + &:focus-visible{ + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} + +button{ + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible{ + outline: rgba(var(--text-color), 1) 0.1rem solid; +} +sm-button{ + --border-radius: 0.3rem; +} +ul{ + list-style: none; +} +.flex{ + display: flex; +} +.grid{ + display: grid; } .hide{ opacity: 0; @@ -54,86 +82,206 @@ p{ .hide-completely{ display: none !important; } +.no-transformations{ + transform: none !important; +} +.overflow-ellipsis{ + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.breakable{ + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +.full-bleed{ + grid-column: 1/4; +} +.h1{ + font-size: 2.5rem; +} +.h2{ + font-size: 2rem; +} +.h3{ + font-size: 1.4rem; +} +.h4{ + font-size: 1rem; +} +.h5{ + font-size: 0.8rem; +} + +.uppercase{ + text-transform: uppercase; +} +.capitalize{ + text-transform: capitalize; +} .flex{ display: flex; } +.grid{ + display: grid; +} +.grid-3{ + grid-template-columns: 1fr auto auto; +} +.flow-column{ + grid-auto-flow: column; +} +.gap-0-5{ + gap: 0.5rem; +} +.gap-1{ + gap: 1rem; +} +.gap-1-5{ + gap: 1.5rem; +} +.gap-2{ + gap: 2rem; +} +.gap-3{ + gap: 3rem; +} +.text-align-right{ + text-align: right; +} +.align-start{ + align-items: flex-start; +} +.align-center{ + align-items: center; +} +.text-center{ + text-align: center; +} +.justify-start{ + justify-content: start; +} +.justify-center{ + justify-content: center; +} +.justify-right{ + margin-left: auto; +} +.align-self-center{ + align-self: center; +} +.justify-self-center{ + justify-self: center; +} +.justify-self-start{ + justify-self: start; +} +.justify-self-end{ + justify-self: end; +} +.direction-column{ + flex-direction: column; +} +.space-between{ + justify-content: space-between; +} +.w-100{ + width: 100%; +} +.color-0-8{ + color: rgba(var(--text-color), 0.8); +} +.weight-400{ + font-weight: 400; +} +.weight-500{ + font-weight: 500; +} +.ripple{ + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} +.interact{ + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.observe-empty-state:empty{ + display: none; +} +.observe-empty-state:not(:empty) ~ .empty-state{ + display: none; +} .icon{ + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} +.button__icon{ height: 1.2rem; width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; -} -.toggle{ - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; - input[type='checkbox']{ - display: none; + &--left{ + margin-right: 0.5rem; } - .switch{ - overflow: hidden; - display: inline-flex; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; + &--right{ + margin-left: 0.5rem; + } +} +#confirmation_popup, +#prompt_popup { + flex-direction: column; + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + sm-button{ margin: 0; } - .circle{ - border-radius: 0.5rem; - transition: transform 0.3s; - &:first-of-type{ - margin-bottom: 0.4rem; + .flex { + padding: 0; + margin-top: 1rem; + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; } - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; - line{ - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - } - } - input:checked ~ .switch .circle{ - transform: translateY(-1.7rem); } } -#navbar{ +#main_header{ display: flex; + gap: 1rem; align-items: center; position: sticky; - padding: 1.5rem 2rem; - left: 0; - right: 0; - top: 0; - background: rgba(var(--foreground-color), 1); + padding: 1rem 1.5rem; + background: rgba(var(--background-color), 1); border-bottom: solid 1px rgba(var(--text-color), 0.16); - box-shadow: 0 0.2rem 0.6rem rgba(0, 0, 0, 0.06); - z-index: 3; + z-index: 2; } #logo{ display: grid; align-items: center; width: 100%; grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; + gap: 0 0.5rem; margin-right: 1rem; h4{ text-transform: capitalize; - font-size: 1.2rem; + font-size: 1rem; font-weight: 600; + margin-top: 0.2rem; } h5{ + font-size: 0.8rem; font-family: 'Roboto', sans-serif; font-weight: 400; } @@ -145,14 +293,19 @@ p{ } } .section{ + display: flex; + flex-direction: column; margin-top: 3rem; - h3 + p{ - margin-top: 1rem; - } + padding: 0 1.5rem; &:first-of-type{ margin-top: 0; } } +.section__header{ + display: flex; + padding: 1rem 0; + justify-content: space-between; +} .card{ padding: 1.5rem; display: flex; @@ -160,19 +313,15 @@ p{ min-width: 20rem; border-radius: 0.5rem; margin-right: 1.5rem; - border: solid 1px rgba(var(--text-color), 0.2); + background-color: rgba(var(--text-color), 0.06); h3{ font-weight: 500; } } -sm-menu{ - margin-left: auto; -} -@media only screen and (min-width: 640px){ - main{ - margin: 1.5rem 4vw; - } - p{ - max-width: 40rem; + +@media screen and (min-width: 640px) { + // for tablet and desktop + sm-popup{ + --width: 24rem; } } \ No newline at end of file diff --git a/Layouts/many sections layout/index.html b/Layouts/many sections layout/index.html index 42fb39a..584c09d 100644 --- a/Layouts/many sections layout/index.html +++ b/Layouts/many sections layout/index.html @@ -6,59 +6,66 @@ Document + + + - - -
+ + +
-
-

Section Heading

- - first option - second option - third option +
+
+

Section Heading

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +

+
+ + first option + second option + third option
-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

Card

@@ -87,17 +94,19 @@
-
-

Section Heading

- - first option - second option - third option +
+
+

Section Heading

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +

+
+ + first option + second option + third option
-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

Card

@@ -126,17 +135,19 @@
-
-

Section Heading

- - first option - second option - third option +
+
+

Section Heading

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +

+
+ + first option + second option + third option
-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

Card

@@ -164,23 +175,9 @@
-
- - - + + + \ No newline at end of file diff --git a/Layouts/many sections layout/js/components.js b/Layouts/many sections layout/js/components.js deleted file mode 100644 index 30d8c2f..0000000 --- a/Layouts/many sections layout/js/components.js +++ /dev/null @@ -1,2918 +0,0 @@ -//Button - -const smButton = document.createElement('template') -smButton.innerHTML = ` - -
- -
`; -customElements.define('sm-button', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smButton.content.cloneNode(true)) - } - static get observedAttributes() { - return ['disabled'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - dispatch = () => { - if (this.getAttribute('disabled') === 'true') { - this.dispatchEvent(new CustomEvent('disabled', { - bubbles: true, - composed: true - })) - } - else { - this.dispatchEvent(new CustomEvent('clicked', { - bubbles: true, - composed: true - })) - } - } - - connectedCallback() { - this.addEventListener('click', (e) => { - this.dispatch() - }) - this.addEventListener('keyup', (e) => { - if (e.code === "Enter" || e.code === "Space") - this.dispatch() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - - -
-`; -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 = () => { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; - if (this.input.value !== '') { - if (this.animate) - this.inputParent.classList.add('animate-label') - else - this.label.classList.add('hide') - this.clearBtn.classList.remove('hide') - } - else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - this.clearBtn.classList.add('hide') - } - if (this.valueChanged) { - if (this.input.checkValidity()) { - this.helperText.classList.add('hide') - this.inputParent.style.boxShadow = `` - } - else { - this.helperText.classList.remove('hide') - this.inputParent.style.boxShadow = `0 0 0 0.1rem ${this.computedStyle.getPropertyValue('--error-color')}` - } - } - } - - connectedCallback() { - this.inputParent = this.shadowRoot.querySelector('.input') - this.computedStyle = window.getComputedStyle(this.inputParent) - this.clearBtn = this.shadowRoot.querySelector('.clear') - this.label = this.shadowRoot.querySelector('.label') - this.helperText = this.shadowRoot.querySelector('.helper-text') - this.valueChanged = false; - this.animate = this.hasAttribute('animate') - this.input = this.shadowRoot.querySelector('input') - this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') - if (this.hasAttribute('value')) { - this.input.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('helper-text')) { - this.helperText.textContent = this.getAttribute('helper-text') - } - if (this.hasAttribute('type')) { - if (this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric') - } - else - this.input.setAttribute('type', this.getAttribute('type')) - } - else - this.input.setAttribute('type', 'text') - this.input.addEventListener('keydown', e => { - if (this.getAttribute('type') === 'number') - this.preventNonNumericalInput(e); - }) - this.input.addEventListener('input', e => { - this.checkInput() - }) - this.input.addEventListener('change', e => { - this.valueChanged = true; - if (this.input.checkValidity()) - this.helperText.classList.add('hide') - else - this.helperText.classList.remove('hide') - }) - this.clearBtn.addEventListener('click', e => { - this.input.value = '' - this.checkInput() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'placeholder') - this.shadowRoot.querySelector('.label').textContent = newValue; - } - } - }) - -// tab-header - -const smTabs = document.createElement('template') -smTabs.innerHTML = ` - -
-
- Nothing to see here -
-
-
- Nothing to see here -
-
-`; - -customElements.define('sm-tabs', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smTabs.content.cloneNode(true)) - this.indicator = this.shadowRoot.querySelector('.indicator'); - this.tabSlot = this.shadowRoot.querySelector('slot[name="tab"]'); - this.panelSlot = this.shadowRoot.querySelector('slot[name="panel"]'); - this.tabHeader = this.shadowRoot.querySelector('.tab-header'); - } - connectedCallback() { - - //animations - let flyInLeft = [ - { - opacity: 0, - transform: 'translateX(-1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyInRight = [ - { - opacity: 0, - transform: 'translateX(1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyOutLeft = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(-1rem)' - } - ], - flyOutRight = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(1rem)' - } - ], - animationOptions = { - duration: 300, - fill: 'forwards', - easing: 'ease' - } - this.prevTab - this.allTabs - - this.shadowRoot.querySelector('slot[name="panel"]').addEventListener('slotchange', () => { - this.shadowRoot.querySelector('slot[name="panel"]').assignedElements().forEach((panel, index) => { - panel.classList.add('hide-completely') - }) - }) - this.shadowRoot.querySelector('slot[name="tab"]').addEventListener('slotchange', () => { - this.allTabs = this.shadowRoot.querySelector('slot[name="tab"]').assignedElements(); - this.shadowRoot.querySelector('slot[name="tab"]').assignedElements().forEach((panel, index) => { - panel.setAttribute('rank', index + 1) - }) - }) - this._targetBodyFlyRight = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInRight, animationOptions) - } - this._targetBodyFlyLeft = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInLeft, animationOptions) - } - this.tabSlot.addEventListener('click', e => { - if (e.target === this.prevTab || !e.target.closest('sm-tab')) - return - if (this.prevTab) - this.prevTab.classList.remove('active') - e.target.classList.add('active') - - e.target.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) - this.indicator.setAttribute('style', `width: ${e.target.getBoundingClientRect().width}px; transform: translateX(${e.target.getBoundingClientRect().left - e.target.parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - - if (this.prevTab) { - let targetBody = e.target.nextElementSibling, - currentBody = this.prevTab.nextElementSibling; - - if (this.prevTab.getAttribute('rank') < e.target.getAttribute('rank')) { - if (currentBody && !targetBody) - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyRight(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyRight(targetBody) - } - } - } else { - if (currentBody && !targetBody) - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyLeft(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyLeft(targetBody) - } - } - } - } else { - e.target.nextElementSibling.classList.remove('hide-completely') - } - this.prevTab = e.target; - }) - let resizeObserver = new ResizeObserver(entries => { - entries.forEach((entry) => { - if (this.prevTab) { - let tabDimensions = this.prevTab.getBoundingClientRect(); - this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - }) - }) - resizeObserver.observe(this) - let observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - let activeElement = this.tabSlot.assignedElements().filter(element => { - if (element.classList.contains('active')) - return true - }) - if (activeElement.length) { - let tabDimensions = activeElement[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - activeElement[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - else { - this.tabSlot.assignedElements()[0].classList.add('active') - this.panelSlot.assignedElements()[0].classList.remove('hide-completely') - let tabDimensions = this.tabSlot.assignedElements()[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - this.prevTab = this.tabSlot.assignedElements()[0]; - } - } - }) - }, - { threshold: 1.0 }) - observer.observe(this) - if (this.hasAttribute('enable-flick') && this.getAttribute('enable-flick') == 'true') { - let touchStartTime = 0, - touchEndTime = 0, - swipeTimeThreshold = 200, - swipeDistanceThreshold = 20, - startingPointX = 0, - endingPointX = 0, - currentIndex = 0; - this.addEventListener('touchstart', e => { - touchStartTime = e.timeStamp - startingPointX = e.changedTouches[0].clientX - }) - this.panelSlot.addEventListener('touchend', e => { - touchEndTime = e.timeStamp - endingPointX = e.changedTouches[0].clientX - if (touchEndTime - touchStartTime < swipeTimeThreshold) { - currentIndex = this.allTabs.findIndex(element => element.classList.contains('active')) - if (startingPointX > endingPointX && startingPointX - endingPointX > swipeDistanceThreshold && currentIndex < this.allTabs.length) { - this.allTabs[currentIndex + 1].click() - } - else if (startingPointX < endingPointX && endingPointX - startingPointX > swipeDistanceThreshold && currentIndex > 0) { - this.allTabs[currentIndex - 1].click() - } - } - }) - } - } -}) - -// tab -const smTab = document.createElement('template') -smTab.innerHTML = ` - -
- -
-`; - -customElements.define('sm-tab', class extends HTMLElement { - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smTab.content.cloneNode(true)) - } -}) - -//chcekbox - -const smCheckbox = document.createElement('template') -smCheckbox.innerHTML = ` - -` -customElements.define('sm-checkbox', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smCheckbox.content.cloneNode(true)) - - this.checkbox = this.shadowRoot.querySelector('.checkbox'); - this.input = this.shadowRoot.querySelector('input') - - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.getAttribute('checked') - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.checkbox.classList.add('disabled') - this.isDisabled = true - } - else { - this.checkbox.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } - -}) - -//audio - -const smAudio = document.createElement('template') -smAudio.innerHTML = ` - -
- - play - - - - pause - - - -
/
- -
- -`; - -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') - } - } - } -}) - -//switch - -const smSwitch = document.createElement('template') -smSwitch.innerHTML = ` - -` - -customElements.define('sm-switch', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSwitch.content.cloneNode(true)) - this.switch = this.shadowRoot.querySelector('.switch'); - this.input = this.shadowRoot.querySelector('input') - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.isChecked - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.switch.classList.add('disabled') - this.isDisabled = true - } - else { - this.switch.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } -}) - -// select -const smSelect = document.createElement('template') -smSelect.innerHTML = ` - -
-
-
- - - -
-
- -
-
`; -customElements.define('sm-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - - collapse = () => { - this.optionList.animate(this.slideUp, this.animationOptions) - this.optionList.classList.add('hide') - this.chevron.classList.remove('rotate') - this.open = false - } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [ - { transform: `translateY(-0.5rem)` }, - { transform: `translateY(0)` } - ], - this.slideUp = [ - { transform: `translateY(0)` }, - { transform: `translateY(-0.5rem)` } - ], - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' - } - selection.addEventListener('click', e => { - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { - this.setAttribute('value', e.detail.value) - this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - if (previousOption) { - previousOption.classList.remove('check-selected') - } - previousOption = e.target; - } - if(!e.detail.switching) - this.collapse() - - e.target.classList.add('check-selected') - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); - document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { - this.collapse() - } - }) - } -}) - -// option -const smOption = document.createElement('template') -smOption.innerHTML = ` - -
- - - - -
`; -customElements.define('sm-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smOption.content.cloneNode(true)) - } - - sendDetails = (switching) => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value'), - switching: switching - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - let validKey = [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight' - ] - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - if (validKey.includes(e.code)) { - e.preventDefault() - this.sendDetails(true) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -// select -const smStripSelect = document.createElement('template') -smStripSelect.innerHTML = ` - -
-
- - Previous - - -
- -
- - Next - - -
-
`; -customElements.define('sm-strip-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - scrollLeft = () => { - this.select.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.select.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - connectedCallback() { - let previousOption, - slot = this.shadowRoot.querySelector('slot'); - this.selectContainer = this.shadowRoot.querySelector('.select-container') - this.select = this.shadowRoot.querySelector('.select') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.selectOptions - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.previousArrow.classList.add('hide') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.remove('hide') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.nextArrow.classList.add('hide') - this.nextGradient.classList.add('hide') - } - else { - this.nextArrow.classList.remove('hide') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - - const selectObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - } - }) - - selectObserver.observe(this.selectContainer) - this.addEventListener('optionSelected', e => { - if (previousOption === e.target) return; - if (previousOption) - previousOption.classList.remove('active') - e.target.classList.add('active') - e.target.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }) - this.setAttribute('value', e.detail.value) - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - previousOption = e.target; - }) - slot.addEventListener('slotchange', e => { - this.selectOptions = slot.assignedElements() - firstElementObserver.observe(this.selectOptions[0]) - lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) - if (this.selectOptions[0]) { - let firstElement = this.selectOptions[0]; - this.setAttribute('value', firstElement.getAttribute('value')) - firstElement.classList.add('active') - previousOption = firstElement; - } - }); - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -// option -const smStripOption = document.createElement('template') -smStripOption.innerHTML = ` - -
- -
`; -customElements.define('sm-strip-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripOption.content.cloneNode(true)) - } - sendDetails = () => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value') - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -//popup -const smPopup = document.createElement('template') -smPopup.innerHTML = ` - - -`; -customElements.define('sm-popup', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smPopup.content.cloneNode(true)) - } - - resumeScrolling = () => { - const scrollY = document.body.style.top; - window.scrollTo(0, parseInt(scrollY || '0') * -1); - setTimeout(() => { - document.body.setAttribute('style', `overflow: auto; top: initial`) - }, 300); - } - - show(pinned, popupStack) { - this.pinned = pinned - this.popupStack = popupStack - this.popupContainer.classList.remove('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(0)'; - else - this.popup.style.transform = 'scale(1)'; - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - } - hide() { - this.popupContainer.classList.add('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(100%)'; - else - this.popup.style.transform = 'scale(0.9)'; - if (typeof this.popupStack !== 'undefined') { - this.popupStack.pop() - if (this.popupStack.items.length === 0) { - this.resumeScrolling() - } - } - else { - this.resumeScrolling() - } - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartY < e.changedTouches[0].clientY) { - this.offset = e.changedTouches[0].clientY - this.touchStartY; - this.touchEndAnimataion = window.requestAnimationFrame(this.movePopup) - } - /*else { - offset = touchStartY - e.changedTouches[0].clientY; - this.popup.style.transform = `translateY(-${offset}px)` - }*/ - } - - handleTouchEnd = (e) => { - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.3s' - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndY - this.touchStartY > this.threshold) { - this.hide() - } - else { - this.show() - } - } - else { - if (this.touchEndY > this.touchStartY) - this.hide() - } - } - - movePopup = () => { - this.popup.style.transform = `translateY(${this.offset}px)` - } - - connectedCallback() { - this.pinned = false - this.popupStack - this.popupContainer = this.shadowRoot.querySelector('.popup-container') - this.popup = this.shadowRoot.querySelector('.popup') - this.offset - this.popupHeader = this.shadowRoot.querySelector('.popup-top') - this.touchStartY = 0 - this.touchEndY = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - this.touchEndAnimataion; - - if (this.hasAttribute('heading')) - this.shadowRoot.querySelector('.heading').textContent = this.getAttribute('heading') - - this.popupContainer.addEventListener('mousedown', e => { - if (e.target === this.popupContainer && !this.pinned) { - this.hide() - } - }) - - this.shadowRoot.querySelector('.close').addEventListener('click', e => { - this.hide() - }) - - this.popupHeader.addEventListener('touchstart', this.handleTouchStart) - this.popupHeader.addEventListener('touchmove', this.handleTouchMove) - this.popupHeader.addEventListener('touchend', this.handleTouchEnd) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd) - } -}) - -//carousel - -const smCarousel = document.createElement('template') -smCarousel.innerHTML = ` - - -`; - -customElements.define('sm-carousel', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smCarousel.content.cloneNode(true)) - } - - scrollLeft = () => { - this.carousel.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.carousel.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - - connectedCallback() { - this.carousel = this.shadowRoot.querySelector('.carousel') - this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') - this.carouselSlot = this.shadowRoot.querySelector('slot') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.carouselItems - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width/3 - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.previousArrow.classList.remove('expand') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.add('expand') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.nextArrow.classList.remove('expand') - this.nextGradient.classList.add('hide') - } - else{ - this.nextArrow.classList.add('expand') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - - const carouselObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 - } - }) - - carouselObserver.observe(this.carouselContainer) - - this.carouselSlot.addEventListener('slotchange', e => { - this.carouselItems = this.carouselSlot.assignedElements() - firstElementObserver.observe(this.carouselItems[0]) - lastElementObserver.observe(this.carouselItems[this.carouselItems.length - 1]) - }) - - this.addEventListener('keyup', e => { - if (e.code === 'ArrowLeft') - this.scrollRight() - else - this.scrollRight() - }) - - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -//notifications - -const smNotifications = document.createElement('template') -smNotifications.innerHTML = ` - -
-
-` - -customElements.define('sm-notifications', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smNotifications.content.cloneNode(true)) - } - - handleTouchStart = (e) => { - this.notification = e.target.closest('.notification') - this.touchStartX = e.changedTouches[0].clientX - this.notification.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartX < e.changedTouches[0].clientX) { - this.offset = e.changedTouches[0].clientX - this.touchStartX; - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - else { - this.offset = -(this.touchStartX - e.changedTouches[0].clientX); - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - } - - handleTouchEnd = (e) => { - this.notification.style.transition = 'height 0.3s, transform 0.3s, opacity 0.3s' - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndX = e.changedTouches[0].clientX - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndX - this.touchStartX > this.threshold) { - this.removeNotification(this.notification) - } - else if (this.touchStartX - this.touchEndX > this.threshold) { - this.removeNotification(this.notification, true) - } - else { - this.resetPosition() - } - } - else { - if (this.touchEndX > this.touchStartX) { - this.removeNotification(this.notification) - } - else { - this.removeNotification(this.notification, true) - } - } - } - - movePopup = () => { - this.notification.style.transform = `translateX(${this.offset}px)` - } - - resetPosition = () => { - this.notification.style.transform = `translateX(0)` - } - - push = (messageHeader, messageBody, options) => { - let notification = document.createElement('div'), - composition = ``, - { pinned, type } = options; - notification.classList.add('notification') - if (pinned) - notification.classList.add('pinned') - composition += ` -
-
- ` - if (type === 'error') { - composition += ` - - - - - ` - } - else if (type === 'success') { - composition += ` - - - - ` - } - composition += ` -

${messageHeader}

- - Close - - - -
-

${messageBody}

-
` - notification.innerHTML = composition - this.notificationPanel.prepend(notification) - if (window.innerWidth > 640) { - notification.animate([ - { - transform: `translateX(1rem)`, - opacity: '0' - }, - { - transform: 'translateX(0)', - opacity: '1' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `transform: none;`); - } - } - else { - notification.setAttribute('style', `transform: translateY(0); opacity: 1`) - } - notification.addEventListener('touchstart', this.handleTouchStart) - notification.addEventListener('touchmove', this.handleTouchMove) - notification.addEventListener('touchend', this.handleTouchEnd) - } - - removeNotification = (notification, toLeft) => { - notification.style.height = notification.scrollHeight + 'px'; - if (!this.offset) - this.offset = 0; - - if (toLeft) - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(-100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - else { - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - } - setTimeout( () => { - notification.remove() - }, this.animationOptions.duration*2) - } - - connectedCallback() { - this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: "ease" - } - this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) - this.notification - this.offset - this.touchStartX = 0 - this.touchEndX = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 - this.touchEndAnimataion; - - this.notificationPanel.addEventListener('click', e => { - if (e.target.closest('.close'))( - this.removeNotification(e.target.closest('.notification')) - ) - }) - - const observer = new MutationObserver(mutationList => { - mutationList.forEach(mutation => { - if (mutation.type === 'childList') { - if (mutation.addedNodes.length) { - if (!mutation.addedNodes[0].classList.contains('pinned')) - setTimeout(() => { - this.removeNotification(mutation.addedNodes[0]) - }, 4000); - if (window.innerWidth > 640) - this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; - else - this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; - } - else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { - this.notificationPanel.style.padding = 0; - } - } - }) - }) - observer.observe(this.notificationPanel, { - attributes: true, - childList: true, - subtree: true - }) - } -}) -// sm-menu -const smMenu = document.createElement('template') -smMenu.innerHTML = ` - -
- -
- -
-
`; -customElements.define('sm-menu', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenu.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - expand = () => { - if (!this.open) { - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - this.optionList.classList.remove('hide') - this.optionList.classList.add('no-transformations') - this.open = true - this.icon.classList.add('focused') - } - } - collapse = () => { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - } - } - connectedCallback() { - this.availableOptions - this.containerDimensions - this.optionList = this.shadowRoot.querySelector('.options') - let slot = this.shadowRoot.querySelector('.options slot'), - menu = this.shadowRoot.querySelector('.menu') - this.icon = this.shadowRoot.querySelector('.icon') - this.open = false; - menu.addEventListener('click', e => { - if (!this.open) { - this.expand() - } else { - this.collapse() - } - }) - menu.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - if (!this.open) { - this.expand() - } else { - this.collapse() - } - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.optionList.addEventListener('click', e => { - this.collapse() - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - this.containerDimensions = this.optionList.getBoundingClientRect() - this.menuDimensions = menu.getBoundingClientRect() - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - if (this.hasAttribute('set-context') && this.getAttribute('set-context') === 'true') { - this.parentNode.setAttribute('oncontextmenu', 'return false') - this.parentNode.addEventListener('mouseup', e => { - if (e.button === 2) { - this.expand() - } - }) - } - const intersectionObserver = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (!entry.isIntersecting && this.open) { - if(window.innerHeight - entry.intersectionRect.top < this.containerDimensions.height) - this.optionList.classList.add('moveUp') - else - this.optionList.classList.remove('moveUp') - if (entry.intersectionRect.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - } - }) - }, { - threshold: 1 - }) - intersectionObserver.observe(this.optionList) - } -}) - -// option -const smMenuOption = document.createElement('template') -smMenuOption.innerHTML = ` - -
- -
`; -customElements.define('sm-menu-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenuOption.content.cloneNode(true)) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.click() - } - }) - this.setAttribute('tabindex', '0') - } -}) \ No newline at end of file diff --git a/Layouts/many sections layout/js/components.min.js b/Layouts/many sections layout/js/components.min.js new file mode 100644 index 0000000..3ad756a --- /dev/null +++ b/Layouts/many sections layout/js/components.min.js @@ -0,0 +1,7 @@ +const smButton=document.createElement("template");smButton.innerHTML="\n\n
\n \n
",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}handleKeyDown(e){this.hasAttribute("disabled")||"Enter"!==e.key&&"Space"!==e.code||(e.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,n){"disabled"===e?(this.removeAttribute("tabindex"),this.setAttribute("aria-disabled","true")):(this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled","false"))}}); +const smCarousel=document.createElement("template");smCarousel.innerHTML='\n\n\n',customElements.define("sm-carousel",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCarousel.content.cloneNode(!0)),this.isAutoPlaying=!1,this.autoPlayInterval=5e3,this.autoPlayTimeout,this.initialTimeout,this.activeSlideNum=0,this.carouselItems,this.indicators,this.showIndicator=!1,this.carousel=this.shadowRoot.querySelector(".carousel"),this.carouselContainer=this.shadowRoot.querySelector(".carousel-container"),this.carouselSlot=this.shadowRoot.querySelector("slot"),this.navButtonRight=this.shadowRoot.querySelector(".carousel__button--right"),this.navButtonLeft=this.shadowRoot.querySelector(".carousel__button--left"),this.indicatorsContainer=this.shadowRoot.querySelector(".indicators"),this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.handleIndicatorClick=this.handleIndicatorClick.bind(this),this.showSlide=this.showSlide.bind(this),this.nextSlide=this.nextSlide.bind(this),this.autoPlay=this.autoPlay.bind(this),this.startAutoPlay=this.startAutoPlay.bind(this),this.stopAutoPlay=this.stopAutoPlay.bind(this)}static get observedAttributes(){return["indicator","autoplay","interval"]}scrollLeft(){this.carousel.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.carousel.scrollBy({left:this.scrollDistance,behavior:"smooth"})}showSlide(t){this.carousel.scrollTo({left:this.carouselItems[t].getBoundingClientRect().left-this.carousel.getBoundingClientRect().left+this.carousel.scrollLeft,behavior:"smooth"})}nextSlide(){if(!this.carouselItems)return;let t=this.activeSlideNum+1{this.autoPlay()},this.autoPlayInterval))}startAutoPlay(){this.setAttribute("autoplay","")}stopAutoPlay(){this.removeAttribute("autoplay")}createIndicator(t){let n=document.createElement("div");return n.classList.add("indicator"),n.dataset.rank=t,n}handleIndicatorClick(t){if(t.target.closest(".indicator")){const n=parseInt(t.target.closest(".indicator").dataset.rank);this.activeSlideNum!==n&&this.showSlide(n)}}handleKeyDown(t){"ArrowLeft"===t.code?this.scrollRight():"ArrowRight"===t.code&&this.scrollRight()}connectedCallback(){let t=document.createDocumentFragment();this.carouselSlot.addEventListener("slotchange",n=>{this.carouselItems=this.carouselSlot.assignedElements(),this.carouselItems.forEach(t=>i.observe(t)),this.carouselItems.length>0?(o.observe(this.carouselItems[0]),e.observe(this.carouselItems[this.carouselItems.length-1])):(navButtonLeft.classList.add("hide"),navButtonRight.classList.add("hide"),o.disconnect(),e.disconnect()),this.showIndicator&&(this.indicatorsContainer.innerHTML="",this.carouselItems.forEach((n,i)=>{t.append(this.createIndicator(i)),n.dataset.rank=i}),this.indicatorsContainer.append(t),this.indicators=this.indicatorsContainer.children)});const n={threshold:.9,root:this},i=new IntersectionObserver(t=>{t.forEach(t=>{if(this.showIndicator){const n=parseInt(t.target.dataset.rank);t.isIntersecting?(this.indicators[n].classList.add("active"),this.activeSlideNum=n):this.indicators[n].classList.remove("active")}})},n),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonLeft.classList.add("hide"):this.navButtonLeft.classList.remove("hide")})},n),e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonRight.classList.add("hide"):this.navButtonRight.classList.remove("hide")})},n),s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const n=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*n.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.addEventListener("keydown",this.handleKeyDown),this.navButtonRight.addEventListener("click",this.scrollRight),this.navButtonLeft.addEventListener("click",this.scrollLeft),this.indicatorsContainer.addEventListener("click",this.handleIndicatorClick)}attributeChangedCallback(t,n,i){n!==i&&("indicator"===t&&(this.showIndicator=this.hasAttribute("indicator")),"autoplay"===t&&(this.hasAttribute("autoplay")?this.initialTimeout=setTimeout(()=>{this.isAutoPlaying=!0,this.autoPlay()},this.autoPlayInterval):(this.isAutoPlaying=!1,clearTimeout(this.autoPlayTimeout),clearTimeout(this.initialTimeout))),"interval"===t&&(this.hasAttribute("interval")&&""!==this.getAttribute("interval").trim()?this.autoPlayInterval=Math.abs(parseInt(this.getAttribute("interval").trim())):this.autoPlayInterval=5e3))}disconnectedCallback(){this.navButtonRight.removeEventListener("click",this.scrollRight),this.navButtonLeft.removeEventListener("click",this.scrollLeft),this.indicatorsContainer.removeEventListener("click",this.handleIndicatorClick)}}); +const smInput=document.createElement("template");smInput.innerHTML='\n\n
\n \n \n
\n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),this.inputParent=this.shadowRoot.querySelector(".input"),this.input=this.shadowRoot.querySelector("input"),this.clearBtn=this.shadowRoot.querySelector(".clear"),this.label=this.shadowRoot.querySelector(".label"),this.feedbackText=this.shadowRoot.querySelector(".feedback-text"),this._helperText,this._errorText,this.isRequired=!1,this.validationFunction,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.focusOut=this.focusOut.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get isValid(){const t=this.input.checkValidity();let e=!0;return this.customValidation&&(e=this.validationFunction(this.input.value)),t&&e}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required")),this.isValid?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n \n ${this._errorText}\n `)),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):this.label.classList.remove("hide"))}connectedCallback(){this.animate=this.hasAttribute("animate"),this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.reset)}attributeChangedCallback(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.feedbackText.textContent="* required"):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); +const smMenu=document.createElement("template");smMenu.innerHTML='\n\n
\n \n
\n \n
\n
',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n
\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}}); +const smNotifications=document.createElement("template");smNotifications.innerHTML='\n\n
\n',customElements.define("sm-notifications",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smNotifications.content.cloneNode(!0)),this.notificationPanel=this.shadowRoot.querySelector(".notification-panel"),this.animationOptions={duration:300,fill:"forwards",easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)"},this.push=this.push.bind(this),this.createNotification=this.createNotification.bind(this),this.removeNotification=this.removeNotification.bind(this),this.clearAll=this.clearAll.bind(this)}randString(n){let t="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let o=0;o${o}
\n

${n}

\n `,i&&(e.classList.add("pinned"),a+='\n \n '),e.innerHTML=a,e}push(n,t={}){const i=this.createNotification(n,t);return this.notificationPanel.append(i),i.animate([{transform:"translateY(1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animationOptions),i.id}removeNotification(n){n.animate([{transform:"none",opacity:"1"},{transform:"translateY(0.5rem)",opacity:"0"}],this.animationOptions).onfinish=(()=>{n.remove()})}clearAll(){Array.from(this.notificationPanel.children).forEach(n=>{this.removeNotification(n)})}connectedCallback(){this.notificationPanel.addEventListener("click",n=>{n.target.closest(".close")&&this.removeNotification(n.target.closest(".notification"))});const n=new MutationObserver(n=>{n.forEach(n=>{"childList"===n.type&&n.addedNodes.length&&!n.addedNodes[0].classList.contains("pinned")&&setTimeout(()=>{this.removeNotification(n.addedNodes[0])},5e3)})});n.observe(this.notificationPanel,{childList:!0})}}); +const smPopup=document.createElement("template");smPopup.innerHTML='\n\n\n',customElements.define("sm-popup",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smPopup.content.cloneNode(!0)),this.allowClosing=!1,this.isOpen=!1,this.pinned=!1,this.popupStack,this.offset,this.touchStartY=0,this.touchEndY=0,this.touchStartTime=0,this.touchEndTime=0,this.touchEndAnimataion,this.popupContainer=this.shadowRoot.querySelector(".popup-container"),this.popup=this.shadowRoot.querySelector(".popup"),this.popupBodySlot=this.shadowRoot.querySelector(".popup-body slot"),this.popupHeader=this.shadowRoot.querySelector(".popup-top"),this.resumeScrolling=this.resumeScrolling.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.handleTouchStart=this.handleTouchStart.bind(this),this.handleTouchMove=this.handleTouchMove.bind(this),this.handleTouchEnd=this.handleTouchEnd.bind(this),this.movePopup=this.movePopup.bind(this)}static get observedAttributes(){return["open"]}get open(){return this.isOpen}resumeScrolling(){const t=document.body.style.top;window.scrollTo(0,-1*parseInt(t||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}show(t={}){const{pinned:e=!1,popupStack:n}=t;return n&&(this.popupStack=n),this.popupStack&&!this.hasAttribute("open")&&(this.popupStack.push({popup:this,permission:e}),this.popupStack.items.length>1&&this.popupStack.items[this.popupStack.items.length-2].popup.classList.add("stacked"),this.dispatchEvent(new CustomEvent("popupopened",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.setAttribute("open",""),this.pinned=e,this.isOpen=!0),this.popupContainer.classList.remove("hide"),this.popup.style.transform="none",document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.popupStack}hide(){window.innerWidth<640?this.popup.style.transform="translateY(100%)":this.popup.style.transform="translateY(3rem)",this.popupContainer.classList.add("hide"),this.removeAttribute("open"),void 0!==this.popupStack?(this.popupStack.pop(),this.popupStack.items.length?this.popupStack.items[this.popupStack.items.length-1].popup.classList.remove("stacked"):this.resumeScrolling()):this.resumeScrolling(),this.forms.length&&setTimeout(()=>{this.forms.forEach(t=>t.reset())},300),setTimeout(()=>{this.dispatchEvent(new CustomEvent("popupclosed",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.isOpen=!1},300)}handleTouchStart(t){this.touchStartY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.1s",this.touchStartTime=t.timeStamp}handleTouchMove(t){this.touchStartYthis.movePopup()))}handleTouchEnd(t){if(this.touchEndTime=t.timeStamp,cancelAnimationFrame(this.touchEndAnimataion),this.touchEndY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.3s",this.threshold=.3*this.popup.getBoundingClientRect().height,this.touchEndTime-this.touchStartTime>200)if(this.touchEndY-this.touchStartY>this.threshold){if(this.pinned)return void this.show();this.hide()}else this.show();else if(this.touchEndY>this.touchStartY){if(this.pinned)return void this.show();this.hide()}}movePopup(){this.popup.style.transform=`translateY(${this.offset}px)`}connectedCallback(){this.popupBodySlot.addEventListener("slotchange",()=>{this.forms=this.querySelectorAll("sm-form")}),this.popupContainer.addEventListener("mousedown",t=>{t.target!==this.popupContainer||this.pinned||(this.pinned?this.show():this.hide())});const t=new ResizeObserver(t=>{for(let e of t)if(e.contentBoxSize){Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.threshold=.3*e.blockSize.height}else this.threshold=.3*e.contentRect.height});t.observe(this),this.popupHeader.addEventListener("touchstart",t=>{this.handleTouchStart(t)},{passive:!0}),this.popupHeader.addEventListener("touchmove",t=>{this.handleTouchMove(t)},{passive:!0}),this.popupHeader.addEventListener("touchend",t=>{this.handleTouchEnd(t)},{passive:!0})}disconnectedCallback(){this.popupHeader.removeEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.popupHeader.removeEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.popupHeader.removeEventListener("touchend",this.handleTouchEnd,{passive:!0}),resizeObserver.unobserve()}attributeChangedCallback(t,e,n){"open"===t&&this.hasAttribute("open")&&this.show()}}); +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/Layouts/many sections layout/js/helper.js b/Layouts/many sections layout/js/helper.js deleted file mode 100644 index a7c51ee..0000000 --- a/Layouts/many sections layout/js/helper.js +++ /dev/null @@ -1,133 +0,0 @@ -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) -}) -let themeToggler = document.getElementById("theme_toggle") -if (localStorage.theme === "dark") { - darkTheme() - themeToggler.checked = true; -} else { - lightTheme() - themeToggler.checked = false; -} - -function lightTheme() { - document.body.setAttribute("data-theme", "light"); -} - -function darkTheme() { - document.body.setAttribute("data-theme", "dark"); -} -themeToggler.addEventListener("change", () => { - if (themeToggler.checked) { - darkTheme() - localStorage.setItem("theme", "dark"); - } else { - lightTheme() - 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(index) { - let newIndex = index ? index : 1 - return this.items[this.items.length - index]; - } -} -let popupStack = new Stack(), - zIndex = 10; -function showPopup(popup, permission) { - let thisPopup = document.getElementById(popup); - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - popupStack.push({ thisPopup, permission }) - thisPopup.show(permission, popupStack) - zIndex++; - thisPopup.setAttribute('style', `z-index: ${zIndex}`) - return thisPopup; -} -function setAttributes(el, attrs) { - for (var key in attrs) { - el.setAttribute(key, attrs[key]); - } -} -// displays a popup for asking permission. Use this instead of JS confirm -let confirmation = 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); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(false); - } - }) -} - -// 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'); - if (defaultVal) - input.value = defaultVal; - showPopup('prompt') - input.focus() - input.addEventListener('keyup', e => { - if (e.key === 'Enter') { - resolve(input.value); - hidePopup() - } - }) - popup.querySelector('#prompt_message').textContent = message; - popup.querySelector('.submit-btn').onclick = () => { - hidePopup() - resolve(input.value); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(null); - } - }) -} - -function formatedTime(time) { - let timeFrag = new Date(parseInt(time)).toString().split(' '), - day = timeFrag[0], - month = timeFrag[1], - date = timeFrag[2], - year = timeFrag[3], - hours = timeFrag[4].slice(0, timeFrag[4].lastIndexOf(':')), - finalTime = ''; - parseInt(hours.split(':')[0]) > 12 ? finalTime = 'PM' : finalTime = 'AM' - return `${hours} ${finalTime} ${day} ${date} ${month} ${year}` -} - -function copyToClipboard(parent) { - let toast = document.getElementById('textCopied'), - textToCopy = parent.querySelector('.copy').textContent; - navigator.clipboard.writeText(textToCopy) - toast.classList.remove('hide'); - setTimeout(() => { - toast.classList.add('hide'); - }, 2000) -} \ No newline at end of file diff --git a/Layouts/many sections layout/js/main_UI.js b/Layouts/many sections layout/js/main_UI.js new file mode 100644 index 0000000..b4d9afd --- /dev/null +++ b/Layouts/many sections layout/js/main_UI.js @@ -0,0 +1,282 @@ +// Global variables +const domRefs = {}; +const appPages = ['home'] + + +//Checks for internet connection status +if (!navigator.onLine) + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { sound: true } + ); +window.addEventListener("offline", () => { + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { pinned: true, sound: true } + ); +}); +window.addEventListener("online", () => { + getRef("notification_drawer").clearAll(); + notify("We are back online.", "success"); +}); + +// Use instead of document.getElementById +function getRef(elementId) { + if (!domRefs.hasOwnProperty(elementId)) { + domRefs[elementId] = { + count: 1, + ref: null, + }; + return document.getElementById(elementId); + } else { + if (domRefs[elementId].count < 3) { + domRefs[elementId].count = domRefs[elementId].count + 1; + return document.getElementById(elementId); + } else { + if (!domRefs[elementId].ref) + domRefs[elementId].ref = document.getElementById(elementId); + return domRefs[elementId].ref; + } + } +} + +// returns dom with specified element +function createElement(tagName, obj) { + const { className, textContent, innerHTML, attributes = {} } = obj + const elem = document.createElement(tagName) + for (let attribute in attributes) { + elem.setAttribute(attribute, attributes[attribute]) + } + if (className) + elem.className = className + if (textContent) + elem.textContent = textContent + if (innerHTML) + elem.innerHTML = innerHTML + return elem +} + +// Use when a function needs to be executed after user finishes changes +const debounce = (callback, wait) => { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; +} + +// Limits the rate of function execution +let timerId; +function throttle(func, delay) { + // If setTimeout is already scheduled, no need to do anything + if (timerId) { + return; + } + + // Schedule a setTimeout after delay seconds + timerId = setTimeout(function () { + func(); + + // Once setTimeout function execution is finished, timerId = undefined so that in + // the next scroll event function execution can be scheduled by the setTimeout + timerId = undefined; + }, delay); +} + +// 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; + +async function showPopup(popup, pinned) { + zIndex++ + getRef(popup).setAttribute('style', `z-index: ${zIndex}`) + popupStack = getRef(popup).show({ pinned, popupStack }) + return getRef(popup); +} + +// hides the popup or modal +function hidePopup() { + if (popupStack.peek() === undefined) + return; + popupStack.peek().popup.hide() +} + +// displays a popup for asking permission. Use this instead of JS confirm +let getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => { + return new Promise(resolve => { + showPopup('confirmation_popup', true) + getRef('confirm_title').textContent = title; + getRef('confirm_message').textContent = message; + let cancelButton = getRef('confirmation_popup').children[2].children[0], + submitButton = getRef('confirmation_popup').children[2].children[1] + submitButton.textContent = confirmText + cancelButton.textContent = cancelText + submitButton.onclick = () => { + hidePopup() + resolve(true); + } + cancelButton.onclick = () => { + hidePopup() + resolve(false); + } + }) +} + +// displays a popup for asking user input. Use this instead of JS prompt +async function getPromptInput(title, message = '', showText = true, trueBtn = "Ok", falseBtn = "Cancel") { + showPopup('prompt_popup', true) + getRef('prompt_title').textContent = title; + let input = getRef('prompt_input'); + input.setAttribute("placeholder", message) + let buttons = getRef('prompt_popup').querySelectorAll("sm-button"); + if (showText) + input.setAttribute("type", "text") + else + input.setAttribute("type", "password") + input.focusIn() + buttons[0].textContent = falseBtn; + buttons[1].textContent = trueBtn; + return new Promise((resolve, reject) => { + buttons[0].onclick = () => { + hidePopup() + return; + } + buttons[1].onclick = () => { + let value = input.value; + hidePopup() + resolve(value) + } + }) +} + +//Function for displaying toast notifications. pass in error for mode param if you want to show an error. +function notify(message, mode, options = {}) { + const { pinned = false, sound } = options + if (mode === "error") console.error(message); + let icon + switch (mode) { + case 'success': + icon = `` + break; + case 'error': + icon = `` + break; + } + getRef("notification_drawer").push(message, { pinned, icon }); + if (navigator.onLine && sound) { + getRef("notification_sound").currentTime = 0; + getRef("notification_sound").play(); + } +} + +const currentYear = new Date().getFullYear(); +function getFormatedTime(time, relative) { + try { + if (String(time).indexOf("_")) time = String(time).split("_")[0]; + const intTime = parseInt(time); + if (String(intTime).length < 13) time *= 1000; + let timeFrag = new Date(intTime).toString().split(" "), + day = timeFrag[0], + month = timeFrag[1], + date = timeFrag[2], + year = timeFrag[3], + minutes = new Date(intTime).getMinutes(), + hours = new Date(intTime).getHours(), + currentTime = new Date().toString().split(" "); + + minutes = minutes < 10 ? `0${minutes}` : minutes; + let finalHours = ``; + if (hours > 12) finalHours = `${hours - 12}:${minutes}`; + else if (hours === 0) finalHours = `12:${minutes}`; + else finalHours = `${hours}:${minutes}`; + + finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`; + if (relative) { + return `${date} ${month} ${year}`; + } else return `${finalHours} ${month} ${date} ${year}`; + } catch (e) { + console.error(e); + return time; + } +} + +window.addEventListener('hashchange', e => showPage(window.location.hash)) +window.addEventListener("load", () => { + document.body.classList.remove('hide-completely') + showPage(window.location.hash) + // document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = validateAddr) + document.addEventListener('keyup', (e) => { + if (e.code === 'Escape') { + hidePopup() + } + }) + document.addEventListener("pointerdown", (e) => { + if (e.target.closest("button, sm-button:not([disabled]), .interact")) { + createRipple(e, e.target.closest("button, sm-button, .interact")); + } + }); + document.addEventListener('copy', () => { + notify('copied', 'success') + }) +}); + +function createRipple(event, target) { + const circle = document.createElement("span"); + const diameter = Math.max(target.clientWidth, target.clientHeight); + const radius = diameter / 2; + const targetDimensions = target.getBoundingClientRect(); + circle.style.width = circle.style.height = `${diameter}px`; + circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`; + circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`; + circle.classList.add("ripple"); + const rippleAnimation = circle.animate( + [ + { + transform: "scale(3)", + opacity: 0, + }, + ], + { + duration: 1000, + fill: "forwards", + easing: "ease-out", + } + ); + target.append(circle); + rippleAnimation.onfinish = () => { + circle.remove(); + }; +} + +function showPage(targetPage) { + let pageId + if (targetPage === '') { + pageId = 'overview_page' + } + else { + pageId = targetPage.includes('#') ? targetPage.split('#')[1] : targetPage + } + if(!appPages.includes(pageId)) return + document.querySelector('.page:not(.hide-completely)').classList.add('hide-completely') + getRef(pageId).classList.remove('hide-completely') +} \ No newline at end of file diff --git a/Layouts/sidebar layout/css/main.css b/Layouts/sidebar layout/css/main.css index 97dd133..139aad2 100644 --- a/Layouts/sidebar layout/css/main.css +++ b/Layouts/sidebar layout/css/main.css @@ -1,61 +1,88 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap"); * { - -webkit-box-sizing: border-box; - box-sizing: border-box; padding: 0; margin: 0; - font-family: 'Roboto', sans-serif; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } :root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, body { + height: 100%; scroll-behavior: smooth; } body { - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; } -body[data-theme="dark"] { - --accent-color: #4a5cd3; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; -} - -h1, h2, h3, h4, h5 { - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} - -h1 { - font-size: 3rem; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -h4 { - font-size: 1rem; -} - -h5 { - font-size: 0.8rem; +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); } p { - margin: 1.5rem 0; + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); } +p:not(:last-of-type) { + margin-bottom: 1rem; +} + +img { + object-fit: cover; +} + +a { + color: inherit; + text-decoration: none; +} +a:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +button { + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} .hide { opacity: 0; @@ -67,110 +94,264 @@ p { } .no-transformations { - -webkit-transform: none !important; - transform: none !important; + transform: none !important; } -.icon { - height: 1.2rem; - width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; +.overflow-ellipsis { + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -#navbar { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - position: fixed; - left: 0; - bottom: 0; - top: 0; - -webkit-box-shadow: 0.2rem 0 0.5rem rgba(0, 0, 0, 0.1); - box-shadow: 0.2rem 0 0.5rem rgba(0, 0, 0, 0.1); - z-index: 3; - padding: 1rem 0; - background: rgba(var(--foreground-color), 1); - border-right: solid 1px rgba(var(--text-color), 0.16); - -webkit-transform: translateX(-100%); - transform: translateX(-100%); - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; } -#navbar .navbar-item { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - position: relative; - text-align: center; - cursor: pointer; - padding: 0.6rem 1.5rem; - padding-right: 3rem; - border-radius: 0.4em; - color: rgba(var(--text-color), 0.8); - font-size: 0.9em; +.full-bleed { + grid-column: 1/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { text-transform: uppercase; - width: 100%; - -webkit-tap-highlight-color: transparent; } -#navbar .navbar-item .icon { - margin-right: 1rem; -} - -#navbar .navbar-item h4 { +.capitalize { text-transform: capitalize; - font-weight: 600; } -#navbar .active { - color: var(--accent-color); +.flex { + display: flex; } -#navbar .active .icon { - stroke: var(--accent-color); -} - -#logo { - display: -ms-grid; +.grid { display: grid; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { width: 100%; - -ms-grid-columns: auto 1fr; - grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; - margin-right: 1rem; - padding: 0.6rem 2rem; - margin-bottom: 1rem; } -#logo h4 { - text-transform: capitalize; - font-size: 1.2rem; - font-weight: 600; +.color-0-8 { + color: rgba(var(--text-color), 0.8); } -#logo h5 { - font-family: 'Roboto', sans-serif; +.weight-400 { font-weight: 400; } +.weight-500 { + font-weight: 500; +} + +.ripple { + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} + +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.observe-empty-state:empty { + display: none; +} + +.observe-empty-state:not(:empty) ~ .empty-state { + display: none; +} + +.icon { + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; +} +#confirmation_popup h4, +#prompt_popup h4 { + font-weight: 500; + margin-bottom: 0.5rem; +} +#confirmation_popup sm-button, +#prompt_popup sm-button { + margin: 0; +} +#confirmation_popup .flex, +#prompt_popup .flex { + padding: 0; + margin-top: 1rem; +} +#confirmation_popup .flex sm-button:first-of-type, +#prompt_popup .flex sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; +} + +h1, h2, h3, h4.h5 { + font-family: "Poppins", sans-serif; +} + +h2 { + margin: 3rem 0 1rem 0; + text-transform: capitalize; +} + +main { + display: grid; + height: 100%; +} + +#main_header { + padding: 0.5rem 1.5rem; + border-bottom: 1px solid rgba(var(--text-color), 0.1); +} + +#side_nav_button { + padding: 0.5rem; + margin-left: -0.5rem; +} + +#logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.5rem; + margin-right: 1rem; +} +#logo h4 { + text-transform: capitalize; + font-size: 1rem; + font-weight: 600; +} #logo #main_logo { height: 1.4rem; width: 1.4rem; @@ -178,172 +359,118 @@ p { stroke: none; } -.toggle { - margin-top: auto; - position: relative; - cursor: pointer; - padding: 0; -} - -.toggle input[type='checkbox'] { - display: none; -} - -.toggle .switch { - overflow: hidden; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; - margin-right: 1rem; -} - -.toggle .circle { - border-radius: 0.5rem; - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; -} - -.toggle .circle:first-of-type { - margin-bottom: 0.4rem; -} - -.toggle .circle line { - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; -} - -.toggle input:checked ~ .switch .circle { - -webkit-transform: translateY(-1.7rem); - transform: translateY(-1.7rem); -} - -.page { - padding: 2rem 1.5rem; +.right { max-height: 100%; overflow-y: auto; } -.options-tab { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - margin-top: 1rem; - margin-bottom: 1rem; - -ms-flex-wrap: wrap; - flex-wrap: wrap; +#side_nav > :last-child { + padding-bottom: 3rem; } - -.options-tab .option { - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - border-radius: 0.4rem; - padding: 1.5rem; - margin-right: 1rem; - margin-bottom: 1rem; - width: 9rem; - border: solid 1px rgba(var(--text-color), 0.2); - text-transform: capitalize; - cursor: pointer; - -webkit-tap-highlight-color: transparent; -} - -.options-tab .option .icon { - background: rgba(var(--text-color), 0.1); - height: 2.8rem; - width: 2.8rem; - padding: 0.8rem; - border-radius: 2rem; - margin-bottom: 1rem; - stroke: rgba(var(--text-color), 0.4); -} - -.options-tab .option h4 { - font-weight: 400; +#side_nav h4 { font-size: 0.9rem; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 1.5rem; } -#home_page h1 { - font-weight: 600; +.right { + padding: 1.5rem; +} +.right h1 { + margin-bottom: 1.5rem; } -#home_page p { - margin-bottom: 3rem; +.page { + display: flex; + flex-direction: column; + padding-bottom: 3rem; } -#home_page h2 { - margin-bottom: 1rem; +.list { + list-style: none; + display: flex; + flex-direction: column; + margin-bottom: 0.8rem; +} + +.list__item { + display: flex; + padding: 0.8rem 1.5rem; + text-transform: capitalize; +} +.list__item--active { + color: var(--accent-color); + background: rgba(var(--text-color), 0.06); } @media screen and (max-width: 640px) { - #main_header { - position: -webkit-sticky; - position: sticky; - top: 0; - padding: 1.5rem; - } - #main_header .icon { - stroke-width: 12; - height: 3rem; - width: 3rem; - background: rgba(var(--foreground-color), 1); - border-radius: 2rem; - padding: 1rem; - -webkit-box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.16), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.16); - box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.16), 0 0.4rem 0.8rem rgba(0, 0, 0, 0.16); + main { + grid-template-rows: auto 1fr; + grid-template-columns: 1fr; } } +@media screen and (min-width: 640px) { + sm-popup { + --width: 32rem; + } -@media only screen and (min-width: 640px) { - main { - display: -ms-grid; - display: grid; - -ms-grid-columns: auto 1fr; - grid-template-columns: auto 1fr; - gap: 2rem; - height: 100vh; - overflow-y: auto; - } - p { - max-width: 40rem; - } - #navbar { - position: relative; - -webkit-transform: none; - transform: none; - height: 100%; - } #main_header { + padding: 1rem 1.5rem; + grid-area: main-header; + } + + #side_nav_button { display: none; } -} -@media (hover: hover) { - .navbar-item:hover { - background: rgba(var(--text-color), 0.1); + main { + grid-template-columns: 14rem minmax(0, 1fr); + grid-template-rows: auto 1fr; + grid-template-areas: "main-header main-header" ". ."; + } + + .right { + display: grid; + grid-template-columns: 1fr 90% 1fr; + } + .right > * { + grid-column: 2/3; + } + + .page__title { + font-size: 2.5rem; + } + + #overview_page { + display: grid; + gap: 1.5rem; + grid-template-columns: 1fr auto; + } + #overview_page > div:first-of-type { + grid-column: 2/3; + text-align: right; + } + #overview_page > div:nth-of-type(2) { + grid-row: 1/2; } } -/*# sourceMappingURL=main.css.map */ \ No newline at end of file +@media (any-hover: hover) { + ::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; + } + + ::-webkit-scrollbar-thumb { + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + } + ::-webkit-scrollbar-thumb:hover { + background: rgba(var(--text-color), 0.5); + } + + .list__item:hover { + background: rgba(var(--text-color), 0.1); + cursor: pointer; + } +} \ No newline at end of file diff --git a/Layouts/sidebar layout/css/main.min.css b/Layouts/sidebar layout/css/main.min.css new file mode 100644 index 0000000..6fb53cf --- /dev/null +++ b/Layouts/sidebar layout/css/main.min.css @@ -0,0 +1 @@ +.hide,.ripple{pointer-events:none}.list,ul{list-style:none}*{padding:0;margin:0;box-sizing:border-box;font-family:Roboto,sans-serif}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;max-width:65ch;line-height:1.7;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}.hide{opacity:0}.hide-completely{display:none!important}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}#logo h4,.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}#logo h4,.capitalize,h2{text-transform:capitalize}.flex{display:flex}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.direction-column{flex-direction:column}.space-between{justify-content:space-between}#confirmation_popup,#prompt_popup,.page{flex-direction:column}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16)}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}#logo,main{display:grid}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}h1,h2,h3,h4.h5{font-family:Poppins,sans-serif}h2{margin:3rem 0 1rem}main{height:100%}#main_header{padding:.5rem 1.5rem;border-bottom:1px solid rgba(var(--text-color),.1)}#side_nav_button{padding:.5rem;margin-left:-.5rem}#logo{align-items:center;width:100%;grid-template-columns:auto 1fr;gap:0 .5rem;margin-right:1rem}.list,.list__item,.page{display:flex}#logo h4{font-weight:600}#logo #main_logo{height:1.4rem;width:1.4rem;fill:rgba(var(--text-color),1);stroke:none}#side_nav>:last-child{padding-bottom:3rem}#side_nav h4{font-size:.9rem;letter-spacing:.08em;text-transform:uppercase;padding:1.5rem}.right{max-height:100%;overflow-y:auto;padding:1.5rem}.right h1{margin-bottom:1.5rem}.page{padding-bottom:3rem}.list{flex-direction:column;margin-bottom:.8rem}.list__item{padding:.8rem 1.5rem;text-transform:capitalize}.list__item--active{color:var(--accent-color);background:rgba(var(--text-color),.06)}@media screen and (max-width:640px){main{grid-template-rows:auto 1fr;grid-template-columns:1fr}}@media screen and (min-width:640px){sm-popup{--width:32rem}#main_header{padding:1rem 1.5rem;grid-area:main-header}#side_nav_button{display:none}main{grid-template-columns:14rem minmax(0,1fr);grid-template-rows:auto 1fr;grid-template-areas:"main-header main-header" ". ."}.right{display:grid;grid-template-columns:1fr 90% 1fr}.right>*{grid-column:2/3}.page__title{font-size:2.5rem}#overview_page{display:grid;gap:1.5rem;grid-template-columns:1fr auto}#overview_page>div:first-of-type{grid-column:2/3;text-align:right}#overview_page>div:nth-of-type(2){grid-row:1/2}}@media (any-hover:hover){::-webkit-scrollbar{width:.5rem;height:.5rem}::-webkit-scrollbar-thumb{background:rgba(var(--text-color),.3);border-radius:1rem}::-webkit-scrollbar-thumb:hover{background:rgba(var(--text-color),.5)}.list__item:hover{background:rgba(var(--text-color),.1);cursor:pointer}} \ No newline at end of file diff --git a/Layouts/sidebar layout/css/main.scss b/Layouts/sidebar layout/css/main.scss index 83dc1d2..7951a50 100644 --- a/Layouts/sidebar layout/css/main.scss +++ b/Layouts/sidebar layout/css/main.scss @@ -1,49 +1,79 @@ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap'); *{ - box-sizing: border-box; padding: 0; margin: 0; + box-sizing: border-box; font-family: 'Roboto', sans-serif; } :root{ + font-size: clamp(1rem, 1.2vmax, 3rem); +} +html, body{ + height: 100%; scroll-behavior: smooth; } -body{ - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); +body { + &, + *{ + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; + } color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); } -body[data-theme="dark"]{ - --accent-color: #4a5cd3; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; +body[data-theme='dark']{ + &, + *{ + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); + } } -h1, h2, h3, h4, h5{ - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} -h1{ - font-size: 3rem; -} -h2{ - font-size: 2rem; -} -h3{ - font-size: 1.5rem; -} -h4{ - font-size: 1rem; -} -h5{ - font-size: 0.8rem; -} -p{ - margin: 1.5rem 0; +p { + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); + &:not(:last-of-type){ + margin-bottom: 1rem; + } +} +img{ + object-fit: cover; +} + +a{ + color: inherit; + text-decoration: none; + &:focus-visible{ + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} + +button{ + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible{ + outline: rgba(var(--text-color), 1) 0.1rem solid; +} +sm-button{ + --border-radius: 0.3rem; +} +ul{ + list-style: none; +} +.flex{ + display: flex; +} +.grid{ + display: grid; } .hide{ opacity: 0; @@ -55,77 +85,209 @@ p{ .no-transformations{ transform: none !important; } +.overflow-ellipsis{ + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.breakable{ + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +.full-bleed{ + grid-column: 1/4; +} +.h1{ + font-size: 2.5rem; +} +.h2{ + font-size: 2rem; +} +.h3{ + font-size: 1.4rem; +} +.h4{ + font-size: 1rem; +} +.h5{ + font-size: 0.8rem; +} + +.uppercase{ + text-transform: uppercase; +} +.capitalize{ + text-transform: capitalize; +} +.flex{ + display: flex; +} +.grid{ + display: grid; +} +.grid-3{ + grid-template-columns: 1fr auto auto; +} +.flow-column{ + grid-auto-flow: column; +} +.gap-0-5{ + gap: 0.5rem; +} +.gap-1{ + gap: 1rem; +} +.gap-1-5{ + gap: 1.5rem; +} +.gap-2{ + gap: 2rem; +} +.gap-3{ + gap: 3rem; +} +.text-align-right{ + text-align: right; +} +.align-start{ + align-items: flex-start; +} +.align-center{ + align-items: center; +} +.text-center{ + text-align: center; +} +.justify-start{ + justify-content: start; +} +.justify-center{ + justify-content: center; +} +.justify-right{ + margin-left: auto; +} +.align-self-center{ + align-self: center; +} +.justify-self-center{ + justify-self: center; +} +.justify-self-start{ + justify-self: start; +} +.justify-self-end{ + justify-self: end; +} +.direction-column{ + flex-direction: column; +} +.space-between{ + justify-content: space-between; +} +.w-100{ + width: 100%; +} +.color-0-8{ + color: rgba(var(--text-color), 0.8); +} +.weight-400{ + font-weight: 400; +} +.weight-500{ + font-weight: 500; +} +.ripple{ + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} +.interact{ + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.observe-empty-state:empty{ + display: none; +} +.observe-empty-state:not(:empty) ~ .empty-state{ + display: none; +} .icon{ + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} +.button__icon{ height: 1.2rem; width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; + &--left{ + margin-right: 0.5rem; + } + &--right{ + margin-left: 0.5rem; + } } -#navbar{ - display: flex; +#confirmation_popup, +#prompt_popup { flex-direction: column; - align-items: center; - position: fixed; - left: 0; - bottom: 0; - top: 0; - box-shadow: 0.2rem 0 0.5rem rgba(0, 0, 0, 0.1); - z-index: 3; - padding: 1rem 0; - background: rgba(var(--foreground-color), 1); - border-right: solid 1px rgba(var(--text-color), 0.16); - transform: translateX(-100%); - transition: transform 0.3s; - .navbar-item{ - display: flex; - position: relative; - text-align: center; - cursor: pointer; - padding: 0.6rem 1.5rem; - padding-right: 3rem; - border-radius: 0.4em; - color: rgba(var(--text-color), 0.8); - font-size: 0.9em; - text-transform: uppercase; - width: 100%; - -webkit-tap-highlight-color: transparent; - .icon{ - margin-right: 1rem; - } - h4{ - text-transform: capitalize; - font-weight: 600; - } - } - .active{ - color: var(--accent-color); - .icon{ - stroke: var(--accent-color); + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + sm-button{ + margin: 0; + } + .flex { + padding: 0; + margin-top: 1rem; + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; } } } +h1,h2,h3,h4.h5{ + font-family: 'Poppins', sans-serif; +} +h2{ + margin: 3rem 0 1rem 0; + text-transform: capitalize; +} +main{ + display: grid; + height: 100%; +} +#main_header{ + padding: 0.5rem 1.5rem; + border-bottom: 1px solid rgba(var(--text-color), .1); +} +#side_nav_button{ + padding: 0.5rem; + margin-left: -0.5rem; +} #logo{ display: grid; align-items: center; width: 100%; grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; + gap: 0 0.5rem; margin-right: 1rem; - padding: 0.6rem 2rem; - margin-bottom: 1rem; h4{ text-transform: capitalize; - font-size: 1.2rem; + font-size: 1rem; font-weight: 600; } - h5{ - font-family: 'Roboto', sans-serif; - font-weight: 400; - } #main_logo{ height: 1.4rem; width: 1.4rem; @@ -133,135 +295,107 @@ p{ stroke: none; } } -.toggle{ - margin-top: auto; - position: relative; - cursor: pointer; - padding: 0; - input[type='checkbox']{ - display: none; - } - .switch{ - overflow: hidden; - display: inline-flex; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; - margin-right: 1rem; - } - .circle{ - border-radius: 0.5rem; - transition: transform 0.3s; - &:first-of-type{ - margin-bottom: 0.4rem; - } - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; - line{ - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - } - } - input:checked ~ .switch .circle{ - transform: translateY(-1.7rem); - } -} -.page{ - padding: 2rem 1.5rem; +.right{ max-height: 100%; overflow-y: auto; } -.options-tab{ - display: flex; - margin-top: 1rem; - margin-bottom: 1rem; - flex-wrap: wrap; - .option{ - display: inline-flex; - flex-direction: column; - border-radius: 0.4rem; +#side_nav{ + & > :last-child{ + padding-bottom: 3rem; + } + h4{ + font-size: 0.9rem; + letter-spacing: 0.08em; + text-transform: uppercase; padding: 1.5rem; - margin-right: 1rem; - margin-bottom: 1rem; - width: 9rem; - border: solid 1px rgba(var(--text-color), 0.2); - text-transform: capitalize; - cursor: pointer; - -webkit-tap-highlight-color: transparent; - .icon{ - background: rgba(var(--text-color), 0.1); - height: 2.8rem; - width: 2.8rem; - padding: 0.8rem; - border-radius: 2rem; - margin-bottom: 1rem; - stroke: rgba(var(--text-color), 0.4); - } - h4{ - font-weight: 400; - font-size: 0.9rem; - } } } -#home_page{ +.right{ + padding: 1.5rem; h1{ - font-weight: 600; + margin-bottom: 1.5rem; } - p{ - margin-bottom: 3rem; - } - h2{ - margin-bottom: 1rem; +} +.page{ + display: flex; + flex-direction: column; + padding-bottom: 3rem; +} +.list{ + list-style: none; + display: flex; + flex-direction: column; + margin-bottom: 0.8rem; +} +.list__item{ + display: flex; + padding: 0.8rem 1.5rem; + text-transform: capitalize; + &--active{ + color: var(--accent-color); + background: rgba(var(--text-color), .06); } } @media screen and (max-width: 640px){ + main{ + grid-template-rows: auto 1fr; + grid-template-columns: 1fr; + } +} +@media screen and (min-width: 640px){ + sm-popup{ + --width: 32rem; + } #main_header{ - position: sticky; - top: 0; - padding: 1.5rem; - .icon{ - stroke-width: 12; - height: 3rem; - width: 3rem; - background: rgba(var(--foreground-color), 1); - border-radius: 2rem; - padding: 1rem; - box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.16), - 0 0.4rem 0.8rem rgba(0, 0, 0, 0.16); + padding: 1rem 1.5rem; + grid-area: main-header; + } + #side_nav_button{ + display: none; + } + main{ + grid-template-columns: 14rem minmax(0, 1fr); + grid-template-rows: auto 1fr; + grid-template-areas: 'main-header main-header' '. .'; + } + .right{ + display: grid; + grid-template-columns: 1fr 90% 1fr; + & > * { + grid-column: 2/3; + } + } + .page__title{ + font-size: 2.5rem; + } + #overview_page{ + display: grid; + gap: 1.5rem; + grid-template-columns: 1fr auto; + & > div:first-of-type{ + grid-column: 2/3; + text-align: right; + } + & > div:nth-of-type(2){ + grid-row: 1/2; } } } -@media only screen and (min-width: 640px){ - main{ - display: grid; - grid-template-columns: auto 1fr; - gap: 2rem; - height: 100vh; - overflow-y: auto; +@media (any-hover: hover){ + ::-webkit-scrollbar{ + width: 0.5rem; + height: 0.5rem; } - p{ - max-width: 40rem; + + ::-webkit-scrollbar-thumb{ + background: rgba(var(--text-color), 0.3); + border-radius: 1rem; + &:hover{ + background: rgba(var(--text-color), 0.5); + } } - #navbar{ - position: relative; - transform: none; - height: 100%; - } - #main_header{ - display: none; - } -} -@media (hover: hover){ - .navbar-item:hover{ - background: rgba(var(--text-color), 0.1); + .list__item:hover{ + background: rgba(var(--text-color), .1); + cursor: pointer; } } \ No newline at end of file diff --git a/Layouts/sidebar layout/index.html b/Layouts/sidebar layout/index.html index 3e0df48..27ca152 100644 --- a/Layouts/sidebar layout/index.html +++ b/Layouts/sidebar layout/index.html @@ -6,149 +6,83 @@ Document + + + - + + + + +

+

+
+ Cancel + OK +
+
+ +

+

+ +
+ Cancel + OK +
+
- -
- - menu - - - +
-
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi excepturi eius voluptate quod quasi - dolore, quisquam, voluptatem repellendus sapiente consectetur similique ducimus dicta magni harum, -

-

Options

+ + + +
+
+

Dashboard

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Esse, sint. Aperiam ipsum expedita tenetur quasi, repellat ea. Laboriosam, earum ratione!

+
-
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
-
- - transfer - - -

Option

-
-
-
-
-

User Settings

-
+
+

Settings

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Excepturi nihil distinctio dolore molestias ullam architecto ipsam qui possimus aliquam. Odio.

+
+
- - - + + \ No newline at end of file diff --git a/Layouts/sidebar layout/js/components.js b/Layouts/sidebar layout/js/components.js deleted file mode 100644 index 30d8c2f..0000000 --- a/Layouts/sidebar layout/js/components.js +++ /dev/null @@ -1,2918 +0,0 @@ -//Button - -const smButton = document.createElement('template') -smButton.innerHTML = ` - -
- -
`; -customElements.define('sm-button', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smButton.content.cloneNode(true)) - } - static get observedAttributes() { - return ['disabled'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - dispatch = () => { - if (this.getAttribute('disabled') === 'true') { - this.dispatchEvent(new CustomEvent('disabled', { - bubbles: true, - composed: true - })) - } - else { - this.dispatchEvent(new CustomEvent('clicked', { - bubbles: true, - composed: true - })) - } - } - - connectedCallback() { - this.addEventListener('click', (e) => { - this.dispatch() - }) - this.addEventListener('keyup', (e) => { - if (e.code === "Enter" || e.code === "Space") - this.dispatch() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - - -
-`; -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 = () => { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; - if (this.input.value !== '') { - if (this.animate) - this.inputParent.classList.add('animate-label') - else - this.label.classList.add('hide') - this.clearBtn.classList.remove('hide') - } - else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - this.clearBtn.classList.add('hide') - } - if (this.valueChanged) { - if (this.input.checkValidity()) { - this.helperText.classList.add('hide') - this.inputParent.style.boxShadow = `` - } - else { - this.helperText.classList.remove('hide') - this.inputParent.style.boxShadow = `0 0 0 0.1rem ${this.computedStyle.getPropertyValue('--error-color')}` - } - } - } - - connectedCallback() { - this.inputParent = this.shadowRoot.querySelector('.input') - this.computedStyle = window.getComputedStyle(this.inputParent) - this.clearBtn = this.shadowRoot.querySelector('.clear') - this.label = this.shadowRoot.querySelector('.label') - this.helperText = this.shadowRoot.querySelector('.helper-text') - this.valueChanged = false; - this.animate = this.hasAttribute('animate') - this.input = this.shadowRoot.querySelector('input') - this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') - if (this.hasAttribute('value')) { - this.input.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('helper-text')) { - this.helperText.textContent = this.getAttribute('helper-text') - } - if (this.hasAttribute('type')) { - if (this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric') - } - else - this.input.setAttribute('type', this.getAttribute('type')) - } - else - this.input.setAttribute('type', 'text') - this.input.addEventListener('keydown', e => { - if (this.getAttribute('type') === 'number') - this.preventNonNumericalInput(e); - }) - this.input.addEventListener('input', e => { - this.checkInput() - }) - this.input.addEventListener('change', e => { - this.valueChanged = true; - if (this.input.checkValidity()) - this.helperText.classList.add('hide') - else - this.helperText.classList.remove('hide') - }) - this.clearBtn.addEventListener('click', e => { - this.input.value = '' - this.checkInput() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'placeholder') - this.shadowRoot.querySelector('.label').textContent = newValue; - } - } - }) - -// tab-header - -const smTabs = document.createElement('template') -smTabs.innerHTML = ` - -
-
- Nothing to see here -
-
-
- Nothing to see here -
-
-`; - -customElements.define('sm-tabs', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smTabs.content.cloneNode(true)) - this.indicator = this.shadowRoot.querySelector('.indicator'); - this.tabSlot = this.shadowRoot.querySelector('slot[name="tab"]'); - this.panelSlot = this.shadowRoot.querySelector('slot[name="panel"]'); - this.tabHeader = this.shadowRoot.querySelector('.tab-header'); - } - connectedCallback() { - - //animations - let flyInLeft = [ - { - opacity: 0, - transform: 'translateX(-1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyInRight = [ - { - opacity: 0, - transform: 'translateX(1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyOutLeft = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(-1rem)' - } - ], - flyOutRight = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(1rem)' - } - ], - animationOptions = { - duration: 300, - fill: 'forwards', - easing: 'ease' - } - this.prevTab - this.allTabs - - this.shadowRoot.querySelector('slot[name="panel"]').addEventListener('slotchange', () => { - this.shadowRoot.querySelector('slot[name="panel"]').assignedElements().forEach((panel, index) => { - panel.classList.add('hide-completely') - }) - }) - this.shadowRoot.querySelector('slot[name="tab"]').addEventListener('slotchange', () => { - this.allTabs = this.shadowRoot.querySelector('slot[name="tab"]').assignedElements(); - this.shadowRoot.querySelector('slot[name="tab"]').assignedElements().forEach((panel, index) => { - panel.setAttribute('rank', index + 1) - }) - }) - this._targetBodyFlyRight = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInRight, animationOptions) - } - this._targetBodyFlyLeft = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInLeft, animationOptions) - } - this.tabSlot.addEventListener('click', e => { - if (e.target === this.prevTab || !e.target.closest('sm-tab')) - return - if (this.prevTab) - this.prevTab.classList.remove('active') - e.target.classList.add('active') - - e.target.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) - this.indicator.setAttribute('style', `width: ${e.target.getBoundingClientRect().width}px; transform: translateX(${e.target.getBoundingClientRect().left - e.target.parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - - if (this.prevTab) { - let targetBody = e.target.nextElementSibling, - currentBody = this.prevTab.nextElementSibling; - - if (this.prevTab.getAttribute('rank') < e.target.getAttribute('rank')) { - if (currentBody && !targetBody) - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyRight(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyRight(targetBody) - } - } - } else { - if (currentBody && !targetBody) - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyLeft(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyLeft(targetBody) - } - } - } - } else { - e.target.nextElementSibling.classList.remove('hide-completely') - } - this.prevTab = e.target; - }) - let resizeObserver = new ResizeObserver(entries => { - entries.forEach((entry) => { - if (this.prevTab) { - let tabDimensions = this.prevTab.getBoundingClientRect(); - this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - }) - }) - resizeObserver.observe(this) - let observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - let activeElement = this.tabSlot.assignedElements().filter(element => { - if (element.classList.contains('active')) - return true - }) - if (activeElement.length) { - let tabDimensions = activeElement[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - activeElement[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - else { - this.tabSlot.assignedElements()[0].classList.add('active') - this.panelSlot.assignedElements()[0].classList.remove('hide-completely') - let tabDimensions = this.tabSlot.assignedElements()[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - this.prevTab = this.tabSlot.assignedElements()[0]; - } - } - }) - }, - { threshold: 1.0 }) - observer.observe(this) - if (this.hasAttribute('enable-flick') && this.getAttribute('enable-flick') == 'true') { - let touchStartTime = 0, - touchEndTime = 0, - swipeTimeThreshold = 200, - swipeDistanceThreshold = 20, - startingPointX = 0, - endingPointX = 0, - currentIndex = 0; - this.addEventListener('touchstart', e => { - touchStartTime = e.timeStamp - startingPointX = e.changedTouches[0].clientX - }) - this.panelSlot.addEventListener('touchend', e => { - touchEndTime = e.timeStamp - endingPointX = e.changedTouches[0].clientX - if (touchEndTime - touchStartTime < swipeTimeThreshold) { - currentIndex = this.allTabs.findIndex(element => element.classList.contains('active')) - if (startingPointX > endingPointX && startingPointX - endingPointX > swipeDistanceThreshold && currentIndex < this.allTabs.length) { - this.allTabs[currentIndex + 1].click() - } - else if (startingPointX < endingPointX && endingPointX - startingPointX > swipeDistanceThreshold && currentIndex > 0) { - this.allTabs[currentIndex - 1].click() - } - } - }) - } - } -}) - -// tab -const smTab = document.createElement('template') -smTab.innerHTML = ` - -
- -
-`; - -customElements.define('sm-tab', class extends HTMLElement { - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smTab.content.cloneNode(true)) - } -}) - -//chcekbox - -const smCheckbox = document.createElement('template') -smCheckbox.innerHTML = ` - -` -customElements.define('sm-checkbox', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smCheckbox.content.cloneNode(true)) - - this.checkbox = this.shadowRoot.querySelector('.checkbox'); - this.input = this.shadowRoot.querySelector('input') - - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.getAttribute('checked') - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.checkbox.classList.add('disabled') - this.isDisabled = true - } - else { - this.checkbox.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } - -}) - -//audio - -const smAudio = document.createElement('template') -smAudio.innerHTML = ` - -
- - play - - - - pause - - - -
/
- -
- -`; - -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') - } - } - } -}) - -//switch - -const smSwitch = document.createElement('template') -smSwitch.innerHTML = ` - -` - -customElements.define('sm-switch', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSwitch.content.cloneNode(true)) - this.switch = this.shadowRoot.querySelector('.switch'); - this.input = this.shadowRoot.querySelector('input') - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.isChecked - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.switch.classList.add('disabled') - this.isDisabled = true - } - else { - this.switch.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } -}) - -// select -const smSelect = document.createElement('template') -smSelect.innerHTML = ` - -
-
-
- - - -
-
- -
-
`; -customElements.define('sm-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - - collapse = () => { - this.optionList.animate(this.slideUp, this.animationOptions) - this.optionList.classList.add('hide') - this.chevron.classList.remove('rotate') - this.open = false - } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [ - { transform: `translateY(-0.5rem)` }, - { transform: `translateY(0)` } - ], - this.slideUp = [ - { transform: `translateY(0)` }, - { transform: `translateY(-0.5rem)` } - ], - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' - } - selection.addEventListener('click', e => { - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { - this.setAttribute('value', e.detail.value) - this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - if (previousOption) { - previousOption.classList.remove('check-selected') - } - previousOption = e.target; - } - if(!e.detail.switching) - this.collapse() - - e.target.classList.add('check-selected') - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); - document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { - this.collapse() - } - }) - } -}) - -// option -const smOption = document.createElement('template') -smOption.innerHTML = ` - -
- - - - -
`; -customElements.define('sm-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smOption.content.cloneNode(true)) - } - - sendDetails = (switching) => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value'), - switching: switching - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - let validKey = [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight' - ] - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - if (validKey.includes(e.code)) { - e.preventDefault() - this.sendDetails(true) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -// select -const smStripSelect = document.createElement('template') -smStripSelect.innerHTML = ` - -
-
- - Previous - - -
- -
- - Next - - -
-
`; -customElements.define('sm-strip-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - scrollLeft = () => { - this.select.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.select.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - connectedCallback() { - let previousOption, - slot = this.shadowRoot.querySelector('slot'); - this.selectContainer = this.shadowRoot.querySelector('.select-container') - this.select = this.shadowRoot.querySelector('.select') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.selectOptions - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.previousArrow.classList.add('hide') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.remove('hide') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.nextArrow.classList.add('hide') - this.nextGradient.classList.add('hide') - } - else { - this.nextArrow.classList.remove('hide') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - - const selectObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - } - }) - - selectObserver.observe(this.selectContainer) - this.addEventListener('optionSelected', e => { - if (previousOption === e.target) return; - if (previousOption) - previousOption.classList.remove('active') - e.target.classList.add('active') - e.target.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }) - this.setAttribute('value', e.detail.value) - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - previousOption = e.target; - }) - slot.addEventListener('slotchange', e => { - this.selectOptions = slot.assignedElements() - firstElementObserver.observe(this.selectOptions[0]) - lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) - if (this.selectOptions[0]) { - let firstElement = this.selectOptions[0]; - this.setAttribute('value', firstElement.getAttribute('value')) - firstElement.classList.add('active') - previousOption = firstElement; - } - }); - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -// option -const smStripOption = document.createElement('template') -smStripOption.innerHTML = ` - -
- -
`; -customElements.define('sm-strip-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripOption.content.cloneNode(true)) - } - sendDetails = () => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value') - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -//popup -const smPopup = document.createElement('template') -smPopup.innerHTML = ` - - -`; -customElements.define('sm-popup', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smPopup.content.cloneNode(true)) - } - - resumeScrolling = () => { - const scrollY = document.body.style.top; - window.scrollTo(0, parseInt(scrollY || '0') * -1); - setTimeout(() => { - document.body.setAttribute('style', `overflow: auto; top: initial`) - }, 300); - } - - show(pinned, popupStack) { - this.pinned = pinned - this.popupStack = popupStack - this.popupContainer.classList.remove('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(0)'; - else - this.popup.style.transform = 'scale(1)'; - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - } - hide() { - this.popupContainer.classList.add('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(100%)'; - else - this.popup.style.transform = 'scale(0.9)'; - if (typeof this.popupStack !== 'undefined') { - this.popupStack.pop() - if (this.popupStack.items.length === 0) { - this.resumeScrolling() - } - } - else { - this.resumeScrolling() - } - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartY < e.changedTouches[0].clientY) { - this.offset = e.changedTouches[0].clientY - this.touchStartY; - this.touchEndAnimataion = window.requestAnimationFrame(this.movePopup) - } - /*else { - offset = touchStartY - e.changedTouches[0].clientY; - this.popup.style.transform = `translateY(-${offset}px)` - }*/ - } - - handleTouchEnd = (e) => { - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.3s' - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndY - this.touchStartY > this.threshold) { - this.hide() - } - else { - this.show() - } - } - else { - if (this.touchEndY > this.touchStartY) - this.hide() - } - } - - movePopup = () => { - this.popup.style.transform = `translateY(${this.offset}px)` - } - - connectedCallback() { - this.pinned = false - this.popupStack - this.popupContainer = this.shadowRoot.querySelector('.popup-container') - this.popup = this.shadowRoot.querySelector('.popup') - this.offset - this.popupHeader = this.shadowRoot.querySelector('.popup-top') - this.touchStartY = 0 - this.touchEndY = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - this.touchEndAnimataion; - - if (this.hasAttribute('heading')) - this.shadowRoot.querySelector('.heading').textContent = this.getAttribute('heading') - - this.popupContainer.addEventListener('mousedown', e => { - if (e.target === this.popupContainer && !this.pinned) { - this.hide() - } - }) - - this.shadowRoot.querySelector('.close').addEventListener('click', e => { - this.hide() - }) - - this.popupHeader.addEventListener('touchstart', this.handleTouchStart) - this.popupHeader.addEventListener('touchmove', this.handleTouchMove) - this.popupHeader.addEventListener('touchend', this.handleTouchEnd) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd) - } -}) - -//carousel - -const smCarousel = document.createElement('template') -smCarousel.innerHTML = ` - - -`; - -customElements.define('sm-carousel', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smCarousel.content.cloneNode(true)) - } - - scrollLeft = () => { - this.carousel.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.carousel.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - - connectedCallback() { - this.carousel = this.shadowRoot.querySelector('.carousel') - this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') - this.carouselSlot = this.shadowRoot.querySelector('slot') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.carouselItems - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width/3 - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.previousArrow.classList.remove('expand') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.add('expand') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.nextArrow.classList.remove('expand') - this.nextGradient.classList.add('hide') - } - else{ - this.nextArrow.classList.add('expand') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - - const carouselObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 - } - }) - - carouselObserver.observe(this.carouselContainer) - - this.carouselSlot.addEventListener('slotchange', e => { - this.carouselItems = this.carouselSlot.assignedElements() - firstElementObserver.observe(this.carouselItems[0]) - lastElementObserver.observe(this.carouselItems[this.carouselItems.length - 1]) - }) - - this.addEventListener('keyup', e => { - if (e.code === 'ArrowLeft') - this.scrollRight() - else - this.scrollRight() - }) - - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -//notifications - -const smNotifications = document.createElement('template') -smNotifications.innerHTML = ` - -
-
-` - -customElements.define('sm-notifications', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smNotifications.content.cloneNode(true)) - } - - handleTouchStart = (e) => { - this.notification = e.target.closest('.notification') - this.touchStartX = e.changedTouches[0].clientX - this.notification.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartX < e.changedTouches[0].clientX) { - this.offset = e.changedTouches[0].clientX - this.touchStartX; - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - else { - this.offset = -(this.touchStartX - e.changedTouches[0].clientX); - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - } - - handleTouchEnd = (e) => { - this.notification.style.transition = 'height 0.3s, transform 0.3s, opacity 0.3s' - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndX = e.changedTouches[0].clientX - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndX - this.touchStartX > this.threshold) { - this.removeNotification(this.notification) - } - else if (this.touchStartX - this.touchEndX > this.threshold) { - this.removeNotification(this.notification, true) - } - else { - this.resetPosition() - } - } - else { - if (this.touchEndX > this.touchStartX) { - this.removeNotification(this.notification) - } - else { - this.removeNotification(this.notification, true) - } - } - } - - movePopup = () => { - this.notification.style.transform = `translateX(${this.offset}px)` - } - - resetPosition = () => { - this.notification.style.transform = `translateX(0)` - } - - push = (messageHeader, messageBody, options) => { - let notification = document.createElement('div'), - composition = ``, - { pinned, type } = options; - notification.classList.add('notification') - if (pinned) - notification.classList.add('pinned') - composition += ` -
-
- ` - if (type === 'error') { - composition += ` - - - - - ` - } - else if (type === 'success') { - composition += ` - - - - ` - } - composition += ` -

${messageHeader}

- - Close - - - -
-

${messageBody}

-
` - notification.innerHTML = composition - this.notificationPanel.prepend(notification) - if (window.innerWidth > 640) { - notification.animate([ - { - transform: `translateX(1rem)`, - opacity: '0' - }, - { - transform: 'translateX(0)', - opacity: '1' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `transform: none;`); - } - } - else { - notification.setAttribute('style', `transform: translateY(0); opacity: 1`) - } - notification.addEventListener('touchstart', this.handleTouchStart) - notification.addEventListener('touchmove', this.handleTouchMove) - notification.addEventListener('touchend', this.handleTouchEnd) - } - - removeNotification = (notification, toLeft) => { - notification.style.height = notification.scrollHeight + 'px'; - if (!this.offset) - this.offset = 0; - - if (toLeft) - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(-100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - else { - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - } - setTimeout( () => { - notification.remove() - }, this.animationOptions.duration*2) - } - - connectedCallback() { - this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: "ease" - } - this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) - this.notification - this.offset - this.touchStartX = 0 - this.touchEndX = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 - this.touchEndAnimataion; - - this.notificationPanel.addEventListener('click', e => { - if (e.target.closest('.close'))( - this.removeNotification(e.target.closest('.notification')) - ) - }) - - const observer = new MutationObserver(mutationList => { - mutationList.forEach(mutation => { - if (mutation.type === 'childList') { - if (mutation.addedNodes.length) { - if (!mutation.addedNodes[0].classList.contains('pinned')) - setTimeout(() => { - this.removeNotification(mutation.addedNodes[0]) - }, 4000); - if (window.innerWidth > 640) - this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; - else - this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; - } - else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { - this.notificationPanel.style.padding = 0; - } - } - }) - }) - observer.observe(this.notificationPanel, { - attributes: true, - childList: true, - subtree: true - }) - } -}) -// sm-menu -const smMenu = document.createElement('template') -smMenu.innerHTML = ` - -
- -
- -
-
`; -customElements.define('sm-menu', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenu.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - expand = () => { - if (!this.open) { - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - this.optionList.classList.remove('hide') - this.optionList.classList.add('no-transformations') - this.open = true - this.icon.classList.add('focused') - } - } - collapse = () => { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - } - } - connectedCallback() { - this.availableOptions - this.containerDimensions - this.optionList = this.shadowRoot.querySelector('.options') - let slot = this.shadowRoot.querySelector('.options slot'), - menu = this.shadowRoot.querySelector('.menu') - this.icon = this.shadowRoot.querySelector('.icon') - this.open = false; - menu.addEventListener('click', e => { - if (!this.open) { - this.expand() - } else { - this.collapse() - } - }) - menu.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - if (!this.open) { - this.expand() - } else { - this.collapse() - } - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.optionList.addEventListener('click', e => { - this.collapse() - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - this.containerDimensions = this.optionList.getBoundingClientRect() - this.menuDimensions = menu.getBoundingClientRect() - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - if (this.hasAttribute('set-context') && this.getAttribute('set-context') === 'true') { - this.parentNode.setAttribute('oncontextmenu', 'return false') - this.parentNode.addEventListener('mouseup', e => { - if (e.button === 2) { - this.expand() - } - }) - } - const intersectionObserver = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (!entry.isIntersecting && this.open) { - if(window.innerHeight - entry.intersectionRect.top < this.containerDimensions.height) - this.optionList.classList.add('moveUp') - else - this.optionList.classList.remove('moveUp') - if (entry.intersectionRect.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - } - }) - }, { - threshold: 1 - }) - intersectionObserver.observe(this.optionList) - } -}) - -// option -const smMenuOption = document.createElement('template') -smMenuOption.innerHTML = ` - -
- -
`; -customElements.define('sm-menu-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenuOption.content.cloneNode(true)) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.click() - } - }) - this.setAttribute('tabindex', '0') - } -}) \ No newline at end of file diff --git a/Layouts/sidebar layout/js/components.min.js b/Layouts/sidebar layout/js/components.min.js new file mode 100644 index 0000000..4f0c4e7 --- /dev/null +++ b/Layouts/sidebar layout/js/components.min.js @@ -0,0 +1,7 @@ +const smButton=document.createElement("template");smButton.innerHTML="\n\n
\n \n
",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}handleKeyDown(e){this.hasAttribute("disabled")||"Enter"!==e.key&&"Space"!==e.code||(e.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,n){"disabled"===e?(this.removeAttribute("tabindex"),this.setAttribute("aria-disabled","true")):(this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled","false"))}}); +const hamburgerMenu=document.createElement("template");hamburgerMenu.innerHTML='\n\n
\n\n';class HamburgerMenu extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(hamburgerMenu.content.cloneNode(!0)),this.resumeScrolling=this.resumeScrolling.bind(this),this.open=this.open.bind(this),this.close=this.close.bind(this),this.sideNav=this.shadowRoot.querySelector(".side-nav"),this.backdrop=this.shadowRoot.querySelector(".backdrop"),this.isOpen=!1,this.animeOptions={duration:300,easing:"ease"}}static get observedAttributes(){return["open"]}resumeScrolling(){const n=document.body.style.top;window.scrollTo(0,-1*parseInt(n||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}open(){this.isOpen||(document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.classList.remove("hide"),this.sideNav.classList.add("reveal"),this.backdrop.classList.remove("hide"),this.backdrop.animate([{opacity:0},{opacity:1}],this.animeOptions).onfinish=(()=>{this.isOpen=!0,this.setAttribute("open","")}))}close(){this.isOpen&&(this.sideNav.classList.remove("reveal"),this.backdrop.animate([{opacity:1},{opacity:0}],this.animeOptions).onfinish=(()=>{this.backdrop.classList.add("hide"),this.classList.add("hide"),this.isOpen=!1,this.removeAttribute("open")}))}connectedCallback(){this.backdrop.addEventListener("click",this.close);const n=new ResizeObserver(n=>{window.innerWidth<640&&this.isOpen?this.classList.remove("hide"):this.classList.add("hide"),window.innerWidth>640&&this.classList.remove("hide")});n.observe(this)}disconnectedCallback(){this.backdrop.removeEventListener("click",this.close)}attributeChangedCallback(n,e,t){"open"===n&&this.hasAttribute("open")&&this.open()}}window.customElements.define("hamburger-menu",HamburgerMenu); +const smInput=document.createElement("template");smInput.innerHTML='\n\n
\n \n \n
\n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),this.inputParent=this.shadowRoot.querySelector(".input"),this.input=this.shadowRoot.querySelector("input"),this.clearBtn=this.shadowRoot.querySelector(".clear"),this.label=this.shadowRoot.querySelector(".label"),this.feedbackText=this.shadowRoot.querySelector(".feedback-text"),this._helperText,this._errorText,this.isRequired=!1,this.validationFunction,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.focusOut=this.focusOut.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get isValid(){const t=this.input.checkValidity();let e=!0;return this.customValidation&&(e=this.validationFunction(this.input.value)),t&&e}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required")),this.isValid?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n \n ${this._errorText}\n `)),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):this.label.classList.remove("hide"))}connectedCallback(){this.animate=this.hasAttribute("animate"),this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.reset)}attributeChangedCallback(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.feedbackText.textContent="* required"):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); +const smMenu=document.createElement("template");smMenu.innerHTML='\n\n
\n \n
\n \n
\n
',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n
\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}}); +const smNotifications=document.createElement("template");smNotifications.innerHTML='\n\n
\n',customElements.define("sm-notifications",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smNotifications.content.cloneNode(!0)),this.notificationPanel=this.shadowRoot.querySelector(".notification-panel"),this.animationOptions={duration:300,fill:"forwards",easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)"},this.push=this.push.bind(this),this.createNotification=this.createNotification.bind(this),this.removeNotification=this.removeNotification.bind(this),this.clearAll=this.clearAll.bind(this)}randString(n){let t="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let o=0;o${o}
\n

${n}

\n `,i&&(e.classList.add("pinned"),a+='\n \n '),e.innerHTML=a,e}push(n,t={}){const i=this.createNotification(n,t);return this.notificationPanel.append(i),i.animate([{transform:"translateY(1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animationOptions),i.id}removeNotification(n){n.animate([{transform:"none",opacity:"1"},{transform:"translateY(0.5rem)",opacity:"0"}],this.animationOptions).onfinish=(()=>{n.remove()})}clearAll(){Array.from(this.notificationPanel.children).forEach(n=>{this.removeNotification(n)})}connectedCallback(){this.notificationPanel.addEventListener("click",n=>{n.target.closest(".close")&&this.removeNotification(n.target.closest(".notification"))});const n=new MutationObserver(n=>{n.forEach(n=>{"childList"===n.type&&n.addedNodes.length&&!n.addedNodes[0].classList.contains("pinned")&&setTimeout(()=>{this.removeNotification(n.addedNodes[0])},5e3)})});n.observe(this.notificationPanel,{childList:!0})}}); +const smPopup=document.createElement("template");smPopup.innerHTML='\n\n\n',customElements.define("sm-popup",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smPopup.content.cloneNode(!0)),this.allowClosing=!1,this.isOpen=!1,this.pinned=!1,this.popupStack,this.offset,this.touchStartY=0,this.touchEndY=0,this.touchStartTime=0,this.touchEndTime=0,this.touchEndAnimataion,this.popupContainer=this.shadowRoot.querySelector(".popup-container"),this.popup=this.shadowRoot.querySelector(".popup"),this.popupBodySlot=this.shadowRoot.querySelector(".popup-body slot"),this.popupHeader=this.shadowRoot.querySelector(".popup-top"),this.resumeScrolling=this.resumeScrolling.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.handleTouchStart=this.handleTouchStart.bind(this),this.handleTouchMove=this.handleTouchMove.bind(this),this.handleTouchEnd=this.handleTouchEnd.bind(this),this.movePopup=this.movePopup.bind(this)}static get observedAttributes(){return["open"]}get open(){return this.isOpen}resumeScrolling(){const t=document.body.style.top;window.scrollTo(0,-1*parseInt(t||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}show(t={}){const{pinned:e=!1,popupStack:n}=t;return n&&(this.popupStack=n),this.popupStack&&!this.hasAttribute("open")&&(this.popupStack.push({popup:this,permission:e}),this.popupStack.items.length>1&&this.popupStack.items[this.popupStack.items.length-2].popup.classList.add("stacked"),this.dispatchEvent(new CustomEvent("popupopened",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.setAttribute("open",""),this.pinned=e,this.isOpen=!0),this.popupContainer.classList.remove("hide"),this.popup.style.transform="none",document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.popupStack}hide(){window.innerWidth<640?this.popup.style.transform="translateY(100%)":this.popup.style.transform="translateY(3rem)",this.popupContainer.classList.add("hide"),this.removeAttribute("open"),void 0!==this.popupStack?(this.popupStack.pop(),this.popupStack.items.length?this.popupStack.items[this.popupStack.items.length-1].popup.classList.remove("stacked"):this.resumeScrolling()):this.resumeScrolling(),this.forms.length&&setTimeout(()=>{this.forms.forEach(t=>t.reset())},300),setTimeout(()=>{this.dispatchEvent(new CustomEvent("popupclosed",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.isOpen=!1},300)}handleTouchStart(t){this.touchStartY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.1s",this.touchStartTime=t.timeStamp}handleTouchMove(t){this.touchStartYthis.movePopup()))}handleTouchEnd(t){if(this.touchEndTime=t.timeStamp,cancelAnimationFrame(this.touchEndAnimataion),this.touchEndY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.3s",this.threshold=.3*this.popup.getBoundingClientRect().height,this.touchEndTime-this.touchStartTime>200)if(this.touchEndY-this.touchStartY>this.threshold){if(this.pinned)return void this.show();this.hide()}else this.show();else if(this.touchEndY>this.touchStartY){if(this.pinned)return void this.show();this.hide()}}movePopup(){this.popup.style.transform=`translateY(${this.offset}px)`}connectedCallback(){this.popupBodySlot.addEventListener("slotchange",()=>{this.forms=this.querySelectorAll("sm-form")}),this.popupContainer.addEventListener("mousedown",t=>{t.target!==this.popupContainer||this.pinned||(this.pinned?this.show():this.hide())});const t=new ResizeObserver(t=>{for(let e of t)if(e.contentBoxSize){Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.threshold=.3*e.blockSize.height}else this.threshold=.3*e.contentRect.height});t.observe(this),this.popupHeader.addEventListener("touchstart",t=>{this.handleTouchStart(t)},{passive:!0}),this.popupHeader.addEventListener("touchmove",t=>{this.handleTouchMove(t)},{passive:!0}),this.popupHeader.addEventListener("touchend",t=>{this.handleTouchEnd(t)},{passive:!0})}disconnectedCallback(){this.popupHeader.removeEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.popupHeader.removeEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.popupHeader.removeEventListener("touchend",this.handleTouchEnd,{passive:!0}),resizeObserver.unobserve()}attributeChangedCallback(t,e,n){"open"===t&&this.hasAttribute("open")&&this.show()}}); +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/Layouts/sidebar layout/js/helper.js b/Layouts/sidebar layout/js/helper.js deleted file mode 100644 index a7c51ee..0000000 --- a/Layouts/sidebar layout/js/helper.js +++ /dev/null @@ -1,133 +0,0 @@ -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) -}) -let themeToggler = document.getElementById("theme_toggle") -if (localStorage.theme === "dark") { - darkTheme() - themeToggler.checked = true; -} else { - lightTheme() - themeToggler.checked = false; -} - -function lightTheme() { - document.body.setAttribute("data-theme", "light"); -} - -function darkTheme() { - document.body.setAttribute("data-theme", "dark"); -} -themeToggler.addEventListener("change", () => { - if (themeToggler.checked) { - darkTheme() - localStorage.setItem("theme", "dark"); - } else { - lightTheme() - 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(index) { - let newIndex = index ? index : 1 - return this.items[this.items.length - index]; - } -} -let popupStack = new Stack(), - zIndex = 10; -function showPopup(popup, permission) { - let thisPopup = document.getElementById(popup); - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - popupStack.push({ thisPopup, permission }) - thisPopup.show(permission, popupStack) - zIndex++; - thisPopup.setAttribute('style', `z-index: ${zIndex}`) - return thisPopup; -} -function setAttributes(el, attrs) { - for (var key in attrs) { - el.setAttribute(key, attrs[key]); - } -} -// displays a popup for asking permission. Use this instead of JS confirm -let confirmation = 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); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(false); - } - }) -} - -// 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'); - if (defaultVal) - input.value = defaultVal; - showPopup('prompt') - input.focus() - input.addEventListener('keyup', e => { - if (e.key === 'Enter') { - resolve(input.value); - hidePopup() - } - }) - popup.querySelector('#prompt_message').textContent = message; - popup.querySelector('.submit-btn').onclick = () => { - hidePopup() - resolve(input.value); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(null); - } - }) -} - -function formatedTime(time) { - let timeFrag = new Date(parseInt(time)).toString().split(' '), - day = timeFrag[0], - month = timeFrag[1], - date = timeFrag[2], - year = timeFrag[3], - hours = timeFrag[4].slice(0, timeFrag[4].lastIndexOf(':')), - finalTime = ''; - parseInt(hours.split(':')[0]) > 12 ? finalTime = 'PM' : finalTime = 'AM' - return `${hours} ${finalTime} ${day} ${date} ${month} ${year}` -} - -function copyToClipboard(parent) { - let toast = document.getElementById('textCopied'), - textToCopy = parent.querySelector('.copy').textContent; - navigator.clipboard.writeText(textToCopy) - toast.classList.remove('hide'); - setTimeout(() => { - toast.classList.add('hide'); - }, 2000) -} \ No newline at end of file diff --git a/Layouts/sidebar layout/js/main_UI.js b/Layouts/sidebar layout/js/main_UI.js new file mode 100644 index 0000000..96f39cd --- /dev/null +++ b/Layouts/sidebar layout/js/main_UI.js @@ -0,0 +1,309 @@ +// Global variables +const domRefs = {}; +const appPages = ['dashboard', 'settings'] + + +//Checks for internet connection status +if (!navigator.onLine) + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { sound: true } + ); +window.addEventListener("offline", () => { + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { pinned: true, sound: true } + ); +}); +window.addEventListener("online", () => { + getRef("notification_drawer").clearAll(); + notify("We are back online.", "success"); +}); + +// Use instead of document.getElementById +function getRef(elementId) { + if (!domRefs.hasOwnProperty(elementId)) { + domRefs[elementId] = { + count: 1, + ref: null, + }; + return document.getElementById(elementId); + } else { + if (domRefs[elementId].count < 3) { + domRefs[elementId].count = domRefs[elementId].count + 1; + return document.getElementById(elementId); + } else { + if (!domRefs[elementId].ref) + domRefs[elementId].ref = document.getElementById(elementId); + return domRefs[elementId].ref; + } + } +} + +// returns dom with specified element +function createElement(tagName, obj) { + const { className, textContent, innerHTML, attributes = {} } = obj + const elem = document.createElement(tagName) + for (let attribute in attributes) { + elem.setAttribute(attribute, attributes[attribute]) + } + if (className) + elem.className = className + if (textContent) + elem.textContent = textContent + if (innerHTML) + elem.innerHTML = innerHTML + return elem +} + +// Use when a function needs to be executed after user finishes changes +const debounce = (callback, wait) => { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; +} + +// Limits the rate of function execution +let timerId; +function throttle(func, delay) { + // If setTimeout is already scheduled, no need to do anything + if (timerId) { + return; + } + + // Schedule a setTimeout after delay seconds + timerId = setTimeout(function () { + func(); + + // Once setTimeout function execution is finished, timerId = undefined so that in + // the next scroll event function execution can be scheduled by the setTimeout + timerId = undefined; + }, delay); +} + +// 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; + +async function showPopup(popup, pinned) { + zIndex++ + getRef(popup).setAttribute('style', `z-index: ${zIndex}`) + popupStack = getRef(popup).show({ pinned, popupStack }) + return getRef(popup); +} + +// hides the popup or modal +function hidePopup() { + if (popupStack.peek() === undefined) + return; + popupStack.peek().popup.hide() +} + +// displays a popup for asking permission. Use this instead of JS confirm +let getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => { + return new Promise(resolve => { + showPopup('confirmation_popup', true) + getRef('confirm_title').textContent = title; + getRef('confirm_message').textContent = message; + let cancelButton = getRef('confirmation_popup').children[2].children[0], + submitButton = getRef('confirmation_popup').children[2].children[1] + submitButton.textContent = confirmText + cancelButton.textContent = cancelText + submitButton.onclick = () => { + hidePopup() + resolve(true); + } + cancelButton.onclick = () => { + hidePopup() + resolve(false); + } + }) +} + +// displays a popup for asking user input. Use this instead of JS prompt +async function getPromptInput(title, message = '', showText = true, trueBtn = "Ok", falseBtn = "Cancel") { + showPopup('prompt_popup', true) + getRef('prompt_title').textContent = title; + let input = getRef('prompt_input'); + input.setAttribute("placeholder", message) + let buttons = getRef('prompt_popup').querySelectorAll("sm-button"); + if (showText) + input.setAttribute("type", "text") + else + input.setAttribute("type", "password") + input.focusIn() + buttons[0].textContent = falseBtn; + buttons[1].textContent = trueBtn; + return new Promise((resolve, reject) => { + buttons[0].onclick = () => { + hidePopup() + return; + } + buttons[1].onclick = () => { + let value = input.value; + hidePopup() + resolve(value) + } + }) +} + +//Function for displaying toast notifications. pass in error for mode param if you want to show an error. +function notify(message, mode, options = {}) { + const { pinned = false, sound } = options + if (mode === "error") console.error(message); + let icon + switch (mode) { + case 'success': + icon = `` + break; + case 'error': + icon = `` + break; + } + getRef("notification_drawer").push(message, { pinned, icon }); + if (navigator.onLine && sound) { + getRef("notification_sound").currentTime = 0; + getRef("notification_sound").play(); + } +} + +const currentYear = new Date().getFullYear(); +function getFormatedTime(time, relative) { + try { + if (String(time).indexOf("_")) time = String(time).split("_")[0]; + const intTime = parseInt(time); + if (String(intTime).length < 13) time *= 1000; + let timeFrag = new Date(intTime).toString().split(" "), + day = timeFrag[0], + month = timeFrag[1], + date = timeFrag[2], + year = timeFrag[3], + minutes = new Date(intTime).getMinutes(), + hours = new Date(intTime).getHours(), + currentTime = new Date().toString().split(" "); + + minutes = minutes < 10 ? `0${minutes}` : minutes; + let finalHours = ``; + if (hours > 12) finalHours = `${hours - 12}:${minutes}`; + else if (hours === 0) finalHours = `12:${minutes}`; + else finalHours = `${hours}:${minutes}`; + + finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`; + if (relative) { + return `${date} ${month} ${year}`; + } else return `${finalHours} ${month} ${date} ${year}`; + } catch (e) { + console.error(e); + return time; + } +} + +window.addEventListener('hashchange', e => showPage(window.location.hash)) +window.addEventListener("load", () => { + document.body.classList.remove('hide-completely') + showPage(window.location.hash) + // document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = validateAddr) + document.addEventListener('keyup', (e) => { + if (e.code === 'Escape') { + hidePopup() + } + }) + document.addEventListener("pointerdown", (e) => { + if (e.target.closest("button, sm-button:not([disabled]), .interact")) { + createRipple(e, e.target.closest("button, sm-button, .interact")); + } + }); + document.addEventListener('copy', () => { + notify('copied', 'success') + }) +}); + +function createRipple(event, target) { + const circle = document.createElement("span"); + const diameter = Math.max(target.clientWidth, target.clientHeight); + const radius = diameter / 2; + const targetDimensions = target.getBoundingClientRect(); + circle.style.width = circle.style.height = `${diameter}px`; + circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`; + circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`; + circle.classList.add("ripple"); + const rippleAnimation = circle.animate( + [ + { + transform: "scale(3)", + opacity: 0, + }, + ], + { + duration: 1000, + fill: "forwards", + easing: "ease-out", + } + ); + target.append(circle); + rippleAnimation.onfinish = () => { + circle.remove(); + }; +} + +function showPage(targetPage, options = {}) { + const { firstLoad, hashChange } = options + let pageId + if (targetPage === '') { + pageId = 'overview_page' + } + else { + pageId = targetPage.includes('#') ? targetPage.split('#')[1] : targetPage + } + if(!appPages.includes(pageId)) return + document.querySelector('.page:not(.hide-completely)').classList.add('hide-completely') + document.querySelector('.list__item--active').classList.remove('list__item--active') + getRef(pageId).classList.remove('hide-completely') + getRef(pageId).animate([ + { + opacity: 0, + transform: 'translateX(-1rem)' + }, + { + opacity: 1, + transform: 'none' + }, + ], + { + duration: 300, + easing: 'ease' + }) + const targetListItem = document.querySelector(`.list__item[href="#${pageId}"]`) + targetListItem.classList.add('list__item--active') + if (firstLoad && window.innerWidth > 640 && targetListItem.getBoundingClientRect().top > getRef('side_nav').getBoundingClientRect().height) { + getRef('side_nav').scrollTo({ + top: (targetListItem.getBoundingClientRect().top - getRef('side_nav').getBoundingClientRect().top + getRef('side_nav').scrollTop), + behavior: 'smooth' + }) + } + if (hashChange && window.innerWidth < 640) { + getRef('side_nav').close() + } +} \ No newline at end of file diff --git a/Layouts/tabs layout/css/main.css b/Layouts/tabs layout/css/main.css index cfd785f..3b88c01 100644 --- a/Layouts/tabs layout/css/main.css +++ b/Layouts/tabs layout/css/main.css @@ -1,61 +1,88 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap"); * { - -webkit-box-sizing: border-box; - box-sizing: border-box; padding: 0; margin: 0; - font-family: 'Roboto', sans-serif; + box-sizing: border-box; + font-family: "Roboto", sans-serif; } :root { + font-size: clamp(1rem, 1.2vmax, 3rem); +} + +html, body { + height: 100%; scroll-behavior: smooth; } body { - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); +} +body, +body * { + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; } -body[data-theme="dark"] { - --accent-color: #6a7dff; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; -} - -h1, h2, h3, h4, h5 { - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} - -h1 { - font-size: 3rem; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -h4 { - font-size: 1rem; -} - -h5 { - font-size: 0.8rem; +body[data-theme=dark], +body[data-theme=dark] * { + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); } p { - margin: 1.5rem 0; + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); } +p:not(:last-of-type) { + margin-bottom: 1rem; +} + +img { + object-fit: cover; +} + +a { + color: inherit; + text-decoration: none; +} +a:focus-visible { + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; +} + +button { + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible { + outline: rgba(var(--text-color), 1) 0.1rem solid; +} + +sm-button { + --border-radius: 0.3rem; +} + +ul { + list-style: none; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} .hide { opacity: 0; @@ -66,124 +93,258 @@ p { display: none !important; } -.icon { - height: 1.2rem; - width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; +.no-transformations { + transform: none !important; } -.toggle { - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; -} - -.toggle input[type='checkbox'] { - display: none; -} - -.toggle .switch { - overflow: hidden; - display: -webkit-inline-box; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; - margin: 0; -} - -.toggle .circle { - border-radius: 0.5rem; - -webkit-transition: -webkit-transform 0.3s; - transition: -webkit-transform 0.3s; - transition: transform 0.3s; - transition: transform 0.3s, -webkit-transform 0.3s; - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; -} - -.toggle .circle:first-of-type { - margin-bottom: 0.4rem; -} - -.toggle .circle line { - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; -} - -.toggle input:checked ~ .switch .circle { - -webkit-transform: translateY(-1.7rem); - transform: translateY(-1.7rem); -} - -sm-tabs { - margin-bottom: 2rem; -} - -sm-tabs::part(tab-header) { - border-bottom: solid 1px rgba(var(--text-color), 0.2); - padding: 0 1.5rem; - margin-bottom: 2rem; -} - -sm-tabs::part(panel-container) { - padding: 0 1.5rem; -} - -#navbar { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - padding: 1.5rem 2rem; - background: rgba(var(--foreground-color), 1); - z-index: 3; -} - -#logo { - display: -ms-grid; - display: grid; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; +.overflow-ellipsis { width: 100%; - -ms-grid-columns: auto 1fr; - grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; - margin-right: 1rem; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -#logo h4 { +.breakable { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +.full-bleed { + grid-column: 1/4; +} + +.h1 { + font-size: 2.5rem; +} + +.h2 { + font-size: 2rem; +} + +.h3 { + font-size: 1.4rem; +} + +.h4 { + font-size: 1rem; +} + +.h5 { + font-size: 0.8rem; +} + +.uppercase { + text-transform: uppercase; +} + +.capitalize { text-transform: capitalize; - font-size: 1.2rem; - font-weight: 600; } -#logo h5 { - font-family: 'Roboto', sans-serif; +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.grid-3 { + grid-template-columns: 1fr auto auto; +} + +.flow-column { + grid-auto-flow: column; +} + +.gap-0-5 { + gap: 0.5rem; +} + +.gap-1 { + gap: 1rem; +} + +.gap-1-5 { + gap: 1.5rem; +} + +.gap-2 { + gap: 2rem; +} + +.gap-3 { + gap: 3rem; +} + +.text-align-right { + text-align: right; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.text-center { + text-align: center; +} + +.justify-start { + justify-content: start; +} + +.justify-center { + justify-content: center; +} + +.justify-right { + margin-left: auto; +} + +.align-self-center { + align-self: center; +} + +.justify-self-center { + justify-self: center; +} + +.justify-self-start { + justify-self: start; +} + +.justify-self-end { + justify-self: end; +} + +.direction-column { + flex-direction: column; +} + +.space-between { + justify-content: space-between; +} + +.w-100 { + width: 100%; +} + +.color-0-8 { + color: rgba(var(--text-color), 0.8); +} + +.weight-400 { font-weight: 400; } +.weight-500 { + font-weight: 500; +} + +.ripple { + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} + +.interact { + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} + +.observe-empty-state:empty { + display: none; +} + +.observe-empty-state:not(:empty) ~ .empty-state { + display: none; +} + +.icon { + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} + +.button__icon { + height: 1.2rem; + width: 1.2rem; +} +.button__icon--left { + margin-right: 0.5rem; +} +.button__icon--right { + margin-left: 0.5rem; +} + +#confirmation_popup, +#prompt_popup { + flex-direction: column; +} +#confirmation_popup h4, +#prompt_popup h4 { + font-weight: 500; + margin-bottom: 0.5rem; +} +#confirmation_popup sm-button, +#prompt_popup sm-button { + margin: 0; +} +#confirmation_popup .flex, +#prompt_popup .flex { + padding: 0; + margin-top: 1rem; +} +#confirmation_popup .flex sm-button:first-of-type, +#prompt_popup .flex sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; +} + +#main_header { + display: flex; + gap: 1rem; + align-items: center; + position: sticky; + padding: 1rem 1.5rem; + background: rgba(var(--background-color), 1); + border-bottom: solid 1px rgba(var(--text-color), 0.16); + z-index: 2; +} + +#logo { + display: grid; + align-items: center; + width: 100%; + grid-template-columns: auto 1fr; + gap: 0 0.5rem; + margin-right: 1rem; +} +#logo h4 { + text-transform: capitalize; + font-size: 1rem; + font-weight: 600; + margin-top: 0.2rem; +} +#logo h5 { + font-size: 0.8rem; + font-family: "Roboto", sans-serif; + font-weight: 400; +} #logo #main_logo { height: 1.4rem; width: 1.4rem; @@ -191,43 +352,46 @@ sm-tabs::part(panel-container) { stroke: none; } +sm-tab-header { + padding: 0 1.5rem; + background-color: rgba(var(--text-color), 0.06); +} + +sm-tab { + padding: 0.5rem 0.8rem; +} + .section { + display: flex; + flex-direction: column; margin-top: 3rem; + padding: 0 1.5rem; } - -.section h3 + p { - margin-top: 1rem; -} - .section:first-of-type { margin-top: 0; } -.card { - padding: 1.5rem; - display: -webkit-box; - display: -ms-flexbox; +.section__header { display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - -ms-flex-direction: column; - flex-direction: column; - width: 20rem; - border-radius: 0.5rem; - margin-right: 1.5rem; - border: solid 1px rgba(var(--text-color), 0.2); + padding: 1rem 0; + justify-content: space-between; } +.card { + padding: 1.5rem; + display: flex; + flex-direction: column; + min-width: 20rem; + border-radius: 0.5rem; + margin-right: 1.5rem; + background-color: rgba(var(--text-color), 0.06); +} .card h3 { font-weight: 500; } -@media only screen and (min-width: 640px) { - sm-tabs::part(tab-header), sm-tabs::part(panel-container) { - padding: 0 4vw; +@media screen and (min-width: 640px) { + sm-popup { + --width: 24rem; } - p { - max-width: 40rem; - } -} -/*# sourceMappingURL=main.css.map */ \ No newline at end of file +} \ No newline at end of file diff --git a/Layouts/tabs layout/css/main.min.css b/Layouts/tabs layout/css/main.min.css new file mode 100644 index 0000000..4553462 --- /dev/null +++ b/Layouts/tabs layout/css/main.min.css @@ -0,0 +1 @@ +#logo h5,*{font-family:Roboto,sans-serif}*{padding:0;margin:0;box-sizing:border-box}:root{font-size:clamp(1rem,1.2vmax,3rem)}body,html{height:100%;scroll-behavior:smooth}body{color:rgba(var(--text-color),1);background:rgba(var(--background-color),1)}body,body *{--accent-color:#0D7377;--text-color:17,17,17;--background-color:255,255,255;--danger-color:red}body[data-theme=dark],body[data-theme=dark] *{--accent-color:#32E0C4;--text-color:240,240,240;--text-color-light:170,170,170;--background-color:10,10,10;--danger-color:rgb(255, 106, 106)}p{font-size:.8;max-width:65ch;line-height:1.7;margin-bottom:1.5rem;color:rgba(var(--text-color),.8)}p:not(:last-of-type){margin-bottom:1rem}img{object-fit:cover}a{color:inherit;text-decoration:none}a:focus-visible{box-shadow:0 0 0 .1rem rgba(var(--text-color),1) inset}button{display:inline-flex;border:none;background-color:inherit}a:any-link:focus-visible{outline:solid rgba(var(--text-color),1)}sm-button{--border-radius:0.3rem}ul{list-style:none}.hide{opacity:0;pointer-events:none}.hide-completely{display:none!important}#main_header,.flex{display:flex}.no-transformations{transform:none!important}.overflow-ellipsis{width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.breakable{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full-bleed{grid-column:1/4}.h1{font-size:2.5rem}.h2{font-size:2rem}.h3{font-size:1.4rem}.h4{font-size:1rem}.h5{font-size:.8rem}.uppercase{text-transform:uppercase}#logo h4,.capitalize{text-transform:capitalize}.grid{display:grid}.grid-3{grid-template-columns:1fr auto auto}.flow-column{grid-auto-flow:column}.gap-0-5{gap:.5rem}.gap-1{gap:1rem}.gap-1-5{gap:1.5rem}.gap-2{gap:2rem}.gap-3{gap:3rem}.text-align-right{text-align:right}.align-start{align-items:flex-start}#main_header,.align-center{align-items:center}.text-center{text-align:center}.justify-start{justify-content:start}.justify-center{justify-content:center}.justify-right{margin-left:auto}.align-self-center{align-self:center}.justify-self-center{justify-self:center}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.direction-column{flex-direction:column}.space-between{justify-content:space-between}.w-100{width:100%}.color-0-8{color:rgba(var(--text-color),.8)}.weight-400{font-weight:400}.weight-500{font-weight:500}.ripple{position:absolute;border-radius:50%;transform:scale(0);background:rgba(var(--text-color),.16);pointer-events:none}.interact{position:relative;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:transparent}.observe-empty-state:empty{display:none}.observe-empty-state:not(:empty)~.empty-state{display:none}.icon{width:1.5rem;height:1.5rem;fill:rgba(var(--text-color),.9)}.button__icon{height:1.2rem;width:1.2rem}.button__icon--left{margin-right:.5rem}.button__icon--right{margin-left:.5rem}#confirmation_popup,#prompt_popup{flex-direction:column}#confirmation_popup h4,#prompt_popup h4{font-weight:500;margin-bottom:.5rem}#confirmation_popup sm-button,#prompt_popup sm-button{margin:0}#confirmation_popup .flex,#prompt_popup .flex{padding:0;margin-top:1rem}#confirmation_popup .flex sm-button:first-of-type,#prompt_popup .flex sm-button:first-of-type{margin-right:.6rem;margin-left:auto}#main_header{gap:1rem;position:sticky;padding:1rem 1.5rem;background:rgba(var(--background-color),1);border-bottom:solid 1px rgba(var(--text-color),.16);z-index:2}#logo{display:grid;align-items:center;width:100%;grid-template-columns:auto 1fr;gap:0 .5rem;margin-right:1rem}#logo h4{font-size:1rem;font-weight:600;margin-top:.2rem}#logo h5{font-size:.8rem;font-weight:400}#logo #main_logo{height:1.4rem;width:1.4rem;fill:rgba(var(--text-color),1);stroke:none}sm-tab-header{padding:0 1.5rem;background-color:rgba(var(--text-color),.06)}sm-tab{padding:.5rem .8rem}.section{display:flex;flex-direction:column;margin-top:3rem;padding:0 1.5rem}.section:first-of-type{margin-top:0}.section__header{display:flex;padding:1rem 0;justify-content:space-between}.card{padding:1.5rem;display:flex;flex-direction:column;min-width:20rem;border-radius:.5rem;margin-right:1.5rem;background-color:rgba(var(--text-color),.06)}.card h3{font-weight:500}@media screen and (min-width:640px){sm-popup{--width:24rem}} \ No newline at end of file diff --git a/Layouts/tabs layout/css/main.scss b/Layouts/tabs layout/css/main.scss index 04a64ea..29733c0 100644 --- a/Layouts/tabs layout/css/main.scss +++ b/Layouts/tabs layout/css/main.scss @@ -1,49 +1,79 @@ -@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Roboto:wght@400;500;700&display=swap'); *{ - box-sizing: border-box; padding: 0; margin: 0; + box-sizing: border-box; font-family: 'Roboto', sans-serif; } :root{ + font-size: clamp(1rem, 1.2vmax, 3rem); +} +html, body{ + height: 100%; scroll-behavior: smooth; } -body{ - --accent-color: #303F9F; - --text-color: 17, 17, 17; - --foreground-color: 255, 255, 255; - background: rgba(var(--foreground-color), 1); +body { + &, + *{ + --accent-color: #0D7377; + --text-color: 17, 17, 17; + --background-color: 255, 255, 255; + --danger-color: red; + } color: rgba(var(--text-color), 1); - font-size: 16px; + background: rgba(var(--background-color), 1); } -body[data-theme="dark"]{ - --accent-color: #6a7dff; - --foreground-color: 20, 20, 20; - --text-color: 238, 238, 238; +body[data-theme='dark']{ + &, + *{ + --accent-color: #32E0C4; + --text-color: 240, 240, 240; + --text-color-light: 170, 170, 170; + --background-color: 10, 10, 10; + --danger-color: rgb(255, 106, 106); + } } -h1, h2, h3, h4, h5{ - font-family: 'Poppins', sans-serif; - text-transform: capitalize; -} -h1{ - font-size: 3rem; -} -h2{ - font-size: 2rem; -} -h3{ - font-size: 1.5rem; -} -h4{ - font-size: 1rem; -} -h5{ - font-size: 0.8rem; -} -p{ - margin: 1.5rem 0; +p { + font-size: 0.8; + max-width: 65ch; line-height: 1.7; + margin-bottom: 1.5rem; color: rgba(var(--text-color), 0.8); + &:not(:last-of-type){ + margin-bottom: 1rem; + } +} +img{ + object-fit: cover; +} + +a{ + color: inherit; + text-decoration: none; + &:focus-visible{ + box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 1) inset; + } +} + +button{ + display: inline-flex; + border: none; + background-color: inherit; +} + +a:any-link:focus-visible{ + outline: rgba(var(--text-color), 1) 0.1rem solid; +} +sm-button{ + --border-radius: 0.3rem; +} +ul{ + list-style: none; +} +.flex{ + display: flex; +} +.grid{ + display: grid; } .hide{ opacity: 0; @@ -52,88 +82,206 @@ p{ .hide-completely{ display: none !important; } +.no-transformations{ + transform: none !important; +} +.overflow-ellipsis{ + width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.breakable{ + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} +.full-bleed{ + grid-column: 1/4; +} +.h1{ + font-size: 2.5rem; +} +.h2{ + font-size: 2rem; +} +.h3{ + font-size: 1.4rem; +} +.h4{ + font-size: 1rem; +} +.h5{ + font-size: 0.8rem; +} + +.uppercase{ + text-transform: uppercase; +} +.capitalize{ + text-transform: capitalize; +} +.flex{ + display: flex; +} +.grid{ + display: grid; +} +.grid-3{ + grid-template-columns: 1fr auto auto; +} +.flow-column{ + grid-auto-flow: column; +} +.gap-0-5{ + gap: 0.5rem; +} +.gap-1{ + gap: 1rem; +} +.gap-1-5{ + gap: 1.5rem; +} +.gap-2{ + gap: 2rem; +} +.gap-3{ + gap: 3rem; +} +.text-align-right{ + text-align: right; +} +.align-start{ + align-items: flex-start; +} +.align-center{ + align-items: center; +} +.text-center{ + text-align: center; +} +.justify-start{ + justify-content: start; +} +.justify-center{ + justify-content: center; +} +.justify-right{ + margin-left: auto; +} +.align-self-center{ + align-self: center; +} +.justify-self-center{ + justify-self: center; +} +.justify-self-start{ + justify-self: start; +} +.justify-self-end{ + justify-self: end; +} +.direction-column{ + flex-direction: column; +} +.space-between{ + justify-content: space-between; +} +.w-100{ + width: 100%; +} +.color-0-8{ + color: rgba(var(--text-color), 0.8); +} +.weight-400{ + font-weight: 400; +} +.weight-500{ + font-weight: 500; +} +.ripple{ + position: absolute; + border-radius: 50%; + transform: scale(0); + background: rgba(var(--text-color), 0.16); + pointer-events: none; +} +.interact{ + position: relative; + overflow: hidden; + cursor: pointer; + -webkit-tap-highlight-color: transparent; +} +.observe-empty-state:empty{ + display: none; +} +.observe-empty-state:not(:empty) ~ .empty-state{ + display: none; +} .icon{ + width: 1.5rem; + height: 1.5rem; + fill: rgba(var(--text-color), 0.9); +} +.button__icon{ height: 1.2rem; width: 1.2rem; - fill: none; - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; -} -.toggle{ - position: relative; - cursor: pointer; - z-index: 1; - padding: 0; - input[type='checkbox']{ - display: none; + &--left{ + margin-right: 0.5rem; } - .switch{ - overflow: hidden; - display: inline-flex; - flex-direction: column; - justify-items: center; - padding: 0.2rem; - min-height: 1.6rem; - max-height: 1.6rem; - border-radius: 0.5rem; - position: relative; + &--right{ + margin-left: 0.5rem; + } +} +#confirmation_popup, +#prompt_popup { + flex-direction: column; + h4 { + font-weight: 500; + margin-bottom: 0.5rem; + } + sm-button{ margin: 0; } - .circle{ - border-radius: 0.5rem; - transition: transform 0.3s; - &:first-of-type{ - margin-bottom: 0.4rem; - } - fill: rgba(var(--text-color), 0.8); - overflow: visible; - stroke-linecap: round; - stroke-linejoin: round; - height: 1.2rem; - width: 1.2rem; - line{ - stroke: rgba(var(--text-color), 0.8); - stroke-width: 6; + .flex { + padding: 0; + margin-top: 1rem; + sm-button:first-of-type { + margin-right: 0.6rem; + margin-left: auto; } } - input:checked ~ .switch .circle{ - transform: translateY(-1.7rem); - } } -sm-tabs{ - margin-bottom: 2rem; - &::part(tab-header){ - border-bottom: solid 1px rgba(var(--text-color), 0.2); - padding: 0 1.5rem; - margin-bottom: 2rem; - } - &::part(panel-container){ - padding: 0 1.5rem; - } -} -#navbar{ +#main_header{ display: flex; + gap: 1rem; align-items: center; - padding: 1.5rem 2rem; - background: rgba(var(--foreground-color), 1); - z-index: 3; + position: sticky; + padding: 1rem 1.5rem; + background: rgba(var(--background-color), 1); + border-bottom: solid 1px rgba(var(--text-color), 0.16); + z-index: 2; } #logo{ display: grid; align-items: center; width: 100%; grid-template-columns: auto 1fr; - gap: 0.6rem 0.6rem; + gap: 0 0.5rem; margin-right: 1rem; h4{ text-transform: capitalize; - font-size: 1.2rem; + font-size: 1rem; font-weight: 600; + margin-top: 0.2rem; } h5{ + font-size: 0.8rem; font-family: 'Roboto', sans-serif; font-weight: 400; } @@ -144,35 +292,43 @@ sm-tabs{ stroke: none; } } +sm-tab-header{ + padding: 0 1.5rem; + background-color: rgba(var(--text-color), 0.06); +} +sm-tab{ + padding: 0.5rem 0.8rem; +} .section{ + display: flex; + flex-direction: column; margin-top: 3rem; - h3 + p{ - margin-top: 1rem; - } + padding: 0 1.5rem; &:first-of-type{ margin-top: 0; } } +.section__header{ + display: flex; + padding: 1rem 0; + justify-content: space-between; +} .card{ padding: 1.5rem; display: flex; flex-direction: column; - width: 20rem; + min-width: 20rem; border-radius: 0.5rem; margin-right: 1.5rem; - border: solid 1px rgba(var(--text-color), 0.2); + background-color: rgba(var(--text-color), 0.06); h3{ font-weight: 500; } } -@media only screen and (min-width: 640px){ - sm-tabs{ - &::part(tab-header), - &::part(panel-container){ - padding: 0 4vw; - } - } - p{ - max-width: 40rem; + +@media screen and (min-width: 640px) { + // for tablet and desktop + sm-popup{ + --width: 24rem; } } \ No newline at end of file diff --git a/Layouts/tabs layout/index.html b/Layouts/tabs layout/index.html index 5df1fea..6b9519f 100644 --- a/Layouts/tabs layout/index.html +++ b/Layouts/tabs layout/index.html @@ -6,200 +6,143 @@ Document + + + - - -
- - Page 1 - -
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

- This is a button - -
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-
-
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

- -
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-
-
- Page 2 - -
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

- -
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-
-
-

Heading

-

- Lorem ipsum dolor sit amet consectetur adipisicing elit. -

- -
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-

Card

-

- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. -

-
-
-
-
-
-
- - - + + + + + Section 1 + Section 2 + + +
+
+
+

Section Heading

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +

+
+ + first option + second option + third option + +
+ +
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+
+
+
+
+

Section Heading

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. +

+
+ + first option + second option + third option + +
+ +
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+

Card

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, officia. +

+
+
+
+
+ + + \ No newline at end of file diff --git a/Layouts/tabs layout/js/components.js b/Layouts/tabs layout/js/components.js deleted file mode 100644 index 30d8c2f..0000000 --- a/Layouts/tabs layout/js/components.js +++ /dev/null @@ -1,2918 +0,0 @@ -//Button - -const smButton = document.createElement('template') -smButton.innerHTML = ` - -
- -
`; -customElements.define('sm-button', - class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smButton.content.cloneNode(true)) - } - static get observedAttributes() { - return ['disabled'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - dispatch = () => { - if (this.getAttribute('disabled') === 'true') { - this.dispatchEvent(new CustomEvent('disabled', { - bubbles: true, - composed: true - })) - } - else { - this.dispatchEvent(new CustomEvent('clicked', { - bubbles: true, - composed: true - })) - } - } - - connectedCallback() { - this.addEventListener('click', (e) => { - this.dispatch() - }) - this.addEventListener('keyup', (e) => { - if (e.code === "Enter" || e.code === "Space") - this.dispatch() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - } - }) - -//Input -const smInput = document.createElement('template') -smInput.innerHTML = ` - - -
-`; -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 = () => { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; - if (this.input.value !== '') { - if (this.animate) - this.inputParent.classList.add('animate-label') - else - this.label.classList.add('hide') - this.clearBtn.classList.remove('hide') - } - else { - if (this.animate) - this.inputParent.classList.remove('animate-label') - else - this.label.classList.remove('hide') - this.clearBtn.classList.add('hide') - } - if (this.valueChanged) { - if (this.input.checkValidity()) { - this.helperText.classList.add('hide') - this.inputParent.style.boxShadow = `` - } - else { - this.helperText.classList.remove('hide') - this.inputParent.style.boxShadow = `0 0 0 0.1rem ${this.computedStyle.getPropertyValue('--error-color')}` - } - } - } - - connectedCallback() { - this.inputParent = this.shadowRoot.querySelector('.input') - this.computedStyle = window.getComputedStyle(this.inputParent) - this.clearBtn = this.shadowRoot.querySelector('.clear') - this.label = this.shadowRoot.querySelector('.label') - this.helperText = this.shadowRoot.querySelector('.helper-text') - this.valueChanged = false; - this.animate = this.hasAttribute('animate') - this.input = this.shadowRoot.querySelector('input') - this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') - if (this.hasAttribute('value')) { - this.input.value = this.getAttribute('value') - this.checkInput() - } - if (this.hasAttribute('helper-text')) { - this.helperText.textContent = this.getAttribute('helper-text') - } - if (this.hasAttribute('type')) { - if (this.getAttribute('type') === 'number') { - this.input.setAttribute('inputmode', 'numeric') - } - else - this.input.setAttribute('type', this.getAttribute('type')) - } - else - this.input.setAttribute('type', 'text') - this.input.addEventListener('keydown', e => { - if (this.getAttribute('type') === 'number') - this.preventNonNumericalInput(e); - }) - this.input.addEventListener('input', e => { - this.checkInput() - }) - this.input.addEventListener('change', e => { - this.valueChanged = true; - if (this.input.checkValidity()) - this.helperText.classList.add('hide') - else - this.helperText.classList.remove('hide') - }) - this.clearBtn.addEventListener('click', e => { - this.input.value = '' - this.checkInput() - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'placeholder') - this.shadowRoot.querySelector('.label').textContent = newValue; - } - } - }) - -// tab-header - -const smTabs = document.createElement('template') -smTabs.innerHTML = ` - -
-
- Nothing to see here -
-
-
- Nothing to see here -
-
-`; - -customElements.define('sm-tabs', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smTabs.content.cloneNode(true)) - this.indicator = this.shadowRoot.querySelector('.indicator'); - this.tabSlot = this.shadowRoot.querySelector('slot[name="tab"]'); - this.panelSlot = this.shadowRoot.querySelector('slot[name="panel"]'); - this.tabHeader = this.shadowRoot.querySelector('.tab-header'); - } - connectedCallback() { - - //animations - let flyInLeft = [ - { - opacity: 0, - transform: 'translateX(-1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyInRight = [ - { - opacity: 0, - transform: 'translateX(1rem)' - }, - { - opacity: 1, - transform: 'none' - } - ], - flyOutLeft = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(-1rem)' - } - ], - flyOutRight = [ - { - opacity: 1, - transform: 'none' - }, - { - opacity: 0, - transform: 'translateX(1rem)' - } - ], - animationOptions = { - duration: 300, - fill: 'forwards', - easing: 'ease' - } - this.prevTab - this.allTabs - - this.shadowRoot.querySelector('slot[name="panel"]').addEventListener('slotchange', () => { - this.shadowRoot.querySelector('slot[name="panel"]').assignedElements().forEach((panel, index) => { - panel.classList.add('hide-completely') - }) - }) - this.shadowRoot.querySelector('slot[name="tab"]').addEventListener('slotchange', () => { - this.allTabs = this.shadowRoot.querySelector('slot[name="tab"]').assignedElements(); - this.shadowRoot.querySelector('slot[name="tab"]').assignedElements().forEach((panel, index) => { - panel.setAttribute('rank', index + 1) - }) - }) - this._targetBodyFlyRight = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInRight, animationOptions) - } - this._targetBodyFlyLeft = (targetBody) => { - targetBody.classList.remove('hide-completely') - targetBody.animate(flyInLeft, animationOptions) - } - this.tabSlot.addEventListener('click', e => { - if (e.target === this.prevTab || !e.target.closest('sm-tab')) - return - if (this.prevTab) - this.prevTab.classList.remove('active') - e.target.classList.add('active') - - e.target.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }) - this.indicator.setAttribute('style', `width: ${e.target.getBoundingClientRect().width}px; transform: translateX(${e.target.getBoundingClientRect().left - e.target.parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - - if (this.prevTab) { - let targetBody = e.target.nextElementSibling, - currentBody = this.prevTab.nextElementSibling; - - if (this.prevTab.getAttribute('rank') < e.target.getAttribute('rank')) { - if (currentBody && !targetBody) - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyRight(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutLeft, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyRight(targetBody) - } - } - } else { - if (currentBody && !targetBody) - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - } - else if (targetBody && !currentBody) { - this._targetBodyFlyLeft(targetBody) - } - else if (currentBody && targetBody) { - currentBody.animate(flyOutRight, animationOptions).onfinish = () => { - currentBody.classList.add('hide-completely') - this._targetBodyFlyLeft(targetBody) - } - } - } - } else { - e.target.nextElementSibling.classList.remove('hide-completely') - } - this.prevTab = e.target; - }) - let resizeObserver = new ResizeObserver(entries => { - entries.forEach((entry) => { - if (this.prevTab) { - let tabDimensions = this.prevTab.getBoundingClientRect(); - this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - }) - }) - resizeObserver.observe(this) - let observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - let activeElement = this.tabSlot.assignedElements().filter(element => { - if (element.classList.contains('active')) - return true - }) - if (activeElement.length) { - let tabDimensions = activeElement[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - activeElement[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - } - else { - this.tabSlot.assignedElements()[0].classList.add('active') - this.panelSlot.assignedElements()[0].classList.remove('hide-completely') - let tabDimensions = this.tabSlot.assignedElements()[0].getBoundingClientRect(); - this.indicator.setAttribute('style', `transform: translateX(${tabDimensions.left - this.tabSlot.assignedElements()[0].parentNode.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) - this.prevTab = this.tabSlot.assignedElements()[0]; - } - } - }) - }, - { threshold: 1.0 }) - observer.observe(this) - if (this.hasAttribute('enable-flick') && this.getAttribute('enable-flick') == 'true') { - let touchStartTime = 0, - touchEndTime = 0, - swipeTimeThreshold = 200, - swipeDistanceThreshold = 20, - startingPointX = 0, - endingPointX = 0, - currentIndex = 0; - this.addEventListener('touchstart', e => { - touchStartTime = e.timeStamp - startingPointX = e.changedTouches[0].clientX - }) - this.panelSlot.addEventListener('touchend', e => { - touchEndTime = e.timeStamp - endingPointX = e.changedTouches[0].clientX - if (touchEndTime - touchStartTime < swipeTimeThreshold) { - currentIndex = this.allTabs.findIndex(element => element.classList.contains('active')) - if (startingPointX > endingPointX && startingPointX - endingPointX > swipeDistanceThreshold && currentIndex < this.allTabs.length) { - this.allTabs[currentIndex + 1].click() - } - else if (startingPointX < endingPointX && endingPointX - startingPointX > swipeDistanceThreshold && currentIndex > 0) { - this.allTabs[currentIndex - 1].click() - } - } - }) - } - } -}) - -// tab -const smTab = document.createElement('template') -smTab.innerHTML = ` - -
- -
-`; - -customElements.define('sm-tab', class extends HTMLElement { - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smTab.content.cloneNode(true)) - } -}) - -//chcekbox - -const smCheckbox = document.createElement('template') -smCheckbox.innerHTML = ` - -` -customElements.define('sm-checkbox', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smCheckbox.content.cloneNode(true)) - - this.checkbox = this.shadowRoot.querySelector('.checkbox'); - this.input = this.shadowRoot.querySelector('input') - - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.getAttribute('checked') - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.checkbox.classList.add('disabled') - this.isDisabled = true - } - else { - this.checkbox.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } - -}) - -//audio - -const smAudio = document.createElement('template') -smAudio.innerHTML = ` - -
- - play - - - - pause - - - -
/
- -
- -`; - -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') - } - } - } -}) - -//switch - -const smSwitch = document.createElement('template') -smSwitch.innerHTML = ` - -` - -customElements.define('sm-switch', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSwitch.content.cloneNode(true)) - this.switch = this.shadowRoot.querySelector('.switch'); - this.input = this.shadowRoot.querySelector('input') - this.isChecked = false - this.isDisabled = false - } - - static get observedAttributes() { - return ['disabled', 'checked'] - } - - get disabled() { - return this.getAttribute('disabled') - } - - set disabled(val) { - this.setAttribute('disabled', val) - } - - get checked() { - return this.isChecked - } - - set checked(value) { - this.setAttribute('checked', value) - } - - dispatch = () => { - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if ((e.code === "Enter" || e.code === "Space") && this.isDisabled == false) { - this.isChecked = !this.isChecked - this.setAttribute('checked', this.isChecked) - } - }) - } - - attributeChangedCallback(name, oldValue, newValue) { - if (oldValue !== newValue) { - if (name === 'disabled') { - if (newValue === 'true') { - this.switch.classList.add('disabled') - this.isDisabled = true - } - else { - this.switch.classList.remove('disabled') - this.isDisabled = false - } - } - if (name === 'checked') { - if (newValue == 'true') { - this.isChecked = true - this.input.checked = true - this.dispatch() - } - else { - this.isChecked = false - this.input.checked = false - this.dispatch() - } - } - } - } -}) - -// select -const smSelect = document.createElement('template') -smSelect.innerHTML = ` - -
-
-
- - - -
-
- -
-
`; -customElements.define('sm-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - - collapse = () => { - this.optionList.animate(this.slideUp, this.animationOptions) - this.optionList.classList.add('hide') - this.chevron.classList.remove('rotate') - this.open = false - } - connectedCallback() { - this.availableOptions - this.optionList = this.shadowRoot.querySelector('.options') - this.chevron = this.shadowRoot.querySelector('.toggle') - let slot = this.shadowRoot.querySelector('.options slot'), - selection = this.shadowRoot.querySelector('.selection'), - previousOption - this.open = false; - this.slideDown = [ - { transform: `translateY(-0.5rem)` }, - { transform: `translateY(0)` } - ], - this.slideUp = [ - { transform: `translateY(0)` }, - { transform: `translateY(-0.5rem)` } - ], - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: 'ease' - } - selection.addEventListener('click', e => { - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - selection.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') - if (!this.open) { - this.optionList.classList.remove('hide') - this.optionList.animate(this.slideDown, this.animationOptions) - this.chevron.classList.add('rotate') - this.open = true - } else { - this.collapse() - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.addEventListener('optionSelected', e => { - if (previousOption !== e.target) { - this.setAttribute('value', e.detail.value) - this.shadowRoot.querySelector('.option-text').textContent = e.detail.text; - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - if (previousOption) { - previousOption.classList.remove('check-selected') - } - previousOption = e.target; - } - if(!e.detail.switching) - this.collapse() - - e.target.classList.add('check-selected') - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - if (this.availableOptions[0]) { - let firstElement = this.availableOptions[0]; - previousOption = firstElement; - firstElement.classList.add('check-selected') - this.setAttribute('value', firstElement.getAttribute('value')) - this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent - this.availableOptions.forEach((element, index) => { - element.setAttribute('data-rank', index + 1); - element.setAttribute('tabindex', "0"); - }) - } - }); - document.addEventListener('mousedown', e => { - if (!this.contains(e.target) && this.open) { - this.collapse() - } - }) - } -}) - -// option -const smOption = document.createElement('template') -smOption.innerHTML = ` - -
- - - - -
`; -customElements.define('sm-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smOption.content.cloneNode(true)) - } - - sendDetails = (switching) => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value'), - switching: switching - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - let validKey = [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight' - ] - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - if (validKey.includes(e.code)) { - e.preventDefault() - this.sendDetails(true) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -// select -const smStripSelect = document.createElement('template') -smStripSelect.innerHTML = ` - -
-
- - Previous - - -
- -
- - Next - - -
-
`; -customElements.define('sm-strip-select', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripSelect.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - scrollLeft = () => { - this.select.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.select.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - connectedCallback() { - let previousOption, - slot = this.shadowRoot.querySelector('slot'); - this.selectContainer = this.shadowRoot.querySelector('.select-container') - this.select = this.shadowRoot.querySelector('.select') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.selectOptions - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.previousArrow.classList.add('hide') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.remove('hide') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.nextArrow.classList.add('hide') - this.nextGradient.classList.add('hide') - } - else { - this.nextArrow.classList.remove('hide') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.selectContainer, - threshold: 0.95 - }) - - const selectObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.selectContainer.getBoundingClientRect().width - } - }) - - selectObserver.observe(this.selectContainer) - this.addEventListener('optionSelected', e => { - if (previousOption === e.target) return; - if (previousOption) - previousOption.classList.remove('active') - e.target.classList.add('active') - e.target.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }) - this.setAttribute('value', e.detail.value) - this.dispatchEvent(new CustomEvent('change', { - bubbles: true, - composed: true - })) - previousOption = e.target; - }) - slot.addEventListener('slotchange', e => { - this.selectOptions = slot.assignedElements() - firstElementObserver.observe(this.selectOptions[0]) - lastElementObserver.observe(this.selectOptions[this.selectOptions.length - 1]) - if (this.selectOptions[0]) { - let firstElement = this.selectOptions[0]; - this.setAttribute('value', firstElement.getAttribute('value')) - firstElement.classList.add('active') - previousOption = firstElement; - } - }); - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -// option -const smStripOption = document.createElement('template') -smStripOption.innerHTML = ` - -
- -
`; -customElements.define('sm-strip-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smStripOption.content.cloneNode(true)) - } - sendDetails = () => { - let optionSelected = new CustomEvent('optionSelected', { - bubbles: true, - composed: true, - detail: { - text: this.textContent, - value: this.getAttribute('value') - } - }) - this.dispatchEvent(optionSelected) - } - - connectedCallback() { - this.addEventListener('click', e => { - this.sendDetails() - }) - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.sendDetails(false) - } - }) - if (this.hasAttribute('default')) { - setTimeout(() => { - this.sendDetails() - }, 0); - } - } -}) - -//popup -const smPopup = document.createElement('template') -smPopup.innerHTML = ` - - -`; -customElements.define('sm-popup', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smPopup.content.cloneNode(true)) - } - - resumeScrolling = () => { - const scrollY = document.body.style.top; - window.scrollTo(0, parseInt(scrollY || '0') * -1); - setTimeout(() => { - document.body.setAttribute('style', `overflow: auto; top: initial`) - }, 300); - } - - show(pinned, popupStack) { - this.pinned = pinned - this.popupStack = popupStack - this.popupContainer.classList.remove('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(0)'; - else - this.popup.style.transform = 'scale(1)'; - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - } - hide() { - this.popupContainer.classList.add('hide') - if (window.innerWidth < 648) - this.popup.style.transform = 'translateY(100%)'; - else - this.popup.style.transform = 'scale(0.9)'; - if (typeof this.popupStack !== 'undefined') { - this.popupStack.pop() - if (this.popupStack.items.length === 0) { - this.resumeScrolling() - } - } - else { - this.resumeScrolling() - } - } - - handleTouchStart = (e) => { - this.touchStartY = e.changedTouches[0].clientY - this.popup.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartY < e.changedTouches[0].clientY) { - this.offset = e.changedTouches[0].clientY - this.touchStartY; - this.touchEndAnimataion = window.requestAnimationFrame(this.movePopup) - } - /*else { - offset = touchStartY - e.changedTouches[0].clientY; - this.popup.style.transform = `translateY(-${offset}px)` - }*/ - } - - handleTouchEnd = (e) => { - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndY = e.changedTouches[0].clientY - this.popup.style.transition = 'transform 0.3s' - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndY - this.touchStartY > this.threshold) { - this.hide() - } - else { - this.show() - } - } - else { - if (this.touchEndY > this.touchStartY) - this.hide() - } - } - - movePopup = () => { - this.popup.style.transform = `translateY(${this.offset}px)` - } - - connectedCallback() { - this.pinned = false - this.popupStack - this.popupContainer = this.shadowRoot.querySelector('.popup-container') - this.popup = this.shadowRoot.querySelector('.popup') - this.offset - this.popupHeader = this.shadowRoot.querySelector('.popup-top') - this.touchStartY = 0 - this.touchEndY = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.popup.getBoundingClientRect().height * 0.3 - this.touchEndAnimataion; - - if (this.hasAttribute('heading')) - this.shadowRoot.querySelector('.heading').textContent = this.getAttribute('heading') - - this.popupContainer.addEventListener('mousedown', e => { - if (e.target === this.popupContainer && !this.pinned) { - this.hide() - } - }) - - this.shadowRoot.querySelector('.close').addEventListener('click', e => { - this.hide() - }) - - this.popupHeader.addEventListener('touchstart', this.handleTouchStart) - this.popupHeader.addEventListener('touchmove', this.handleTouchMove) - this.popupHeader.addEventListener('touchend', this.handleTouchEnd) - } - disconnectedCallback() { - this.popupHeader.removeEventListener('touchstart', this.handleTouchStart) - this.popupHeader.removeEventListener('touchmove', this.handleTouchMove) - this.popupHeader.removeEventListener('touchend', this.handleTouchEnd) - } -}) - -//carousel - -const smCarousel = document.createElement('template') -smCarousel.innerHTML = ` - - -`; - -customElements.define('sm-carousel', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smCarousel.content.cloneNode(true)) - } - - scrollLeft = () => { - this.carousel.scrollBy({ - top: 0, - left: -this.scrollDistance, - behavior: 'smooth' - }) - } - - scrollRight = () => { - this.carousel.scrollBy({ - top: 0, - left: this.scrollDistance, - behavior: 'smooth' - }) - } - - connectedCallback() { - this.carousel = this.shadowRoot.querySelector('.carousel') - this.carouselContainer = this.shadowRoot.querySelector('.carousel-container') - this.carouselSlot = this.shadowRoot.querySelector('slot') - this.nextArrow = this.shadowRoot.querySelector('.next-item') - this.previousArrow = this.shadowRoot.querySelector('.previous-item') - this.nextGradient = this.shadowRoot.querySelector('.right') - this.previousGradient = this.shadowRoot.querySelector('.left') - this.carouselItems - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width/3 - const firstElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.previousArrow.classList.remove('expand') - this.previousGradient.classList.add('hide') - } - else { - this.previousArrow.classList.add('expand') - this.previousGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - const lastElementObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting){ - this.nextArrow.classList.remove('expand') - this.nextGradient.classList.add('hide') - } - else{ - this.nextArrow.classList.add('expand') - this.nextGradient.classList.remove('hide') - } - }, { - root: this.carouselContainer, - threshold: 0.9 - }) - - const carouselObserver = new IntersectionObserver(entries => { - if (entries[0].isIntersecting) { - this.scrollDistance = this.carouselContainer.getBoundingClientRect().width / 3 - } - }) - - carouselObserver.observe(this.carouselContainer) - - this.carouselSlot.addEventListener('slotchange', e => { - this.carouselItems = this.carouselSlot.assignedElements() - firstElementObserver.observe(this.carouselItems[0]) - lastElementObserver.observe(this.carouselItems[this.carouselItems.length - 1]) - }) - - this.addEventListener('keyup', e => { - if (e.code === 'ArrowLeft') - this.scrollRight() - else - this.scrollRight() - }) - - this.nextArrow.addEventListener('click', this.scrollRight) - this.previousArrow.addEventListener('click', this.scrollLeft) - } - - disconnectedCallback() { - this.nextArrow.removeEventListener('click', this.scrollRight) - this.previousArrow.removeEventListener('click', this.scrollLeft) - } -}) - -//notifications - -const smNotifications = document.createElement('template') -smNotifications.innerHTML = ` - -
-
-` - -customElements.define('sm-notifications', class extends HTMLElement{ - constructor() { - super() - this.shadow = this.attachShadow({ mode: 'open' }).append(smNotifications.content.cloneNode(true)) - } - - handleTouchStart = (e) => { - this.notification = e.target.closest('.notification') - this.touchStartX = e.changedTouches[0].clientX - this.notification.style.transition = 'initial' - this.touchStartTime = e.timeStamp - } - - handleTouchMove = (e) => { - if (this.touchStartX < e.changedTouches[0].clientX) { - this.offset = e.changedTouches[0].clientX - this.touchStartX; - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - else { - this.offset = -(this.touchStartX - e.changedTouches[0].clientX); - this.touchEndAnimataion = requestAnimationFrame(this.movePopup) - } - } - - handleTouchEnd = (e) => { - this.notification.style.transition = 'height 0.3s, transform 0.3s, opacity 0.3s' - this.touchEndTime = e.timeStamp - cancelAnimationFrame(this.touchEndAnimataion) - this.touchEndX = e.changedTouches[0].clientX - if (this.touchEndTime - this.touchStartTime > 200) { - if (this.touchEndX - this.touchStartX > this.threshold) { - this.removeNotification(this.notification) - } - else if (this.touchStartX - this.touchEndX > this.threshold) { - this.removeNotification(this.notification, true) - } - else { - this.resetPosition() - } - } - else { - if (this.touchEndX > this.touchStartX) { - this.removeNotification(this.notification) - } - else { - this.removeNotification(this.notification, true) - } - } - } - - movePopup = () => { - this.notification.style.transform = `translateX(${this.offset}px)` - } - - resetPosition = () => { - this.notification.style.transform = `translateX(0)` - } - - push = (messageHeader, messageBody, options) => { - let notification = document.createElement('div'), - composition = ``, - { pinned, type } = options; - notification.classList.add('notification') - if (pinned) - notification.classList.add('pinned') - composition += ` -
-
- ` - if (type === 'error') { - composition += ` - - - - - ` - } - else if (type === 'success') { - composition += ` - - - - ` - } - composition += ` -

${messageHeader}

- - Close - - - -
-

${messageBody}

-
` - notification.innerHTML = composition - this.notificationPanel.prepend(notification) - if (window.innerWidth > 640) { - notification.animate([ - { - transform: `translateX(1rem)`, - opacity: '0' - }, - { - transform: 'translateX(0)', - opacity: '1' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `transform: none;`); - } - } - else { - notification.setAttribute('style', `transform: translateY(0); opacity: 1`) - } - notification.addEventListener('touchstart', this.handleTouchStart) - notification.addEventListener('touchmove', this.handleTouchMove) - notification.addEventListener('touchend', this.handleTouchEnd) - } - - removeNotification = (notification, toLeft) => { - notification.style.height = notification.scrollHeight + 'px'; - if (!this.offset) - this.offset = 0; - - if (toLeft) - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(-100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - else { - notification.animate([ - { - transform: `translateX(${this.offset}px)`, - opacity: '1' - }, - { - transform: `translateX(100%)`, - opacity: '0' - } - ], this.animationOptions).onfinish = () => { - notification.setAttribute('style', `height: 0; margin-bottom: 0`); - } - } - setTimeout( () => { - notification.remove() - }, this.animationOptions.duration*2) - } - - connectedCallback() { - this.notificationPanel = this.shadowRoot.querySelector('.notification-panel') - this.animationOptions = { - duration: 300, - fill: "forwards", - easing: "ease" - } - this.fontSize = Number(window.getComputedStyle(document.body).getPropertyValue('font-size').match(/\d+/)[0]) - this.notification - this.offset - this.touchStartX = 0 - this.touchEndX = 0 - this.touchStartTime = 0 - this.touchEndTime = 0 - this.threshold = this.notificationPanel.getBoundingClientRect().width * 0.3 - this.touchEndAnimataion; - - this.notificationPanel.addEventListener('click', e => { - if (e.target.closest('.close'))( - this.removeNotification(e.target.closest('.notification')) - ) - }) - - const observer = new MutationObserver(mutationList => { - mutationList.forEach(mutation => { - if (mutation.type === 'childList') { - if (mutation.addedNodes.length) { - if (!mutation.addedNodes[0].classList.contains('pinned')) - setTimeout(() => { - this.removeNotification(mutation.addedNodes[0]) - }, 4000); - if (window.innerWidth > 640) - this.notificationPanel.style.padding = '1.5rem 0 3rem 1.5rem'; - else - this.notificationPanel.style.padding = '1rem 1rem 2rem 1rem'; - } - else if (mutation.removedNodes.length && !this.notificationPanel.children.length) { - this.notificationPanel.style.padding = 0; - } - } - }) - }) - observer.observe(this.notificationPanel, { - attributes: true, - childList: true, - subtree: true - }) - } -}) -// sm-menu -const smMenu = document.createElement('template') -smMenu.innerHTML = ` - -
- -
- -
-
`; -customElements.define('sm-menu', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenu.content.cloneNode(true)) - } - static get observedAttributes() { - return ['value'] - } - get value() { - return this.getAttribute('value') - } - set value(val) { - this.setAttribute('value', val) - } - expand = () => { - if (!this.open) { - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - this.optionList.classList.remove('hide') - this.optionList.classList.add('no-transformations') - this.open = true - this.icon.classList.add('focused') - } - } - collapse = () => { - if (this.open) { - this.open = false - this.icon.classList.remove('focused') - this.optionList.classList.add('hide') - this.optionList.classList.remove('no-transformations') - } - } - connectedCallback() { - this.availableOptions - this.containerDimensions - this.optionList = this.shadowRoot.querySelector('.options') - let slot = this.shadowRoot.querySelector('.options slot'), - menu = this.shadowRoot.querySelector('.menu') - this.icon = this.shadowRoot.querySelector('.icon') - this.open = false; - menu.addEventListener('click', e => { - if (!this.open) { - this.expand() - } else { - this.collapse() - } - }) - menu.addEventListener('keydown', e => { - if (e.code === 'ArrowDown' || e.code === 'ArrowRight') { - e.preventDefault() - this.availableOptions[0].focus() - } - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - if (!this.open) { - this.expand() - } else { - this.collapse() - } - } - }) - this.optionList.addEventListener('keydown', e => { - if (e.code === 'ArrowUp' || e.code === 'ArrowRight') { - e.preventDefault() - if (document.activeElement.previousElementSibling) { - document.activeElement.previousElementSibling.focus() - } - } - if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') { - e.preventDefault() - if (document.activeElement.nextElementSibling) - document.activeElement.nextElementSibling.focus() - } - }) - this.optionList.addEventListener('click', e => { - this.collapse() - }) - slot.addEventListener('slotchange', e => { - this.availableOptions = slot.assignedElements() - this.containerDimensions = this.optionList.getBoundingClientRect() - this.menuDimensions = menu.getBoundingClientRect() - if (this.containerDimensions.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - }); - window.addEventListener('mousedown', e => { - if (!this.contains(e.target) && e.button !== 2) { - this.collapse() - } - }) - if (this.hasAttribute('set-context') && this.getAttribute('set-context') === 'true') { - this.parentNode.setAttribute('oncontextmenu', 'return false') - this.parentNode.addEventListener('mouseup', e => { - if (e.button === 2) { - this.expand() - } - }) - } - const intersectionObserver = new IntersectionObserver(entries => { - entries.forEach(entry => { - if (!entry.isIntersecting && this.open) { - if(window.innerHeight - entry.intersectionRect.top < this.containerDimensions.height) - this.optionList.classList.add('moveUp') - else - this.optionList.classList.remove('moveUp') - if (entry.intersectionRect.left > this.containerDimensions.width) { - this.optionList.style.right = 0 - } - else { - this.optionList.style.right = 'auto' - } - } - }) - }, { - threshold: 1 - }) - intersectionObserver.observe(this.optionList) - } -}) - -// option -const smMenuOption = document.createElement('template') -smMenuOption.innerHTML = ` - -
- -
`; -customElements.define('sm-menu-option', class extends HTMLElement { - constructor() { - super() - this.attachShadow({ mode: 'open' }).append(smMenuOption.content.cloneNode(true)) - } - - connectedCallback() { - this.addEventListener('keyup', e => { - if (e.code === 'Enter' || e.code === 'Space') { - e.preventDefault() - this.click() - } - }) - this.setAttribute('tabindex', '0') - } -}) \ No newline at end of file diff --git a/Layouts/tabs layout/js/components.min.js b/Layouts/tabs layout/js/components.min.js new file mode 100644 index 0000000..7078968 --- /dev/null +++ b/Layouts/tabs layout/js/components.min.js @@ -0,0 +1,9 @@ +const smButton=document.createElement("template");smButton.innerHTML="\n\n
\n \n
",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}handleKeyDown(e){this.hasAttribute("disabled")||"Enter"!==e.key&&"Space"!==e.code||(e.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,n){"disabled"===e?(this.removeAttribute("tabindex"),this.setAttribute("aria-disabled","true")):(this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled","false"))}}); +const smCarousel=document.createElement("template");smCarousel.innerHTML='\n\n\n',customElements.define("sm-carousel",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCarousel.content.cloneNode(!0)),this.isAutoPlaying=!1,this.autoPlayInterval=5e3,this.autoPlayTimeout,this.initialTimeout,this.activeSlideNum=0,this.carouselItems,this.indicators,this.showIndicator=!1,this.carousel=this.shadowRoot.querySelector(".carousel"),this.carouselContainer=this.shadowRoot.querySelector(".carousel-container"),this.carouselSlot=this.shadowRoot.querySelector("slot"),this.navButtonRight=this.shadowRoot.querySelector(".carousel__button--right"),this.navButtonLeft=this.shadowRoot.querySelector(".carousel__button--left"),this.indicatorsContainer=this.shadowRoot.querySelector(".indicators"),this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.handleIndicatorClick=this.handleIndicatorClick.bind(this),this.showSlide=this.showSlide.bind(this),this.nextSlide=this.nextSlide.bind(this),this.autoPlay=this.autoPlay.bind(this),this.startAutoPlay=this.startAutoPlay.bind(this),this.stopAutoPlay=this.stopAutoPlay.bind(this)}static get observedAttributes(){return["indicator","autoplay","interval"]}scrollLeft(){this.carousel.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.carousel.scrollBy({left:this.scrollDistance,behavior:"smooth"})}showSlide(t){this.carousel.scrollTo({left:this.carouselItems[t].getBoundingClientRect().left-this.carousel.getBoundingClientRect().left+this.carousel.scrollLeft,behavior:"smooth"})}nextSlide(){if(!this.carouselItems)return;let t=this.activeSlideNum+1{this.autoPlay()},this.autoPlayInterval))}startAutoPlay(){this.setAttribute("autoplay","")}stopAutoPlay(){this.removeAttribute("autoplay")}createIndicator(t){let n=document.createElement("div");return n.classList.add("indicator"),n.dataset.rank=t,n}handleIndicatorClick(t){if(t.target.closest(".indicator")){const n=parseInt(t.target.closest(".indicator").dataset.rank);this.activeSlideNum!==n&&this.showSlide(n)}}handleKeyDown(t){"ArrowLeft"===t.code?this.scrollRight():"ArrowRight"===t.code&&this.scrollRight()}connectedCallback(){let t=document.createDocumentFragment();this.carouselSlot.addEventListener("slotchange",n=>{this.carouselItems=this.carouselSlot.assignedElements(),this.carouselItems.forEach(t=>i.observe(t)),this.carouselItems.length>0?(o.observe(this.carouselItems[0]),e.observe(this.carouselItems[this.carouselItems.length-1])):(navButtonLeft.classList.add("hide"),navButtonRight.classList.add("hide"),o.disconnect(),e.disconnect()),this.showIndicator&&(this.indicatorsContainer.innerHTML="",this.carouselItems.forEach((n,i)=>{t.append(this.createIndicator(i)),n.dataset.rank=i}),this.indicatorsContainer.append(t),this.indicators=this.indicatorsContainer.children)});const n={threshold:.9,root:this},i=new IntersectionObserver(t=>{t.forEach(t=>{if(this.showIndicator){const n=parseInt(t.target.dataset.rank);t.isIntersecting?(this.indicators[n].classList.add("active"),this.activeSlideNum=n):this.indicators[n].classList.remove("active")}})},n),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonLeft.classList.add("hide"):this.navButtonLeft.classList.remove("hide")})},n),e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonRight.classList.add("hide"):this.navButtonRight.classList.remove("hide")})},n),s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const n=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*n.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.addEventListener("keydown",this.handleKeyDown),this.navButtonRight.addEventListener("click",this.scrollRight),this.navButtonLeft.addEventListener("click",this.scrollLeft),this.indicatorsContainer.addEventListener("click",this.handleIndicatorClick)}attributeChangedCallback(t,n,i){n!==i&&("indicator"===t&&(this.showIndicator=this.hasAttribute("indicator")),"autoplay"===t&&(this.hasAttribute("autoplay")?this.initialTimeout=setTimeout(()=>{this.isAutoPlaying=!0,this.autoPlay()},this.autoPlayInterval):(this.isAutoPlaying=!1,clearTimeout(this.autoPlayTimeout),clearTimeout(this.initialTimeout))),"interval"===t&&(this.hasAttribute("interval")&&""!==this.getAttribute("interval").trim()?this.autoPlayInterval=Math.abs(parseInt(this.getAttribute("interval").trim())):this.autoPlayInterval=5e3))}disconnectedCallback(){this.navButtonRight.removeEventListener("click",this.scrollRight),this.navButtonLeft.removeEventListener("click",this.scrollLeft),this.indicatorsContainer.removeEventListener("click",this.handleIndicatorClick)}}); +const smForm=document.createElement("template");smForm.innerHTML='\n \n\t
\n\t\t\n\t
\n',customElements.define("sm-form",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smForm.content.cloneNode(!0)),this.form=this.shadowRoot.querySelector("form"),this.formElements,this.requiredElements,this.submitButton,this.resetButton,this.allRequiredValid=!1,this.debounce=this.debounce.bind(this),this.handleInput=this.handleInput.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.reset=this.reset.bind(this)}debounce(t,e){let n=null;return(...s)=>{window.clearTimeout(n),n=window.setTimeout(()=>{t.apply(null,s)},e)}}handleInput(t){this.allRequiredValid=this.requiredElements.every(t=>t.isValid),this.submitButton&&(this.allRequiredValid?this.submitButton.disabled=!1:this.submitButton.disabled=!0)}handleKeydown(t){"Enter"===t.key&&this.allRequiredValid&&this.submitButton.click()}reset(){this.formElements.forEach(t=>t.reset())}connectedCallback(){const t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",t=>{this.formElements=[...this.querySelectorAll("sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio")],this.requiredElements=this.formElements.filter(t=>t.hasAttribute("required")),this.submitButton=t.target.assignedElements().find(t=>"primary"===t.getAttribute("variant")||"submit"===t.getAttribute("type")),this.resetButton=t.target.assignedElements().find(t=>"reset"===t.getAttribute("type")),this.resetButton&&this.resetButton.addEventListener("click",this.reset)}),this.addEventListener("input",this.debounce(this.handleInput,100)),this.addEventListener("keydown",this.debounce(this.handleKeydown,100))}disconnectedCallback(){this.removeEventListener("input",this.debounce(this.handleInput,100)),this.removeEventListener("keydown",this.debounce(this.handleKeydown,100))}}); +const smInput=document.createElement("template");smInput.innerHTML='\n\n
\n \n \n
\n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),this.inputParent=this.shadowRoot.querySelector(".input"),this.input=this.shadowRoot.querySelector("input"),this.clearBtn=this.shadowRoot.querySelector(".clear"),this.label=this.shadowRoot.querySelector(".label"),this.feedbackText=this.shadowRoot.querySelector(".feedback-text"),this._helperText,this._errorText,this.isRequired=!1,this.validationFunction,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.focusOut=this.focusOut.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get isValid(){const t=this.input.checkValidity();let e=!0;return this.customValidation&&(e=this.validationFunction(this.input.value)),t&&e}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required")),this.isValid?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n \n ${this._errorText}\n `)),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):this.label.classList.remove("hide"))}connectedCallback(){this.animate=this.hasAttribute("animate"),this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.reset)}attributeChangedCallback(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.feedbackText.textContent="* required"):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); +const smMenu=document.createElement("template");smMenu.innerHTML='\n\n
\n \n
\n \n
\n
',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n
\n \n
',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}}); +const smNotifications=document.createElement("template");smNotifications.innerHTML='\n\n
\n',customElements.define("sm-notifications",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smNotifications.content.cloneNode(!0)),this.notificationPanel=this.shadowRoot.querySelector(".notification-panel"),this.animationOptions={duration:300,fill:"forwards",easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)"},this.push=this.push.bind(this),this.createNotification=this.createNotification.bind(this),this.removeNotification=this.removeNotification.bind(this),this.clearAll=this.clearAll.bind(this)}randString(n){let t="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let o=0;o${o}
\n

${n}

\n `,i&&(e.classList.add("pinned"),a+='\n \n '),e.innerHTML=a,e}push(n,t={}){const i=this.createNotification(n,t);return this.notificationPanel.append(i),i.animate([{transform:"translateY(1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animationOptions),i.id}removeNotification(n){n.animate([{transform:"none",opacity:"1"},{transform:"translateY(0.5rem)",opacity:"0"}],this.animationOptions).onfinish=(()=>{n.remove()})}clearAll(){Array.from(this.notificationPanel.children).forEach(n=>{this.removeNotification(n)})}connectedCallback(){this.notificationPanel.addEventListener("click",n=>{n.target.closest(".close")&&this.removeNotification(n.target.closest(".notification"))});const n=new MutationObserver(n=>{n.forEach(n=>{"childList"===n.type&&n.addedNodes.length&&!n.addedNodes[0].classList.contains("pinned")&&setTimeout(()=>{this.removeNotification(n.addedNodes[0])},5e3)})});n.observe(this.notificationPanel,{childList:!0})}}); +const smPopup=document.createElement("template");smPopup.innerHTML='\n\n\n',customElements.define("sm-popup",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smPopup.content.cloneNode(!0)),this.allowClosing=!1,this.isOpen=!1,this.pinned=!1,this.popupStack,this.offset,this.touchStartY=0,this.touchEndY=0,this.touchStartTime=0,this.touchEndTime=0,this.touchEndAnimataion,this.popupContainer=this.shadowRoot.querySelector(".popup-container"),this.popup=this.shadowRoot.querySelector(".popup"),this.popupBodySlot=this.shadowRoot.querySelector(".popup-body slot"),this.popupHeader=this.shadowRoot.querySelector(".popup-top"),this.resumeScrolling=this.resumeScrolling.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.handleTouchStart=this.handleTouchStart.bind(this),this.handleTouchMove=this.handleTouchMove.bind(this),this.handleTouchEnd=this.handleTouchEnd.bind(this),this.movePopup=this.movePopup.bind(this)}static get observedAttributes(){return["open"]}get open(){return this.isOpen}resumeScrolling(){const t=document.body.style.top;window.scrollTo(0,-1*parseInt(t||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}show(t={}){const{pinned:e=!1,popupStack:n}=t;return n&&(this.popupStack=n),this.popupStack&&!this.hasAttribute("open")&&(this.popupStack.push({popup:this,permission:e}),this.popupStack.items.length>1&&this.popupStack.items[this.popupStack.items.length-2].popup.classList.add("stacked"),this.dispatchEvent(new CustomEvent("popupopened",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.setAttribute("open",""),this.pinned=e,this.isOpen=!0),this.popupContainer.classList.remove("hide"),this.popup.style.transform="none",document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.popupStack}hide(){window.innerWidth<640?this.popup.style.transform="translateY(100%)":this.popup.style.transform="translateY(3rem)",this.popupContainer.classList.add("hide"),this.removeAttribute("open"),void 0!==this.popupStack?(this.popupStack.pop(),this.popupStack.items.length?this.popupStack.items[this.popupStack.items.length-1].popup.classList.remove("stacked"):this.resumeScrolling()):this.resumeScrolling(),this.forms.length&&setTimeout(()=>{this.forms.forEach(t=>t.reset())},300),setTimeout(()=>{this.dispatchEvent(new CustomEvent("popupclosed",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.isOpen=!1},300)}handleTouchStart(t){this.touchStartY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.1s",this.touchStartTime=t.timeStamp}handleTouchMove(t){this.touchStartYthis.movePopup()))}handleTouchEnd(t){if(this.touchEndTime=t.timeStamp,cancelAnimationFrame(this.touchEndAnimataion),this.touchEndY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.3s",this.threshold=.3*this.popup.getBoundingClientRect().height,this.touchEndTime-this.touchStartTime>200)if(this.touchEndY-this.touchStartY>this.threshold){if(this.pinned)return void this.show();this.hide()}else this.show();else if(this.touchEndY>this.touchStartY){if(this.pinned)return void this.show();this.hide()}}movePopup(){this.popup.style.transform=`translateY(${this.offset}px)`}connectedCallback(){this.popupBodySlot.addEventListener("slotchange",()=>{this.forms=this.querySelectorAll("sm-form")}),this.popupContainer.addEventListener("mousedown",t=>{t.target!==this.popupContainer||this.pinned||(this.pinned?this.show():this.hide())});const t=new ResizeObserver(t=>{for(let e of t)if(e.contentBoxSize){Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.threshold=.3*e.blockSize.height}else this.threshold=.3*e.contentRect.height});t.observe(this),this.popupHeader.addEventListener("touchstart",t=>{this.handleTouchStart(t)},{passive:!0}),this.popupHeader.addEventListener("touchmove",t=>{this.handleTouchMove(t)},{passive:!0}),this.popupHeader.addEventListener("touchend",t=>{this.handleTouchEnd(t)},{passive:!0})}disconnectedCallback(){this.popupHeader.removeEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.popupHeader.removeEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.popupHeader.removeEventListener("touchend",this.handleTouchEnd,{passive:!0}),resizeObserver.unobserve()}attributeChangedCallback(t,e,n){"open"===t&&this.hasAttribute("open")&&this.show()}}); +const smTabHeader=document.createElement("template");smTabHeader.innerHTML='\n\n
\n
\n \n
\n
\n
\n',customElements.define("sm-tab-header",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabHeader.content.cloneNode(!0)),this.prevTab,this.allTabs,this.activeTab,this.indicator=this.shadowRoot.querySelector(".indicator"),this.tabSlot=this.shadowRoot.querySelector("slot"),this.tabHeader=this.shadowRoot.querySelector(".tab-header"),this.changeTab=this.changeTab.bind(this),this.handleClick=this.handleClick.bind(this),this.handlePanelChange=this.handlePanelChange.bind(this)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedtab${this.target}`,{bubbles:!0,detail:{index:parseInt(t)}}))}moveIndiactor(t){this.indicator.setAttribute("style",`width: ${t.width}px; transform: translateX(${t.left-this.tabHeader.getBoundingClientRect().left+this.tabHeader.scrollLeft}px)`)}changeTab(t){t!==this.prevTab&&t.closest("sm-tab")&&(this.prevTab&&this.prevTab.classList.remove("active"),t.classList.add("active"),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.moveIndiactor(t.getBoundingClientRect()),this.prevTab=t,this.activeTab=t)}handleClick(t){t.target.closest("sm-tab")&&(this.changeTab(t.target),this.fireEvent(t.target.dataset.index))}handlePanelChange(t){this.changeTab(this.allTabs[t.detail.index])}connectedCallback(){if(!this.hasAttribute("target")||""===this.getAttribute("target").value)return;this.target=this.getAttribute("target"),this.tabSlot.addEventListener("slotchange",()=>{this.allTabs=this.tabSlot.assignedElements(),this.allTabs.forEach((t,n)=>{t.dataset.index=n})}),this.addEventListener("click",this.handleClick),document.addEventListener(`switchedpanel${this.target}`,this.handlePanelChange);let t=new ResizeObserver(t=>{t.forEach(t=>{if(this.prevTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}})});t.observe(this);let n=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting)if(this.indicator.style.transition="none",this.activeTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}else{this.allTabs[0].classList.add("active");let t=this.allTabs[0].getBoundingClientRect();this.moveIndiactor(t),this.fireEvent(0),this.prevTab=this.tabSlot.assignedElements()[0],this.activeTab=this.prevTab}})},{threshold:1});n.observe(this)}disconnectedCallback(){this.removeEventListener("click",this.handleClick),document.removeEventListener(`switchedpanel${this.target}`,this.handlePanelChange)}});const smTab=document.createElement("template");smTab.innerHTML='\n\n
\n\n
\n',customElements.define("sm-tab",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smTab.content.cloneNode(!0))}});const smTabPanels=document.createElement("template");smTabPanels.innerHTML='\n\n
\n Nothing to see here.\n
\n',customElements.define("sm-tab-panels",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabPanels.content.cloneNode(!0)),this.isTransitioning=!1,this.panelContainer=this.shadowRoot.querySelector(".panel-container"),this.panelSlot=this.shadowRoot.querySelector("slot"),this.handleTabChange=this.handleTabChange.bind(this)}handleTabChange(t){this.isTransitioning=!0,this.panelContainer.scrollTo({left:this.allPanels[t.detail.index].getBoundingClientRect().left-this.panelContainer.getBoundingClientRect().left+this.panelContainer.scrollLeft,behavior:"smooth"}),setTimeout(()=>{this.isTransitioning=!1},300)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedpanel${this.id}`,{bubbles:!0,detail:{index:parseInt(t)}}))}connectedCallback(){this.panelSlot.addEventListener("slotchange",()=>{this.allPanels=this.panelSlot.assignedElements(),this.allPanels.forEach((n,e)=>{n.dataset.index=e,t.observe(n)})}),document.addEventListener(`switchedtab${this.id}`,this.handleTabChange);const t=new IntersectionObserver(t=>{t.forEach(t=>{!this.isTransitioning&&t.isIntersecting&&this.fireEvent(t.target.dataset.index)})},{threshold:.6})}disconnectedCallback(){intersectionObserver.disconnect(),document.removeEventListener(`switchedtab${this.id}`,this.handleTabChange)}}); +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/Layouts/tabs layout/js/helper.js b/Layouts/tabs layout/js/helper.js deleted file mode 100644 index a7c51ee..0000000 --- a/Layouts/tabs layout/js/helper.js +++ /dev/null @@ -1,133 +0,0 @@ -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) -}) -let themeToggler = document.getElementById("theme_toggle") -if (localStorage.theme === "dark") { - darkTheme() - themeToggler.checked = true; -} else { - lightTheme() - themeToggler.checked = false; -} - -function lightTheme() { - document.body.setAttribute("data-theme", "light"); -} - -function darkTheme() { - document.body.setAttribute("data-theme", "dark"); -} -themeToggler.addEventListener("change", () => { - if (themeToggler.checked) { - darkTheme() - localStorage.setItem("theme", "dark"); - } else { - lightTheme() - 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(index) { - let newIndex = index ? index : 1 - return this.items[this.items.length - index]; - } -} -let popupStack = new Stack(), - zIndex = 10; -function showPopup(popup, permission) { - let thisPopup = document.getElementById(popup); - document.body.setAttribute('style', `overflow: hidden; top: -${window.scrollY}px`) - popupStack.push({ thisPopup, permission }) - thisPopup.show(permission, popupStack) - zIndex++; - thisPopup.setAttribute('style', `z-index: ${zIndex}`) - return thisPopup; -} -function setAttributes(el, attrs) { - for (var key in attrs) { - el.setAttribute(key, attrs[key]); - } -} -// displays a popup for asking permission. Use this instead of JS confirm -let confirmation = 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); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(false); - } - }) -} - -// 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'); - if (defaultVal) - input.value = defaultVal; - showPopup('prompt') - input.focus() - input.addEventListener('keyup', e => { - if (e.key === 'Enter') { - resolve(input.value); - hidePopup() - } - }) - popup.querySelector('#prompt_message').textContent = message; - popup.querySelector('.submit-btn').onclick = () => { - hidePopup() - resolve(input.value); - } - popup.querySelector('.cancel-btn').onclick = () => { - hidePopup() - resolve(null); - } - }) -} - -function formatedTime(time) { - let timeFrag = new Date(parseInt(time)).toString().split(' '), - day = timeFrag[0], - month = timeFrag[1], - date = timeFrag[2], - year = timeFrag[3], - hours = timeFrag[4].slice(0, timeFrag[4].lastIndexOf(':')), - finalTime = ''; - parseInt(hours.split(':')[0]) > 12 ? finalTime = 'PM' : finalTime = 'AM' - return `${hours} ${finalTime} ${day} ${date} ${month} ${year}` -} - -function copyToClipboard(parent) { - let toast = document.getElementById('textCopied'), - textToCopy = parent.querySelector('.copy').textContent; - navigator.clipboard.writeText(textToCopy) - toast.classList.remove('hide'); - setTimeout(() => { - toast.classList.add('hide'); - }, 2000) -} \ No newline at end of file diff --git a/Layouts/tabs layout/js/main_UI.js b/Layouts/tabs layout/js/main_UI.js new file mode 100644 index 0000000..b4d9afd --- /dev/null +++ b/Layouts/tabs layout/js/main_UI.js @@ -0,0 +1,282 @@ +// Global variables +const domRefs = {}; +const appPages = ['home'] + + +//Checks for internet connection status +if (!navigator.onLine) + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { sound: true } + ); +window.addEventListener("offline", () => { + notify( + "There seems to be a problem connecting to the internet, Please check you internet connection.", + "error", + { pinned: true, sound: true } + ); +}); +window.addEventListener("online", () => { + getRef("notification_drawer").clearAll(); + notify("We are back online.", "success"); +}); + +// Use instead of document.getElementById +function getRef(elementId) { + if (!domRefs.hasOwnProperty(elementId)) { + domRefs[elementId] = { + count: 1, + ref: null, + }; + return document.getElementById(elementId); + } else { + if (domRefs[elementId].count < 3) { + domRefs[elementId].count = domRefs[elementId].count + 1; + return document.getElementById(elementId); + } else { + if (!domRefs[elementId].ref) + domRefs[elementId].ref = document.getElementById(elementId); + return domRefs[elementId].ref; + } + } +} + +// returns dom with specified element +function createElement(tagName, obj) { + const { className, textContent, innerHTML, attributes = {} } = obj + const elem = document.createElement(tagName) + for (let attribute in attributes) { + elem.setAttribute(attribute, attributes[attribute]) + } + if (className) + elem.className = className + if (textContent) + elem.textContent = textContent + if (innerHTML) + elem.innerHTML = innerHTML + return elem +} + +// Use when a function needs to be executed after user finishes changes +const debounce = (callback, wait) => { + let timeoutId = null; + return (...args) => { + window.clearTimeout(timeoutId); + timeoutId = window.setTimeout(() => { + callback.apply(null, args); + }, wait); + }; +} + +// Limits the rate of function execution +let timerId; +function throttle(func, delay) { + // If setTimeout is already scheduled, no need to do anything + if (timerId) { + return; + } + + // Schedule a setTimeout after delay seconds + timerId = setTimeout(function () { + func(); + + // Once setTimeout function execution is finished, timerId = undefined so that in + // the next scroll event function execution can be scheduled by the setTimeout + timerId = undefined; + }, delay); +} + +// 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; + +async function showPopup(popup, pinned) { + zIndex++ + getRef(popup).setAttribute('style', `z-index: ${zIndex}`) + popupStack = getRef(popup).show({ pinned, popupStack }) + return getRef(popup); +} + +// hides the popup or modal +function hidePopup() { + if (popupStack.peek() === undefined) + return; + popupStack.peek().popup.hide() +} + +// displays a popup for asking permission. Use this instead of JS confirm +let getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => { + return new Promise(resolve => { + showPopup('confirmation_popup', true) + getRef('confirm_title').textContent = title; + getRef('confirm_message').textContent = message; + let cancelButton = getRef('confirmation_popup').children[2].children[0], + submitButton = getRef('confirmation_popup').children[2].children[1] + submitButton.textContent = confirmText + cancelButton.textContent = cancelText + submitButton.onclick = () => { + hidePopup() + resolve(true); + } + cancelButton.onclick = () => { + hidePopup() + resolve(false); + } + }) +} + +// displays a popup for asking user input. Use this instead of JS prompt +async function getPromptInput(title, message = '', showText = true, trueBtn = "Ok", falseBtn = "Cancel") { + showPopup('prompt_popup', true) + getRef('prompt_title').textContent = title; + let input = getRef('prompt_input'); + input.setAttribute("placeholder", message) + let buttons = getRef('prompt_popup').querySelectorAll("sm-button"); + if (showText) + input.setAttribute("type", "text") + else + input.setAttribute("type", "password") + input.focusIn() + buttons[0].textContent = falseBtn; + buttons[1].textContent = trueBtn; + return new Promise((resolve, reject) => { + buttons[0].onclick = () => { + hidePopup() + return; + } + buttons[1].onclick = () => { + let value = input.value; + hidePopup() + resolve(value) + } + }) +} + +//Function for displaying toast notifications. pass in error for mode param if you want to show an error. +function notify(message, mode, options = {}) { + const { pinned = false, sound } = options + if (mode === "error") console.error(message); + let icon + switch (mode) { + case 'success': + icon = `` + break; + case 'error': + icon = `` + break; + } + getRef("notification_drawer").push(message, { pinned, icon }); + if (navigator.onLine && sound) { + getRef("notification_sound").currentTime = 0; + getRef("notification_sound").play(); + } +} + +const currentYear = new Date().getFullYear(); +function getFormatedTime(time, relative) { + try { + if (String(time).indexOf("_")) time = String(time).split("_")[0]; + const intTime = parseInt(time); + if (String(intTime).length < 13) time *= 1000; + let timeFrag = new Date(intTime).toString().split(" "), + day = timeFrag[0], + month = timeFrag[1], + date = timeFrag[2], + year = timeFrag[3], + minutes = new Date(intTime).getMinutes(), + hours = new Date(intTime).getHours(), + currentTime = new Date().toString().split(" "); + + minutes = minutes < 10 ? `0${minutes}` : minutes; + let finalHours = ``; + if (hours > 12) finalHours = `${hours - 12}:${minutes}`; + else if (hours === 0) finalHours = `12:${minutes}`; + else finalHours = `${hours}:${minutes}`; + + finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`; + if (relative) { + return `${date} ${month} ${year}`; + } else return `${finalHours} ${month} ${date} ${year}`; + } catch (e) { + console.error(e); + return time; + } +} + +window.addEventListener('hashchange', e => showPage(window.location.hash)) +window.addEventListener("load", () => { + document.body.classList.remove('hide-completely') + showPage(window.location.hash) + // document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = validateAddr) + document.addEventListener('keyup', (e) => { + if (e.code === 'Escape') { + hidePopup() + } + }) + document.addEventListener("pointerdown", (e) => { + if (e.target.closest("button, sm-button:not([disabled]), .interact")) { + createRipple(e, e.target.closest("button, sm-button, .interact")); + } + }); + document.addEventListener('copy', () => { + notify('copied', 'success') + }) +}); + +function createRipple(event, target) { + const circle = document.createElement("span"); + const diameter = Math.max(target.clientWidth, target.clientHeight); + const radius = diameter / 2; + const targetDimensions = target.getBoundingClientRect(); + circle.style.width = circle.style.height = `${diameter}px`; + circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`; + circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`; + circle.classList.add("ripple"); + const rippleAnimation = circle.animate( + [ + { + transform: "scale(3)", + opacity: 0, + }, + ], + { + duration: 1000, + fill: "forwards", + easing: "ease-out", + } + ); + target.append(circle); + rippleAnimation.onfinish = () => { + circle.remove(); + }; +} + +function showPage(targetPage) { + let pageId + if (targetPage === '') { + pageId = 'overview_page' + } + else { + pageId = targetPage.includes('#') ? targetPage.split('#')[1] : targetPage + } + if(!appPages.includes(pageId)) return + document.querySelector('.page:not(.hide-completely)').classList.add('hide-completely') + getRef(pageId).classList.remove('hide-completely') +} \ No newline at end of file diff --git a/components/components.min.js b/components/components.min.js new file mode 100644 index 0000000..c7a4723 --- /dev/null +++ b/components/components.min.js @@ -0,0 +1,21 @@ +const smButton=document.createElement("template");smButton.innerHTML="\n\n
\n \n
",customElements.define("sm-button",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smButton.content.cloneNode(!0))}static get observedAttributes(){return["disabled"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}handleKeyDown(e){this.hasAttribute("disabled")||"Enter"!==e.key&&"Space"!==e.code||(e.preventDefault(),this.click())}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","button"),this.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(e,t,n){"disabled"===e?(this.removeAttribute("tabindex"),this.setAttribute("aria-disabled","true")):(this.setAttribute("tabindex","0"),this.setAttribute("aria-disabled","false"))}}); +const smCarousel=document.createElement("template");smCarousel.innerHTML='\n\n\n',customElements.define("sm-carousel",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCarousel.content.cloneNode(!0)),this.isAutoPlaying=!1,this.autoPlayInterval=5e3,this.autoPlayTimeout,this.initialTimeout,this.activeSlideNum=0,this.carouselItems,this.indicators,this.showIndicator=!1,this.carousel=this.shadowRoot.querySelector(".carousel"),this.carouselContainer=this.shadowRoot.querySelector(".carousel-container"),this.carouselSlot=this.shadowRoot.querySelector("slot"),this.navButtonRight=this.shadowRoot.querySelector(".carousel__button--right"),this.navButtonLeft=this.shadowRoot.querySelector(".carousel__button--left"),this.indicatorsContainer=this.shadowRoot.querySelector(".indicators"),this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.handleIndicatorClick=this.handleIndicatorClick.bind(this),this.showSlide=this.showSlide.bind(this),this.nextSlide=this.nextSlide.bind(this),this.autoPlay=this.autoPlay.bind(this),this.startAutoPlay=this.startAutoPlay.bind(this),this.stopAutoPlay=this.stopAutoPlay.bind(this)}static get observedAttributes(){return["indicator","autoplay","interval"]}scrollLeft(){this.carousel.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.carousel.scrollBy({left:this.scrollDistance,behavior:"smooth"})}showSlide(t){this.carousel.scrollTo({left:this.carouselItems[t].getBoundingClientRect().left-this.carousel.getBoundingClientRect().left+this.carousel.scrollLeft,behavior:"smooth"})}nextSlide(){if(!this.carouselItems)return;let t=this.activeSlideNum+1{this.autoPlay()},this.autoPlayInterval))}startAutoPlay(){this.setAttribute("autoplay","")}stopAutoPlay(){this.removeAttribute("autoplay")}createIndicator(t){let n=document.createElement("div");return n.classList.add("indicator"),n.dataset.rank=t,n}handleIndicatorClick(t){if(t.target.closest(".indicator")){const n=parseInt(t.target.closest(".indicator").dataset.rank);this.activeSlideNum!==n&&this.showSlide(n)}}handleKeyDown(t){"ArrowLeft"===t.code?this.scrollRight():"ArrowRight"===t.code&&this.scrollRight()}connectedCallback(){let t=document.createDocumentFragment();this.carouselSlot.addEventListener("slotchange",n=>{this.carouselItems=this.carouselSlot.assignedElements(),this.carouselItems.forEach(t=>i.observe(t)),this.carouselItems.length>0?(o.observe(this.carouselItems[0]),e.observe(this.carouselItems[this.carouselItems.length-1])):(navButtonLeft.classList.add("hide"),navButtonRight.classList.add("hide"),o.disconnect(),e.disconnect()),this.showIndicator&&(this.indicatorsContainer.innerHTML="",this.carouselItems.forEach((n,i)=>{t.append(this.createIndicator(i)),n.dataset.rank=i}),this.indicatorsContainer.append(t),this.indicators=this.indicatorsContainer.children)});const n={threshold:.9,root:this},i=new IntersectionObserver(t=>{t.forEach(t=>{if(this.showIndicator){const n=parseInt(t.target.dataset.rank);t.isIntersecting?(this.indicators[n].classList.add("active"),this.activeSlideNum=n):this.indicators[n].classList.remove("active")}})},n),o=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonLeft.classList.add("hide"):this.navButtonLeft.classList.remove("hide")})},n),e=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?this.navButtonRight.classList.add("hide"):this.navButtonRight.classList.remove("hide")})},n),s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const n=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*n.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.addEventListener("keydown",this.handleKeyDown),this.navButtonRight.addEventListener("click",this.scrollRight),this.navButtonLeft.addEventListener("click",this.scrollLeft),this.indicatorsContainer.addEventListener("click",this.handleIndicatorClick)}attributeChangedCallback(t,n,i){n!==i&&("indicator"===t&&(this.showIndicator=this.hasAttribute("indicator")),"autoplay"===t&&(this.hasAttribute("autoplay")?this.initialTimeout=setTimeout(()=>{this.isAutoPlaying=!0,this.autoPlay()},this.autoPlayInterval):(this.isAutoPlaying=!1,clearTimeout(this.autoPlayTimeout),clearTimeout(this.initialTimeout))),"interval"===t&&(this.hasAttribute("interval")&&""!==this.getAttribute("interval").trim()?this.autoPlayInterval=Math.abs(parseInt(this.getAttribute("interval").trim())):this.autoPlayInterval=5e3))}disconnectedCallback(){this.navButtonRight.removeEventListener("click",this.scrollRight),this.navButtonLeft.removeEventListener("click",this.scrollLeft),this.indicatorsContainer.removeEventListener("click",this.handleIndicatorClick)}}); +const smCheckbox=document.createElement("template");smCheckbox.innerHTML='\n\n',customElements.define("sm-checkbox",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCheckbox.content.cloneNode(!0)),this.checkbox=this.shadowRoot.querySelector(".checkbox"),this.reset=this.reset.bind(this),this.dispatch=this.dispatch.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this)}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(e){e?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(e){this.setAttribute("value",e)}get value(){return this.getAttribute("value")}reset(){this.removeAttribute("checked")}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0}))}handleKeyDown(e){"Space"===e.code&&(e.preventDefault(),this.click())}handleClick(e){this.toggleAttribute("checked")}connectedCallback(){this.hasAttribute("disabled")||this.setAttribute("tabindex","0"),this.setAttribute("role","checkbox"),this.hasAttribute("checked")||this.setAttribute("aria-checked","false"),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("click",this.handleClick)}attributeChangedCallback(e,t,n){t!==n&&("checked"===e?(this.setAttribute("aria-checked",this.hasAttribute("checked")),this.dispatch()):"disabled"===e&&(this.hasAttribute("disabled")?this.removeAttribute("tabindex"):this.setAttribute("tabindex","0")))}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("change",this.handleClick)}}); +const smCopy=document.createElement("template");smCopy.innerHTML='\n\n\n
\n

\n \n
\n',customElements.define("sm-copy",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smCopy.content.cloneNode(!0)),this.copyContent=this.shadowRoot.querySelector(".copy-content"),this.copyButton=this.shadowRoot.querySelector(".copy-button"),this.copy=this.copy.bind(this)}static get observedAttributes(){return["value"]}set value(n){this.setAttribute("value",n)}get value(){return this.getAttribute("value")}fireEvent(){this.dispatchEvent(new CustomEvent("copy",{composed:!0,bubbles:!0,cancelable:!0}))}copy(){navigator.clipboard.writeText(this.copyContent.textContent).then(n=>this.fireEvent()).catch(n=>console.error(n))}connectedCallback(){this.copyButton.addEventListener("click",this.copy)}attributeChangedCallback(n,t,o){"value"===n&&(this.copyContent.textContent=o)}disconnectedCallback(){this.copyButton.removeEventListener("click",this.copy)}}); +const fileInput=document.createElement("template");fileInput.innerHTML='\n \t\n\t
    \n \t\n',customElements.define("file-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(fileInput.content.cloneNode(!0)),this.input=this.shadowRoot.querySelector("input"),this.fileInput=this.shadowRoot.querySelector(".file-input"),this.filesPreviewWraper=this.shadowRoot.querySelector(".files-preview-wrapper"),this.reflectedAttributes=["accept","multiple","capture"],this.reset=this.reset.bind(this),this.formatBytes=this.formatBytes.bind(this),this.createFilePreview=this.createFilePreview.bind(this),this.handleChange=this.handleChange.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}static get observedAttributes(){return["accept","multiple","capture"]}get files(){return this.input.files}set accept(t){this.setAttribute("accept",t)}set multiple(t){t?this.setAttribute("mutiple",""):this.removeAttribute("mutiple")}set capture(t){this.setAttribute("capture",t)}set value(t){this.input.value=t}get isValid(){return""!==this.input.value}reset(){this.input.value="",this.filesPreviewWraper.innerHTML=""}formatBytes(t,e=2){if(0===t)return"0 Bytes";const n=0>e?0:e,i=Math.floor(Math.log(t)/Math.log(1024));return parseFloat((t/Math.pow(1024,i)).toFixed(n))+" "+["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"][i]}createFilePreview(t){const e=document.createElement("li"),{name:n,size:i}=t;return e.className="file-preview",e.innerHTML=`\n\t\t\t
    ${n}
    \n
    ${this.formatBytes(i)}
    \n\t\t`,e}handleChange(t){this.filesPreviewWraper.innerHTML="";const e=document.createDocumentFragment();Array.from(t.target.files).forEach(t=>{e.append(this.createFilePreview(t))}),this.filesPreviewWraper.append(e)}handleKeyDown(t){"Enter"!==t.key&&"Space"!==t.code||(t.preventDefault(),this.input.click())}connectedCallback(){this.setAttribute("role","button"),this.setAttribute("aria-label","File upload"),this.input.addEventListener("change",this.handleChange),this.fileInput.addEventListener("keydown",this.handleKeyDown)}attributeChangedCallback(t){this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t))}disconnectedCallback(){this.input.removeEventListener("change",this.handleChange),this.fileInput.removeEventListener("keydown",this.handleKeyDown)}}); +const smForm=document.createElement("template");smForm.innerHTML='\n \n\t
    \n\t\t\n\t
    \n',customElements.define("sm-form",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smForm.content.cloneNode(!0)),this.form=this.shadowRoot.querySelector("form"),this.formElements,this.requiredElements,this.submitButton,this.resetButton,this.allRequiredValid=!1,this.debounce=this.debounce.bind(this),this.handleInput=this.handleInput.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.reset=this.reset.bind(this)}debounce(t,e){let n=null;return(...s)=>{window.clearTimeout(n),n=window.setTimeout(()=>{t.apply(null,s)},e)}}handleInput(t){this.allRequiredValid=this.requiredElements.every(t=>t.isValid),this.submitButton&&(this.allRequiredValid?this.submitButton.disabled=!1:this.submitButton.disabled=!0)}handleKeydown(t){"Enter"===t.key&&this.allRequiredValid&&this.submitButton.click()}reset(){this.formElements.forEach(t=>t.reset())}connectedCallback(){const t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",t=>{this.formElements=[...this.querySelectorAll("sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio")],this.requiredElements=this.formElements.filter(t=>t.hasAttribute("required")),this.submitButton=t.target.assignedElements().find(t=>"primary"===t.getAttribute("variant")||"submit"===t.getAttribute("type")),this.resetButton=t.target.assignedElements().find(t=>"reset"===t.getAttribute("type")),this.resetButton&&this.resetButton.addEventListener("click",this.reset)}),this.addEventListener("input",this.debounce(this.handleInput,100)),this.addEventListener("keydown",this.debounce(this.handleKeydown,100))}disconnectedCallback(){this.removeEventListener("input",this.debounce(this.handleInput,100)),this.removeEventListener("keydown",this.debounce(this.handleKeydown,100))}}); +const hamburgerMenu=document.createElement("template");hamburgerMenu.innerHTML='\n\n
    \n\n';class HamburgerMenu extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(hamburgerMenu.content.cloneNode(!0)),this.resumeScrolling=this.resumeScrolling.bind(this),this.open=this.open.bind(this),this.close=this.close.bind(this),this.sideNav=this.shadowRoot.querySelector(".side-nav"),this.backdrop=this.shadowRoot.querySelector(".backdrop"),this.isOpen=!1,this.animeOptions={duration:300,easing:"ease"}}static get observedAttributes(){return["open"]}resumeScrolling(){const n=document.body.style.top;window.scrollTo(0,-1*parseInt(n||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}open(){this.isOpen||(document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.classList.remove("hide"),this.sideNav.classList.add("reveal"),this.backdrop.classList.remove("hide"),this.backdrop.animate([{opacity:0},{opacity:1}],this.animeOptions).onfinish=(()=>{this.isOpen=!0,this.setAttribute("open","")}))}close(){this.isOpen&&(this.sideNav.classList.remove("reveal"),this.backdrop.animate([{opacity:1},{opacity:0}],this.animeOptions).onfinish=(()=>{this.backdrop.classList.add("hide"),this.classList.add("hide"),this.isOpen=!1,this.removeAttribute("open")}))}connectedCallback(){this.backdrop.addEventListener("click",this.close);const n=new ResizeObserver(n=>{window.innerWidth<640&&this.isOpen?this.classList.remove("hide"):this.classList.add("hide"),window.innerWidth>640&&this.classList.remove("hide")});n.observe(this)}disconnectedCallback(){this.backdrop.removeEventListener("click",this.close)}attributeChangedCallback(n,e,t){"open"===n&&this.hasAttribute("open")&&this.open()}}window.customElements.define("hamburger-menu",HamburgerMenu); +const smInput=document.createElement("template");smInput.innerHTML='\n\n
    \n \n \n
    \n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),this.inputParent=this.shadowRoot.querySelector(".input"),this.input=this.shadowRoot.querySelector("input"),this.clearBtn=this.shadowRoot.querySelector(".clear"),this.label=this.shadowRoot.querySelector(".label"),this.feedbackText=this.shadowRoot.querySelector(".feedback-text"),this._helperText,this._errorText,this.isRequired=!1,this.validationFunction,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.focusOut=this.focusOut.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get isValid(){const t=this.input.checkValidity();let e=!0;return this.customValidation&&(e=this.validationFunction(this.input.value)),t&&e}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required")),this.isValid?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n \n ${this._errorText}\n `)),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):this.label.classList.remove("hide"))}connectedCallback(){this.animate=this.hasAttribute("animate"),this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.reset)}attributeChangedCallback(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.feedbackText.textContent="* required"):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); +const smMenu=document.createElement("template");smMenu.innerHTML='\n\n
    \n \n
    \n \n
    \n
    ',customElements.define("sm-menu",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smMenu.content.cloneNode(!0)),this.isOpen=!1,this.availableOptions,this.containerDimensions,this.animOptions={duration:200,easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.menu=this.shadowRoot.querySelector(".menu"),this.icon=this.shadowRoot.querySelector(".icon"),this.expand=this.expand.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClickoutSide=this.handleClickoutSide.bind(this)}static get observedAttributes(){return["value"]}get value(){return this.getAttribute("value")}set value(n){this.setAttribute("value",n)}expand(){this.isOpen||(this.optionList.classList.remove("hide"),this.optionList.animate([{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animOptions).onfinish=(()=>{this.isOpen=!0,this.icon.classList.add("focused")}))}collapse(){this.isOpen&&(this.optionList.animate([{transform:"none",opacity:"1"},{transform:window.innerWidth<640?"translateY(1.5rem)":"translateY(-1rem)",opacity:"0"}],this.animOptions).onfinish=(()=>{this.isOpen=!1,this.icon.classList.remove("focused"),this.optionList.classList.add("hide")}))}toggle(){this.isOpen?this.collapse():this.expand()}handleKeyDown(n){n.target===this?"ArrowDown"===n.code?(n.preventDefault(),this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.toggle()):"ArrowUp"===n.code?(n.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===n.code?(n.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus()):"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),n.target.click())}handleClickoutSide(n){this.contains(n.target)||2===n.button||this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.setAttribute("aria-label","dropdown menu");const n=this.shadowRoot.querySelector(".options slot");n.addEventListener("slotchange",n=>{this.availableOptions=n.target.assignedElements(),this.containerDimensions=this.optionList.getBoundingClientRect()}),this.addEventListener("click",this.toggle),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mousedown",this.handleClickoutSide)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mousedown",this.handleClickoutSide)}});const menuOption=document.createElement("template");menuOption.innerHTML='\n\n
    \n \n
    ',customElements.define("menu-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(menuOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.addEventListener("keyup",n=>{"Enter"!==n.code&&"Space"!==n.code||(n.preventDefault(),this.click())})}}); +const smNotifications=document.createElement("template");smNotifications.innerHTML='\n\n
    \n',customElements.define("sm-notifications",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smNotifications.content.cloneNode(!0)),this.notificationPanel=this.shadowRoot.querySelector(".notification-panel"),this.animationOptions={duration:300,fill:"forwards",easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)"},this.push=this.push.bind(this),this.createNotification=this.createNotification.bind(this),this.removeNotification=this.removeNotification.bind(this),this.clearAll=this.clearAll.bind(this)}randString(n){let t="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let o=0;o${o}\n

    ${n}

    \n `,i&&(e.classList.add("pinned"),a+='\n \n '),e.innerHTML=a,e}push(n,t={}){const i=this.createNotification(n,t);return this.notificationPanel.append(i),i.animate([{transform:"translateY(1rem)",opacity:"0"},{transform:"none",opacity:"1"}],this.animationOptions),i.id}removeNotification(n){n.animate([{transform:"none",opacity:"1"},{transform:"translateY(0.5rem)",opacity:"0"}],this.animationOptions).onfinish=(()=>{n.remove()})}clearAll(){Array.from(this.notificationPanel.children).forEach(n=>{this.removeNotification(n)})}connectedCallback(){this.notificationPanel.addEventListener("click",n=>{n.target.closest(".close")&&this.removeNotification(n.target.closest(".notification"))});const n=new MutationObserver(n=>{n.forEach(n=>{"childList"===n.type&&n.addedNodes.length&&!n.addedNodes[0].classList.contains("pinned")&&setTimeout(()=>{this.removeNotification(n.addedNodes[0])},5e3)})});n.observe(this.notificationPanel,{childList:!0})}}); +const smPopup=document.createElement("template");smPopup.innerHTML='\n\n\n',customElements.define("sm-popup",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smPopup.content.cloneNode(!0)),this.allowClosing=!1,this.isOpen=!1,this.pinned=!1,this.popupStack,this.offset,this.touchStartY=0,this.touchEndY=0,this.touchStartTime=0,this.touchEndTime=0,this.touchEndAnimataion,this.popupContainer=this.shadowRoot.querySelector(".popup-container"),this.popup=this.shadowRoot.querySelector(".popup"),this.popupBodySlot=this.shadowRoot.querySelector(".popup-body slot"),this.popupHeader=this.shadowRoot.querySelector(".popup-top"),this.resumeScrolling=this.resumeScrolling.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.handleTouchStart=this.handleTouchStart.bind(this),this.handleTouchMove=this.handleTouchMove.bind(this),this.handleTouchEnd=this.handleTouchEnd.bind(this),this.movePopup=this.movePopup.bind(this)}static get observedAttributes(){return["open"]}get open(){return this.isOpen}resumeScrolling(){const t=document.body.style.top;window.scrollTo(0,-1*parseInt(t||"0")),setTimeout(()=>{document.body.style.overflow="auto",document.body.style.top="initial"},300)}show(t={}){const{pinned:e=!1,popupStack:n}=t;return n&&(this.popupStack=n),this.popupStack&&!this.hasAttribute("open")&&(this.popupStack.push({popup:this,permission:e}),this.popupStack.items.length>1&&this.popupStack.items[this.popupStack.items.length-2].popup.classList.add("stacked"),this.dispatchEvent(new CustomEvent("popupopened",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.setAttribute("open",""),this.pinned=e,this.isOpen=!0),this.popupContainer.classList.remove("hide"),this.popup.style.transform="none",document.body.style.overflow="hidden",document.body.style.top=`-${window.scrollY}px`,this.popupStack}hide(){window.innerWidth<640?this.popup.style.transform="translateY(100%)":this.popup.style.transform="translateY(3rem)",this.popupContainer.classList.add("hide"),this.removeAttribute("open"),void 0!==this.popupStack?(this.popupStack.pop(),this.popupStack.items.length?this.popupStack.items[this.popupStack.items.length-1].popup.classList.remove("stacked"):this.resumeScrolling()):this.resumeScrolling(),this.forms.length&&setTimeout(()=>{this.forms.forEach(t=>t.reset())},300),setTimeout(()=>{this.dispatchEvent(new CustomEvent("popupclosed",{bubbles:!0,detail:{popup:this,popupStack:this.popupStack}})),this.isOpen=!1},300)}handleTouchStart(t){this.touchStartY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.1s",this.touchStartTime=t.timeStamp}handleTouchMove(t){this.touchStartYthis.movePopup()))}handleTouchEnd(t){if(this.touchEndTime=t.timeStamp,cancelAnimationFrame(this.touchEndAnimataion),this.touchEndY=t.changedTouches[0].clientY,this.popup.style.transition="transform 0.3s",this.threshold=.3*this.popup.getBoundingClientRect().height,this.touchEndTime-this.touchStartTime>200)if(this.touchEndY-this.touchStartY>this.threshold){if(this.pinned)return void this.show();this.hide()}else this.show();else if(this.touchEndY>this.touchStartY){if(this.pinned)return void this.show();this.hide()}}movePopup(){this.popup.style.transform=`translateY(${this.offset}px)`}connectedCallback(){this.popupBodySlot.addEventListener("slotchange",()=>{this.forms=this.querySelectorAll("sm-form")}),this.popupContainer.addEventListener("mousedown",t=>{t.target!==this.popupContainer||this.pinned||(this.pinned?this.show():this.hide())});const t=new ResizeObserver(t=>{for(let e of t)if(e.contentBoxSize){Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.threshold=.3*e.blockSize.height}else this.threshold=.3*e.contentRect.height});t.observe(this),this.popupHeader.addEventListener("touchstart",t=>{this.handleTouchStart(t)},{passive:!0}),this.popupHeader.addEventListener("touchmove",t=>{this.handleTouchMove(t)},{passive:!0}),this.popupHeader.addEventListener("touchend",t=>{this.handleTouchEnd(t)},{passive:!0})}disconnectedCallback(){this.popupHeader.removeEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.popupHeader.removeEventListener("touchmove",this.handleTouchMove,{passive:!0}),this.popupHeader.removeEventListener("touchend",this.handleTouchEnd,{passive:!0}),resizeObserver.unobserve()}attributeChangedCallback(t,e,n){"open"===t&&this.hasAttribute("open")&&this.show()}}); +const smRadio=document.createElement("template");smRadio.innerHTML='\n\n
    \n \n \n \n
    \n',window.customElements.define("sm-radio",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smRadio.content.cloneNode(!0)),this.radio=this.shadowRoot.querySelector(".radio"),this.reset=this.reset.bind(this),this.dispatchChangeEvent=this.dispatchChangeEvent.bind(this),this.dispatchGroupEvent=this.dispatchGroupEvent.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleClick=this.handleClick.bind(this),this.handleRadioGroup=this.handleRadioGroup.bind(this),this.uniqueId,this.options}static get observedAttributes(){return["value","disabled","checked"]}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.hasAttribute("checked")}set checked(t){t?this.setAttribute("checked",""):this.removeAttribute("checked")}set value(t){this.setAttribute("value",t)}get value(){return this.getAttribute("value")}reset(){this.removeAttribute("checked")}dispatchChangeEvent(){this.dispatchEvent(new CustomEvent("change",this.options))}dispatchGroupEvent(){this.hasAttribute("name")&&""!==this.getAttribute("name").trim()&&this.dispatchEvent(new CustomEvent(`changed${this.getAttribute("name")}`,this.options))}handleKeyDown(t){"Space"===t.code&&(t.preventDefault(),this.handleClick())}handleClick(){this.hasAttribute("checked")||(this.setAttribute("checked",""),this.dispatchGroupEvent())}handleRadioGroup(t){t.detail.uid!==this.uniqueId&&this.reset()}randString(t){let e="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n\n *{\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n margin: 0;\n }\n \n :host{\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n }\n label{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 100%;\n outline: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n :host(:not([disabled])) label:focus-visible{\n -webkit-box-shadow: 0 0 0 0.1rem var(--accent-color);\n box-shadow: 0 0 0 0.1rem var(--accent-color);\n }\n :host([disabled]) {\n cursor: not-allowed;\n opacity: 0.6;\n pointer-events: none;\n }\n .switch {\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 2.4rem;\n flex-shrink: 0;\n margin-left: auto;\n padding: 0.2rem;\n cursor: pointer;\n border-radius: 2rem;\n }\n \n input {\n display: none;\n }\n \n .track {\n position: absolute;\n left: 0;\n right: 0;\n height: 1.4rem;\n -webkit-transition: background 0.3s;\n -o-transition: background 0.3s;\n transition: background 0.3s;\n background: rgba(var(--text-color), 0.4);\n -webkit-box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n box-shadow: 0 0.1rem 0.3rem #00000040 inset;\n border-radius: 1rem;\n }\n \n .switch:active .button::after,\n .switch:focus .button::after{\n opacity: 1\n }\n .switch:focus-visible .button::after{\n opacity: 1\n }\n \n .button::after{\n content: \'\';\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n height: 2.6rem;\n width: 2.6rem;\n background: rgba(var(--text-color), 0.2);\n border-radius: 2rem;\n opacity: 0;\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n }\n \n .button {\n position: relative;\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n height: 1rem;\n width: 1rem;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n border-radius: 1rem;\n -webkit-box-shadow: 0 0.1rem 0.4rem #00000060;\n box-shadow: 0 0.1rem 0.4rem #00000060;\n -webkit-transition: -webkit-transform 0.3s;\n transition: -webkit-transform 0.3s;\n -o-transition: transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s;\n border: solid 0.3rem white;\n }\n \n input:checked ~ .button {\n -webkit-transform: translateX(100%);\n -ms-transform: translateX(100%);\n transform: translateX(100%);\n }\n \n input:checked ~ .track {\n background: var(--accent-color);\n }\n\n',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,this.dispatch=this.dispatch.bind(this)}static get observedAttributes(){return["disabled","checked"]}get disabled(){return this.isDisabled}set disabled(n){n?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get checked(){return this.isChecked}set checked(n){n?this.setAttribute("checked",""):this.removeAttribute("checked")}dispatch(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this.isChecked}}))}connectedCallback(){this.addEventListener("keydown",n=>{"Space"!==n.code||this.isDisabled||(n.preventDefault(),this.input.click())}),this.input.addEventListener("click",n=>{this.input.checked?this.checked=!0:this.checked=!1,this.dispatch()})}attributeChangedCallback(n,t,e){t!==e&&("disabled"===n?this.hasAttribute("disabled")?this.disabled=!0:this.disabled=!1:"checked"===n&&(this.hasAttribute("checked")?(this.isChecked=!0,this.input.checked=!0):(this.isChecked=!1,this.input.checked=!1)))}}); +const smSelect=document.createElement("template");smSelect.innerHTML='\n\n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    ',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),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.availableOptions,this.previousOption,this.isOpen=!1,this.slideDown=[{transform:"translateY(-0.5rem)",opacity:0},{transform:"translateY(0)",opacity:1}],this.slideUp=[{transform:"translateY(0)",opacity:1},{transform:"translateY(-0.5rem)",opacity:0}],this.animationOptions={duration:300,fill:"forwards",easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.chevron=this.shadowRoot.querySelector(".toggle"),this.selection=this.shadowRoot.querySelector(".selection"),this.selectedOptionText=this.shadowRoot.querySelector(".selected-option-text")}static get observedAttributes(){return["value","disabled"]}get value(){return this.getAttribute("value")}set value(e){this.setAttribute("value",e)}reset(){}open(){this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.isOpen=!0}collapse(){this.chevron.classList.remove("rotate"),this.optionList.animate(this.slideUp,this.animationOptions).onfinish=(()=>{this.optionList.classList.add("hide"),this.isOpen=!1})}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(e){"ArrowUp"===e.code?(e.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===e.code&&(e.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}handleOptionSelection(e){this.previousOption!==document.activeElement&&(this.value=document.activeElement.getAttribute("value"),this.selectedOptionText.textContent=document.activeElement.textContent,this.fireEvent(),this.previousOption&&this.previousOption.classList.remove("check-selected"),document.activeElement.classList.add("check-selected"),this.previousOption=document.activeElement)}handleClick(e){e.target===this?this.toggle():(this.handleOptionSelection(),this.collapse())}handleKeydown(e){e.target===this?this.isOpen&&"ArrowDown"===e.code?(e.preventDefault(),this.availableOptions[0].focus(),this.handleOptionSelection(e)):"Enter"!==e.code&&"Space"!==e.code||(e.preventDefault(),this.toggle()):(this.handleOptionsNavigation(e),this.handleOptionSelection(e),"Enter"!==e.code&&"Space"!==e.code||(e.preventDefault(),this.collapse()))}handleClickOutside(e){this.isOpen&&!this.contains(e.target)&&this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.hasAttribute("disabled")||this.selection.setAttribute("tabindex","0");let e=this.shadowRoot.querySelector("slot");e.addEventListener("slotchange",t=>{if(this.availableOptions=e.assignedElements(),this.availableOptions[0]){let e=this.availableOptions[0];this.previousOption=e,e.classList.add("check-selected"),this.value=e.getAttribute("value"),this.selectedOptionText.textContent=e.textContent,this.availableOptions.forEach(e=>{e.setAttribute("tabindex","0")})}}),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeydown),document.addEventListener("mousedown",this.handleClickOutside)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeydown),document.removeEventListener("mousedown",this.handleClickOutside)}attributeChangedCallback(e){"disabled"===e&&(this.hasAttribute("disabled")?this.selection.removeAttribute("tabindex"):this.selection.setAttribute("tabindex","0"))}});const smOption=document.createElement("template");smOption.innerHTML='\n\n
    \n \n \n
    ',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");spinner.innerHTML='\n\n\n\n';class SquareLoader extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(spinner.content.cloneNode(!0))}}window.customElements.define("sm-spinner",SquareLoader); +const stripSelect=document.createElement("template");stripSelect.innerHTML='\n\n
    \n
    \n \n
    \n \n
    \n \n
    \n
    \n\n',customElements.define("strip-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(stripSelect.content.cloneNode(!0)),this.stripSelect=this.shadowRoot.querySelector(".strip-select"),this.slottedOptions,this._value,this.scrollDistance,this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.fireEvent=this.fireEvent.bind(this)}get value(){return this._value}scrollLeft(){this.stripSelect.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.stripSelect.scrollBy({left:this.scrollDistance,behavior:"smooth"})}fireEvent(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this._value}}))}connectedCallback(){this.setAttribute("role","listbox");const t=this.shadowRoot.querySelector("slot"),e=this.shadowRoot.querySelector(".cover--left"),n=this.shadowRoot.querySelector(".cover--right"),i=this.shadowRoot.querySelector(".nav-button--left"),o=this.shadowRoot.querySelector(".nav-button--right");t.addEventListener("slotchange",s=>{const l=t.assignedElements();l.forEach(t=>{t.hasAttribute("selected")&&(t.setAttribute("active",""),this._value=t.value)}),this.hasAttribute("multiline")||(l.length>0?(r.observe(t.assignedElements()[0]),a.observe(t.assignedElements()[t.assignedElements().length-1])):(i.classList.add("hide"),o.classList.add("hide"),e.classList.add("hide"),n.classList.add("hide"),r.disconnect(),a.disconnect()))});const s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const e=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*e.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.stripSelect.addEventListener("option-clicked",e=>{this._value!==e.target.value&&(this._value=e.target.value,t.assignedElements().forEach(t=>t.removeAttribute("active")),e.target.setAttribute("active",""),e.target.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.fireEvent())});const r=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?(i.classList.add("hide"),e.classList.add("hide")):(i.classList.remove("hide"),e.classList.remove("hide"))})},{threshold:.9,root:this}),a=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?(o.classList.add("hide"),n.classList.add("hide")):(o.classList.remove("hide"),n.classList.remove("hide"))})},{threshold:.9,root:this});i.addEventListener("click",this.scrollLeft),o.addEventListener("click",this.scrollRight)}disconnectedCallback(){navButtonLeft.removeEventListener("click",this.scrollLeft),navButtonRight.removeEventListener("click",this.scrollRight)}});const stripOption=document.createElement("template");stripOption.innerHTML='\n\n\n',customElements.define("strip-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(stripOption.content.cloneNode(!0)),this._value,this.radioButton=this.shadowRoot.querySelector("input"),this.fireEvent=this.fireEvent.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}get value(){return this._value}fireEvent(){this.dispatchEvent(new CustomEvent("option-clicked",{bubbles:!0,composed:!0,detail:{value:this._value}}))}handleKeyDown(t){"Enter"!==t.key&&"Space"!==t.key||this.fireEvent()}connectedCallback(){this.setAttribute("role","option"),this.setAttribute("tabindex","0"),this._value=this.getAttribute("value"),this.addEventListener("click",this.fireEvent),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){this.removeEventListener("click",this.fireEvent),this.removeEventListener("keydown",this.handleKeyDown)}}); +const smTabHeader=document.createElement("template");smTabHeader.innerHTML='\n\n
    \n
    \n \n
    \n
    \n
    \n',customElements.define("sm-tab-header",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabHeader.content.cloneNode(!0)),this.prevTab,this.allTabs,this.activeTab,this.indicator=this.shadowRoot.querySelector(".indicator"),this.tabSlot=this.shadowRoot.querySelector("slot"),this.tabHeader=this.shadowRoot.querySelector(".tab-header"),this.changeTab=this.changeTab.bind(this),this.handleClick=this.handleClick.bind(this),this.handlePanelChange=this.handlePanelChange.bind(this)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedtab${this.target}`,{bubbles:!0,detail:{index:parseInt(t)}}))}moveIndiactor(t){this.indicator.setAttribute("style",`width: ${t.width}px; transform: translateX(${t.left-this.tabHeader.getBoundingClientRect().left+this.tabHeader.scrollLeft}px)`)}changeTab(t){t!==this.prevTab&&t.closest("sm-tab")&&(this.prevTab&&this.prevTab.classList.remove("active"),t.classList.add("active"),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.moveIndiactor(t.getBoundingClientRect()),this.prevTab=t,this.activeTab=t)}handleClick(t){t.target.closest("sm-tab")&&(this.changeTab(t.target),this.fireEvent(t.target.dataset.index))}handlePanelChange(t){this.changeTab(this.allTabs[t.detail.index])}connectedCallback(){if(!this.hasAttribute("target")||""===this.getAttribute("target").value)return;this.target=this.getAttribute("target"),this.tabSlot.addEventListener("slotchange",()=>{this.allTabs=this.tabSlot.assignedElements(),this.allTabs.forEach((t,n)=>{t.dataset.index=n})}),this.addEventListener("click",this.handleClick),document.addEventListener(`switchedpanel${this.target}`,this.handlePanelChange);let t=new ResizeObserver(t=>{t.forEach(t=>{if(this.prevTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}})});t.observe(this);let n=new IntersectionObserver(t=>{t.forEach(t=>{if(t.isIntersecting)if(this.indicator.style.transition="none",this.activeTab){let t=this.activeTab.getBoundingClientRect();this.moveIndiactor(t)}else{this.allTabs[0].classList.add("active");let t=this.allTabs[0].getBoundingClientRect();this.moveIndiactor(t),this.fireEvent(0),this.prevTab=this.tabSlot.assignedElements()[0],this.activeTab=this.prevTab}})},{threshold:1});n.observe(this)}disconnectedCallback(){this.removeEventListener("click",this.handleClick),document.removeEventListener(`switchedpanel${this.target}`,this.handlePanelChange)}});const smTab=document.createElement("template");smTab.innerHTML='\n\n
    \n\n
    \n',customElements.define("sm-tab",class extends HTMLElement{constructor(){super(),this.shadow=this.attachShadow({mode:"open"}).append(smTab.content.cloneNode(!0))}});const smTabPanels=document.createElement("template");smTabPanels.innerHTML='\n\n
    \n Nothing to see here.\n
    \n',customElements.define("sm-tab-panels",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTabPanels.content.cloneNode(!0)),this.isTransitioning=!1,this.panelContainer=this.shadowRoot.querySelector(".panel-container"),this.panelSlot=this.shadowRoot.querySelector("slot"),this.handleTabChange=this.handleTabChange.bind(this)}handleTabChange(t){this.isTransitioning=!0,this.panelContainer.scrollTo({left:this.allPanels[t.detail.index].getBoundingClientRect().left-this.panelContainer.getBoundingClientRect().left+this.panelContainer.scrollLeft,behavior:"smooth"}),setTimeout(()=>{this.isTransitioning=!1},300)}fireEvent(t){this.dispatchEvent(new CustomEvent(`switchedpanel${this.id}`,{bubbles:!0,detail:{index:parseInt(t)}}))}connectedCallback(){this.panelSlot.addEventListener("slotchange",()=>{this.allPanels=this.panelSlot.assignedElements(),this.allPanels.forEach((n,e)=>{n.dataset.index=e,t.observe(n)})}),document.addEventListener(`switchedtab${this.id}`,this.handleTabChange);const t=new IntersectionObserver(t=>{t.forEach(t=>{!this.isTransitioning&&t.isIntersecting&&this.fireEvent(t.target.dataset.index)})},{threshold:.6})}disconnectedCallback(){intersectionObserver.disconnect(),document.removeEventListener(`switchedtab${this.id}`,this.handleTabChange)}}); +const tagsInput=document.createElement("template");tagsInput.innerHTML='\n \n
    \n \n

    \n
    \n',customElements.define("tags-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(tagsInput.content.cloneNode(!0)),this.input=this.shadowRoot.querySelector("input"),this.tagsWrapper=this.shadowRoot.querySelector(".tags-wrapper"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["placeholder","limit"],this.limit=void 0,this.tags=new Set,this.reset=this.reset.bind(this),this.handleInput=this.handleInput.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.handleClick=this.handleClick.bind(this),this.removeTag=this.removeTag.bind(this)}static get observedAttributes(){return["placeholder","limit"]}get value(){return[...this.tags].join()}focusIn(){this.input.focus()}reset(){for(this.input.value="",this.tags.clear();this.input.previousElementSibling;)this.input.previousElementSibling.remove()}handleInput(t){const e=t.target.value.trim().length;t.target.setAttribute("size",e||"3"),e?this.placeholder.classList.add("hide"):e||this.tags.size||this.placeholder.classList.remove("hide")}handleKeydown(t){if(","!==t.key&&"/"!==t.key||t.preventDefault(),""!==t.target.value.trim()){if("Enter"===t.key||","===t.key||"/"===t.key||"Space"===t.code){const e=t.target.value.trim();if(this.tags.has(e))this.tagsWrapper.querySelector(`[data-value="${e}"]`).animate([{backgroundColor:"initial"},{backgroundColor:"var(--accent-color)"},{backgroundColor:"initial"}],{duration:300,easing:"ease"});else{const t=document.createElement("span");t.dataset.value=e,t.className="tag",t.innerHTML=`\n ${e}\n \n `,this.input.before(t),this.tags.add(e)}if(t.target.value="",t.target.setAttribute("size","3"),this.limit&&this.limitthis.tags.size&&(this.input.readOnly=!1)}handleClick(t){t.target.closest(".tag")?this.removeTag(t.target.closest(".tag")):this.input.focus()}removeTag(t){this.tags.delete(t.dataset.value),t.remove(),this.tags.size||this.placeholder.classList.remove("hide")}connectedCallback(){this.input.addEventListener("input",this.handleInput),this.input.addEventListener("keydown",this.handleKeydown),this.tagsWrapper.addEventListener("click",this.handleClick)}attributeChangedCallback(t,e,n){"placeholder"===t&&(this.placeholder.textContent=n),"limit"===t&&(this.limit=parseInt(n))}disconnectedCallback(){this.input.removeEventListener("input",this.handleInput),this.input.removeEventListener("keydown",this.handleKeydown),this.tagsWrapper.removeEventListener("click",this.handleClick)}}); +const smTextarea=document.createElement("template");smTextarea.innerHTML='\n\n\n',customElements.define("sm-textarea",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTextarea.content.cloneNode(!0)),this.textarea=this.shadowRoot.querySelector("textarea"),this.textareaBox=this.shadowRoot.querySelector(".textarea"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["disabled","required","readonly","rows","minlength","maxlength"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["disabled","value","placeholder","required","readonly","rows","minlength","maxlength"]}get value(){return this.textarea.value}set value(e){this.setAttribute("value",e),this.fireEvent()}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get isValid(){return this.textarea.checkValidity()}reset(){this.setAttribute("value","")}focusIn(){this.textarea.focus()}fireEvent(){let e=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(e)}checkInput(){this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder")&&(""!==this.textarea.value?this.placeholder.classList.add("hide"):this.placeholder.classList.remove("hide"))}connectedCallback(){this.textarea.addEventListener("input",e=>{this.textareaBox.dataset.value=this.textarea.value,this.checkInput()})}attributeChangedCallback(e,t,n){this.reflectedAttributes.includes(e)?this.hasAttribute(e)?this.textarea.setAttribute(e,this.getAttribute(e)?this.getAttribute(e):""):this.textContent.removeAttribute(e):"placeholder"===e?this.placeholder.textContent=this.getAttribute("placeholder"):"value"===e&&(this.textarea.value=n,this.textareaBox.dataset.value=n,this.checkInput())}}); +const textField=document.createElement("template");textField.innerHTML='\n\n
    \n
    \n
    \n \n Edit\n \n \n \n Save\n \n \n
    \n
    \n',customElements.define("text-field",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(textField.content.cloneNode(!0)),this.textField=this.shadowRoot.querySelector(".text-field"),this.textContainer=this.textField.children[0],this.iconsContainer=this.textField.children[1],this.editButton=this.textField.querySelector(".edit-button"),this.saveButton=this.textField.querySelector(".save-button"),this.isTextEditable=!1,this.isDisabled=!1,this.fireEvent=this.fireEvent.bind(this),this.setEditable=this.setEditable.bind(this),this.setNonEditable=this.setNonEditable.bind(this),this.revert=this.revert.bind(this)}static get observedAttributes(){return["disabled"]}get value(){return this.text}set value(t){this.text=t,this.textContainer.textContent=t,this.setAttribute("value",t)}set disabled(t){this.isDisabled=t,this.isDisabled?this.setAttribute("disabled",""):this.removeAttribute("disabled")}fireEvent(t){let e=new CustomEvent("change",{bubbles:!0,cancelable:!0,composed:!0,detail:{value:t}});this.dispatchEvent(e)}setEditable(){this.isTextEditable||(this.textContainer.contentEditable=!0,this.textContainer.classList.add("editable"),this.textContainer.focus(),document.execCommand("selectAll",!1,null),this.editButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.editButton.classList.add("hide")}),setTimeout(()=>{this.saveButton.classList.remove("hide"),this.saveButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!0)}setNonEditable(){this.isTextEditable&&(this.textContainer.contentEditable=!1,this.textContainer.classList.remove("editable"),this.text!==this.textContainer.textContent.trim()&&(this.setAttribute("value",this.textContainer.textContent),this.text=this.textContainer.textContent.trim(),this.fireEvent(this.text)),this.saveButton.animate(this.rotateOut,this.animOptions).onfinish=(()=>{this.saveButton.classList.add("hide")}),setTimeout(()=>{this.editButton.classList.remove("hide"),this.editButton.animate(this.rotateIn,this.animOptions)},100),this.isTextEditable=!1)}revert(){this.textContainer.isContentEditable&&(this.value=this.text,this.setNonEditable())}connectedCallback(){this.text,this.hasAttribute("value")&&(this.text=this.getAttribute("value"),this.textContainer.textContent=this.text),this.hasAttribute("disable")?this.isDisabled=!0:this.isDisabled=!1,this.rotateOut=[{transform:"rotate(0)",opacity:1},{transform:"rotate(90deg)",opacity:0}],this.rotateIn=[{transform:"rotate(-90deg)",opacity:0},{transform:"rotate(0)",opacity:1}],this.animOptions={duration:300,easing:"cubic-bezier(0.175, 0.885, 0.32, 1.275)",fill:"forwards"},this.isDisabled||(this.iconsContainer.classList.remove("hide"),this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable))}attributeChangedCallback(t){"disabled"===t&&(this.hasAttribute("disabled")?(this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable),this.revert()):(this.textContainer.addEventListener("dblclick",this.setEditable),this.editButton.addEventListener("click",this.setEditable),this.saveButton.addEventListener("click",this.setNonEditable)))}disconnectedCallback(){this.textContainer.removeEventListener("dblclick",this.setEditable),this.editButton.removeEventListener("click",this.setEditable),this.saveButton.removeEventListener("click",this.setNonEditable)}}); +const themeToggle=document.createElement("template");themeToggle.innerHTML='\n \n \n';class ThemeToggle extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(themeToggle.content.cloneNode(!0)),this.isChecked=!1,this.hasTheme="light",this.toggleState=this.toggleState.bind(this),this.fireEvent=this.fireEvent.bind(this),this.handleThemeChange=this.handleThemeChange.bind(this)}static get observedAttributes(){return["checked"]}daylight(){this.hasTheme="light",document.body.dataset.theme="light",this.setAttribute("aria-checked","false")}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark",this.setAttribute("aria-checked","true")}toggleState(){this.toggleAttribute("checked"),this.fireEvent()}handleKeyDown(e){"Space"===e.code&&this.toggleState()}handleThemeChange(e){e.detail.theme!==this.hasTheme&&("dark"===e.detail.theme?this.setAttribute("checked",""):this.removeAttribute("checked"))}fireEvent(){this.dispatchEvent(new CustomEvent("themechange",{bubbles:!0,composed:!0,detail:{theme:this.hasTheme}}))}connectedCallback(){this.setAttribute("role","switch"),this.setAttribute("aria-label","theme toggle"),"dark"===localStorage.theme?(this.nightlight(),this.setAttribute("checked","")):"light"===localStorage.theme?(this.daylight(),this.removeAttribute("checked")):window.matchMedia("(prefers-color-scheme: dark)").matches?(this.nightlight(),this.setAttribute("checked","")):(this.daylight(),this.removeAttribute("checked")),this.addEventListener("click",this.toggleState),this.addEventListener("keydown",this.handleKeyDown),document.addEventListener("themechange",this.handleThemeChange)}disconnectedCallback(){this.removeEventListener("click",this.toggleState),this.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("themechange",this.handleThemeChange)}attributeChangedCallback(e,t,n){"checked"===e&&(this.hasAttribute("checked")?(this.nightlight(),localStorage.setItem("theme","dark")):(this.daylight(),localStorage.setItem("theme","light")))}}window.customElements.define("theme-toggle",ThemeToggle); \ No newline at end of file diff --git a/components/index.html b/components/index.html index 758e628..ce1c67b 100644 --- a/components/index.html +++ b/components/index.html @@ -5,6 +5,7 @@ SM Components + @@ -53,7 +54,6 @@

    Components

      -
      @@ -648,7 +648,7 @@ navigationDrawerButton.addEventListner('click', e => { navigationDrawer.open(); // Will open hamburger menu on mobile devices when hidden }) - </script> +</script>
      @@ -1328,18 +1328,6 @@ -
      -

      Spinner

      -

      - Just drop the sm-spinner in markup where you want to show the spinner -

      - -
      -
      -<sm-spinner></sm-spinner>
      -
      -
      -

      Strip select

      @@ -1923,9 +1911,10 @@ - +