aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/index.js')
-rw-r--r--web/src/index.js126
1 files changed, 82 insertions, 44 deletions
diff --git a/web/src/index.js b/web/src/index.js
index a215c46..ff570da 100644
--- a/web/src/index.js
+++ b/web/src/index.js
@@ -13,9 +13,10 @@
//
// 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 {html, render, Component} from "../lib/htm/preact.js"
+import {Spinner} from "./spinner.js"
+import {SearchBox} from "./search-box.js"
+import {giphyIsEnabled, GiphySearchTab, setGiphyAPIKey} from "./giphy.js"
import * as widgetAPI from "./widget-api.js"
import * as frequent from "./frequently-used.js"
@@ -31,7 +32,7 @@ if (params.has('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`
+const makeThumbnailURL = mxc => `${HOMESERVER_URL}/_matrix/media/v3/thumbnail/${mxc.slice(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
@@ -52,6 +53,7 @@ class App extends Component {
super(props)
this.defaultTheme = params.get("theme")
this.state = {
+ viewingGifs: false,
packs: defaultState.packs,
loading: true,
error: null,
@@ -118,7 +120,7 @@ class App extends Component {
filtering: {
...this.state.filtering,
searchTerm,
- packs: packsWithFilteredStickers.filter(({ stickers }) => !!stickers.length),
+ packs: packsWithFilteredStickers.filter(({stickers}) => !!stickers.length),
},
})
}
@@ -135,10 +137,10 @@ class App extends Component {
setTheme(theme) {
if (theme === "default") {
delete localStorage.mauStickerThemeOverride
- this.setState({ theme: this.defaultTheme })
+ this.setState({theme: this.defaultTheme})
} else {
localStorage.mauStickerThemeOverride = theme
- this.setState({ theme: theme })
+ this.setState({theme: theme})
}
}
@@ -154,7 +156,7 @@ class App extends Component {
_loadPacks(disableCache = false) {
const cache = disableCache ? "no-cache" : undefined
- fetch(INDEX, { cache }).then(async indexRes => {
+ fetch(INDEX, {cache}).then(async indexRes => {
if (indexRes.status >= 400) {
this.setState({
loading: false,
@@ -164,13 +166,14 @@ class App extends Component {
}
const indexData = await indexRes.json()
HOMESERVER_URL = indexData.homeserver_url || HOMESERVER_URL
+ setGiphyAPIKey(indexData.giphy_api_key, indexData.giphy_mxc_prefix)
// 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 })
+ packRes = await fetch(packFile, {cache})
} else {
- packRes = await fetch(`${PACKS_BASE_URL}/${packFile}`, { cache })
+ packRes = await fetch(`${PACKS_BASE_URL}/${packFile}`, {cache})
}
const packData = await packRes.json()
for (const sticker of packData.stickers) {
@@ -182,7 +185,7 @@ class App extends Component {
})
}
this.updateFrequentlyUsed()
- }, error => this.setState({ loading: false, error }))
+ }, error => this.setState({loading: false, error}))
}
componentDidMount() {
@@ -214,6 +217,9 @@ class App extends Component {
let maxXElem = null
for (const entry of intersections) {
const packID = entry.target.getAttribute("data-pack-id")
+ if (!packID) {
+ continue
+ }
const navElement = document.getElementById(`nav-${packID}`)
if (entry.isIntersecting) {
navElement.classList.add("visible")
@@ -230,9 +236,9 @@ class App extends Component {
}
}
if (minXElem !== null) {
- minXElem.scrollIntoView({ inline: "start" })
+ minXElem.scrollIntoView({inline: "start"})
} else if (maxXElem !== null) {
- maxXElem.scrollIntoView({ inline: "end" })
+ maxXElem.scrollIntoView({inline: "end"})
}
}
@@ -268,36 +274,66 @@ class App extends Component {
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]
+ 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>`
+ 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>`
+ 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="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 onClickOverride = this.state.viewingGifs
+ ? (evt, packID) => {
+ evt.preventDefault()
+ this.setState({viewingGifs: false}, () => {
+ scrollToSection(null, packID)
+ })
+ } : null
+ const switchToGiphy = () => this.setState({viewingGifs: true, filtering: defaultState.filtering})
+
+ return html`
+ <main class="has-content ${theme}">
+ <nav onWheel=${this.navScroll} ref=${elem => this.navRef = elem}>
+ ${giphyIsEnabled() && html`
+ <${NavBarItem} pack=${{id: "giphy", title: "GIPHY"}} iconOverride="giphy" onClickOverride=${switchToGiphy} extraClass=${this.state.viewingGifs ? "visible" : ""}/>
+ `}
+ <${NavBarItem} pack=${this.state.frequentlyUsed} iconOverride="recent" onClickOverride=${onClickOverride}/>
+ ${this.state.packs.map(pack => html`<${NavBarItem} id=${pack.id} pack=${pack} onClickOverride=${onClickOverride}/>`)}
+ <${NavBarItem} pack=${{id: "settings", title: "Settings"}} iconOverride="settings" onClickOverride=${onClickOverride}/>
+ </nav>
+
+ ${this.state.viewingGifs ? html`
+ <${GiphySearchTab}/>
+ ` : html`
+ <${SearchBox} onInput=${this.searchStickers} value=${this.state.filtering.searchTerm ?? ""}/>
+ <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`
+const Settings = ({app}) => html`
<section class="stickerpack settings" id="pack-settings" data-pack-id="settings">
<h1>Settings</h1>
<div class="settings-list">
@@ -306,7 +342,7 @@ const Settings = ({ app }) => html`
<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)} />
+ onInput=${evt => app.setStickersPerRow(evt.target.value)}/>
</div>
<div>
<label for="theme">Theme: </label>
@@ -325,13 +361,15 @@ const Settings = ({ app }) => html`
// 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()
+ if (pack) {
+ 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}>
+const NavBarItem = ({pack, iconOverride = null, onClickOverride = null, extraClass = null}) => html`
+ <a href="#pack-${pack.id}" id="nav-${pack.id}" data-pack-id=${pack.id} title=${pack.title} class="${extraClass}"
+ onClick=${onClickOverride ? (evt => onClickOverride(evt, pack.id)) : (isMobileSafari ? (evt => scrollToSection(evt, pack.id)) : undefined)}>
<div class="sticker">
${iconOverride ? html`
<span class="icon icon-${iconOverride}"/>
@@ -343,7 +381,7 @@ const NavBarItem = ({ pack, iconOverride = null }) => html`
</a>
`
-const Pack = ({ pack, send }) => html`
+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">
@@ -354,10 +392,10 @@ const Pack = ({ pack, send }) => html`
</section>
`
-const Sticker = ({ content, send }) => html`
+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} />
+ <img data-src=${makeThumbnailURL(content.url)} alt=${content.body} title=${content.body}/>
</div>
`
-render(html`<${App} />`, document.body)
+render(html`<${App}/>`, document.body)
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage