Fixed creation of users + better frontend handling of permissions
This commit is contained in:
222
frontend/components/editor/extensions/marks.ts
Normal file
222
frontend/components/editor/extensions/marks.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
// extensions/customMarks.ts
|
||||
import {
|
||||
Mark,
|
||||
markInputRule,
|
||||
markPasteRule,
|
||||
mergeAttributes,
|
||||
} from "@tiptap/core";
|
||||
|
||||
// Define available size options
|
||||
const sizeOptions = {
|
||||
xs: "text-xs",
|
||||
sm: "text-sm",
|
||||
base: "text-base",
|
||||
lg: "text-lg",
|
||||
xl: "text-xl",
|
||||
} as const;
|
||||
|
||||
export type SizeOption = keyof typeof sizeOptions;
|
||||
|
||||
export interface FontSizeOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
}
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
fontSize: {
|
||||
setFontSize: (attributes: { size: SizeOption }) => ReturnType;
|
||||
toggleFontSize: (attributes: { size: SizeOption }) => ReturnType;
|
||||
unsetFontSize: () => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const fontSizeInputRegex = /(?:^|\s)(~((?:[^~]+))~)$/;
|
||||
export const fontSizePasteRegex = /(?:^|\s)(~((?:[^~]+))~)/g;
|
||||
|
||||
export const FontSize = Mark.create<FontSizeOptions>({
|
||||
name: "fontSize",
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
HTMLAttributes: {},
|
||||
};
|
||||
},
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
size: {
|
||||
default: "base",
|
||||
parseHTML: (element: HTMLElement) => {
|
||||
const sizeClass = Object.entries(sizeOptions).find(
|
||||
([, className]) =>
|
||||
element.classList.contains(className),
|
||||
)?.[0];
|
||||
return sizeClass || "base";
|
||||
},
|
||||
renderHTML: (attributes: { size: SizeOption }) => ({
|
||||
class: sizeOptions[attributes.size],
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: "span",
|
||||
getAttrs: (node: HTMLElement) => {
|
||||
const hasSizeClass = Object.values(sizeOptions).some(
|
||||
(className) => node.classList.contains(className),
|
||||
);
|
||||
return hasSizeClass ? {} : null;
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return [
|
||||
"span",
|
||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
||||
0,
|
||||
];
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
return {
|
||||
setFontSize:
|
||||
(attributes: { size: SizeOption }) =>
|
||||
({ commands }) => {
|
||||
return commands.setMark(this.name, attributes);
|
||||
},
|
||||
toggleFontSize:
|
||||
(attributes: { size: SizeOption }) =>
|
||||
({ commands }) => {
|
||||
return commands.toggleMark(this.name, attributes);
|
||||
},
|
||||
unsetFontSize:
|
||||
() =>
|
||||
({ commands }) => {
|
||||
return commands.unsetMark(this.name);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
"Mod-s": () => this.editor.commands.toggleFontSize({ size: "sm" }),
|
||||
};
|
||||
},
|
||||
|
||||
addInputRules() {
|
||||
return [
|
||||
markInputRule({
|
||||
find: fontSizeInputRegex,
|
||||
type: this.type,
|
||||
getAttributes: { size: "sm" }, // Default size for input rule
|
||||
}),
|
||||
];
|
||||
},
|
||||
|
||||
addPasteRules() {
|
||||
return [
|
||||
markPasteRule({
|
||||
find: fontSizePasteRegex,
|
||||
type: this.type,
|
||||
getAttributes: { size: "sm" }, // Default size for paste rule
|
||||
}),
|
||||
];
|
||||
},
|
||||
});
|
||||
|
||||
// TextColor remains unchanged
|
||||
export interface TextColorOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
}
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
textColor: {
|
||||
setTextColor: (attributes: { color: string }) => ReturnType;
|
||||
toggleTextColor: (attributes: { color: string }) => ReturnType;
|
||||
unsetTextColor: () => ReturnType;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const TextColor = Mark.create<TextColorOptions>({
|
||||
name: "textColor",
|
||||
addOptions() {
|
||||
return {
|
||||
HTMLAttributes: {},
|
||||
};
|
||||
},
|
||||
addAttributes() {
|
||||
return {
|
||||
color: {
|
||||
default: null,
|
||||
parseHTML: (element: HTMLElement) => {
|
||||
const colorClass = Array.from(element.classList).find(
|
||||
(cls) => cls.startsWith("text-"),
|
||||
);
|
||||
return colorClass ? colorClass.replace("text-", "") : null;
|
||||
},
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.color) return {};
|
||||
// Use !important to override prose styles
|
||||
return {
|
||||
class: `text-${attributes.color} !text-${attributes.color}`,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: "span",
|
||||
getAttrs: (node: HTMLElement) => {
|
||||
const colorClass = Array.from(node.classList).find((cls) =>
|
||||
cls.startsWith("text-"),
|
||||
);
|
||||
return colorClass
|
||||
? { color: colorClass.replace("text-", "") }
|
||||
: null;
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return [
|
||||
"span",
|
||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
|
||||
0,
|
||||
];
|
||||
},
|
||||
addCommands() {
|
||||
return {
|
||||
setTextColor:
|
||||
(attributes: { color: string }) =>
|
||||
({ commands }) => {
|
||||
return commands.setMark(this.name, attributes);
|
||||
},
|
||||
toggleTextColor:
|
||||
(attributes: { color: string }) =>
|
||||
({ commands }) => {
|
||||
return commands.toggleMark(this.name, attributes);
|
||||
},
|
||||
unsetTextColor:
|
||||
() =>
|
||||
({ commands }) => {
|
||||
return commands.unsetMark(this.name);
|
||||
},
|
||||
};
|
||||
},
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
"Mod-Shift-c": () =>
|
||||
this.editor.commands.toggleTextColor({ color: "gray-500" }),
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user