@jhits/plugin-content 0.0.11 → 0.0.12
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.
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
interface TranslationEditorProps {
|
|
2
|
+
messages: Record<string, any>;
|
|
3
|
+
locale: string;
|
|
4
|
+
}
|
|
5
|
+
declare function TranslationEditorInner({ messages: initialMessages, locale: initialLocale }: TranslationEditorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export default TranslationEditorInner;
|
|
7
|
+
export type { TranslationEditorProps };
|
|
2
8
|
//# sourceMappingURL=TranslationEditor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationEditor.d.ts","sourceRoot":"","sources":["../../src/components/TranslationEditor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TranslationEditor.d.ts","sourceRoot":"","sources":["../../src/components/TranslationEditor.tsx"],"names":[],"mappings":"AAQA,UAAU,sBAAsB;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,iBAAS,sBAAsB,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,sBAAsB,kDA8S3G;AAeD,eAAe,sBAAsB,CAAC;AACtC,YAAY,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -2,31 +2,57 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { useRouter, usePathname } from 'next/navigation';
|
|
4
4
|
import { useState, useEffect, useMemo, useRef } from 'react';
|
|
5
|
-
import { useLocale, useMessages } from 'next-intl';
|
|
6
5
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
7
6
|
import { X, Globe, Search, ChevronRight, Plus, CornerDownRight, ShieldCheck, Lock, Bold, Italic, Type } from 'lucide-react';
|
|
8
7
|
import { parse } from '../utils/parser';
|
|
9
|
-
|
|
8
|
+
function TranslationEditorInner({ messages: initialMessages, locale: initialLocale }) {
|
|
10
9
|
const router = useRouter();
|
|
11
10
|
const pathname = usePathname();
|
|
12
|
-
const
|
|
13
|
-
const locale = useLocale();
|
|
11
|
+
const [mounted, setMounted] = useState(false);
|
|
14
12
|
const [open, setOpen] = useState(false);
|
|
15
13
|
const [userData, setUserData] = useState(null);
|
|
16
14
|
const [loadingAuth, setLoadingAuth] = useState(true);
|
|
17
|
-
const [jsonData, setJsonData] = useState(
|
|
15
|
+
const [jsonData, setJsonData] = useState(initialMessages);
|
|
18
16
|
const [searchQuery, setSearchQuery] = useState('');
|
|
19
17
|
const [saving, setSaving] = useState(false);
|
|
20
18
|
const [activePath, setActivePath] = useState(null);
|
|
21
19
|
const [showAddForm, setShowAddForm] = useState(false);
|
|
22
20
|
const [newKey, setNewKey] = useState('');
|
|
23
21
|
const [newValue, setNewValue] = useState('');
|
|
24
|
-
|
|
22
|
+
const [selectedSection, setSelectedSection] = useState('');
|
|
23
|
+
const textareaRefs = useRef({});
|
|
24
|
+
// All useMemo calls
|
|
25
25
|
const availableSections = useMemo(() => {
|
|
26
26
|
return Object.keys(jsonData).filter(key => typeof jsonData[key] === 'object');
|
|
27
27
|
}, [jsonData]);
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const filteredItems = useMemo(() => {
|
|
29
|
+
const allPaths = getFlattenedPaths(jsonData);
|
|
30
|
+
const filtered = allPaths.filter(item => {
|
|
31
|
+
if (activePath === item.path)
|
|
32
|
+
return true;
|
|
33
|
+
const matchesSearch = item.path.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
34
|
+
item.value.toLowerCase().includes(searchQuery.toLowerCase());
|
|
35
|
+
if (searchQuery)
|
|
36
|
+
return matchesSearch;
|
|
37
|
+
return item.path.startsWith(`${selectedSection}.`) || item.path.startsWith('common.');
|
|
38
|
+
});
|
|
39
|
+
return [...filtered].sort((a, b) => {
|
|
40
|
+
const getPriority = (path) => {
|
|
41
|
+
if (path.startsWith(`${selectedSection}.`))
|
|
42
|
+
return 1;
|
|
43
|
+
if (path.startsWith('common.'))
|
|
44
|
+
return 3;
|
|
45
|
+
return 2;
|
|
46
|
+
};
|
|
47
|
+
const priorityA = getPriority(a.path);
|
|
48
|
+
const priorityB = getPriority(b.path);
|
|
49
|
+
return priorityA !== priorityB ? priorityA - priorityB : a.path.localeCompare(b.path);
|
|
50
|
+
});
|
|
51
|
+
}, [jsonData, searchQuery, selectedSection, activePath]);
|
|
52
|
+
// All useEffect calls
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setMounted(true);
|
|
55
|
+
}, []);
|
|
30
56
|
useEffect(() => {
|
|
31
57
|
async function checkAuth() {
|
|
32
58
|
try {
|
|
@@ -46,19 +72,36 @@ export default function TranslationEditor() {
|
|
|
46
72
|
}, []);
|
|
47
73
|
useEffect(() => {
|
|
48
74
|
const handleLocaleUpdate = (event) => {
|
|
49
|
-
if (event.detail.locale ===
|
|
75
|
+
if (event.detail.locale === initialLocale) {
|
|
50
76
|
setJsonData(event.detail.messages);
|
|
51
77
|
router.refresh();
|
|
52
78
|
}
|
|
53
79
|
};
|
|
54
80
|
window.addEventListener('locale-updated', handleLocaleUpdate);
|
|
55
81
|
return () => window.removeEventListener('locale-updated', handleLocaleUpdate);
|
|
56
|
-
}, [
|
|
82
|
+
}, [initialLocale, router]);
|
|
57
83
|
useEffect(() => {
|
|
58
|
-
setJsonData(
|
|
59
|
-
}, [
|
|
84
|
+
setJsonData(initialMessages);
|
|
85
|
+
}, [initialMessages]);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const parts = pathname.split('/').filter(Boolean);
|
|
88
|
+
const cleanParts = (parts[0]?.length === 2) ? parts.slice(1) : parts;
|
|
89
|
+
const urlKey = cleanParts[0] || 'home';
|
|
90
|
+
if (availableSections.includes(urlKey)) {
|
|
91
|
+
setSelectedSection(urlKey);
|
|
92
|
+
}
|
|
93
|
+
else if (availableSections.length > 0 && !selectedSection) {
|
|
94
|
+
setSelectedSection(availableSections[0]);
|
|
95
|
+
}
|
|
96
|
+
}, [pathname, availableSections, selectedSection]);
|
|
97
|
+
// Don't render anything until mounted
|
|
98
|
+
if (!mounted) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
60
101
|
const isAdmin = userData?.role === 'admin' || userData?.role === 'dev';
|
|
61
102
|
const isDev = userData?.role === 'dev';
|
|
103
|
+
if (loadingAuth || !isAdmin)
|
|
104
|
+
return null;
|
|
62
105
|
const applyFormatting = (path, type) => {
|
|
63
106
|
const el = textareaRefs.current[path];
|
|
64
107
|
if (!el)
|
|
@@ -126,13 +169,13 @@ export default function TranslationEditor() {
|
|
|
126
169
|
const res = await fetch('/api/plugin-content/save', {
|
|
127
170
|
method: 'POST',
|
|
128
171
|
headers: { 'Content-Type': 'application/json' },
|
|
129
|
-
body: JSON.stringify({ locale, messages: jsonData }),
|
|
172
|
+
body: JSON.stringify({ locale: initialLocale, messages: jsonData }),
|
|
130
173
|
});
|
|
131
174
|
if (res.ok) {
|
|
132
175
|
router.refresh();
|
|
133
176
|
setShowAddForm(false);
|
|
134
177
|
window.dispatchEvent(new CustomEvent('locale-updated', {
|
|
135
|
-
detail: { locale, messages: jsonData }
|
|
178
|
+
detail: { locale: initialLocale, messages: jsonData }
|
|
136
179
|
}));
|
|
137
180
|
}
|
|
138
181
|
else {
|
|
@@ -154,46 +197,6 @@ export default function TranslationEditor() {
|
|
|
154
197
|
setNewValue('');
|
|
155
198
|
setShowAddForm(false);
|
|
156
199
|
};
|
|
157
|
-
// Set the initial section based on the URL, but only if it matches a JSON key
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
const parts = pathname.split('/').filter(Boolean);
|
|
160
|
-
const cleanParts = (parts[0]?.length === 2) ? parts.slice(1) : parts;
|
|
161
|
-
const urlKey = cleanParts[0] || 'home';
|
|
162
|
-
// If "over-mij" isn't in JSON, but "about" is, this helps her pick
|
|
163
|
-
if (availableSections.includes(urlKey)) {
|
|
164
|
-
setSelectedSection(urlKey);
|
|
165
|
-
}
|
|
166
|
-
else if (availableSections.length > 0 && !selectedSection) {
|
|
167
|
-
setSelectedSection(availableSections[0]);
|
|
168
|
-
}
|
|
169
|
-
}, [pathname, availableSections]);
|
|
170
|
-
const filteredItems = useMemo(() => {
|
|
171
|
-
const allPaths = getFlattenedPaths(jsonData);
|
|
172
|
-
const filtered = allPaths.filter(item => {
|
|
173
|
-
if (activePath === item.path)
|
|
174
|
-
return true;
|
|
175
|
-
const matchesSearch = item.path.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
176
|
-
item.value.toLowerCase().includes(searchQuery.toLowerCase());
|
|
177
|
-
if (searchQuery)
|
|
178
|
-
return matchesSearch;
|
|
179
|
-
// Default view: Selected Section + Common
|
|
180
|
-
return item.path.startsWith(`${selectedSection}.`) || item.path.startsWith('common.');
|
|
181
|
-
});
|
|
182
|
-
return [...filtered].sort((a, b) => {
|
|
183
|
-
const getPriority = (path) => {
|
|
184
|
-
if (path.startsWith(`${selectedSection}.`))
|
|
185
|
-
return 1;
|
|
186
|
-
if (path.startsWith('common.'))
|
|
187
|
-
return 3;
|
|
188
|
-
return 2;
|
|
189
|
-
};
|
|
190
|
-
const priorityA = getPriority(a.path);
|
|
191
|
-
const priorityB = getPriority(b.path);
|
|
192
|
-
return priorityA !== priorityB ? priorityA - priorityB : a.path.localeCompare(b.path);
|
|
193
|
-
});
|
|
194
|
-
}, [jsonData, searchQuery, selectedSection, activePath]);
|
|
195
|
-
if (loadingAuth || !isAdmin)
|
|
196
|
-
return null;
|
|
197
200
|
return (_jsxs(_Fragment, { children: [_jsxs("button", { onClick: () => setOpen(true), className: "fixed bottom-6 right-6 bg-neutral-950 dark:bg-white text-white dark:text-neutral-950 px-6 py-3 rounded-full flex items-center gap-3 shadow-2xl z-50 hover:bg-neutral-900 dark:hover:bg-neutral-100 transition-all border border-neutral-800/20 dark:border-neutral-200/20", children: [_jsx(Globe, { size: 18 }), " ", _jsx("span", { className: "font-bold", children: "Editor" })] }), _jsx(AnimatePresence, { children: open && (_jsxs(_Fragment, { children: [_jsx(motion.div, { className: "fixed inset-0 bg-neutral-950/50 dark:bg-neutral-950/70 z-40", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, onClick: () => setOpen(false) }), _jsxs(motion.div, { className: "fixed right-0 top-0 bottom-0 bg-card text-foreground shadow-2xl z-50 flex flex-col border-l border-border w-[550px]", initial: { x: '100%' }, animate: { x: 0 }, exit: { x: '100%' }, children: [_jsxs("div", { className: "p-6 bg-card border-b border-border flex justify-between items-center", children: [_jsxs("div", { children: [_jsxs("h2", { className: "text-2xl font-serif flex items-center gap-2", children: [isDev ? 'Dev Mode' : 'Content Editor', isDev ? _jsx(ShieldCheck, { className: "text-primary", size: 20 }) : _jsx(Lock, { className: "text-primary", size: 16 })] }), _jsxs("p", { className: "text-[10px] uppercase font-bold text-neutral-500 dark:text-neutral-400", children: ["Welkom, ", userData?.name] })] }), _jsxs("div", { className: "flex gap-2", children: [isDev && (_jsx("button", { onClick: () => setShowAddForm(!showAddForm), className: `p-2 rounded-full transition-colors ${showAddForm ? 'bg-primary text-white' : 'hover:bg-neutral-100 dark:hover:bg-neutral-800 text-neutral-600 dark:text-neutral-400'}`, children: _jsx(Plus, { size: 22 }) })), _jsx("button", { onClick: () => setOpen(false), className: "p-2 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-full text-neutral-600 dark:text-neutral-400", children: _jsx(X, { size: 24 }) })] })] }), isDev && showAddForm && (_jsxs(motion.div, { initial: { height: 0 }, animate: { height: 'auto' }, className: "bg-neutral-100/50 dark:bg-neutral-800/50 border-b border-border p-6 space-y-4 overflow-hidden", children: [_jsx("input", { value: newKey, onChange: e => setNewKey(e.target.value), placeholder: "pagina.sectie.sleutel", className: "w-full p-3 rounded-xl border border-border bg-card text-foreground placeholder:text-neutral-500 dark:placeholder:text-neutral-400 text-sm font-mono" }), _jsx("textarea", { value: newValue, onChange: e => setNewValue(e.target.value), placeholder: "Nieuwe vertaling...", className: "w-full p-3 rounded-xl border border-border bg-card text-foreground placeholder:text-neutral-500 dark:placeholder:text-neutral-400 text-sm min-h-[80px]" }), _jsxs("button", { onClick: addNewEntry, className: "w-full py-3 bg-primary text-white rounded-xl font-bold text-sm flex items-center justify-center gap-2", children: [_jsx(CornerDownRight, { size: 16 }), " Toevoegen"] })] })), _jsx("div", { className: "px-6 py-4 bg-card border-b border-border", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-neutral-500 dark:text-neutral-400" }), _jsx("input", { type: "text", placeholder: "Zoek in teksten...", className: "w-full pl-10 pr-4 py-2.5 bg-neutral-100/50 dark:bg-neutral-800/50 border border-border rounded-xl focus:outline-none focus:ring-2 focus:ring-primary/20 text-foreground placeholder:text-neutral-500 dark:placeholder:text-neutral-400", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value) })] }) }), _jsx("div", { className: "flex-1 overflow-y-auto p-6 space-y-10 bg-background pb-32", children: filteredItems.map((item) => (_jsxs("div", { className: "group relative", children: [_jsxs("div", { className: "flex justify-between items-center mb-3", children: [_jsx("div", { className: "flex items-center gap-2", children: item.path.split('.').map((part, i, arr) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `px-2 py-1 rounded-md text-[10px] font-bold uppercase tracking-wider ${i === arr.length - 1 ? 'bg-primary text-white' : 'bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-400 border border-border'}`, children: part.replace(/_/g, ' ') }), i !== arr.length - 1 && _jsx(ChevronRight, { size: 10, className: "text-neutral-400 dark:text-neutral-500" })] }, i))) }), _jsx(AnimatePresence, { children: activePath === item.path && (_jsxs(motion.div, { initial: { opacity: 0, y: 5 }, animate: { opacity: 1, y: 0 }, className: "formatting-toolbar flex gap-1 bg-card border border-border rounded-lg p-1 shadow-sm", children: [_jsx("button", { type: "button", tabIndex: -1, onClick: () => applyFormatting(item.path, 'bold'), className: "p-1.5 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded text-foreground", children: _jsx(Bold, { size: 14 }) }), _jsx("button", { type: "button", tabIndex: -1, onClick: () => applyFormatting(item.path, 'italic'), className: "p-1.5 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded text-foreground", children: _jsx(Italic, { size: 14 }) }), _jsx("button", { type: "button", tabIndex: -1, onClick: () => applyFormatting(item.path, 'both'), className: "p-1.5 hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded text-foreground", children: _jsx(Type, { size: 14 }) })] })) })] }), _jsxs("div", { className: "relative w-full min-h-[60px]", children: [_jsx("div", { className: "absolute inset-0 p-5 text-lg leading-relaxed pointer-events-none whitespace-pre-wrap break-words border-2 border-transparent text-foreground", "aria-hidden": "true", children: parse(item.value, true) }), _jsx("textarea", { ref: (el) => { textareaRefs.current[item.path] = el; }, className: `
|
|
198
201
|
w-full p-5 bg-transparent border-2 rounded-2xl
|
|
199
202
|
text-transparent caret-primary leading-relaxed shadow-sm
|
|
@@ -222,3 +225,4 @@ function getFlattenedPaths(obj, prefix = '') {
|
|
|
222
225
|
}
|
|
223
226
|
return paths;
|
|
224
227
|
}
|
|
228
|
+
export default TranslationEditorInner;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,19 +5,22 @@
|
|
|
5
5
|
export interface ContentPluginProps {
|
|
6
6
|
/** Whether to show the editor (default: true) */
|
|
7
7
|
enabled?: boolean;
|
|
8
|
+
/** Locale string - can be passed explicitly or will be fetched from context */
|
|
9
|
+
locale?: string;
|
|
10
|
+
/** Messages object - can be passed explicitly or will be fetched from context */
|
|
11
|
+
messages?: Record<string, any>;
|
|
8
12
|
}
|
|
9
13
|
/**
|
|
10
14
|
* Content Plugin Component
|
|
11
15
|
* Renders the translation editor for editing website content
|
|
12
16
|
*/
|
|
13
|
-
|
|
14
|
-
export default ContentPlugin;
|
|
17
|
+
export default function ContentPlugin({ enabled, locale, messages }: ContentPluginProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
18
|
export { ContentPlugin };
|
|
16
|
-
export { default as TranslationEditor } from './components/TranslationEditor';
|
|
17
19
|
export { default as MultilineText } from './components/MultilineText';
|
|
18
20
|
export type { MultilineTextProps } from './components/MultilineText';
|
|
19
21
|
export { default as ParsedText } from './components/ParsedText';
|
|
20
22
|
export type { ParsedTextProps } from './components/ParsedText';
|
|
23
|
+
export type { TranslationEditorProps } from './components/TranslationEditor';
|
|
21
24
|
export { ParserConfigProvider, useParserConfig } from './context/ParserConfigContext';
|
|
22
25
|
export type { ParserConfigProviderProps } from './context/ParserConfigContext';
|
|
23
26
|
export { useParse } from './hooks/useParse';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,kBAAkB;IAC/B,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;AAoBD;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,OAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,kBAAkB,kDAmB7F;AAkBD,OAAO,EAAE,aAAa,EAAE,CAAC;AAGzB,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAG7E,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACtF,YAAY,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAG/E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAItD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAGvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,22 +3,44 @@
|
|
|
3
3
|
* Provides content editing functionality for website translations
|
|
4
4
|
*/
|
|
5
5
|
'use client';
|
|
6
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
-
import
|
|
6
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
|
+
import { useState, useEffect, lazy, Suspense } from 'react';
|
|
8
|
+
const TranslationEditor = lazy(() => import('./components/TranslationEditor'));
|
|
9
|
+
function ContentPluginWithIntl({ locale, messages }) {
|
|
10
|
+
return (_jsx(Suspense, { fallback: null, children: _jsx(TranslationEditor, { messages: messages, locale: locale }) }));
|
|
11
|
+
}
|
|
12
|
+
function ClientOnly({ children }) {
|
|
13
|
+
const [mounted, setMounted] = useState(false);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
setMounted(true);
|
|
16
|
+
}, []);
|
|
17
|
+
return mounted ? _jsx(_Fragment, { children: children }) : null;
|
|
18
|
+
}
|
|
8
19
|
/**
|
|
9
20
|
* Content Plugin Component
|
|
10
21
|
* Renders the translation editor for editing website content
|
|
11
22
|
*/
|
|
12
|
-
function ContentPlugin({ enabled = true }) {
|
|
23
|
+
export default function ContentPlugin({ enabled = true, locale, messages }) {
|
|
13
24
|
if (!enabled)
|
|
14
25
|
return null;
|
|
15
|
-
|
|
26
|
+
// If locale and messages are provided as props, use them directly
|
|
27
|
+
if (locale && messages) {
|
|
28
|
+
return (_jsx(ClientOnly, { children: _jsx(ContentPluginWithIntl, { locale: locale, messages: messages }) }));
|
|
29
|
+
}
|
|
30
|
+
// Otherwise, try to use context (for backward compatibility)
|
|
31
|
+
// This path might have issues with context not being found
|
|
32
|
+
return (_jsx(ClientOnly, { children: _jsx(ContentPluginWithIntlFallback, {}) }));
|
|
33
|
+
}
|
|
34
|
+
function ContentPluginWithIntlFallback() {
|
|
35
|
+
// Dynamic import to avoid SSR issues with next-intl hooks
|
|
36
|
+
const { useMessages, useLocale, NextIntlClientProvider } = require('next-intl');
|
|
37
|
+
const messages = useMessages();
|
|
38
|
+
const locale = useLocale();
|
|
39
|
+
return (_jsx(NextIntlClientProvider, { locale: locale, messages: messages, children: _jsx(Suspense, { fallback: null, children: _jsx(TranslationEditor, { messages: messages, locale: locale }) }) }));
|
|
16
40
|
}
|
|
17
|
-
// Export
|
|
18
|
-
export default ContentPlugin;
|
|
41
|
+
// Export named export for flexibility
|
|
19
42
|
export { ContentPlugin };
|
|
20
43
|
// Export components
|
|
21
|
-
export { default as TranslationEditor } from './components/TranslationEditor';
|
|
22
44
|
export { default as MultilineText } from './components/MultilineText';
|
|
23
45
|
export { default as ParsedText } from './components/ParsedText';
|
|
24
46
|
// Export context
|
package/package.json
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jhits/plugin-content",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Content management and localization plugin for the JHITS ecosystem",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"main": "./
|
|
9
|
-
"types": "./
|
|
8
|
+
"main": "./src/index.ts",
|
|
9
|
+
"types": "./src/index.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"types": "./
|
|
13
|
-
"
|
|
12
|
+
"types": "./src/index.tsx",
|
|
13
|
+
"import": "./src/index.tsx",
|
|
14
|
+
"default": "./src/index.tsx"
|
|
15
|
+
},
|
|
16
|
+
"./src": {
|
|
17
|
+
"types": "./src/index.tsx",
|
|
18
|
+
"import": "./src/index.tsx",
|
|
19
|
+
"default": "./src/index.tsx"
|
|
14
20
|
},
|
|
15
21
|
"./server": {
|
|
16
|
-
"types": "./
|
|
17
|
-
"
|
|
22
|
+
"types": "./src/index.server.ts",
|
|
23
|
+
"import": "./src/index.server.ts",
|
|
24
|
+
"default": "./src/index.server.ts"
|
|
18
25
|
}
|
|
19
26
|
},
|
|
20
27
|
"dependencies": {
|
|
21
28
|
"framer-motion": "^12.34.0",
|
|
22
29
|
"lucide-react": "^0.564.0",
|
|
23
|
-
"@jhits/plugin-core": "0.0.
|
|
30
|
+
"@jhits/plugin-core": "0.0.7"
|
|
24
31
|
},
|
|
25
32
|
"peerDependencies": {
|
|
26
33
|
"next": ">=15.0.0",
|