Skip to content

Commit 46a336b

Browse files
josh-ramos-22Josh Ramos
andauthored
[WEB-65] [EDITOR] Make blog title editable within editor (#374)
* created styled text box for editable titles * basic graphical functionality of renaming files done. Onto redux integration * changed cursor to ibeam (text) when hovering over * removed unused types * renaming partially working -> updates on dashboard but doesn't persist on immediate refresh of editor * fixed persistence of changes on reload issue but now it's messing up the back button ;-; * fixed back button issue by setting replace to true -> Doesn't add to react router history :D * added code to prevent users from naming their documents with an empty string --------- Co-authored-by: Josh Ramos <josh.ramos@student.unsw.edu.au>
1 parent 387be22 commit 46a336b

File tree

4 files changed

+93
-4
lines changed

4 files changed

+93
-4
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import styled from "styled-components";
2+
3+
export const StyledTextBox = styled.input`
4+
background: transparent;
5+
6+
border: none;
7+
border-color: transparent;
8+
9+
10+
padding: 0.5em;
11+
12+
font-size: inherit;
13+
14+
display: flex;
15+
justify-content: center;
16+
align-items: center;
17+
user-select: none;
18+
19+
&:hover {
20+
cursor: text;
21+
color: black;
22+
transform: scale(1.04);
23+
}
24+
25+
cursor: pointer;
26+
`;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from "react";
2+
import { StyledTextBox } from "./EditableTitle-Styled";
3+
4+
type Props = {
5+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
6+
onBlur?: React.FocusEventHandler<HTMLInputElement>
7+
value: string
8+
};
9+
10+
export default function EditableTitle({ onChange, onBlur, value, ...styleProps }: Props) {
11+
return (
12+
<StyledTextBox onChange={onChange} onBlur={onBlur} value={value} {...styleProps}/>
13+
);
14+
}
15+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import EditableTitle from './EditableTitle';
2+
3+
export default EditableTitle;

frontend/src/packages/editor/index.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import CreateContentBlock from "src/cse-ui-kit/CreateContentBlock_button";
88
import CreateHeadingBlock from "src/cse-ui-kit/CreateHeadingBlock_button";
99
import SyncDocument from "src/cse-ui-kit/SyncDocument_button";
1010
import PublishDocument from "src/cse-ui-kit/PublishDocument_button";
11+
import EditableTitle from "src/cse-ui-kit/EditableTitle_textbox";
12+
1113
import EditorHeader from "src/deprecated/components/Editor/EditorHeader";
1214
import { useParams, useLocation, useNavigate } from "react-router-dom";
1315

@@ -20,6 +22,12 @@ import CreateCodeBlock from "src/cse-ui-kit/CreateCodeBlock_button ";
2022
import IconButton from "@mui/material/IconButton";
2123
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
2224

25+
import {
26+
RenamePayloadType,
27+
renameFileEntityAction,
28+
} from "src/packages/dashboard/state/folders/actions";
29+
import { useDispatch } from "react-redux";
30+
2331
const Container = styled.div`
2432
display: flex;
2533
flex-direction: column;
@@ -52,7 +60,34 @@ const EditorPage: FC = () => {
5260
const [focusedId, setFocusedId] = useState<number>(0);
5361

5462
const state = useLocation().state as LocationState;
55-
const filename = state != null ? state.filename : "";
63+
64+
const [filename, setFilename] = useState<string>(state != null ? state.filename : "");
65+
66+
const [savedFilename, setSavedFilename] = useState<string>(`${filename}`);
67+
68+
const navigate = useNavigate();
69+
const dispatch = useDispatch();
70+
const updateFilename = () => {
71+
// No empty names allowed!
72+
if (filename == "") {
73+
setFilename(savedFilename);
74+
75+
} else if (filename !== savedFilename && id !== undefined) {
76+
const newPayload: RenamePayloadType = { id, newName: filename };
77+
dispatch(renameFileEntityAction(newPayload));
78+
79+
// Re-navigate to current page with new file name so that
80+
// filename changes are persistent on reloads
81+
navigate("/editor/" + id, {
82+
replace: true,
83+
state: {
84+
filename
85+
}
86+
}), [navigate];
87+
88+
setSavedFilename(`${filename}`);
89+
}
90+
}
5691

5792
const updateValues: UpdateCallback = (idx, updatedBlock) => {
5893
const requiresUpdate = JSON.stringify(blocks[idx]) !== JSON.stringify(updateValues);
@@ -100,16 +135,26 @@ const EditorPage: FC = () => {
100135
opManager.current?.pushToServer(newCreationOperation(newElement, blocks.length));
101136
}
102137

103-
const navigate = useNavigate();
104138

105139
return (
106140
<div style={{ height: "100%" }}>
107141
<EditorHeader>
108142
<LeftContainer>
109-
<IconButton aria-label="back" onClick={() => navigate(-1)} sx={{ 'paddingRight': '20px' }}>
143+
<IconButton
144+
aria-label="back"
145+
onClick={() => navigate(-1)}
146+
sx={{ 'paddingRight': '20px' }}>
110147
<ArrowBackIcon fontSize="inherit"/>
111148
</IconButton>
112-
{filename}
149+
150+
<EditableTitle
151+
value={filename}
152+
onChange={(event) => {
153+
setFilename(event.target.value)
154+
}}
155+
onBlur={updateFilename}
156+
/>
157+
113158
</LeftContainer>
114159
<ButtonContainer>
115160
<SyncDocument onClick={() => syncDocument()} />

0 commit comments

Comments
 (0)