mirror of https://github.com/usememos/memos
refactor: remove MemoContentContext and integrate MemoViewContext
- Deleted MemoContentContext and its associated types. - Updated Tag and TaskListItem components to use MemoViewContext instead. - Refactored MemoContent component to eliminate context provider and directly use derived values. - Simplified MemoViewContext to only include essential data. - Enhanced error handling in various components by introducing a centralized error handling utility. - Improved type safety across components and hooks by refining TypeScript definitions. - Updated remark plugins to enhance tag parsing and preserve node types.pull/5405/head
parent
ab650ac86d
commit
85f4fc7a75
@ -1,14 +0,0 @@
|
||||
import { createContext } from "react";
|
||||
|
||||
export interface MemoContentContextType {
|
||||
memoName?: string;
|
||||
readonly: boolean;
|
||||
disableFilter?: boolean;
|
||||
parentPage?: string;
|
||||
containerRef?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export const MemoContentContext = createContext<MemoContentContextType>({
|
||||
readonly: true,
|
||||
disableFilter: false,
|
||||
});
|
||||
@ -0,0 +1,38 @@
|
||||
export function getErrorMessage(error: unknown, fallback = "Unknown error"): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
if (typeof error === "string") {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error && typeof error === "object" && "message" in error) {
|
||||
return String(error.message);
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export function handleError(
|
||||
error: unknown,
|
||||
toast: (message: string) => void,
|
||||
options?: {
|
||||
context?: string;
|
||||
fallbackMessage?: string;
|
||||
onError?: (error: unknown) => void;
|
||||
},
|
||||
): void {
|
||||
const contextPrefix = options?.context ? `${options.context}: ` : "";
|
||||
const fallback = options?.fallbackMessage;
|
||||
|
||||
const errorMessage = options?.context ? `${contextPrefix}${getErrorMessage(error, fallback)}` : getErrorMessage(error, fallback);
|
||||
|
||||
console.error(error);
|
||||
toast(errorMessage);
|
||||
options?.onError?.(error);
|
||||
}
|
||||
|
||||
export function isError(value: unknown): value is Error {
|
||||
return value instanceof Error;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
export type TableData = Record<string, unknown>;
|
||||
|
||||
export interface ApiError {
|
||||
message: string;
|
||||
code?: string;
|
||||
details?: unknown;
|
||||
}
|
||||
|
||||
export function isApiError(error: unknown): error is ApiError {
|
||||
return typeof error === "object" && error !== null && "message" in error && typeof (error as ApiError).message === "string";
|
||||
}
|
||||
|
||||
export type ToastFunction = (message: string) => void | Promise<void>;
|
||||
@ -0,0 +1,44 @@
|
||||
import type { Data, Element as HastElement } from "hast";
|
||||
|
||||
export interface TagNode {
|
||||
type: "tagNode";
|
||||
value: string;
|
||||
data: TagNodeData;
|
||||
}
|
||||
|
||||
export interface TagNodeData {
|
||||
hName: "span";
|
||||
hProperties: TagNodeProperties;
|
||||
hChildren: Array<{ type: "text"; value: string }>;
|
||||
}
|
||||
|
||||
export interface TagNodeProperties {
|
||||
className: string;
|
||||
"data-tag": string;
|
||||
}
|
||||
|
||||
export interface ExtendedData extends Data {
|
||||
mdastType?: string;
|
||||
}
|
||||
|
||||
export function hasExtendedData(node: unknown): node is { data: ExtendedData } {
|
||||
return typeof node === "object" && node !== null && "data" in node && typeof (node as { data: unknown }).data === "object";
|
||||
}
|
||||
|
||||
export function isTagElement(node: HastElement): boolean {
|
||||
if (hasExtendedData(node) && node.data.mdastType === "tagNode") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const className = node.properties?.className;
|
||||
if (Array.isArray(className) && className.includes("tag")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTaskListItemElement(node: HastElement): boolean {
|
||||
const type = node.properties?.type;
|
||||
return typeof type === "string" && type === "checkbox";
|
||||
}
|
||||
@ -1,24 +1,22 @@
|
||||
import type { Root } from "mdast";
|
||||
import { visit } from "unist-util-visit";
|
||||
import type { ExtendedData } from "@/types/markdown";
|
||||
|
||||
const STANDARD_NODE_TYPES = new Set(["text", "root", "paragraph", "heading", "list", "listItem"]);
|
||||
|
||||
// Remark plugin to preserve original mdast node types in the data field
|
||||
export const remarkPreserveType = () => {
|
||||
return (tree: Root) => {
|
||||
visit(tree, (node: any) => {
|
||||
// Skip text nodes and standard element types
|
||||
if (node.type === "text" || node.type === "root") {
|
||||
visit(tree, (node) => {
|
||||
if (STANDARD_NODE_TYPES.has(node.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Preserve the original mdast type in data
|
||||
if (!node.data) {
|
||||
node.data = {};
|
||||
}
|
||||
|
||||
// Store original type for custom node types
|
||||
if (node.type !== "paragraph" && node.type !== "heading" && node.type !== "list" && node.type !== "listItem") {
|
||||
node.data.mdastType = node.type;
|
||||
}
|
||||
const data = node.data as ExtendedData;
|
||||
data.mdastType = node.type;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue