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
|
&.fade-out
|
||||||
pointer-events none
|
pointer-events none
|
||||||
|
|
||||||
.icon-play
|
svg-icon
|
||||||
|
[name="play"]
|
||||||
transform translateX(3px)
|
transform translateX(3px)
|
||||||
|
|
||||||
#audio-player-play,
|
#audio-player-play,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
component Icon(name string)
|
component Icon(name string)
|
||||||
go:utils.Icon(name)
|
svg-icon.padded-icon(name=name, class="icon-" + name)
|
||||||
|
|
||||||
component RawIcon(name string)
|
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%
|
width 100%
|
||||||
justify-content center
|
justify-content center
|
||||||
|
|
||||||
.icon-diamond
|
svg-icon
|
||||||
|
[name="diamond"]
|
||||||
margin-left 0.3rem
|
margin-left 0.3rem
|
||||||
margin-right 0
|
margin-right 0
|
||||||
|
|
||||||
|
@ -47,7 +47,8 @@ const soundtrack-margin = 1rem
|
|||||||
pointer-events none
|
pointer-events none
|
||||||
box-shadow outline-shadow-medium
|
box-shadow outline-shadow-medium
|
||||||
|
|
||||||
.icon-play
|
svg-icon
|
||||||
|
[name="play"]
|
||||||
transform translateX(27%)
|
transform translateX(27%)
|
||||||
|
|
||||||
.media-visualizer
|
.media-visualizer
|
||||||
|
@ -13,8 +13,9 @@ import ServiceWorkerManager from "./ServiceWorkerManager"
|
|||||||
import ServerEvents from "./ServerEvents"
|
import ServerEvents from "./ServerEvents"
|
||||||
import { displayAiringDate, displayDate, displayTime } from "./DateView"
|
import { displayAiringDate, displayDate, displayTime } from "./DateView"
|
||||||
import { findAll, supportsWebP, requestIdleCallback, swapElements, delay, findAllInside } from "./Utils"
|
import { findAll, supportsWebP, requestIdleCallback, swapElements, delay, findAllInside } from "./Utils"
|
||||||
import * as actions from "./Actions"
|
|
||||||
import ToolTip from "./Elements/tool-tip/tool-tip"
|
import ToolTip from "./Elements/tool-tip/tool-tip"
|
||||||
|
import * as actions from "./Actions"
|
||||||
|
import * as WebComponents from "./WebComponents"
|
||||||
|
|
||||||
export default class AnimeNotifier {
|
export default class AnimeNotifier {
|
||||||
app: Application
|
app: Application
|
||||||
@ -102,7 +103,7 @@ export default class AnimeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Web components
|
// Web components
|
||||||
this.registerWebComponents()
|
WebComponents.register()
|
||||||
|
|
||||||
// Tooltip
|
// Tooltip
|
||||||
this.tip = new 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() {
|
applyPageTitle() {
|
||||||
let headers = document.getElementsByTagName("h1")
|
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)
|
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
|
.padded-icon
|
||||||
width 1em
|
|
||||||
height 1em
|
|
||||||
min-width 1em
|
|
||||||
margin-right 0.5em
|
margin-right 0.5em
|
||||||
vertical-align text-bottom
|
vertical-align text-bottom
|
||||||
fill currentColor
|
|
||||||
|
|
||||||
.raw-icon
|
svg-icon
|
||||||
width 1em
|
[name="headphones"]
|
||||||
height 1em
|
|
||||||
min-width 1em
|
|
||||||
fill currentColor
|
|
||||||
|
|
||||||
.icon-headphones
|
|
||||||
transform translateY(2px)
|
transform translateY(2px)
|
@ -13,7 +13,8 @@
|
|||||||
transform scale(1.1)
|
transform scale(1.1)
|
||||||
opacity 1
|
opacity 1
|
||||||
|
|
||||||
.icon-discord
|
svg-icon
|
||||||
|
[name="discord"]
|
||||||
transform scale(1.1)
|
transform scale(1.1)
|
||||||
|
|
||||||
// .sidebar-social-media
|
// .sidebar-social-media
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
.tab
|
.tab
|
||||||
|
horizontal
|
||||||
|
align-items center
|
||||||
color text-color
|
color text-color
|
||||||
padding 0.5rem 1rem
|
padding 0.5rem 1rem
|
||||||
background-color tab-background
|
background-color tab-background
|
||||||
|
@ -1,28 +1,15 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"fmt"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var svgIcons = make(map[string]string)
|
// Icon shows an icon that has a margin-right attribute.
|
||||||
|
|
||||||
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 ...
|
|
||||||
func Icon(name string) string {
|
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 {
|
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