create a link embed
- proof of concept of a separate web components package - link embed has icon/title/subtitle - web components are registered just before app mounts, making them available in the markdown as well as the app
This commit is contained in:
parent
6ffe5939a5
commit
75228e1a3a
9 changed files with 141 additions and 17 deletions
7
libs/embeds/package.json
Normal file
7
libs/embeds/package.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "@goldenwere/static-web-templates-embeds",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"main": "src/index.ts"
|
||||
}
|
1
libs/embeds/src/index.ts
Normal file
1
libs/embeds/src/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './link'
|
101
libs/embeds/src/link.ts
Normal file
101
libs/embeds/src/link.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
import type { AttributeObserver } from './observer'
|
||||
|
||||
export type LinkEmbedAttributes = typeof LinkEmbed.observedAttributes[number]
|
||||
|
||||
/**
|
||||
* A link embed is a link with a title and an optional icon + subtitle
|
||||
*/
|
||||
export class LinkEmbed extends HTMLElement {
|
||||
static observedAttributes = [
|
||||
'icon',
|
||||
'title',
|
||||
'subtitle',
|
||||
'href',
|
||||
'target',
|
||||
] as const
|
||||
|
||||
_observers: AttributeObserver<LinkEmbedAttributes> = {} as any
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
const { ownerDocument } = this
|
||||
|
||||
const _link = ownerDocument.createElement('a')
|
||||
_link.setAttribute('rel', 'noreferrer noopener')
|
||||
this._observers.href = {
|
||||
element: _link,
|
||||
observer: (oldVal, newVal) => {
|
||||
const { element } = this._observers.href
|
||||
element!.setAttribute('href', newVal)
|
||||
},
|
||||
}
|
||||
this._observers.target = {
|
||||
element: _link,
|
||||
observer: (oldVal, newVal) => {
|
||||
const { element } = this._observers.href
|
||||
if (!!newVal) {
|
||||
element!.setAttribute('target', newVal)
|
||||
} else {
|
||||
element!.removeAttribute('target')
|
||||
}
|
||||
},
|
||||
}
|
||||
this.append(_link)
|
||||
|
||||
const _icon = ownerDocument.createElement('img')
|
||||
_icon.alt = '' // decorative
|
||||
this._observers.icon = {
|
||||
element: _icon,
|
||||
observer: (oldVal, newVal) => {
|
||||
const { element } = this._observers.icon
|
||||
if (!!newVal) {
|
||||
element!.setAttribute('src', newVal)
|
||||
} else {
|
||||
element!.style.display = 'hidden'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const _textWrapper = ownerDocument.createElement('div')
|
||||
_textWrapper.classList.add('text')
|
||||
_link.append(_textWrapper)
|
||||
|
||||
const _title = ownerDocument.createElement('p')
|
||||
this._observers.title = {
|
||||
element: _title,
|
||||
observer: (oldVal, newVal) => {
|
||||
const { element } = this._observers.title
|
||||
element!.innerHTML = newVal
|
||||
},
|
||||
}
|
||||
|
||||
const _subtitle = ownerDocument.createElement('p')
|
||||
this._observers.subtitle = {
|
||||
element: _subtitle,
|
||||
observer: (oldVal, newVal) => {
|
||||
const { element } = this._observers.subtitle
|
||||
if (!!newVal) {
|
||||
element!.innerHTML = newVal
|
||||
} else {
|
||||
element!.style.display = 'hidden'
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_textWrapper.append(
|
||||
_title,
|
||||
_subtitle,
|
||||
)
|
||||
}
|
||||
|
||||
attributeChangedCallback(name: LinkEmbedAttributes, oldVal: any, newVal: any) {
|
||||
this._observers[name].observer(oldVal, newVal)
|
||||
}
|
||||
}
|
||||
|
||||
export const registerLinkEmbed = () => {
|
||||
if (!customElements.get('link-embed')) {
|
||||
customElements.define('link-embed', LinkEmbed)
|
||||
}
|
||||
}
|
7
libs/embeds/src/observer.d.ts
vendored
Normal file
7
libs/embeds/src/observer.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
export type AttributeObserver<T extends string> = Record<T, {
|
||||
element?: HTMLElement,
|
||||
observer: (
|
||||
oldVal: any,
|
||||
newVal: any,
|
||||
) => void
|
||||
}>
|
Loading…
Add table
Add a link
Reference in a new issue