From 43d186a370cd4036e02babe7e5b86abe01b2e009 Mon Sep 17 00:00:00 2001 From: Maurice Schorn Date: Sun, 4 Feb 2024 18:50:43 +0100 Subject: [PATCH] Markdown support for TextPreviews (#396) * add markdown-to-jsx dependency * replace TextPreview with Markdown * basic table styling * add light mode backgroundColor --- frontend/package-lock.json | 18 ++++++++ frontend/package.json | 1 + frontend/src/components/share/FilePreview.tsx | 41 ++++++++++++++----- frontend/src/styles/global.style.tsx | 11 ++++- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 90bdb0a6..12131cec 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -22,6 +22,7 @@ "file-saver": "^2.0.5", "jose": "^4.14.4", "jwt-decode": "^3.1.2", + "markdown-to-jsx": "^7.4.1", "mime-types": "^2.1.35", "moment": "^2.29.4", "next": "^13.4.12", @@ -6100,6 +6101,17 @@ "semver": "bin/semver.js" } }, + "node_modules/markdown-to-jsx": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.1.tgz", + "integrity": "sha512-GbrbkTnHp9u6+HqbPRFJbObi369AgJNXi/sGqq5HRsoZW063xR1XDCaConqq+whfEIAlzB1YPnOgsPc7B7bc/A==", + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -13250,6 +13262,12 @@ } } }, + "markdown-to-jsx": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.4.1.tgz", + "integrity": "sha512-GbrbkTnHp9u6+HqbPRFJbObi369AgJNXi/sGqq5HRsoZW063xR1XDCaConqq+whfEIAlzB1YPnOgsPc7B7bc/A==", + "requires": {} + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index be49c925..49e4258e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,7 @@ "file-saver": "^2.0.5", "jose": "^4.14.4", "jwt-decode": "^3.1.2", + "markdown-to-jsx": "^7.4.1", "mime-types": "^2.1.35", "moment": "^2.29.4", "next": "^13.4.12", diff --git a/frontend/src/components/share/FilePreview.tsx b/frontend/src/components/share/FilePreview.tsx index 07d2889d..0ff32bc4 100644 --- a/frontend/src/components/share/FilePreview.tsx +++ b/frontend/src/components/share/FilePreview.tsx @@ -1,9 +1,10 @@ -import { Button, Center, Stack, Text, Title } from "@mantine/core"; +import { Button, Center, Stack, Text, Title, useMantineTheme } from "@mantine/core"; import { modals } from "@mantine/modals"; import Link from "next/link"; import React, { Dispatch, SetStateAction, useEffect, useState } from "react"; import { FormattedMessage } from "react-intl"; import api from "../../services/api.service"; +import Markdown from "markdown-to-jsx"; const FilePreviewContext = React.createContext<{ shareId: string; @@ -115,22 +116,40 @@ const ImagePreview = () => { const TextPreview = () => { const { shareId, fileId } = React.useContext(FilePreviewContext); - const [text, setText] = useState(null); + const [ text, setText ] = useState(""); + const { colorScheme } = useMantineTheme(); useEffect(() => { api .get(`/shares/${shareId}/files/${fileId}?download=false`) - .then((res) => setText(res.data)); - }, [shareId, fileId]); + .then((res) => setText(res.data ?? "Preview couldn't be fetched.")); + }, [ shareId, fileId ]); + + const options = { + overrides: { + pre: { + props: { + style: { + backgroundColor: colorScheme == "dark" + ? "rgba(50, 50, 50, 0.5)" + : "rgba(220, 220, 220, 0.5)", + padding: "0.75em", + whiteSpace: "pre-wrap", + } + } + }, + table: { + props: { + className: "md" + } + } + } + }; return ( -
- - - {text} - - -
+ + {text} + ); }; diff --git a/frontend/src/styles/global.style.tsx b/frontend/src/styles/global.style.tsx index c3b5ffad..ef284de0 100644 --- a/frontend/src/styles/global.style.tsx +++ b/frontend/src/styles/global.style.tsx @@ -3,11 +3,20 @@ import { Global } from "@mantine/core"; const GlobalStyle = () => { return ( ({ + styles={(theme) => ({ a: { color: "inherit", textDecoration: "none", }, + "table.md, table.md th:nth-of-type(odd), table.md td:nth-of-type(odd)": { + background: theme.colorScheme == "dark" + ? "rgba(50, 50, 50, 0.5)" + : "rgba(220, 220, 220, 0.5)", + }, + "table.md td": { + paddingLeft: "0.5em", + paddingRight: "0.5em", + }, })} /> );