mirror of
https://github.com/usememos/memos.git
synced 2024-12-19 17:12:02 +03:00
feat: add MemoContent
component
This commit is contained in:
parent
7b0987610c
commit
6e4577f721
@ -3,10 +3,9 @@ import * as utils from "../helpers/utils";
|
|||||||
import useI18n from "../hooks/useI18n";
|
import useI18n from "../hooks/useI18n";
|
||||||
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 Image from "./Image";
|
|
||||||
import toastHelper from "./Toast";
|
import toastHelper from "./Toast";
|
||||||
|
import MemoContent from "./MemoContent";
|
||||||
|
import MemoResources from "./MemoResources";
|
||||||
import "../less/memo.less";
|
import "../less/memo.less";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -72,14 +71,8 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="memo-content-text" dangerouslySetInnerHTML={{ __html: formatMemoContent(memo.content) }}></div>
|
<MemoContent className="memo-content-wrapper" content={memo.content} />
|
||||||
<Only when={imageUrls.length > 0}>
|
<MemoResources memo={memo} />
|
||||||
<div className="images-wrapper">
|
|
||||||
{imageUrls.map((imgUrl, idx) => (
|
|
||||||
<Image className="memo-img" key={idx} imgUrl={imgUrl} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</Only>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
import { formatMemoContent } from "../helpers/marked";
|
import MemoContent, { DisplayConfig } from "./MemoContent";
|
||||||
import "../less/daily-memo.less";
|
import "../less/daily-memo.less";
|
||||||
|
|
||||||
interface DailyMemo extends Memo {
|
interface DailyMemo extends Memo {
|
||||||
@ -18,22 +18,17 @@ 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 displayConfig: DisplayConfig = {
|
||||||
|
enableExpand: false,
|
||||||
|
showInlineImage: true,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="daily-memo-wrapper">
|
<div className="daily-memo-wrapper">
|
||||||
<div className="time-wrapper">
|
<div className="time-wrapper">
|
||||||
<span className="normal-text">{memo.timeStr}</span>
|
<span className="normal-text">{memo.timeStr}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="memo-content-container">
|
<MemoContent className="memo-content-container" content={memo.content} displayConfig={displayConfig} />
|
||||||
<div
|
|
||||||
className="memo-content-text"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: formatMemoContent(memo.content, {
|
|
||||||
inlineImage: true,
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<div className="split-line"></div>
|
<div className="split-line"></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -5,11 +5,12 @@ import { memo, useEffect, useRef, useState } from "react";
|
|||||||
import "dayjs/locale/zh";
|
import "dayjs/locale/zh";
|
||||||
import useI18n from "../hooks/useI18n";
|
import useI18n from "../hooks/useI18n";
|
||||||
import { UNKNOWN_ID } from "../helpers/consts";
|
import { UNKNOWN_ID } from "../helpers/consts";
|
||||||
import { DONE_BLOCK_REG, formatMemoContent, TODO_BLOCK_REG } from "../helpers/marked";
|
import { DONE_BLOCK_REG, TODO_BLOCK_REG } from "../helpers/marked";
|
||||||
import { editorStateService, locationService, memoService, userService } from "../services";
|
import { editorStateService, locationService, memoService, userService } from "../services";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import Only from "./common/OnlyWhen";
|
import Only from "./common/OnlyWhen";
|
||||||
import toastHelper from "./Toast";
|
import toastHelper from "./Toast";
|
||||||
|
import MemoContent from "./MemoContent";
|
||||||
import MemoResources from "./MemoResources";
|
import MemoResources from "./MemoResources";
|
||||||
import showMemoCardDialog from "./MemoCardDialog";
|
import showMemoCardDialog from "./MemoCardDialog";
|
||||||
import showShareMemoImageDialog from "./ShareMemoImageDialog";
|
import showShareMemoImageDialog from "./ShareMemoImageDialog";
|
||||||
@ -17,18 +18,10 @@ import "../less/memo.less";
|
|||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
const MAX_MEMO_CONTAINER_HEIGHT = 384;
|
|
||||||
|
|
||||||
type ExpandButtonStatus = -1 | 0 | 1;
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
memo: Memo;
|
memo: Memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
|
||||||
expandButtonStatus: ExpandButtonStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getFormatedMemoCreatedAtStr = (createdTs: number, locale = "en"): string => {
|
export const getFormatedMemoCreatedAtStr = (createdTs: number, locale = "en"): string => {
|
||||||
if (Date.now() - createdTs < 1000 * 60 * 60 * 24) {
|
if (Date.now() - createdTs < 1000 * 60 * 60 * 24) {
|
||||||
return dayjs(createdTs).locale(locale).fromNow();
|
return dayjs(createdTs).locale(locale).fromNow();
|
||||||
@ -40,26 +33,12 @@ export const getFormatedMemoCreatedAtStr = (createdTs: number, locale = "en"): s
|
|||||||
const Memo: React.FC<Props> = (props: Props) => {
|
const Memo: React.FC<Props> = (props: Props) => {
|
||||||
const memo = props.memo;
|
const memo = props.memo;
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const [state, setState] = useState<State>({
|
|
||||||
expandButtonStatus: -1,
|
|
||||||
});
|
|
||||||
const [createdAtStr, setCreatedAtStr] = useState<string>(getFormatedMemoCreatedAtStr(memo.createdTs, locale));
|
const [createdAtStr, setCreatedAtStr] = useState<string>(getFormatedMemoCreatedAtStr(memo.createdTs, locale));
|
||||||
const memoContainerRef = useRef<HTMLDivElement>(null);
|
const memoContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const memoContentContainerRef = useRef<HTMLDivElement>(null);
|
const memoContentContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const isVisitorMode = userService.isVisitorMode();
|
const isVisitorMode = userService.isVisitorMode();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!memoContentContainerRef) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Number(memoContentContainerRef.current?.clientHeight) > MAX_MEMO_CONTAINER_HEIGHT) {
|
|
||||||
setState({
|
|
||||||
...state,
|
|
||||||
expandButtonStatus: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let intervalFlag = -1;
|
let intervalFlag = -1;
|
||||||
if (Date.now() - memo.createdTs < 1000 * 60 * 60 * 24) {
|
if (Date.now() - memo.createdTs < 1000 * 60 * 60 * 24) {
|
||||||
intervalFlag = setInterval(() => {
|
intervalFlag = setInterval(() => {
|
||||||
@ -185,17 +164,6 @@ const Memo: React.FC<Props> = (props: Props) => {
|
|||||||
editorStateService.setEditMemoWithId(memo.id);
|
editorStateService.setEditMemoWithId(memo.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExpandBtnClick = () => {
|
|
||||||
const expandButtonStatus = Boolean(!state.expandButtonStatus);
|
|
||||||
if (!expandButtonStatus) {
|
|
||||||
memoContainerRef.current?.scrollIntoView();
|
|
||||||
}
|
|
||||||
|
|
||||||
setState({
|
|
||||||
expandButtonStatus: Number(expandButtonStatus) as ExpandButtonStatus,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.pinned ? "pinned" : ""}`} ref={memoContainerRef}>
|
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.pinned ? "pinned" : ""}`} ref={memoContainerRef}>
|
||||||
<div className="memo-top-wrapper">
|
<div className="memo-top-wrapper">
|
||||||
@ -238,21 +206,12 @@ const Memo: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<MemoContent
|
||||||
ref={memoContentContainerRef}
|
className=""
|
||||||
className={`memo-content-text ${state.expandButtonStatus === 0 ? "expanded" : ""}`}
|
content={memo.content}
|
||||||
onClick={handleMemoContentClick}
|
onMemoContentClick={handleMemoContentClick}
|
||||||
onDoubleClick={handleMemoContentDoubleClick}
|
onMemoContentDoubleClick={handleMemoContentDoubleClick}
|
||||||
dangerouslySetInnerHTML={{ __html: formatMemoContent(memo.content) }}
|
/>
|
||||||
></div>
|
|
||||||
{state.expandButtonStatus !== -1 && (
|
|
||||||
<div className="expand-btn-container">
|
|
||||||
<span className={`btn ${state.expandButtonStatus === 0 ? "expand-btn" : "fold-btn"}`} onClick={handleExpandBtnClick}>
|
|
||||||
{state.expandButtonStatus === 0 ? "Expand" : "Fold"}
|
|
||||||
<Icon.ChevronRight className="icon-img" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<MemoResources memo={memo} />
|
<MemoResources memo={memo} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -9,6 +9,7 @@ import toastHelper from "./Toast";
|
|||||||
import { generateDialog } from "./Dialog";
|
import { generateDialog } from "./Dialog";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import Selector from "./common/Selector";
|
import Selector from "./common/Selector";
|
||||||
|
import MemoContent from "./MemoContent";
|
||||||
import MemoResources from "./MemoResources";
|
import MemoResources from "./MemoResources";
|
||||||
import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog";
|
import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog";
|
||||||
import "../less/memo-card-dialog.less";
|
import "../less/memo-card-dialog.less";
|
||||||
@ -161,11 +162,12 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="memo-container">
|
<div className="memo-container">
|
||||||
<div
|
<MemoContent
|
||||||
className="memo-content-text"
|
className=""
|
||||||
onClick={handleMemoContentClick}
|
displayConfig={{ enableExpand: false }}
|
||||||
dangerouslySetInnerHTML={{ __html: formatMemoContent(memo.content) }}
|
content={memo.content}
|
||||||
></div>
|
onMemoContentClick={handleMemoContentClick}
|
||||||
|
/>
|
||||||
<MemoResources memo={memo} />
|
<MemoResources memo={memo} />
|
||||||
</div>
|
</div>
|
||||||
<div className="layer-container"></div>
|
<div className="layer-container"></div>
|
||||||
|
@ -1,28 +1,100 @@
|
|||||||
import { useRef } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { formatMemoContent } from "../helpers/marked";
|
import { formatMemoContent } from "../helpers/marked";
|
||||||
|
import Icon from "./Icon";
|
||||||
import "../less/memo-content.less";
|
import "../less/memo-content.less";
|
||||||
|
|
||||||
|
const defaultDisplayConfig: DisplayConfig = {
|
||||||
|
enableExpand: true,
|
||||||
|
showInlineImage: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface DisplayConfig {
|
||||||
|
enableExpand: boolean;
|
||||||
|
showInlineImage: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className: string;
|
className: string;
|
||||||
content: string;
|
content: string;
|
||||||
onMemoContentClick: (e: React.MouseEvent) => void;
|
displayConfig?: Partial<DisplayConfig>;
|
||||||
|
onMemoContentClick?: (e: React.MouseEvent) => void;
|
||||||
|
onMemoContentDoubleClick?: (e: React.MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ExpandButtonStatus = -1 | 0 | 1;
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
expandButtonStatus: ExpandButtonStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_MEMO_CONTAINER_HEIGHT = 384;
|
||||||
|
|
||||||
const MemoContent: React.FC<Props> = (props: Props) => {
|
const MemoContent: React.FC<Props> = (props: Props) => {
|
||||||
const { className, content, onMemoContentClick } = props;
|
const { className, content, onMemoContentClick, onMemoContentDoubleClick } = props;
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
expandButtonStatus: -1,
|
||||||
|
});
|
||||||
const memoContentContainerRef = useRef<HTMLDivElement>(null);
|
const memoContentContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const displayConfig = {
|
||||||
|
...defaultDisplayConfig,
|
||||||
|
...props.displayConfig,
|
||||||
|
};
|
||||||
|
const formatConfig = {
|
||||||
|
inlineImage: displayConfig.showInlineImage,
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!memoContentContainerRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayConfig.enableExpand) {
|
||||||
|
if (Number(memoContentContainerRef.current?.clientHeight) > MAX_MEMO_CONTAINER_HEIGHT) {
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
expandButtonStatus: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleMemoContentClick = async (e: React.MouseEvent) => {
|
const handleMemoContentClick = async (e: React.MouseEvent) => {
|
||||||
onMemoContentClick(e);
|
if (onMemoContentClick) {
|
||||||
|
onMemoContentClick(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMemoContentDoubleClick = async (e: React.MouseEvent) => {
|
||||||
|
if (onMemoContentDoubleClick) {
|
||||||
|
onMemoContentDoubleClick(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExpandBtnClick = () => {
|
||||||
|
const expandButtonStatus = Boolean(!state.expandButtonStatus);
|
||||||
|
setState({
|
||||||
|
expandButtonStatus: Number(expandButtonStatus) as ExpandButtonStatus,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={`memo-content-wrapper ${className}`}>
|
||||||
ref={memoContentContainerRef}
|
<div
|
||||||
className={`memo-content-text ${className}`}
|
ref={memoContentContainerRef}
|
||||||
onClick={handleMemoContentClick}
|
className={`memo-content-text ${state.expandButtonStatus === 0 ? "expanded" : ""}`}
|
||||||
dangerouslySetInnerHTML={{ __html: formatMemoContent(content) }}
|
onClick={handleMemoContentClick}
|
||||||
></div>
|
onDoubleClick={handleMemoContentDoubleClick}
|
||||||
|
dangerouslySetInnerHTML={{ __html: formatMemoContent(content, formatConfig) }}
|
||||||
|
></div>
|
||||||
|
{state.expandButtonStatus !== -1 && (
|
||||||
|
<div className="expand-btn-container">
|
||||||
|
<span className={`btn ${state.expandButtonStatus === 0 ? "expand-btn" : "fold-btn"}`} onClick={handleExpandBtnClick}>
|
||||||
|
{state.expandButtonStatus === 0 ? "Expand" : "Fold"}
|
||||||
|
<Icon.ChevronRight className="icon-img" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,11 +4,12 @@ import toImage from "../labs/html2image";
|
|||||||
import { ANIMATION_DURATION } from "../helpers/consts";
|
import { ANIMATION_DURATION } from "../helpers/consts";
|
||||||
import useI18n from "../hooks/useI18n";
|
import useI18n from "../hooks/useI18n";
|
||||||
import * as utils from "../helpers/utils";
|
import * as utils from "../helpers/utils";
|
||||||
import { formatMemoContent, IMAGE_URL_REG } from "../helpers/marked";
|
import { IMAGE_URL_REG } from "../helpers/marked";
|
||||||
import Only from "./common/OnlyWhen";
|
import Only from "./common/OnlyWhen";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import { generateDialog } from "./Dialog";
|
import { generateDialog } from "./Dialog";
|
||||||
import toastHelper from "./Toast";
|
import toastHelper from "./Toast";
|
||||||
|
import MemoContent from "./MemoContent";
|
||||||
import "../less/share-memo-image-dialog.less";
|
import "../less/share-memo-image-dialog.less";
|
||||||
|
|
||||||
interface Props extends DialogProps {
|
interface Props extends DialogProps {
|
||||||
@ -91,7 +92,7 @@ const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<img className="memo-shortcut-img" onClick={handleDownloadBtnClick} src={shortcutImgUrl} />
|
<img className="memo-shortcut-img" onClick={handleDownloadBtnClick} src={shortcutImgUrl} />
|
||||||
</Only>
|
</Only>
|
||||||
<span className="time-text">{memo.createdAtStr}</span>
|
<span className="time-text">{memo.createdAtStr}</span>
|
||||||
<div className="memo-content-text" dangerouslySetInnerHTML={{ __html: formatMemoContent(memo.content) }}></div>
|
<MemoContent className="memo-content-wrapper" content={memo.content} displayConfig={{ enableExpand: false }} />
|
||||||
<Only when={imageUrls.length > 0}>
|
<Only when={imageUrls.length > 0}>
|
||||||
<div className="images-container">
|
<div className="images-container">
|
||||||
{imageUrls.map((imgUrl, idx) => (
|
{imageUrls.map((imgUrl, idx) => (
|
||||||
|
@ -43,10 +43,10 @@ const defaultFormatterConfig: FormatterConfig = {
|
|||||||
inlineImage: false,
|
inlineImage: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatMemoContent = (content: string, addtionConfig?: Partial<FormatterConfig>) => {
|
const formatMemoContent = (content: string, additionConfig?: Partial<FormatterConfig>) => {
|
||||||
const config = {
|
const config = {
|
||||||
...defaultFormatterConfig,
|
...defaultFormatterConfig,
|
||||||
...addtionConfig,
|
...additionConfig,
|
||||||
};
|
};
|
||||||
const tempElement = document.createElement("div");
|
const tempElement = document.createElement("div");
|
||||||
tempElement.innerHTML = parseMarkedToHtml(escape(content));
|
tempElement.innerHTML = parseMarkedToHtml(escape(content));
|
||||||
|
@ -19,13 +19,5 @@
|
|||||||
|
|
||||||
> .memo-content-container {
|
> .memo-content-container {
|
||||||
@apply flex flex-col justify-start items-start w-full overflow-x-hidden p-0 text-base;
|
@apply flex flex-col justify-start items-start w-full overflow-x-hidden p-0 text-base;
|
||||||
|
|
||||||
> .images-container {
|
|
||||||
@apply flex flex-col justify-start items-start mt-1 w-full;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
@apply w-full h-auto rounded mb-2 last:mb-0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,16 @@
|
|||||||
@apply sticky top-0 z-10 max-w-2xl w-full min-h-full flex flex-row justify-between items-center px-4 sm:pr-6 pt-6 mb-2;
|
@apply sticky top-0 z-10 max-w-2xl w-full min-h-full flex flex-row justify-between items-center px-4 sm:pr-6 pt-6 mb-2;
|
||||||
background-color: #f6f5f4;
|
background-color: #f6f5f4;
|
||||||
|
|
||||||
> .logo-img {
|
> .title-container {
|
||||||
@apply h-14 w-auto;
|
@apply flex flex-row justify-start items-center;
|
||||||
|
|
||||||
|
> .logo-img {
|
||||||
|
@apply h-12 sm:h-14 w-auto mr-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .title-text {
|
||||||
|
@apply text-xl sm:text-3xl font-mono text-gray-700;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .action-button-container {
|
> .action-button-container {
|
||||||
|
@ -55,12 +55,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .memo-container {
|
> .memo-container {
|
||||||
.flex(column, flex-start, flex-start);
|
@apply w-full flex flex-col justify-start items-start pt-2;
|
||||||
@apply w-full pt-2;
|
|
||||||
|
|
||||||
> .memo-content-text {
|
|
||||||
@apply w-full text-base;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .normal-text {
|
> .normal-text {
|
||||||
|
@ -1,41 +1,78 @@
|
|||||||
@import "./mixin.less";
|
@import "./mixin.less";
|
||||||
|
|
||||||
.memo-content-text {
|
.memo-content-wrapper {
|
||||||
@apply w-full whitespace-pre-wrap break-words text-base leading-7;
|
@apply w-full flex flex-col justify-start items-start;
|
||||||
|
|
||||||
> p {
|
> .memo-content-text {
|
||||||
@apply inline-block w-full h-auto mb-1 last:mb-0 text-base leading-7 whitespace-pre-wrap break-words;
|
@apply w-full whitespace-pre-wrap break-words text-base leading-7;
|
||||||
|
|
||||||
|
&.expanded {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 8;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
> p {
|
||||||
|
@apply inline-block w-full h-auto mb-1 last:mb-0 text-base leading-7 whitespace-pre-wrap break-words;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
@apply float-left max-w-full w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-span {
|
||||||
|
@apply inline-block w-auto font-mono text-blue-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.memo-link-text {
|
||||||
|
@apply inline-block text-blue-600 cursor-pointer font-bold border-none no-underline hover:opacity-80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
@apply inline-block text-blue-600 cursor-pointer underline break-all hover:opacity-80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.counter-block,
|
||||||
|
.todo-block {
|
||||||
|
@apply float-left inline-block box-border text-center w-7 font-mono select-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.todo-block {
|
||||||
|
@apply w-4 h-4 leading-4 border rounded box-border text-lg cursor-pointer shadow-inner hover:opacity-80;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
@apply w-full mt-1 py-2 px-3 rounded text-sm bg-gray-100 whitespace-pre-wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.img {
|
> .expand-btn-container {
|
||||||
@apply float-left max-w-full w-full;
|
@apply w-full relative flex flex-row justify-start items-center;
|
||||||
}
|
|
||||||
|
|
||||||
.tag-span {
|
> .btn {
|
||||||
@apply inline-block w-auto font-mono text-blue-600;
|
@apply flex flex-row justify-start items-center pl-2 pr-1 py-1 my-1 text-xs rounded-lg border bg-gray-100 border-gray-200 opacity-80 shadow hover:opacity-60;
|
||||||
}
|
|
||||||
|
|
||||||
.memo-link-text {
|
&.expand-btn {
|
||||||
@apply inline-block text-blue-600 cursor-pointer font-bold border-none no-underline hover:opacity-80;
|
@apply mt-2;
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
> .icon-img {
|
||||||
@apply inline-block text-blue-600 cursor-pointer underline break-all hover:opacity-80;
|
@apply rotate-90;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.counter-block,
|
&.fold-btn {
|
||||||
.todo-block {
|
> .icon-img {
|
||||||
@apply float-left inline-block box-border text-center w-7 font-mono select-none;
|
@apply -rotate-90;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.todo-block {
|
> .icon-img {
|
||||||
@apply w-4 h-4 leading-4 border rounded box-border text-lg cursor-pointer shadow-inner hover:opacity-80;
|
@apply w-4 h-auto ml-1 transition-all;
|
||||||
margin-top: 6px;
|
}
|
||||||
margin-left: 6px;
|
}
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
@apply w-full mt-1 py-2 px-3 rounded text-sm bg-gray-100 whitespace-pre-wrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,11 +44,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .time-text {
|
> .time-text {
|
||||||
@apply w-full px-6 pt-5 text-xs text-gray-500 bg-white;
|
@apply w-full px-6 pt-5 pb-2 text-xs text-gray-500 bg-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .memo-content-text {
|
> .memo-content-wrapper {
|
||||||
@apply w-full pt-2 pb-4 px-6 text-base bg-white;
|
@apply w-full px-6 text-base bg-white pb-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .images-container {
|
> .images-container {
|
||||||
|
@ -47,7 +47,10 @@ const Explore = () => {
|
|||||||
<section className="page-wrapper explore">
|
<section className="page-wrapper explore">
|
||||||
<div className="page-container">
|
<div className="page-container">
|
||||||
<div className="page-header">
|
<div className="page-header">
|
||||||
<img className="logo-img" src="/logo-full.webp" alt="" />
|
<div className="title-container">
|
||||||
|
<img className="logo-img" src="/logo.webp" alt="" />
|
||||||
|
<span className="title-text">Explore</span>
|
||||||
|
</div>
|
||||||
<div className="action-button-container">
|
<div className="action-button-container">
|
||||||
<Only when={!loadingState.isLoading}>
|
<Only when={!loadingState.isLoading}>
|
||||||
{user ? (
|
{user ? (
|
||||||
|
Loading…
Reference in New Issue
Block a user