2023-10-01 23:03:52 +00:00
import styles from './text.module.css'
import { useState , useRef , useEffect , useMemo , useCallback } from 'react'
import { extractUrls } from '../lib/md'
import { IMGPROXY _URL _REGEXP , IMG _URL _REGEXP } from '../lib/url'
import FileMissing from '../svgs/file-warning-line.svg'
import { useShowModal } from './modal'
import { useMe } from './me'
import { Dropdown } from 'react-bootstrap'
export function decodeOriginalUrl ( imgproxyUrl ) {
const parts = imgproxyUrl . split ( '/' )
// base64url is not a known encoding in browsers
// so we need to replace the invalid chars
const b64Url = parts [ parts . length - 1 ] . replace ( /-/g , '+' ) . replace ( /_/ , '/' )
const originalUrl = Buffer . from ( b64Url , 'base64' ) . toString ( 'utf-8' )
return originalUrl
}
export const IMG _CACHE _STATES = {
LOADING : 'IS_LOADING' ,
LOADED : 'IS_LOADED' ,
ERROR : 'IS_ERROR'
}
// this is the image at public/placeholder_click_to_load.png as a data URI so we don't have to rely on network to render it
const IMAGE _CLICK _TO _LOAD _DATA _URI = ' data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TxQ8qghYUEcxQnSyIijjWKhShQqgVWnUwufQLmjQkKS6OgmvBwY / FqoOLs64OroIg + AHi6uKk6CIl / i8ptIj14Lgf7 + 497 t4BQrXINKstAmi6bSZiUTGVXhU7XtGFAfRhBBMys4w5SYqj5fi6h4 + vd2Ge1frcn6NHzVgM8InEEWaYNvEG8cymbXDeJw6yvKwSnxOPm3RB4keuKx6 / cc65LPDMoJlMzBMHicVcEytNzPKmRjxNHFI1nfKFlMcq5y3OWrHM6vfkLwxk9JVlrtMcRgyLWIIEEQrKKKAIG2FadVIsJGg / 2 sI / 5 PolcinkKoCRYwElaJBdP / gf / O7Wyk5NekmBKND + 4 jgfo0DHLlCrOM73sePUTgD / M3ClN / ylKjD7SXqloYWOgN5t4OK6oSl7wOUOMPhkyKbsSn6aQjYLvJ / RN6WB / luge83rrb6P0wcgSV3Fb4CDQ2AsR9nrLd7d2dzbv2fq / f0A3Xly0Qz3JtMAAAAGYktHRABdAF0AWtYatQwAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnCRcSMjozlXYQAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAIABJREFUeNrt3XdAFHfiNvCHXVgWkBp6F7DSVLoiosGCUZPYsMQSRWJsp8Z45jSXaDR2DdGoMZr3zVmI0agpenZRwQZWBCUKCChYcEFpLmX39wdhZFxAzGGJPp + / Y H f a z s 4 8 8 2 2 z o z V s 2 B A 1 i O i 1 J O E u I G I A E B E D g I g Y A E T E A C A i B g A R M Q C I i A F A R A w A I m I A E B E D g I g Y A E T E A C A i B g A R M Q C I i A F A R A w A I m I A E B E D g I g Y A E T E A C A i B g A R M Q C I i A F A R A w A I m I A E B E D g I g Y A E T E A C A i B g A R M Q C I i A F A R A w A I m I A E B E D g I g Y A E T E A C B i A B A R A 4 C I G A B E x A A g I g Y A E T E A i I g B Q E Q M A C J i A B A R A 4 C I G A B E x A A g I g Y A E T E A i I g B Q E Q M A C J i A B A R A 4 C I G A B E x A A g I g Y A E T E A i I g B Q E Q M A C J i A B A R A 4 C I G A B E x A A g I g Y A E T E A i I g B Q E Q M A C J i A B A R A 4 C I G A B E x A A g I g Y A E Q O A i B g A R M Q A I C I G A B E x A I i I A U B E D A A i Y g A Q E Q O A i B g A R M Q A I C I G A B E x A I i I A U B E D A A i Y g A Q E Q O A i B g A r z h X V z f u B B J x c H B k A D w P z s 4 u D Z 7 W 1 9 c P Q U H t G 3 X 9 c r k c r V q 1 5 h H / n L / L l 5 2 1 t Q 0 c H Z 0 Y A M + a l 5 d X g 6 Y b P H g o h g 0 b g c T E x E Z d f 0 B A E K R S K c / e 5 / h d / h 3 o 6 u r C z a 0 Z A + B Z c n N r D i M j o 3 q n M T Y 2 w c y Z n y I 8 v C d O n T q F 8 v K y R t 0 G d 3 d 3 l J W V v T T 7 R E 9 P H / 3 6 D f i b l g C c X 5 l j U y 6 X w 9 b W l g H w L P n 4 + N R 7 8 n l 7 t 8 G c O X P R o k V L l J S U 4 N d f d z T 6 N j R t 6 o L y 8 v K X Y n / Y 2 d l j 9 u w v 8 P D h w 7 / d d 9 m y Z S s Y G B i 8 M s e m T K Y L K y v r l 2 q b t F + 9 E k A z X L q U V O t 7 A w Z E o E e P c O j o 6 A A A E h J O o 6 i o q F H X b 2 F h C Q s L i y e W A A w M D G B o a I R b t 3 K f Y R j 6 Y d S o 0 Z B I J N i 3 b + / f 7 r t s 2 7 b d S x O k j V M F k M H c 3 J w l g G d F S 0 s L D g 4 O U C q V o t e b N G m C 6 d M / Q e / e f Y S T v 6 y s D L / 8 s r P R t y E w M A g S i a T e A P D z C 8 C A A Y O e 6 c n f q 1 c f j B s 3 H o a G h r h w 4 f x T V X N s b e 0 Q H v 7 W S x H m T 1 u V 8 v X 1 g 5 9 f w F 9 e p 1 Q q x b R p 0 6 G t 3 f j X R p l M B j M z M w Z A Q w 0 Z 8 h 6 m T p 3 W 4 O m 9 v d t A X 1 9 f o 7 h r Z W U N L S 0 t V F Z W C q + V l 5 f D 3 d 3 j i c t 0 c H D E v H k L 4 O H h 2 a B t a N G i J Q B o h B A A 6 O j I E B X 1 I X r 3 7 o O Y m I 3 P b L + N G T M W A w Y M F M I u I y M D o a F d 0 K t X H 0 R E D M b 7 7 0 d i / P i J m D Z t O i Z O n I w 2 b d q K 5 s / J u Q l 9 f X 3 M m T P v h X V n a m l p w d 7 e H m V l T 1 c C S E x M Q G h o K C Z N m g w j I + O n X u / b b / e F l 5 c 3 R o 0 a 0 2 i f x c D A A N r a 2 p D J Z N D T 0 4 O 1 t c 1 L c 4 5 J v b 0 9 P 3 8 Z r + Q T J v w D n T q F w t r a B o a G R r h w 4 f w T 5 + v e P R w u L i 4 4 e f I E b t z I F l 7 P z 1 c g P v 4 Y L l 1 K g o m J K c z N z S G X y 9 G 2 b V s 0 a 9 Y M V 6 5 c R m l p q c b y v L y 8 M X n y V F h Y W M D D w x N n z 5 5 B c X H 9 V Y b B g 4 d C L p f j 6 N F Y 3 L 1 7 R 3 j d w 8 M T 0 6 Z 9 D E t L K y x a N L / R q x 4 1 S z r t 2 r W D l p Z W j c / h h b Z t 2 8 H d 3 Q P N m z d H 0 6 Z N I Z f L c e H C B W z e v B E 5 O T d F y 3 F y a o o T J + L h 4 + O H v n 3 7 w c T E B J c u J U G t V j / H t h w / B A d 3 R H p 6 O s 6 d O 9 P g + Z y c m u L o 0 V i 8 + 2 4 / d O v W H W V l 5 U h P T 2 v Q v H K 5 H B 9 8 8 C F 0 d X V h b 2 + P 2 7 f v i I 6 j v / Y 5 f O H j 4 4 f k 5 E v w 9 f W D s 3 N T X L 9 + H V l Z m S w B 1 J W W s 2 Z 9 B n 9 / f + G 1 L l 3 e R P f u P Z 4 4 r 4 u L K w D U e j I D Q F r a N S x b t h i r V 6 9 C e X k 5 t L S 0 4 O T k D J V K 8 8 D u 1 K k z J k 2 a D E N D Q w C A s b E x p k y Z C r l c X u f 6 m z d v C W P j q q t O d S l E S 0 s L w 4 a N x J Q p H 8 H A o A m + / j o a C o W i 0 f e b k 1 N T z J 4 9 F 8 2 b N 6 9 3 u q y s L P z w w / / H 1 K n / w P b t 2 z S q B o G B 7 d G + f d W 4 i N W r V 6 K g o A B h Y V 2 x Y M E i t G 3 b 7 r k d B 5 6 e X n + W p B r e e D l k y H u w t L R E U V E R 1 q 5 d A 1 1 d X Q w f P g L / + t c s 2 N g 8 u f V 9 w I A I o Q d J I p F g y J C h M D E x / c s X s Z E j R + P t t 9 / B L 7 / s E K o A A G B v b 8 8 q Q G 2 s r K z x 6 a e f o 1 m z R 3 2 l 5 8 6 d Q 2 F h I Q Y M i K j 3 A N T R k c H O z q 7 e A A C A f v 0 G I C r q A + j o 6 E C l U u G n n 7 a g o C B f N E 3 f v g M w c u T 7 w h d 2 / / 5 9 n D 9 / D j Y 2 t p g 8 + a N 6 0 t 5 H + P v h w 4 d w d X X D 3 L n z 0 b V r V 6 j V a q x f / x 0 y M t K e y b 7 z 8 v J C S k o K T p w 4 j r Q 0 8 T o q K y u R m n o F 0 d F f Y d a s T 3 D w 4 P 5 a l x E U 1 B 7 D h 4 8 Q G g y L i 4 v x 7 b d r o F Q q Y W V l j U m T J m P c u I n P p W X e 1 d V F a K t p 2 M k / D F 5 e X k h I O A U A u H L l M n b u r D r x W r Z s h c 8 / n 4 O + f e v u C j U x M U V w c E f R a 8 b G x v j g g w + f e t s d H Z 0 w d + 5 8 + P n 5 Y d W q b 4 S q Z 3 W V z N r 6 5 e k J e G m q A C 1 a t M R H H 0 2 D h Y W l q D 4 X H b 0 M 8 f F x s L d 3 Q F h Y G J K S k v D g w f 1 a D 9 6 A g K r G n 7 1 7 9 2 h M 4 + D g i K l T p y E o K E h o 4 E l M T M D W r V s 0 6 s / d u 3 e H R F K V j S U l J V i x I h q / / f Y r F A o F g o L a w 8 b G F u f O n d X Y h n f f 7 Y c 3 3 n g D A K B W q z F 0 6 D C Y m Z l B p V J h y 5 Y Y H D t 2 9 J n t v z / + S M W 5 c 2 e Q m J g A u V w u G k B z + v Q p L F u 2 B L m 5 O X X O H x T U H q N G R S I l J Q W x s Y e E 1 + / d y 0 N F R Q U 8 P D w g k U h g b 2 + P 4 O C O K C k p R W b m 9 W f y W e R y O Q Y N G g K p V I q k p C S k p l 5 5 4 s n f o 0 c P / P 7 7 7 7 h 2 7 a r w + t W r f 8 D B w R G 2 t n b Q 0 d F B y 5 Y t 4 e P j h + z s b C g U 9 0 T L G D l y F F x c N E c d W l p a o r J S 9 c R t q P b W W 7 0 x Z k w U T E x M 8 P 3 3 6 3 H l y m X h v e D g E F h b W 6 O 8 v B y H D h 1 k C a D m w T d 1 6 j R R c e v K l c t Y s S I a A P D g w X 0 s X 7 4 E W 7 d u x Y g R 7 6 N J k y Y a y 3 B 3 d x f + r q 2 e 3 q l T q O g L L i 0 t x b p 1 3 4 l K E N O n f 4 K O H R 9 d B c r K y r B + / T r h S z x 6 N B Y z Z 3 4 C Y 2 M T 9 O r V R 6 P 1 2 M H B Q f i / a 9 d u 0 N X V B Q C c P 3 8 e e / f u e W 7 7 s 2 Z j Z 1 U b S P 4 T 9 / + o U Z H Q 0 d H B r l 2 / a b z / 3 / / u Q k L C 6 R p X S x O M H h 2 J 6 d M / w R t v N H 6 3 l p 9 f g K i 3 p j 5 D h 1 a d / A U F + d i z Z 7 f G + 6 t X r 0 J u b m 6 N q 7 M j Z s z 4 F 0 a O H C 2 0 k 9 j Y 2 M L X 1 6 9 G 6 I n D o V e v 3 k 8 c k m x k Z I y P P / 4 n I i I G Q U 9 P D / v 3 7 8 P J k 8 c f K 6 V W X X i q L x I M g D 8 T M z I y C n p 6 e s J r m Z m Z W L p
const IMAGE _PROCESSING _DATA _URI = ' data : image / png ; base64 , iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TxQ8qghYUEcxQnSyIijjWKhShQqgVWnUwufQLmjQkKS6OgmvBwY / FqoOLs64OroIg + AHi6uKk6CIl / i8ptIj14Lgf7 + 497 t4BQrXINKstAmi6bSZiUTGVXhU7XtGFAfRhBBMys4w5SYqj5fi6h4 + vd2Ge1frcn6NHzVgM8InEEWaYNvEG8cymbXDeJw6yvKwSnxOPm3RB4keuKx6 / cc65LPDMoJlMzBMHicVcEytNzPKmRjxNHFI1nfKFlMcq5y3OWrHM6vfkLwxk9JVlrtMcRgyLWIIEEQrKKKAIG2FadVIsJGg / 2 sI / 5 PolcinkKoCRYwElaJBdP / gf / O7Wyk5NekmBKND + 4 jgfo0DHLlCrOM73sePUTgD / M3ClN / ylKjD7SXqloYWOgN5t4OK6oSl7wOUOMPhkyKbsSn6aQjYLvJ / RN6WB / luge83rrb6P0wcgSV3Fb4CDQ2AsR9nrLd7d2dzbv2fq / f0A3Xly0Qz3JtMAAAAGYktHRABdAF0AWtYatQwAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnCRcSJTTRrt + BAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAHlZJREFUeNrt3WdAFHfCBvCHzlKkL0WKSpUq0hVQUTQxepbEkKaJ6UajxhhBvfe9e + 8 SI / YWTIzGmJge46UZu6BiBAWkqhRFkS4ovQn7fiBsGGaBRcnZnt83lplh9j8zz / zbDCozZz4jAxE9lFRZBEQMACJiABARA4CIGABExAAgIgYAETEAiIgBQEQMACJiABARA4CIGABExAAgIgYAETEAiIgBQEQMACJiABARA4CIGABExAAgIgYAETEAiIgBQEQMACJiABARA4CIGABExAAgIgYAETEAiIgBQEQMACJiABARA4CIGABEDAAiYgAQEQOAiBgARMQAICIGABExAIiIAUBEDAAiYgAQEQOAiBgARMQAICIGABExAIiIAUBEDAAiYgAQEQOAiBgARMQAICIGABExAIiIAUBEDAAiYgAQEQOAiBgARMQAICIGABExAIiIAUBEDAAiYgAQEQOAiBgARMQAIGIAEBEDgIgYAETEACAiBgARMQCIiAFARAwAImIAEBEDgIgYAETEACAiBgARMQCIiAFARAwAImIAEBEDgKgfzZgRAV1dXRZEH6mzCOh + ZmJiinnz5qOsrBR1dXUsEAYAPSx8fPzwwguzoaOjg23bPmSBMADoYRER8QwmTJgAdXV1nDuXguLiIhYKA4AedPr6AzBv3nwMHToUANDW1oaff / 6 JBXOb2AlI / c7S0gpPP / 0 sjI2N + 7 yul9cwTJv2ONTU1ES / c3f3wL / + 9 a784geA7Oxs5ORks9BZA6C7zcbGFtOmTYe9vQM2b96EysrKPrTnfTFx4iRoaWnhvff + jdbWVsHvp06djkmTJkNTU1Pw + W + / 7 b u j f X 7 1 1 d d x 5 M h h 5 O X l M g D u J n N z C y x Z E o W 0 t F Q c P n w I h Y X X / m t / e 8 6 c u a i o q M C 3 3 3 7 d 5 3 V V V F T w 2 G O T k Z i Y g L K y 0 n 7 d r 7 C w c R g 5 M h g r V o g v i D t h Y G C I t 9 5 6 G 1 l Z m b f 1 n b s a P N g e U 6 d O g 4 e H B 5 q a m r B p 0 w b k 5 i p 3 V w 4 I C M K j j 0 7 E k C F D U F R U h P f e + z c a G u o F y 8 y b t w D + / v 6 i d a 9 c u Y K U l K T b 3 u / H H p u M k S O D o a q q 9 p c E g E S i g 4 i I p 6 C u r o 7 t 2 7 f d k w G g 5 u X l 8 c 9 7 Y U d c X F w Q F j Y W Q 4 Y M w Z g x Y R g + 3 A c D B g z A t W s F a G l p u e 3 t O j g 4 o b K y Q n H 6 q a v j 7 b e X w M f H F 4 M H D 0 F u b g 7 K y 8 v 7 / D c q K y u x e P E S D B g w A O f P Z / V L e U y b 9 j i e f D I C p q a m M D e 3 w N m z i f 1 2 l 4 6 M X A p r a 2 s 4 O T n D z E y K p K S z t 1 2 2 L 7 7 4 E m b M e B J W V l Z o a m r C 1 q 0 f I C M j v d d 1 R 4 4 M w a u v v o 7 w 8 P E w M j J C a W k p o q N X o K r q p m j Z q 1 e v Q l 9 f H 1 K p u a B p o K e n B z M z K d L T 0 9 H W J g z I 0 N D R u H I l v 8 e m x v P P z 4 a 6 u j q M j Y 1 x 8 O A B 0 T Z u + 6 J S U 8 P 0 6 U / g t d f m w M X F B b W 1 d Y i P P 8 E A 6 K 3 t 5 + H h 2 d 4 x o a o K I y M j u L q 6 I T x 8 P F x c X K C q q o a r V 6 / 0 e b v P P P M c m p u b U V J S I v h c V 1 c X U V H L 4 e L i I j 9 o T k 7 O O H 4 8 D r d u 3 V J 6 + x o a m j A x M U V 2 9 k U 8 9 9 w s B A Q E o b i 4 C N e v l 9 9 2 W c y a 9 Q I m T n w M q q r t X T T W 1 t Z o a W m 5 4 7 a u l 9 c w L F j w F o y M j O S f 2 d r a w c H B E Y m J C W h r a 1 N q O 0 O H u u K l l 1 7 G 9 O m P w 9 L S E q q q q m h u b s a 2 b R 8 i J S W 5 x 3 V H j R q D V 1 9 9 H W F h Y 2 F o a A g A u H 7 9 O q K j 3 0 d F x X W F 6 9 T W 1 u L M m U T E x 8 d D R 0 c X U q k U G h o a U F V V h Z 3 d I I w c G Y z K y h s o K i q U r / P s s z N x 4 s R x h d u T S s 3 x 1 l t v y y c O a W p q o r G x s V / 6 E s L D J 2 D u 3 H n w 9 h 4 O L S 0 t + f 7 H x h 5 j A P T E 3 z 8 Q D g 4 O C u / S 5 u b m 8 P H x R V j Y O N j Y 2 K K m p r b b k 6 W r E S O C E R A Q i C N H D s k / M z E x R V T U c t j Z 2 Y l C w d z c E o m J C c q 1 n 9 T V M X / + Q s T H n 0 B B w V W 0 t c k w Y s Q I B A W N g L m 5 B T I z M / o U J h 3 V 3 Z C Q U K i o q A i a G U 5 O T r h 0 6 R L K y s p u q 3 z H j B m L l 1 9 + F T o 6 O g q a X + b w 9 P R C U l I S m p u b u t 2 G u 7 s n X n 7 5 F U y Z M h X m 5 u b y g G p u b s a O H d u R m H i 6 2 3 X H j g 3 H a 6 / N w a h R o 2 B g Y C D / / M a N G 1 i 9 O h q l p S W 9 f o e G h n o k J y c h L i 4 W B g Y G s L V t P 3 4 6 O j r Q 0 t L C 7 7 + f E g T / p U t 5 o i D W 0 N B E V N Q y S K V S w e f 6 + v o 4 d u z I b Z + / A Q F B m D v 3 T Y S E h I j K u K G h A Y c P H 2 I A 9 C Q 0 d B S s r a 1 7 X E Z b W x u 2 t r Y I C Q l F Y G A Q T E z M U F J S L G o z d q 1 q O j o 6 Q i Y D L l w 4 D x s b W y x Z E g U L C w u F y 1 t Z W a G 6 u h q X L 1 / q 9 e K P j F y G 6 u o q n D p 1 E g C Q n X 0 R l p Z W s L W 1 g 6 2 t H Y K D Q 9 H Q 0 N B j V b T z i b l k S R S G D R s m + L y j + a O h o Q F X V z c k J p 5 G Q 0 N D n 8 r 2 i S e e x I w Z T 0 J D Q 6 P b Z Y y M j O D r 6 4 u M j A z U 1 t a I + j k W L 4 7 E 1 K n T Y G Y m F Y R T W 1 s b d u 3 6 F C d P d n + 3 / c c / / o X g 4 G D o 6 + u L 7 u y r V 0 f j 2 r W C P n 2 f o K A R C A s b K 7 / D 3 r x 5 E 2 v W r E J T U 5 O 8 j 2 P K l K m o r q 5 B Z q a w O T J / / k J 5 r U / Y L 2 K A 8 + e z l L 6 x d K 4 N z Z k z F 4 8 8 8 i g G D B i g c J l b t 2 5 h / / 5 9 D I C e q 0 7 j Y W p q p n T H m 7 6 + P p y c n D B u X D g 8 P D y h r S 3 B l S v 5 o m p s a G g o p F I p b G 3 t U F p a g n n z 5 g u q w I q 2 7 e j o h K S k s 6 i t r e 3 2 4 l + y Z C k c H B y w d W s M a m r + v G C S k 5 M w b J g 3 D A 0 N I Z F I M H z 4 c D g 5 u S A v L 7 f b 7 e n r D 8 D S p c v g 6 O g k + L y 1 t R W 7 d n 2 K + P i T c H B w h L G x M R w d n X H 8 e K z S 5 d r R z u 6 4 W 3 c 4 e f I k M j M z Y G 9 v L 7 + g 9 f T 0 4 O f n j 7 y 8 S 6 I L o b y 8 H E O H u k J P T 0 9 U X o a G h s j O z h a U Q 4 e 6 u j r c u t U K Z 2 d n U Q C p q 6 t D V 1 c X a W m p S n V y 6 u s P w B t v z M P E i R O h r a 0 t D 6 B P P / 1 E 0 I n n 7 u 6 O w M A g y G R t g m b A j B k R G D 1 6 d L f H X V t b W + n a 3 8 C B 1 n j l l d c w f f r j M D U 1 7 X F Z m U y G X 3 7 5 m Q H Q c 4 / s J O j r D x B 0 r J W V l U F P T 0 9 0 8 n a m q q o K E x N T e H p 6 I T x 8 A o Y M c U B z c w t K S o r / a H O O h q m p G T Q 1 N e H n 5 y 8 / c Q C g p K Q E j Y 2 N o i q b p q Y m 7 O 0 d F L b b 1 N T U s G T J U g w d O h S Z m R k 4 c O A 3 0 c F O T 0 9 H Q E C g / G 9 J p V I E B 4 d A I p E g K y u z S / X b A l F R y 2 B t b S P a z g 8 / 7 M H B g / t R V F S E u L h j M D O T w t 3 d H W Z m U i Q n 9 9 x x p 6 W l h c W L I + H r 6 y v 6 X V J S E m J i N i M j I x 2 t r W 1 / 9 L G o y m t Z v r 5 + K C 0 t E 7 S p K y s r c P x 4 L A Y O t I a V l Z W o 9 j
2023-10-02 12:28:39 +00:00
export function useImgUrlCache ( text , { imgproxyUrls , tab } ) {
2023-10-01 23:03:52 +00:00
const ref = useRef ( { } )
const [ imgUrlCache , setImgUrlCache ] = useState ( { } )
const me = useMe ( )
const updateCache = ( url , state ) => setImgUrlCache ( ( prev ) => ( { ... prev , [ url ] : state } ) )
useEffect ( ( ) => {
const urls = extractUrls ( text )
urls . forEach ( ( url ) => {
if ( IMG _URL _REGEXP . test ( url ) || ! ! imgproxyUrls ? . [ url ] ) {
// it's probably an image if the regexp matches or if we processed the URL as an image in the worker
updateCache ( url , IMG _CACHE _STATES . LOADED )
} else {
// don't use image detection by trying to load as an image if user opted-out of loading external images automatically
2023-10-02 12:28:39 +00:00
if ( me ? . clickToLoadImg && tab !== 'preview' ) return
2023-10-01 23:03:52 +00:00
// make sure it's not a false negative by trying to load URL as <img>
const img = new window . Image ( )
ref . current [ url ] = img
updateCache ( url , IMG _CACHE _STATES . LOADING )
const callback = ( state ) => {
updateCache ( url , state )
delete ref . current [ url ]
}
img . onload = ( ) => callback ( IMG _CACHE _STATES . LOADED )
img . onerror = ( ) => callback ( IMG _CACHE _STATES . ERROR )
img . src = url
}
} )
return ( ) => {
Object . values ( ref . current ) . forEach ( ( img ) => {
img . onload = null
img . onerror = null
img . src = ''
} )
}
} , [ text ] )
return imgUrlCache
}
2023-10-02 12:28:39 +00:00
export function ZoomableImage ( { src , topLevel , srcSet : srcSetObj , tab , ... props } ) {
2023-10-01 23:03:52 +00:00
const me = useMe ( )
const showModal = useShowModal ( )
2023-10-02 12:28:39 +00:00
const [ originalUrlConsent , setOriginalUrlConsent ] = useState ( ! me || tab === 'preview' ? true : ! me . clickToLoadImg )
2023-10-01 23:03:52 +00:00
// if there is no srcset obj, image is still processing (srcSetObj === undefined) or it wasn't detected as an image by the worker (srcSetObj === null).
// we handle both cases the same as imgproxy errors.
const [ imgproxyErr , setImgproxyErr ] = useState ( ! srcSetObj )
const [ originalErr , setOriginalErr ] = useState ( )
// backwards compatibility:
// src may already be imgproxy url since we used to replace image urls with imgproxy urls
const originalUrl = IMGPROXY _URL _REGEXP . test ( src ) ? decodeOriginalUrl ( src ) : src
// we will fallback to the original error if there was an error with our image proxy
const loadOriginalUrl = ! ! imgproxyErr
const srcSet = useMemo ( ( ) => {
if ( ! srcSetObj ) return undefined
// srcSetObj shape: { [widthDescriptor]: <imgproxyUrl>, ... }
return Object . entries ( srcSetObj ) . reduce ( ( acc , [ wDescriptor , url ] , i , arr ) => {
return acc + ` ${ url } ${ wDescriptor } ` + ( i < arr . length - 1 ? ', ' : '' )
} , '' )
} , [ srcSetObj ] )
const sizes = ` ${ ( topLevel ? 100 : 66 ) } vw `
// get source url in best resolution
const bestResSrc = useMemo ( ( ) => {
if ( ! srcSetObj ) return undefined
return Object . entries ( srcSetObj ) . reduce ( ( acc , [ wDescriptor , url ] ) => {
const w = Number ( wDescriptor . replace ( /w$/ , '' ) )
return w > acc . w ? { w , url } : acc
} , { w : 0 , url : undefined } ) . url
} , [ srcSetObj ] )
const onError = useCallback ( ( err ) => {
if ( ! imgproxyErr ) {
// first error is imgproxy error since that was loaded
console . error ( 'imgproxy image error:' , err )
setImgproxyErr ( true )
} else {
// second error is error from original url
console . error ( 'original image error:' , err )
setOriginalErr ( true )
}
} , [ setImgproxyErr , setOriginalErr , imgproxyErr , originalUrl ] )
const handleClick = useCallback ( ( ) => showModal ( close => (
< div
className = 'd-grid w-100 h-100' style = { { placeContent : 'center' } } onClick = { close }
>
< img
style = { { cursor : 'zoom-out' , maxWidth : '100%' , maxHeight : '100%' , minHeight : 0 , minWidth : 0 } }
// also load original url in fullscreen if the original url was loaded
src = { loadOriginalUrl ? originalUrl : bestResSrc }
onError = { onError }
{ ... props }
/ >
< / d i v >
) , {
fullScreen : true ,
overflow : (
< Dropdown . Item
href = { originalUrl } target = '_blank' rel = 'noreferrer'
>
{ loadOriginalUrl ? 'open in new tab' : 'open original' }
< / D r o p d o w n . I t e m > )
} ) , [ showModal , loadOriginalUrl , originalUrl , bestResSrc , onError , props ] )
if ( ! src ) return null
if ( ( srcSetObj === undefined ) && originalUrlConsent && ! originalErr ) {
// image is still processing and user is okay with loading original url automatically
return (
< img
className = { topLevel ? styles . topLevel : undefined }
style = { { cursor : 'zoom-in' , maxHeight : topLevel ? '35vh' : '25vh' } }
src = { originalUrl }
onClick = { handleClick }
onError = { ( ) => setOriginalErr ( true ) }
{ ... props }
/ >
)
}
if ( ( srcSetObj === undefined ) && ! originalUrlConsent && ! originalErr ) {
// image is still processing and user is not okay with loading original url automatically
const { host } = new URL ( originalUrl )
return (
< div style = { { width : '256px' } } >
< img
className = { topLevel ? styles . topLevel : undefined }
src = { IMAGE _PROCESSING _DATA _URI } width = '256px' height = '256px'
style = { { cursor : 'pointer' } } onClick = { ( ) => setOriginalUrlConsent ( true ) }
/ >
< div className = 'text-muted fst-italic text-center' > click to load original from < / d i v >
< div className = 'text-muted fst-italic text-center' > { host } < / d i v >
< / d i v >
)
}
if ( originalErr ) {
// we already tried original URL: degrade <img> to <a> tag
return (
< >
< span className = 'd-flex align-items-baseline text-warning-emphasis fw-bold pb-1' >
< FileMissing width = { 18 } height = { 18 } className = 'fill-warning me-1 align-self-center' / >
failed to load image
< / s p a n >
< a target = '_blank' href = { originalUrl } rel = 'noreferrer' > { originalUrl } < / a >
< / >
)
}
if ( imgproxyErr && ! originalUrlConsent ) {
// respect privacy setting that external images should not be loaded automatically
const { host } = new URL ( originalUrl )
return (
< div style = { { width : '256px' } } >
< div className = 'd-flex align-items-baseline text-warning-emphasis fw-bold pb-1 justify-content-center' >
< FileMissing width = { 18 } height = { 18 } className = 'fill-warning me-1 align-self-center' / >
image proxy error
< / d i v >
< img
className = { topLevel ? styles . topLevel : undefined }
src = { IMAGE _CLICK _TO _LOAD _DATA _URI } width = '256px' height = '256px'
style = { { cursor : 'pointer' } } onClick = { ( ) => setOriginalUrlConsent ( true ) }
/ >
< div className = 'text-muted fst-italic text-center' > from { host } < / d i v >
< / d i v >
)
}
return (
< img
className = { topLevel ? styles . topLevel : undefined }
style = { { cursor : 'zoom-in' , maxHeight : topLevel ? '35vh' : '25vh' } }
// browsers that don't support srcSet and sizes will use src. use best resolution possible in that case
src = { loadOriginalUrl ? originalUrl : bestResSrc }
// we need to disable srcset and sizes to force browsers to use src
srcSet = { loadOriginalUrl ? undefined : srcSet }
sizes = { loadOriginalUrl ? undefined : sizes }
onClick = { handleClick }
onError = { onError }
{ ... props }
/ >
)
}