Notra/src/lib/editorReducer.ts

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;
}
}