From 0d92f65f7e905792f2a3a662a9374523ff77e866 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 1 Jan 2023 19:41:42 +0800 Subject: [PATCH 01/59] Esc for compose field --- src/components/compose.jsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/compose.jsx b/src/components/compose.jsx index e2c408ba..05fda4bd 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -2,6 +2,7 @@ import './compose.css'; import '@github/text-expander-element'; import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; +import { useHotkeys } from 'react-hotkeys-hook'; import stringLength from 'string-length'; import supportedLanguages from '../data/status-supported-languages'; @@ -445,6 +446,18 @@ function Compose({ setCharCount(getCharCount()); }; + useHotkeys( + 'esc', + () => { + if (!standalone && confirmClose()) { + onClose(); + } + }, + { + enableOnFormTags: true, + }, + ); + return (
From bfaefbe17869dfbe8585dceb44de36fe7a6b153a Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 1 Jan 2023 20:53:40 +0800 Subject: [PATCH 02/59] Disable autocapitalize on input field And disable a bunch of others too --- src/pages/login.jsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pages/login.jsx b/src/pages/login.jsx index 9dd2dc76..fcf797ce 100644 --- a/src/pages/login.jsx +++ b/src/pages/login.jsx @@ -68,6 +68,10 @@ function Login() { ref={instanceURLRef} disabled={uiState === 'loading'} list="instances-list" + autocorrect="off" + autocapitalize="off" + autocomplete="off" + spellcheck="false" /> {instancesList.map((instance) => ( From 727b944f3b1aeed0a0715c52742c20dc95fa3f66 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 1 Jan 2023 20:59:55 +0800 Subject: [PATCH 03/59] toLowerCase() all the instance URLs! --- src/app.jsx | 4 ++-- src/components/compose.jsx | 6 +++--- src/pages/login.jsx | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app.jsx b/src/app.jsx index c8cccc91..86cf33e5 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -82,7 +82,7 @@ function App() { let account = accounts.find((a) => a.info.id === mastoAccount.id); if (account) { account.info = mastoAccount; - account.instanceURL = instanceURL; + account.instanceURL = instanceURL.toLowerCase(); account.accessToken = accessToken; } else { account = { @@ -166,7 +166,7 @@ function App() { console.log(info); const { uri, domain } = info; const instances = store.local.getJSON('instances') || {}; - instances[domain || uri] = info; + instances[(domain || uri).toLowerCase()] = info; store.local.setJSON('instances', instances); })(); }); diff --git a/src/components/compose.jsx b/src/components/compose.jsx index 05fda4bd..ac059ce5 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -73,9 +73,9 @@ function Compose({ const configuration = useMemo(() => { try { const instances = store.local.getJSON('instances'); - const currentInstance = accounts.find( - (a) => a.info.id === currentAccount, - ).instanceURL; + const currentInstance = accounts + .find((a) => a.info.id === currentAccount) + .instanceURL.toLowerCase(); const config = instances[currentInstance].configuration; console.log(config); return config; diff --git a/src/pages/login.jsx b/src/pages/login.jsx index fcf797ce..63312d5c 100644 --- a/src/pages/login.jsx +++ b/src/pages/login.jsx @@ -16,14 +16,14 @@ function Login() { useEffect(() => { if (cachedInstanceURL) { - instanceURLRef.current.value = cachedInstanceURL; + instanceURLRef.current.value = cachedInstanceURL.toLowerCase(); } }, []); const onSubmit = (e) => { e.preventDefault(); const { elements } = e.target; - let instanceURL = elements.instanceURL.value; + let instanceURL = elements.instanceURL.value.toLowerCase(); // Remove protocol from instance URL instanceURL = instanceURL.replace(/(^\w+:|^)\/\//, ''); store.local.set('instanceURL', instanceURL); From 2925afeefc6d2e3ba9f05e018bd2ab9fdd93222c Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 1 Jan 2023 21:00:43 +0800 Subject: [PATCH 04/59] Refetch list of instance URLs Also bump list to more than 200 --- scripts/fetch-instances-list.js | 3 +- src/data/instances.json | 521 +++++++++++++++++++++++--------- 2 files changed, 379 insertions(+), 145 deletions(-) diff --git a/scripts/fetch-instances-list.js b/scripts/fetch-instances-list.js index 7b39126c..f90a2fb7 100644 --- a/scripts/fetch-instances-list.js +++ b/scripts/fetch-instances-list.js @@ -3,7 +3,8 @@ import fs from 'fs'; const { INSTANCES_SOCIAL_SECRET_TOKEN } = process.env; const params = new URLSearchParams({ - count: 200, + count: 0, + min_users: 1_000, sort_by: 'active_users', sort_order: 'desc', }); diff --git a/src/data/instances.json b/src/data/instances.json index dd5018f8..a936f9ad 100644 --- a/src/data/instances.json +++ b/src/data/instances.json @@ -1,202 +1,435 @@ [ "mastodon.social", + "mstdn.social", "mastodon.world", "mas.to", "pawoo.net", "mastodon.online", + "infosec.exchange", "mstdn.jp", + "mastodonapp.uk", + "hachyderm.io", + "techhub.social", + "fosstodon.org", "universeodon.com", "mastodon.lol", - "mastodonapp.uk", - "infosec.exchange", - "mastodon.uno", - "techhub.social", "mastodon.sdf.org", - "fosstodon.org", "troet.cafe", - "masto.ai", + "mastodon.uno", + "mastodon.nl", "mstdn.party", - "c.im", - "hachyderm.io", - "m.cmx.im", + "masto.ai", "mstdn.ca", - "sfba.social", + "home.social", + "c.im", "kolektiva.social", - "mastodon.scot", - "ohai.social", + "m.cmx.im", + "sfba.social", "fedibird.com", "piaille.fr", - "home.social", - "mindly.social", - "mastodon.nl", - "toot.community", - "aus.social", - "thu.closed.social", "mastodon.gamedev.place", - "nerdculture.de", + "mastodon.scot", + "mindly.social", + "ohai.social", "mastodon.cloud", - "mastodon.ie", + "toot.community", "det.social", - "mastodon.au", + "aus.social", "nrw.social", "mastodon.art", "chaos.social", + "social.vivaldi.net", + "mastodon.ie", "norden.social", + "sueden.social", + "mastodon.top", + "mastodon.au", + "mastodontech.de", + "mas.todon.de", "ioc.exchange", "alive.bar", - "tkz.one", - "sueden.social", - "mastodon.nu", - "mastodon.top", - "mastouille.fr", - "mastodontech.de", - "o3o.ca", "social.tchncs.de", + "mastodon.nu", + "social.cologne", + "mastouille.fr", + "o3o.ca", + "mathstodon.xyz", "noagendasocial.com", "newsie.social", - "masto.es", - "planet.moe", - "social.vivaldi.net", - "ravenation.club", - "wxw.moe", - "mathstodon.xyz", - "social.cologne", - "mastodon.nz", - "qoto.org", - "hessen.social", + "sigmoid.social", "mastodon.com.tr", - "ruhr.social", + "hessen.social", "muenchen.social", - "mamot.fr", - "twit.social", - "dice.camp", "meow.social", - "www.masto.pt", - "social.anoxinon.de", - "www.sociale.network", + "masto.es", + "masto.nu", "tech.lgbt", + "ruhr.social", + "mastodon.green", + "mstdn.plus", + "wxw.moe", + "qoto.org", + "mamot.fr", + "tkz.one", + "dice.camp", + "social.anoxinon.de", + "mastodon.nz", + "twit.social", + "ravenation.club", + "planet.moe", + "mstdn.science", + "med-mastodon.com", "econtwitter.net", + "fediscience.org", + "toot.io", "masthead.social", - "glasgow.social", - "ieji.de", + "social.dev-wiki.de", + "mastodont.cat", "toot.wales", + "ieji.de", "ecoevo.social", "ro-mastodon.puyo.jp", - "noc.social", - "indieweb.social", "zirk.us", - "twingyeo.kr", + "noc.social", "social.linux.pizza", - "mastodont.cat", - "social.dev-wiki.de", - "mastodonczech.cz", - "climatejustice.social", - "eldritch.cafe", - "g0v.social", - "socel.net", - "dju.social", - "mastodontti.fi", - "101010.pl", - "framapiaf.org", - "wien.rocks", - "botsin.space", - "mastodon.bida.im", - "bildung.social", - "pouet.chapril.org", - "urbanists.social", - "wandering.shop", - "masto.pt", - "union.place", - "metalhead.club", - "ruby.social", - "hiveway.net", - "h4.io", - "genomic.social", - "mastodon-belgium.be", - "mastodon.xyz", - "octodon.social", - "pol.social", - "tooot.im", - "berlin.social", - "sciences.social", - "mstdn.guru", - "qdon.space", - "mastodon.radio", - "lile.cl", - "masto.nu", - "witches.live", + "cyberplace.social", + "indieweb.social", "mastodonners.nl", - "muenster.im", - "lor.sh", - "phpc.social", - "pewtix.com", - "social.librem.one", + "convo.casa", + "twingyeo.kr", + "sself.co", + "urbanists.social", + "glasgow.social", + "botsin.space", + "eldritch.cafe", + "climatejustice.social", + "theblower.au", + "framapiaf.org", + "artsio.com", + "mastodon.iriseden.eu", + "socel.net", + "g0v.social", + "mastodonczech.cz", + "mastodontti.fi", + "wandering.shop", + "thu.closed.social", + "mastodon.bida.im", + "geekdom.social", + "stranger.social", + "cupoftea.social", + "bildung.social", + "awscommunity.social", + "mas.town", + "ruby.social", + "sciences.social", + "wien.rocks", + "respublicae.eu", + "metalhead.club", + "pouet.chapril.org", + "genomic.social", + "dju.social", + "101010.pl", + "graphics.social", + "defcon.social", + "mastodon.xyz", + "bark.lgbt", + "witches.live", + "climatejustice.rocks", "rollenspiel.social", - "peoplemaking.games", + "berlin.social", + "masto.pt", + "litmind.club", + "livellosegreto.it", + "mstdn.guru", + "nerdculture.de", + "journa.host", + "octodon.social", + "union.place", + "mastodon-belgium.be", + "mastodon.radio", + "pol.social", + "rheinneckar.social", + "hometech.social", + "androiddev.social", + "social.librem.one", "kinky.business", - "mastodon.fun", - "me.ns.ci", - "mastodon.eus", + "phpc.social", + "mast.lat", + "muenster.im", + "mastodon.chasem.dev", + "tooot.im", + "musician.social", "dresden.network", - "hostux.social", - "scholar.social", - "freiburg.social", - "todon.eu", - "writing.exchange", + "swiss.social", + "h4.io", "toot.aquilenet.fr", "digitalcourage.social", - "rheinneckar.social", - "discuss.systems", - "defcon.social", - "snabelen.no", + "toad.social", + "poweredbygay.social", + "hostux.social", "mastodon.se", + "mastodon.me.uk", "rubber.social", - "fulda.social", - "vis.social", - "toot.funami.tech", - "mast.dragon-fly.club", + "pewtix.com", + "mastodon.berlin", + "lor.sh", + "mastodon.fun", + "me.ns.ci", + "snabelen.no", + "freiburg.social", "disabled.social", - "medibubble.org", - "mastodon.technology", + "spore.social", + "qdon.space", + "beta.qdon.space", + "scholar.social", "vmst.io", - "mstdn.io", - "equestria.social", - "vocalodon.net", - "mastodon.ml", - "libretooth.gr", + "astrodon.social", + "masto.nobigtech.es", + "hci.social", + "mastodon.eus", + "todon.eu", + "discuss.systems", "tooting.ch", - "dizl.de", - "best-friends.chat", - "romancelandia.club", - "queer.party", - "tilde.zone", - "xarxa.cloud", - "abdl.link", - "bitcoinhackers.org", - "photog.social", - "macaw.social", + "paquita.masto.host", + "fulda.social", + "lile.cl", + "medibubble.org", + "writing.exchange", + "historians.social", + "vocalodon.net", + "vis.social", "yiff.life", - "sociale.network", + "fur.lgbt", + "peoplemaking.games", + "hcommons.social", + "mstdn.io", + "libretooth.gr", + "m.sclo.nl", + "pettingzoo.co", + "mastodon.zaclys.com", + "equestria.social", + "best-friends.chat", "ursal.zone", - "eupolicy.social", - "gruene.social", - "artisan.chat", - "graz.social", + "bitcoinhackers.org", + "uiuxdev.social", + "queer.party", + "mastodon.ml", + "aethy.com", + "abdl.link", + "mastodon.com.py", + "mapstodon.space", + "typo.social", + "cryptodon.lol", + "tilde.zone", + "computerfairi.es", "social.coop", - "mstdn.id", - "social.sciences.re", - "ludosphere.fr", - "social.politicaconciencia.org", - "oslo.town", - "scicomm.xyz", + "mast.dragon-fly.club", + "dragon-fly.club", "floss.social", - "creators.social", - "tabletop.social", + "photog.social", "bonn.social", - "openbiblio.social", - "mastodon.la", - "halifaxsocial.ca", + "sciencemastodon.com", + "mastodon.coffee", + "mastorol.es", + "federated.press", + "toot.funami.tech", + "mastodon.gal", + "tabletop.social", + "shakedown.social", + "dizl.de", + "romancelandia.club", + "oslo.town", + "graz.social", + "sociale.network", + "todon.nl", + "nofan.xyz", + "data-folks.masto.host", + "scicomm.xyz", + "layer8.space", + "artisan.chat", "freeradical.zone", + "toot.cat", + "fandom.ink", + "twiukraine.com", + "eupolicy.social", + "xarxa.cloud", + "bsd.network", + "weirder.earth", + "linuxrocks.online", + "mastodon.cat", + "girlcock.club", + "bolha.us", + "zeroes.ca", + "douchi.space", + "cybre.space", + "mastodon.la", + "sunny.garden", + "bbq.snoot.com", + "liker.social", + "vulpine.club", + "imastodon.net", + "mstdn.maud.io", + "freeatlantis.com", + "is.nota.live", + "mastodon.org.uk", + "mastodon.arch-linux.cz", + "mona.do", + "tyrol.social", + "mstdn.id", + "mastodon.uy", + "mastodon.in.th", + "kurry.social", + "toot.cafe", + "shelter.moe", + "social.politicaconciencia.org", + "h-net.social", + "mstdn.mx", + "kopiti.am", + "mastodon.vlaanderen", + "mao.mastodonhub.com", + "cloud-native.social", + "mograph.social", + "oc.todon.fr", + "ura-mstdn.com", + "uri.life", + "liberdon.com", + "kinkyelephant.com", + "nojack.easydns.ca", + "mastodon.be", + "podcastindex.social", + "blacktwitter.io", + "awoo.space", + "woof.group", + "ani.work", + "colorid.es", + "seo.chat", + "mental.social", + "plural.cafe", + "ika.queloud.net", + "mastodon.com.br", + "mstdn.tokyocameraclub.com", + "donphan.social", + "gensokyo.town", + "ichiji.social", + "sunbeam.city", + "mstdn.kemono-friends.info", + "littlefo.rest", + "kirakiratter.com", + "uwu.social", + "elekk.xyz", + "hispagatos.space", + "hello.2heng.xin", + "the.fores.top", + "mstdn.fr", + "mastodon.mnetwork.co.kr", + "mastodon.gougere.fr", + "dobbs.town", + "gameliberty.club", + "gensokyo.social", + "mathtod.online", + "mastodon.cc", + "iztasocial.site", + "mastodon.pirateparty.be", + "dingdash.com", + "mastodon.partipirate.org", + "oulipo.social", + "anticapitalist.party", + "kemonodon.club", + "toot.turbo.chat", + "photodn.net", + "otogamer.me", + "bear.community", + "tablegame.mstdn.cloud", + "anarchism.space", + "ffxiv-mastodon.com", + "lgbt.io", + "lou.lt", + "social.chinwag.org", + "chinwag.org", + "aleph.land", + "social.slat.org", + "mastodon.juggler.jp", + "eigadon.net", + "vocalounge.cafe", + "acg.mn", + "acg.debula.ml", + "eletusk.club", + "otoya.space", + "social.coletivos.org", + "mastodon.cipherbliss.com", + "truthsocial.co.in", + "mstdn.osaka", + "social.targaryen.house", + "catdon.life", + "stereodon.social", + "social.opendesktop.org", + "nasface.cz", + "toot.site", + "fetswing.org", + "vipgirlfriend.xxx", + "mastodon.elte.hu", + "bgme.me", + "kinbaku.club", + "m.rthome.me", + "animalliberation.social", + "mastodon.librelabucm.org", + "mastodon.gza.jp", + "med-mammoth.com", + "hearthtodon.com", + "counter.social", "kfem.cat", - "federated.press" + "pet123.club", + "beta.woof.group", + "explosion.party", + "id.cc", + "freespeechextremist.com", + "cawfee.club", + "1234.as", + "fedi.absturztau.be", + "fsmi.social", + "go5.dev", + "poa.st", + "patriot.online", + "seaofog.com", + "libranet.de", + "tea.codes", + "pixelfed.social", + "shitposter.club", + "squeet.me", + "shared.graphics", + "glindr.org", + "pxlmo.com", + "pixel.tchncs.de", + "love.alicecomplex.com", + "friendica.eskimo.com", + "meatbag.app", + "fediverse.bbad.com", + "pix.toot.wales", + "fgc.network", + "bookrastinating.com", + "pixey.org", + "pixelfed.tokyo", + "chudbuds.lol", + "freeframe.masto.host", + "varishangout.net", + "friendica.vrije-mens.org", + "bae.st", + "brighteon.social", + "pixelfed.uno", + "helladoge.com", + "donotban.com", + "bookwyrm.social", + "spinster.xyz", + "pixelfed.de", + "metapixl.com", + "venera.social", + "blob.cat", + "onevery.ignorelist.com", + "cliq.buzz", + "pxl.roflcopter.fr", + "p.1069-3.com", + "www2.patriot.online", + "gc2.jp", + "soap.shitposter.club", + "www.mastodon.scot" ] \ No newline at end of file From 8099fedf8266904e73b0e10c2752ae32966f0df5 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Sun, 1 Jan 2023 21:02:06 +0800 Subject: [PATCH 05/59] Don't store instances list inside JS bundle --- src/pages/login.jsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/pages/login.jsx b/src/pages/login.jsx index 63312d5c..d184ceaa 100644 --- a/src/pages/login.jsx +++ b/src/pages/login.jsx @@ -3,7 +3,7 @@ import './login.css'; import { useEffect, useRef, useState } from 'preact/hooks'; import Loader from '../components/loader'; -import instancesList from '../data/instances.json'; +import instancesListURL from '../data/instances.json?url'; import { getAuthorizationURL, registerApplication } from '../utils/auth'; import store from '../utils/store'; import useTitle from '../utils/useTitle'; @@ -14,6 +14,20 @@ function Login() { const cachedInstanceURL = store.local.get('instanceURL'); const [uiState, setUIState] = useState('default'); + const [instancesList, setInstancesList] = useState([]); + useEffect(() => { + (async () => { + try { + const res = await fetch(instancesListURL); + const data = await res.json(); + setInstancesList(data); + } catch (e) { + // Silently fail + console.error(e); + } + })(); + }, []); + useEffect(() => { if (cachedInstanceURL) { instanceURLRef.current.value = cachedInstanceURL.toLowerCase(); From 21bdb51cd69e6208b99421ca9d57c93a99296688 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 12:03:06 +0800 Subject: [PATCH 06/59] Compose pop-in/out now can work with non-id medias Commented out for now to see if it really works The bug is due to valtio proxying the File object --- src/app.jsx | 15 +++++++-- src/components/compose.jsx | 64 ++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/app.jsx b/src/app.jsx index 86cf33e5..034bc929 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -237,13 +237,22 @@ function App() { replyToStatus={ typeof snapStates.showCompose !== 'boolean' ? snapStates.showCompose.replyToStatus - : null + : window.__COMPOSE__?.replyToStatus || null + } + editStatus={ + states.showCompose?.editStatus || + window.__COMPOSE__?.editStatus || + null + } + draftStatus={ + states.showCompose?.draftStatus || + window.__COMPOSE__?.draftStatus || + null } - editStatus={states.showCompose?.editStatus || null} - draftStatus={states.showCompose?.draftStatus || null} onClose={(results) => { const { newStatus } = results || {}; states.showCompose = false; + window.__COMPOSE__ = null; if (newStatus) { states.reloadStatusPage++; setTimeout(() => { diff --git a/src/components/compose.jsx b/src/components/compose.jsx index ac059ce5..96b19b24 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -476,21 +476,21 @@ function Compose({ disabled={uiState === 'loading'} onClick={() => { // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window - const containNonIDMediaAttachments = - mediaAttachments.length > 0 && - mediaAttachments.some((media) => !media.id); - if (containNonIDMediaAttachments) { - const yes = confirm( - 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?', - ); - if (!yes) { - return; - } - } + // const containNonIDMediaAttachments = + // mediaAttachments.length > 0 && + // mediaAttachments.some((media) => !media.id); + // if (containNonIDMediaAttachments) { + // const yes = confirm( + // 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?', + // ); + // if (!yes) { + // return; + // } + // } - const mediaAttachmentsWithIDs = mediaAttachments.filter( - (media) => media.id, - ); + // const mediaAttachmentsWithIDs = mediaAttachments.filter( + // (media) => media.id, + // ); const newWin = openCompose({ editStatus, @@ -502,7 +502,7 @@ function Compose({ language, sensitive, poll, - mediaAttachments: mediaAttachmentsWithIDs, + mediaAttachments, }, }); @@ -537,17 +537,17 @@ function Compose({ disabled={uiState === 'loading'} onClick={() => { // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window - const containNonIDMediaAttachments = - mediaAttachments.length > 0 && - mediaAttachments.some((media) => !media.id); - if (containNonIDMediaAttachments) { - const yes = confirm( - 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?', - ); - if (!yes) { - return; - } - } + // const containNonIDMediaAttachments = + // mediaAttachments.length > 0 && + // mediaAttachments.some((media) => !media.id); + // if (containNonIDMediaAttachments) { + // const yes = confirm( + // 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?', + // ); + // if (!yes) { + // return; + // } + // } if (!window.opener) { alert('Looks like you closed the parent window.'); @@ -561,13 +561,13 @@ function Compose({ if (!yes) return; } - const mediaAttachmentsWithIDs = mediaAttachments.filter( - (media) => media.id, - ); + // const mediaAttachmentsWithIDs = mediaAttachments.filter( + // (media) => media.id, + // ); onClose({ fn: () => { - window.opener.__STATES__.showCompose = { + const passData = { editStatus, replyToStatus, draftStatus: { @@ -577,9 +577,11 @@ function Compose({ language, sensitive, poll, - mediaAttachments: mediaAttachmentsWithIDs, + mediaAttachments, }, }; + window.opener.__COMPOSE__ = passData; + window.opener.__STATES__.showCompose = true; }, }); }} From 07dff34e20e0436a7ef6291f1a86f1032078556a Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 14:21:38 +0800 Subject: [PATCH 07/59] Show formatted duration for video media --- src/components/status.css | 55 ++++++++++++++++++++------------------- src/components/status.jsx | 17 ++++++++++++ 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/components/status.css b/src/components/status.css index ae65237a..ebc1d6ad 100644 --- a/src/components/status.css +++ b/src/components/status.css @@ -357,39 +357,40 @@ position: relative; background-clip: padding-box; } -.status .media-video:before { - /* draw a circle in the middle */ - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); +.status .media-video[data-formatted-duration]:before { + pointer-events: none; + content: '⏵'; width: 70px; height: 70px; - border-radius: 50%; + font-size: 50px; + position: absolute; + text-indent: 3px; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: var(--text-insignificant-color); background-color: var(--bg-blur-color); backdrop-filter: blur(6px) saturate(3) invert(0.2); - z-index: 1; + display: flex; + place-content: center; + place-items: center; + border-radius: 70px; } -.status .media-video:after { - /* show play icon */ - content: ''; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-35%, -50%); - width: 0; - height: 0; - border-style: solid; - border-width: 15px 0 15px 26px; - border-color: transparent transparent transparent - var(--text-insignificant-color); +.status .media-video[data-formatted-duration]:hover:before { + color: var(--text-color); +} +.status .media-video[data-formatted-duration]:after { + font-size: 12px; pointer-events: none; - opacity: 0.75; - z-index: 2; -} -.status .media-video:hover:after { - opacity: 1; + content: attr(data-formatted-duration); + position: absolute; + bottom: 8px; + left: 8px; + color: var(--bg-color); + background-color: var(--text-color); + backdrop-filter: blur(6px) saturate(3) invert(0.2); + border-radius: 4px; + padding: 0 4px; } .status .media-gif video { object-fit: cover; diff --git a/src/components/status.jsx b/src/components/status.jsx index 5f8df8af..5dbff1f5 100644 --- a/src/components/status.jsx +++ b/src/components/status.jsx @@ -764,9 +764,11 @@ function Media({ media, showOriginal, onClick = () => {} }) { const shortDuration = original.duration <= 20; const isGIF = type === 'gifv' || shortDuration; const loopable = original.duration <= 60; + const formattedDuration = formatDuration(original.duration); return (
{} }) { ); } +function formatDuration(time) { + if (!time) return; + let hours = Math.floor(time / 3600); + let minutes = Math.floor((time % 3600) / 60); + let seconds = Math.round(time % 60); + + if (hours === 0) { + return `${minutes}:${seconds.toString().padStart(2, '0')}`; + } else { + return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds + .toString() + .padStart(2, '0')}`; + } +} + export default Status; From 89cb909094d7bec2aa28089febb35373d95dd418 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 14:22:01 +0800 Subject: [PATCH 08/59] Fix NODE_ENV not even working here --- vite.config.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/vite.config.js b/vite.config.js index 9e0fa720..48a6268c 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,11 +7,9 @@ import htmlPlugin from 'vite-plugin-html-config'; import VitePluginHtmlEnv from 'vite-plugin-html-env'; import { VitePWA } from 'vite-plugin-pwa'; -const { - VITE_CLIENT_NAME: CLIENT_NAME, - NODE_ENV, - VITE_APP_ERROR_LOGGING, -} = loadEnv('production', process.cwd()); +const { NODE_ENV } = process.env; +const { VITE_CLIENT_NAME: CLIENT_NAME, VITE_APP_ERROR_LOGGING: ERROR_LOGGING } = + loadEnv('production', process.cwd()); const commitHash = execSync('git rev-parse --short HEAD').toString().trim(); @@ -32,7 +30,7 @@ export default defineConfig({ splitVendorChunkPlugin(), VitePluginHtmlEnv(), htmlPlugin({ - headScripts: VITE_APP_ERROR_LOGGING ? [rollbarCode] : [], + headScripts: ERROR_LOGGING ? [rollbarCode] : [], }), VitePWA({ manifest: { From fee37f9880d295fa545b41c208573ca030f31eb3 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 14:22:31 +0800 Subject: [PATCH 09/59] Disable workbox logging because it's too verbose --- public/sw.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/sw.js b/public/sw.js index 44af1ed5..814b3820 100644 --- a/public/sw.js +++ b/public/sw.js @@ -3,6 +3,8 @@ import { ExpirationPlugin } from 'workbox-expiration'; import { RegExpRoute, registerRoute, Route } from 'workbox-routing'; import { CacheFirst, StaleWhileRevalidate } from 'workbox-strategies'; +self.__WB_DISABLE_DEV_LOGS = true; + const imageRoute = new Route( ({ request, sameOrigin }) => { const isRemote = !sameOrigin; From a09f1ea1a31b2786373d84d69b0ce3dfb0509cc2 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 14:23:00 +0800 Subject: [PATCH 10/59] SWR cache /statuses/:id/context --- public/sw.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/public/sw.js b/public/sw.js index 814b3820..8bf163f7 100644 --- a/public/sw.js +++ b/public/sw.js @@ -46,20 +46,20 @@ const apiExtendedRoute = new RegExpRoute( ); registerRoute(apiExtendedRoute); -// Not caching API requests, doesn't seem to be necessary fo now -// -// const apiRoute = new RegExpRoute( -// /^https?:\/\/[^\/]+\/api\//, -// new StaleWhileRevalidate({ -// cacheName: 'api', -// plugins: [ -// new ExpirationPlugin({ -// maxAgeSeconds: 60, // 1 minute -// }), -// new CacheableResponsePlugin({ -// statuses: [0, 200], -// }), -// ], -// }), -// ); -// registerRoute(apiRoute); +const apiRoute = new RegExpRoute( + // Matches: + // - statuses/:id/context - some contexts are really huge + /^https?:\/\/[^\/]+\/api\/v\d+\/(statuses\/\d+\/context)/, + new StaleWhileRevalidate({ + cacheName: 'api', + plugins: [ + new ExpirationPlugin({ + maxAgeSeconds: 5 * 60, // 5 minutes + }), + new CacheableResponsePlugin({ + statuses: [0, 200], + }), + ], + }), +); +registerRoute(apiRoute); From 44f179a69f010baf15b6a3dc77e5107460157402 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 14:42:28 +0800 Subject: [PATCH 11/59] Beautify notifications slightly --- src/pages/notifications.css | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/pages/notifications.css b/src/pages/notifications.css index 05899dd8..334d3241 100644 --- a/src/pages/notifications.css +++ b/src/pages/notifications.css @@ -20,41 +20,56 @@ opacity: 0.75; color: var(--text-insignificant-color); } +.notification-type.notification-mention { + color: var(--reply-to-color); +} .notification-type.notification-favourite { color: var(--favourite-color); } .notification-type.notification-reblog { color: var(--reblog-color); } -.notification-type.notification-poll, -.notification-type.notification-mention { +.notification-type.notification-poll { color: var(--link-color); } .notification .status-link { - border-radius: 8px 8px 0 0; + border-radius: 8px; border: 1px solid var(--outline-color); + max-height: 160px; + overflow: hidden; + filter: saturate(0.25); +} +.notification .status-link:not(.status-type-mention) > .status { max-height: 160px; overflow: hidden; /* fade out mask gradient bottom */ mask-image: linear-gradient( - rgba(0, 0, 0, 1), - rgba(0, 0, 0, 1) 50%, - transparent + rgba(0, 0, 0, 1) 130px, + rgba(0, 0, 0, 0.5) 145px, + transparent 159px ); - filter: saturate(0.25); } .notification .status-link.status-type-mention { max-height: 320px; filter: none; background-color: var(--bg-color); margin-top: calc(-16px - 1px); + border-color: var(--reply-to-color); + box-shadow: 0 0 0 3px var(--reply-to-faded-color); } .notification .status-link:is(:hover, :focus) { background-color: var(--bg-blur-color); filter: saturate(1); border-color: var(--outline-hover-color); } +.notification .status-link.status-type-mention:is(:hover, :focus) { + border-color: var(--reply-to-color); + box-shadow: 0 0 5px var(--reply-to-color); +} +.notification .status-link:active { + filter: brightness(0.95); +} .notification .status-link > * { pointer-events: none; } From c3aef80ad4b8d28b221810b771afa5f4410725f3 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 15:00:13 +0800 Subject: [PATCH 12/59] More styles --- src/app.css | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app.css b/src/app.css index f3817a1d..361586c0 100644 --- a/src/app.css +++ b/src/app.css @@ -374,18 +374,17 @@ a.mention span { z-index: 1000; display: flex; background-color: var(--backdrop-color); + animation: appear 0.2s ease-out; } .deck-backdrop > a { flex-grow: 1; - backdrop-filter: saturate(0.75); + /* backdrop-filter: saturate(0.75); */ } @keyframes slide-in { 0% { - opacity: 0.5; transform: translate3d(100%, 0, 0); } 100% { - opacity: 1; transform: translate3d(0, 0, 0); } } @@ -402,7 +401,6 @@ a.mention span { .decks { flex-grow: 1; - transition: transform 0.5s var(--timing-function); } .deck-close { @@ -808,7 +806,11 @@ meter.donut:is(.danger, .explode):after { #app { display: flex; } + .decks { + transition: transform 0.4s var(--timing-function); + } .decks:has(~ .deck-backdrop) { + transition: transform 0.4s ease-out; transform: translate3d(-5vw, 0, 0); } .deck-backdrop .deck { From c2bf9eabc5fb97711ca14d9b196a0373320d3400 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 15:09:31 +0800 Subject: [PATCH 13/59] Remove consoles in prod --- package-lock.json | 13 +++++++++++++ package.json | 1 + vite.config.js | 2 ++ 3 files changed, 16 insertions(+) diff --git a/package-lock.json b/package-lock.json index 2f718061..5e8e9e0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "vite-plugin-html-config": "~1.0.11", "vite-plugin-html-env": "~1.2.7", "vite-plugin-pwa": "~0.14.0", + "vite-plugin-remove-console": "~1.3.0", "workbox-cacheable-response": "~6.5.4", "workbox-expiration": "~6.5.4", "workbox-routing": "~6.5.4", @@ -5471,6 +5472,12 @@ "workbox-window": "^6.5.4" } }, + "node_modules/vite-plugin-remove-console": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-remove-console/-/vite-plugin-remove-console-1.3.0.tgz", + "integrity": "sha512-5a/OLYB6yNRHMuHj9rBQRYMQ1NBKffxA8BaD77urUBLcGOWMHFHALjh6C26wZfZd41KytSwLp6DhvNKU78mNJg==", + "dev": true + }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", @@ -9679,6 +9686,12 @@ "workbox-window": "^6.5.4" } }, + "vite-plugin-remove-console": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-remove-console/-/vite-plugin-remove-console-1.3.0.tgz", + "integrity": "sha512-5a/OLYB6yNRHMuHj9rBQRYMQ1NBKffxA8BaD77urUBLcGOWMHFHALjh6C26wZfZd41KytSwLp6DhvNKU78mNJg==", + "dev": true + }, "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index dbde5c5c..e52bcd0c 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "vite-plugin-html-config": "~1.0.11", "vite-plugin-html-env": "~1.2.7", "vite-plugin-pwa": "~0.14.0", + "vite-plugin-remove-console": "~1.3.0", "workbox-cacheable-response": "~6.5.4", "workbox-expiration": "~6.5.4", "workbox-routing": "~6.5.4", diff --git a/vite.config.js b/vite.config.js index 48a6268c..916aaaaf 100644 --- a/vite.config.js +++ b/vite.config.js @@ -6,6 +6,7 @@ import { defineConfig, loadEnv, splitVendorChunkPlugin } from 'vite'; import htmlPlugin from 'vite-plugin-html-config'; import VitePluginHtmlEnv from 'vite-plugin-html-env'; import { VitePWA } from 'vite-plugin-pwa'; +import removeConsole from 'vite-plugin-remove-console'; const { NODE_ENV } = process.env; const { VITE_CLIENT_NAME: CLIENT_NAME, VITE_APP_ERROR_LOGGING: ERROR_LOGGING } = @@ -29,6 +30,7 @@ export default defineConfig({ preact(), splitVendorChunkPlugin(), VitePluginHtmlEnv(), + removeConsole(), htmlPlugin({ headScripts: ERROR_LOGGING ? [rollbarCode] : [], }), From 39124ccc70312c693842070931e53ea6b280215c Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Mon, 2 Jan 2023 21:36:24 +0800 Subject: [PATCH 14/59] Add experimental scroll-based effects - Scroll to top = refresh Home - Scroll up/down = show/hide header and compose button - Scroll near bottom = load next statuses - Move Compose button to only at Home instead of 'App' level --- src/app.css | 21 +++++++++++++++- src/app.jsx | 31 +++++------------------ src/pages/home.jsx | 57 +++++++++++++++++++++++++++++++++++++----- src/utils/useScroll.js | 35 ++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 32 deletions(-) create mode 100644 src/utils/useScroll.js diff --git a/src/app.css b/src/app.css index 361586c0..62ba9ccc 100644 --- a/src/app.css +++ b/src/app.css @@ -90,6 +90,13 @@ a.mention span { grid-template-columns: 1fr 1fr 1fr; align-items: center; user-select: none; + transition: transform 0.5s ease-in-out; +} +.deck header[hidden] { + transform: translateY(-100%); + opacity: 0; + pointer-events: none; + user-select: none; } .deck header > .header-side:last-of-type { text-align: right; @@ -350,6 +357,7 @@ a.mention span { color: inherit; transition: background-color 0.2s ease-out; -webkit-tap-highlight-color: transparent; + animation: appear 0.2s ease-out; } .status-link:is(:hover, :focus) { background-color: var(--link-bg-hover-color); @@ -600,7 +608,18 @@ button.carousel-dot[disabled].active { z-index: 1; box-shadow: 0 3px 8px -1px var(--bg-faded-blur-color), 0 10px 36px -4px var(--button-bg-blur-color); - transition: background-color 0.2s ease-in-out; + transition: all 0.3s ease-in-out; +} +#compose-button[hidden] { + transform: translateY(150%); + pointer-events: none; + user-select: none; +} +#compose-button .icon { + transition: transform 0.3s ease-in-out; +} +#compose-button[hidden] .icon { + transform: rotate(90deg); } #compose-button:is(:hover, :focus) { background-color: var(--button-bg-color); diff --git a/src/app.jsx b/src/app.jsx index 034bc929..903f8d3c 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -177,31 +177,12 @@ function App() { return ( <> {isLoggedIn && currentDeck && ( - <> - -
- {/* Home will never be unmounted */} -
- +
+ {/* Home will never be unmounted */} +
)} {!isLoggedIn && uiState === 'loading' && }
- {inReplyToAccountId && !withinContext && size !== 's' && ( - <> - {inReplyToAccountId === status.account.id ? ( -
- - Thread -
- ) : ( - !!inReplyToAccount && - !mentions.find((mention) => { - return mention.id === inReplyToAccountId; - }) && ( -
- {' '} - + {!!inReplyToId && + !!inReplyToAccountId && + !withinContext && + size !== 's' && ( + <> + {inReplyToAccountId === status.account.id ? ( +
+ + Thread
- ) - )} - - )} + ) : ( + !!inReplyToAccount && + (!!spoilerText || + !mentions.find((mention) => { + return mention.id === inReplyToAccountId; + })) && ( +
+ {' '} + +
+ ) + )} + + )}
Date: Wed, 4 Jan 2023 19:03:11 +0800 Subject: [PATCH 36/59] Refactor textarea and chars count meter It won't re-render on every key press anymore --- src/components/compose.jsx | 453 +++++++++++++++++++++---------------- src/utils/states.js | 1 + 2 files changed, 259 insertions(+), 195 deletions(-) diff --git a/src/components/compose.jsx b/src/components/compose.jsx index 07ac4569..890c4356 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -1,14 +1,17 @@ import './compose.css'; import '@github/text-expander-element'; +import { forwardRef } from 'preact/compat'; import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useHotkeys } from 'react-hotkeys-hook'; import stringLength from 'string-length'; +import { useSnapshot } from 'valtio'; import supportedLanguages from '../data/status-supported-languages'; import urlRegex from '../data/url-regex'; import emojifyText from '../utils/emojify-text'; import openCompose from '../utils/open-compose'; +import states from '../utils/states'; import store from '../utils/store'; import visibilityIconsMap from '../utils/visibility-icons-map'; @@ -54,6 +57,16 @@ menu.className = 'text-expander-menu'; const DEFAULT_LANG = 'en'; +// https://github.com/mastodon/mastodon/blob/c4a429ed47e85a6bbf0d470a41cc2f64cf120c19/app/javascript/mastodon/features/compose/util/counter.js +const urlRegexObj = new RegExp(urlRegex.source, urlRegex.flags); +const usernameRegex = /(^|[^\/\w])@(([a-z0-9_]+)@[a-z0-9\.\-]+[a-z0-9]+)/gi; +const urlPlaceholder = '$2xxxxxxxxxxxxxxxxxxxxxxx'; +function countableText(inputText) { + return inputText + .replace(urlRegexObj, urlPlaceholder) + .replace(usernameRegex, '$1@$3'); +} + function Compose({ onClose, replyToStatus, @@ -62,6 +75,7 @@ function Compose({ standalone, hasOpener, }) { + console.warn('RENDER COMPOSER'); const [uiState, setUIState] = useState('default'); const accounts = store.local.getJSON('accounts'); @@ -223,130 +237,6 @@ function Compose({ } }, [draftStatus, editStatus, replyToStatus]); - const textExpanderRef = useRef(); - const textExpanderTextRef = useRef(''); - useEffect(() => { - if (textExpanderRef.current) { - const handleChange = (e) => { - // console.log('text-expander-change', e); - const { key, provide, text } = e.detail; - textExpanderTextRef.current = text; - - if (text === '') { - provide( - Promise.resolve({ - matched: false, - }), - ); - return; - } - - if (key === ':') { - // const emojis = customEmojis.current.filter((emoji) => - // emoji.shortcode.startsWith(text), - // ); - const emojis = filterShortcodes(customEmojis.current, text); - let html = ''; - emojis.forEach((emoji) => { - const { shortcode, url } = emoji; - html += ` -
  • - - :${encodeHTML(shortcode)}: -
  • `; - }); - // console.log({ emojis, html }); - menu.innerHTML = html; - provide( - Promise.resolve({ - matched: emojis.length > 0, - fragment: menu, - }), - ); - return; - } - - const type = { - '@': 'accounts', - '#': 'hashtags', - }[key]; - provide( - new Promise((resolve) => { - const searchResults = masto.v2.search({ - type, - q: text, - limit: 5, - }); - searchResults.then((value) => { - if (text !== textExpanderTextRef.current) { - return; - } - console.log({ value, type, v: value[type] }); - const results = value[type]; - console.log('RESULTS', value, results); - let html = ''; - results.forEach((result) => { - const { - name, - avatarStatic, - displayName, - username, - acct, - emojis, - } = result; - const displayNameWithEmoji = emojifyText(displayName, emojis); - // const item = menuItem.cloneNode(); - if (acct) { - html += ` -
  • - - - - - ${displayNameWithEmoji || username} -
    @${encodeHTML(acct)} -
    -
  • - `; - } else { - html += ` -
  • - #${encodeHTML(name)} -
  • - `; - } - menu.innerHTML = html; - }); - console.log('MENU', results, menu); - resolve({ - matched: results.length > 0, - fragment: menu, - }); - }); - }), - ); - }; - - textExpanderRef.current.addEventListener( - 'text-expander-change', - handleChange, - ); - - textExpanderRef.current.addEventListener('text-expander-value', (e) => { - const { key, item } = e.detail; - if (key === ':') { - e.detail.value = `:${item.dataset.value}:`; - } else { - e.detail.value = `${key}${item.dataset.value}`; - } - }); - } - }, []); - const formRef = useRef(); const beforeUnloadCopy = @@ -432,19 +322,16 @@ function Compose({ }); }, []); - const [charCount, setCharCount] = useState( - textareaRef.current?.value?.length + - spoilerTextRef.current?.value?.length || 0, - ); - const leftChars = maxCharacters - charCount; const getCharCount = () => { const { value } = textareaRef.current; const { value: spoilerText } = spoilerTextRef.current; return stringLength(countableText(value)) + stringLength(spoilerText); }; const updateCharCount = () => { - setCharCount(getCharCount()); + const count = getCharCount(); + states.composerCharacterCount = count; }; + useEffect(updateCharCount, []); useHotkeys( 'esc', @@ -818,41 +705,22 @@ function Compose({ {' '}
    - - - + )} -
    - + {suffixType === 'image' ? ( + + ) : suffixType === 'video' || suffixType === 'gifv' ? ( +
    + {descTextarea} +
    + +
    -
    + {showModal && ( + { + if (e.target === e.currentTarget) { + setShowModal(false); + } + }} + > +
    +
    +

    + { + { + image: 'Edit image description', + video: 'Edit video description', + audio: 'Edit audio description', + }[suffixType] + } +

    +
    +
    +
    + {suffixType === 'image' ? ( + + ) : suffixType === 'video' || suffixType === 'gifv' ? ( +
    + {descTextarea} +
    +
    +
    + )} + ); } From fd9d09b8b27ca5f94952d0dc2589cc6461e40079 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Fri, 6 Jan 2023 01:52:09 +0800 Subject: [PATCH 51/59] Bump valtio --- package-lock.json | 124 +++++++++++++++++++--------------------------- package.json | 2 +- 2 files changed, 53 insertions(+), 73 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9505cd8..53bac186 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "swiped-events": "~1.1.7", "toastify-js": "~1.12.0", "use-resize-observer": "~9.1.0", - "valtio": "~1.8.0" + "valtio": "~1.8.2" }, "devDependencies": { "@preact/preset-vite": "~2.5.0", @@ -313,7 +313,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "devOptional": true, + "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, @@ -435,7 +435,7 @@ "version": "7.19.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6.9.0" } @@ -444,7 +444,7 @@ "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6.9.0" } @@ -1696,7 +1696,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "devOptional": true, + "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -3155,7 +3155,7 @@ "version": "0.16.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.7.tgz", "integrity": "sha512-P6OBFYFSQOGzfApqCeYKqfKRRbCIRsdppTXFo4aAvtiW3o8TTyiIplBvHJI171saPAiy3WlawJHCveJVIOIx1A==", - "devOptional": true, + "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -3383,7 +3383,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "devOptional": true + "dev": true }, "node_modules/function.prototype.name": { "version": "1.1.5", @@ -3520,7 +3520,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "devOptional": true, + "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -3693,7 +3693,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "devOptional": true, + "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -4289,7 +4289,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "devOptional": true, + "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4452,13 +4452,13 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "devOptional": true + "dev": true }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "devOptional": true + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -4476,7 +4476,7 @@ "version": "8.4.20", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", - "devOptional": true, + "dev": true, "funding": [ { "type": "opencollective", @@ -4564,9 +4564,9 @@ } }, "node_modules/proxy-compare": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", - "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.4.0.tgz", + "integrity": "sha512-FD8KmQUQD6Mfpd0hywCOzcon/dbkFP8XBd9F1ycbKtvVsfv6TsFUKJ2eC0Iz2y+KzlkdT1Z8SY6ZSgm07zOyqg==" }, "node_modules/punycode": { "version": "2.1.1", @@ -4754,7 +4754,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "devOptional": true, + "dev": true, "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -4781,7 +4781,7 @@ "version": "3.7.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.4.tgz", "integrity": "sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==", - "devOptional": true, + "dev": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -4923,7 +4923,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5059,7 +5059,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "devOptional": true, + "dev": true, "engines": { "node": ">= 0.4" }, @@ -5121,7 +5121,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "devOptional": true, + "dev": true, "engines": { "node": ">=4" } @@ -5351,42 +5351,22 @@ } }, "node_modules/valtio": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.8.0.tgz", - "integrity": "sha512-lNw7wM0Qb9iBzXMju+XCn+UiIlf5uCe5pcI8XRqcvxEZ/mnRXyKXoOodPDKB8cIAVekA3Q3zWA7rboCdS4ea7g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.8.2.tgz", + "integrity": "sha512-ypFWPi3aY04tojWAFPbTYBDw5iFaCDbKAJ2XqhmY2XOSorNtaCZJNg++FSssv8gMJwmPXfrU/RjncQtsoOHbUg==", "dependencies": { - "proxy-compare": "2.3.0", + "proxy-compare": "2.4.0", "use-sync-external-store": "1.2.0" }, "engines": { "node": ">=12.7.0" }, "peerDependencies": { - "@babel/helper-module-imports": ">=7.12", - "@babel/types": ">=7.13", - "aslemammad-vite-plugin-macro": ">=1.0.0-alpha.1", - "babel-plugin-macros": ">=3.0", - "react": ">=16.8", - "vite": ">=2.8.6" + "react": ">=16.8" }, "peerDependenciesMeta": { - "@babel/helper-module-imports": { - "optional": true - }, - "@babel/types": { - "optional": true - }, - "aslemammad-vite-plugin-macro": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - }, "react": { "optional": true - }, - "vite": { - "optional": true } } }, @@ -5394,7 +5374,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz", "integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==", - "devOptional": true, + "dev": true, "dependencies": { "esbuild": "^0.16.3", "postcss": "^8.4.20", @@ -6089,7 +6069,7 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "devOptional": true, + "dev": true, "requires": { "@babel/types": "^7.18.6" } @@ -6181,13 +6161,13 @@ "version": "7.19.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "devOptional": true + "dev": true }, "@babel/helper-validator-identifier": { "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "devOptional": true + "dev": true }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -7031,7 +7011,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", - "devOptional": true, + "dev": true, "requires": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -8054,7 +8034,7 @@ "version": "0.16.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.7.tgz", "integrity": "sha512-P6OBFYFSQOGzfApqCeYKqfKRRbCIRsdppTXFo4aAvtiW3o8TTyiIplBvHJI171saPAiy3WlawJHCveJVIOIx1A==", - "devOptional": true, + "dev": true, "requires": { "@esbuild/android-arm": "0.16.7", "@esbuild/android-arm64": "0.16.7", @@ -8236,7 +8216,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "devOptional": true + "dev": true }, "function.prototype.name": { "version": "1.1.5", @@ -8337,7 +8317,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "devOptional": true, + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -8465,7 +8445,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "devOptional": true, + "dev": true, "requires": { "has": "^1.0.3" } @@ -8901,7 +8881,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "devOptional": true + "dev": true }, "no-case": { "version": "3.0.4", @@ -9028,13 +9008,13 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "devOptional": true + "dev": true }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "devOptional": true + "dev": true }, "picomatch": { "version": "2.3.1", @@ -9046,7 +9026,7 @@ "version": "8.4.20", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", - "devOptional": true, + "dev": true, "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -9091,9 +9071,9 @@ "dev": true }, "proxy-compare": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", - "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.4.0.tgz", + "integrity": "sha512-FD8KmQUQD6Mfpd0hywCOzcon/dbkFP8XBd9F1ycbKtvVsfv6TsFUKJ2eC0Iz2y+KzlkdT1Z8SY6ZSgm07zOyqg==" }, "punycode": { "version": "2.1.1", @@ -9234,7 +9214,7 @@ "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "devOptional": true, + "dev": true, "requires": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -9251,7 +9231,7 @@ "version": "3.7.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.4.tgz", "integrity": "sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==", - "devOptional": true, + "dev": true, "requires": { "fsevents": "~2.3.2" } @@ -9346,7 +9326,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "devOptional": true + "dev": true }, "source-map-support": { "version": "0.5.21", @@ -9449,7 +9429,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "devOptional": true + "dev": true }, "swiped-events": { "version": "1.1.7", @@ -9490,7 +9470,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "devOptional": true + "dev": true }, "to-regex-range": { "version": "5.0.1", @@ -9663,11 +9643,11 @@ "requires": {} }, "valtio": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.8.0.tgz", - "integrity": "sha512-lNw7wM0Qb9iBzXMju+XCn+UiIlf5uCe5pcI8XRqcvxEZ/mnRXyKXoOodPDKB8cIAVekA3Q3zWA7rboCdS4ea7g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.8.2.tgz", + "integrity": "sha512-ypFWPi3aY04tojWAFPbTYBDw5iFaCDbKAJ2XqhmY2XOSorNtaCZJNg++FSssv8gMJwmPXfrU/RjncQtsoOHbUg==", "requires": { - "proxy-compare": "2.3.0", + "proxy-compare": "2.4.0", "use-sync-external-store": "1.2.0" } }, @@ -9675,7 +9655,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz", "integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==", - "devOptional": true, + "dev": true, "requires": { "esbuild": "^0.16.3", "fsevents": "~2.3.2", diff --git a/package.json b/package.json index a63ec00d..4d4ecf31 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "swiped-events": "~1.1.7", "toastify-js": "~1.12.0", "use-resize-observer": "~9.1.0", - "valtio": "~1.8.0" + "valtio": "~1.8.2" }, "devDependencies": { "@preact/preset-vite": "~2.5.0", From fffc8cc983f3ee6a6c783842aeff9f1c2b4cec01 Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Fri, 6 Jan 2023 12:51:53 +0800 Subject: [PATCH 52/59] Further grouping of notifications --- src/app.css | 8 ++++++++ src/pages/notifications.jsx | 35 +++++++++++++++-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/app.css b/src/app.css index 26751dd5..0e50fd3b 100644 --- a/src/app.css +++ b/src/app.css @@ -820,6 +820,14 @@ meter.donut:is(.danger, .explode):after { filter: brightness(0.8); } +/* AVATARS STACK */ + +.avatars-stack { + display: flex; + flex-wrap: wrap; + gap: 4px; +} + @media (min-width: 40em) { html, body { diff --git a/src/pages/notifications.jsx b/src/pages/notifications.jsx index 378aca72..cf425c83 100644 --- a/src/pages/notifications.jsx +++ b/src/pages/notifications.jsx @@ -112,7 +112,7 @@ function Notification({ notification }) {

    )} {_accounts?.length > 1 && ( -

    +

    {_accounts.map((account, i) => ( <> Date: Fri, 6 Jan 2023 18:25:47 +0800 Subject: [PATCH 53/59] Rewrite the

    { - if (!showOriginal && isGIF) { + if (hoverAnimate) { try { videoRef.current.pause(); } catch (e) {} @@ -775,38 +781,32 @@ function Media({ media, showOriginal, onClick = () => {} }) { onClick(e); }} onMouseEnter={() => { - if (!showOriginal && isGIF) { + if (hoverAnimate) { try { videoRef.current.play(); } catch (e) {} } }} onMouseLeave={() => { - if (!showOriginal && isGIF) { + if (hoverAnimate) { try { videoRef.current.pause(); } catch (e) {} } }} > - {showOriginal ? ( -
    - `, - }} + {showOriginal || autoAnimate ? ( +