@adminforth/markdown 1.11.1 → 1.12.0
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/build.log +2 -2
- package/custom/MarkdownRenderer.vue +123 -33
- package/dist/custom/MarkdownRenderer.vue +123 -33
- package/dist/index.js +8 -4
- package/index.ts +4 -0
- package/package.json +1 -1
- package/types.ts +12 -0
package/build.log
CHANGED
|
@@ -14,5 +14,5 @@ custom/tsconfig.json
|
|
|
14
14
|
custom/utils/
|
|
15
15
|
custom/utils/monacoMarkdownToggle.ts
|
|
16
16
|
|
|
17
|
-
sent
|
|
18
|
-
total size is
|
|
17
|
+
sent 55,455 bytes received 180 bytes 111,270.00 bytes/sec
|
|
18
|
+
total size is 54,773 speedup is 0.98
|
|
@@ -1,39 +1,121 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
2
|
+
<div>
|
|
3
|
+
<div
|
|
4
|
+
:class="{ 'overflow-hidden': !expanded && isOverflowing }"
|
|
5
|
+
:style="!expanded && isOverflowing ? computedMaxHeight : {}"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
ref="contentRef"
|
|
9
|
+
v-html="purifiedHtml"
|
|
10
|
+
class="prose
|
|
11
|
+
prose-p:my-0
|
|
12
|
+
prose-headings:my-0
|
|
13
|
+
prose-h1:text-[1.6rem]
|
|
14
|
+
prose-ul:my-0
|
|
15
|
+
prose-ol:my-0
|
|
16
|
+
prose-li:my-0
|
|
17
|
+
prose-pre:my-0
|
|
18
|
+
prose-hr:my-1
|
|
19
|
+
prose-table:my-0
|
|
20
|
+
leading-none
|
|
21
|
+
dark: dark:text-gray-300
|
|
22
|
+
dark:[&_th]:text-white
|
|
23
|
+
dark:[&_td]:text-white
|
|
24
|
+
dark:[&_thead]:border-b-gray-600
|
|
25
|
+
dark:[&_code]:text-white
|
|
26
|
+
dark:[&_h1]:text-white dark:[&_h2]:text-gray-100 dark:[&_h3]:text-gray-200
|
|
27
|
+
dark:[&_a]:text-white dark:[&_a:hover]:text-white
|
|
28
|
+
dark:[&_pre]:bg-black dark:[&_pre]:border dark:[&_border-slate-800]
|
|
29
|
+
dark:[&_strong]:text-white
|
|
30
|
+
dark:[&_em]:text-gray-400
|
|
31
|
+
dark:[&_del]:text-gray-600"
|
|
32
|
+
:class="compactPreviewStyles"
|
|
33
|
+
></div>
|
|
34
|
+
</div>
|
|
35
|
+
<button
|
|
36
|
+
v-if="isOverflowing || expanded"
|
|
37
|
+
@click="expanded = !expanded"
|
|
38
|
+
class="mt-1 text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 font-medium focus:outline-none hover:underline"
|
|
39
|
+
>
|
|
40
|
+
{{ expanded ? 'Show less' : 'Show more' }}
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { computed, ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
|
47
|
+
import { marked } from "marked";
|
|
48
|
+
import DOMPurify from "dompurify";
|
|
34
49
|
|
|
35
|
-
const
|
|
50
|
+
const props = defineProps<{
|
|
51
|
+
column: any;
|
|
52
|
+
record: any;
|
|
53
|
+
meta: {
|
|
54
|
+
pluginInstanceId: string;
|
|
55
|
+
compactShowPreview?: boolean;
|
|
56
|
+
maxShowViewContainerHeightPx?: number;
|
|
57
|
+
}
|
|
58
|
+
}>();
|
|
59
|
+
|
|
60
|
+
const compactPreviewStyles = computed(() => {
|
|
61
|
+
if (props.meta.compactShowPreview) {
|
|
62
|
+
return `
|
|
63
|
+
prose-ul:leading-[0.2]
|
|
64
|
+
prose-ol:leading-[0.2]
|
|
65
|
+
prose-li:leading-[1]
|
|
66
|
+
prose-h1:leading-none
|
|
67
|
+
prose-h2:leading-none
|
|
68
|
+
prose-h3:leading-none
|
|
69
|
+
prose-h1:text-[1.3rem]
|
|
70
|
+
prose-h2:text-[1.2rem]
|
|
71
|
+
prose-h3:text-[1.1rem]
|
|
72
|
+
prose-blockquote:my-0
|
|
73
|
+
`
|
|
74
|
+
} else {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const computedMaxHeight = computed(() => {
|
|
80
|
+
if (props.meta.maxShowViewContainerHeightPx) {
|
|
81
|
+
return { maxHeight: `${props.meta.maxShowViewContainerHeightPx}px` };
|
|
82
|
+
}
|
|
83
|
+
return {};
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const contentRef = ref<HTMLElement | null>(null);
|
|
87
|
+
const expanded = ref(false);
|
|
88
|
+
const isOverflowing = ref(false);
|
|
36
89
|
|
|
90
|
+
let resizeObserver: ResizeObserver | null = null;
|
|
91
|
+
|
|
92
|
+
function checkOverflow() {
|
|
93
|
+
if (!props.meta.maxShowViewContainerHeightPx || !contentRef.value) {
|
|
94
|
+
isOverflowing.value = false;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
isOverflowing.value = contentRef.value.scrollHeight > props.meta.maxShowViewContainerHeightPx;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function setupObserver() {
|
|
101
|
+
resizeObserver?.disconnect();
|
|
102
|
+
if (!props.meta.maxShowViewContainerHeightPx || !contentRef.value) return;
|
|
103
|
+
|
|
104
|
+
resizeObserver = new ResizeObserver(() => checkOverflow());
|
|
105
|
+
resizeObserver.observe(contentRef.value);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
onMounted(async () => {
|
|
109
|
+
await nextTick();
|
|
110
|
+
checkOverflow();
|
|
111
|
+
setupObserver();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
onBeforeUnmount(() => {
|
|
115
|
+
resizeObserver?.disconnect();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const purifiedHtml = computed(() => {
|
|
37
119
|
if (!props.record[props.column.name]) return '-';
|
|
38
120
|
const html = marked(String(props.record[props.column.name]));
|
|
39
121
|
if (html instanceof Promise) {
|
|
@@ -42,5 +124,13 @@
|
|
|
42
124
|
}
|
|
43
125
|
return DOMPurify.sanitize(html);
|
|
44
126
|
});
|
|
127
|
+
|
|
128
|
+
// Re-check overflow whenever content changes
|
|
129
|
+
watch(purifiedHtml, async () => {
|
|
130
|
+
expanded.value = false;
|
|
131
|
+
await nextTick();
|
|
132
|
+
checkOverflow();
|
|
133
|
+
setupObserver();
|
|
134
|
+
});
|
|
45
135
|
</script>
|
|
46
136
|
|
|
@@ -1,39 +1,121 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
2
|
+
<div>
|
|
3
|
+
<div
|
|
4
|
+
:class="{ 'overflow-hidden': !expanded && isOverflowing }"
|
|
5
|
+
:style="!expanded && isOverflowing ? computedMaxHeight : {}"
|
|
6
|
+
>
|
|
7
|
+
<div
|
|
8
|
+
ref="contentRef"
|
|
9
|
+
v-html="purifiedHtml"
|
|
10
|
+
class="prose
|
|
11
|
+
prose-p:my-0
|
|
12
|
+
prose-headings:my-0
|
|
13
|
+
prose-h1:text-[1.6rem]
|
|
14
|
+
prose-ul:my-0
|
|
15
|
+
prose-ol:my-0
|
|
16
|
+
prose-li:my-0
|
|
17
|
+
prose-pre:my-0
|
|
18
|
+
prose-hr:my-1
|
|
19
|
+
prose-table:my-0
|
|
20
|
+
leading-none
|
|
21
|
+
dark: dark:text-gray-300
|
|
22
|
+
dark:[&_th]:text-white
|
|
23
|
+
dark:[&_td]:text-white
|
|
24
|
+
dark:[&_thead]:border-b-gray-600
|
|
25
|
+
dark:[&_code]:text-white
|
|
26
|
+
dark:[&_h1]:text-white dark:[&_h2]:text-gray-100 dark:[&_h3]:text-gray-200
|
|
27
|
+
dark:[&_a]:text-white dark:[&_a:hover]:text-white
|
|
28
|
+
dark:[&_pre]:bg-black dark:[&_pre]:border dark:[&_border-slate-800]
|
|
29
|
+
dark:[&_strong]:text-white
|
|
30
|
+
dark:[&_em]:text-gray-400
|
|
31
|
+
dark:[&_del]:text-gray-600"
|
|
32
|
+
:class="compactPreviewStyles"
|
|
33
|
+
></div>
|
|
34
|
+
</div>
|
|
35
|
+
<button
|
|
36
|
+
v-if="isOverflowing || expanded"
|
|
37
|
+
@click="expanded = !expanded"
|
|
38
|
+
class="mt-1 text-sm text-primary-600 hover:text-primary-700 dark:text-primary-400 dark:hover:text-primary-300 font-medium focus:outline-none hover:underline"
|
|
39
|
+
>
|
|
40
|
+
{{ expanded ? 'Show less' : 'Show more' }}
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { computed, ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
|
47
|
+
import { marked } from "marked";
|
|
48
|
+
import DOMPurify from "dompurify";
|
|
34
49
|
|
|
35
|
-
const
|
|
50
|
+
const props = defineProps<{
|
|
51
|
+
column: any;
|
|
52
|
+
record: any;
|
|
53
|
+
meta: {
|
|
54
|
+
pluginInstanceId: string;
|
|
55
|
+
compactShowPreview?: boolean;
|
|
56
|
+
maxShowViewContainerHeightPx?: number;
|
|
57
|
+
}
|
|
58
|
+
}>();
|
|
59
|
+
|
|
60
|
+
const compactPreviewStyles = computed(() => {
|
|
61
|
+
if (props.meta.compactShowPreview) {
|
|
62
|
+
return `
|
|
63
|
+
prose-ul:leading-[0.2]
|
|
64
|
+
prose-ol:leading-[0.2]
|
|
65
|
+
prose-li:leading-[1]
|
|
66
|
+
prose-h1:leading-none
|
|
67
|
+
prose-h2:leading-none
|
|
68
|
+
prose-h3:leading-none
|
|
69
|
+
prose-h1:text-[1.3rem]
|
|
70
|
+
prose-h2:text-[1.2rem]
|
|
71
|
+
prose-h3:text-[1.1rem]
|
|
72
|
+
prose-blockquote:my-0
|
|
73
|
+
`
|
|
74
|
+
} else {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const computedMaxHeight = computed(() => {
|
|
80
|
+
if (props.meta.maxShowViewContainerHeightPx) {
|
|
81
|
+
return { maxHeight: `${props.meta.maxShowViewContainerHeightPx}px` };
|
|
82
|
+
}
|
|
83
|
+
return {};
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const contentRef = ref<HTMLElement | null>(null);
|
|
87
|
+
const expanded = ref(false);
|
|
88
|
+
const isOverflowing = ref(false);
|
|
36
89
|
|
|
90
|
+
let resizeObserver: ResizeObserver | null = null;
|
|
91
|
+
|
|
92
|
+
function checkOverflow() {
|
|
93
|
+
if (!props.meta.maxShowViewContainerHeightPx || !contentRef.value) {
|
|
94
|
+
isOverflowing.value = false;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
isOverflowing.value = contentRef.value.scrollHeight > props.meta.maxShowViewContainerHeightPx;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function setupObserver() {
|
|
101
|
+
resizeObserver?.disconnect();
|
|
102
|
+
if (!props.meta.maxShowViewContainerHeightPx || !contentRef.value) return;
|
|
103
|
+
|
|
104
|
+
resizeObserver = new ResizeObserver(() => checkOverflow());
|
|
105
|
+
resizeObserver.observe(contentRef.value);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
onMounted(async () => {
|
|
109
|
+
await nextTick();
|
|
110
|
+
checkOverflow();
|
|
111
|
+
setupObserver();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
onBeforeUnmount(() => {
|
|
115
|
+
resizeObserver?.disconnect();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const purifiedHtml = computed(() => {
|
|
37
119
|
if (!props.record[props.column.name]) return '-';
|
|
38
120
|
const html = marked(String(props.record[props.column.name]));
|
|
39
121
|
if (html instanceof Promise) {
|
|
@@ -42,5 +124,13 @@
|
|
|
42
124
|
}
|
|
43
125
|
return DOMPurify.sanitize(html);
|
|
44
126
|
});
|
|
127
|
+
|
|
128
|
+
// Re-check overflow whenever content changes
|
|
129
|
+
watch(purifiedHtml, async () => {
|
|
130
|
+
expanded.value = false;
|
|
131
|
+
await nextTick();
|
|
132
|
+
checkOverflow();
|
|
133
|
+
setupObserver();
|
|
134
|
+
});
|
|
45
135
|
</script>
|
|
46
136
|
|
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
54
54
|
modifyResourceConfig: { get: () => super.modifyResourceConfig }
|
|
55
55
|
});
|
|
56
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
var _a, _b, _c;
|
|
57
|
+
var _a, _b, _c, _d, _e;
|
|
58
58
|
_super.modifyResourceConfig.call(this, adminforth, resourceConfig);
|
|
59
59
|
this.resourceConfig = resourceConfig;
|
|
60
60
|
const fieldName = this.options.fieldName;
|
|
@@ -105,6 +105,8 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
105
105
|
meta: {
|
|
106
106
|
pluginInstanceId: this.pluginInstanceId,
|
|
107
107
|
columnName: fieldName,
|
|
108
|
+
compactShowPreview: (_a = this.options.compactShowPreview) !== null && _a !== void 0 ? _a : true,
|
|
109
|
+
maxShowViewContainerHeightPx: this.options.maxShowViewContainerHeightPx,
|
|
108
110
|
},
|
|
109
111
|
};
|
|
110
112
|
column.components.list = {
|
|
@@ -112,6 +114,8 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
112
114
|
meta: {
|
|
113
115
|
pluginInstanceId: this.pluginInstanceId,
|
|
114
116
|
columnName: fieldName,
|
|
117
|
+
compactShowPreview: (_b = this.options.compactShowPreview) !== null && _b !== void 0 ? _b : true,
|
|
118
|
+
maxShowViewContainerHeightPx: this.options.maxShowViewContainerHeightPx,
|
|
115
119
|
},
|
|
116
120
|
};
|
|
117
121
|
column.components.edit = {
|
|
@@ -119,7 +123,7 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
119
123
|
meta: {
|
|
120
124
|
pluginInstanceId: this.pluginInstanceId,
|
|
121
125
|
columnName: fieldName,
|
|
122
|
-
uploadPluginInstanceId: (
|
|
126
|
+
uploadPluginInstanceId: (_c = this.uploadPlugin) === null || _c === void 0 ? void 0 : _c.pluginInstanceId,
|
|
123
127
|
},
|
|
124
128
|
};
|
|
125
129
|
column.components.create = {
|
|
@@ -127,14 +131,14 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
127
131
|
meta: {
|
|
128
132
|
pluginInstanceId: this.pluginInstanceId,
|
|
129
133
|
columnName: fieldName,
|
|
130
|
-
uploadPluginInstanceId: (
|
|
134
|
+
uploadPluginInstanceId: (_d = this.uploadPlugin) === null || _d === void 0 ? void 0 : _d.pluginInstanceId,
|
|
131
135
|
},
|
|
132
136
|
};
|
|
133
137
|
const topPanelSettings = this.options.topPanelSettings || {};
|
|
134
138
|
const commonMeta = {
|
|
135
139
|
pluginInstanceId: this.pluginInstanceId,
|
|
136
140
|
columnName: fieldName,
|
|
137
|
-
uploadPluginInstanceId: (
|
|
141
|
+
uploadPluginInstanceId: (_e = this.uploadPlugin) === null || _e === void 0 ? void 0 : _e.pluginInstanceId,
|
|
138
142
|
topPanelSettings: topPanelSettings,
|
|
139
143
|
};
|
|
140
144
|
column.components.edit = {
|
package/index.ts
CHANGED
|
@@ -106,6 +106,8 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
106
106
|
meta: {
|
|
107
107
|
pluginInstanceId: this.pluginInstanceId,
|
|
108
108
|
columnName: fieldName,
|
|
109
|
+
compactShowPreview: this.options.compactShowPreview ?? true,
|
|
110
|
+
maxShowViewContainerHeightPx: this.options.maxShowViewContainerHeightPx,
|
|
109
111
|
},
|
|
110
112
|
};
|
|
111
113
|
|
|
@@ -114,6 +116,8 @@ export default class MarkdownPlugin extends AdminForthPlugin {
|
|
|
114
116
|
meta: {
|
|
115
117
|
pluginInstanceId: this.pluginInstanceId,
|
|
116
118
|
columnName: fieldName,
|
|
119
|
+
compactShowPreview: this.options.compactShowPreview ?? true,
|
|
120
|
+
maxShowViewContainerHeightPx: this.options.maxShowViewContainerHeightPx,
|
|
117
121
|
},
|
|
118
122
|
};
|
|
119
123
|
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -82,4 +82,16 @@ export interface PluginOptions {
|
|
|
82
82
|
link?: boolean;
|
|
83
83
|
codeBlock?: boolean;
|
|
84
84
|
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* When true, the preview will be shown in a compact mode with a "Show more" button if the content exceeds the specified max height.
|
|
88
|
+
* This allows users to expand and collapse the preview as needed, improving readability for long content.
|
|
89
|
+
* Default is true.
|
|
90
|
+
*/
|
|
91
|
+
compactShowPreview?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Maximum height in pixels for the preview container when `compactShowPreview` is enabled.
|
|
94
|
+
* If the content exceeds this height, a "Show more" button will appear to allow users to expand the preview.
|
|
95
|
+
*/
|
|
96
|
+
maxShowViewContainerHeightPx?: number;
|
|
85
97
|
}
|