matrix-art

An image gallery for Matrix
git clone git://archive.git.mtrnord.blog/MTRNord/matrix-art.git
Log | Files | Refs | README | LICENSE

commit 5f084492edc5b09534cbd09d04bfb0023357da43
parent e11757fd021a22f0e1796cd4624fc09c8fceeb90
Author: MTRNord <mtrnord1@gmail.com>
Date:   Fri, 31 Dec 2021 13:37:35 +0100

Fix post rendering

Diffstat:
Mhelpers/matrix_client.ts | 6+++++-
Mpackage-lock.json | 28++++++++++++++++++++++++++++
Mpackage.json | 5++++-
Mpages/Home.tsx | 10++++++++--
Mpages/post/[id].tsx | 132+++++++++++++++++++++++++++----------------------------------------------------
5 files changed, 90 insertions(+), 91 deletions(-)

diff --git a/helpers/matrix_client.ts b/helpers/matrix_client.ts @@ -47,7 +47,11 @@ export default class MatrixClient { async registerAsGuest(serverUrl: string) { function generateToken(len: number) { var arr = new Uint8Array(len / 2); - window.crypto.getRandomValues(arr); + if (typeof window !== "undefined") { + window.crypto.getRandomValues(arr); + } else { + require("crypto").randomFillSync(arr); + } return Array.from(arr, (num) => { return num.toString(16).padStart(2, "0"); }).join(""); diff --git a/package-lock.json b/package-lock.json @@ -23,6 +23,7 @@ "@types/pouchdb": "^6.4.0", "@types/react": "17.0.38", "autoprefixer": "^10.4.0", + "cross-env": "^7.0.3", "eslint": "8.5.0", "eslint-config-next": "12.0.7", "postcss": "^8.4.5", @@ -2608,6 +2609,24 @@ "sha.js": "^2.4.8" } }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8980,6 +8999,15 @@ "sha.js": "^2.4.8" } }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", diff --git a/package.json b/package.json @@ -2,6 +2,7 @@ "name": "matrix-art", "private": true, "scripts": { + "dev-inspect": "cross-env NODE_OPTIONS='--inspect' next dev", "dev": "next dev", "build": "next build", "start": "next start", @@ -26,10 +27,11 @@ "@types/pouchdb": "^6.4.0", "@types/react": "17.0.38", "autoprefixer": "^10.4.0", + "cross-env": "^7.0.3", "eslint": "8.5.0", "eslint-config-next": "12.0.7", "postcss": "^8.4.5", "tailwindcss": "^3.0.7", "typescript": "4.5.4" } -} +} +\ No newline at end of file diff --git a/pages/Home.tsx b/pages/Home.tsx @@ -188,12 +188,13 @@ export default class Home extends Component<Props, State>{ render_image_box(thumbnail_url: string, id: string, post_id: string, sender: string, caption: string) { // TODO show creators display name instead of mxid and show avatar image + // TODO proper alt text const direct_link = `/post/${encodeURIComponent(post_id)}`; return ( <li className='h-[270px]' key={id}> - <Link href={direct_link}> + <Link href={direct_link} passHref> <div className='relative h-[270px] cursor-pointer'> - <img className='relative max-w-full h-[270px] object-cover align-bottom z-0' src={this.context.client?.thumbnailLink(thumbnail_url, "scale", 270, 270)}></img> + <img alt={caption} title={caption} className='relative max-w-full h-[270px] object-cover align-bottom z-0' src={this.context.client?.thumbnailLink(thumbnail_url, "scale", 270, 270)}></img> <div className="flex-col max-w-full h-[270px] opacity-0 hover:opacity-100 duration-300 absolute bg-gradient-to-b from-transparent to-black/[.25] inset-0 z-10 flex justify-end items-start text-white p-4"> <h2 className='truncate max-w-full text-base font-semibold'>{caption}</h2> <p className='truncate max-w-full text-sm'>{sender}</p> @@ -215,4 +216,9 @@ export function isImageGalleryEvent(event: ImageEvents): event is ImageGalleryEv export function isImageEvent(event: ImageEvents): event is ImageEvent { return event.type === "m.image" && event.redacted_because === undefined; +}; + +export const getServerSideProps = async (context: any) => { + console.log("getServerSideProps"); + return { props: {} }; }; \ No newline at end of file diff --git a/pages/post/[id].tsx b/pages/post/[id].tsx @@ -1,3 +1,4 @@ +import { GetServerSidePropsContext, InferGetServerSidePropsType } from "next"; import Head from "next/head"; import { NextRouter, withRouter } from "next/router"; import { Component, ReactNode } from "react"; @@ -5,7 +6,8 @@ import { RingLoader } from "react-spinners"; import { ClientContext } from "../../components/ClientContext"; import Header from "../../components/Header"; import { ImageEvent, ImageGalleryEvent, MatrixEventBase, MatrixImageEvents } from "../../helpers/event_types"; -import { constMatrixArtServer } from "../../helpers/matrix_client"; +import MatrixClient, { constMatrixArtServer } from "../../helpers/matrix_client"; +import Storage from "../../helpers/storage"; import { get_data } from "../api/directory"; import { isImageEvent, isImageGalleryEvent } from "../Home"; @@ -16,16 +18,13 @@ const centerSpinner = ` transform: translate(-50%, -50%); `; -interface Props { +type Props = InferGetServerSidePropsType<typeof getServerSideProps> & { router: NextRouter; -} +}; type State = { - directory_data: { _id: string; user_id: string; user_room: string; }[]; - event_id?: string; hasFullyLoaded: boolean; isLoadingImages: boolean; - directoryIsLoaded: boolean; image_event: MatrixImageEvents; error?: any; }; @@ -38,87 +37,13 @@ class Post extends Component<Props, State> { this.state = { hasFullyLoaded: false, - directoryIsLoaded: false, isLoadingImages: false } as State; } - async componentDidUpdate() { - if (this.state.event_id && this.state.event_id.startsWith("$")) { - await this.loadEvent(this.state.event_id); - } - } - - async getStaticPaths() { - const directory_data = await get_data(); - let paths: { params: { id: string; }; }[] = []; - for (let user of directory_data) { - // We dont need many events - const roomId = await this.context.client?.followUser(user.user_room); - await this.context.client?.getTimeline(roomId, 100, (events) => { - // Filter events by type - const image_events = events.filter((event) => event.type == "m.image_gallery" || event.type == "m.image"); - for (let event of image_events) { - const path_non_encoded = { params: { id: event.event_id } }; - const path = { params: { id: encodeURIComponent(event.event_id) } }; - paths.push(path); - } - }); - } - return { - paths: paths, - fallback: 'blocking' - }; - } - - async componentDidMount() { - const { id } = this.props.router.query; - console.log(`id: ${id}`); - console.log(`is ready: ${this.props.router.isReady}`); - const event_id = decodeURIComponent(id as string); - - if (event_id && event_id.startsWith("$")) { - // auto-register as a guest if not logged in - if (!this.context.client?.accessToken) { - this.registerAsGuest(); - } else { - console.log("Already logged in"); - try { - const data = await (await fetch('/api/directory')).json(); - this.setState({ event_id: event_id, directory_data: data.data, directoryIsLoaded: true }); - } catch (error) { - this.setState({ - hasFullyLoaded: true, - error - }); - } - } - } - } - - async componentWillUnmount() { - const { id } = this.props.router.query; - console.log(`id: ${id}`); - console.log(`is ready: ${this.props.router.isReady}`); - const event_id = decodeURIComponent(id as string); - - if (event_id && event_id.startsWith("$")) { - // auto-register as a guest if not logged in - if (!this.context.client?.accessToken) { - this.registerAsGuest(); - } else { - console.log("Already logged in"); - try { - const data = await (await fetch('/api/directory')).json(); - this.setState({ event_id: event_id, directory_data: data.data, directoryIsLoaded: true }); - } catch (error) { - this.setState({ - hasFullyLoaded: true, - error - }); - } - } + if (this.props.directory_data && this.props.event_id && this.props.event_id.startsWith("$")) { + await this.loadEvent(this.props.event_id); } } @@ -138,8 +63,8 @@ class Post extends Component<Props, State> { } async loadEvent(event_id: string) { - const { directoryIsLoaded, directory_data, hasFullyLoaded, isLoadingImages } = this.state; - if (!directoryIsLoaded || isLoadingImages || hasFullyLoaded) { + const { hasFullyLoaded, isLoadingImages } = this.state; + if (isLoadingImages || hasFullyLoaded || !this.props.directory_data) { return; } this.setState({ @@ -147,7 +72,7 @@ class Post extends Component<Props, State> { }); try { // TODO fix this. It is super inefficent. - for (let user of directory_data) { + for (let user of this.props.directory_data) { // We dont need many events const roomId = await this.context.client?.followUser(user.user_room); await this.context.client?.getTimeline(roomId, 100, (events) => { @@ -171,7 +96,7 @@ class Post extends Component<Props, State> { } render() { - const { error, event_id, hasFullyLoaded, image_event } = this.state; + const { error, hasFullyLoaded, image_event } = this.state; if (!hasFullyLoaded) { return ( @@ -183,7 +108,7 @@ class Post extends Component<Props, State> { ); } - if (!event_id || !event_id?.startsWith("$")) { + if (!this.props.event_id || !this.props.event_id?.startsWith("$")) { return ( <div className="h-full bg-[#fefefe]/[.95] dark:bg-[#14181E]/[.95]"> <Head> @@ -295,4 +220,37 @@ class Post extends Component<Props, State> { } Post.contextType = ClientContext; + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const { query } = context; + const event_id = decodeURIComponent(query.id as string); + + if (event_id && event_id.startsWith("$")) { + // auto-register as a guest if not logged in + const client = new MatrixClient(new Storage()); + if (!client.accessToken) { + try { + let serverUrl = constMatrixArtServer + "/_matrix/client"; + await client.registerAsGuest(serverUrl); + } catch (err) { + console.error("Failed to register as guest:", err); + } + } else { + console.log("Already logged in"); + } + try { + const data = await get_data(); + + return { + props: { + directory_data: data, event_id: event_id + } + }; + } catch (error) { + return { notFound: true, props: {} }; + } + } + return { notFound: true, props: {} }; + +}; export default withRouter(Post); \ No newline at end of file