Skip to content

Commit 1ac2862

Browse files
authored
Merge pull request #10 from citizenwatchamerica/feature/PWA-277-custom-contentful-app-rich-text-html-converter
Feature/pwa 277 custom contentful app rich text html converter
2 parents 368b31d + 31d7c15 commit 1ac2862

39 files changed

Lines changed: 219 additions & 315 deletions

.github/workflows/deploy-apps.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
required: true
99
type: choice
1010
options:
11-
- rich-text-html-converter
11+
- html-field-editor
1212
- salesforce-commerce-cloud
1313
push:
1414
branches:
@@ -32,7 +32,7 @@ jobs:
3232
run: |
3333
# Map: app directory name -> GitHub secret suffix for CONTENTFUL_APP_DEF_ID_*
3434
declare -A APPS=(
35-
["rich-text-html-converter"]="RICH_TEXT_HTML_CONVERTER"
35+
["html-field-editor"]="HTML_FIELD_EDITOR"
3636
["salesforce-commerce-cloud"]="SALESFORCE_COMMERCE_CLOUD"
3737
)
3838

apps/rich-text-html-converter/.claude/settings.local.json renamed to apps/html-field-editor/.claude/settings.local.json

File renamed without changes.
File renamed without changes.

apps/rich-text-html-converter/package.json renamed to apps/html-field-editor/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
{
2-
"name": "html-to-rich-text-conversion-contentful",
2+
"name": "html-field-editor",
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
66
"@contentful/app-sdk": "4.25.0",
77
"@contentful/f36-components": "4.65.4",
88
"@contentful/f36-tokens": "4.0.2",
99
"@contentful/react-apps-toolkit": "1.2.16",
10-
"@contentful/rich-text-html-renderer": "^17.2.2",
1110
"@contentful/rich-text-types": "16.8.5",
12-
"@tiptap/extension-link": "^3.23.2",
1311
"@tiptap/extension-subscript": "^3.23.2",
1412
"@tiptap/extension-superscript": "^3.23.2",
1513
"@tiptap/extension-table": "^3.23.2",
@@ -33,8 +31,8 @@
3331
"test:ci": "vitest run",
3432
"create-app-definition": "contentful-app-scripts create-app-definition",
3533
"add-locations": "contentful-app-scripts add-locations",
36-
"deploy": "contentful-app-scripts upload --ci --bundle-dir ./dist --organization-id ${CONTENTFUL_ORG_ID} --definition-id ${CONTENTFUL_APP_DEF_ID} --token ${CONTENTFUL_ACCESS_TOKEN}",
37-
"deploy:test": "contentful-app-scripts upload --ci --bundle-dir ./dist --organization-id ${DEV_TESTING_ORG_ID} --definition-id 66J3nYAMa13A1O7E8MDDMu --token ${TEST_CMA_TOKEN}"
34+
"deploy": "contentful-app-scripts --ci upload --bundle-dir ./dist --organization-id ${CONTENTFUL_ORG_ID} --definition-id ${CONTENTFUL_APP_DEF_ID} --token ${CONTENTFUL_ACCESS_TOKEN}",
35+
"deploy:test": "contentful-app-scripts --ci upload --bundle-dir ./dist --organization-id ${DEV_TESTING_ORG_ID} --definition-id 66J3nYAMa13A1O7E8MDDMu --token ${TEST_CMA_TOKEN}"
3836
},
3937
"devDependencies": {
4038
"@contentful/app-scripts": "^2.3.0",

apps/rich-text-html-converter/src/components/LocalhostWarning.tsx renamed to apps/html-field-editor/src/components/LocalhostWarning.tsx

File renamed without changes.

apps/rich-text-html-converter/src/components/RichTextEditor/RawHtmlBlock.ts renamed to apps/html-field-editor/src/components/RichTextEditor/RawHtmlBlock.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ export const RawHtmlBlock = Node.create({
2323
},
2424

2525
parseHTML() {
26-
return [{ tag: 'div[data-type="raw-html-block"]' }];
26+
// High priority so this rule wins over ProseMirror's default <div> handling.
27+
return [{ tag: 'div[data-type="raw-html-block"]', priority: 1000 }];
2728
},
2829

2930
renderHTML({ HTMLAttributes }) {

apps/rich-text-html-converter/src/components/RichTextEditor/Toolbar.tsx renamed to apps/html-field-editor/src/components/RichTextEditor/Toolbar.tsx

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Editor } from '@tiptap/react';
2-
import { useEffect, useRef, useState } from 'react';
32

43
interface Props {
54
editor: Editor | null;
@@ -8,31 +7,10 @@ interface Props {
87
}
98

109
export default function Toolbar({ editor, isHtmlMode, onToggleHtml }: Props) {
11-
const [linkUrl, setLinkUrl] = useState('');
12-
const [showLink, setShowLink] = useState(false);
13-
const linkAnchorRef = useRef<HTMLDivElement>(null);
14-
const linkInputRef = useRef<HTMLInputElement>(null);
15-
16-
// Close link popover on outside click
17-
useEffect(() => {
18-
if (!showLink) return;
19-
const handle = (e: MouseEvent) => {
20-
if (!linkAnchorRef.current?.contains(e.target as Node)) setShowLink(false);
21-
};
22-
document.addEventListener('mousedown', handle);
23-
return () => document.removeEventListener('mousedown', handle);
24-
}, [showLink]);
25-
26-
useEffect(() => {
27-
if (showLink) linkInputRef.current?.focus();
28-
}, [showLink]);
29-
3010
if (!editor) return <div className="rte-toolbar" />;
3111

3212
const dis = isHtmlMode;
3313

34-
// ── Helpers ──────────────────────────────────────────────────────────────
35-
3614
const headingLevel = (): string => {
3715
for (let i = 1; i <= 6; i++) {
3816
if (editor.isActive('heading', { level: i })) return String(i);
@@ -48,31 +26,6 @@ export default function Toolbar({ editor, isHtmlMode, onToggleHtml }: Props) {
4826
}
4927
};
5028

51-
const openLink = () => {
52-
setLinkUrl(editor.getAttributes('link').href ?? '');
53-
setShowLink(true);
54-
};
55-
56-
const applyLink = () => {
57-
const raw = linkUrl.trim();
58-
if (!raw) {
59-
editor.chain().focus().extendMarkRange('link').unsetLink().run();
60-
} else {
61-
const href = /^https?:\/\//i.test(raw) ? raw : `https://${raw}`;
62-
editor.chain().focus().extendMarkRange('link').setLink({ href }).run();
63-
}
64-
setShowLink(false);
65-
setLinkUrl('');
66-
};
67-
68-
const removeLink = () => {
69-
editor.chain().focus().extendMarkRange('link').unsetLink().run();
70-
setShowLink(false);
71-
setLinkUrl('');
72-
};
73-
74-
// ── Render ────────────────────────────────────────────────────────────────
75-
7629
return (
7730
<div className="rte-toolbar">
7831

@@ -177,51 +130,6 @@ export default function Toolbar({ editor, isHtmlMode, onToggleHtml }: Props) {
177130

178131
<span className="rte-divider" />
179132

180-
{/* Link */}
181-
<div ref={linkAnchorRef} className="rte-link-anchor">
182-
<Btn
183-
active={editor.isActive('link')}
184-
disabled={dis}
185-
title="Link"
186-
onPress={openLink}
187-
><LinkIcon /></Btn>
188-
189-
{showLink && (
190-
<div className="rte-link-popover">
191-
<input
192-
ref={linkInputRef}
193-
type="url"
194-
className="rte-link-input"
195-
placeholder="https://example.com"
196-
value={linkUrl}
197-
onChange={e => setLinkUrl(e.target.value)}
198-
onKeyDown={e => {
199-
if (e.key === 'Enter') { e.preventDefault(); applyLink(); }
200-
if (e.key === 'Escape') setShowLink(false);
201-
}}
202-
/>
203-
<button
204-
type="button"
205-
className="rte-btn rte-btn-text"
206-
onMouseDown={e => { e.preventDefault(); applyLink(); }}
207-
>
208-
Apply
209-
</button>
210-
{editor.isActive('link') && (
211-
<button
212-
type="button"
213-
className="rte-btn rte-btn-danger"
214-
onMouseDown={e => { e.preventDefault(); removeLink(); }}
215-
>
216-
Remove
217-
</button>
218-
)}
219-
</div>
220-
)}
221-
</div>
222-
223-
<span className="rte-divider" />
224-
225133
{/* Table */}
226134
<Btn
227135
active={false}
@@ -320,15 +228,6 @@ function HRIcon() {
320228
);
321229
}
322230

323-
function LinkIcon() {
324-
return (
325-
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
326-
<path d="M6 9.5a3.5 3.5 0 004.9-.1l1.5-1.5a3.5 3.5 0 00-4.95-4.95L6.4 4.1" />
327-
<path d="M9 5.5a3.5 3.5 0 00-4.9.1L2.6 7.1a3.5 3.5 0 004.95 4.95L8.6 10.9" />
328-
</svg>
329-
);
330-
}
331-
332231
function TableIcon() {
333232
return (
334233
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" stroke="currentColor" strokeWidth="1.25">

0 commit comments

Comments
 (0)