mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
Closes: [BS-2909](https://linear.app/affine-design/issue/BS-2909/新增highlighter) ### What's Changed! Currently the highlighter tool is very similar to brush, but for the future, it's a standalone module. * Added `Highlighter` element model * Added `Highlighter` tool * Added `Highlighter` entry to the global toolbar
219 lines
5.5 KiB
TypeScript
219 lines
5.5 KiB
TypeScript
import {
|
|
ColorSchema,
|
|
ConnectorMode,
|
|
DEFAULT_CONNECTOR_MODE,
|
|
DEFAULT_FRONT_ENDPOINT_STYLE,
|
|
DEFAULT_HIGHLIGHTER_LINE_WIDTH,
|
|
DEFAULT_REAR_ENDPOINT_STYLE,
|
|
DEFAULT_ROUGHNESS,
|
|
DefaultTheme,
|
|
EdgelessTextZodSchema,
|
|
FontFamily,
|
|
FontFamilySchema,
|
|
FontStyle,
|
|
FontStyleSchema,
|
|
FontWeight,
|
|
FontWeightSchema,
|
|
FrameZodSchema,
|
|
HIGHLIGHTER_LINE_WIDTHS,
|
|
LayoutType,
|
|
LineWidth,
|
|
MindmapStyle,
|
|
NoteZodSchema,
|
|
PointStyle,
|
|
ShapeStyle,
|
|
StrokeStyle,
|
|
StrokeStyleSchema,
|
|
TextAlign,
|
|
TextAlignSchema,
|
|
TextVerticalAlign,
|
|
} from '@blocksuite/affine-model';
|
|
import {
|
|
z,
|
|
ZodDefault,
|
|
ZodIntersection,
|
|
ZodObject,
|
|
type ZodTypeAny,
|
|
ZodUnion,
|
|
} from 'zod';
|
|
|
|
const ConnectorEndpointSchema = z.nativeEnum(PointStyle);
|
|
const LineWidthSchema = z.nativeEnum(LineWidth);
|
|
const ShapeStyleSchema = z.nativeEnum(ShapeStyle);
|
|
const TextVerticalAlignSchema = z.nativeEnum(TextVerticalAlign);
|
|
const ConnectorModeSchema = z.nativeEnum(ConnectorMode);
|
|
const LayoutTypeSchema = z.nativeEnum(LayoutType);
|
|
const MindmapStyleSchema = z.nativeEnum(MindmapStyle);
|
|
|
|
export const ConnectorSchema = z
|
|
.object({
|
|
frontEndpointStyle: ConnectorEndpointSchema,
|
|
rearEndpointStyle: ConnectorEndpointSchema,
|
|
stroke: ColorSchema,
|
|
strokeStyle: StrokeStyleSchema,
|
|
strokeWidth: LineWidthSchema,
|
|
rough: z.boolean(),
|
|
mode: ConnectorModeSchema,
|
|
labelStyle: z.object({
|
|
color: ColorSchema,
|
|
fontSize: z.number(),
|
|
fontFamily: FontFamilySchema,
|
|
fontWeight: FontWeightSchema,
|
|
fontStyle: FontStyleSchema,
|
|
textAlign: TextAlignSchema,
|
|
}),
|
|
})
|
|
.default({
|
|
frontEndpointStyle: DEFAULT_FRONT_ENDPOINT_STYLE,
|
|
rearEndpointStyle: DEFAULT_REAR_ENDPOINT_STYLE,
|
|
stroke: DefaultTheme.connectorColor,
|
|
strokeStyle: StrokeStyle.Solid,
|
|
strokeWidth: LineWidth.Two,
|
|
rough: false,
|
|
mode: DEFAULT_CONNECTOR_MODE,
|
|
labelStyle: {
|
|
color: DefaultTheme.black,
|
|
fontSize: 16,
|
|
fontFamily: FontFamily.Inter,
|
|
fontWeight: FontWeight.Regular,
|
|
fontStyle: FontStyle.Normal,
|
|
textAlign: TextAlign.Center,
|
|
},
|
|
});
|
|
|
|
export const BrushSchema = z
|
|
.object({
|
|
color: ColorSchema,
|
|
lineWidth: LineWidthSchema,
|
|
})
|
|
.default({
|
|
color: DefaultTheme.black,
|
|
lineWidth: LineWidth.Four,
|
|
});
|
|
|
|
export const HighlighterSchema = z
|
|
.object({
|
|
color: ColorSchema,
|
|
lineWidth: z
|
|
.number()
|
|
.int()
|
|
.refine(value => HIGHLIGHTER_LINE_WIDTHS.includes(value)),
|
|
})
|
|
.default({
|
|
color: DefaultTheme.hightlighterColor,
|
|
lineWidth: DEFAULT_HIGHLIGHTER_LINE_WIDTH,
|
|
});
|
|
|
|
const DEFAULT_SHAPE = {
|
|
color: DefaultTheme.shapeTextColor,
|
|
fillColor: DefaultTheme.shapeFillColor,
|
|
strokeColor: DefaultTheme.shapeStrokeColor,
|
|
strokeStyle: StrokeStyle.Solid,
|
|
strokeWidth: LineWidth.Two,
|
|
shapeStyle: ShapeStyle.General,
|
|
filled: true,
|
|
radius: 0,
|
|
fontSize: 20,
|
|
fontFamily: FontFamily.Inter,
|
|
fontWeight: FontWeight.Regular,
|
|
fontStyle: FontStyle.Normal,
|
|
textAlign: TextAlign.Center,
|
|
roughness: DEFAULT_ROUGHNESS,
|
|
};
|
|
|
|
const ShapeObject = {
|
|
color: ColorSchema,
|
|
fillColor: ColorSchema,
|
|
strokeColor: ColorSchema,
|
|
strokeStyle: StrokeStyleSchema,
|
|
strokeWidth: z.number(),
|
|
shapeStyle: ShapeStyleSchema,
|
|
filled: z.boolean(),
|
|
radius: z.number(),
|
|
fontSize: z.number(),
|
|
fontFamily: FontFamilySchema,
|
|
fontWeight: FontWeightSchema,
|
|
fontStyle: FontStyleSchema,
|
|
textAlign: TextAlignSchema,
|
|
textHorizontalAlign: TextAlignSchema.optional(),
|
|
textVerticalAlign: TextVerticalAlignSchema.optional(),
|
|
roughness: z.number(),
|
|
};
|
|
|
|
export const ShapeSchema = z.object(ShapeObject).default(DEFAULT_SHAPE);
|
|
|
|
export const RoundedShapeSchema = z
|
|
.object(ShapeObject)
|
|
.default({ ...DEFAULT_SHAPE, radius: 0.1 });
|
|
|
|
export const TextSchema = z
|
|
.object({
|
|
color: ColorSchema,
|
|
fontSize: z.number(),
|
|
fontFamily: FontFamilySchema,
|
|
fontWeight: FontWeightSchema,
|
|
fontStyle: FontStyleSchema,
|
|
textAlign: TextAlignSchema,
|
|
})
|
|
.default({
|
|
color: DefaultTheme.textColor,
|
|
fontSize: 24,
|
|
fontFamily: FontFamily.Inter,
|
|
fontWeight: FontWeight.Regular,
|
|
fontStyle: FontStyle.Normal,
|
|
textAlign: TextAlign.Left,
|
|
});
|
|
|
|
export const MindmapSchema = z
|
|
.object({
|
|
layoutType: LayoutTypeSchema,
|
|
style: MindmapStyleSchema,
|
|
})
|
|
.default({
|
|
layoutType: LayoutType.RIGHT,
|
|
style: MindmapStyle.ONE,
|
|
});
|
|
|
|
export const NodePropsSchema = z.object({
|
|
connector: ConnectorSchema,
|
|
brush: BrushSchema,
|
|
highlighter: HighlighterSchema,
|
|
text: TextSchema,
|
|
mindmap: MindmapSchema,
|
|
'affine:edgeless-text': EdgelessTextZodSchema,
|
|
'affine:note': NoteZodSchema,
|
|
'affine:frame': FrameZodSchema,
|
|
// shapes
|
|
'shape:diamond': ShapeSchema,
|
|
'shape:ellipse': ShapeSchema,
|
|
'shape:rect': ShapeSchema,
|
|
'shape:triangle': ShapeSchema,
|
|
'shape:roundedRect': RoundedShapeSchema,
|
|
});
|
|
|
|
export type NodeProps = z.infer<typeof NodePropsSchema>;
|
|
|
|
export function makeDeepOptional(schema: ZodTypeAny): ZodTypeAny {
|
|
if (schema instanceof ZodDefault) {
|
|
return makeDeepOptional(schema._def.innerType);
|
|
}
|
|
if (schema instanceof ZodObject) {
|
|
const shape = schema.shape;
|
|
const deepOptionalShape = Object.fromEntries(
|
|
Object.entries(shape).map(([key, value]) => {
|
|
return [key, makeDeepOptional(value as ZodTypeAny)];
|
|
})
|
|
);
|
|
return z.object(deepOptionalShape).optional();
|
|
} else if (schema instanceof ZodUnion) {
|
|
return schema.or(z.undefined());
|
|
} else if (schema instanceof ZodIntersection) {
|
|
return z.intersection(
|
|
makeDeepOptional(schema._def.left),
|
|
makeDeepOptional(schema._def.right)
|
|
);
|
|
} else {
|
|
return schema.optional();
|
|
}
|
|
}
|