Added theme-toggle component
This commit is contained in:
parent
849ef98877
commit
427726bd4b
@ -54,6 +54,7 @@
|
|||||||
<p>
|
<p>
|
||||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||||
</p>
|
</p>
|
||||||
|
<sm-button variant="primary">This is a button</sm-button>
|
||||||
<sm-carousel>
|
<sm-carousel>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>Card</h3>
|
<h3>Card</h3>
|
||||||
|
|||||||
@ -96,7 +96,8 @@ ul {
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
grid-template-columns: 12rem minmax(0, 1fr);
|
grid-template-columns: 12rem 1fr;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.tr:nth-of-type(odd) {
|
.tr:nth-of-type(odd) {
|
||||||
background-color: rgba(var(--text-color), 0.04);
|
background-color: rgba(var(--text-color), 0.04);
|
||||||
@ -320,29 +321,6 @@ ul {
|
|||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-switcher {
|
|
||||||
position: relative;
|
|
||||||
justify-self: flex-end;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
.theme-switcher .icon {
|
|
||||||
position: absolute;
|
|
||||||
transition: transform 0.6s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-switcher__checkbox {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.theme-switcher__checkbox:checked ~ .moon-icon {
|
|
||||||
transform: scale(0) rotate(90deg);
|
|
||||||
}
|
|
||||||
.theme-switcher__checkbox:not(:checked) ~ .sun-icon {
|
|
||||||
transform: scale(0) rotate(-90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.comment,
|
.token.comment,
|
||||||
.token.block-comment,
|
.token.block-comment,
|
||||||
.token.prolog,
|
.token.prolog,
|
||||||
|
|||||||
2
components/css/main.min.css
vendored
2
components/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -89,7 +89,8 @@ ul{
|
|||||||
display: grid;
|
display: grid;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
grid-template-columns: 12rem minmax(0, 1fr);
|
grid-template-columns: 12rem 1fr;
|
||||||
|
width: 100%;
|
||||||
&:nth-of-type(odd){
|
&:nth-of-type(odd){
|
||||||
background-color: rgba(var(--text-color), .04);
|
background-color: rgba(var(--text-color), .04);
|
||||||
}
|
}
|
||||||
@ -268,28 +269,6 @@ ul{
|
|||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.theme-switcher{
|
|
||||||
position: relative;
|
|
||||||
justify-self: flex-end;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
.icon{
|
|
||||||
position: absolute;
|
|
||||||
transition: transform 0.6s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.theme-switcher__checkbox{
|
|
||||||
display: none;
|
|
||||||
&:checked ~ .moon-icon{
|
|
||||||
transform: scale(0) rotate(90deg);
|
|
||||||
}
|
|
||||||
&:not(:checked) ~ .sun-icon{
|
|
||||||
transform: scale(0) rotate(-90deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Syntax highlighting
|
//Syntax highlighting
|
||||||
|
|
||||||
.token.comment,
|
.token.comment,
|
||||||
|
|||||||
245
components/dist/select.js
vendored
245
components/dist/select.js
vendored
@ -7,16 +7,6 @@ smSelect.innerHTML = `
|
|||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.icon {
|
|
||||||
fill: none;
|
|
||||||
height: 0.8rem;
|
|
||||||
width: 0.8rem;
|
|
||||||
stroke: rgba(var(--text-color), 0.7);
|
|
||||||
stroke-width: 6;
|
|
||||||
overflow: visible;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
}
|
|
||||||
:host{
|
:host{
|
||||||
display: -webkit-inline-box;
|
display: -webkit-inline-box;
|
||||||
display: -ms-inline-flexbox;
|
display: -ms-inline-flexbox;
|
||||||
@ -27,6 +17,10 @@ smSelect.innerHTML = `
|
|||||||
--max-height: auto;
|
--max-height: auto;
|
||||||
--min-width: 100%;
|
--min-width: 100%;
|
||||||
}
|
}
|
||||||
|
:host([disabled]) .select{
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
.hide{
|
.hide{
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
@ -37,12 +31,17 @@ smSelect.innerHTML = `
|
|||||||
display: flex;
|
display: flex;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-box-direction: normal;
|
-webkit-box-direction: normal;
|
||||||
-ms-flex-direction: column;
|
-ms-flex-direction: column;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
.icon {
|
||||||
|
height: 1.5rem;
|
||||||
|
width: 1.5rem;
|
||||||
|
fill: rgba(var(--text-color), 0.7);
|
||||||
|
}
|
||||||
.option-text{
|
.option-text{
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -80,7 +79,7 @@ smSelect.innerHTML = `
|
|||||||
}
|
}
|
||||||
.options{
|
.options{
|
||||||
top: 100%;
|
top: 100%;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.2rem;
|
||||||
overflow: hidden auto;
|
overflow: hidden auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
grid-area: options;
|
grid-area: options;
|
||||||
@ -121,11 +120,9 @@ smSelect.innerHTML = `
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="select" >
|
<div class="select" >
|
||||||
<div class="selection" tabindex="0">
|
<div class="selection">
|
||||||
<div class="option-text"></div>
|
<div class="option-text"></div>
|
||||||
<svg class="icon toggle" viewBox="0 0 64 64">
|
<svg class="icon toggle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>
|
||||||
<polyline points="63.65 15.99 32 47.66 0.35 15.99"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<div part="options" class="options hide">
|
<div part="options" class="options hide">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
@ -139,9 +136,45 @@ customElements.define('sm-select', class extends HTMLElement {
|
|||||||
}).append(smSelect.content.cloneNode(true))
|
}).append(smSelect.content.cloneNode(true))
|
||||||
|
|
||||||
this.reset = this.reset.bind(this)
|
this.reset = this.reset.bind(this)
|
||||||
|
this.open = this.open.bind(this)
|
||||||
|
this.collapse = this.collapse.bind(this)
|
||||||
|
this.toggle = this.toggle.bind(this)
|
||||||
|
this.handleSelectKeyDown = this.handleSelectKeyDown.bind(this)
|
||||||
|
this.handleOptionsKeyDown = this.handleOptionsKeyDown.bind(this)
|
||||||
|
this.handleOptionsKeyDown = this.handleOptionsKeyDown.bind(this)
|
||||||
|
|
||||||
|
this.availableOptions
|
||||||
|
this.optionList = this.shadowRoot.querySelector('.options')
|
||||||
|
this.chevron = this.shadowRoot.querySelector('.toggle')
|
||||||
|
this.selection = this.shadowRoot.querySelector('.selection'),
|
||||||
|
this.previousOption
|
||||||
|
this.isOpen = false;
|
||||||
|
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'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['value']
|
return ['value', 'disabled']
|
||||||
}
|
}
|
||||||
get value() {
|
get value() {
|
||||||
return this.getAttribute('value')
|
return this.getAttribute('value')
|
||||||
@ -150,94 +183,89 @@ customElements.define('sm-select', class extends HTMLElement {
|
|||||||
this.setAttribute('value', val)
|
this.setAttribute('value', val)
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(){
|
reset() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
this.optionList.classList.remove('hide')
|
||||||
|
this.optionList.animate(this.slideDown, this.animationOptions)
|
||||||
|
this.chevron.classList.add('rotate')
|
||||||
|
this.isOpen = true
|
||||||
|
}
|
||||||
collapse() {
|
collapse() {
|
||||||
this.chevron.classList.remove('rotate')
|
this.chevron.classList.remove('rotate')
|
||||||
this.optionList.animate(this.slideUp, this.animationOptions)
|
this.optionList.animate(this.slideUp, this.animationOptions)
|
||||||
.onfinish = () => {
|
.onfinish = () => {
|
||||||
this.optionList.classList.add('hide')
|
this.optionList.classList.add('hide')
|
||||||
this.open = false
|
this.isOpen = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toggle() {
|
||||||
|
if (!this.isOpen && !this.hasAttribute('disabled')) {
|
||||||
|
this.open()
|
||||||
|
} else {
|
||||||
|
this.collapse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
handleSelectKeyDown(e) {
|
||||||
this.availableOptions
|
if (e.code === 'ArrowDown' || e.code === 'ArrowRight') {
|
||||||
this.optionList = this.shadowRoot.querySelector('.options')
|
e.preventDefault()
|
||||||
this.chevron = this.shadowRoot.querySelector('.toggle')
|
this.availableOptions[0].focus()
|
||||||
let slot = this.shadowRoot.querySelector('.options slot'),
|
|
||||||
selection = this.shadowRoot.querySelector('.selection'),
|
|
||||||
previousOption
|
|
||||||
this.open = false;
|
|
||||||
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'
|
|
||||||
}
|
}
|
||||||
selection.addEventListener('click', e => {
|
else if (e.code === 'Enter' || e.code === 'Space') {
|
||||||
if (!this.open) {
|
if (!this.isOpen) {
|
||||||
this.optionList.classList.remove('hide')
|
this.optionList.classList.remove('hide')
|
||||||
this.optionList.animate(this.slideDown, this.animationOptions)
|
this.optionList.animate(this.slideDown, this.animationOptions)
|
||||||
this.chevron.classList.add('rotate')
|
this.chevron.classList.add('rotate')
|
||||||
this.open = true
|
this.isOpen = true
|
||||||
} else {
|
} else {
|
||||||
this.collapse()
|
this.collapse()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
selection.addEventListener('keydown', e => {
|
}
|
||||||
if (e.code === 'ArrowDown' || e.code === 'ArrowRight') {
|
handleOptionsKeyDown(e) {
|
||||||
e.preventDefault()
|
if (e.code === 'ArrowUp' || e.code === 'ArrowRight') {
|
||||||
|
e.preventDefault()
|
||||||
|
if (document.activeElement.previousElementSibling) {
|
||||||
|
document.activeElement.previousElementSibling.focus()
|
||||||
|
} else {
|
||||||
|
this.availableOptions[this.availableOptions.length - 1].focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') {
|
||||||
|
e.preventDefault()
|
||||||
|
if (document.activeElement.nextElementSibling) {
|
||||||
|
document.activeElement.nextElementSibling.focus()
|
||||||
|
} else {
|
||||||
this.availableOptions[0].focus()
|
this.availableOptions[0].focus()
|
||||||
}
|
}
|
||||||
if (e.code === 'Enter' || e.code === 'Space')
|
}
|
||||||
if (!this.open) {
|
}
|
||||||
this.optionList.classList.remove('hide')
|
connectedCallback() {
|
||||||
this.optionList.animate(this.slideDown, this.animationOptions)
|
this.setAttribute('role', 'listbox')
|
||||||
this.chevron.classList.add('rotate')
|
if (!this.hasAttribute('disabled')) {
|
||||||
this.open = true
|
this.selection.setAttribute('tabindex', '0')
|
||||||
} else {
|
}
|
||||||
this.collapse()
|
let slot = this.shadowRoot.querySelector('slot')
|
||||||
}
|
slot.addEventListener('slotchange', e => {
|
||||||
})
|
this.availableOptions = slot.assignedElements()
|
||||||
this.optionList.addEventListener('keydown', e => {
|
if (this.availableOptions[0]) {
|
||||||
if (e.code === 'ArrowUp' || e.code === 'ArrowRight') {
|
let firstElement = this.availableOptions[0];
|
||||||
e.preventDefault()
|
this.previousOption = firstElement;
|
||||||
if (document.activeElement.previousElementSibling) {
|
firstElement.classList.add('check-selected')
|
||||||
document.activeElement.previousElementSibling.focus()
|
this.setAttribute('value', firstElement.getAttribute('value'))
|
||||||
} else {
|
this.shadowRoot.querySelector('.option-text').textContent = firstElement.textContent
|
||||||
this.availableOptions[this.availableOptions.length - 1].focus()
|
this.availableOptions.forEach((element, index) => {
|
||||||
}
|
element.setAttribute('tabindex', "0");
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (e.code === 'ArrowDown' || e.code === 'ArrowLeft') {
|
});
|
||||||
e.preventDefault()
|
this.selection.addEventListener('click', this.toggle)
|
||||||
if (document.activeElement.nextElementSibling) {
|
this.selection.addEventListener('keydown', this.handleSelectKeyDown)
|
||||||
document.activeElement.nextElementSibling.focus()
|
this.optionList.addEventListener('keydown', this.handleOptionsKeyDown)
|
||||||
} else{
|
|
||||||
this.availableOptions[0].focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.addEventListener('optionSelected', e => {
|
this.addEventListener('optionSelected', e => {
|
||||||
if (previousOption !== e.target) {
|
if (this.previousOption !== e.target) {
|
||||||
this.setAttribute('value', e.detail.value)
|
this.setAttribute('value', e.detail.value)
|
||||||
this.shadowRoot.querySelector('.option-text').textContent = e.detail.text;
|
this.shadowRoot.querySelector('.option-text').textContent = e.detail.text;
|
||||||
this.dispatchEvent(new CustomEvent('change', {
|
this.dispatchEvent(new CustomEvent('change', {
|
||||||
@ -247,36 +275,36 @@ customElements.define('sm-select', class extends HTMLElement {
|
|||||||
value: e.detail.value
|
value: e.detail.value
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
if (previousOption) {
|
if (this.previousOption) {
|
||||||
previousOption.classList.remove('check-selected')
|
this.previousOption.classList.remove('check-selected')
|
||||||
}
|
}
|
||||||
previousOption = e.target;
|
this.previousOption = e.target;
|
||||||
}
|
}
|
||||||
if (!e.detail.switching)
|
if (!e.detail.switching)
|
||||||
this.collapse()
|
this.collapse()
|
||||||
|
|
||||||
e.target.classList.add('check-selected')
|
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 => {
|
document.addEventListener('mousedown', e => {
|
||||||
if (!this.contains(e.target) && this.open) {
|
if (this.isOpen && !this.contains(e.target)) {
|
||||||
this.collapse()
|
this.collapse()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
attributeChangedCallback(name, oldVal, newVal) {
|
||||||
|
if (name === "disabled") {
|
||||||
|
if (this.hasAttribute('disabled')) {
|
||||||
|
this.selection.removeAttribute('tabindex')
|
||||||
|
}else {
|
||||||
|
this.selection.setAttribute('tabindex', '0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
this.selection.removeEventListener('click', this.toggle)
|
||||||
|
this.selection.removeEventListener('keydown', this.handleSelectKeyDown)
|
||||||
|
this.optionList.removeEventListener('keydown', this.handleOptionsKeyDown)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// option
|
// option
|
||||||
@ -351,6 +379,8 @@ customElements.define('sm-option', class extends HTMLElement {
|
|||||||
this.attachShadow({
|
this.attachShadow({
|
||||||
mode: 'open'
|
mode: 'open'
|
||||||
}).append(smOption.content.cloneNode(true))
|
}).append(smOption.content.cloneNode(true))
|
||||||
|
|
||||||
|
this.sendDetails = this.sendDetails.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendDetails(switching) {
|
sendDetails(switching) {
|
||||||
@ -367,15 +397,14 @@ customElements.define('sm-option', class extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
this.setAttribute('role', 'option')
|
||||||
let validKey = [
|
let validKey = [
|
||||||
'ArrowUp',
|
'ArrowUp',
|
||||||
'ArrowDown',
|
'ArrowDown',
|
||||||
'ArrowLeft',
|
'ArrowLeft',
|
||||||
'ArrowRight'
|
'ArrowRight'
|
||||||
]
|
]
|
||||||
this.addEventListener('click', e => {
|
this.addEventListener('click', this.sendDetails)
|
||||||
this.sendDetails()
|
|
||||||
})
|
|
||||||
this.addEventListener('keyup', e => {
|
this.addEventListener('keyup', e => {
|
||||||
if (e.code === 'Enter' || e.code === 'Space') {
|
if (e.code === 'Enter' || e.code === 'Space') {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
2
components/dist/select.min.js
vendored
2
components/dist/select.min.js
vendored
File diff suppressed because one or more lines are too long
178
components/dist/theme-toggle.js
vendored
Normal file
178
components/dist/theme-toggle.js
vendored
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
const themeToggle = document.createElement('template')
|
||||||
|
themeToggle.innerHTML = `
|
||||||
|
<style>
|
||||||
|
*{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
:host{
|
||||||
|
}
|
||||||
|
.theme-toggle {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
width: 1.4rem;
|
||||||
|
height: 1.4rem;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
.theme-toggle::after{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
opacity: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: transform 0.3s, opacity 0.3s;
|
||||||
|
transform: translate(-50%, -50%) scale(1.2);
|
||||||
|
background-color: rgba(var(--text-color), 0.12);
|
||||||
|
}
|
||||||
|
:host(:focus-within) .theme-toggle{
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
:host(:focus-within) .theme-toggle::after{
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, -50%) scale(1);
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
fill: rgba(var(--text-color), 1);
|
||||||
|
transition: transform 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-switcher__checkbox {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:host([checked]) .moon-icon {
|
||||||
|
transform: scale(0) rotate(90deg);
|
||||||
|
}
|
||||||
|
:host(:not([checked])) .sun-icon {
|
||||||
|
transform: scale(0) rotate(-90deg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<label class="theme-toggle" title="Change theme" tabindex="0">
|
||||||
|
<svg class="icon moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
||||||
|
height="24">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path
|
||||||
|
d="M10 6a8 8 0 0 0 11.955 6.956C21.474 18.03 17.2 22 12 22 6.477 22 2 17.523 2 12c0-5.2 3.97-9.474 9.044-9.955A7.963 7.963 0 0 0 10 6zm-6 6a8 8 0 0 0 8 8 8.006 8.006 0 0 0 6.957-4.045c-.316.03-.636.045-.957.045-5.523 0-10-4.477-10-10 0-.321.015-.64.045-.957A8.006 8.006 0 0 0 4 12zm14.164-9.709L19 2.5v1l-.836.209a2 2 0 0 0-1.455 1.455L16.5 6h-1l-.209-.836a2 2 0 0 0-1.455-1.455L13 3.5v-1l.836-.209A2 2 0 0 0 15.29.836L15.5 0h1l.209.836a2 2 0 0 0 1.455 1.455zm5 5L24 7.5v1l-.836.209a2 2 0 0 0-1.455 1.455L21.5 11h-1l-.209-.836a2 2 0 0 0-1.455-1.455L18 8.5v-1l.836-.209a2 2 0 0 0 1.455-1.455L20.5 5h1l.209.836a2 2 0 0 0 1.455 1.455z" />
|
||||||
|
</svg>
|
||||||
|
<svg class="icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
||||||
|
height="24">
|
||||||
|
<path fill="none" d="M0 0h24v24H0z" />
|
||||||
|
<path
|
||||||
|
d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z" />
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
`
|
||||||
|
|
||||||
|
class ThemeToggle extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.attachShadow({
|
||||||
|
mode: 'open'
|
||||||
|
}).append(themeToggle.content.cloneNode(true))
|
||||||
|
|
||||||
|
this.isChecked = false
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
|
nightlight() {
|
||||||
|
this.hasTheme = 'dark'
|
||||||
|
document.body.dataset.theme = 'dark'
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleState() {
|
||||||
|
this.toggleAttribute('checked')
|
||||||
|
this.fireEvent()
|
||||||
|
}
|
||||||
|
handleKeyDown(e) {
|
||||||
|
if (e.code === 'Space') {
|
||||||
|
this.toggleState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleThemeChange(e) {
|
||||||
|
if (e.detail.theme !== this.hasTheme) {
|
||||||
|
if (e.detail.theme === 'dark') {
|
||||||
|
this.setAttribute('checked', '')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.removeAttribute('checked')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent() {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('themechange', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: {
|
||||||
|
theme: this.hasTheme
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.setAttribute('role', 'switch')
|
||||||
|
this.setAttribute('aria-label', 'theme toggle')
|
||||||
|
if (localStorage.theme === "dark") {
|
||||||
|
this.nightlight();
|
||||||
|
this.setAttribute('checked', '')
|
||||||
|
} else if (localStorage.theme === "light") {
|
||||||
|
this.daylight();
|
||||||
|
this.removeAttribute('checked')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (window.matchMedia(`(prefers-color-scheme: dark)`).matches) {
|
||||||
|
this.nightlight();
|
||||||
|
this.setAttribute('checked', '')
|
||||||
|
} else {
|
||||||
|
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(name, oldVal, newVal) {
|
||||||
|
if (name === 'checked') {
|
||||||
|
if (this.hasAttribute('checked')) {
|
||||||
|
this.nightlight();
|
||||||
|
localStorage.setItem("theme", "dark");
|
||||||
|
} else {
|
||||||
|
this.daylight();
|
||||||
|
localStorage.setItem("theme", "light");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('theme-toggle', ThemeToggle);
|
||||||
1
components/dist/theme-toggle.min.js
vendored
Normal file
1
components/dist/theme-toggle.min.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
const themeToggle=document.createElement("template");themeToggle.innerHTML='\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n }\n .theme-toggle {\n display: flex;\n position: relative;\n width: 1.4rem;\n height: 1.4rem;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n .theme-toggle::after{\n content: \'\';\n position: absolute;\n width: 2.5rem;\n height: 2.5rem;\n top: 50%;\n left: 50%;\n opacity: 0;\n border-radius: 50%;\n pointer-events: none;\n transition: transform 0.3s, opacity 0.3s;\n transform: translate(-50%, -50%) scale(1.2);\n background-color: rgba(var(--text-color), 0.12);\n }\n :host(:focus-within) .theme-toggle{\n outline: none;\n }\n :host(:focus-within) .theme-toggle::after{\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n .icon {\n position: absolute;\n height: 100%;\n width: 100%;\n fill: rgba(var(--text-color), 1);\n transition: transform 0.6s;\n }\n \n .theme-switcher__checkbox {\n display: none;\n }\n :host([checked]) .moon-icon {\n transform: scale(0) rotate(90deg);\n }\n :host(:not([checked])) .sun-icon {\n transform: scale(0) rotate(-90deg);\n }\n </style>\n <label class="theme-toggle" title="Change theme" tabindex="0">\n <svg class="icon moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"\n height="24">\n <path fill="none" d="M0 0h24v24H0z" />\n <path\n d="M10 6a8 8 0 0 0 11.955 6.956C21.474 18.03 17.2 22 12 22 6.477 22 2 17.523 2 12c0-5.2 3.97-9.474 9.044-9.955A7.963 7.963 0 0 0 10 6zm-6 6a8 8 0 0 0 8 8 8.006 8.006 0 0 0 6.957-4.045c-.316.03-.636.045-.957.045-5.523 0-10-4.477-10-10 0-.321.015-.64.045-.957A8.006 8.006 0 0 0 4 12zm14.164-9.709L19 2.5v1l-.836.209a2 2 0 0 0-1.455 1.455L16.5 6h-1l-.209-.836a2 2 0 0 0-1.455-1.455L13 3.5v-1l.836-.209A2 2 0 0 0 15.29.836L15.5 0h1l.209.836a2 2 0 0 0 1.455 1.455zm5 5L24 7.5v1l-.836.209a2 2 0 0 0-1.455 1.455L21.5 11h-1l-.209-.836a2 2 0 0 0-1.455-1.455L18 8.5v-1l.836-.209a2 2 0 0 0 1.455-1.455L20.5 5h1l.209.836a2 2 0 0 0 1.455 1.455z" />\n </svg>\n <svg class="icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"\n height="24">\n <path fill="none" d="M0 0h24v24H0z" />\n <path\n d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z" />\n </svg>\n </label>\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"}nightlight(){this.hasTheme="dark",document.body.dataset.theme="dark"}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);
|
||||||
@ -28,22 +28,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<h4>SM Components</h4>
|
<h4>SM Components</h4>
|
||||||
<label class="theme-switcher" title="Change theme">
|
<theme-toggle></theme-toggle>
|
||||||
<input id="theme_switcher" class="theme-switcher__checkbox" type="checkbox"
|
|
||||||
aria-label="Dark mode toggle">
|
|
||||||
<svg class="icon moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
|
||||||
height="24">
|
|
||||||
<path fill="none" d="M0 0h24v24H0z" />
|
|
||||||
<path
|
|
||||||
d="M10 6a8 8 0 0 0 11.955 6.956C21.474 18.03 17.2 22 12 22 6.477 22 2 17.523 2 12c0-5.2 3.97-9.474 9.044-9.955A7.963 7.963 0 0 0 10 6zm-6 6a8 8 0 0 0 8 8 8.006 8.006 0 0 0 6.957-4.045c-.316.03-.636.045-.957.045-5.523 0-10-4.477-10-10 0-.321.015-.64.045-.957A8.006 8.006 0 0 0 4 12zm14.164-9.709L19 2.5v1l-.836.209a2 2 0 0 0-1.455 1.455L16.5 6h-1l-.209-.836a2 2 0 0 0-1.455-1.455L13 3.5v-1l.836-.209A2 2 0 0 0 15.29.836L15.5 0h1l.209.836a2 2 0 0 0 1.455 1.455zm5 5L24 7.5v1l-.836.209a2 2 0 0 0-1.455 1.455L21.5 11h-1l-.209-.836a2 2 0 0 0-1.455-1.455L18 8.5v-1l.836-.209a2 2 0 0 0 1.455-1.455L20.5 5h1l.209.836a2 2 0 0 0 1.455 1.455z" />
|
|
||||||
</svg>
|
|
||||||
<svg class="icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24"
|
|
||||||
height="24">
|
|
||||||
<path fill="none" d="M0 0h24v24H0z" />
|
|
||||||
<path
|
|
||||||
d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z" />
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
</header>
|
</header>
|
||||||
<hamburger-menu id="side_nav">
|
<hamburger-menu id="side_nav">
|
||||||
<h4>Getting Started</h4>
|
<h4>Getting Started</h4>
|
||||||
@ -282,7 +267,7 @@
|
|||||||
touch enabled devices swipe can be used.
|
touch enabled devices swipe can be used.
|
||||||
</p>
|
</p>
|
||||||
<h2>Interactive demo</h2>
|
<h2>Interactive demo</h2>
|
||||||
<sm-carousel align-items="start" indicator>
|
<sm-carousel indicator>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3>Title</h3>
|
<h3>Title</h3>
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.</p>
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, optio.</p>
|
||||||
@ -525,10 +510,9 @@
|
|||||||
</p>
|
</p>
|
||||||
<h2>Interactive demo</h2>
|
<h2>Interactive demo</h2>
|
||||||
<sm-form>
|
<sm-form>
|
||||||
<sm-input placeholder="Email" type="email" error-text="please enter correct email" required animate>
|
<sm-input placeholder="Email" type="email" error-text="please enter correct email" required animate></sm-input>
|
||||||
</sm-input>
|
|
||||||
<sm-input placeholder="Password" type="password" required animate></sm-input>
|
<sm-input placeholder="Password" type="password" required animate></sm-input>
|
||||||
<sm-button variant="primary" disabled>Submit</sm-button>
|
<sm-button variant="primary" disabled>Login</sm-button>
|
||||||
</sm-form>
|
</sm-form>
|
||||||
<h2>Supported functions</h2>
|
<h2>Supported functions</h2>
|
||||||
<section class="table">
|
<section class="table">
|
||||||
@ -806,6 +790,10 @@
|
|||||||
</p>
|
</p>
|
||||||
<text-field value="Double click me!"></text-field>
|
<text-field value="Double click me!"></text-field>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="theme_toggle_page" class="page hide-completely">
|
||||||
|
<h1 class="page__title">Theme toggle</h1>
|
||||||
|
<theme-toggle></theme-toggle>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<template id="nav_item_template">
|
<template id="nav_item_template">
|
||||||
@ -839,6 +827,7 @@
|
|||||||
<script src="dist/tags-input.js"></script>
|
<script src="dist/tags-input.js"></script>
|
||||||
<script src="dist/textarea.js"></script>
|
<script src="dist/textarea.js"></script>
|
||||||
<script src="dist/text-field.js"></script>
|
<script src="dist/text-field.js"></script>
|
||||||
|
<script src="dist/theme-toggle.js"></script>
|
||||||
<script id="default_ui_library">
|
<script id="default_ui_library">
|
||||||
const domRefs = {};
|
const domRefs = {};
|
||||||
|
|
||||||
@ -921,42 +910,6 @@
|
|||||||
notify("We are back online.", "success");
|
notify("We are back online.", "success");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getRef("theme_switcher")) {
|
|
||||||
if (localStorage.theme === "dark") {
|
|
||||||
nightlight();
|
|
||||||
getRef("theme_switcher").checked = true;
|
|
||||||
} else if (localStorage.theme === "light") {
|
|
||||||
daylight();
|
|
||||||
getRef("theme_switcher").checked = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (window.matchMedia(`(prefers-color-scheme: dark)`).matches) {
|
|
||||||
nightlight();
|
|
||||||
getRef("theme_switcher").checked = true;
|
|
||||||
} else {
|
|
||||||
daylight();
|
|
||||||
getRef("theme_switcher").checked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function daylight() {
|
|
||||||
document.body.setAttribute("data-theme", "light");
|
|
||||||
}
|
|
||||||
|
|
||||||
function nightlight() {
|
|
||||||
document.body.setAttribute("data-theme", "dark");
|
|
||||||
}
|
|
||||||
getRef("theme_switcher").addEventListener("change", function (e) {
|
|
||||||
if (this.checked) {
|
|
||||||
nightlight();
|
|
||||||
localStorage.setItem("theme", "dark");
|
|
||||||
} else {
|
|
||||||
daylight();
|
|
||||||
localStorage.setItem("theme", "light");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// function required for popups or modals to appear
|
// function required for popups or modals to appear
|
||||||
class Stack {
|
class Stack {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -1158,7 +1111,6 @@
|
|||||||
renderComponentList()
|
renderComponentList()
|
||||||
showPage(window.location.hash, { firstLoad: true })
|
showPage(window.location.hash, { firstLoad: true })
|
||||||
getRef('total_components_count').textContent = componentsList.length
|
getRef('total_components_count').textContent = componentsList.length
|
||||||
// PR.prettyPrint()
|
|
||||||
getComponents()
|
getComponents()
|
||||||
})
|
})
|
||||||
function showPage(targetPage, options = {}) {
|
function showPage(targetPage, options = {}) {
|
||||||
@ -1281,6 +1233,10 @@
|
|||||||
name: 'Text field',
|
name: 'Text field',
|
||||||
pageId: 'text_field_page'
|
pageId: 'text_field_page'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'theme toggle',
|
||||||
|
pageId: 'theme_toggle_page'
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
function renderComponentList() {
|
function renderComponentList() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user