1
0
Fork 0
forked from Mirrors/gomuks

web/timeline: lazy-load images and avatars

This commit is contained in:
Tulir Asokan 2024-10-10 22:18:29 +03:00
parent 67c9060e85
commit c52c9029a7
3 changed files with 13 additions and 12 deletions

View file

@ -15,12 +15,12 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import React from "react" import React from "react"
import { RoomStateStore } from "../../api/statestore.ts" import { RoomStateStore } from "../../api/statestore.ts"
import { getMediaURL } from "../../api/media.ts"
import { DBEvent, MemberEventContent } from "../../api/types" import { DBEvent, MemberEventContent } from "../../api/types"
import HiddenEvent from "./content/HiddenEvent.tsx" import HiddenEvent from "./content/HiddenEvent.tsx"
import MessageBody from "./content/MessageBody.tsx" import MessageBody from "./content/MessageBody.tsx"
import { EventContentProps } from "./content/props.ts" import { EventContentProps } from "./content/props.ts"
import "./TimelineEvent.css" import "./TimelineEvent.css"
import { getMediaURL } from "../../api/media.ts"
export interface TimelineEventProps { export interface TimelineEventProps {
room: RoomStateStore room: RoomStateStore
@ -51,7 +51,7 @@ const TimelineEvent = ({ room, eventRowID }: TimelineEventProps) => {
// } // }
return <div className="timeline-event"> return <div className="timeline-event">
<div className="sender-avatar"> <div className="sender-avatar">
<img src={getMediaURL(memberEvtContent?.avatar_url)} alt="" /> <img loading="lazy" src={getMediaURL(memberEvtContent?.avatar_url)} alt="" />
</div> </div>
<div className="sender-and-content"> <div className="sender-and-content">
<div className="event-sender-and-time"> <div className="event-sender-and-time">

View file

@ -79,15 +79,15 @@ const MessageBody = ({ event }: EventContentProps) => {
case "m.image": { case "m.image": {
const openLightbox = use(LightboxContext) const openLightbox = use(LightboxContext)
const style = calculateMediaSize(content.info?.w, content.info?.h) const style = calculateMediaSize(content.info?.w, content.info?.h)
if (content.url) { return <div className="media-container" style={style.container}>
return <div className="media-container" style={style.container}> <img
<img style={style.media} src={getMediaURL(content.url)} alt={content.body} onClick={openLightbox}/> loading="lazy"
</div> style={style.media}
} else if (content.file) { src={getMediaURL(content.url ?? content.file?.url)}
return <div className="media-container" style={style.container}> alt={content.body}
<img style={style.media} src={getMediaURL(content.file.url)} alt={content.body} onClick={openLightbox}/> onClick={openLightbox}
</div> />
} </div>
} }
} }
return <code>{`{ "type": "${event.type}" }`}</code> return <code>{`{ "type": "${event.type}" }`}</code>

View file

@ -85,6 +85,7 @@ export const transformTags: NonNullable<sanitizeHtml.IOptions["transformTags"]>
} }
attribs.src = getMediaURL(src)! attribs.src = getMediaURL(src)!
attribs.loading = "lazy"
return { tagName, attribs } return { tagName, attribs }
}, },
"code": function(tagName: string, attribs: sanitizeHtml.Attributes) { "code": function(tagName: string, attribs: sanitizeHtml.Attributes) {
@ -188,7 +189,7 @@ export const sanitizeHtmlParams: sanitizeHtml.IOptions = {
// eslint-disable-next-line id-length // eslint-disable-next-line id-length
a: ["href", "name", "target", "rel"], // remote target: custom to matrix a: ["href", "name", "target", "rel"], // remote target: custom to matrix
// img tags also accept width/height, we just map those to max-width & max-height during transformation // img tags also accept width/height, we just map those to max-width & max-height during transformation
img: ["src", "alt", "title", "style", "data-mx-emoticon"], img: ["src", "alt", "title", "style", "loading", "data-mx-emoticon"],
ol: ["start"], ol: ["start"],
code: ["class"], // We don't actually allow all classes, we filter them in transformTags code: ["class"], // We don't actually allow all classes, we filter them in transformTags
}, },