diff --git a/layout/sidebar/audioplayer.scarlet b/layout/sidebar/audioplayer.scarlet index b863d783..b7381b03 100644 --- a/layout/sidebar/audioplayer.scarlet +++ b/layout/sidebar/audioplayer.scarlet @@ -92,8 +92,9 @@ animation rotate-x-once &.fade-out pointer-events none - .icon-play - transform translateX(3px) + svg-icon + [name="play"] + transform translateX(3px) #audio-player-play, #audio-player-pause, diff --git a/mixins/Icon.pixy b/mixins/Icon.pixy index 10b4bab3..4d3292e4 100644 --- a/mixins/Icon.pixy +++ b/mixins/Icon.pixy @@ -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) \ No newline at end of file + svg-icon(name=name, class="icon-" + name) \ No newline at end of file diff --git a/pages/shop/shop.scarlet b/pages/shop/shop.scarlet index dded931f..5baac79b 100644 --- a/pages/shop/shop.scarlet +++ b/pages/shop/shop.scarlet @@ -57,9 +57,10 @@ const item-color-anime-support-ticket = hsl(217, 64%, 50%) width 100% justify-content center - .icon-diamond - margin-left 0.3rem - margin-right 0 + svg-icon + [name="diamond"] + margin-left 0.3rem + margin-right 0 #pro-benefits-footer margin-top 3rem diff --git a/pages/soundtracks/soundtracks.scarlet b/pages/soundtracks/soundtracks.scarlet index bce26feb..91963efb 100644 --- a/pages/soundtracks/soundtracks.scarlet +++ b/pages/soundtracks/soundtracks.scarlet @@ -47,8 +47,9 @@ const soundtrack-margin = 1rem pointer-events none box-shadow outline-shadow-medium - .icon-play - transform translateX(27%) + svg-icon + [name="play"] + transform translateX(27%) .media-visualizer horizontal diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 327527b8..17a80db1 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -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([ - ["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") diff --git a/scripts/Diff.ts b/scripts/Diff.ts index a9f57939..e3ca65ee 100644 --- a/scripts/Diff.ts +++ b/scripts/Diff.ts @@ -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 --git a/scripts/Elements/svg-icon/svg-icon.scarlet b/scripts/Elements/svg-icon/svg-icon.scarlet new file mode 100644 index 00000000..be2c1343 --- /dev/null +++ b/scripts/Elements/svg-icon/svg-icon.scarlet @@ -0,0 +1,10 @@ +svg-icon + display inline-block + width 1em + height 1em + + svg + display inherit + width 1em + height 1em + fill currentColor \ No newline at end of file diff --git a/scripts/Elements/svg-icon/svg-icon.ts b/scripts/Elements/svg-icon/svg-icon.ts new file mode 100644 index 00000000..b3893a9b --- /dev/null +++ b/scripts/Elements/svg-icon/svg-icon.ts @@ -0,0 +1,48 @@ +import Diff from "scripts/Diff" + +export default class SVGIcon extends HTMLElement { + static cache = new Map>() + + 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) + } +} \ No newline at end of file diff --git a/scripts/WebComponents.ts b/scripts/WebComponents.ts new file mode 100644 index 00000000..f3b529c6 --- /dev/null +++ b/scripts/WebComponents.ts @@ -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([ + ["tool-tip", ToolTip], + ["svg-icon", SVGIcon] + ]) + + // Register all custom elements + for(const [tag, definition] of elements.entries()) { + window.customElements.define(tag, definition) + } +} \ No newline at end of file diff --git a/styles/icons.scarlet b/styles/icons.scarlet index 9cfeed76..a635f2ef 100644 --- a/styles/icons.scarlet +++ b/styles/icons.scarlet @@ -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 - transform translateY(2px) \ No newline at end of file +svg-icon + [name="headphones"] + transform translateY(2px) \ No newline at end of file diff --git a/styles/social-media.scarlet b/styles/social-media.scarlet index dabf98c6..8520ab14 100644 --- a/styles/social-media.scarlet +++ b/styles/social-media.scarlet @@ -13,8 +13,9 @@ transform scale(1.1) opacity 1 -.icon-discord - transform scale(1.1) +svg-icon + [name="discord"] + transform scale(1.1) // .sidebar-social-media // position relative diff --git a/styles/tabs.scarlet b/styles/tabs.scarlet index 96786a38..819531f4 100644 --- a/styles/tabs.scarlet +++ b/styles/tabs.scarlet @@ -1,4 +1,6 @@ .tab + horizontal + align-items center color text-color padding 0.5rem 1rem background-color tab-background diff --git a/utils/Icon.go b/utils/Icon.go index dfc6ea25..2b701f96 100644 --- a/utils/Icon.go +++ b/utils/Icon.go @@ -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), "", 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("", name) }