chore: show inline image in daily review dialog (#135)

This commit is contained in:
boojack 2022-07-29 20:11:14 +08:00 committed by GitHub
parent 9994b1fabc
commit df7b4d54c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 31 deletions

View file

@ -2,10 +2,10 @@ import { IMAGE_URL_REG } from "../helpers/consts";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";
import useToggle from "../hooks/useToggle"; import useToggle from "../hooks/useToggle";
import { memoService } from "../services"; import { memoService } from "../services";
import { formatMemoContent } from "../helpers/marked";
import Only from "./common/OnlyWhen"; import Only from "./common/OnlyWhen";
import Image from "./Image"; import Image from "./Image";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
import { formatMemoContent } from "./Memo";
import "../less/memo.less"; import "../less/memo.less";
interface Props { interface Props {

View file

@ -1,7 +1,5 @@
import { IMAGE_URL_REG } from "../helpers/consts";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";
import Only from "./common/OnlyWhen"; import { formatMemoContent } from "../helpers/marked";
import { formatMemoContent } from "./Memo";
import "../less/daily-memo.less"; import "../less/daily-memo.less";
interface DailyMemo extends Memo { interface DailyMemo extends Memo {
@ -20,7 +18,6 @@ const DailyMemo: React.FC<Props> = (props: Props) => {
createdAtStr: utils.getDateTimeString(propsMemo.createdTs), createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
timeStr: utils.getTimeString(propsMemo.createdTs), timeStr: utils.getTimeString(propsMemo.createdTs),
}; };
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []).map((s) => s.replace(IMAGE_URL_REG, "$1"));
return ( return (
<div className="daily-memo-wrapper"> <div className="daily-memo-wrapper">
@ -28,14 +25,14 @@ const DailyMemo: React.FC<Props> = (props: Props) => {
<span className="normal-text">{memo.timeStr}</span> <span className="normal-text">{memo.timeStr}</span>
</div> </div>
<div className="memo-content-container"> <div className="memo-content-container">
<div className="memo-content-text" dangerouslySetInnerHTML={{ __html: formatMemoContent(memo.content) }}></div> <div
<Only when={imageUrls.length > 0}> className="memo-content-text"
<div className="images-container"> dangerouslySetInnerHTML={{
{imageUrls.map((imgUrl, idx) => ( __html: formatMemoContent(memo.content, {
<img key={idx} src={imgUrl} decoding="async" /> inlineImage: true,
))} }),
</div> }}
</Only> ></div>
</div> </div>
<div className="split-line"></div> <div className="split-line"></div>
</div> </div>

View file

@ -1,9 +1,9 @@
import { memo, useEffect, useRef, useState } from "react"; import { memo, useEffect, useRef, useState } from "react";
import { escape, indexOf } from "lodash-es"; import { indexOf } from "lodash-es";
import dayjs from "dayjs"; import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
import { IMAGE_URL_REG, LINK_URL_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../helpers/consts"; import { IMAGE_URL_REG, UNKNOWN_ID } from "../helpers/consts";
import { DONE_BLOCK_REG, parseMarkedToHtml, TODO_BLOCK_REG } from "../helpers/marked"; import { DONE_BLOCK_REG, formatMemoContent, TODO_BLOCK_REG } from "../helpers/marked";
import { editorStateService, locationService, memoService, userService } from "../services"; import { editorStateService, locationService, memoService, userService } from "../services";
import Only from "./common/OnlyWhen"; import Only from "./common/OnlyWhen";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
@ -234,15 +234,4 @@ const Memo: React.FC<Props> = (props: Props) => {
); );
}; };
export function formatMemoContent(content: string) {
const tempElement = document.createElement("div");
tempElement.innerHTML = parseMarkedToHtml(escape(content));
return tempElement.innerHTML
.replace(IMAGE_URL_REG, "")
.replace(MEMO_LINK_REG, "<span class='memo-link-text' data-value='$2'>$1</span>")
.replace(LINK_URL_REG, "<a class='link' target='_blank' rel='noreferrer' href='$2'>$1</a>")
.replace(TAG_REG, "<span class='tag-span'>#$1</span> ");
}
export default memo(Memo); export default memo(Memo);

View file

@ -2,12 +2,11 @@ import { useState, useEffect, useCallback } from "react";
import { editorStateService, memoService, userService } from "../services"; import { editorStateService, memoService, userService } from "../services";
import { IMAGE_URL_REG, MEMO_LINK_REG, UNKNOWN_ID } from "../helpers/consts"; import { IMAGE_URL_REG, MEMO_LINK_REG, UNKNOWN_ID } from "../helpers/consts";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";
import { parseHtmlToRawText } from "../helpers/marked"; import { formatMemoContent, parseHtmlToRawText } from "../helpers/marked";
import Only from "./common/OnlyWhen"; import Only from "./common/OnlyWhen";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
import { generateDialog } from "./Dialog"; import { generateDialog } from "./Dialog";
import Image from "./Image"; import Image from "./Image";
import { formatMemoContent } from "./Memo";
import "../less/memo-card-dialog.less"; import "../less/memo-card-dialog.less";
import Selector from "./common/Selector"; import Selector from "./common/Selector";

View file

@ -3,10 +3,10 @@ import { userService } from "../services";
import toImage from "../labs/html2image"; import toImage from "../labs/html2image";
import { ANIMATION_DURATION, IMAGE_URL_REG } from "../helpers/consts"; import { ANIMATION_DURATION, IMAGE_URL_REG } from "../helpers/consts";
import * as utils from "../helpers/utils"; import * as utils from "../helpers/utils";
import { formatMemoContent } from "../helpers/marked";
import { generateDialog } from "./Dialog"; import { generateDialog } from "./Dialog";
import Only from "./common/OnlyWhen"; import Only from "./common/OnlyWhen";
import toastHelper from "./Toast"; import toastHelper from "./Toast";
import { formatMemoContent } from "./Memo";
import "../less/share-memo-image-dialog.less"; import "../less/share-memo-image-dialog.less";
interface Props extends DialogProps { interface Props extends DialogProps {

View file

@ -1,3 +1,6 @@
import { escape } from "lodash-es";
import { IMAGE_URL_REG, LINK_URL_REG, MEMO_LINK_REG, TAG_REG } from "./consts";
const CODE_BLOCK_REG = /```([\s\S]*?)```/g; const CODE_BLOCK_REG = /```([\s\S]*?)```/g;
const BOLD_TEXT_REG = /\*\*(.+?)\*\*/g; const BOLD_TEXT_REG = /\*\*(.+?)\*\*/g;
const EM_TEXT_REG = /\*(.+?)\*/g; const EM_TEXT_REG = /\*(.+?)\*/g;
@ -28,4 +31,32 @@ const parseHtmlToRawText = (htmlStr: string): string => {
return text; return text;
}; };
export { parseMarkedToHtml, parseHtmlToRawText }; interface FormatterConfig {
inlineImage: boolean;
}
const defaultFormatterConfig: FormatterConfig = {
inlineImage: false,
};
const formatMemoContent = (content: string, addtionConfig?: Partial<FormatterConfig>) => {
const config = {
...defaultFormatterConfig,
...addtionConfig,
};
const tempElement = document.createElement("div");
tempElement.innerHTML = parseMarkedToHtml(escape(content));
let outputString = tempElement.innerHTML;
if (config.inlineImage) {
outputString = outputString.replace(IMAGE_URL_REG, "<img class='img' src='$1' />");
} else {
outputString = outputString.replace(IMAGE_URL_REG, "");
}
return outputString
.replace(MEMO_LINK_REG, "<span class='memo-link-text' data-value='$2'>$1</span>")
.replace(LINK_URL_REG, "<a class='link' target='_blank' rel='noreferrer' href='$2'>$1</a>")
.replace(TAG_REG, "<span class='tag-span'>#$1</span> ");
};
export { formatMemoContent, parseHtmlToRawText };

View file

@ -7,6 +7,10 @@
@apply inline-block w-full h-auto mb-1 last:mb-0 text-base leading-7 whitespace-pre-wrap break-all; @apply inline-block w-full h-auto mb-1 last:mb-0 text-base leading-7 whitespace-pre-wrap break-all;
} }
.img {
@apply float-left max-w-full w-full;
}
.tag-span { .tag-span {
@apply inline-block w-auto font-mono text-blue-600; @apply inline-block w-auto font-mono text-blue-600;
} }