134 lines
3.0 KiB
TypeScript
134 lines
3.0 KiB
TypeScript
import { v4 as uuidv4 } from "uuid";
|
|
|
|
export type ILine = {
|
|
id: string;
|
|
text: string;
|
|
};
|
|
|
|
export type IBlock = {
|
|
id: string;
|
|
tag: string;
|
|
locked: boolean;
|
|
lines: ILine[];
|
|
};
|
|
|
|
type EditorState = IBlock[];
|
|
|
|
export type Action =
|
|
| { type: "add_block" }
|
|
| { type: "copy" }
|
|
| { type: "delete_block", blockId: string }
|
|
| { type: "add_line", blockId: string }
|
|
| { type: "delete_line", blockId: string }
|
|
| { type: "update_line_text"; blockId: string; lineId: string; text: string }
|
|
| { type: "update_tag"; blockId: string; tag: string }
|
|
| { type: "toggle_lock", blockId: string };
|
|
|
|
export function editorReducer(state: EditorState, action: Action): EditorState {
|
|
switch (action.type) {
|
|
case "add_block":
|
|
return [
|
|
...state,
|
|
{
|
|
id: uuidv4(),
|
|
tag: "",
|
|
locked: false,
|
|
lines: Array.from({ length: 4 }, () => ({
|
|
id: uuidv4(),
|
|
text: "",
|
|
})),
|
|
}
|
|
];
|
|
|
|
case "copy":
|
|
let copyText = "";
|
|
|
|
state.forEach((block) => {
|
|
if (block.tag !== "") {
|
|
copyText += `[${block.tag}]\n`;
|
|
}
|
|
|
|
block.lines.forEach((line) => copyText += line.text + "\n")
|
|
copyText += "\n";
|
|
});
|
|
|
|
navigator.clipboard.writeText(copyText);
|
|
return state;
|
|
|
|
case "delete_block":
|
|
return state.filter((block) => block.id !== action.blockId);
|
|
|
|
case "add_line":
|
|
return state.map((block) => {
|
|
if (block.id === action.blockId) {
|
|
return {
|
|
...block,
|
|
lines: [...block.lines, { id: uuidv4(), text: "" }],
|
|
};
|
|
} else {
|
|
return block;
|
|
}
|
|
});
|
|
|
|
case "delete_line":
|
|
return state.map((block) => {
|
|
if (block.id === action.blockId && block.lines.length > 0) {
|
|
return {
|
|
...block,
|
|
lines: block.lines.slice(0, -1),
|
|
};
|
|
} else {
|
|
return block;
|
|
}
|
|
});
|
|
|
|
case "update_line_text":
|
|
return state.map((block) => {
|
|
if (block.id === action.blockId) {
|
|
return {
|
|
...block,
|
|
lines: block.lines.map((line) => {
|
|
if (line.id === action.lineId) {
|
|
return {
|
|
...line,
|
|
text: action.text,
|
|
};
|
|
} else {
|
|
return line;
|
|
}
|
|
}),
|
|
};
|
|
} else {
|
|
return block;
|
|
}
|
|
});
|
|
|
|
case "update_tag":
|
|
return state.map((block) => {
|
|
if (block.id === action.blockId) {
|
|
return {
|
|
...block,
|
|
tag: action.tag,
|
|
};
|
|
} else {
|
|
return block;
|
|
}
|
|
});
|
|
|
|
case "toggle_lock":
|
|
return state.map((block) => {
|
|
if (block.id === action.blockId) {
|
|
return {
|
|
...block,
|
|
locked: !block.locked,
|
|
};
|
|
} else {
|
|
return block;
|
|
}
|
|
});
|
|
|
|
default:
|
|
return state;
|
|
}
|
|
}
|