@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 CHANGED
@@ -14,5 +14,5 @@ custom/tsconfig.json
14
14
  custom/utils/
15
15
  custom/utils/monacoMarkdownToggle.ts
16
16
 
17
- sent 52,947 bytes received 180 bytes 106,254.00 bytes/sec
18
- total size is 52,265 speedup is 0.98
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
- <div
3
- v-html="purifiedHtml"
4
- class="prose
5
- prose-p:my-0
6
- prose-headings:my-0
7
- prose-h1:text-[1.6rem]
8
- prose-ul:my-0
9
- prose-ol:my-0
10
- prose-li:my-0
11
- prose-pre:my-0
12
- prose-hr:my-1
13
- leading-tight
14
- dark: dark:text-gray-300
15
- dark:[&_th]:text-white
16
- dark:[&_td]:text-white
17
- dark:[&_thead]:border-b-gray-600
18
- dark:[&_code]:text-white
19
- dark:[&_h1]:text-white dark:[&_h2]:text-gray-100 dark:[&_h3]:text-gray-200
20
- dark:[&_a]:text-white dark:[&_a:hover]:text-white
21
- dark:[&_pre]:bg-black dark:[&_pre]:border dark:[&_border-slate-800]
22
- dark:[&_strong]:text-white
23
- dark:[&_em]:text-gray-400
24
- dark:[&_del]:text-gray-600">
25
- </div>
26
- </template>
27
-
28
- <script setup lang="ts">
29
- import { computed } from 'vue';
30
- import { marked } from "marked";
31
- import DOMPurify from "dompurify";
32
-
33
- const props = defineProps<{ column: any; record: any }>();
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 purifiedHtml = computed(() => {
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
- <div
3
- v-html="purifiedHtml"
4
- class="prose
5
- prose-p:my-0
6
- prose-headings:my-0
7
- prose-h1:text-[1.6rem]
8
- prose-ul:my-0
9
- prose-ol:my-0
10
- prose-li:my-0
11
- prose-pre:my-0
12
- prose-hr:my-1
13
- leading-tight
14
- dark: dark:text-gray-300
15
- dark:[&_th]:text-white
16
- dark:[&_td]:text-white
17
- dark:[&_thead]:border-b-gray-600
18
- dark:[&_code]:text-white
19
- dark:[&_h1]:text-white dark:[&_h2]:text-gray-100 dark:[&_h3]:text-gray-200
20
- dark:[&_a]:text-white dark:[&_a:hover]:text-white
21
- dark:[&_pre]:bg-black dark:[&_pre]:border dark:[&_border-slate-800]
22
- dark:[&_strong]:text-white
23
- dark:[&_em]:text-gray-400
24
- dark:[&_del]:text-gray-600">
25
- </div>
26
- </template>
27
-
28
- <script setup lang="ts">
29
- import { computed } from 'vue';
30
- import { marked } from "marked";
31
- import DOMPurify from "dompurify";
32
-
33
- const props = defineProps<{ column: any; record: any }>();
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 purifiedHtml = computed(() => {
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: (_a = this.uploadPlugin) === null || _a === void 0 ? void 0 : _a.pluginInstanceId,
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: (_b = this.uploadPlugin) === null || _b === void 0 ? void 0 : _b.pluginInstanceId,
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: (_c = this.uploadPlugin) === null || _c === void 0 ? void 0 : _c.pluginInstanceId,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/markdown",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "description": "Markdown plugin for adminforth",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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
  }