@airoom/nextmin-react 2.0.2 → 2.0.3
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 +57 -0
- package/dist/components/AddressAutocomplete.d.ts +4 -1
- package/dist/components/AddressAutocomplete.js +2 -2
- package/dist/components/AdminApp.js +86 -1
- package/dist/components/FileUploader.d.ts +3 -0
- package/dist/components/FileUploader.js +84 -28
- package/dist/components/PasswordInput.d.ts +2 -0
- package/dist/components/PasswordInput.js +2 -2
- package/dist/components/PhoneInput.d.ts +2 -0
- package/dist/components/PhoneInput.js +2 -2
- package/dist/components/QRCodeModal.d.ts +10 -0
- package/dist/components/QRCodeModal.js +153 -0
- package/dist/components/RefSelect.d.ts +4 -1
- package/dist/components/RefSelect.js +163 -65
- package/dist/components/SchemaForm.d.ts +2 -1
- package/dist/components/SchemaForm.js +132 -55
- package/dist/components/Sidebar.js +96 -7
- package/dist/components/TableFilters.js +1 -1
- package/dist/components/editor/TiptapEditor.js +43 -12
- package/dist/components/editor/Toolbar.js +195 -70
- package/dist/components/editor/components/CustomFontSizeModal.d.ts +13 -0
- package/dist/components/editor/components/CustomFontSizeModal.js +81 -0
- package/dist/components/editor/components/DistrictGridModal.js +1 -1
- package/dist/components/editor/components/SchemaInsertionModal.js +1 -1
- package/dist/components/editor/editor.css +2 -0
- package/dist/components/editor/extensions/FontSize.d.ts +19 -0
- package/dist/components/editor/extensions/FontSize.js +41 -0
- package/dist/components/viewer/DynamicViewer.js +50 -15
- package/dist/components/viewer/useViewDrawer.js +42 -2
- package/dist/hooks/useAppNavigation.d.ts +3 -0
- package/dist/hooks/useAppNavigation.js +37 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/lib/QueryBuilder.d.ts +3 -1
- package/dist/lib/QueryBuilder.js +10 -0
- package/dist/lib/api.d.ts +6 -0
- package/dist/lib/api.js +45 -24
- package/dist/lib/schemaUtils.js +1 -1
- package/dist/lib/types.d.ts +6 -1
- package/dist/nextmin.css +1 -1
- package/dist/providers/NextMinProvider.d.ts +5 -1
- package/dist/providers/NextMinProvider.js +12 -2
- package/dist/providers/themeResolver.d.ts +25 -0
- package/dist/providers/themeResolver.js +174 -0
- package/dist/router/NextMinRouter.d.ts +0 -1
- package/dist/router/NextMinRouter.js +0 -1
- package/dist/views/CreateEditPage.js +20 -11
- package/dist/views/DashboardPage.js +1 -1
- package/dist/views/ListPage.js +37 -6
- package/dist/views/SettingsEdit.js +1 -1
- package/dist/views/list/DataTableHero.d.ts +5 -5
- package/dist/views/list/DataTableHero.js +154 -41
- package/dist/views/list/ListHeader.js +9 -1
- package/package.json +4 -2
|
@@ -18,19 +18,37 @@ import TableHeader from '@tiptap/extension-table-header';
|
|
|
18
18
|
import { ResizableImage } from './extensions/ResizableImage';
|
|
19
19
|
import { GridContainer, GridItem } from './extensions/Grid';
|
|
20
20
|
import { LayoutRow, LayoutColumn } from './extensions/Layout';
|
|
21
|
+
import { FontSize } from './extensions/FontSize';
|
|
21
22
|
import { Toolbar } from './Toolbar';
|
|
22
23
|
import { cn } from '../../lib/utils';
|
|
23
24
|
// Styles for Tiptap
|
|
24
25
|
// Styles for Tiptap
|
|
25
26
|
// import '../../styles.css'; // REMOVED: CSS should be imported by consumer (see package.json exports)
|
|
26
27
|
import { SlashCommand, getSuggestionOptions } from './extensions/SlashCommand';
|
|
27
|
-
|
|
28
|
+
import { Extension } from '@tiptap/core';
|
|
28
29
|
import { SchemaInsertionModal } from './components/SchemaInsertionModal';
|
|
29
30
|
import { DistrictGridModal } from './components/DistrictGridModal';
|
|
30
31
|
import { ImageBubbleMenu } from './components/ImageBubbleMenu';
|
|
31
32
|
import { TableBubbleMenu } from './components/TableBubbleMenu';
|
|
32
33
|
import { Container } from './extensions/Container';
|
|
33
|
-
//
|
|
34
|
+
// Extension to clear inherited marks when pressing Enter at the end of a heading
|
|
35
|
+
const ClearMarksOnHeaderEnter = Extension.create({
|
|
36
|
+
name: 'clearMarksOnHeaderEnter',
|
|
37
|
+
addKeyboardShortcuts() {
|
|
38
|
+
return {
|
|
39
|
+
Enter: ({ editor }) => {
|
|
40
|
+
if (editor.isActive('heading')) {
|
|
41
|
+
const handled = editor.commands.splitBlock();
|
|
42
|
+
if (handled) {
|
|
43
|
+
editor.commands.unsetAllMarks();
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
});
|
|
34
52
|
export const TiptapEditor = ({ value, onChange, className, placeholder = 'Start writing...', availableSchemas = [], currentSpeciality }) => {
|
|
35
53
|
// State for schema insertion modal
|
|
36
54
|
const [selectedSchema, setSelectedSchema] = useState(null);
|
|
@@ -46,12 +64,16 @@ export const TiptapEditor = ({ value, onChange, className, placeholder = 'Start
|
|
|
46
64
|
StarterKit.configure({
|
|
47
65
|
heading: {
|
|
48
66
|
levels: [1, 2, 3, 4, 5, 6]
|
|
49
|
-
}
|
|
67
|
+
},
|
|
68
|
+
link: false,
|
|
69
|
+
underline: false,
|
|
50
70
|
}),
|
|
71
|
+
ClearMarksOnHeaderEnter,
|
|
51
72
|
Highlight.configure({
|
|
52
73
|
multicolor: true,
|
|
53
74
|
}),
|
|
54
75
|
TextStyle,
|
|
76
|
+
FontSize,
|
|
55
77
|
FontFamily,
|
|
56
78
|
Color,
|
|
57
79
|
Link.configure({
|
|
@@ -92,22 +114,31 @@ export const TiptapEditor = ({ value, onChange, className, placeholder = 'Start
|
|
|
92
114
|
editorProps: {
|
|
93
115
|
attributes: {
|
|
94
116
|
class: cn("prose prose-sm sm:prose-base dark:prose-invert focus:outline-none h-[500px] overflow-y-auto p-4 max-w-none [&_li_p]:m-0", className)
|
|
95
|
-
}
|
|
117
|
+
},
|
|
118
|
+
transformPastedHTML(html) {
|
|
119
|
+
let cleaned = html
|
|
120
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
121
|
+
.replace(/<o:p>[\s\S]*?<\/o:p>/gi, '')
|
|
122
|
+
.replace(/<\/?(xml|meta|link)[^>]*>/gi, '');
|
|
123
|
+
return cleaned;
|
|
124
|
+
},
|
|
96
125
|
},
|
|
97
126
|
onUpdate: ({ editor }) => {
|
|
98
127
|
onChange(editor.getHTML());
|
|
99
128
|
},
|
|
100
129
|
immediatelyRender: false,
|
|
101
130
|
});
|
|
102
|
-
//
|
|
131
|
+
// Sync editor content when value prop changes from outside
|
|
103
132
|
useEffect(() => {
|
|
104
|
-
if (editor && value !==
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
133
|
+
if (editor && value !== undefined) {
|
|
134
|
+
const currentHTML = editor.getHTML();
|
|
135
|
+
if (value !== currentHTML) {
|
|
136
|
+
// Do not reset if both are effectively empty
|
|
137
|
+
if ((editor.getText() === '' || currentHTML === '<p></p>') && (value === '' || value === '<p></p>'))
|
|
138
|
+
return;
|
|
139
|
+
if (!editor.isFocused) {
|
|
140
|
+
editor.commands.setContent(value || '', { emitUpdate: false });
|
|
141
|
+
}
|
|
111
142
|
}
|
|
112
143
|
}
|
|
113
144
|
}, [value, editor]);
|
|
@@ -1,103 +1,228 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React, { useRef, useState } from 'react';
|
|
4
|
+
import { RemoveFormatting, Bold, Italic, Underline as UnderlineIcon, Strikethrough, List, ListOrdered, Quote, Code, Code2, Undo, Redo, Image as ImageIcon, LayoutTemplate, LayoutPanelLeft, AlignLeft, AlignCenter, AlignRight, AlignJustify, Square, Table as TableIcon, Palette, PaintBucket, Type, MapPin, Link as LinkIcon, Minus, } from 'lucide-react';
|
|
4
5
|
import { cn } from '../../lib/utils';
|
|
5
6
|
import { uploadFile } from '../../lib/upload';
|
|
7
|
+
import { CustomFontSizeModal } from './components/CustomFontSizeModal';
|
|
8
|
+
// ─── Block Type Dropdown ─────────────────────────────────────────────────────
|
|
9
|
+
const BLOCK_TYPES = [
|
|
10
|
+
{ label: 'Paragraph', value: 'paragraph' },
|
|
11
|
+
{ label: 'Heading 1', value: 'h1' },
|
|
12
|
+
{ label: 'Heading 2', value: 'h2' },
|
|
13
|
+
{ label: 'Heading 3', value: 'h3' },
|
|
14
|
+
{ label: 'Heading 4', value: 'h4' },
|
|
15
|
+
{ label: 'Heading 5', value: 'h5' },
|
|
16
|
+
{ label: 'Heading 6', value: 'h6' },
|
|
17
|
+
];
|
|
18
|
+
function getActiveBlock(editor) {
|
|
19
|
+
for (let i = 1; i <= 6; i++) {
|
|
20
|
+
if (editor.isActive('heading', { level: i }))
|
|
21
|
+
return `h${i}`;
|
|
22
|
+
}
|
|
23
|
+
return 'paragraph';
|
|
24
|
+
}
|
|
25
|
+
function setBlock(editor, value) {
|
|
26
|
+
if (value === 'paragraph') {
|
|
27
|
+
editor.chain().focus().setParagraph().run();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const level = parseInt(value.replace('h', ''), 10);
|
|
31
|
+
editor.chain().focus().toggleHeading({ level }).unsetFontSize().run();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ─── Font Family List ─────────────────────────────────────────────────────────
|
|
35
|
+
const FONT_GROUPS = [
|
|
36
|
+
{
|
|
37
|
+
label: 'Default',
|
|
38
|
+
fonts: [
|
|
39
|
+
{ label: 'Default', value: 'default' },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'Sans-Serif',
|
|
44
|
+
fonts: [
|
|
45
|
+
{ label: 'Inter', value: "'Inter', sans-serif" },
|
|
46
|
+
{ label: 'Roboto', value: "'Roboto', sans-serif" },
|
|
47
|
+
{ label: 'Open Sans', value: "'Open Sans', sans-serif" },
|
|
48
|
+
{ label: 'Lato', value: "'Lato', sans-serif" },
|
|
49
|
+
{ label: 'Poppins', value: "'Poppins', sans-serif" },
|
|
50
|
+
{ label: 'Nunito', value: "'Nunito', sans-serif" },
|
|
51
|
+
{ label: 'Outfit', value: "'Outfit', sans-serif" },
|
|
52
|
+
{ label: 'DM Sans', value: "'DM Sans', sans-serif" },
|
|
53
|
+
{ label: 'Figtree', value: "'Figtree', sans-serif" },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Serif',
|
|
58
|
+
fonts: [
|
|
59
|
+
{ label: 'Georgia', value: "Georgia, serif" },
|
|
60
|
+
{ label: 'Playfair Display', value: "'Playfair Display', serif" },
|
|
61
|
+
{ label: 'Merriweather', value: "'Merriweather', serif" },
|
|
62
|
+
{ label: 'Lora', value: "'Lora', serif" },
|
|
63
|
+
{ label: 'EB Garamond', value: "'EB Garamond', serif" },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
label: 'Monospace',
|
|
68
|
+
fonts: [
|
|
69
|
+
{ label: 'Fira Code', value: "'Fira Code', monospace" },
|
|
70
|
+
{ label: 'JetBrains Mono', value: "'JetBrains Mono', monospace" },
|
|
71
|
+
{ label: 'Source Code Pro', value: "'Source Code Pro', monospace" },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: 'Bangla',
|
|
76
|
+
fonts: [
|
|
77
|
+
{ label: 'Hind Siliguri', value: "'Hind Siliguri', sans-serif" },
|
|
78
|
+
{ label: 'Noto Sans Bengali', value: "'Noto Sans Bengali', sans-serif" },
|
|
79
|
+
{ label: 'Kalpurush', value: "'Kalpurush', sans-serif" },
|
|
80
|
+
{ label: 'Siyam Rupali', value: "'Siyam Rupali', sans-serif" },
|
|
81
|
+
{ label: 'SolaimanLipi', value: "'SolaimanLipi', sans-serif" },
|
|
82
|
+
{ label: 'Akaash', value: "'Akaash', sans-serif" },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
// ─── Font Size List ──────────────────────────────────────────────────────────
|
|
87
|
+
const FONT_SIZES = [
|
|
88
|
+
{ label: 'Default size', value: 'default' },
|
|
89
|
+
{ label: '10px', value: '10px' },
|
|
90
|
+
{ label: '12px', value: '12px' },
|
|
91
|
+
{ label: '13px', value: '13px' },
|
|
92
|
+
{ label: '14px', value: '14px' },
|
|
93
|
+
{ label: '15px', value: '15px' },
|
|
94
|
+
{ label: '16px', value: '16px' },
|
|
95
|
+
{ label: '18px', value: '18px' },
|
|
96
|
+
{ label: '20px', value: '20px' },
|
|
97
|
+
{ label: '24px', value: '24px' },
|
|
98
|
+
{ label: '28px', value: '28px' },
|
|
99
|
+
{ label: '32px', value: '32px' },
|
|
100
|
+
{ label: '36px', value: '36px' },
|
|
101
|
+
{ label: '48px', value: '48px' },
|
|
102
|
+
{ label: '72px', value: '72px' },
|
|
103
|
+
{ label: 'Custom...', value: 'custom' },
|
|
104
|
+
];
|
|
105
|
+
// ─── Divider ──────────────────────────────────────────────────────────────────
|
|
106
|
+
const Divider = () => (_jsx("div", { className: "w-px h-5 bg-gray-200 dark:bg-gray-700 mx-0.5 flex-shrink-0" }));
|
|
107
|
+
// ─── Toolbar Button ───────────────────────────────────────────────────────────
|
|
108
|
+
const Btn = ({ onClick, isActive = false, disabled = false, title, children, }) => (_jsx("button", { onClick: onClick, disabled: disabled, title: title, type: "button", className: cn('inline-flex items-center justify-center w-7 h-7 rounded-md text-gray-600 dark:text-gray-300', 'transition-all duration-100', 'hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-white', isActive && 'bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400 ring-1 ring-blue-200 dark:ring-blue-800', disabled && 'opacity-30 cursor-not-allowed pointer-events-none'), children: children }));
|
|
109
|
+
// ─── Styled native select ─────────────────────────────────────────────────────
|
|
110
|
+
const NativeSelect = ({ value, onChange, className, children, title, }) => (_jsx("select", { title: title, value: value, onChange: e => onChange(e.target.value), className: cn('h-7 px-1.5 text-xs rounded-md border border-gray-200 dark:border-gray-700', 'bg-white dark:bg-zinc-900 text-gray-700 dark:text-gray-200', 'outline-none focus:ring-1 focus:ring-blue-400 cursor-pointer', 'appearance-none pr-5', className), style: { backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236b7280'/%3E%3C/svg%3E\")", backgroundRepeat: 'no-repeat', backgroundPosition: 'right 4px center' }, children: children }));
|
|
111
|
+
// ─── Main Toolbar ─────────────────────────────────────────────────────────────
|
|
6
112
|
export const Toolbar = ({ editor, onDistrictGridClick }) => {
|
|
7
113
|
const fileInputRef = useRef(null);
|
|
8
|
-
|
|
114
|
+
const [fontSizeInput, setFontSizeInput] = useState(null);
|
|
115
|
+
const [isCustomFontSizeModalOpen, setIsCustomFontSizeModalOpen] = useState(false);
|
|
116
|
+
const [, setTick] = useState(0);
|
|
117
|
+
React.useEffect(() => {
|
|
118
|
+
if (!editor)
|
|
119
|
+
return;
|
|
120
|
+
const update = () => setTick(t => t + 1);
|
|
121
|
+
editor.on('selectionUpdate', update);
|
|
122
|
+
editor.on('transaction', update);
|
|
123
|
+
editor.on('focus', update);
|
|
124
|
+
editor.on('blur', update);
|
|
125
|
+
return () => {
|
|
126
|
+
editor.off('selectionUpdate', update);
|
|
127
|
+
editor.off('transaction', update);
|
|
128
|
+
editor.off('focus', update);
|
|
129
|
+
editor.off('blur', update);
|
|
130
|
+
};
|
|
131
|
+
}, [editor]);
|
|
132
|
+
if (!editor)
|
|
9
133
|
return null;
|
|
10
|
-
}
|
|
11
134
|
const addImage = async (e) => {
|
|
12
135
|
const file = e.target.files?.[0];
|
|
13
136
|
if (file) {
|
|
14
137
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// const url = URL.createObjectURL(file);
|
|
18
|
-
const url = await uploadFile(file); // Needs verify this exists/works
|
|
19
|
-
if (url) {
|
|
138
|
+
const url = await uploadFile(file);
|
|
139
|
+
if (url)
|
|
20
140
|
editor.chain().focus().setImage({ src: url }).run();
|
|
21
|
-
}
|
|
22
141
|
}
|
|
23
142
|
catch (error) {
|
|
24
|
-
console.error(
|
|
143
|
+
console.error('Upload failed', error);
|
|
25
144
|
}
|
|
26
145
|
}
|
|
27
|
-
// Reset inputs
|
|
28
146
|
if (fileInputRef.current)
|
|
29
147
|
fileInputRef.current.value = '';
|
|
30
148
|
};
|
|
31
|
-
const
|
|
32
|
-
|
|
149
|
+
const activeFont = editor.getAttributes('textStyle').fontFamily || 'default';
|
|
150
|
+
const activeFontSize = editor.getAttributes('textStyle').fontSize || '';
|
|
151
|
+
const applyFontSize = (val) => {
|
|
152
|
+
const trimmed = val.trim();
|
|
153
|
+
if (!trimmed || trimmed.toLowerCase() === 'default' || trimmed === '0') {
|
|
154
|
+
editor.chain().focus().unsetFontSize().run();
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
editor.chain().focus().setFontSize(trimmed).run();
|
|
158
|
+
}
|
|
33
159
|
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (font === 'default') {
|
|
38
|
-
editor.chain().focus().unsetFontFamily().run();
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
editor.chain().focus().setFontFamily(font).run();
|
|
42
|
-
}
|
|
43
|
-
}, value: editor.getAttributes('textStyle').fontFamily || 'default', children: [_jsx("option", { value: "default", children: "Default Font" }), _jsxs("optgroup", { label: "Bangla Fonts", children: [_jsx("option", { value: "'Hind Siliguri', sans-serif", children: "Hind Siliguri" }), _jsx("option", { value: "'Kalpurush', sans-serif", children: "Kalpurush" }), _jsx("option", { value: "'Siyam Rupali', sans-serif", children: "Siyam Rupali" }), _jsx("option", { value: "'SolaimanLipi', sans-serif", children: "SolaimanLipi" }), _jsx("option", { value: "'Akaash', sans-serif", children: "Akaash" }), _jsx("option", { value: "'Mukti Narrow', sans-serif", children: "Mukti Narrow" })] }), _jsxs("optgroup", { label: "Standard", children: [_jsx("option", { value: "Inter, sans-serif", children: "Inter" }), _jsx("option", { value: "Roboto, sans-serif", children: "Roboto" }), _jsx("option", { value: "serif", children: "Serif" }), _jsx("option", { value: "monospace", children: "Monospace" })] })] }) }), _jsx(ToolbarButton, { onClick: () => {
|
|
44
|
-
const previousUrl = editor.getAttributes('link').href;
|
|
45
|
-
const url = window.prompt('URL', previousUrl);
|
|
46
|
-
if (url === null) {
|
|
47
|
-
return;
|
|
160
|
+
return (_jsxs("div", { className: "\n flex flex-wrap items-center gap-0.5 px-2 py-1.5\n border-b border-gray-100 dark:border-gray-800\n bg-gray-50/80 dark:bg-zinc-900/80\n backdrop-blur-sm sticky top-0 z-10\n ", children: [_jsx(Btn, { onClick: () => editor.chain().focus().undo().run(), disabled: !editor.can().undo(), title: "Undo (Ctrl+Z)", children: _jsx(Undo, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().redo().run(), disabled: !editor.can().redo(), title: "Redo (Ctrl+Shift+Z)", children: _jsx(Redo, { size: 15 }) }), _jsx(Divider, {}), _jsx(NativeSelect, { title: "Block type", value: getActiveBlock(editor), onChange: v => setBlock(editor, v), className: "w-32", children: BLOCK_TYPES.map(bt => (_jsx("option", { value: bt.value, children: bt.label }, bt.value))) }), _jsx(Divider, {}), _jsx(NativeSelect, { title: "Font family", value: activeFont, onChange: v => {
|
|
161
|
+
if (v === 'default') {
|
|
162
|
+
editor.chain().focus().unsetFontFamily().run();
|
|
48
163
|
}
|
|
164
|
+
else {
|
|
165
|
+
editor.chain().focus().setFontFamily(v).run();
|
|
166
|
+
}
|
|
167
|
+
}, className: "w-36", children: FONT_GROUPS.map(group => (_jsx("optgroup", { label: group.label, children: group.fonts.map(f => (_jsx("option", { value: f.value, children: f.label }, f.value))) }, group.label))) }), _jsxs(NativeSelect, { title: "Font size", value: activeFontSize || 'default', onChange: v => {
|
|
168
|
+
if (v === 'custom') {
|
|
169
|
+
setIsCustomFontSizeModalOpen(true);
|
|
170
|
+
}
|
|
171
|
+
else if (v === 'default') {
|
|
172
|
+
editor.chain().focus().unsetFontSize().run();
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
editor.chain().focus().setFontSize(v).run();
|
|
176
|
+
}
|
|
177
|
+
}, className: "w-24", children: [!FONT_SIZES.some(s => s.value === activeFontSize) && activeFontSize && (_jsx("option", { value: activeFontSize, children: activeFontSize })), FONT_SIZES.map(s => (_jsx("option", { value: s.value, children: s.label }, s.value)))] }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => editor.chain().focus().toggleBold().run(), isActive: editor.isActive('bold'), title: "Bold (Ctrl+B)", children: _jsx(Bold, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleItalic().run(), isActive: editor.isActive('italic'), title: "Italic (Ctrl+I)", children: _jsx(Italic, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleUnderline().run(), isActive: editor.isActive('underline'), title: "Underline (Ctrl+U)", children: _jsx(UnderlineIcon, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleStrike().run(), isActive: editor.isActive('strike'), title: "Strikethrough", children: _jsx(Strikethrough, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleCode().run(), isActive: editor.isActive('code'), title: "Inline code", children: _jsx(Code, { size: 15 }) }), _jsx(Btn, { onClick: () => {
|
|
178
|
+
editor.chain()
|
|
179
|
+
.focus()
|
|
180
|
+
.unsetAllMarks()
|
|
181
|
+
.unsetFontSize()
|
|
182
|
+
.unsetFontFamily()
|
|
183
|
+
.run();
|
|
184
|
+
}, title: "Clear formatting", children: _jsx(RemoveFormatting, { size: 15 }) }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => editor.chain().focus().setTextAlign('left').run(), isActive: editor.isActive({ textAlign: 'left' }), title: "Align left", children: _jsx(AlignLeft, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().setTextAlign('center').run(), isActive: editor.isActive({ textAlign: 'center' }), title: "Align center", children: _jsx(AlignCenter, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().setTextAlign('right').run(), isActive: editor.isActive({ textAlign: 'right' }), title: "Align right", children: _jsx(AlignRight, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().setTextAlign('justify').run(), isActive: editor.isActive({ textAlign: 'justify' }), title: "Justify", children: _jsx(AlignJustify, { size: 15 }) }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => editor.chain().focus().toggleBulletList().run(), isActive: editor.isActive('bulletList'), title: "Bullet list", children: _jsx(List, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleOrderedList().run(), isActive: editor.isActive('orderedList'), title: "Numbered list", children: _jsx(ListOrdered, { size: 15 }) }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => editor.chain().focus().toggleBlockquote().run(), isActive: editor.isActive('blockquote'), title: "Blockquote", children: _jsx(Quote, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().toggleCodeBlock().run(), isActive: editor.isActive('codeBlock'), title: "Code block", children: _jsx(Code2, { size: 15 }) }), _jsx(Btn, { onClick: () => editor.chain().focus().setHorizontalRule().run(), title: "Horizontal rule", children: _jsx(Minus, { size: 15 }) }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => {
|
|
185
|
+
const prev = editor.getAttributes('link').href;
|
|
186
|
+
const url = window.prompt('URL', prev);
|
|
187
|
+
if (url === null)
|
|
188
|
+
return;
|
|
49
189
|
if (url === '') {
|
|
50
190
|
editor.chain().focus().extendMarkRange('link').unsetLink().run();
|
|
51
191
|
return;
|
|
52
192
|
}
|
|
53
193
|
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
|
|
54
|
-
}, isActive: editor.isActive('link'),
|
|
55
|
-
editor
|
|
56
|
-
.chain()
|
|
57
|
-
.focus()
|
|
194
|
+
}, isActive: editor.isActive('link'), title: "Link", children: _jsx(LinkIcon, { size: 15 }) }), _jsx(Btn, { onClick: () => fileInputRef.current?.click(), title: "Insert image", children: _jsx(ImageIcon, { size: 15 }) }), _jsx("input", { type: "file", ref: fileInputRef, onChange: addImage, className: "hidden", accept: "image/*" }), _jsx(Divider, {}), _jsx(Btn, { onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(), title: "Insert table", children: _jsx(TableIcon, { size: 15 }) }), _jsx(Btn, { title: "2-column layout", onClick: () => {
|
|
195
|
+
editor.chain().focus()
|
|
58
196
|
.insertContent('<p> </p>')
|
|
59
197
|
.insertContent('<div data-type="layout-row" data-cols="2"><div data-type="layout-column"><p></p></div><div data-type="layout-column"><p></p></div></div>')
|
|
60
198
|
.run();
|
|
61
|
-
}, children: _jsx(LayoutTemplate, { size:
|
|
62
|
-
editor
|
|
63
|
-
.chain()
|
|
64
|
-
.focus()
|
|
199
|
+
}, children: _jsx(LayoutTemplate, { size: 15 }) }), _jsx(Btn, { title: "3-column layout", onClick: () => {
|
|
200
|
+
editor.chain().focus()
|
|
65
201
|
.insertContent('<p> </p>')
|
|
66
202
|
.insertContent('<div data-type="layout-row" data-cols="3"><div data-type="layout-column"><p></p></div><div data-type="layout-column"><p></p></div><div data-type="layout-column"><p></p></div></div>')
|
|
67
203
|
.run();
|
|
68
|
-
}, children: _jsx(LayoutPanelLeft, { size:
|
|
69
|
-
editor
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
204
|
+
}, children: _jsx(LayoutPanelLeft, { size: 15 }) }), _jsx(Btn, { title: "Full-width container", onClick: () => {
|
|
205
|
+
editor.chain().focus().insertContent({ type: 'container', content: [{ type: 'paragraph' }] }).run();
|
|
206
|
+
}, children: _jsx(Square, { size: 15 }) }), onDistrictGridClick && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Btn, { onClick: onDistrictGridClick, title: "District grid", children: _jsx(MapPin, { size: 15 }) })] })), _jsx(Divider, {}), _jsxs("div", { className: "relative inline-flex", title: "Text color", children: [_jsx(Btn, { onClick: () => { }, isActive: editor.isActive('textStyle'), children: _jsx(Type, { size: 15 }) }), _jsx("input", { type: "color", className: "absolute inset-0 opacity-0 w-full h-full cursor-pointer", onChange: e => editor.chain().focus().setColor(e.target.value).run(), value: editor.getAttributes('textStyle').color || '#000000' })] }), _jsxs("div", { className: "relative inline-flex", title: "Highlight color", children: [_jsx(Btn, { onClick: () => { }, isActive: editor.isActive('highlight'), children: _jsx(Palette, { size: 15 }) }), _jsx("input", { type: "color", className: "absolute inset-0 opacity-0 w-full h-full cursor-pointer", onChange: e => editor.chain().focus().setHighlight({ color: e.target.value }).run(), value: editor.getAttributes('highlight').color || '#ffff00' })] }), _jsxs("div", { className: "relative inline-flex", title: "Background color", children: [_jsx(Btn, { onClick: () => { }, isActive: !!editor.getAttributes('gridContainer').backgroundColor ||
|
|
207
|
+
!!editor.getAttributes('layoutRow').backgroundColor ||
|
|
208
|
+
!!editor.getAttributes('layoutColumn').backgroundColor ||
|
|
209
|
+
!!editor.getAttributes('container').backgroundColor, children: _jsx(PaintBucket, { size: 15 }) }), _jsx("input", { type: "color", className: "absolute inset-0 opacity-0 w-full h-full cursor-pointer", onChange: e => {
|
|
210
|
+
const val = e.target.value;
|
|
211
|
+
const cmd = editor.chain().focus();
|
|
212
|
+
if (editor.isActive('gridItem') || editor.isActive('gridContainer')) {
|
|
213
|
+
cmd.updateAttributes('gridContainer', { backgroundColor: val });
|
|
77
214
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
editor.chain().focus().updateAttributes('gridContainer', { backgroundColor: val }).run();
|
|
90
|
-
}
|
|
91
|
-
else if (editor.isActive('container')) {
|
|
92
|
-
editor.chain().focus().updateAttributes('container', { backgroundColor: val }).run();
|
|
93
|
-
}
|
|
94
|
-
else if (editor.isActive('layoutColumn')) {
|
|
95
|
-
editor.chain().focus().updateAttributes('layoutColumn', { backgroundColor: val }).run();
|
|
96
|
-
}
|
|
97
|
-
else if (editor.isActive('layoutRow')) {
|
|
98
|
-
editor.chain().focus().updateAttributes('layoutRow', { backgroundColor: val }).run();
|
|
99
|
-
}
|
|
100
|
-
} })] })] }), _jsx("div", { className: "w-[1px] h-6 bg-gray-300 dark:bg-gray-700 mx-1" }), _jsxs("div", { className: "flex items-center gap-1 relative group", children: [_jsx("span", { className: "text-[10px] text-gray-500 absolute left-1 pointer-events-none", children: "R" }), _jsx("input", { type: "number", placeholder: "0", className: "w-16 h-8 pl-4 pr-1 text-xs bg-transparent border border-gray-200 dark:border-gray-700 rounded", onChange: (e) => {
|
|
215
|
+
else if (editor.isActive('container')) {
|
|
216
|
+
cmd.updateAttributes('container', { backgroundColor: val });
|
|
217
|
+
}
|
|
218
|
+
else if (editor.isActive('layoutColumn')) {
|
|
219
|
+
cmd.updateAttributes('layoutColumn', { backgroundColor: val });
|
|
220
|
+
}
|
|
221
|
+
else if (editor.isActive('layoutRow')) {
|
|
222
|
+
cmd.updateAttributes('layoutRow', { backgroundColor: val });
|
|
223
|
+
}
|
|
224
|
+
cmd.run();
|
|
225
|
+
} })] }), _jsx(Divider, {}), _jsxs("div", { className: "relative flex items-center", title: "Border radius", children: [_jsx("span", { className: "absolute left-1.5 text-[9px] text-gray-400 pointer-events-none font-medium", children: "R" }), _jsx("input", { type: "number", placeholder: "0", className: "\n w-14 h-7 pl-4 pr-1 text-xs rounded-md\n border border-gray-200 dark:border-gray-700\n bg-white dark:bg-zinc-900\n text-gray-700 dark:text-gray-200\n outline-none focus:ring-1 focus:ring-blue-400\n ", onChange: e => {
|
|
101
226
|
const val = e.target.value;
|
|
102
227
|
const radius = val ? `${val}px` : null;
|
|
103
228
|
const cmd = editor.chain().focus();
|
|
@@ -114,5 +239,5 @@ export const Toolbar = ({ editor, onDistrictGridClick }) => {
|
|
|
114
239
|
cmd.updateAttributes('layoutRow', { borderRadius: radius });
|
|
115
240
|
}
|
|
116
241
|
cmd.run();
|
|
117
|
-
} })] }), _jsx(
|
|
242
|
+
} })] }), _jsx(CustomFontSizeModal, { isOpen: isCustomFontSizeModalOpen, onClose: () => setIsCustomFontSizeModalOpen(false), onApply: applyFontSize, currentSize: activeFontSize })] }));
|
|
118
243
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface CustomFontSizeModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onApply: (fontSize: string) => void;
|
|
5
|
+
currentSize?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateAndFormatFontSize(input: string): {
|
|
8
|
+
valid: boolean;
|
|
9
|
+
formatted: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const CustomFontSizeModal: ({ isOpen, onClose, onApply, currentSize, }: CustomFontSizeModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, Input, } from '@heroui/react';
|
|
5
|
+
import { Type, AlertCircle } from 'lucide-react';
|
|
6
|
+
export function validateAndFormatFontSize(input) {
|
|
7
|
+
const raw = input.trim();
|
|
8
|
+
if (!raw)
|
|
9
|
+
return { valid: false, formatted: '', error: 'Please enter a font size' };
|
|
10
|
+
const match = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*([a-zA-Z%]*)$/);
|
|
11
|
+
if (!match) {
|
|
12
|
+
return { valid: false, formatted: raw, error: 'Invalid size format (e.g. 16px or 1.5rem)' };
|
|
13
|
+
}
|
|
14
|
+
const num = parseFloat(match[1]);
|
|
15
|
+
const unit = match[2].toLowerCase();
|
|
16
|
+
if (isNaN(num)) {
|
|
17
|
+
return { valid: false, formatted: raw, error: 'Invalid numeric value' };
|
|
18
|
+
}
|
|
19
|
+
// Default unit to px if none provided
|
|
20
|
+
if (!unit || unit === 'px') {
|
|
21
|
+
if (num < 6) {
|
|
22
|
+
return { valid: false, formatted: '6px', error: 'Minimum allowed size is 6px' };
|
|
23
|
+
}
|
|
24
|
+
if (num > 150) {
|
|
25
|
+
return { valid: false, formatted: '150px', error: 'Maximum allowed size is 150px (capped)' };
|
|
26
|
+
}
|
|
27
|
+
return { valid: true, formatted: `${num}px` };
|
|
28
|
+
}
|
|
29
|
+
if (unit === 'rem' || unit === 'em') {
|
|
30
|
+
if (num < 0.5) {
|
|
31
|
+
return { valid: false, formatted: `0.5${unit}`, error: `Minimum allowed size is 0.5${unit}` };
|
|
32
|
+
}
|
|
33
|
+
if (num > 8) {
|
|
34
|
+
return { valid: false, formatted: `8${unit}`, error: `Maximum size for ${unit} is 8${unit} (capped at ~128px)` };
|
|
35
|
+
}
|
|
36
|
+
return { valid: true, formatted: `${num}${unit}` };
|
|
37
|
+
}
|
|
38
|
+
if (unit === 'pt') {
|
|
39
|
+
if (num < 5)
|
|
40
|
+
return { valid: false, formatted: '5pt', error: 'Minimum allowed size is 5pt' };
|
|
41
|
+
if (num > 115)
|
|
42
|
+
return { valid: false, formatted: '115pt', error: 'Maximum allowed size is 115pt' };
|
|
43
|
+
return { valid: true, formatted: `${num}pt` };
|
|
44
|
+
}
|
|
45
|
+
if (unit === '%') {
|
|
46
|
+
if (num < 50)
|
|
47
|
+
return { valid: false, formatted: '50%', error: 'Minimum allowed size is 50%' };
|
|
48
|
+
if (num > 1000)
|
|
49
|
+
return { valid: false, formatted: '1000%', error: 'Maximum allowed size is 1000%' };
|
|
50
|
+
return { valid: true, formatted: `${num}%` };
|
|
51
|
+
}
|
|
52
|
+
return { valid: false, formatted: raw, error: `Unsupported unit "${unit}". Use px, rem, pt, or em` };
|
|
53
|
+
}
|
|
54
|
+
export const CustomFontSizeModal = ({ isOpen, onClose, onApply, currentSize = '', }) => {
|
|
55
|
+
const [sizeInput, setSizeInput] = useState(currentSize || '16px');
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (isOpen) {
|
|
58
|
+
setSizeInput(currentSize || '16px');
|
|
59
|
+
}
|
|
60
|
+
}, [isOpen, currentSize]);
|
|
61
|
+
const validation = validateAndFormatFontSize(sizeInput);
|
|
62
|
+
const handleApply = () => {
|
|
63
|
+
if (validation.formatted) {
|
|
64
|
+
onApply(validation.formatted);
|
|
65
|
+
}
|
|
66
|
+
onClose();
|
|
67
|
+
};
|
|
68
|
+
return (_jsx(Modal, { isOpen: isOpen, onClose: onClose, size: "xs", backdrop: "opaque", classNames: {
|
|
69
|
+
base: "dark:bg-zinc-900 border border-gray-200 dark:border-gray-800 rounded-xl shadow-xl",
|
|
70
|
+
header: "border-b border-gray-100 dark:border-gray-800 py-3 px-4",
|
|
71
|
+
body: "py-4 px-4",
|
|
72
|
+
footer: "border-t border-gray-100 dark:border-gray-800 py-2.5 px-4 flex justify-end gap-2"
|
|
73
|
+
}, children: _jsx(ModalContent, { children: () => (_jsxs(_Fragment, { children: [_jsxs(ModalHeader, { className: "flex items-center gap-2 text-sm font-semibold text-gray-800 dark:text-gray-100", children: [_jsx(Type, { size: 16, className: "text-blue-500" }), _jsx("span", { children: "Custom Font Size" })] }), _jsx(ModalBody, { children: _jsxs("div", { className: "flex flex-col gap-2.5", children: [_jsx("label", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Enter size (e.g. 15px, 22px, 1.5rem)" }), _jsx(Input, { autoFocus: true, placeholder: "16px", value: sizeInput, onChange: (e) => setSizeInput(e.target.value), onKeyDown: (e) => {
|
|
74
|
+
if (e.key === 'Enter') {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
handleApply();
|
|
77
|
+
}
|
|
78
|
+
}, variant: "bordered", size: "sm", isInvalid: !validation.valid, classNames: {
|
|
79
|
+
inputWrapper: "border-gray-200 dark:border-gray-700 bg-white dark:bg-zinc-950 shadow-none focus-within:ring-2 focus-within:ring-blue-500"
|
|
80
|
+
} }), validation.error && (_jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-amber-600 dark:text-amber-400 font-medium", children: [_jsx(AlertCircle, { size: 13, className: "flex-shrink-0" }), _jsx("span", { children: validation.error })] })), _jsxs("div", { className: "flex items-center gap-1.5 pt-1", children: [_jsx("span", { className: "text-[11px] text-gray-400", children: "Quick units:" }), ['12px', '15px', '22px', '28px', '40px'].map((preset) => (_jsx("button", { type: "button", onClick: () => setSizeInput(preset), className: "px-1.5 py-0.5 text-[11px] rounded bg-gray-100 dark:bg-zinc-800 text-gray-600 dark:text-gray-300 hover:bg-blue-50 hover:text-blue-600 dark:hover:bg-blue-950 transition-colors", children: preset }, preset)))] })] }) }), _jsxs(ModalFooter, { children: [_jsx(Button, { size: "sm", variant: "flat", color: "default", onPress: onClose, children: "Cancel" }), _jsx(Button, { size: "sm", color: "primary", onPress: handleApply, children: "Apply Size" })] })] })) }) }));
|
|
81
|
+
};
|
|
@@ -67,5 +67,5 @@ export const DistrictGridModal = ({ isOpen, onClose, onInsert, currentSpeciality
|
|
|
67
67
|
? "bg-primary-50 border-primary-500 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400"
|
|
68
68
|
: "bg-transparent border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-900"), children: "Doctors" }), _jsx("button", { onClick: () => setBaseType('hospitals'), className: cn("px-4 py-2 rounded-lg border text-sm font-medium transition-colors", baseType === 'hospitals'
|
|
69
69
|
? "bg-primary-50 border-primary-500 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400"
|
|
70
|
-
: "bg-transparent border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-900"), children: "Hospitals" })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(RefSelect, { name: "districts", label: "Search & Select Districts", refModel: "Districts", value: selectedDistricts, onChange: (ids) => setSelectedDistricts(ids), multiple: true
|
|
70
|
+
: "bg-transparent border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-900"), children: "Hospitals" })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(RefSelect, { name: "districts", label: "Search & Select Districts", refModel: "Districts", value: selectedDistricts, onChange: (ids) => setSelectedDistricts(ids), multiple: true }), _jsx("p", { className: "text-xs text-gray-400", children: "Select one or more districts to create grid items." })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(RefSelect, { name: "speciality", label: "Search & Select Speciality", refModel: "Specialities", showKey: "name", value: selectedSpecialityId, onChange: (id) => setSelectedSpecialityId(id || ''), multiple: false }), _jsx("p", { className: "text-xs text-gray-400", children: "Leave empty to create URLs without speciality." }), specialitySlug && (_jsx("div", { className: "mt-1 px-2 py-1 bg-primary-50 dark:bg-primary-900/20 rounded border border-primary-200 dark:border-primary-800", children: _jsxs("p", { className: "text-xs text-primary-700 dark:text-primary-400", children: ["Slug: ", _jsx("code", { className: "font-mono", children: specialitySlug })] }) }))] }), selectedDistricts.length > 0 && (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { className: "text-sm font-medium", children: "URL Preview" }), _jsxs("div", { className: "px-3 py-2 bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 max-h-32 overflow-y-auto", children: [_jsx("p", { className: "text-xs text-gray-500 mb-2", children: "Example URL pattern (actual district slugs will be used):" }), _jsx("code", { className: "text-xs text-gray-700 dark:text-gray-300", children: getPreviewUrl('[district-slug]') })] })] }))] }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "flat", onPress: onClose, children: "Cancel" }), _jsx(Button, { color: "primary", onPress: handleInsert, isDisabled: selectedDistricts.length === 0, children: "Insert Grid" })] })] }) }) }));
|
|
71
71
|
};
|
|
@@ -83,7 +83,7 @@ export const SchemaInsertionModal = ({ isOpen, onClose, onInsert, schema, availa
|
|
|
83
83
|
base: "bg-white dark:bg-zinc-950 border border-gray-200 dark:border-gray-800",
|
|
84
84
|
header: "border-b border-gray-200 dark:border-gray-800",
|
|
85
85
|
footer: "border-t border-gray-200 dark:border-gray-800",
|
|
86
|
-
}, children: _jsx(ModalContent, { children: _jsxs(_Fragment, { children: [_jsxs(ModalHeader, { children: ["Insert ", schema.modelName] }), _jsxs(ModalBody, { className: "py-6 flex flex-col gap-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(RefSelect, { name: "items", label: "Search & Select", refModel: schema.modelName, value: selectedIds, onChange: (ids) => setSelectedIds(ids), multiple: true
|
|
86
|
+
}, children: _jsx(ModalContent, { children: _jsxs(_Fragment, { children: [_jsxs(ModalHeader, { children: ["Insert ", schema.modelName] }), _jsxs(ModalBody, { className: "py-6 flex flex-col gap-6", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(RefSelect, { name: "items", label: "Search & Select", refModel: schema.modelName, value: selectedIds, onChange: (ids) => setSelectedIds(ids), multiple: true }), _jsx("p", { className: "text-xs text-gray-400", children: "Leave empty to fetch latest items automatically." })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("label", { className: "text-sm font-medium", children: "View Type" }), _jsxs("div", { className: "flex gap-4", children: [_jsx("button", { onClick: () => setViewType('grid'), className: cn("px-4 py-2 rounded-lg border text-sm font-medium transition-colors", viewType === 'grid'
|
|
87
87
|
? "bg-primary-50 border-primary-500 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400"
|
|
88
88
|
: "bg-transparent border-gray-200 dark:border-gray-800 hover:bg-gray-50"), children: "Grid (Pills)" }), _jsx("button", { onClick: () => setViewType('list'), className: cn("px-4 py-2 rounded-lg border text-sm font-medium transition-colors", viewType === 'list'
|
|
89
89
|
? "bg-primary-50 border-primary-500 text-primary-700 dark:bg-primary-900/20 dark:text-primary-400"
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=EB+Garamond:ital,wght@0,400..800;1,400..800&family=Figtree:ital,wght@0,300..900;1,300..900&family=Fira+Code:wght@300..700&family=Hind+Siliguri:wght@300;400;500;600;700&family=Inter:wght@100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&family=Lora:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&family=Noto+Sans+Bengali:wght@100..900&family=Nunito:ital,wght@0,200..1000;1,200..1000&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Outfit:wght@100..900&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap');
|
|
2
|
+
|
|
1
3
|
.editor-input {
|
|
2
4
|
min-height: 150px;
|
|
3
5
|
resize: none;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
export interface FontSizeOptions {
|
|
3
|
+
types: string[];
|
|
4
|
+
}
|
|
5
|
+
declare module '@tiptap/core' {
|
|
6
|
+
interface Commands<ReturnType> {
|
|
7
|
+
fontSize: {
|
|
8
|
+
/**
|
|
9
|
+
* Set the font size attribute
|
|
10
|
+
*/
|
|
11
|
+
setFontSize: (fontSize: string) => ReturnType;
|
|
12
|
+
/**
|
|
13
|
+
* Unset the font size attribute
|
|
14
|
+
*/
|
|
15
|
+
unsetFontSize: () => ReturnType;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export declare const FontSize: Extension<FontSizeOptions, any>;
|