<info-card
name="秋サンマ"
avatar="https://gravatar.com/avatar/c8288b14c875abb75c7c82d7785d7545?size=120"
blog-site="https://blog.autumnsaury.com"
>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Similique est dignissimos unde esse illo iusto nulla!
Omnis provident voluptas laudantium inventore corporis! Exercitationem, minima aperiam sequi eos expedita accusamus
officiis?
</info-card>
body {
transition: background-color 0.5s;
}
info-card {
border-radius: 10px;
box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.14) , 0px 3px 1px -2px rgba(0,0,0,0.12) , 0px 1px 5px 0px rgba(0,0,0,0.2);
}
xxxxxxxxxx
customElements.define('info-card', class extends HTMLElement {
constructor() {
super()
const template = /* html */ `
<div class="wrapper">
<img class="avatar" src="${this.avatar}" alt="avatar">
<button type="button" class="toggle-btn">Dark Mode</button>
<div class="name">
${this.name}
</div>
<a href="${this.blogSite}">My Blog</a>
<slot></slot>
</div>
`
const style = /* css */ `
:host {
display: block;
width: 300px;
height: 300px;
}
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
position: relative;
width: calc(100% - 2rem);
height: calc(100% - 2rem);
padding: 1rem;
border-radius: 10px;
font-size: 14px;
--title-color: black;
--content-color: gray;
--link-color: dodgerblue;
background-color: white;
transition: 1s;
}
.wrapper__dark {
--title-color: lightgray;
--content-color: lightgray;
--link-color: lightskyblue;
background-color: #333;
}
.avatar {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
}
.toggle-btn {
position: absolute;
top: 1rem;
right: 1rem;
border: none;
background-color: transparent;
color: var(--content-color);
cursor: pointer;
}
.name {
font-size: 1.5rem;
font-weight: bold;
color: var(--title-color);
}
a {
text-decoration: none;
color: var(--link-color);
font-weight: bold;
}
slot {
display: block;
font-size: 12px;
color: var(--content-color);
text-indent: 2em;
}
`
this.attachShadow({ mode: 'open' })
this.shadowRoot.innerHTML = template + `<style>${style}</style>`
const toggleBtn = this.shadowRoot.querySelector('.toggle-btn')
toggleBtn.addEventListener('click', () => {
this.dark = !this.dark
this.dispatchEvent(new CustomEvent('dark-mode-change', {
detail: {
dark: this.dark
}
}))
})
}
static get observedAttributes() {
return [
'dark'
]
}
attributeChangedCallback(name, oldValue, newValue) {
switch (name) {
case 'dark':
const wrapper = this.shadowRoot.querySelector('.wrapper')
if (this.hasAttribute('dark')) {
wrapper.classList.add('wrapper__dark')
} else {
wrapper.classList.remove('wrapper__dark')
}
}
}
// #region getters and setters
get name () {
return this.getAttribute('name')
}
get avatar () {
return this.getAttribute('avatar')
}
get blogSite () {
return this.getAttribute('blog-site')
}
get dark () {
return this.hasAttribute('dark')
}
set dark (value) {
if (value === true) {
this.setAttribute('dark', '')
} else if (value === false) {
this.removeAttribute('dark')
}
}
// #endregion
})
const card = document.querySelector('info-card')
card.addEventListener('dark-mode-change', ev => {
if (ev.detail.dark) {
document.body.style.backgroundColor = '#000'
} else {
document.body.style.backgroundColor = '#fff'
}
})
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.