Skip to content

Commit

Permalink
Improve blog feature
Browse files Browse the repository at this point in the history
  • Loading branch information
ubbn committed May 12, 2024
1 parent cd4dc6f commit ab25396
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 43 deletions.
19 changes: 11 additions & 8 deletions frontend/src/common/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import { $getRoot } from "lexical";
import { useEffect } from "react";
import React from "react";
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
Expand All @@ -32,7 +32,7 @@ function Placeholder() {
return <div className="editor-placeholder">Enter some rich text...</div>;
}

const editorConfig = (value: string, editable: boolean): any => ({
const editorConfig = (value: string): any => ({
// The editor theme
theme: ExampleTheme,
// Handling of errors during update
Expand All @@ -54,13 +54,12 @@ const editorConfig = (value: string, editable: boolean): any => ({
AutoLinkNode,
LinkNode,
],
editable,
});

function MyOnChangePlugin({ onChange, value }: { onChange: any, value: any }) {
function MyOnChangePlugin({ onChange, value, editable }: { onChange: any, value: any, editable: boolean }) {
const [editor] = useLexicalComposerContext();

useEffect(() => {
React.useEffect(() => {
return editor.registerUpdateListener(({ editorState }) => {
// onChange(editorState);

Expand All @@ -80,7 +79,7 @@ function MyOnChangePlugin({ onChange, value }: { onChange: any, value: any }) {
});
}, [editor, onChange]);

useEffect(() => {
React.useEffect(() => {
editor.update(() => {
// Get the RootNode from the EditorState
const rootNode = $getRoot();
Expand All @@ -90,6 +89,10 @@ function MyOnChangePlugin({ onChange, value }: { onChange: any, value: any }) {
});
}, [value])

React.useEffect(() => {
editor.setEditable(editable)
}, [editor, editable])

return null;
}

Expand Down Expand Up @@ -122,7 +125,7 @@ export default function Editor({
}

return (
<LexicalComposer initialConfig={editorConfig("", editable)}>
<LexicalComposer initialConfig={editorConfig("")}>
<div className="editor-container">
{!hideToolbar && <ToolbarPlugin />}
<div className="editor-inner">
Expand All @@ -136,7 +139,7 @@ export default function Editor({
ignoreHistoryMergeTagChange
ignoreSelectionChange
/>
<MyOnChangePlugin value={text} onChange={onChange} />
<MyOnChangePlugin value={text} onChange={onChange} editable={editable} />
<HistoryPlugin />
<AutoFocusPlugin />
<CodeHighlightPlugin />
Expand Down
83 changes: 64 additions & 19 deletions frontend/src/components/blog/Post.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { useEffect, useState } from "react";
import { EditOutlined, EyeOutlined, SaveOutlined } from "@ant-design/icons";
import { Button } from "antd";
import React from "react";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { styled } from "styled-components";
import { FlexRow } from "../../common";
import Editor from "../../common/editor/editor";
import { setNeuron, thunkGetNeuron } from "../../redux/neuronSlice";
import { RootState, useAppDispatch } from "../../redux/store";
import { useSelector } from "react-redux";
import Editor from "../../common/editor/editor";
import { styled } from "styled-components";

const Post = () => {
const [item, setItem] = useState<Neuron>()
const { id } = useParams();
const dispatch = useAppDispatch();
const [initial, setInitial] = React.useState<Neuron>()
const [item, setItem] = React.useState<Neuron>()
const [editMode, setEditMode] = React.useState<boolean>(false)
const [pristine, setPristine] = React.useState<boolean>(true);
const { selected } = useSelector((v: RootState) => v.neuron);
const { loading } = useSelector((v: RootState) => v.main);

useEffect(() => {
const { id } = useParams();
const dispatch = useAppDispatch();

React.useEffect(() => {
if (id) {
setItem(undefined)
dispatch(thunkGetNeuron(id))
Expand All @@ -23,24 +30,57 @@ const Post = () => {
})
}, [id]);

useEffect(() => {
React.useEffect(() => {
if (selected) {
setInitial(selected)
setItem(selected)
}
}, [selected])

const saveNeuron = () => {
// onSave(item);
setPristine(true);
setInitial(item)
}

const onView = () => {
setEditMode(false)
}

const onEdit = () => {
setEditMode(true)
}

if (loading) {
return <>Loading...</>
return <Container>Loading...</Container>
}

return (
<Container>
<StyledTitle>{item?.title}</StyledTitle>
<Container editMode={editMode}>
<FlexRow style={{ justifyContent: "space-between", alignItems: "start" }}>
<StyledTitle>{item?.title}</StyledTitle>
{editMode ?
<div>
<Button icon={<SaveOutlined />} disabled={pristine} danger type="text" onClick={saveNeuron} />
<Button icon={<EyeOutlined />} type="link" onClick={onView} />
</div>
:
<Button icon={<EditOutlined />} type="link" onClick={onEdit} />
}
</FlexRow>
<$Wrapper>
<Editor
text={item?.detail}
hideToolbar
editable={false}
text={initial?.detail}
hideToolbar={!editMode}
editable={editMode}
onChange={(value) => {
if (value === initial?.title) {
setPristine(true)
} else {
setPristine(false)
}
setItem({ ...item, detail: value } as Neuron)
}}
/>
</$Wrapper>
</Container>
Expand All @@ -49,13 +89,14 @@ const Post = () => {

export default Post;

const Container = styled.div`
export const Container = styled.div<{ editMode?: boolean; }>`
width: 100%;
padding: 20px 80px 60px;
.editor-container {
border: none;
border: ${props => props.editMode ? "1px solid #dde" : "none"};
}
.editor-input {
padding: 0;
padding: ${props => props.editMode ? "10px" : 0};
}
@media (max-width: 600px) {
padding: 0 5px;
Expand All @@ -64,10 +105,14 @@ const Container = styled.div`

const StyledTitle = styled.h1`
font-size: 30px;
max-width: 90%;
line-height: 30px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`

const $Wrapper = styled.div`
margin-top: 20px;
flex: 1;
height: 100%
& img {
Expand Down
46 changes: 30 additions & 16 deletions frontend/src/components/blog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { format } from "date-fns";
import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { styled } from "styled-components";
import { FlexRow } from "../../common";
import { thunkFetchNeurons } from "../../redux/neuronSlice";
import { RootState, useAppDispatch } from "../../redux/store";
import { getDateFromStr, yyyyMMdd } from "../neuron/utils";
import { compareNeurons, getDateFromStr, yyyyMMdd } from "../neuron/utils";
import { Container } from "./Post";

const getDateInYYYYMMDD = (ognooStr?: string) => {
if (ognooStr) {
Expand All @@ -31,7 +34,7 @@ const Blog = () => {

useEffect(() => {
if (items.length > 0) {
setPagedItems(items.filter(v => v.public).slice(0, pageSize));
setPagedItems(items.filter(v => v.public).sort(compareNeurons).slice(0, pageSize));
setTotalPage(Math.ceil(items.length / pageSize));
} else {
setPagedItems([]);
Expand Down Expand Up @@ -60,30 +63,41 @@ const Blog = () => {
}
}

if (pagedItems.length === 0) {
return <Container>No post...</Container>
}

return (
<div style={{ width: "100%" }}>
<Container>
{pagedItems.map((v, i) => (
<div key={i}
onClick={() => onClickPost(v.id)}
style={{
border: "1px solid lightgrey",
padding: "5px 10px",
margin: "20px 0",
borderRadius: 6,
cursor: "pointer"
}}
>
<StyledCart key={i} onClick={() => onClickPost(v.id)}>
<h2>{v.title}</h2>
{getDateInYYYYMMDD(v.created)}
</div>
<FlexRow style={{ alignItems: "end", justifyContent: "space-between" }}>
<div style={{ color: "gray", fontSize: 14 }} title="Published on">
{getDateInYYYYMMDD(v.created)}
</div>
</FlexRow>
</StyledCart>
))}
{pagedItems.length > pageSize && <div style={{ margin: 20 }}>
<Button onClick={onPrev}>prev</Button>
{currentPage} of {totalPage}
<Button onClick={onNext}>next</Button>
</div>}
</div>
</Container>
);
};

export default Blog;

const StyledCart = styled.div`
border: 1px solid lightgrey;
padding: 25px;
margin: 20px 0;
border-radius: 6px;
cursor: pointer;
box-shadow: 3px 3px 7px lightgray;
&:hover {
box-shadow: 7px 7px 13px lightgray;
}
`
3 changes: 3 additions & 0 deletions frontend/src/components/layout/menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,7 @@ const Text = styled.div<{ selected: boolean }>`

const Separator = styled.span`
margin: 0 20px;
@media (max-width: 600px) {
margin: 0 13px;
}
`;

0 comments on commit ab25396

Please sign in to comment.