Use web components for SVG icons
This commit is contained in:
parent
b32005cdee
commit
d974156d68
@ -92,7 +92,8 @@ animation rotate-x-once
|
||||
&.fade-out
|
||||
pointer-events none
|
||||
|
||||
.icon-play
|
||||
svg-icon
|
||||
[name="play"]
|
||||
transform translateX(3px)
|
||||
|
||||
#audio-player-play,
|
||||
|
@ -1,5 +1,5 @@
|
||||
component Icon(name string)
|
||||
go:utils.Icon(name)
|
||||
svg-icon.padded-icon(name=name, class="icon-" + name)
|
||||
|
||||
component RawIcon(name string)
|
||||
go:utils.RawIcon(name)
|
||||
svg-icon(name=name, class="icon-" + name)
|
@ -57,7 +57,8 @@ const item-color-anime-support-ticket = hsl(217, 64%, 50%)
|
||||
width 100%
|
||||
justify-content center
|
||||
|
||||
.icon-diamond
|
||||
svg-icon
|
||||
[name="diamond"]
|
||||
margin-left 0.3rem
|
||||
margin-right 0
|
||||
|
||||
|
@ -47,7 +47,8 @@ const soundtrack-margin = 1rem
|
||||
pointer-events none
|
||||
box-shadow outline-shadow-medium
|
||||
|
||||
.icon-play
|
||||
svg-icon
|
||||
[name="play"]
|
||||
transform translateX(27%)
|
||||
|
||||
.media-visualizer
|
||||
|
@ -13,8 +13,9 @@ import ServiceWorkerManager from "./ServiceWorkerManager"
|
||||
import ServerEvents from "./ServerEvents"
|
||||
import { displayAiringDate, displayDate, displayTime } from "./DateView"
|
||||
import { findAll, supportsWebP, requestIdleCallback, swapElements, delay, findAllInside } from "./Utils"
|
||||
import * as actions from "./Actions"
|
||||
import ToolTip from "./Elements/tool-tip/tool-tip"
|
||||
import * as actions from "./Actions"
|
||||
import * as WebComponents from "./WebComponents"
|
||||
|
||||
export default class AnimeNotifier {
|
||||
app: Application
|
||||
@ -102,7 +103,7 @@ export default class AnimeNotifier {
|
||||
}
|
||||
|
||||
// Web components
|
||||
this.registerWebComponents()
|
||||
WebComponents.register()
|
||||
|
||||
// Tooltip
|
||||
this.tip = new ToolTip()
|
||||
@ -210,23 +211,6 @@ export default class AnimeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
registerWebComponents() {
|
||||
if(!("customElements" in window)) {
|
||||
console.warn("Web components not supported in your current browser")
|
||||
return
|
||||
}
|
||||
|
||||
// Custom element names must have a dash in their name
|
||||
const elements = new Map<string, Function>([
|
||||
["tool-tip", ToolTip]
|
||||
])
|
||||
|
||||
// Register all custom elements
|
||||
for(const [tag, definition] of elements.entries()) {
|
||||
window.customElements.define(tag, definition)
|
||||
}
|
||||
}
|
||||
|
||||
applyPageTitle() {
|
||||
let headers = document.getElementsByTagName("h1")
|
||||
|
||||
|
@ -147,6 +147,12 @@ export default class Diff {
|
||||
}
|
||||
}
|
||||
|
||||
// Never diff the contents of web components
|
||||
if(a.nodeName.includes("-")) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Child nodes
|
||||
Diff.childNodes(a, b)
|
||||
}
|
||||
}
|
||||
|
10
scripts/Elements/svg-icon/svg-icon.scarlet
Normal file
10
scripts/Elements/svg-icon/svg-icon.scarlet
Normal file
@ -0,0 +1,10 @@
|
||||
svg-icon
|
||||
display inline-block
|
||||
width 1em
|
||||
height 1em
|
||||
|
||||
svg
|
||||
display inherit
|
||||
width 1em
|
||||
height 1em
|
||||
fill currentColor
|
48
scripts/Elements/svg-icon/svg-icon.ts
Normal file
48
scripts/Elements/svg-icon/svg-icon.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import Diff from "scripts/Diff"
|
||||
|
||||
export default class SVGIcon extends HTMLElement {
|
||||
static cache = new Map<string, Promise<string>>()
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["name"]
|
||||
}
|
||||
|
||||
attributeChangedCallback(attrName) {
|
||||
if(attrName === "name") {
|
||||
this.render()
|
||||
}
|
||||
}
|
||||
|
||||
async render() {
|
||||
let cache = SVGIcon.cache[this.name]
|
||||
|
||||
if(cache) {
|
||||
let text = await cache
|
||||
Diff.mutations.queue(() => this.innerHTML = text)
|
||||
return
|
||||
}
|
||||
|
||||
SVGIcon.cache[this.name] = new Promise(async (resolve, reject) => {
|
||||
let url = `//media.notify.moe/images/icons/${this.name}.svg`
|
||||
let response = await fetch(url)
|
||||
|
||||
if(!response.ok) {
|
||||
console.warn(`Failed loading SVG icon: ${url}`)
|
||||
reject(response.statusText)
|
||||
return
|
||||
}
|
||||
|
||||
let text = await response.text()
|
||||
Diff.mutations.queue(() => this.innerHTML = text)
|
||||
resolve(text)
|
||||
})
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.getAttribute("name") || ""
|
||||
}
|
||||
|
||||
set name(value: string) {
|
||||
this.setAttribute("name", value)
|
||||
}
|
||||
}
|
20
scripts/WebComponents.ts
Normal file
20
scripts/WebComponents.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import ToolTip from "./Elements/tool-tip/tool-tip"
|
||||
import SVGIcon from "./Elements/svg-icon/svg-icon"
|
||||
|
||||
export function register() {
|
||||
if(!("customElements" in window)) {
|
||||
console.warn("Web components not supported in your current browser")
|
||||
return
|
||||
}
|
||||
|
||||
// Custom element names must have a dash in their name
|
||||
const elements = new Map<string, Function>([
|
||||
["tool-tip", ToolTip],
|
||||
["svg-icon", SVGIcon]
|
||||
])
|
||||
|
||||
// Register all custom elements
|
||||
for(const [tag, definition] of elements.entries()) {
|
||||
window.customElements.define(tag, definition)
|
||||
}
|
||||
}
|
@ -1,16 +1,7 @@
|
||||
.icon
|
||||
width 1em
|
||||
height 1em
|
||||
min-width 1em
|
||||
.padded-icon
|
||||
margin-right 0.5em
|
||||
vertical-align text-bottom
|
||||
fill currentColor
|
||||
|
||||
.raw-icon
|
||||
width 1em
|
||||
height 1em
|
||||
min-width 1em
|
||||
fill currentColor
|
||||
|
||||
.icon-headphones
|
||||
svg-icon
|
||||
[name="headphones"]
|
||||
transform translateY(2px)
|
@ -13,7 +13,8 @@
|
||||
transform scale(1.1)
|
||||
opacity 1
|
||||
|
||||
.icon-discord
|
||||
svg-icon
|
||||
[name="discord"]
|
||||
transform scale(1.1)
|
||||
|
||||
// .sidebar-social-media
|
||||
|
@ -1,4 +1,6 @@
|
||||
.tab
|
||||
horizontal
|
||||
align-items center
|
||||
color text-color
|
||||
padding 0.5rem 1rem
|
||||
background-color tab-background
|
||||
|
@ -1,28 +1,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var svgIcons = make(map[string]string)
|
||||
|
||||
func init() {
|
||||
files, _ := ioutil.ReadDir("images/icons/")
|
||||
|
||||
for _, file := range files {
|
||||
name := strings.TrimSuffix(file.Name(), ".svg")
|
||||
data, _ := ioutil.ReadFile("images/icons/" + name + ".svg")
|
||||
svgIcons[name] = strings.Replace(string(data), "<svg ", "<svg class='icon icon-"+name+"' ", 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Icon ...
|
||||
// Icon shows an icon that has a margin-right attribute.
|
||||
func Icon(name string) string {
|
||||
return svgIcons[name]
|
||||
return fmt.Sprintf("<svg-icon name='%s' class='padded-icon'></svg-icon>", name)
|
||||
}
|
||||
|
||||
// RawIcon ...
|
||||
// RawIcon shows the raw icon without any additional margin.
|
||||
func RawIcon(name string) string {
|
||||
return strings.Replace(svgIcons[name], "class='icon", "class='raw-icon", 1)
|
||||
return fmt.Sprintf("<svg-icon name='%s'></svg-icon>", name)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user