Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
ruibaby committed Apr 18, 2024
2 parents b2f447b + fdc2453 commit 7a58c88
Show file tree
Hide file tree
Showing 17 changed files with 377 additions and 23 deletions.
2 changes: 1 addition & 1 deletion platform/application/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ext {
guava = "32.0.1-jre"
jsoup = '1.15.3'
jsonPatch = "1.13"
springDocOpenAPI = "2.4.0"
springDocOpenAPI = "2.5.0"
lucene = "9.9.1"
resilience4jVersion = "2.2.0"
twoFactorAuth = "1.3"
Expand Down
2 changes: 1 addition & 1 deletion ui/console-src/layouts/BasicLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ onMounted(() => {
</script>

<template>
<div class="flex h-full">
<div class="flex min-h-screen">
<aside
class="navbar fixed hidden h-full overflow-y-auto md:flex md:flex-col"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ const handleCreateUser = async () => {
v-model="selectedRole"
:label="$t('core.user.grant_permission_modal.fields.role.label')"
type="roleSelect"
validation="required"
></FormKit>
<FormKit
v-model="formState.bio"
Expand Down
46 changes: 29 additions & 17 deletions ui/packages/editor/src/components/EditorHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { Menu as VMenu } from "floating-vue";
import { Menu as VMenu, Dropdown as VDropdown } from "floating-vue";
import { Editor, type AnyExtension } from "@/tiptap/vue-3";
import MdiPlusCircle from "~icons/mdi/plus-circle";
import type { ToolbarItem, ToolboxItem } from "@/types";
Expand Down Expand Up @@ -93,22 +93,34 @@ function getToolboxItemsFromExtensions() {
v-bind="item.props"
tabindex="-1"
/>
<VMenu v-else class="inline-flex" tabindex="-1">
<component :is="item.component" v-bind="item.props" tabindex="-1" />
<template #popper>
<div
class="relative rounded-md bg-white overflow-hidden drop-shadow w-48 p-1 max-h-72 overflow-y-auto"
>
<component
v-bind="child.props"
:is="child.component"
v-for="(child, childIndex) in item.children"
:key="childIndex"
tabindex="-1"
/>
</div>
</template>
</VMenu>
<template v-else>
<VDropdown
class="inline-flex"
tabindex="-1"
:triggers="['click']"
:popper-triggers="['click']"
>
<component
:is="item.component"
v-bind="item.props"
:children="item.children"
tabindex="-1"
/>
<template #popper>
<div
class="relative rounded-md bg-white overflow-hidden drop-shadow w-48 p-1 max-h-72 overflow-y-auto"
>
<component
v-bind="child.props"
:is="child.component"
v-for="(child, childIndex) in item.children"
:key="childIndex"
tabindex="-1"
/>
</div>
</template>
</VDropdown>
</template>
</div>
</div>
</template>
7 changes: 6 additions & 1 deletion ui/packages/editor/src/components/toolbar/ToolbarItem.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts" setup>
import type { Component } from "vue";
import { VTooltip } from "floating-vue";
import IconArrowDown from "~icons/ri/arrow-down-s-fill";
import type { ToolbarItem } from "@/types";
withDefaults(
defineProps<{
Expand All @@ -9,13 +11,15 @@ withDefaults(
title?: string;
action?: () => void;
icon?: Component;
children: ToolbarItem[];
}>(),
{
isActive: false,
disabled: false,
title: undefined,
action: undefined,
icon: undefined,
children: undefined,
}
);
</script>
Expand All @@ -28,11 +32,12 @@ withDefaults(
{ 'cursor-not-allowed opacity-70': disabled },
{ 'hover:bg-gray-100': !disabled },
]"
class="p-1 rounded-sm"
class="inline-flex items-center space-x-1 p-1 rounded-sm"
:disabled="disabled"
tabindex="-1"
@click="action"
>
<component :is="icon" />
<IconArrowDown v-if="children?.length" />
</button>
</template>
2 changes: 2 additions & 0 deletions ui/packages/editor/src/dev/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
ExtensionListKeymap,
ExtensionSearchAndReplace,
ExtensionClearFormat,
ExtensionFormatBrush,
} from "../index";
const content = useLocalStorage("content", "");
Expand Down Expand Up @@ -113,6 +114,7 @@ const editor = useEditor({
ExtensionListKeymap,
ExtensionSearchAndReplace,
ExtensionClearFormat,
ExtensionFormatBrush,
],
parseOptions: {
preserveWhitespace: true,
Expand Down
74 changes: 73 additions & 1 deletion ui/packages/editor/src/extensions/code-block/code-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import {
findParentNode,
VueNodeViewRenderer,
} from "@/tiptap/vue-3";
import { EditorState, TextSelection, type Transaction } from "@/tiptap/pm";
import {
EditorState,
Plugin,
PluginKey,
TextSelection,
type Transaction,
} from "@/tiptap/pm";
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
import type { CodeBlockLowlightOptions } from "@tiptap/extension-code-block-lowlight";
import CodeBlockViewRenderer from "./CodeBlockViewRenderer.vue";
Expand Down Expand Up @@ -237,4 +243,70 @@ export default CodeBlockLowlight.extend<
},
};
},

addProseMirrorPlugins() {
return [
// Solve the paste problem. Because the upstream has not been
// able to deal with this problem for a long time, it is
// handled manually locally.
// see: https://github.com/ueberdosis/tiptap/pull/3606
new Plugin({
key: new PluginKey("codeBlockVSCodeHandlerFixPaste"),
props: {
handlePaste: (view, event) => {
if (!event.clipboardData) {
return false;
}
// don’t create a new code block within code blocks
if (this.editor.isActive(this.type.name)) {
return false;
}

const text = event.clipboardData.getData("text/plain");
const vscode = event.clipboardData.getData("vscode-editor-data");
const vscodeData = vscode ? JSON.parse(vscode) : undefined;
const language = vscodeData?.mode;

if (!text || !language) {
return false;
}

const { tr, schema } = view.state;

// add text to code block
// strip carriage return chars from text pasted as code
// see: https://github.com/ProseMirror/prosemirror-view/commit/a50a6bcceb4ce52ac8fcc6162488d8875613aacd
const contentTextNode = schema.text(text.replace(/\r\n?/g, "\n"));

// create an empty code block
tr.replaceSelectionWith(
this.type.create({ language }, contentTextNode)
);

const { selection } = tr;
// Whether the current position is code block, if not, move forward to code block.
let codeBlockPos = Math.max(0, selection.from - 1);
while (
codeBlockPos > 0 &&
tr.doc.resolve(codeBlockPos).parent.type.name !== this.type.name
) {
codeBlockPos--;
}
// put cursor inside the newly created code block
tr.setSelection(TextSelection.near(tr.doc.resolve(codeBlockPos)));

// store meta information
// this is useful for other plugins that depends on the paste event
// like the paste rule plugin
tr.setMeta("paste", true);

view.dispatch(tr);

return true;
},
},
}),
...(this.parent?.() || []),
];
},
});
120 changes: 120 additions & 0 deletions ui/packages/editor/src/extensions/format-brush/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import ToolbarItem from "@/components/toolbar/ToolbarItem.vue";
import { i18n } from "@/locales";
import { CoreEditor, Extension, Plugin, PluginKey } from "@/tiptap";
import { markRaw } from "vue";
import BxsBrushAlt from "~icons/bxs/brush-alt";
import { getMarksByFirstTextNode, setMarks } from "./util";

declare module "@/tiptap" {
interface Commands<ReturnType> {
formatBrush: {
copyFormatBrush: () => ReturnType;
pasteFormatBrush: () => ReturnType;
};
}
}

export interface FormatBrushStore {
formatBrush: boolean;
formatBrushMarks: any[];
}

const formatBrush = Extension.create<any, FormatBrushStore>({
addOptions() {
return {
...this.parent?.(),
getToolbarItems({ editor }: { editor: CoreEditor }) {
const formatBrush =
editor.view.dom.classList.contains("format-brush-mode");
return {
priority: 25,
component: markRaw(ToolbarItem),
props: {
editor,
isActive: formatBrush,
icon: markRaw(BxsBrushAlt),
title: formatBrush
? i18n.global.t(
"editor.extensions.format_brush.toolbar_item.cancel"
)
: i18n.global.t(
"editor.extensions.format_brush.toolbar_item.title"
),
action: () => {
if (formatBrush) {
editor.commands.pasteFormatBrush();
} else {
editor.commands.copyFormatBrush();
}
},
},
};
},
};
},

addCommands() {
return {
copyFormatBrush:
() =>
({ state }) => {
const markRange = getMarksByFirstTextNode(state);
this.storage.formatBrushMarks = markRange;
this.storage.formatBrush = true;
this.editor.view.dom.classList.add("format-brush-mode");
return true;
},
pasteFormatBrush: () => () => {
this.storage.formatBrushMarks = [];
this.storage.formatBrush = false;
this.editor.view.dom.classList.remove("format-brush-mode");
return true;
},
};
},

addStorage() {
return {
formatBrush: false,
formatBrushMarks: [],
};
},

addProseMirrorPlugins() {
const storage = this.storage;
const editor = this.editor;
return [
new Plugin({
key: new PluginKey("formatBrushPlugin"),
props: {
handleDOMEvents: {
mouseup(view) {
if (!storage.formatBrush) {
return;
}
editor
.chain()
.command(({ tr }) => {
setMarks(view.state, storage.formatBrushMarks, tr);
return true;
})
.pasteFormatBrush()
.run();
},
},
},
}),
];
},

addKeyboardShortcuts() {
return {
"Shift-Mod-c": () => {
this.editor.commands.copyFormatBrush();
return true;
},
};
},
});

export default formatBrush;
Loading

0 comments on commit 7a58c88

Please sign in to comment.