mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-22 22:49:45 +01:00
chore: publish
This commit is contained in:
@@ -43,7 +43,7 @@ function CodeblockComponent(props) {
|
||||
core_1.refractor.register(syntax);
|
||||
const preventUpdate = language === languageDefinition.filename;
|
||||
updateAttributes({
|
||||
language: languageDefinition.filename,
|
||||
language: languageDefinition.filename
|
||||
}, { preventUpdate, addToHistory: false });
|
||||
});
|
||||
})();
|
||||
@@ -51,13 +51,13 @@ function CodeblockComponent(props) {
|
||||
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: {
|
||||
flexDirection: "column",
|
||||
borderRadius: "default",
|
||||
overflow: "hidden",
|
||||
} }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Text, { ref: forwardRef, as: "pre", sx: {
|
||||
overflow: "hidden"
|
||||
} }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Text, { ref: forwardRef, as: "pre", autoCorrect: "off", autoCapitalize: "none", sx: {
|
||||
"div, span.token, span.line-number-widget, span.line-number::before": {
|
||||
fontFamily: "monospace",
|
||||
fontSize: "code",
|
||||
whiteSpace: "pre !important",
|
||||
tabSize: 1,
|
||||
tabSize: 1
|
||||
},
|
||||
position: "relative",
|
||||
lineHeight: "20px",
|
||||
@@ -67,24 +67,24 @@ function CodeblockComponent(props) {
|
||||
display: "flex",
|
||||
px: 2,
|
||||
pt: 2,
|
||||
pb: 1,
|
||||
pb: 1
|
||||
}, spellCheck: false }), (0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ ref: toolbarRef, contentEditable: false, sx: {
|
||||
bg: "codeBg",
|
||||
alignItems: "center",
|
||||
justifyContent: "end",
|
||||
borderTop: "1px solid var(--codeBorder)",
|
||||
justifyContent: "flex-end",
|
||||
borderTop: "1px solid var(--codeBorder)"
|
||||
} }, { children: [caretPosition ? ((0, jsx_runtime_1.jsxs)(rebass_1.Text, Object.assign({ variant: "subBody", sx: { mr: 2, color: "codeFg" } }, { children: ["Line ", caretPosition.line, ", Column ", caretPosition.column, " ", caretPosition.selected
|
||||
? `(${caretPosition.selected} selected)`
|
||||
: ""] }))) : null, (0, jsx_runtime_1.jsx)(button_1.Button, Object.assign({ variant: "icon", sx: { p: 1, mr: 1, ":hover": { bg: "codeSelection" } }, title: "Toggle indentation mode", onClick: () => {
|
||||
editor.commands.changeCodeBlockIndentation({
|
||||
type: indentType === "space" ? "tab" : "space",
|
||||
amount: indentLength,
|
||||
amount: indentLength
|
||||
});
|
||||
} }, { children: (0, jsx_runtime_1.jsxs)(rebass_1.Text, Object.assign({ variant: "subBody", sx: { color: "codeFg" } }, { children: [indentType === "space" ? "Spaces" : "Tabs", ": ", indentLength] })) })), (0, jsx_runtime_1.jsx)(button_1.Button, Object.assign({ variant: "icon", sx: {
|
||||
p: 1,
|
||||
mr: 1,
|
||||
bg: isOpen ? "codeSelection" : "transparent",
|
||||
":hover": { bg: "codeSelection" },
|
||||
":hover": { bg: "codeSelection" }
|
||||
}, onClick: () => {
|
||||
setIsOpen(true);
|
||||
}, title: "Change language" }, { children: (0, jsx_runtime_1.jsx)(rebass_1.Text, Object.assign({ variant: "subBody", spellCheck: false, sx: { color: "codeFg" } }, { children: (languageDefinition === null || languageDefinition === void 0 ? void 0 : languageDefinition.title) || "Plaintext" })) }))] }))] })), (0, jsx_runtime_1.jsx)(responsive_1.ResponsivePresenter, Object.assign({ isOpen: isOpen, onClose: () => {
|
||||
@@ -101,7 +101,7 @@ function CodeblockComponent(props) {
|
||||
align: "end",
|
||||
isTargetAbsolute: true,
|
||||
location: "top",
|
||||
yOffset: 5,
|
||||
yOffset: 5
|
||||
}, title: "Change code block language" }, { children: (0, jsx_runtime_1.jsx)(LanguageSelector, { selectedLanguage: (languageDefinition === null || languageDefinition === void 0 ? void 0 : languageDefinition.filename) || "Plaintext", onLanguageSelected: (language) => {
|
||||
updateAttributes({ language }, { addToHistory: true, preventUpdate: false });
|
||||
setIsOpen(false);
|
||||
@@ -116,7 +116,7 @@ function LanguageSelector(props) {
|
||||
height: 200,
|
||||
width: ["auto", 300],
|
||||
overflowY: "auto",
|
||||
bg: "background",
|
||||
bg: "background"
|
||||
} }, { children: [(0, jsx_runtime_1.jsx)(forms_1.Input, { onFocus: () => {
|
||||
console.log("EHLLO!");
|
||||
}, autoFocus: true, placeholder: "Search languages", sx: {
|
||||
@@ -126,7 +126,7 @@ function LanguageSelector(props) {
|
||||
bg: "background",
|
||||
mx: 2,
|
||||
p: "7px",
|
||||
zIndex: 999,
|
||||
zIndex: 999
|
||||
}, onChange: (e) => {
|
||||
if (!e.target.value)
|
||||
return setLanguages(languages_json_1.default);
|
||||
@@ -139,12 +139,12 @@ function LanguageSelector(props) {
|
||||
} }), (0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: {
|
||||
flexDirection: "column",
|
||||
pt: 1,
|
||||
mt: 1,
|
||||
mt: 1
|
||||
} }, { children: languages.map((lang) => ((0, jsx_runtime_1.jsxs)(button_1.Button, Object.assign({ variant: "menuitem", sx: {
|
||||
textAlign: "left",
|
||||
py: 1,
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
alignItems: "center"
|
||||
}, onClick: () => onLanguageSelected(lang.filename) }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Text, Object.assign({ variant: "body" }, { children: lang.title })), selectedLanguage === lang.filename ? ((0, jsx_runtime_1.jsx)(icon_1.Icon, { path: icons_1.Icons.check, size: "small" })) : lang.alias ? ((0, jsx_runtime_1.jsx)(rebass_1.Text, Object.assign({ variant: "subBody", sx: { fontSize: "10px" } }, { children: lang.alias.slice(0, 3).join(", ") }))) : null] }), lang.title))) }))] })) })));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Plugin } from "prosemirror-state";
|
||||
import { DecorationSet } from "prosemirror-view";
|
||||
import { AddMarkStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from "prosemirror-transform";
|
||||
export declare type MergedStep = AddMarkStep | RemoveMarkStep | ReplaceAroundStep | ReplaceStep;
|
||||
export declare function HighlighterPlugin({ name, defaultLanguage, }: {
|
||||
export declare function HighlighterPlugin({ name, defaultLanguage }: {
|
||||
name: string;
|
||||
defaultLanguage: string | null | undefined;
|
||||
}): Plugin<DecorationSet>;
|
||||
|
||||
@@ -35,16 +35,17 @@ function getLineDecoration(from, line, total, isActive) {
|
||||
const attributes = {
|
||||
class: `line-number ${isActive ? "active" : ""}`,
|
||||
"data-line": String(line).padEnd(maxLength, " "),
|
||||
autocapitalize: "none"
|
||||
};
|
||||
const spec = {
|
||||
line: line,
|
||||
active: isActive,
|
||||
total,
|
||||
from,
|
||||
from
|
||||
};
|
||||
return prosemirror_view_1.Decoration.inline(from, from + 1, attributes, spec);
|
||||
}
|
||||
function getDecorations({ doc, name, defaultLanguage, caretPosition, }) {
|
||||
function getDecorations({ doc, name, defaultLanguage, caretPosition }) {
|
||||
const decorations = [];
|
||||
const languages = core_2.refractor.listLanguages();
|
||||
(0, core_1.findChildren)(doc, (node) => node.type.name === name).forEach((block) => {
|
||||
@@ -67,7 +68,7 @@ function getDecorations({ doc, name, defaultLanguage, caretPosition, }) {
|
||||
const to = from + node.text.length;
|
||||
if (node.classes.length) {
|
||||
const decoration = prosemirror_view_1.Decoration.inline(from, to, {
|
||||
class: node.classes.join(" "),
|
||||
class: node.classes.join(" ")
|
||||
});
|
||||
decorations.push(decoration);
|
||||
}
|
||||
@@ -76,7 +77,7 @@ function getDecorations({ doc, name, defaultLanguage, caretPosition, }) {
|
||||
});
|
||||
return prosemirror_view_1.DecorationSet.create(doc, decorations);
|
||||
}
|
||||
function HighlighterPlugin({ name, defaultLanguage, }) {
|
||||
function HighlighterPlugin({ name, defaultLanguage }) {
|
||||
const key = new prosemirror_state_1.PluginKey("highlighter");
|
||||
return new prosemirror_state_1.Plugin({
|
||||
key,
|
||||
@@ -85,7 +86,7 @@ function HighlighterPlugin({ name, defaultLanguage, }) {
|
||||
return getDecorations({
|
||||
doc: state.doc,
|
||||
name,
|
||||
defaultLanguage,
|
||||
defaultLanguage
|
||||
});
|
||||
},
|
||||
apply: (transaction, decorationSet, oldState, newState) => {
|
||||
@@ -120,17 +121,17 @@ function HighlighterPlugin({ name, defaultLanguage, }) {
|
||||
doc: transaction.doc,
|
||||
name,
|
||||
defaultLanguage,
|
||||
caretPosition: position,
|
||||
caretPosition: position
|
||||
});
|
||||
}
|
||||
decorationSet = getActiveLineDecorations(transaction.doc, decorationSet, position);
|
||||
return decorationSet.map(transaction.mapping, transaction.doc);
|
||||
},
|
||||
}
|
||||
},
|
||||
props: {
|
||||
decorations(state) {
|
||||
return key.getState(state);
|
||||
},
|
||||
}
|
||||
},
|
||||
appendTransaction: (transactions, prevState, nextState) => {
|
||||
const tr = nextState.tr;
|
||||
@@ -157,7 +158,7 @@ function HighlighterPlugin({ name, defaultLanguage, }) {
|
||||
}
|
||||
});
|
||||
return modified ? tr : null;
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.HighlighterPlugin = HighlighterPlugin;
|
||||
@@ -182,7 +183,7 @@ function getActiveLineDecorations(doc, decorations, position) {
|
||||
decorations = decorations.remove(lineDecorations);
|
||||
const newDecorations = [];
|
||||
for (const decoration of cloned) {
|
||||
const { from, spec: { line, total }, } = decoration;
|
||||
const { from, spec: { line, total } } = decoration;
|
||||
const isActive = line === (position === null || position === void 0 ? void 0 : position.line);
|
||||
const newDecoration = getLineDecoration(from, line, (position === null || position === void 0 ? void 0 : position.total) || total, isActive);
|
||||
newDecorations.push(newDecoration);
|
||||
|
||||
@@ -7,29 +7,39 @@ const re_resizable_1 = require("re-resizable");
|
||||
const react_1 = require("react");
|
||||
const responsive_1 = require("../../components/responsive");
|
||||
const toolbargroup_1 = require("../../toolbar/components/toolbargroup");
|
||||
const toolbar_1 = require("../../toolbar");
|
||||
function EmbedComponent(props) {
|
||||
const { editor, updateAttributes, selected, node } = props;
|
||||
const embedRef = (0, react_1.useRef)();
|
||||
const { src, width, height, align } = node.attrs;
|
||||
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(rebass_1.Box, Object.assign({ sx: {
|
||||
display: "flex",
|
||||
justifyContent: align === "center" ? "center" : align === "left" ? "start" : "end",
|
||||
justifyContent: align === "center" ? "center" : align === "left" ? "start" : "end"
|
||||
} }, { children: (0, jsx_runtime_1.jsxs)(re_resizable_1.Resizable, Object.assign({ enable: {
|
||||
bottom: editor.isEditable,
|
||||
left: editor.isEditable,
|
||||
right: editor.isEditable,
|
||||
top: editor.isEditable,
|
||||
bottomLeft: editor.isEditable,
|
||||
bottomRight: editor.isEditable,
|
||||
topLeft: editor.isEditable,
|
||||
topRight: editor.isEditable,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false,
|
||||
top: false,
|
||||
bottomLeft: false,
|
||||
bottomRight: editor.isEditable && selected,
|
||||
topLeft: false,
|
||||
topRight: false
|
||||
}, size: {
|
||||
height: height || "auto",
|
||||
width: width || "auto",
|
||||
}, maxWidth: "100%", onResizeStop: (e, direction, ref, d) => {
|
||||
width: width || "auto"
|
||||
}, maxWidth: "100%", handleComponent: {
|
||||
bottomRight: ((0, jsx_runtime_1.jsx)(toolbar_1.Icon, { sx: {
|
||||
width: 25,
|
||||
height: 25,
|
||||
marginLeft: -17,
|
||||
marginTop: "3px",
|
||||
borderTopLeftRadius: "default",
|
||||
borderBottomRightRadius: "default"
|
||||
}, path: toolbar_1.Icons.resize, size: 25, color: "primary" }))
|
||||
}, onResizeStop: (e, direction, ref, d) => {
|
||||
updateAttributes({
|
||||
width: ref.clientWidth,
|
||||
height: ref.clientHeight,
|
||||
height: ref.clientHeight
|
||||
}, { addToHistory: true, preventUpdate: false });
|
||||
}, lockAspectRatio: true }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ width: "100%", sx: {
|
||||
position: "relative",
|
||||
@@ -42,27 +52,27 @@ function EmbedComponent(props) {
|
||||
borderColor: selected ? "border" : "bgSecondary",
|
||||
cursor: "pointer",
|
||||
":hover": {
|
||||
borderColor: "border",
|
||||
},
|
||||
borderColor: "border"
|
||||
}
|
||||
} }, { children: (0, jsx_runtime_1.jsx)(responsive_1.DesktopOnly, { children: selected && ((0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: { position: "relative", justifyContent: "end" } }, { children: (0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: {
|
||||
position: "absolute",
|
||||
top: -40,
|
||||
mb: 2,
|
||||
alignItems: "end",
|
||||
alignItems: "end"
|
||||
} }, { children: (0, jsx_runtime_1.jsx)(toolbargroup_1.ToolbarGroup, { editor: editor, tools: [
|
||||
"embedAlignLeft",
|
||||
"embedAlignCenter",
|
||||
"embedAlignRight",
|
||||
"embedProperties",
|
||||
"embedProperties"
|
||||
], sx: {
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
bg: "background",
|
||||
bg: "background"
|
||||
} }) })) }))) }) })), (0, jsx_runtime_1.jsx)(rebass_1.Box, Object.assign({ as: "iframe", ref: embedRef, src: src, width: "100%", height: "100%", sx: {
|
||||
border: selected
|
||||
? "2px solid var(--primary)"
|
||||
: "2px solid transparent",
|
||||
borderRadius: "default",
|
||||
borderRadius: "default"
|
||||
} }, props))] })) })) }));
|
||||
}
|
||||
exports.EmbedComponent = EmbedComponent;
|
||||
|
||||
@@ -43,54 +43,63 @@ function ImageComponent(props) {
|
||||
? "start"
|
||||
: "end",
|
||||
":hover .drag-handle, :active .drag-handle": {
|
||||
opacity: 1,
|
||||
},
|
||||
opacity: 1
|
||||
}
|
||||
} }, { children: (0, jsx_runtime_1.jsxs)(re_resizable_1.Resizable, Object.assign({ enable: {
|
||||
bottom: editor.isEditable,
|
||||
left: editor.isEditable,
|
||||
right: editor.isEditable,
|
||||
top: editor.isEditable,
|
||||
bottomLeft: editor.isEditable,
|
||||
bottomRight: editor.isEditable,
|
||||
topLeft: editor.isEditable,
|
||||
topRight: editor.isEditable,
|
||||
bottom: false,
|
||||
left: false,
|
||||
right: false,
|
||||
top: false,
|
||||
bottomLeft: false,
|
||||
bottomRight: editor.isEditable && selected,
|
||||
topLeft: false,
|
||||
topRight: false
|
||||
}, handleComponent: {
|
||||
bottomRight: ((0, jsx_runtime_1.jsx)(icon_1.Icon, { sx: {
|
||||
width: 25,
|
||||
height: 25,
|
||||
marginLeft: -17,
|
||||
marginTop: -17,
|
||||
borderTopLeftRadius: "default",
|
||||
borderBottomRightRadius: "default"
|
||||
}, path: icons_1.Icons.resize, size: 25, color: "primary" }))
|
||||
}, style: {
|
||||
position: "relative",
|
||||
float: float ? (align === "left" ? "left" : "right") : "none",
|
||||
float: float ? (align === "left" ? "left" : "right") : "none"
|
||||
}, size: {
|
||||
height: height || "auto",
|
||||
width: width || "auto",
|
||||
width: width || "auto"
|
||||
}, maxWidth: "100%", onResizeStop: (e, direction, ref, d) => {
|
||||
updateAttributes({
|
||||
width: ref.clientWidth,
|
||||
height: ref.clientHeight,
|
||||
height: ref.clientHeight
|
||||
}, { addToHistory: true, preventUpdate: false });
|
||||
}, lockAspectRatio: true }, { children: [(0, jsx_runtime_1.jsx)(responsive_1.DesktopOnly, { children: selected && ((0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: { position: "relative", justifyContent: "end" } }, { children: (0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: {
|
||||
position: "absolute",
|
||||
top: -40,
|
||||
mb: 2,
|
||||
alignItems: "end",
|
||||
alignItems: "end"
|
||||
} }, { children: (0, jsx_runtime_1.jsx)(toolbargroup_1.ToolbarGroup, { editor: editor, tools: [
|
||||
"imageAlignLeft",
|
||||
"imageAlignCenter",
|
||||
"imageAlignRight",
|
||||
"imageProperties",
|
||||
"imageProperties"
|
||||
], sx: {
|
||||
boxShadow: "menu",
|
||||
borderRadius: "default",
|
||||
bg: "background",
|
||||
bg: "background"
|
||||
} }) })) }))) }), selected && ((0, jsx_runtime_1.jsx)(icon_1.Icon, { className: "drag-handle", "data-drag-handle": true, draggable: true, path: icons_1.Icons.dragHandle, sx: {
|
||||
cursor: "grab",
|
||||
position: "absolute",
|
||||
top: 2,
|
||||
left: 2,
|
||||
zIndex: 999,
|
||||
zIndex: 999
|
||||
} })), (0, jsx_runtime_1.jsx)(rebass_1.Image, Object.assign({ "data-drag-image": true, ref: imageRef, alt: alt, src: "/placeholder.svg", title: title, width: "100%", height: "100%", sx: {
|
||||
bg: "bgSecondary",
|
||||
border: selected
|
||||
? "2px solid var(--primary)"
|
||||
: "2px solid transparent",
|
||||
borderRadius: "default",
|
||||
borderRadius: "default"
|
||||
} }, props))] })) })) }));
|
||||
}
|
||||
exports.ImageComponent = ImageComponent;
|
||||
|
||||
@@ -17,13 +17,13 @@ function OutlineListComponent(props) {
|
||||
ul: {
|
||||
display: collapsed ? "none" : "block",
|
||||
paddingInlineStart: 0,
|
||||
paddingLeft: isNested ? 1 : 0,
|
||||
paddingLeft: 0,
|
||||
marginBlockStart: isNested ? 5 : 0,
|
||||
marginBlockEnd: 0,
|
||||
marginBlockEnd: 0
|
||||
},
|
||||
li: {
|
||||
listStyleType: "none",
|
||||
},
|
||||
listStyleType: "none"
|
||||
}
|
||||
} }) }));
|
||||
}
|
||||
exports.OutlineListComponent = OutlineListComponent;
|
||||
|
||||
@@ -14,31 +14,35 @@ function OutlineListItemComponent(props) {
|
||||
const isMobile = (0, toolbarstore_1.useIsMobile)();
|
||||
const isNested = ((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.type.name) === outlinelist_1.OutlineList.name;
|
||||
const isCollapsed = isNested && ((_b = node.lastChild) === null || _b === void 0 ? void 0 : _b.attrs.collapsed);
|
||||
const onClick = () => {
|
||||
const [subList] = (0, core_1.findChildren)(node, (node) => node.type.name === outlinelist_1.OutlineList.name);
|
||||
if (!subList)
|
||||
return;
|
||||
const { pos } = subList;
|
||||
editor.commands.toggleOutlineCollapse(pos + getPos() + 1, !isCollapsed);
|
||||
};
|
||||
return ((0, jsx_runtime_1.jsxs)(rebass_1.Flex, { children: [(0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ className: "outline", sx: {
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
mt: isMobile ? "0px" : "3px",
|
||||
mt: isMobile ? "0px" : "3px"
|
||||
} }, { children: [isNested ? ((0, jsx_runtime_1.jsx)(icon_1.Icon, { path: isCollapsed ? icons_1.Icons.chevronRight : icons_1.Icons.chevronDown, title: isCollapsed
|
||||
? "Click to uncollapse list"
|
||||
: "Click to collapse list", sx: {
|
||||
cursor: "pointer",
|
||||
transition: `all .2s ease-in-out`,
|
||||
":hover": {
|
||||
transform: ["unset", "scale(1.3)"],
|
||||
transform: ["unset", "scale(1.3)"]
|
||||
},
|
||||
":active": {
|
||||
transform: ["scale(1.3)", "unset"],
|
||||
transform: ["scale(1.3)", "unset"]
|
||||
},
|
||||
".icon:hover path": {
|
||||
fill: "var(--checked) !important",
|
||||
},
|
||||
}, size: isMobile ? 24 : 18, onMouseDown: (e) => e.preventDefault(), onClick: () => {
|
||||
const [subList] = (0, core_1.findChildren)(node, (node) => node.type.name === outlinelist_1.OutlineList.name);
|
||||
if (!subList)
|
||||
return;
|
||||
const { pos } = subList;
|
||||
editor.commands.toggleOutlineCollapse(pos + getPos() + 1, !isCollapsed);
|
||||
} })) : ((0, jsx_runtime_1.jsx)(icon_1.Icon, { path: icons_1.Icons.circle, size: isMobile ? 24 : 18, sx: { transform: "scale(0.4)" } })), isNested && !isCollapsed && ((0, jsx_runtime_1.jsx)(rebass_1.Box, { sx: {
|
||||
fill: "var(--checked) !important"
|
||||
}
|
||||
}, size: isMobile ? 24 : 18, onMouseDown: (e) => e.preventDefault(), onTouchEnd: (e) => {
|
||||
e.preventDefault();
|
||||
onClick();
|
||||
}, onClick: onClick })) : ((0, jsx_runtime_1.jsx)(icon_1.Icon, { path: icons_1.Icons.circle, size: isMobile ? 24 : 18, sx: { transform: "scale(0.4)" } })), isNested && !isCollapsed && ((0, jsx_runtime_1.jsx)(rebass_1.Box, { sx: {
|
||||
flex: 1,
|
||||
width: 1,
|
||||
mt: 2,
|
||||
@@ -49,12 +53,12 @@ function OutlineListItemComponent(props) {
|
||||
transition: `all .2s ease-in-out`,
|
||||
":hover": {
|
||||
backgroundColor: "fontTertiary",
|
||||
width: 4,
|
||||
},
|
||||
width: 4
|
||||
}
|
||||
}, contentEditable: false }))] })), (0, jsx_runtime_1.jsx)(rebass_1.Text, { ref: forwardRef, sx: {
|
||||
pl: 2,
|
||||
pl: 1,
|
||||
listStyleType: "none",
|
||||
flex: 1,
|
||||
flex: 1
|
||||
} })] }));
|
||||
}
|
||||
exports.OutlineListItemComponent = OutlineListItemComponent;
|
||||
|
||||
@@ -28,8 +28,8 @@ function TaskItemComponent(props) {
|
||||
bg: "background",
|
||||
borderRadius: "default",
|
||||
":hover > .dragHandle": {
|
||||
opacity: editor.isEditable ? 1 : 0,
|
||||
},
|
||||
opacity: editor.isEditable ? 1 : 0
|
||||
}
|
||||
} }, { children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { className: "dragHandle", draggable: "true", "data-drag-handle": true, path: icons_1.Icons.dragHandle, sx: {
|
||||
opacity: [1, 1, 0],
|
||||
alignSelf: "start",
|
||||
@@ -37,8 +37,8 @@ function TaskItemComponent(props) {
|
||||
bg: "transparent",
|
||||
cursor: "grab",
|
||||
".icon:hover path": {
|
||||
fill: "var(--checked) !important",
|
||||
},
|
||||
fill: "var(--checked) !important"
|
||||
}
|
||||
}, size: isMobile ? 24 : 20 }), (0, jsx_runtime_1.jsx)(icon_1.Icon, { path: checked ? icons_1.Icons.check : "", stroke: "1px", sx: {
|
||||
border: "2px solid",
|
||||
borderColor: checked ? "checked" : "icon",
|
||||
@@ -48,18 +48,23 @@ function TaskItemComponent(props) {
|
||||
p: "1px",
|
||||
cursor: editor.isEditable ? "pointer" : "unset",
|
||||
":hover": {
|
||||
borderColor: "checked",
|
||||
borderColor: "checked"
|
||||
},
|
||||
":hover .icon path": {
|
||||
fill: "var(--checked) !important",
|
||||
},
|
||||
fill: "var(--checked) !important"
|
||||
}
|
||||
}, onMouseDown: (e) => {
|
||||
e.preventDefault();
|
||||
toggle();
|
||||
}, onTouchEnd: (e) => {
|
||||
e.preventDefault();
|
||||
toggle();
|
||||
}, color: checked ? "checked" : "icon", size: isMobile ? 16 : 14 }), (0, jsx_runtime_1.jsx)(rebass_1.Text, { as: "div", ref: forwardRef, sx: {
|
||||
textDecorationLine: checked ? "line-through" : "none",
|
||||
opacity: checked ? 0.8 : 1,
|
||||
flex: 1,
|
||||
p: {
|
||||
textDecorationLine: checked ? "line-through" : "none",
|
||||
opacity: checked ? 0.8 : 1
|
||||
},
|
||||
flex: 1
|
||||
} })] })) }));
|
||||
}
|
||||
exports.TaskItemComponent = TaskItemComponent;
|
||||
@@ -69,7 +74,7 @@ function toggleChildren(node, tr, toggleState, parentPos) {
|
||||
// need to add 1 to get inside the node
|
||||
const actualPos = pos + parentPos + 1;
|
||||
tr.setNodeMarkup(actualPos, undefined, {
|
||||
checked: toggleState,
|
||||
checked: toggleState
|
||||
});
|
||||
}
|
||||
return tr;
|
||||
|
||||
@@ -46,11 +46,11 @@ function TaskListComponent(props) {
|
||||
}, [nested, node]);
|
||||
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Flex, Object.assign({ sx: {
|
||||
flexDirection: "column",
|
||||
":hover > div > .toggleSublist": { opacity: 1 },
|
||||
":hover > div > .toggleSublist": { opacity: 1 }
|
||||
} }, { children: nested ? ((0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
right: 0
|
||||
}, contentEditable: false }, { children: [collapsed && ((0, jsx_runtime_1.jsxs)(rebass_1.Text, Object.assign({ variant: "body", sx: { color: "fontTertiary", mr: 35 } }, { children: [stats.checked, "/", stats.total] }))), (0, jsx_runtime_1.jsx)(icon_1.Icon, { className: "toggleSublist", path: collapsed ? icons_1.Icons.chevronDown : icons_1.Icons.chevronUp, sx: {
|
||||
opacity: isMobile || collapsed ? 1 : 0,
|
||||
position: "absolute",
|
||||
@@ -59,8 +59,8 @@ function TaskListComponent(props) {
|
||||
mr: 2,
|
||||
cursor: "pointer",
|
||||
".icon:hover path": {
|
||||
fill: "var(--checked) !important",
|
||||
},
|
||||
fill: "var(--checked) !important"
|
||||
}
|
||||
}, size: isMobile ? 24 : 20, onClick: () => {
|
||||
updateAttributes({ collapsed: !collapsed }, { addToHistory: false, preventUpdate: true });
|
||||
} })] }))) : ((0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: {
|
||||
@@ -71,7 +71,7 @@ function TaskListComponent(props) {
|
||||
mb: 2,
|
||||
alignItems: "center",
|
||||
justifyContent: "end",
|
||||
overflow: "hidden",
|
||||
overflow: "hidden"
|
||||
}, contentEditable: false }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Box, { sx: {
|
||||
height: "100%",
|
||||
width: `${stats.percentage}%`,
|
||||
@@ -79,7 +79,7 @@ function TaskListComponent(props) {
|
||||
bg: "border",
|
||||
zIndex: 0,
|
||||
left: 0,
|
||||
transition: "width 250ms ease-out",
|
||||
transition: "width 250ms ease-out"
|
||||
} }), (0, jsx_runtime_1.jsx)(forms_1.Input, { readOnly: !editor.isEditable, value: title || "", variant: "clean", sx: { p: 0, px: 2, zIndex: 1, color: "fontTertiary" }, placeholder: "Untitled", onChange: (e) => {
|
||||
updateAttributes({ title: e.target.value }, { addToHistory: true, preventUpdate: false });
|
||||
} }), (0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: { flexShrink: 0, pr: 2 } }, { children: [(0, jsx_runtime_1.jsx)(icon_1.Icon, { path: icons_1.Icons.checkbox, size: 15, color: "fontTertiary" }), (0, jsx_runtime_1.jsxs)(rebass_1.Text, Object.assign({ variant: "body", sx: { ml: 1, color: "fontTertiary" } }, { children: [stats.checked, "/", stats.total] }))] }))] }))) })), (0, jsx_runtime_1.jsx)(rebass_1.Text, { as: "div", ref: forwardRef, sx: {
|
||||
@@ -88,12 +88,13 @@ function TaskListComponent(props) {
|
||||
paddingInlineStart: 0,
|
||||
marginBlockStart: nested ? 10 : 0,
|
||||
marginBlockEnd: 0,
|
||||
marginLeft: nested ? -35 : 0
|
||||
},
|
||||
li: {
|
||||
listStyleType: "none",
|
||||
position: "relative",
|
||||
marginBottom: [2, "7px"],
|
||||
},
|
||||
marginBottom: [2, "7px"]
|
||||
}
|
||||
} })] }));
|
||||
}
|
||||
exports.TaskListComponent = TaskListComponent;
|
||||
|
||||
@@ -19,7 +19,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
||||
const react_1 = __importDefault(require("@mdi/react"));
|
||||
const rebass_1 = require("rebass");
|
||||
const toolbarstore_1 = require("../stores/toolbarstore");
|
||||
function MDIIconWrapper({ title, path, size = 24, color = "icon", stroke, rotate, }) {
|
||||
function MDIIconWrapper({ title, path, size = 24, color = "icon", stroke, rotate }) {
|
||||
const theme = (0, toolbarstore_1.useTheme)();
|
||||
const themedColor = (theme === null || theme === void 0 ? void 0 : theme.colors)
|
||||
? theme.colors[color]
|
||||
@@ -28,7 +28,7 @@ function MDIIconWrapper({ title, path, size = 24, color = "icon", stroke, rotate
|
||||
? `${(theme === null || theme === void 0 ? void 0 : theme.iconSizes[size]) || 24}px`
|
||||
: `${size}px`, style: {
|
||||
strokeWidth: stroke || "0px",
|
||||
stroke: themedColor,
|
||||
stroke: themedColor
|
||||
}, color: themedColor, spin: rotate }));
|
||||
}
|
||||
function Icon(props) {
|
||||
|
||||
1
packages/editor/dist/cjs/toolbar/icons.d.ts
vendored
1
packages/editor/dist/cjs/toolbar/icons.d.ts
vendored
@@ -93,6 +93,7 @@ export declare const Icons: {
|
||||
chevronLeft: string;
|
||||
circle: string;
|
||||
arrowLeft: string;
|
||||
resize: string;
|
||||
none: string;
|
||||
};
|
||||
export declare type IconNames = keyof typeof Icons;
|
||||
|
||||
3
packages/editor/dist/cjs/toolbar/icons.js
vendored
3
packages/editor/dist/cjs/toolbar/icons.js
vendored
@@ -97,5 +97,6 @@ exports.Icons = {
|
||||
chevronLeft: js_1.mdiChevronLeft,
|
||||
circle: js_1.mdiCircle,
|
||||
arrowLeft: js_1.mdiArrowLeft,
|
||||
none: "",
|
||||
resize: js_1.mdiResizeBottomRight,
|
||||
none: ""
|
||||
};
|
||||
|
||||
@@ -18,11 +18,11 @@ function TablePopup(props) {
|
||||
const { onInsertTable } = props;
|
||||
const [cellLocation, setCellLocation] = (0, react_1.useState)({
|
||||
column: 0,
|
||||
row: 0,
|
||||
row: 0
|
||||
});
|
||||
const [tableSize, setTableSize] = (0, react_1.useState)({
|
||||
columns: MIN_COLUMNS,
|
||||
rows: MIN_ROWS,
|
||||
rows: MIN_ROWS
|
||||
});
|
||||
(0, react_1.useEffect)(() => {
|
||||
if (!autoExpand)
|
||||
@@ -39,7 +39,7 @@ function TablePopup(props) {
|
||||
: Math.min(old.columns + columnFactor, MAX_COLUMNS),
|
||||
rows: isDecrease
|
||||
? Math.max(row + rowFactor, MIN_ROWS)
|
||||
: Math.min(old.rows + rowFactor, MAX_ROWS),
|
||||
: Math.min(old.rows + rowFactor, MAX_ROWS)
|
||||
};
|
||||
});
|
||||
}, [cellLocation, autoExpand]);
|
||||
@@ -50,14 +50,14 @@ function TablePopup(props) {
|
||||
disabled: !cellLocation.column || !cellLocation.row,
|
||||
onClick: () => onInsertTable({
|
||||
columns: cellLocation.column,
|
||||
rows: cellLocation.row,
|
||||
}),
|
||||
rows: cellLocation.row
|
||||
})
|
||||
} }, { children: (0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: { px: 1, pt: 1, flexDirection: "column", alignItems: "center" } }, { children: [(0, jsx_runtime_1.jsx)(rebass_1.Box, Object.assign({ sx: {
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${tableSize.columns}, minmax(${cellSize}px, 1fr))`,
|
||||
gap: "small",
|
||||
bg: "background",
|
||||
width: "100%",
|
||||
width: "100%"
|
||||
}, onTouchMove: (e) => {
|
||||
const touch = e.touches.item(0);
|
||||
const element = document.elementFromPoint(touch.pageX, touch.pageY);
|
||||
@@ -74,21 +74,23 @@ function TablePopup(props) {
|
||||
borderRadius: "small",
|
||||
bg: isCellHighlighted(index, cellLocation, tableSize)
|
||||
? "disabled"
|
||||
: "transparent",
|
||||
: "transparent"
|
||||
}, onTouchStart: () => {
|
||||
setCellLocation(getCellLocation(index, tableSize));
|
||||
}, onMouseEnter: () => {
|
||||
setCellLocation(getCellLocation(index, tableSize));
|
||||
}, onTouchEnd: (e) => {
|
||||
e.preventDefault();
|
||||
}, onClick: () => {
|
||||
onInsertTable({
|
||||
columns: cellLocation.column,
|
||||
rows: cellLocation.row,
|
||||
rows: cellLocation.row
|
||||
});
|
||||
} }, index))) })), (0, jsx_runtime_1.jsxs)(rebass_1.Flex, Object.assign({ sx: {
|
||||
display: ["flex", "none", "none"],
|
||||
mt: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
justifyContent: "center"
|
||||
} }, { children: [(0, jsx_runtime_1.jsx)(inlineinput_1.InlineInput, { containerProps: { sx: { mr: 1 } }, label: "columns", placeholder: `${cellLocation.column} columns`, type: "number", value: cellLocation.column, onChange: (e) => {
|
||||
setCellLocation((l) => (Object.assign(Object.assign({}, l), { column: e.target.valueAsNumber || 0 })));
|
||||
} }), (0, jsx_runtime_1.jsx)(inlineinput_1.InlineInput, { label: "rows", placeholder: `${cellLocation.row} rows`, type: "number", value: cellLocation.row, onChange: (e) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Plugin } from "prosemirror-state";
|
||||
import { DecorationSet } from "prosemirror-view";
|
||||
import { AddMarkStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from "prosemirror-transform";
|
||||
export declare type MergedStep = AddMarkStep | RemoveMarkStep | ReplaceAroundStep | ReplaceStep;
|
||||
export declare function HighlighterPlugin({ name, defaultLanguage }: {
|
||||
export declare function HighlighterPlugin({ name, defaultLanguage, }: {
|
||||
name: string;
|
||||
defaultLanguage: string | null | undefined;
|
||||
}): Plugin<DecorationSet>;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
|
||||
import { Decoration, DecorationSet } from "prosemirror-view";
|
||||
import { findChildren } from "@tiptap/core";
|
||||
import { refractor } from "refractor/lib/core";
|
||||
import { toCaretPosition, toCodeLines } from "./code-block";
|
||||
import { toCaretPosition, toCodeLines, } from "./code-block";
|
||||
function parseNodes(nodes, className = []) {
|
||||
return nodes.reduce((result, node) => {
|
||||
if (node.type === "comment" || node.type === "doctype")
|
||||
@@ -32,17 +32,16 @@ function getLineDecoration(from, line, total, isActive) {
|
||||
const attributes = {
|
||||
class: `line-number ${isActive ? "active" : ""}`,
|
||||
"data-line": String(line).padEnd(maxLength, " "),
|
||||
autocapitalize: "none"
|
||||
};
|
||||
const spec = {
|
||||
line: line,
|
||||
active: isActive,
|
||||
total,
|
||||
from
|
||||
from,
|
||||
};
|
||||
return Decoration.inline(from, from + 1, attributes, spec);
|
||||
}
|
||||
function getDecorations({ doc, name, defaultLanguage, caretPosition }) {
|
||||
function getDecorations({ doc, name, defaultLanguage, caretPosition, }) {
|
||||
const decorations = [];
|
||||
const languages = refractor.listLanguages();
|
||||
findChildren(doc, (node) => node.type.name === name).forEach((block) => {
|
||||
@@ -65,7 +64,7 @@ function getDecorations({ doc, name, defaultLanguage, caretPosition }) {
|
||||
const to = from + node.text.length;
|
||||
if (node.classes.length) {
|
||||
const decoration = Decoration.inline(from, to, {
|
||||
class: node.classes.join(" ")
|
||||
class: node.classes.join(" "),
|
||||
});
|
||||
decorations.push(decoration);
|
||||
}
|
||||
@@ -74,7 +73,7 @@ function getDecorations({ doc, name, defaultLanguage, caretPosition }) {
|
||||
});
|
||||
return DecorationSet.create(doc, decorations);
|
||||
}
|
||||
export function HighlighterPlugin({ name, defaultLanguage }) {
|
||||
export function HighlighterPlugin({ name, defaultLanguage, }) {
|
||||
const key = new PluginKey("highlighter");
|
||||
return new Plugin({
|
||||
key,
|
||||
@@ -83,7 +82,7 @@ export function HighlighterPlugin({ name, defaultLanguage }) {
|
||||
return getDecorations({
|
||||
doc: state.doc,
|
||||
name,
|
||||
defaultLanguage
|
||||
defaultLanguage,
|
||||
});
|
||||
},
|
||||
apply: (transaction, decorationSet, oldState, newState) => {
|
||||
@@ -118,17 +117,17 @@ export function HighlighterPlugin({ name, defaultLanguage }) {
|
||||
doc: transaction.doc,
|
||||
name,
|
||||
defaultLanguage,
|
||||
caretPosition: position
|
||||
caretPosition: position,
|
||||
});
|
||||
}
|
||||
decorationSet = getActiveLineDecorations(transaction.doc, decorationSet, position);
|
||||
return decorationSet.map(transaction.mapping, transaction.doc);
|
||||
}
|
||||
},
|
||||
},
|
||||
props: {
|
||||
decorations(state) {
|
||||
return key.getState(state);
|
||||
}
|
||||
},
|
||||
},
|
||||
appendTransaction: (transactions, prevState, nextState) => {
|
||||
const tr = nextState.tr;
|
||||
@@ -155,7 +154,7 @@ export function HighlighterPlugin({ name, defaultLanguage }) {
|
||||
}
|
||||
});
|
||||
return modified ? tr : null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -179,7 +178,7 @@ function getActiveLineDecorations(doc, decorations, position) {
|
||||
decorations = decorations.remove(lineDecorations);
|
||||
const newDecorations = [];
|
||||
for (const decoration of cloned) {
|
||||
const { from, spec: { line, total } } = decoration;
|
||||
const { from, spec: { line, total }, } = decoration;
|
||||
const isActive = line === (position === null || position === void 0 ? void 0 : position.line);
|
||||
const newDecoration = getLineDecoration(from, line, (position === null || position === void 0 ? void 0 : position.total) || total, isActive);
|
||||
newDecorations.push(newDecoration);
|
||||
|
||||
@@ -14,7 +14,7 @@ export declare type ToolButtonProps = ButtonProps & {
|
||||
};
|
||||
export declare const ToolButton: React.NamedExoticComponent<ButtonProps & {
|
||||
icon: IconNames;
|
||||
iconColor?: "background" | "border" | "text" | "blue" | "gray" | "green" | "orange" | "purple" | "red" | "yellow" | "checked" | "disabled" | "placeholder" | "icon" | "overlay" | "hover" | keyof import("@notesnook/theme/dist/theme/colorscheme/static").StaticColors | "primary" | "bgTransparent" | "accent" | "bgSecondary" | "bgSecondaryText" | "bgSecondaryHover" | "fontSecondary" | "fontTertiary" | "secondary" | undefined;
|
||||
iconColor?: "text" | "background" | "border" | "blue" | "gray" | "green" | "orange" | "purple" | "red" | "yellow" | "checked" | "disabled" | "placeholder" | "icon" | "overlay" | "primary" | "bgSecondary" | keyof import("@notesnook/theme/dist/theme/colorscheme/static").StaticColors | "bgTransparent" | "accent" | "bgSecondaryText" | "bgSecondaryHover" | "hover" | "fontSecondary" | "fontTertiary" | "secondary" | undefined;
|
||||
iconSize?: number | "small" | "big" | "medium" | undefined;
|
||||
toggled: boolean;
|
||||
buttonRef?: React.MutableRefObject<HTMLButtonElement | null | undefined> | undefined;
|
||||
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
AddMarkStep,
|
||||
RemoveMarkStep,
|
||||
ReplaceAroundStep,
|
||||
ReplaceStep
|
||||
ReplaceStep,
|
||||
} from "prosemirror-transform";
|
||||
import {
|
||||
CaretPosition,
|
||||
CodeBlockAttributes,
|
||||
getLines,
|
||||
toCaretPosition,
|
||||
toCodeLines
|
||||
toCodeLines,
|
||||
} from "./code-block";
|
||||
|
||||
export type MergedStep =
|
||||
@@ -64,13 +64,12 @@ function getLineDecoration(
|
||||
const attributes = {
|
||||
class: `line-number ${isActive ? "active" : ""}`,
|
||||
"data-line": String(line).padEnd(maxLength, " "),
|
||||
autocapitalize: "none"
|
||||
};
|
||||
const spec: any = {
|
||||
line: line,
|
||||
active: isActive,
|
||||
total,
|
||||
from
|
||||
from,
|
||||
};
|
||||
|
||||
return Decoration.inline(from, from + 1, attributes, spec);
|
||||
@@ -80,7 +79,7 @@ function getDecorations({
|
||||
doc,
|
||||
name,
|
||||
defaultLanguage,
|
||||
caretPosition
|
||||
caretPosition,
|
||||
}: {
|
||||
caretPosition?: CaretPosition;
|
||||
doc: ProsemirrorNode;
|
||||
@@ -116,7 +115,7 @@ function getDecorations({
|
||||
const to = from + node.text.length;
|
||||
if (node.classes.length) {
|
||||
const decoration = Decoration.inline(from, to, {
|
||||
class: node.classes.join(" ")
|
||||
class: node.classes.join(" "),
|
||||
});
|
||||
decorations.push(decoration);
|
||||
}
|
||||
@@ -129,7 +128,7 @@ function getDecorations({
|
||||
|
||||
export function HighlighterPlugin({
|
||||
name,
|
||||
defaultLanguage
|
||||
defaultLanguage,
|
||||
}: {
|
||||
name: string;
|
||||
defaultLanguage: string | null | undefined;
|
||||
@@ -143,7 +142,7 @@ export function HighlighterPlugin({
|
||||
return getDecorations({
|
||||
doc: state.doc,
|
||||
name,
|
||||
defaultLanguage
|
||||
defaultLanguage,
|
||||
});
|
||||
},
|
||||
apply: (
|
||||
@@ -197,7 +196,7 @@ export function HighlighterPlugin({
|
||||
doc: transaction.doc,
|
||||
name,
|
||||
defaultLanguage,
|
||||
caretPosition: position
|
||||
caretPosition: position,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,13 +207,13 @@ export function HighlighterPlugin({
|
||||
);
|
||||
|
||||
return decorationSet.map(transaction.mapping, transaction.doc);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
decorations(state) {
|
||||
return key.getState(state);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
appendTransaction: (transactions, prevState, nextState) => {
|
||||
@@ -255,7 +254,7 @@ export function HighlighterPlugin({
|
||||
);
|
||||
|
||||
return modified ? tr : null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -293,7 +292,7 @@ function getActiveLineDecorations(
|
||||
for (const decoration of cloned) {
|
||||
const {
|
||||
from,
|
||||
spec: { line, total }
|
||||
spec: { line, total },
|
||||
} = decoration;
|
||||
|
||||
const isActive = line === position?.line;
|
||||
|
||||
Reference in New Issue
Block a user