@adminforth/rich-editor 2.1.2 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/build.log +2 -2
- package/custom/quillEditor.vue +90 -45
- package/dist/custom/quillEditor.vue +90 -45
- package/dist/index.js +4 -4
- package/index.ts +4 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://tluma.ai/ask-ai/devforth/adminforth)
|
|
6
6
|
|
|
7
|
+
> [!WARNING]
|
|
8
|
+
> **This plugin is not recommended for new projects.** Use the [Markdown plugin](https://adminforth.dev/docs/tutorial/Plugins/markdown/) (`@adminforth/markdown`) for editing formatted text instead. It stores content as Markdown, which suits the agentic era much better than HTML: AI agents read and write Markdown reliably, it stays readable as plain text and gives clean diffs. RichEditor keeps working for apps which already store HTML.
|
|
9
|
+
|
|
7
10
|
Allows to add a rich text editor to your AdminForth text columns.
|
|
8
11
|
|
|
9
12
|
## Features
|
package/build.log
CHANGED
|
@@ -10,5 +10,5 @@ custom/package.json
|
|
|
10
10
|
custom/quillEditor.vue
|
|
11
11
|
custom/tsconfig.json
|
|
12
12
|
|
|
13
|
-
sent
|
|
14
|
-
total size is
|
|
13
|
+
sent 38,509 bytes received 115 bytes 77,248.00 bytes/sec
|
|
14
|
+
total size is 38,086 speedup is 0.99
|
package/custom/quillEditor.vue
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="wasQuillInitializedSuccessfully"
|
|
4
|
-
class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
class="af-quill-editor block w-full whitespace-normal rounded-default border shadow-customLight transition-colors
|
|
5
|
+
bg-lightInputBackground text-lightInputText border-lightInputBorder hover:border-lightInputBorderHover
|
|
6
|
+
focus-within:border-lightInputFocusBorder focus-within:ring-[3px] focus-within:ring-lightInputFocusRing
|
|
7
|
+
dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:border-darkInputBorderHover
|
|
8
|
+
dark:focus-within:border-darkInputFocusBorder dark:focus-within:ring-darkInputFocusRing"
|
|
8
9
|
>
|
|
9
10
|
<div
|
|
10
11
|
ref="editor"
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
</template>
|
|
29
30
|
|
|
30
31
|
<script setup lang="ts">
|
|
31
|
-
import { onMounted, ref, onUnmounted, watch, type Ref } from "vue";
|
|
32
|
+
import { onMounted, ref, onUnmounted, watch, h, render, type Ref, type FunctionalComponent } from "vue";
|
|
32
33
|
import { callAdminForthApi } from '@/utils';
|
|
33
34
|
import { AdminForthColumnCommon } from '@/types/Common';
|
|
34
35
|
import adminforth from '@/adminforth';
|
|
@@ -39,6 +40,11 @@ import "quill/dist/quill.snow.css";
|
|
|
39
40
|
import QuillTableBetter from 'quill-table-better-yaroslav8765';
|
|
40
41
|
import 'quill-table-better-yaroslav8765/dist/quill-table-better.css';
|
|
41
42
|
import { Textarea } from '@/afcl'
|
|
43
|
+
import {
|
|
44
|
+
IconAlignCenter, IconAlignJustify, IconAlignLeft, IconAlignRight, IconBold, IconCode, IconHeading2, IconHeading3,
|
|
45
|
+
IconImage, IconItalic, IconLink, IconList, IconListChecks, IconListOrdered, IconRemoveFormatting, IconStrikethrough,
|
|
46
|
+
IconTable, IconTextQuote, IconUnderline,
|
|
47
|
+
} from '@iconify-prerendered/vue-lucide';
|
|
42
48
|
|
|
43
49
|
import { useI18n } from 'vue-i18n';
|
|
44
50
|
import { ok } from "assert";
|
|
@@ -131,6 +137,31 @@ Quill.register({
|
|
|
131
137
|
'modules/table-better': QuillTableBetter
|
|
132
138
|
}, true);
|
|
133
139
|
|
|
140
|
+
// the toolbar draws Lucide icons like the rest of the UI; Quill takes icons as SVG strings,
|
|
141
|
+
// so they are set after the table module registered its own one
|
|
142
|
+
function iconSvg(icon: FunctionalComponent) {
|
|
143
|
+
const holder = document.createElement('div');
|
|
144
|
+
render(h(icon), holder);
|
|
145
|
+
return holder.innerHTML;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const quillIcons = Quill.import('ui/icons') as Record<string, any>;
|
|
149
|
+
Object.assign(quillIcons, {
|
|
150
|
+
bold: iconSvg(IconBold),
|
|
151
|
+
italic: iconSvg(IconItalic),
|
|
152
|
+
underline: iconSvg(IconUnderline),
|
|
153
|
+
strike: iconSvg(IconStrikethrough),
|
|
154
|
+
'table-better': iconSvg(IconTable),
|
|
155
|
+
blockquote: iconSvg(IconTextQuote),
|
|
156
|
+
'code-block': iconSvg(IconCode),
|
|
157
|
+
link: iconSvg(IconLink),
|
|
158
|
+
image: iconSvg(IconImage),
|
|
159
|
+
clean: iconSvg(IconRemoveFormatting),
|
|
160
|
+
header: { ...quillIcons.header, 2: iconSvg(IconHeading2), 3: iconSvg(IconHeading3) },
|
|
161
|
+
list: { ...quillIcons.list, ordered: iconSvg(IconListOrdered), bullet: iconSvg(IconList), check: iconSvg(IconListChecks) },
|
|
162
|
+
align: { ...quillIcons.align, '': iconSvg(IconAlignLeft), center: iconSvg(IconAlignCenter), right: iconSvg(IconAlignRight), justify: iconSvg(IconAlignJustify) },
|
|
163
|
+
});
|
|
164
|
+
|
|
134
165
|
|
|
135
166
|
const updaterQueue = new AsyncQueue();
|
|
136
167
|
|
|
@@ -630,34 +661,61 @@ function removeCompletionOnBlur() {
|
|
|
630
661
|
|
|
631
662
|
.af-quill-editor {
|
|
632
663
|
|
|
664
|
+
// the toolbar sits on a hairline over the text, its buttons are quiet like AFCL ghost icon buttons
|
|
633
665
|
.ql-toolbar.ql-snow[class] {
|
|
634
|
-
border:
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
666
|
+
@apply flex flex-wrap items-center gap-0.5 border-0 border-b border-lightInputBorder px-1.5 py-1 dark:border-darkInputBorder;
|
|
667
|
+
font-family: inherit;
|
|
668
|
+
|
|
669
|
+
.ql-formats {
|
|
670
|
+
@apply inline-flex items-center gap-0.5 mr-2;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
button, .ql-picker-label {
|
|
674
|
+
@apply w-7 h-7 p-1.5 rounded-default border-0 text-lightInputIconColor transition-colors dark:text-darkInputIconColor;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
button svg, .ql-picker-label svg {
|
|
678
|
+
@apply w-4 h-4;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
button:hover, .ql-picker-label:hover {
|
|
682
|
+
@apply bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
button.ql-active, .ql-picker-label.ql-active, .ql-picker-item.ql-selected {
|
|
686
|
+
@apply text-lightPrimary dark:text-darkPrimary;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.ql-picker.ql-icon-picker {
|
|
690
|
+
@apply w-7 h-7;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.ql-picker-options {
|
|
694
|
+
@apply p-1 rounded-lg border-0 bg-lightDropdownOptionsBackground shadow-popover dark:bg-darkDropdownOptionsBackground dark:shadow-darkPopover;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.ql-picker-item {
|
|
698
|
+
@apply w-7 h-7 p-1.5 rounded-md text-lightInputIconColor hover:bg-lightDropdownOptionsHoverBackground hover:text-lightInputText dark:text-darkInputIconColor dark:hover:bg-darkDropdownOptionsHoverBackground dark:hover:text-darkInputText;
|
|
638
699
|
}
|
|
639
700
|
}
|
|
640
701
|
|
|
641
702
|
.ql-container {
|
|
642
703
|
border: 0;
|
|
704
|
+
font-family: inherit;
|
|
705
|
+
font-size: inherit;
|
|
706
|
+
|
|
643
707
|
.ql-editor {
|
|
644
708
|
position: relative;
|
|
645
|
-
|
|
709
|
+
@apply px-3 py-2.5 text-sm;
|
|
646
710
|
min-height: 100px;
|
|
647
711
|
&.ql-blank::before {
|
|
648
|
-
left:
|
|
649
|
-
font-style: normal;
|
|
712
|
+
@apply left-3 right-3 not-italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
|
|
650
713
|
}
|
|
651
714
|
}
|
|
652
715
|
}
|
|
653
716
|
|
|
654
|
-
// .ql-editor:not(:focus) [completer] {
|
|
655
|
-
// display: none;
|
|
656
|
-
// }
|
|
657
|
-
|
|
658
717
|
.ql-editor [completer] {
|
|
659
|
-
|
|
660
|
-
font-style: italic;
|
|
718
|
+
@apply italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
|
|
661
719
|
}
|
|
662
720
|
|
|
663
721
|
// basic typography
|
|
@@ -690,23 +748,21 @@ function removeCompletionOnBlur() {
|
|
|
690
748
|
/* Horizontal rule */
|
|
691
749
|
hr {
|
|
692
750
|
margin: 0.8rem 0;
|
|
693
|
-
border:
|
|
694
|
-
border-top: 1px solid #ddd;
|
|
751
|
+
@apply border-0 border-t border-lightInputBorder dark:border-darkInputBorder;
|
|
695
752
|
}
|
|
696
753
|
|
|
697
754
|
/* Blockquotes */
|
|
698
755
|
blockquote {
|
|
699
756
|
margin: 0.8rem 0;
|
|
700
757
|
padding-left: 0.8rem;
|
|
701
|
-
border-
|
|
758
|
+
@apply border-0 border-l-2 border-lightInputBorder text-lightInputIconColor dark:border-darkInputBorder dark:text-darkInputIconColor;
|
|
702
759
|
}
|
|
703
760
|
|
|
704
761
|
/* Preformatted text */
|
|
705
762
|
pre {
|
|
706
763
|
margin: 0.8rem 0;
|
|
707
764
|
padding: 0.4rem;
|
|
708
|
-
|
|
709
|
-
border-radius: 3px;
|
|
765
|
+
@apply rounded bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
|
|
710
766
|
}
|
|
711
767
|
|
|
712
768
|
/* Tables */
|
|
@@ -717,11 +773,11 @@ function removeCompletionOnBlur() {
|
|
|
717
773
|
|
|
718
774
|
th, td {
|
|
719
775
|
padding: 0.3rem;
|
|
720
|
-
border
|
|
776
|
+
@apply border border-lightInputBorder dark:border-darkInputBorder;
|
|
721
777
|
}
|
|
722
778
|
|
|
723
779
|
thead th {
|
|
724
|
-
border-
|
|
780
|
+
@apply border-b-2;
|
|
725
781
|
}
|
|
726
782
|
|
|
727
783
|
/* Images */
|
|
@@ -732,27 +788,21 @@ function removeCompletionOnBlur() {
|
|
|
732
788
|
}
|
|
733
789
|
}
|
|
734
790
|
|
|
791
|
+
// Quill's own icons which are left (table menus) follow the muted icon color too
|
|
735
792
|
.ql-snow .ql-stroke {
|
|
736
|
-
@apply dark:stroke-
|
|
737
|
-
@apply stroke-lightPrimary;
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
.ql-snow button:hover .ql-stroke,
|
|
741
|
-
.ql-snow [role="button"]:hover .ql-stroke {
|
|
742
|
-
@apply dark:stroke-darkPrimary;
|
|
743
|
-
@apply stroke-lightPrimary;
|
|
744
|
-
filter: brightness(1.3);
|
|
793
|
+
@apply stroke-lightInputIconColor dark:stroke-darkInputIconColor;
|
|
745
794
|
}
|
|
746
795
|
|
|
747
796
|
.ql-snow .ql-fill {
|
|
748
|
-
@apply dark:fill-
|
|
749
|
-
@apply fill-lightPrimary;
|
|
797
|
+
@apply fill-lightInputIconColor dark:fill-darkInputIconColor;
|
|
750
798
|
}
|
|
751
799
|
|
|
752
|
-
.ql-snow
|
|
753
|
-
@apply dark:
|
|
754
|
-
|
|
755
|
-
|
|
800
|
+
.ql-snow .ql-active .ql-stroke {
|
|
801
|
+
@apply stroke-lightPrimary dark:stroke-darkPrimary;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.ql-snow .ql-active .ql-fill {
|
|
805
|
+
@apply fill-lightPrimary dark:fill-darkPrimary;
|
|
756
806
|
}
|
|
757
807
|
|
|
758
808
|
}
|
|
@@ -779,11 +829,6 @@ function removeCompletionOnBlur() {
|
|
|
779
829
|
}
|
|
780
830
|
}
|
|
781
831
|
|
|
782
|
-
.ql-table-better svg path {
|
|
783
|
-
@apply dark:fill-darkPrimary;
|
|
784
|
-
@apply fill-lightPrimary;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
832
|
.ql-table-select-container {
|
|
788
833
|
@apply dark:bg-darkForm;
|
|
789
834
|
@apply bg-lightForm;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="wasQuillInitializedSuccessfully"
|
|
4
|
-
class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
class="af-quill-editor block w-full whitespace-normal rounded-default border shadow-customLight transition-colors
|
|
5
|
+
bg-lightInputBackground text-lightInputText border-lightInputBorder hover:border-lightInputBorderHover
|
|
6
|
+
focus-within:border-lightInputFocusBorder focus-within:ring-[3px] focus-within:ring-lightInputFocusRing
|
|
7
|
+
dark:bg-darkInputBackground dark:text-darkInputText dark:border-darkInputBorder dark:hover:border-darkInputBorderHover
|
|
8
|
+
dark:focus-within:border-darkInputFocusBorder dark:focus-within:ring-darkInputFocusRing"
|
|
8
9
|
>
|
|
9
10
|
<div
|
|
10
11
|
ref="editor"
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
</template>
|
|
29
30
|
|
|
30
31
|
<script setup lang="ts">
|
|
31
|
-
import { onMounted, ref, onUnmounted, watch, type Ref } from "vue";
|
|
32
|
+
import { onMounted, ref, onUnmounted, watch, h, render, type Ref, type FunctionalComponent } from "vue";
|
|
32
33
|
import { callAdminForthApi } from '@/utils';
|
|
33
34
|
import { AdminForthColumnCommon } from '@/types/Common';
|
|
34
35
|
import adminforth from '@/adminforth';
|
|
@@ -39,6 +40,11 @@ import "quill/dist/quill.snow.css";
|
|
|
39
40
|
import QuillTableBetter from 'quill-table-better-yaroslav8765';
|
|
40
41
|
import 'quill-table-better-yaroslav8765/dist/quill-table-better.css';
|
|
41
42
|
import { Textarea } from '@/afcl'
|
|
43
|
+
import {
|
|
44
|
+
IconAlignCenter, IconAlignJustify, IconAlignLeft, IconAlignRight, IconBold, IconCode, IconHeading2, IconHeading3,
|
|
45
|
+
IconImage, IconItalic, IconLink, IconList, IconListChecks, IconListOrdered, IconRemoveFormatting, IconStrikethrough,
|
|
46
|
+
IconTable, IconTextQuote, IconUnderline,
|
|
47
|
+
} from '@iconify-prerendered/vue-lucide';
|
|
42
48
|
|
|
43
49
|
import { useI18n } from 'vue-i18n';
|
|
44
50
|
import { ok } from "assert";
|
|
@@ -131,6 +137,31 @@ Quill.register({
|
|
|
131
137
|
'modules/table-better': QuillTableBetter
|
|
132
138
|
}, true);
|
|
133
139
|
|
|
140
|
+
// the toolbar draws Lucide icons like the rest of the UI; Quill takes icons as SVG strings,
|
|
141
|
+
// so they are set after the table module registered its own one
|
|
142
|
+
function iconSvg(icon: FunctionalComponent) {
|
|
143
|
+
const holder = document.createElement('div');
|
|
144
|
+
render(h(icon), holder);
|
|
145
|
+
return holder.innerHTML;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const quillIcons = Quill.import('ui/icons') as Record<string, any>;
|
|
149
|
+
Object.assign(quillIcons, {
|
|
150
|
+
bold: iconSvg(IconBold),
|
|
151
|
+
italic: iconSvg(IconItalic),
|
|
152
|
+
underline: iconSvg(IconUnderline),
|
|
153
|
+
strike: iconSvg(IconStrikethrough),
|
|
154
|
+
'table-better': iconSvg(IconTable),
|
|
155
|
+
blockquote: iconSvg(IconTextQuote),
|
|
156
|
+
'code-block': iconSvg(IconCode),
|
|
157
|
+
link: iconSvg(IconLink),
|
|
158
|
+
image: iconSvg(IconImage),
|
|
159
|
+
clean: iconSvg(IconRemoveFormatting),
|
|
160
|
+
header: { ...quillIcons.header, 2: iconSvg(IconHeading2), 3: iconSvg(IconHeading3) },
|
|
161
|
+
list: { ...quillIcons.list, ordered: iconSvg(IconListOrdered), bullet: iconSvg(IconList), check: iconSvg(IconListChecks) },
|
|
162
|
+
align: { ...quillIcons.align, '': iconSvg(IconAlignLeft), center: iconSvg(IconAlignCenter), right: iconSvg(IconAlignRight), justify: iconSvg(IconAlignJustify) },
|
|
163
|
+
});
|
|
164
|
+
|
|
134
165
|
|
|
135
166
|
const updaterQueue = new AsyncQueue();
|
|
136
167
|
|
|
@@ -630,34 +661,61 @@ function removeCompletionOnBlur() {
|
|
|
630
661
|
|
|
631
662
|
.af-quill-editor {
|
|
632
663
|
|
|
664
|
+
// the toolbar sits on a hairline over the text, its buttons are quiet like AFCL ghost icon buttons
|
|
633
665
|
.ql-toolbar.ql-snow[class] {
|
|
634
|
-
border:
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
666
|
+
@apply flex flex-wrap items-center gap-0.5 border-0 border-b border-lightInputBorder px-1.5 py-1 dark:border-darkInputBorder;
|
|
667
|
+
font-family: inherit;
|
|
668
|
+
|
|
669
|
+
.ql-formats {
|
|
670
|
+
@apply inline-flex items-center gap-0.5 mr-2;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
button, .ql-picker-label {
|
|
674
|
+
@apply w-7 h-7 p-1.5 rounded-default border-0 text-lightInputIconColor transition-colors dark:text-darkInputIconColor;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
button svg, .ql-picker-label svg {
|
|
678
|
+
@apply w-4 h-4;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
button:hover, .ql-picker-label:hover {
|
|
682
|
+
@apply bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
button.ql-active, .ql-picker-label.ql-active, .ql-picker-item.ql-selected {
|
|
686
|
+
@apply text-lightPrimary dark:text-darkPrimary;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.ql-picker.ql-icon-picker {
|
|
690
|
+
@apply w-7 h-7;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.ql-picker-options {
|
|
694
|
+
@apply p-1 rounded-lg border-0 bg-lightDropdownOptionsBackground shadow-popover dark:bg-darkDropdownOptionsBackground dark:shadow-darkPopover;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.ql-picker-item {
|
|
698
|
+
@apply w-7 h-7 p-1.5 rounded-md text-lightInputIconColor hover:bg-lightDropdownOptionsHoverBackground hover:text-lightInputText dark:text-darkInputIconColor dark:hover:bg-darkDropdownOptionsHoverBackground dark:hover:text-darkInputText;
|
|
638
699
|
}
|
|
639
700
|
}
|
|
640
701
|
|
|
641
702
|
.ql-container {
|
|
642
703
|
border: 0;
|
|
704
|
+
font-family: inherit;
|
|
705
|
+
font-size: inherit;
|
|
706
|
+
|
|
643
707
|
.ql-editor {
|
|
644
708
|
position: relative;
|
|
645
|
-
|
|
709
|
+
@apply px-3 py-2.5 text-sm;
|
|
646
710
|
min-height: 100px;
|
|
647
711
|
&.ql-blank::before {
|
|
648
|
-
left:
|
|
649
|
-
font-style: normal;
|
|
712
|
+
@apply left-3 right-3 not-italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
|
|
650
713
|
}
|
|
651
714
|
}
|
|
652
715
|
}
|
|
653
716
|
|
|
654
|
-
// .ql-editor:not(:focus) [completer] {
|
|
655
|
-
// display: none;
|
|
656
|
-
// }
|
|
657
|
-
|
|
658
717
|
.ql-editor [completer] {
|
|
659
|
-
|
|
660
|
-
font-style: italic;
|
|
718
|
+
@apply italic text-lightInputPlaceholderText dark:text-darkInputPlaceholderText;
|
|
661
719
|
}
|
|
662
720
|
|
|
663
721
|
// basic typography
|
|
@@ -690,23 +748,21 @@ function removeCompletionOnBlur() {
|
|
|
690
748
|
/* Horizontal rule */
|
|
691
749
|
hr {
|
|
692
750
|
margin: 0.8rem 0;
|
|
693
|
-
border:
|
|
694
|
-
border-top: 1px solid #ddd;
|
|
751
|
+
@apply border-0 border-t border-lightInputBorder dark:border-darkInputBorder;
|
|
695
752
|
}
|
|
696
753
|
|
|
697
754
|
/* Blockquotes */
|
|
698
755
|
blockquote {
|
|
699
756
|
margin: 0.8rem 0;
|
|
700
757
|
padding-left: 0.8rem;
|
|
701
|
-
border-
|
|
758
|
+
@apply border-0 border-l-2 border-lightInputBorder text-lightInputIconColor dark:border-darkInputBorder dark:text-darkInputIconColor;
|
|
702
759
|
}
|
|
703
760
|
|
|
704
761
|
/* Preformatted text */
|
|
705
762
|
pre {
|
|
706
763
|
margin: 0.8rem 0;
|
|
707
764
|
padding: 0.4rem;
|
|
708
|
-
|
|
709
|
-
border-radius: 3px;
|
|
765
|
+
@apply rounded bg-lightSecondaryDarken text-lightInputText dark:bg-darkSecondaryLighten dark:text-darkInputText;
|
|
710
766
|
}
|
|
711
767
|
|
|
712
768
|
/* Tables */
|
|
@@ -717,11 +773,11 @@ function removeCompletionOnBlur() {
|
|
|
717
773
|
|
|
718
774
|
th, td {
|
|
719
775
|
padding: 0.3rem;
|
|
720
|
-
border
|
|
776
|
+
@apply border border-lightInputBorder dark:border-darkInputBorder;
|
|
721
777
|
}
|
|
722
778
|
|
|
723
779
|
thead th {
|
|
724
|
-
border-
|
|
780
|
+
@apply border-b-2;
|
|
725
781
|
}
|
|
726
782
|
|
|
727
783
|
/* Images */
|
|
@@ -732,27 +788,21 @@ function removeCompletionOnBlur() {
|
|
|
732
788
|
}
|
|
733
789
|
}
|
|
734
790
|
|
|
791
|
+
// Quill's own icons which are left (table menus) follow the muted icon color too
|
|
735
792
|
.ql-snow .ql-stroke {
|
|
736
|
-
@apply dark:stroke-
|
|
737
|
-
@apply stroke-lightPrimary;
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
.ql-snow button:hover .ql-stroke,
|
|
741
|
-
.ql-snow [role="button"]:hover .ql-stroke {
|
|
742
|
-
@apply dark:stroke-darkPrimary;
|
|
743
|
-
@apply stroke-lightPrimary;
|
|
744
|
-
filter: brightness(1.3);
|
|
793
|
+
@apply stroke-lightInputIconColor dark:stroke-darkInputIconColor;
|
|
745
794
|
}
|
|
746
795
|
|
|
747
796
|
.ql-snow .ql-fill {
|
|
748
|
-
@apply dark:fill-
|
|
749
|
-
@apply fill-lightPrimary;
|
|
797
|
+
@apply fill-lightInputIconColor dark:fill-darkInputIconColor;
|
|
750
798
|
}
|
|
751
799
|
|
|
752
|
-
.ql-snow
|
|
753
|
-
@apply dark:
|
|
754
|
-
|
|
755
|
-
|
|
800
|
+
.ql-snow .ql-active .ql-stroke {
|
|
801
|
+
@apply stroke-lightPrimary dark:stroke-darkPrimary;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.ql-snow .ql-active .ql-fill {
|
|
805
|
+
@apply fill-lightPrimary dark:fill-darkPrimary;
|
|
756
806
|
}
|
|
757
807
|
|
|
758
808
|
}
|
|
@@ -779,11 +829,6 @@ function removeCompletionOnBlur() {
|
|
|
779
829
|
}
|
|
780
830
|
}
|
|
781
831
|
|
|
782
|
-
.ql-table-better svg path {
|
|
783
|
-
@apply dark:fill-darkPrimary;
|
|
784
|
-
@apply fill-lightPrimary;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
832
|
.ql-table-select-container {
|
|
788
833
|
@apply dark:bg-darkForm;
|
|
789
834
|
@apply bg-lightForm;
|
package/dist/index.js
CHANGED
|
@@ -135,9 +135,9 @@ export default class RichEditorPlugin extends AdminForthPlugin {
|
|
|
135
135
|
}));
|
|
136
136
|
// after edit we need to delete attachments that are not in the html anymore
|
|
137
137
|
// and add new ones
|
|
138
|
-
(resourceConfig.hooks.edit.afterSave).push((_a) => __awaiter(this, [_a], void 0, function* ({ recordId,
|
|
139
|
-
process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, '
|
|
140
|
-
if (
|
|
138
|
+
(resourceConfig.hooks.edit.afterSave).push((_a) => __awaiter(this, [_a], void 0, function* ({ recordId, updates, adminUser }) {
|
|
139
|
+
process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'updates', updates);
|
|
140
|
+
if (updates[this.options.htmlFieldName] === undefined) {
|
|
141
141
|
// field was not changed, do nothing
|
|
142
142
|
return { ok: true };
|
|
143
143
|
}
|
|
@@ -146,7 +146,7 @@ export default class RichEditorPlugin extends AdminForthPlugin {
|
|
|
146
146
|
Filters.EQ(this.options.attachments.attachmentResourceIdFieldName, resourceConfig.resourceId)
|
|
147
147
|
]);
|
|
148
148
|
const existingS3Paths = existingAparts.map((a) => a[this.options.attachments.attachmentFieldName]);
|
|
149
|
-
const newS3Paths = getAttachmentPathes(
|
|
149
|
+
const newS3Paths = getAttachmentPathes(updates[this.options.htmlFieldName]);
|
|
150
150
|
process.env.HEAVY_DEBUG && console.log('📸 Existing s3Paths (from db)', existingS3Paths);
|
|
151
151
|
process.env.HEAVY_DEBUG && console.log('📸 Found new s3Paths (from text)', newS3Paths);
|
|
152
152
|
const toDelete = existingS3Paths.filter(s3Path => !newS3Paths.includes(s3Path));
|
package/index.ts
CHANGED
|
@@ -172,9 +172,9 @@ export default class RichEditorPlugin extends AdminForthPlugin {
|
|
|
172
172
|
// after edit we need to delete attachments that are not in the html anymore
|
|
173
173
|
// and add new ones
|
|
174
174
|
(resourceConfig.hooks.edit.afterSave).push(
|
|
175
|
-
async ({ recordId,
|
|
176
|
-
process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, '
|
|
177
|
-
if (
|
|
175
|
+
async ({ recordId, updates, adminUser }: { recordId: any, updates: any, adminUser: AdminUser }) => {
|
|
176
|
+
process.env.HEAVY_DEBUG && console.log('⚓ Cought hook', recordId, 'updates', updates);
|
|
177
|
+
if (updates[this.options.htmlFieldName] === undefined) {
|
|
178
178
|
// field was not changed, do nothing
|
|
179
179
|
return { ok: true };
|
|
180
180
|
}
|
|
@@ -183,7 +183,7 @@ export default class RichEditorPlugin extends AdminForthPlugin {
|
|
|
183
183
|
Filters.EQ(this.options.attachments.attachmentResourceIdFieldName, resourceConfig.resourceId)
|
|
184
184
|
]);
|
|
185
185
|
const existingS3Paths = existingAparts.map((a: any) => a[this.options.attachments.attachmentFieldName]);
|
|
186
|
-
const newS3Paths = getAttachmentPathes(
|
|
186
|
+
const newS3Paths = getAttachmentPathes(updates[this.options.htmlFieldName]);
|
|
187
187
|
process.env.HEAVY_DEBUG && console.log('📸 Existing s3Paths (from db)', existingS3Paths)
|
|
188
188
|
process.env.HEAVY_DEBUG && console.log('📸 Found new s3Paths (from text)', newS3Paths);
|
|
189
189
|
const toDelete = existingS3Paths.filter(s3Path => !newS3Paths.includes(s3Path));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adminforth/rich-editor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Rich editor plugin for adminforth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"zod": "^4.3.6"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"adminforth": "^
|
|
30
|
+
"adminforth": "^4.4.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.10.7",
|
|
34
|
-
"adminforth": "^
|
|
34
|
+
"adminforth": "^4.7.3",
|
|
35
35
|
"semantic-release": "^24.2.1",
|
|
36
36
|
"semantic-release-slack-bot": "^4.0.2",
|
|
37
37
|
"typescript": "^5.7.3"
|