added a picker

This commit is contained in:
nerf van nerfingen 2022-06-25 22:00:25 +02:00
parent 048ad5ae88
commit 27dd86a765
23 changed files with 1482 additions and 0 deletions

View file

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -0,0 +1 @@
{"title": "Splittermond", "id": "Splittermond", "stickers": [{"body": "SL_Frust", "url": "mxc://matrix.org/HbIcgjOqyyXxaIxXHSuWjkos", "info": {"w": 154, "h": 146, "size": 30700, "mimetype": "image/png", "thumbnail_url": "mxc://matrix.org/HbIcgjOqyyXxaIxXHSuWjkos", "thumbnail_info": {"w": 154, "h": 146, "size": 30700, "mimetype": "image/png"}}, "msgtype": "m.sticker", "id": "sha256:647fab3645fe41f5c07f79410a04a1b7695484742db84dd06b63b4a43ca5fcb7"}]}

23
web/esinstall.js Normal file
View file

@ -0,0 +1,23 @@
const { install, printStats } = require("esinstall")
install(
[{
specifier: "htm/preact",
all: false,
default: false,
namespace: false,
named: ["html", "render", "Component"],
}],
{
dest: "./lib",
sourceMap: false,
treeshake: true,
verbose: true,
}
).then(data => {
const oldPrefix = "web_modules/"
const newPrefix = "lib/"
const spaces = " ".repeat(oldPrefix.length - newPrefix.length)
console.log("Installation complete")
console.log(printStats(data.stats).replace(oldPrefix, newPrefix + spaces))
})

22
web/index.html Normal file
View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no">
<title>Maunium sticker picker</title>
<link rel="modulepreload" href="src/widget-api.js"/>
<link rel="modulepreload" href="src/frequently-used.js"/>
<link rel="modulepreload" href="src/spinner.js"/>
<link rel="modulepreload" href="lib/htm/preact.js"/>
<link rel="preload" href="packs/index.json" as="fetch" type="application/json" crossorigin/>
<link rel="stylesheet" href="style/index.css"/>
<link rel="stylesheet" href="style/spinner.css"/>
<script src="src/index.js" type="module"></script>
<script nomodule>document.body.innerText = "This sticker picker requires modern JavaScript"</script>
</head>
<body>
<noscript>This sticker picker requires JavaScript</noscript>
</body>
</html>

7
web/lib/htm/preact.js Normal file

File diff suppressed because one or more lines are too long

19
web/package.json Normal file
View file

@ -0,0 +1,19 @@
{
"name": "maunium-stickerpicker",
"version": "0.1.0",
"description": "A fast and simple Matrix sticker picker widget",
"repository": "https://github.com/maunium/stickerpicker",
"author": "Tulir Asokan <tulir@maunium.net>",
"license": "AGPL-3.0-or-later",
"private": true,
"scripts": {
"esinstall": "node ./esinstall.js",
"sass": "sass --no-source-map --style=compressed style/"
},
"dependencies": {
"htm": "^3.1.0",
"preact": "^10.5.14",
"esinstall": "^1.1.7",
"sass": "^1.42.1"
}
}

0
web/packs/.gitkeep Normal file
View file

View file

@ -0,0 +1 @@
{"title": "Splittermond", "id": "Splittermond", "stickers": [{"body": "SL_Frust", "url": "mxc://matrix.org/HbIcgjOqyyXxaIxXHSuWjkos", "info": {"w": 154, "h": 146, "size": 30700, "mimetype": "image/png", "thumbnail_url": "mxc://matrix.org/HbIcgjOqyyXxaIxXHSuWjkos", "thumbnail_info": {"w": 154, "h": 146, "size": 30700, "mimetype": "image/png"}}, "msgtype": "m.sticker", "id": "sha256:647fab3645fe41f5c07f79410a04a1b7695484742db84dd06b63b4a43ca5fcb7"}]}

6
web/packs/index.json Normal file
View file

@ -0,0 +1,6 @@
{
"packs": [
"Splittermond.json"
],
"homeserver_url": "https://matrix-client.matrix.org"
}

1
web/res/favorite.svg Normal file
View file

@ -0,0 +1 @@
<svg height='100px' width='100px' fill="#000000" xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"><g><g i:extraneous="self"><path d="M77,95.3c-0.7,0-1.4-0.2-2-0.6l-25.1-16l-25.1,16c-1.3,0.8-2.9,0.8-4.1-0.1c-1.2-0.9-1.8-2.4-1.4-3.9l7.5-28.9l-23-18.9 c-1.2-1-1.6-2.5-1.2-4c0.5-1.4,1.8-2.4,3.3-2.5l29.8-1.8L46.6,6.9c1.1-2.8,5.7-2.8,6.8,0l10.9,27.8L94,36.4 c1.5,0.1,2.8,1.1,3.3,2.5c0.5,1.4,0,3-1.2,4l-23,19l7.5,28.8c0.4,1.5-0.2,3-1.4,3.9C78.6,95,77.8,95.3,77,95.3z M49.9,70.6 c0.7,0,1.4,0.2,2,0.6l19.2,12.3l-5.7-22c-0.4-1.4,0.1-2.9,1.2-3.8l17.6-14.5l-22.7-1.4c-1.4-0.1-2.7-1-3.2-2.3L50,18.3l-8.3,21.2 c-0.5,1.3-1.8,2.2-3.2,2.3l-22.8,1.4l17.5,14.4c1.1,0.9,1.6,2.4,1.2,3.8l-5.7,22.1l19.2-12.2C48.5,70.8,49.2,70.6,49.9,70.6z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 1 KiB

1
web/res/recent.svg Normal file
View file

@ -0,0 +1 @@
<svg height='100px' width='100px' fill="#000000" xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"><g><g i:extraneous="self"><g><path d="M84,17.3c-17.8-17.8-46.7-18-64.8-0.5l-6.4-6.4c-0.8-0.8-2-1.1-3.2-0.8C8.7,9.9,7.7,10.9,7.5,12L2.6,35.6 c-0.2,1.1,0.1,2.1,0.8,2.8c0.8,0.8,1.8,1.1,2.9,0.8l23.6-4.9c1.2-0.2,2.1-1,2.4-2.2c0.3-1.1,0-2.4-0.8-3.2L25,22.6 C39.9,8.3,63.6,8.5,78.2,23.1C93,37.9,93,62,78.2,76.9C71,84.1,61.5,88,51.3,88s-19.7-4-26.9-11.1c-5.6-5.6-9.3-12.7-10.6-20.5 c-0.4-2.2-2.5-3.8-4.7-3.4c-2.2,0.4-3.7,2.5-3.4,4.7c1.6,9.5,6.1,18.1,12.9,24.9c8.7,8.7,20.3,13.5,32.7,13.5s24-4.8,32.7-13.5 C102,64.6,102,35.3,84,17.3z"></path><path d="M51.6,21c-2.3,0-4.1,1.8-4.1,4.1V50c0,1.5,0.8,2.9,2.1,3.6l13.2,7.3c0.6,0.4,1.3,0.5,2,0.5c1.4,0,2.8-0.8,3.6-2.1 c1.1-2,0.4-4.5-1.6-5.6l-11.1-6.1V25.1C55.7,22.8,53.9,21,51.6,21z"></path></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
web/res/search.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.145 18.29c-5.042 0-9.145-4.102-9.145-9.145s4.103-9.145 9.145-9.145 9.145 4.103 9.145 9.145-4.102 9.145-9.145 9.145zm0-15.167c-3.321 0-6.022 2.702-6.022 6.022s2.702 6.022 6.022 6.022 6.023-2.702 6.023-6.022-2.702-6.022-6.023-6.022zm9.263 12.443c-.817 1.176-1.852 2.188-3.046 2.981l5.452 5.453 3.014-3.013-5.42-5.421z"/></svg>

After

Width:  |  Height:  |  Size: 419 B

1
web/res/settings.svg Normal file
View file

@ -0,0 +1 @@
<svg height='100px' width='100px' fill="#000000" xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve"><g><g i:extraneous="self"><g><path d="M5273.1,2400.1v-2c0-2.8-5-4-9.7-4s-9.7,1.3-9.7,4v2c0,1.8,0.7,3.6,2,4.9l5,4.9c0.3,0.3,0.4,0.6,0.4,1v6.4 c0,0.4,0.2,0.7,0.6,0.8l2.9,0.9c0.5,0.1,1-0.2,1-0.8v-7.2c0-0.4,0.2-0.7,0.4-1l5.1-5C5272.4,2403.7,5273.1,2401.9,5273.1,2400.1z M5263.4,2400c-4.8,0-7.4-1.3-7.5-1.8v0c0.1-0.5,2.7-1.8,7.5-1.8c4.8,0,7.3,1.3,7.5,1.8C5270.7,2398.7,5268.2,2400,5263.4,2400z"></path><path d="M5268.4,2410.3c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1h4.3c0.6,0,1-0.4,1-1c0-0.6-0.4-1-1-1H5268.4z"></path><path d="M5272.7,2413.7h-4.3c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1h4.3c0.6,0,1-0.4,1-1C5273.7,2414.1,5273.3,2413.7,5272.7,2413.7z"></path><path d="M5272.7,2417h-4.3c-0.6,0-1,0.4-1,1c0,0.6,0.4,1,1,1h4.3c0.6,0,1-0.4,1-1C5273.7,2417.5,5273.3,2417,5272.7,2417z"></path></g><g><path d="M50,30.5c-10.8,0-19.5,8.8-19.5,19.5S39.2,69.5,50,69.5c10.8,0,19.5-8.8,19.5-19.5S60.8,30.5,50,30.5z M50,63.6 c-7.5,0-13.6-6.1-13.6-13.6S42.5,36.4,50,36.4c7.5,0,13.6,6.1,13.6,13.6S57.5,63.6,50,63.6z"></path><path d="M94.8,39.1l-13-1.3c-0.2-0.6-0.5-1.1-0.7-1.7L89.4,26c1-1.2,0.9-2.9-0.2-3.9L78,10.8c-1.1-1.1-2.8-1.2-3.9-0.2l-10.1,8.3 c-0.6-0.3-1.1-0.5-1.7-0.7l-1.3-13c-0.2-1.5-1.4-2.7-2.9-2.7H42.1c-1.5,0-2.8,1.1-2.9,2.7l-1.3,13c-0.6,0.2-1.1,0.5-1.7,0.7 L26,10.6c-1.2-1-2.9-0.9-3.9,0.2L10.8,22c-1.1,1.1-1.2,2.8-0.2,3.9l8.3,10.1c-0.3,0.6-0.5,1.1-0.7,1.7l-13,1.3 c-1.5,0.2-2.7,1.4-2.7,2.9v15.9c0,1.5,1.1,2.8,2.7,2.9l13,1.3c0.2,0.6,0.5,1.1,0.7,1.7L10.6,74c-1,1.2-0.9,2.9,0.2,3.9L22,89.2 c1.1,1.1,2.8,1.2,3.9,0.2l10.1-8.3c0.6,0.3,1.1,0.5,1.7,0.7l1.3,13c0.2,1.5,1.4,2.7,2.9,2.7h15.9c1.5,0,2.8-1.1,2.9-2.7l1.3-13 c0.6-0.2,1.1-0.5,1.7-0.7L74,89.4c1.2,1,2.9,0.9,3.9-0.2L89.2,78c1.1-1.1,1.2-2.8,0.2-3.9l-8.3-10.1c0.3-0.6,0.5-1.1,0.7-1.7 l13-1.3c1.5-0.2,2.6-1.4,2.6-2.9V42.1C97.5,40.6,96.4,39.3,94.8,39.1z M91.6,55.3l-12.2,1.2c-1.2,0.1-2.2,0.9-2.5,2 c-0.5,1.5-1.1,2.9-1.8,4.4c-0.5,1-0.4,2.3,0.3,3.2l7.8,9.5l-7.4,7.4l-9.5-7.8c-0.9-0.7-2.2-0.9-3.2-0.3c-1.5,0.8-2.9,1.4-4.4,1.8 c-1.1,0.4-1.9,1.3-2,2.5l-1.2,12.2H44.7l-1.2-12.2c-0.1-1.2-0.9-2.2-2-2.5c-1.5-0.5-2.9-1.1-4.4-1.8c-1-0.5-2.3-0.4-3.2,0.3 l-9.5,7.8l-7.4-7.4l7.8-9.5c0.7-0.9,0.9-2.2,0.3-3.2c-0.8-1.5-1.4-2.9-1.8-4.4c-0.4-1.1-1.3-1.9-2.5-2L8.4,55.3V44.7l12.2-1.2 c1.2-0.1,2.2-0.9,2.5-2c0.5-1.5,1.1-2.9,1.8-4.4c0.5-1,0.4-2.3-0.3-3.2l-7.8-9.5l7.4-7.4l9.5,7.8c0.9,0.7,2.2,0.9,3.2,0.3 c1.5-0.8,2.9-1.4,4.4-1.8c1.1-0.4,1.9-1.3,2-2.5l1.2-12.2h10.5l1.2,12.2c0.1,1.2,0.9,2.2,2,2.5c1.5,0.5,2.9,1.1,4.4,1.8 c1,0.5,2.3,0.4,3.2-0.3l9.5-7.8l7.4,7.4l-7.8,9.5c-0.7,0.9-0.9,2.2-0.3,3.2c0.8,1.5,1.4,2.9,1.8,4.4c0.4,1.1,1.3,1.9,2.5,2 l12.2,1.2V55.3z"></path></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -0,0 +1,34 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
const FREQUENTLY_USED = JSON.parse(window.localStorage.mauFrequentlyUsedStickerIDs || "{}")
let FREQUENTLY_USED_SORTED = null
export const add = id => {
const [count] = FREQUENTLY_USED[id] || [0]
FREQUENTLY_USED[id] = [count + 1, Date.now()]
window.localStorage.mauFrequentlyUsedStickerIDs = JSON.stringify(FREQUENTLY_USED)
FREQUENTLY_USED_SORTED = null
}
export const get = (limit = 16) => {
if (FREQUENTLY_USED_SORTED === null) {
FREQUENTLY_USED_SORTED = Object.entries(FREQUENTLY_USED)
.sort(([, [count1, date1]], [, [count2, date2]]) =>
count2 === count1 ? date2 - date1 : count2 - count1)
.map(([emoji]) => emoji)
}
return FREQUENTLY_USED_SORTED.slice(0, limit)
}

363
web/src/index.js Normal file
View file

@ -0,0 +1,363 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import { html, render, Component } from "../lib/htm/preact.js"
import { Spinner } from "./spinner.js"
import { SearchBox } from "./search-box.js"
import * as widgetAPI from "./widget-api.js"
import * as frequent from "./frequently-used.js"
// The base URL for fetching packs. The app will first fetch ${PACK_BASE_URL}/index.json,
// then ${PACK_BASE_URL}/${packFile} for each packFile in the packs object of the index.json file.
const PACKS_BASE_URL = "packs"
let INDEX = `${PACKS_BASE_URL}/index.json`
const params = new URLSearchParams(document.location.search)
if (params.has('config')) {
INDEX = params.get("config")
}
// This is updated from packs/index.json
let HOMESERVER_URL = "https://matrix-client.matrix.org"
const makeThumbnailURL = mxc => `${HOMESERVER_URL}/_matrix/media/r0/thumbnail/${mxc.substr(6)}?height=128&width=128&method=scale`
// We need to detect iOS webkit because it has a bug related to scrolling non-fixed divs
// This is also used to fix scrolling to sections on Element iOS
const isMobileSafari = navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/)
const supportedThemes = ["light", "dark", "black"]
const defaultState = {
packs: [],
filtering: {
searchTerm: "",
packs: [],
},
}
class App extends Component {
constructor(props) {
super(props)
this.defaultTheme = params.get("theme")
this.state = {
packs: defaultState.packs,
loading: true,
error: null,
stickersPerRow: parseInt(localStorage.mauStickersPerRow || "4"),
theme: localStorage.mauStickerThemeOverride || this.defaultTheme,
frequentlyUsed: {
id: "frequently-used",
title: "Frequently used",
stickerIDs: frequent.get(),
stickers: [],
},
filtering: defaultState.filtering,
}
if (!supportedThemes.includes(this.state.theme)) {
this.state.theme = "light"
}
if (!supportedThemes.includes(this.defaultTheme)) {
this.defaultTheme = "light"
}
this.stickersByID = new Map(JSON.parse(localStorage.mauFrequentlyUsedStickerCache || "[]"))
this.state.frequentlyUsed.stickers = this._getStickersByID(this.state.frequentlyUsed.stickerIDs)
this.imageObserver = null
this.packListRef = null
this.navRef = null
this.searchStickers = this.searchStickers.bind(this)
this.sendSticker = this.sendSticker.bind(this)
this.navScroll = this.navScroll.bind(this)
this.reloadPacks = this.reloadPacks.bind(this)
this.observeSectionIntersections = this.observeSectionIntersections.bind(this)
this.observeImageIntersections = this.observeImageIntersections.bind(this)
}
_getStickersByID(ids) {
return ids.map(id => this.stickersByID.get(id)).filter(sticker => !!sticker)
}
updateFrequentlyUsed() {
const stickerIDs = frequent.get()
const stickers = this._getStickersByID(stickerIDs)
this.setState({
frequentlyUsed: {
...this.state.frequentlyUsed,
stickerIDs,
stickers,
},
})
localStorage.mauFrequentlyUsedStickerCache = JSON.stringify(stickers.map(sticker => [sticker.id, sticker]))
}
searchStickers(e) {
const sanitizeString = s => s.toLowerCase().trim()
const searchTerm = sanitizeString(e.target.value)
const allPacks = [this.state.frequentlyUsed, ...this.state.packs]
const packsWithFilteredStickers = allPacks.map(pack => ({
...pack,
stickers: pack.stickers.filter(sticker =>
sanitizeString(sticker.body).includes(searchTerm) ||
sanitizeString(sticker.id).includes(searchTerm)
),
}))
this.setState({
filtering: {
...this.state.filtering,
searchTerm,
packs: packsWithFilteredStickers.filter(({ stickers }) => !!stickers.length),
},
})
}
setStickersPerRow(val) {
localStorage.mauStickersPerRow = val
document.documentElement.style.setProperty("--stickers-per-row", localStorage.mauStickersPerRow)
this.setState({
stickersPerRow: val,
})
this.packListRef.scrollTop = this.packListRef.scrollHeight
}
setTheme(theme) {
if (theme === "default") {
delete localStorage.mauStickerThemeOverride
this.setState({ theme: this.defaultTheme })
} else {
localStorage.mauStickerThemeOverride = theme
this.setState({ theme: theme })
}
}
reloadPacks() {
this.imageObserver.disconnect()
this.sectionObserver.disconnect()
this.setState({
packs: defaultState.packs,
filtering: defaultState.filtering,
})
this._loadPacks(true)
}
_loadPacks(disableCache = false) {
const cache = disableCache ? "no-cache" : undefined
fetch(INDEX, { cache }).then(async indexRes => {
if (indexRes.status >= 400) {
this.setState({
loading: false,
error: indexRes.status !== 404 ? indexRes.statusText : null,
})
return
}
const indexData = await indexRes.json()
HOMESERVER_URL = indexData.homeserver_url || HOMESERVER_URL
// TODO only load pack metadata when scrolled into view?
for (const packFile of indexData.packs) {
let packRes
if (packFile.startsWith("https://") || packFile.startsWith("http://")) {
packRes = await fetch(packFile, { cache })
} else {
packRes = await fetch(`${PACKS_BASE_URL}/${packFile}`, { cache })
}
const packData = await packRes.json()
for (const sticker of packData.stickers) {
this.stickersByID.set(sticker.id, sticker)
}
this.setState({
packs: [...this.state.packs, packData],
loading: false,
})
}
this.updateFrequentlyUsed()
}, error => this.setState({ loading: false, error }))
}
componentDidMount() {
document.documentElement.style.setProperty("--stickers-per-row", this.state.stickersPerRow.toString())
this._loadPacks()
this.imageObserver = new IntersectionObserver(this.observeImageIntersections, {
rootMargin: "100px",
})
this.sectionObserver = new IntersectionObserver(this.observeSectionIntersections)
}
observeImageIntersections(intersections) {
for (const entry of intersections) {
const img = entry.target.children.item(0)
if (entry.isIntersecting) {
img.setAttribute("src", img.getAttribute("data-src"))
img.classList.add("visible")
} else {
img.removeAttribute("src")
img.classList.remove("visible")
}
}
}
observeSectionIntersections(intersections) {
const navWidth = this.navRef.getBoundingClientRect().width
let minX = 0, maxX = navWidth
let minXElem = null
let maxXElem = null
for (const entry of intersections) {
const packID = entry.target.getAttribute("data-pack-id")
const navElement = document.getElementById(`nav-${packID}`)
if (entry.isIntersecting) {
navElement.classList.add("visible")
const bb = navElement.getBoundingClientRect()
if (bb.x < minX) {
minX = bb.x
minXElem = navElement
} else if (bb.right > maxX) {
maxX = bb.right
maxXElem = navElement
}
} else {
navElement.classList.remove("visible")
}
}
if (minXElem !== null) {
minXElem.scrollIntoView({ inline: "start" })
} else if (maxXElem !== null) {
maxXElem.scrollIntoView({ inline: "end" })
}
}
componentDidUpdate() {
if (this.packListRef === null) {
return
}
for (const elem of this.packListRef.getElementsByClassName("sticker")) {
this.imageObserver.observe(elem)
}
for (const elem of this.packListRef.children) {
this.sectionObserver.observe(elem)
}
}
componentWillUnmount() {
this.imageObserver.disconnect()
this.sectionObserver.disconnect()
}
sendSticker(evt) {
const id = evt.currentTarget.getAttribute("data-sticker-id")
const sticker = this.stickersByID.get(id)
frequent.add(id)
this.updateFrequentlyUsed()
widgetAPI.sendSticker(sticker)
}
navScroll(evt) {
this.navRef.scrollLeft += evt.deltaY
}
render() {
const theme = `theme-${this.state.theme}`
const filterActive = !!this.state.filtering.searchTerm
const packs = filterActive ? this.state.filtering.packs : [this.state.frequentlyUsed, ...this.state.packs]
if (this.state.loading) {
return html`<main class="spinner ${theme}"><${Spinner} size=${80} green /></main>`
} else if (this.state.error) {
return html`<main class="error ${theme}">
<h1>Failed to load packs</h1>
<p>${this.state.error}</p>
</main>`
} else if (this.state.packs.length === 0) {
return html`<main class="empty ${theme}"><h1>No packs found 😿</h1></main>`
}
return html`<main class="has-content ${theme}">
<nav onWheel=${this.navScroll} ref=${elem => this.navRef = elem}>
<${NavBarItem} pack=${this.state.frequentlyUsed} iconOverride="recent" />
${this.state.packs.map(pack => html`<${NavBarItem} id=${pack.id} pack=${pack}/>`)}
<${NavBarItem} pack=${{ id: "settings", title: "Settings" }} iconOverride="settings" />
</nav>
<${SearchBox} onKeyUp=${this.searchStickers} />
<div class="pack-list ${isMobileSafari ? "ios-safari-hack" : ""}" ref=${elem => this.packListRef = elem}>
${filterActive && packs.length === 0 ? html`<div class="search-empty"><h1>No stickers match your search</h1></div>` : null}
${packs.map(pack => html`<${Pack} id=${pack.id} pack=${pack} send=${this.sendSticker} />`)}
<${Settings} app=${this}/>
</div>
</main>`
}
}
const Settings = ({ app }) => html`
<section class="stickerpack settings" id="pack-settings" data-pack-id="settings">
<h1>Settings</h1>
<div class="settings-list">
<button onClick=${app.reloadPacks}>Reload</button>
<div>
<label for="stickers-per-row">Stickers per row: ${app.state.stickersPerRow}</label>
<input type="range" min=2 max=10 id="stickers-per-row" id="stickers-per-row"
value=${app.state.stickersPerRow}
onInput=${evt => app.setStickersPerRow(evt.target.value)} />
</div>
<div>
<label for="theme">Theme: </label>
<select name="theme" id="theme" onChange=${evt => app.setTheme(evt.target.value)}>
<option value="default">Default</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="black">Black</option>
</select>
</div>
</div>
</section>
`
// By default we just let the browser handle scrolling to sections, but webviews on Element iOS
// open the link in the browser instead of just scrolling there, so we need to scroll manually:
const scrollToSection = (evt, id) => {
const pack = document.getElementById(`pack-${id}`)
pack.scrollIntoView({ block: "start", behavior: "instant" })
evt.preventDefault()
}
const NavBarItem = ({ pack, iconOverride = null }) => html`
<a href="#pack-${pack.id}" id="nav-${pack.id}" data-pack-id=${pack.id} title=${pack.title}
onClick=${isMobileSafari ? (evt => scrollToSection(evt, pack.id)) : undefined}>
<div class="sticker">
${iconOverride ? html`
<span class="icon icon-${iconOverride}"/>
` : html`
<img src=${makeThumbnailURL(pack.stickers[0].url)}
alt=${pack.stickers[0].body} class="visible" />
`}
</div>
</a>
`
const Pack = ({ pack, send }) => html`
<section class="stickerpack" id="pack-${pack.id}" data-pack-id=${pack.id}>
<h1>${pack.title}</h1>
<div class="sticker-list">
${pack.stickers.map(sticker => html`
<${Sticker} key=${sticker.id} content=${sticker} send=${send}/>
`)}
</div>
</section>
`
const Sticker = ({ content, send }) => html`
<div class="sticker" onClick=${send} data-sticker-id=${content.id}>
<img data-src=${makeThumbnailURL(content.url)} alt=${content.body} title=${content.body} />
</div>
`
render(html`<${App} />`, document.body)

26
web/src/search-box.js Normal file
View file

@ -0,0 +1,26 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import { html } from "../lib/htm/preact.js"
export const SearchBox = ({ onKeyUp, placeholder = 'Find stickers' }) => {
const component = html`
<div class="search-box">
<input type="text" placeholder=${placeholder} onKeyUp=${onKeyUp} />
<span class="icon icon-search" />
</div>
`
return component
}

41
web/src/spinner.js Normal file
View file

@ -0,0 +1,41 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import { html } from "../lib/htm/preact.js"
export const Spinner = ({ size = 40, noCenter = false, noMargin = false, green = false }) => {
let margin = 0
if (!isNaN(+size)) {
size = +size
margin = noMargin ? 0 : `${Math.round(size / 6)}px`
size = `${size}px`
}
const noInnerMargin = !noCenter || !margin
const comp = html`
<div style="width: ${size}; height: ${size}; margin: ${noInnerMargin ? 0 : margin} 0;"
class="sk-chase ${green && "green"}">
<div class="sk-chase-dot" />
<div class="sk-chase-dot" />
<div class="sk-chase-dot" />
<div class="sk-chase-dot" />
<div class="sk-chase-dot" />
<div class="sk-chase-dot" />
</div>
`
if (!noCenter) {
return html`<div style="margin: ${margin} 0;" class="sk-center-wrapper">${comp}</div>`
}
return comp
}

76
web/src/widget-api.js Normal file
View file

@ -0,0 +1,76 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
let widgetId = null
window.onmessage = event => {
if (!window.parent || !event.data) {
return
}
const request = event.data
if (!request.requestId || !request.widgetId || !request.action || request.api !== "toWidget") {
return
}
if (widgetId) {
if (widgetId !== request.widgetId) {
return
}
} else {
widgetId = request.widgetId
}
let response
if (request.action === "visibility") {
response = {}
} else if (request.action === "capabilities") {
response = { capabilities: ["m.sticker"] }
} else {
response = { error: { message: "Action not supported" } }
}
window.parent.postMessage({ ...request, response }, event.origin)
}
export function sendSticker(content) {
const data = {
content: { ...content },
// `name` is for Element Web (and also the spec)
// Element Android uses content -> body as the name
name: content.body,
}
// Custom field that stores the ID even for non-telegram stickers
delete data.content.id
// This is for Element iOS
const widgetData = {
...data,
description: content.body,
file: `${content.id}.png`,
}
// Element iOS explodes if there are extra fields present
delete widgetData.content["net.maunium.telegram.sticker"]
window.parent.postMessage({
api: "fromWidget",
action: "m.sticker",
requestId: `sticker-${Date.now()}`,
widgetId,
data,
widgetData,
}, "*")
}

1
web/style/index.css Normal file
View file

@ -0,0 +1 @@
*{font-family:sans-serif}body{margin:0}h1{font-size:1rem}:root{--stickers-per-row: 4;--sticker-size: calc(100vw / var(--stickers-per-row))}main{color:var(--text-color)}main.spinner{margin-top:5rem}main.error,main.empty{margin:2rem}main.empty{text-align:center}main.has-content{position:fixed;top:0;left:0;right:0;bottom:0;display:grid;grid-template-rows:calc(12vw + 2px) min-content auto}main.theme-light{--highlight-color: #eee;--search-box-color: var(--highlight-color);--text-color: black;background-color:#fff}main.theme-dark{--highlight-color: #444;--search-box-color: #383e4b;--text-color: white;background-color:#22262e}main.theme-black{--highlight-color: #222;--search-box-color: var(--highlight-color);--text-color: white;background-color:#000}.icon{width:100%;height:100%;background-color:var(--text-color);mask-size:contain;-webkit-mask-size:contain;mask-image:var(--icon-image);-webkit-mask-image:var(--icon-image)}.icon.icon-settings{--icon-image: url(../res/settings.svg)}.icon.icon-recent{--icon-image: url(../res/recent.svg)}.icon.icon.icon-search{--icon-image: url(../res/search.svg)}nav{display:flex;overflow-x:auto}nav>a{border-bottom:2px solid transparent}nav>a.visible{border-bottom-color:green}nav>a>div.sticker{width:12vw;height:12vw}div.pack-list,nav{scrollbar-width:none}div.pack-list::-webkit-scrollbar,nav::-webkit-scrollbar{display:none}div.pack-list{overflow-y:auto}div.pack-list.ios-safari-hack{position:fixed;top:calc(calc(12vw + 2px) + calc(2 * 0.7rem + 2 * 0.5rem + 1rem));bottom:0;left:0;right:0;-webkit-overflow-scrolling:touch}div.search-empty{margin:1.2rem;text-align:center}section.stickerpack{margin-top:.75rem}section.stickerpack>div.sticker-list{display:flex;flex-wrap:wrap}section.stickerpack>h1{margin:0 0 0 .75rem}div.sticker{display:flex;padding:4px;cursor:pointer;position:relative;width:var(--sticker-size);height:var(--sticker-size);box-sizing:border-box}div.sticker:hover{background-color:var(--highlight-color)}div.sticker>img{display:none;width:100%;object-fit:contain}div.sticker>img.visible{display:initial}div.sticker>.icon{width:70%;height:70%;margin:15%}div.search-box{position:relative;display:flex}div.search-box>input[type=text]{flex-grow:1;background-color:var(--search-box-color);outline:none;border:none;border-radius:.25rem;height:1rem;padding:.7rem;padding-right:calc(1rem + 0.7rem);margin:.5rem;font-size:1rem;color:var(--text-color)}div.search-box>span.icon{display:flex;position:absolute;top:calc(50% - 1rem / 2);right:1rem;width:1rem;height:1rem;box-sizing:border-box}div.settings-list{display:flex;flex-direction:column}div.settings-list>*{margin:.5rem}div.settings-list button{padding:.5rem;border-radius:.25rem}div.settings-list input{width:100%}

206
web/style/index.sass Normal file
View file

@ -0,0 +1,206 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2020 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
*
font-family: sans-serif
body
margin: 0
h1
font-size: 1rem
\:root
--stickers-per-row: 4
--sticker-size: calc(100vw / var(--stickers-per-row))
$nav-sticker-size: 12vw
$nav-bottom-highlight: 2px
$nav-height: calc(#{$nav-sticker-size} + #{$nav-bottom-highlight})
$nav-height-inverse: calc(-#{$nav-sticker-size} - #{$nav-bottom-highlight})
$search-box-icon-size: 1rem
$search-box-input-height: 1rem
$search-box-input-padding: .7rem
$search-box-input-margin: .5rem
$search-box-height: calc(2 * #{$search-box-input-padding} + 2 * #{$search-box-input-margin} + #{$search-box-input-height})
main
color: var(--text-color)
&.spinner
margin-top: 5rem
&.error, &.empty
margin: 2rem
&.empty
text-align: center
&.has-content
position: fixed
top: 0
left: 0
right: 0
bottom: 0
display: grid
grid-template-rows: $nav-height min-content auto
main.theme-light
--highlight-color: #eee
--search-box-color: var(--highlight-color)
--text-color: black
background-color: white
main.theme-dark
--highlight-color: #444
--search-box-color: #383e4b
--text-color: white
background-color: #22262e
main.theme-black
--highlight-color: #222
--search-box-color: var(--highlight-color)
--text-color: white
background-color: black
.icon
width: 100%
height: 100%
background-color: var(--text-color)
mask-size: contain
-webkit-mask-size: contain
mask-image: var(--icon-image)
-webkit-mask-image: var(--icon-image)
&.icon-settings
--icon-image: url(../res/settings.svg)
&.icon-recent
--icon-image: url(../res/recent.svg)
&.icon.icon-search
--icon-image: url(../res/search.svg)
nav
display: flex
overflow-x: auto
> a
border-bottom: $nav-bottom-highlight solid transparent
&.visible
border-bottom-color: green
> div.sticker
width: $nav-sticker-size
height: $nav-sticker-size
div.pack-list, nav
scrollbar-width: none
&::-webkit-scrollbar
display: none
div.pack-list
overflow-y: auto
div.pack-list.ios-safari-hack
position: fixed
top: calc(#{$nav-height} + #{$search-box-height})
bottom: 0
left: 0
right: 0
-webkit-overflow-scrolling: touch
div.search-empty
margin: 1.2rem
text-align: center
section.stickerpack
margin-top: .75rem
> div.sticker-list
display: flex
flex-wrap: wrap
> h1
margin: 0 0 0 .75rem
div.sticker
display: flex
padding: 4px
cursor: pointer
position: relative
width: var(--sticker-size)
height: var(--sticker-size)
box-sizing: border-box
&:hover
background-color: var(--highlight-color)
> img
display: none
width: 100%
object-fit: contain
&.visible
display: initial
> .icon
width: 70%
height: 70%
margin: 15%
div.search-box
position: relative
display: flex
>input[type="text"]
flex-grow: 1
background-color: var(--search-box-color)
outline: none
border: none
border-radius: .25rem
height: $search-box-input-height
padding: $search-box-input-padding
padding-right: calc(#{$search-box-icon-size} + #{$search-box-input-padding})
margin: $search-box-input-margin
font-size: 1rem
color: var(--text-color)
>span.icon
display: flex
position: absolute
top: calc(50% - #{$search-box-icon-size} / 2)
right: $search-box-icon-size
width: $search-box-icon-size
height: $search-box-icon-size
box-sizing: border-box
div.settings-list
display: flex
flex-direction: column
> *
margin: .5rem
button
padding: .5rem
border-radius: .25rem
input
width: 100%

1
web/style/spinner.css Normal file
View file

@ -0,0 +1 @@
.sk-center-wrapper{width:100%;display:flex;justify-content:space-around}.sk-chase{position:relative;animation:sk-chase 2.5s infinite linear both}.sk-chase.green>.sk-chase-dot:before{background-color:#00c853}.sk-chase>.sk-chase-dot{width:100%;height:100%;position:absolute;left:0;top:0;animation:sk-chase-dot 2s infinite ease-in-out both}.sk-chase>.sk-chase-dot:before{content:"";display:block;width:25%;height:25%;border-radius:100%;animation:sk-chase-dot-before 2s infinite ease-in-out both;background-color:#fff}.sk-chase>.sk-chase-dot:nth-child(1){animation-delay:-1.1s}.sk-chase>.sk-chase-dot:nth-child(2){animation-delay:-1s}.sk-chase>.sk-chase-dot:nth-child(3){animation-delay:-0.9s}.sk-chase>.sk-chase-dot:nth-child(4){animation-delay:-0.8s}.sk-chase>.sk-chase-dot:nth-child(5){animation-delay:-0.7s}.sk-chase>.sk-chase-dot:nth-child(6){animation-delay:-0.6s}.sk-chase>.sk-chase-dot:nth-child(1):before{animation-delay:-1.1s}.sk-chase>.sk-chase-dot:nth-child(2):before{animation-delay:-1s}.sk-chase>.sk-chase-dot:nth-child(3):before{animation-delay:-0.9s}.sk-chase>.sk-chase-dot:nth-child(4):before{animation-delay:-0.8s}.sk-chase>.sk-chase-dot:nth-child(5):before{animation-delay:-0.7s}.sk-chase>.sk-chase-dot:nth-child(6):before{animation-delay:-0.6s}@keyframes sk-chase{100%{transform:rotate(360deg)}}@keyframes sk-chase-dot{80%,100%{transform:rotate(360deg)}}@keyframes sk-chase-dot-before{50%{transform:scale(0.4)}100%,0%{transform:scale(1)}}

68
web/style/spinner.sass Normal file
View file

@ -0,0 +1,68 @@
// Chase spinner from https://tobiasahlin.com/spinkit/. MIT license
.sk-center-wrapper
width: 100%
display: flex
justify-content: space-around
.sk-chase
position: relative
animation: sk-chase 2.5s infinite linear both
&.green > .sk-chase-dot:before
background-color: #00C853
> .sk-chase-dot
width: 100%
height: 100%
position: absolute
left: 0
top: 0
animation: sk-chase-dot 2.0s infinite ease-in-out both
&:before
content: ''
display: block
width: 25%
height: 25%
border-radius: 100%
animation: sk-chase-dot-before 2.0s infinite ease-in-out both
background-color: #FFF
&:nth-child(1)
animation-delay: -1.1s
&:nth-child(2)
animation-delay: -1.0s
&:nth-child(3)
animation-delay: -0.9s
&:nth-child(4)
animation-delay: -0.8s
&:nth-child(5)
animation-delay: -0.7s
&:nth-child(6)
animation-delay: -0.6s
&:nth-child(1):before
animation-delay: -1.1s
&:nth-child(2):before
animation-delay: -1.0s
&:nth-child(3):before
animation-delay: -0.9s
&:nth-child(4):before
animation-delay: -0.8s
&:nth-child(5):before
animation-delay: -0.7s
&:nth-child(6):before
animation-delay: -0.6s
@keyframes sk-chase
100%
transform: rotate(360deg)
@keyframes sk-chase-dot
80%, 100%
transform: rotate(360deg)
@keyframes sk-chase-dot-before
50%
transform: scale(0.4)
100%, 0%
transform: scale(1.0)

583
web/yarn.lock Normal file
View file

@ -0,0 +1,583 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@rollup/plugin-commonjs@^16.0.0":
version "16.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz#169004d56cd0f0a1d0f35915d31a036b0efe281f"
integrity sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==
dependencies:
"@rollup/pluginutils" "^3.1.0"
commondir "^1.0.1"
estree-walker "^2.0.1"
glob "^7.1.6"
is-reference "^1.2.1"
magic-string "^0.25.7"
resolve "^1.17.0"
"@rollup/plugin-inject@^4.0.0", "@rollup/plugin-inject@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.2.tgz#55b21bb244a07675f7fdde577db929c82fc17395"
integrity sha512-TSLMA8waJ7Dmgmoc8JfPnwUwVZgLjjIAM6MqeIFqPO2ODK36JqE0Cf2F54UTgCUuW8da93Mvoj75a6KAVWgylw==
dependencies:
"@rollup/pluginutils" "^3.0.4"
estree-walker "^1.0.1"
magic-string "^0.25.5"
"@rollup/plugin-json@^4.0.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==
dependencies:
"@rollup/pluginutils" "^3.0.8"
"@rollup/plugin-node-resolve@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-10.0.0.tgz#44064a2b98df7530e66acf8941ff262fc9b4ead8"
integrity sha512-sNijGta8fqzwA1VwUEtTvWCx2E7qC70NMsDh4ZG13byAXYigBNZMxALhKUSycBks5gupJdq0lFrKumFrRZ8H3A==
dependencies:
"@rollup/pluginutils" "^3.1.0"
"@types/resolve" "1.17.1"
builtin-modules "^3.1.0"
deepmerge "^4.2.2"
is-module "^1.0.0"
resolve "^1.17.0"
"@rollup/plugin-replace@^2.4.2":
version "2.4.2"
resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a"
integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==
dependencies:
"@rollup/pluginutils" "^3.1.0"
magic-string "^0.25.7"
"@rollup/pluginutils@^3.0.4", "@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
dependencies:
"@types/estree" "0.0.39"
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@types/estree@*":
version "0.0.50"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
"@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
"@types/node@*":
version "16.10.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.2.tgz#5764ca9aa94470adb4e1185fe2e9f19458992b2e"
integrity sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ==
"@types/resolve@1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
dependencies:
"@types/node" "*"
anymatch@~3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
dependencies:
normalize-path "^3.0.0"
picomatch "^2.0.4"
assert@^1.4.1:
version "1.5.0"
resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
dependencies:
object-assign "^4.1.1"
util "0.10.3"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
builtin-modules@^3.1.0, builtin-modules@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
builtins@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
"chokidar@>=3.0.0 <4.0.0":
version "3.5.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
glob-parent "~5.1.2"
is-binary-path "~2.1.0"
is-glob "~4.0.1"
normalize-path "~3.0.0"
readdirp "~3.6.0"
optionalDependencies:
fsevents "~2.3.2"
cjs-module-lexer@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
es-module-lexer@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.6.0.tgz#e72ab05b7412e62b9be37c37a09bdb6000d706f0"
integrity sha512-f8kcHX1ArhllUtb/wVSyvygoKCznIjnxhLxy7TCvIiMdT7fL4ZDTIKaadMe6eLvOXg6Wk02UeoFgUoZ2EKZZUA==
esinstall@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/esinstall/-/esinstall-1.1.7.tgz#ceabeb4b8685bf48c805a503e292dfafe4e0cb22"
integrity sha512-irDsrIF7fZ5BCQEAV5gmH+4nsK6JhnkI9C9VloXdmzJLbM1EcshPw8Ap95UUGc4ZJdzGeOrjV+jgKjQ/Z7Q3pg==
dependencies:
"@rollup/plugin-commonjs" "^16.0.0"
"@rollup/plugin-inject" "^4.0.2"
"@rollup/plugin-json" "^4.0.0"
"@rollup/plugin-node-resolve" "^10.0.0"
"@rollup/plugin-replace" "^2.4.2"
builtin-modules "^3.2.0"
cjs-module-lexer "^1.2.1"
es-module-lexer "^0.6.0"
execa "^5.1.1"
is-valid-identifier "^2.0.2"
kleur "^4.1.1"
mkdirp "^1.0.3"
picomatch "^2.3.0"
resolve "^1.20.0"
rimraf "^3.0.0"
rollup "~2.37.1"
rollup-plugin-polyfill-node "^0.6.2"
slash "~3.0.0"
validate-npm-package-name "^3.0.0"
vm2 "^3.9.2"
estree-walker@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
estree-walker@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
execa@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
human-signals "^2.1.0"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.1"
onetime "^5.1.2"
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@~2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
get-stream@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
glob@^7.1.3, glob@^7.1.6:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
htm@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/htm/-/htm-3.1.0.tgz#0c305493b60da9f6ed097a2aaf4c994bd85ea022"
integrity sha512-L0s3Sid5r6YwrEvkig14SK3Emmc+kIjlfLhEGn2Vy3bk21JyDEes4MoDsbJk6luaPp8bugErnxPz86ZuAw6e5Q==
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
dependencies:
binary-extensions "^2.0.0"
is-core-module@^2.2.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3"
integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==
dependencies:
has "^1.0.3"
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-reference@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
dependencies:
"@types/estree" "*"
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
is-valid-identifier@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-valid-identifier/-/is-valid-identifier-2.0.2.tgz#146d9dbf29821b8118580b039d2203aa4bd1da4b"
integrity sha512-mpS5EGqXOwzXtKAg6I44jIAqeBfntFLxpAth1rrKbxtKyI6LPktyDYpHBI+tHlduhhX/SF26mFXmxQu995QVqg==
dependencies:
assert "^1.4.1"
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
kleur@^4.1.1:
version "4.1.4"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d"
integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==
magic-string@^0.25.5, magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
mkdirp@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
onetime@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
preact@^10.5.14:
version "10.5.14"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.5.14.tgz#0b14a2eefba3c10a57116b90d1a65f5f00cd2701"
integrity sha512-KojoltCrshZ099ksUZ2OQKfbH66uquFoxHSbnwKbTJHeQNvx42EmC7wQVWNuDt6vC5s3nudRHFtKbpY4ijKlaQ==
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
dependencies:
picomatch "^2.2.1"
resolve@^1.17.0, resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
rimraf@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
rollup-plugin-polyfill-node@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.6.2.tgz#dea62e00f5cc2c174e4b4654b5daab79b1a92fc3"
integrity sha512-gMCVuR0zsKq0jdBn8pSXN1Ejsc458k2QsFFvQdbHoM0Pot5hEnck+pBP/FDwFS6uAi77pD3rDTytsaUStsOMlA==
dependencies:
"@rollup/plugin-inject" "^4.0.0"
rollup@~2.37.1:
version "2.37.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.37.1.tgz#aa7aadffd75c80393f9314f9857e851b0ffd34e7"
integrity sha512-V3ojEeyGeSdrMSuhP3diBb06P+qV4gKQeanbDv+Qh/BZbhdZ7kHV0xAt8Yjk4GFshq/WjO7R4c7DFM20AwTFVQ==
optionalDependencies:
fsevents "~2.1.2"
sass@^1.42.1:
version "1.42.1"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.42.1.tgz#5ab17bebc1cb1881ad2e0c9a932c66ad64e441e2"
integrity sha512-/zvGoN8B7dspKc5mC6HlaygyCBRvnyzzgD5khiaCfglWztY99cYoiTUksVx11NlnemrcfH5CEaCpsUKoW0cQqg==
dependencies:
chokidar ">=3.0.0 <4.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
signal-exit@^3.0.3:
version "3.0.5"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f"
integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==
slash@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
sourcemap-codec@^1.4.4:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
util@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
dependencies:
inherits "2.0.1"
validate-npm-package-name@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e"
integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34=
dependencies:
builtins "^1.0.3"
vm2@^3.9.2:
version "3.9.3"
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.3.tgz#29917f6cc081cc43a3f580c26c5b553fd3c91f40"
integrity sha512-smLS+18RjXYMl9joyJxMNI9l4w7biW8ilSDaVRvFBDwOH8P0BK1ognFQTpg0wyQ6wIKLTblHJvROW692L/E53Q==
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=