Skip to content
This repository has been archived by the owner on Nov 29, 2023. It is now read-only.

feat: add resize feature supports for image and iframe #2

Merged
merged 11 commits into from
Jan 31, 2023
4 changes: 2 additions & 2 deletions example/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { unified } from "unified";
import rehypeParse from "rehype-parse";
import rehypeFormat from "rehype-format";
import rehypeStringify from "rehype-stringify";
import { useLocalStorage } from "@vueuse/core";
import {
ExtensionBlockquote,
ExtensionBold,
Expand Down Expand Up @@ -77,7 +78,7 @@ import {
Separator,
} from "@halo-dev/richtext-editor";

const content = ref("");
const content = useLocalStorage("content", "");

const editor = useEditor({
content: content.value,
Expand All @@ -100,7 +101,6 @@ const editor = useEditor({
ExtensionStrike,
ExtensionText,
ExtensionImage.configure({
inline: true,
HTMLAttributes: {
loading: "lazy",
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"dependencies": {
"pinia": "^2.0.28",
"vue": "^3.2.45"
"vue": "^3.2.45",
"@vueuse/core": "^9.10.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
Expand Down
3 changes: 1 addition & 2 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@halo-dev/richtext-editor",
"version": "0.0.0-alpha.17",
"version": "0.0.0-alpha.18-0",
"description": "",
"files": [
"dist"
Expand Down Expand Up @@ -84,7 +84,6 @@
"@tiptap/extension-underline": "2.0.0-beta.209",
"@tiptap/suggestion": "2.0.0-beta.209",
"@tiptap/vue-3": "2.0.0-beta.209",
"@vueuse/core": "^9.10.0",
"floating-vue": "2.0.0-beta.20",
"highlight.js": "11.7.0",
"katex": "^0.16.4",
Expand Down
36 changes: 36 additions & 0 deletions packages/editor/src/components/block/BlockActionButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts" setup>
import { VTooltip } from "floating-vue";

withDefaults(
defineProps<{
tooltip?: string;
selected?: boolean;
}>(),
{
tooltip: undefined,
selected: false,
}
);
</script>

<template>
<div
v-tooltip="tooltip"
class="editor-block__actions-button"
:class="{
'editor-block__actions-button--selected': selected,
}"
>
<slot name="icon" />
</div>
</template>

<style lang="scss">
.editor-block__actions-button {
@apply p-1.5 bg-gray-50 rounded-md cursor-pointer hover:bg-gray-100;

&--selected {
@apply bg-gray-200;
}
}
</style>
37 changes: 37 additions & 0 deletions packages/editor/src/components/block/BlockActionInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts" setup>
import { computed } from "vue";
import { VTooltip } from "floating-vue";

const props = withDefaults(
defineProps<{
tooltip?: string;
modelValue: string;
}>(),
{
tooltip: undefined,
}
);

const emit = defineEmits<{
(emit: "update:modelValue", value: string): void;
}>();

const value = computed({
get: () => props.modelValue,
set: (value: string) => emit("update:modelValue", value),
});
</script>

<template>
<input
v-model.lazy.trim="value"
v-tooltip="tooltip"
class="editor-block__actions-input"
/>
</template>

<style lang="scss">
.editor-block__actions-input {
@apply bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-32 py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500;
}
</style>
10 changes: 10 additions & 0 deletions packages/editor/src/components/block/BlockActionSeparator.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<template>
<div class="editor-block__actions-separator"></div>
</template>

<style>
.editor-block__actions-separator {
@apply h-5 bg-gray-100 mx-1.5;
width: 1px;
}
</style>
109 changes: 109 additions & 0 deletions packages/editor/src/components/block/BlockCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<script lang="ts" setup>
import type { Editor } from "@tiptap/vue-3";
import { Dropdown as VDropdown } from "floating-vue";
import { computed, ref } from "vue";
import MdiDeleteForeverOutline from "~icons/mdi/delete-forever-outline?color=red";
import MdiArrowULeftBottom from "~icons/mdi/arrow-u-left-bottom";
import BlockActionSeparator from "./BlockActionSeparator.vue";
import BlockActionButton from "./BlockActionButton.vue";

const props = withDefaults(
defineProps<{
selected: boolean;
editor: Editor;
getPos: () => number;
deleteNode: () => void;
}>(),
{
selected: false,
}
);

const hover = ref(false);

const dropdownVisible = computed(() => {
return hover.value || props.selected;
});

function handleInsertNewLine() {
props.editor.commands.insertContentAt(
props.getPos() + 1,
[{ type: "paragraph", content: "" }],
{
updateSelection: true,
}
);
props.editor.commands.focus(props.getPos() + 2, {
scrollIntoView: true,
});
}
</script>

<template>
<section
class="editor-block"
:class="{ 'editor-block--selected': selected }"
@mouseenter="hover = true"
@mouseleave="hover = false"
>
<VDropdown
placement="bottom-end"
:shown="dropdownVisible"
:auto-hide="false"
:triggers="[]"
:distance="8"
theme="editor-block-dropdown"
>
<div class="editor-block__content">
<slot name="content" />
</div>
<template #popper>
<div class="editor-block__actions">
<slot name="actions" />

<BlockActionButton tooltip="换行" @click="handleInsertNewLine">
<template #icon>
<MdiArrowULeftBottom />
</template>
</BlockActionButton>

<BlockActionSeparator />

<BlockActionButton tooltip="删除" @click="deleteNode">
<template #icon>
<MdiDeleteForeverOutline />
</template>
</BlockActionButton>
</div>
</template>
</VDropdown>
</section>
</template>

<style lang="scss">
.editor-block {
@apply relative;

&__content {
@apply transition-all
rounded
p-2;
}

&__actions {
@apply p-1 flex flex-row gap-0.5 items-center;
}

&:hover & {
&__content {
@apply bg-gray-50;
}
}

&--selected & {
&__content {
@apply bg-gray-50;
}
}
}
</style>
48 changes: 28 additions & 20 deletions packages/editor/src/extensions/code-block/CodeBlockViewRenderer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Decoration } from "prosemirror-view";
import { NodeViewContent, NodeViewWrapper, Editor, Node } from "@tiptap/vue-3";
import lowlight from "./lowlight";
import { computed } from "vue";
import BlockCard from "@/components/block/BlockCard.vue";

const props = defineProps<{
editor: Editor;
Expand All @@ -30,25 +31,32 @@ const selectedLanguage = computed({
});
</script>
<template>
<node-view-wrapper
class="code-block divide-gray-100 bg-gray-100 overflow-hidden rounded-md my-3"
>
<div class="px-2 py-1.5">
<select
v-model="selectedLanguage"
contenteditable="false"
class="block px-2 py-1.5 text-sm text-gray-900 border border-gray-300 rounded-md bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
>
<option :value="null">auto</option>
<option
v-for="(language, index) in languages"
:key="index"
:value="language"
>
{{ language }}
</option>
</select>
</div>
<pre><code><node-view-content /></code></pre>
<node-view-wrapper>
<block-card
:editor="editor"
:delete-node="deleteNode"
:get-pos="getPos"
:selected="selected"
>
<template #content>
<div class="py-1.5">
<select
v-model="selectedLanguage"
contenteditable="false"
class="block px-2 py-1.5 text-sm text-gray-900 border border-gray-300 rounded-md bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
>
<option :value="null">auto</option>
<option
v-for="(language, index) in languages"
:key="index"
:value="language"
>
{{ language }}
</option>
</select>
</div>
<pre><code><node-view-content /></code></pre>
</template>
</block-card>
</node-view-wrapper>
</template>
Loading