Skip to content

Commit

Permalink
Refactored step content block functions to work with a multi-step tut…
Browse files Browse the repository at this point in the history
…orial
  • Loading branch information
tomdng committed Mar 19, 2021
1 parent 98c4ced commit 439d5b6
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 74 deletions.
File renamed without changes.
127 changes: 110 additions & 17 deletions src/components/tutorialEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,110 @@ const ContentBlock: AnyStyledComponent = styled.div`
margin-bottom: 20px;
`;

// TODO: See if some of the block editing functions can be simplified
const TutEditor: React.FC = (): JSX.Element => {
const [content, setContent] = useState([
const [step /* , setStep */] = useState(0);
const [steps, setSteps] = useState([
{
type: "text",
value: ""
stepTitle: "Step 1",
stepHint: "",
stepSuccess: "",
content: [
{
type: "code",
value: ""
}
]
}
]);

const addBlock = (): void => {
const contentCopy = [...content];
contentCopy.push({
const stepCopy = steps[step];
stepCopy.content.push({
type: "text",
value: ""
});
setContent(contentCopy);

setSteps([
...steps.slice(0, step),
stepCopy,
...steps.slice(step + 1, steps.length)
]);
};

const deleteBlock = (index: number): void => {
const stepCopy = steps[step];
stepCopy.content = [
...stepCopy.content.slice(0, index),
...stepCopy.content.slice(index + 1, stepCopy.content.length)
];

setSteps([
...steps.slice(0, step),
stepCopy,
...steps.slice(step + 1, steps.length)
]);
};

const changeOrder = (direction: "up" | "down", index: number): void => {
const stepCopy = steps[step];
const contentCopy = stepCopy.content;
let diff = 0;

if (direction === "up" && index - 1 >= 0) {
// const temp = contentCopy[index - 1];
// contentCopy[index - 1] = contentCopy[index];
// contentCopy[index] = temp;
diff = -1;
} else if (direction === "down" && index + 1 < contentCopy.length) {
diff = 1;
}

const temp = contentCopy[index + diff];
contentCopy[index + diff] = contentCopy[index];
contentCopy[index] = temp;

stepCopy.content = contentCopy;
setSteps([
...steps.slice(0, step),
stepCopy,
...steps.slice(step + 1, steps.length)
]);
};

const toggleBlockType = (type: string, index: number): void => {
const stepCopy = steps[step];
stepCopy.content[index].type = type;
setSteps([
...steps.slice(0, step),
stepCopy,
...steps.slice(step + 1, steps.length)
]);
};

// This change handler works for both text blocks and code blocks
// by checking the type of the change argument.
const blockChangeHandler = (
change: React.ChangeEvent<HTMLInputElement> | string,
index: number
): void => {
let changeText = "";
// Checks to see what type the change argument is because it can
// either be an onChange event or just a string, which is what Ace Editor
// uses for the code block
if (typeof change === "object" && change.target) {
changeText = change.target.value;
} else if (typeof change === "string") {
changeText = change;
} else return;

const stepCopy = steps[step];
stepCopy.content[index].value = changeText;
setSteps([
...steps.slice(0, step),
stepCopy,
...steps.slice(step + 1, steps.length)
]);
};

return (
Expand Down Expand Up @@ -153,17 +242,21 @@ const TutEditor: React.FC = (): JSX.Element => {
</StyledTitle>
<StepContentBody>
<div>
{content.map((value: ContentBlock, index: number) => {
return (
<StepContent
value={value}
index={index}
key={index.toString()}
content={content}
setContent={setContent}
/>
);
})}
{steps[step].content.map(
(content: ContentBlock, index: number) => {
return (
<StepContent
content={content}
index={index}
key={index.toString()}
deleteBlock={deleteBlock}
changeOrder={changeOrder}
toggleBlockType={toggleBlockType}
changeHandler={blockChangeHandler}
/>
);
}
)}
</div>
<Button
submitFunction={addBlock}
Expand Down
86 changes: 29 additions & 57 deletions src/components/tutorialEditor/stepContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,26 @@ interface ContentBlock {
}

interface StepContentProps {
value: ContentBlock;
content: ContentBlock;
index: number;
content: ContentBlock[];
setContent: Function;
deleteBlock: (index: number) => void;
changeHandler: (
change: React.ChangeEvent<HTMLInputElement> | string,
index: number
) => void;
changeOrder: (direction: "up" | "down", index: number) => void;
toggleBlockType: (type: string, index: number) => void;
}

const StepContent: React.FC<StepContentProps> = (props): JSX.Element => {
const { value, index, content, setContent } = props;
const {
content,
index,
deleteBlock,
changeHandler,
changeOrder,
toggleBlockType
} = props;

const [hovering, setHovering] = useState(-1);

Expand All @@ -105,47 +117,7 @@ const StepContent: React.FC<StepContentProps> = (props): JSX.Element => {
width: "100%",
backgroundColor: background,
fontFamily: "Source Code Pro",
display: content[index].type === "code" ? "block" : "none"
};

const changeType = (type: string): void => {
const contentCopy = [...content];
contentCopy[index].type = type;
setContent(contentCopy);
};

const changeOrder = (direction: "up" | "down"): void => {
const contentCopy = [...content];
if (direction === "up" && index - 1 >= 0) {
const temp = contentCopy[index - 1];
contentCopy[index - 1] = contentCopy[index];
contentCopy[index] = temp;
} else if (direction === "down" && index + 1 < content.length) {
const temp = contentCopy[index + 1];
contentCopy[index + 1] = contentCopy[index];
contentCopy[index] = temp;
}
setContent(contentCopy);
};

const deleteBlock = (): void => {
const contentCopy = [...content];
contentCopy.splice(index, 1);
setContent(contentCopy);
};

const handleTextChange = (
event: React.ChangeEvent<HTMLInputElement>
): void => {
const contentCopy = [...content];
contentCopy[index].value = event.target.value;
setContent(contentCopy);
};

const handleCodeChange = (code: string): void => {
const contentCopy = [...content];
contentCopy[index].value = code;
setContent(contentCopy);
display: content.type === "code" ? "block" : "none"
};

return (
Expand All @@ -161,49 +133,49 @@ const StepContent: React.FC<StepContentProps> = (props): JSX.Element => {
<ContentBlockInnerWrapper>
<Button
backgroundColor={
value.type === "text" ? "rgba(256, 256, 256, 0.2)" : "none"
content.type === "text" ? "rgba(256, 256, 256, 0.2)" : "none"
}
submitFunction={(): void => {
changeType("text");
toggleBlockType("text", index);
}}
text="Text"
/>
<Button
backgroundColor={
value.type === "code" ? "rgba(256, 256, 256, 0.2)" : "none"
content.type === "code" ? "rgba(256, 256, 256, 0.2)" : "none"
}
submitFunction={(): void => {
changeType("code");
toggleBlockType("code", index);
}}
text="Code"
/>
<UpDownContainer>
<Arrow
icon={chevronUp}
onClick={(): void => {
changeOrder("up");
changeOrder("up", index);
}}
/>
<Arrow
icon={chevronDown}
onClick={(): void => {
changeOrder("down");
changeOrder("down", index);
}}
/>
</UpDownContainer>
<TextInput
value={content[index].value}
value={content.value}
style={{
display: content[index].type === "text" ? "block" : "none"
display: content.type === "text" ? "block" : "none"
}}
type="text"
placeholder="Type text here..."
onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
handleTextChange(event);
changeHandler(event, index);
}}
/>
<AceEditor
value={content[index].value}
value={content.value}
style={codeInputStyle}
fontSize="16px"
mode="python"
Expand All @@ -216,14 +188,14 @@ const StepContent: React.FC<StepContentProps> = (props): JSX.Element => {
tabSize: 4
}}
onChange={(code: string): void => {
handleCodeChange(code);
changeHandler(code, index);
}}
/>
</ContentBlockInnerWrapper>
<DeleteBlock
visible={hovering === index ? "flex" : "none"}
onClick={(): void => {
deleteBlock();
deleteBlock(index);
}}
>
<TrashIcon icon={bxTrashAlt} />
Expand Down

0 comments on commit 439d5b6

Please sign in to comment.