@jiggai/kitchen-plugin-marketing 0.5.1 → 0.5.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/dist/api/handler.js +7 -6
- package/dist/tabs/content-calendar.js +243 -21
- package/package.json +1 -1
package/dist/api/handler.js
CHANGED
|
@@ -453,7 +453,8 @@ var XDriver = class extends BaseDriver {
|
|
|
453
453
|
var InstagramDriver = class extends BaseDriver {
|
|
454
454
|
platform = "instagram";
|
|
455
455
|
label = "Instagram";
|
|
456
|
-
|
|
456
|
+
// Text fallback; UI renders these inside icon circles
|
|
457
|
+
icon = "IG";
|
|
457
458
|
postizProvider = "instagram";
|
|
458
459
|
getMaxLength() {
|
|
459
460
|
return 2200;
|
|
@@ -467,7 +468,7 @@ var InstagramDriver = class extends BaseDriver {
|
|
|
467
468
|
var FacebookDriver = class extends BaseDriver {
|
|
468
469
|
platform = "facebook";
|
|
469
470
|
label = "Facebook";
|
|
470
|
-
icon = "
|
|
471
|
+
icon = "f";
|
|
471
472
|
postizProvider = "facebook";
|
|
472
473
|
getMaxLength() {
|
|
473
474
|
return 63206;
|
|
@@ -481,7 +482,7 @@ var FacebookDriver = class extends BaseDriver {
|
|
|
481
482
|
var LinkedInDriver = class extends BaseDriver {
|
|
482
483
|
platform = "linkedin";
|
|
483
484
|
label = "LinkedIn";
|
|
484
|
-
icon = "
|
|
485
|
+
icon = "in";
|
|
485
486
|
postizProvider = "linkedin";
|
|
486
487
|
getMaxLength() {
|
|
487
488
|
return 3e3;
|
|
@@ -495,7 +496,7 @@ var LinkedInDriver = class extends BaseDriver {
|
|
|
495
496
|
var TikTokDriver = class extends BaseDriver {
|
|
496
497
|
platform = "tiktok";
|
|
497
498
|
label = "TikTok";
|
|
498
|
-
icon = "
|
|
499
|
+
icon = "TT";
|
|
499
500
|
postizProvider = "tiktok";
|
|
500
501
|
getMaxLength() {
|
|
501
502
|
return 2200;
|
|
@@ -509,7 +510,7 @@ var TikTokDriver = class extends BaseDriver {
|
|
|
509
510
|
var DiscordDriver = class extends BaseDriver {
|
|
510
511
|
platform = "discord";
|
|
511
512
|
label = "Discord";
|
|
512
|
-
icon = "
|
|
513
|
+
icon = "DS";
|
|
513
514
|
postizProvider = "discord";
|
|
514
515
|
getMaxLength() {
|
|
515
516
|
return 2e3;
|
|
@@ -546,7 +547,7 @@ var DiscordDriver = class extends BaseDriver {
|
|
|
546
547
|
var TelegramDriver = class extends BaseDriver {
|
|
547
548
|
platform = "telegram";
|
|
548
549
|
label = "Telegram";
|
|
549
|
-
icon = "
|
|
550
|
+
icon = "TG";
|
|
550
551
|
postizProvider = "telegram";
|
|
551
552
|
getMaxLength() {
|
|
552
553
|
return 4096;
|
|
@@ -230,7 +230,11 @@
|
|
|
230
230
|
resize: "vertical",
|
|
231
231
|
fontFamily: "inherit",
|
|
232
232
|
fontSize: "0.9rem",
|
|
233
|
-
outline: "none"
|
|
233
|
+
outline: "none",
|
|
234
|
+
// Hard-force LTR to avoid any inherited RTL / bidi overrides in host app
|
|
235
|
+
direction: "ltr",
|
|
236
|
+
unicodeBidi: "plaintext",
|
|
237
|
+
textAlign: "left"
|
|
234
238
|
},
|
|
235
239
|
input: {
|
|
236
240
|
background: "rgba(255,255,255,0.03)",
|
|
@@ -342,6 +346,11 @@
|
|
|
342
346
|
const [modalContent, setModalContent] = useState("");
|
|
343
347
|
const [modalPlatforms, setModalPlatforms] = useState([]);
|
|
344
348
|
const [modalMediaUrl, setModalMediaUrl] = useState("");
|
|
349
|
+
const [modalShowMedia, setModalShowMedia] = useState(false);
|
|
350
|
+
const [modalUploading, setModalUploading] = useState(false);
|
|
351
|
+
const [modalMediaLibrary, setModalMediaLibrary] = useState([]);
|
|
352
|
+
const [modalSelectedMediaIds, setModalSelectedMediaIds] = useState([]);
|
|
353
|
+
const modalFileInputRef = useRef(null);
|
|
345
354
|
const [modalSaving, setModalSaving] = useState(false);
|
|
346
355
|
const [modalPublishing, setModalPublishing] = useState(false);
|
|
347
356
|
const [modalError, setModalError] = useState(null);
|
|
@@ -374,6 +383,51 @@
|
|
|
374
383
|
} catch {
|
|
375
384
|
}
|
|
376
385
|
}, [teamId, postizHeaders]);
|
|
386
|
+
const loadMedia = useCallback(async () => {
|
|
387
|
+
try {
|
|
388
|
+
const res = await fetch(`${apiBase}/media?team=${encodeURIComponent(teamId)}&limit=200`);
|
|
389
|
+
const json = await res.json();
|
|
390
|
+
setModalMediaLibrary(Array.isArray(json.data) ? json.data : []);
|
|
391
|
+
} catch {
|
|
392
|
+
}
|
|
393
|
+
}, [teamId]);
|
|
394
|
+
const handleModalFileUpload = useCallback(async (files) => {
|
|
395
|
+
if (!files || files.length === 0) return;
|
|
396
|
+
setModalUploading(true);
|
|
397
|
+
setModalError(null);
|
|
398
|
+
try {
|
|
399
|
+
for (const file of Array.from(files)) {
|
|
400
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
401
|
+
const reader = new FileReader();
|
|
402
|
+
reader.onload = () => resolve(reader.result);
|
|
403
|
+
reader.onerror = reject;
|
|
404
|
+
reader.readAsDataURL(file);
|
|
405
|
+
});
|
|
406
|
+
const up = await fetch(`${apiBase}/media?team=${encodeURIComponent(teamId)}`, {
|
|
407
|
+
method: "POST",
|
|
408
|
+
headers: { "content-type": "application/json" },
|
|
409
|
+
body: JSON.stringify({ data: base64, filename: file.name, mimeType: file.type })
|
|
410
|
+
});
|
|
411
|
+
if (!up.ok) {
|
|
412
|
+
const err = await up.json().catch(() => ({}));
|
|
413
|
+
throw new Error(err?.message || `Upload failed (${up.status})`);
|
|
414
|
+
}
|
|
415
|
+
const item = await up.json().catch(() => null);
|
|
416
|
+
if (item?.id) {
|
|
417
|
+
setModalSelectedMediaIds((prev) => prev.includes(item.id) ? prev : [...prev, item.id]);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
await loadMedia();
|
|
421
|
+
} catch (e) {
|
|
422
|
+
setModalError(e?.message || "Upload failed");
|
|
423
|
+
} finally {
|
|
424
|
+
setModalUploading(false);
|
|
425
|
+
if (modalFileInputRef.current) modalFileInputRef.current.value = "";
|
|
426
|
+
}
|
|
427
|
+
}, [teamId, loadMedia]);
|
|
428
|
+
const toggleModalMedia = (id) => {
|
|
429
|
+
setModalSelectedMediaIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]);
|
|
430
|
+
};
|
|
377
431
|
useEffect(() => {
|
|
378
432
|
setLoading(true);
|
|
379
433
|
Promise.all([loadPosts(), loadDrivers()]).finally(() => setLoading(false));
|
|
@@ -393,6 +447,9 @@
|
|
|
393
447
|
setModalContent("");
|
|
394
448
|
setModalPlatforms([]);
|
|
395
449
|
setModalMediaUrl("");
|
|
450
|
+
setModalShowMedia(false);
|
|
451
|
+
setModalSelectedMediaIds([]);
|
|
452
|
+
setModalMediaLibrary([]);
|
|
396
453
|
setModalError(null);
|
|
397
454
|
setModalSuccess(null);
|
|
398
455
|
setModalOpen(true);
|
|
@@ -423,7 +480,8 @@
|
|
|
423
480
|
content: modalContent,
|
|
424
481
|
platforms: modalPlatforms.length > 0 ? modalPlatforms : ["draft"],
|
|
425
482
|
status: modalDate ? "scheduled" : "draft",
|
|
426
|
-
scheduledAt: modalDate || void 0
|
|
483
|
+
scheduledAt: modalDate || void 0,
|
|
484
|
+
mediaIds: modalSelectedMediaIds
|
|
427
485
|
})
|
|
428
486
|
});
|
|
429
487
|
if (!res.ok) throw new Error(`Save failed (${res.status})`);
|
|
@@ -451,6 +509,7 @@
|
|
|
451
509
|
content: modalContent,
|
|
452
510
|
platforms: modalPlatforms,
|
|
453
511
|
scheduledAt: modalDate || void 0,
|
|
512
|
+
// NOTE: Postiz expects publicly reachable URLs; uploaded library media is local-only for now.
|
|
454
513
|
mediaUrls: modalMediaUrl ? [modalMediaUrl] : void 0
|
|
455
514
|
})
|
|
456
515
|
});
|
|
@@ -468,7 +527,8 @@
|
|
|
468
527
|
content: modalContent,
|
|
469
528
|
platforms: modalPlatforms,
|
|
470
529
|
status: modalDate ? "scheduled" : "published",
|
|
471
|
-
scheduledAt: modalDate || void 0
|
|
530
|
+
scheduledAt: modalDate || void 0,
|
|
531
|
+
mediaIds: modalSelectedMediaIds
|
|
472
532
|
})
|
|
473
533
|
}).catch(() => {
|
|
474
534
|
});
|
|
@@ -535,7 +595,7 @@
|
|
|
535
595
|
function WeekView() {
|
|
536
596
|
const weekStart = anchor;
|
|
537
597
|
const days = Array.from({ length: 7 }, (_, i) => addDays(weekStart, i));
|
|
538
|
-
const hours = Array.from({ length:
|
|
598
|
+
const hours = Array.from({ length: 24 }, (_, i) => i);
|
|
539
599
|
return h(
|
|
540
600
|
"div",
|
|
541
601
|
null,
|
|
@@ -793,6 +853,7 @@
|
|
|
793
853
|
// Textarea
|
|
794
854
|
h("textarea", {
|
|
795
855
|
style: s.textarea,
|
|
856
|
+
dir: "ltr",
|
|
796
857
|
value: modalContent,
|
|
797
858
|
onChange: (e) => setModalContent(e.target.value),
|
|
798
859
|
placeholder: "Write something \u2026",
|
|
@@ -803,8 +864,13 @@
|
|
|
803
864
|
"div",
|
|
804
865
|
{ style: { display: "flex", gap: "0.5rem", alignItems: "center", flexWrap: "wrap" } },
|
|
805
866
|
h("button", {
|
|
867
|
+
type: "button",
|
|
806
868
|
style: { ...s.btnGhost, padding: "0.3rem 0.6rem", fontSize: "0.75rem" },
|
|
807
|
-
onClick: () =>
|
|
869
|
+
onClick: async () => {
|
|
870
|
+
const next = !modalShowMedia;
|
|
871
|
+
setModalShowMedia(next);
|
|
872
|
+
if (next) await loadMedia();
|
|
873
|
+
}
|
|
808
874
|
}, "\u{1F5BC} Insert Media"),
|
|
809
875
|
charLimit && h("span", {
|
|
810
876
|
style: {
|
|
@@ -814,14 +880,158 @@
|
|
|
814
880
|
}
|
|
815
881
|
}, `${modalContent.length}/${charLimit}`)
|
|
816
882
|
),
|
|
817
|
-
// Media URL
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
883
|
+
// Media panel (upload + library + URL)
|
|
884
|
+
modalShowMedia && h(
|
|
885
|
+
"div",
|
|
886
|
+
{
|
|
887
|
+
style: {
|
|
888
|
+
background: "rgba(255,255,255,0.02)",
|
|
889
|
+
border: "1px solid var(--ck-border-subtle)",
|
|
890
|
+
borderRadius: "10px",
|
|
891
|
+
padding: "0.75rem"
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
h(
|
|
895
|
+
"div",
|
|
896
|
+
{ style: { display: "flex", gap: "0.5rem", alignItems: "center", marginBottom: "0.5rem", flexWrap: "wrap" } },
|
|
897
|
+
h("input", {
|
|
898
|
+
ref: modalFileInputRef,
|
|
899
|
+
type: "file",
|
|
900
|
+
accept: "image/*,video/*",
|
|
901
|
+
multiple: true,
|
|
902
|
+
style: { display: "none" },
|
|
903
|
+
onChange: (e) => void handleModalFileUpload(e.target.files)
|
|
904
|
+
}),
|
|
905
|
+
h("button", {
|
|
906
|
+
type: "button",
|
|
907
|
+
style: { ...s.btnGhost, padding: "0.35rem 0.6rem", fontSize: "0.75rem", opacity: modalUploading ? 0.7 : 1 },
|
|
908
|
+
onClick: () => modalFileInputRef.current?.click(),
|
|
909
|
+
disabled: modalUploading
|
|
910
|
+
}, modalUploading ? "\u23F3 Uploading\u2026" : "\u{1F4C1} Upload"),
|
|
911
|
+
h("button", {
|
|
912
|
+
type: "button",
|
|
913
|
+
style: { ...s.btnGhost, padding: "0.35rem 0.6rem", fontSize: "0.75rem" },
|
|
914
|
+
onClick: () => setModalShowMedia(false)
|
|
915
|
+
}, "Done")
|
|
916
|
+
),
|
|
917
|
+
h("input", {
|
|
918
|
+
style: s.input,
|
|
919
|
+
type: "url",
|
|
920
|
+
value: modalMediaUrl,
|
|
921
|
+
onChange: (e) => setModalMediaUrl(e.target.value),
|
|
922
|
+
placeholder: "Paste a public image/video URL (needed for Postiz)\u2026"
|
|
923
|
+
}),
|
|
924
|
+
// Selected media strip
|
|
925
|
+
modalSelectedMediaIds.length > 0 && h(
|
|
926
|
+
"div",
|
|
927
|
+
{ style: { display: "flex", flexWrap: "wrap", gap: "0.5rem", marginTop: "0.65rem" } },
|
|
928
|
+
...modalSelectedMediaIds.map((id) => {
|
|
929
|
+
const item = modalMediaLibrary.find((m) => m.id === id);
|
|
930
|
+
if (!item) return null;
|
|
931
|
+
return h(
|
|
932
|
+
"div",
|
|
933
|
+
{
|
|
934
|
+
key: id,
|
|
935
|
+
style: {
|
|
936
|
+
position: "relative",
|
|
937
|
+
width: "64px",
|
|
938
|
+
height: "64px",
|
|
939
|
+
borderRadius: "8px",
|
|
940
|
+
overflow: "hidden",
|
|
941
|
+
border: "2px solid rgba(127,90,240,0.55)"
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
item.mimeType?.startsWith("video/") ? h("div", {
|
|
945
|
+
style: { width: "100%", height: "100%", background: "rgba(0,0,0,0.35)", display: "flex", alignItems: "center", justifyContent: "center", color: "white" }
|
|
946
|
+
}, "\u{1F3A5}") : h("img", { src: item.thumbnailDataUrl, style: { width: "100%", height: "100%", objectFit: "cover" } }),
|
|
947
|
+
h("button", {
|
|
948
|
+
type: "button",
|
|
949
|
+
onClick: () => toggleModalMedia(id),
|
|
950
|
+
style: {
|
|
951
|
+
position: "absolute",
|
|
952
|
+
top: "2px",
|
|
953
|
+
right: "2px",
|
|
954
|
+
background: "rgba(0,0,0,0.6)",
|
|
955
|
+
border: "none",
|
|
956
|
+
borderRadius: "50%",
|
|
957
|
+
width: "18px",
|
|
958
|
+
height: "18px",
|
|
959
|
+
color: "white",
|
|
960
|
+
fontSize: "0.65rem",
|
|
961
|
+
cursor: "pointer",
|
|
962
|
+
display: "flex",
|
|
963
|
+
alignItems: "center",
|
|
964
|
+
justifyContent: "center"
|
|
965
|
+
}
|
|
966
|
+
}, "\u2715")
|
|
967
|
+
);
|
|
968
|
+
})
|
|
969
|
+
),
|
|
970
|
+
// Library grid
|
|
971
|
+
h(
|
|
972
|
+
"div",
|
|
973
|
+
{ style: { marginTop: "0.65rem" } },
|
|
974
|
+
h("div", { style: { fontSize: "0.75rem", fontWeight: 600, color: "var(--ck-text-secondary)", marginBottom: "0.4rem" } }, "Media Library"),
|
|
975
|
+
modalMediaLibrary.length === 0 ? h("div", { style: { fontSize: "0.75rem", color: "var(--ck-text-tertiary)", padding: "0.5rem 0" } }, "No media yet \u2014 upload something.") : h(
|
|
976
|
+
"div",
|
|
977
|
+
{
|
|
978
|
+
style: {
|
|
979
|
+
display: "grid",
|
|
980
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(86px, 1fr))",
|
|
981
|
+
gap: "0.5rem",
|
|
982
|
+
maxHeight: "220px",
|
|
983
|
+
overflowY: "auto",
|
|
984
|
+
paddingRight: "4px"
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
...modalMediaLibrary.map((item) => {
|
|
988
|
+
const selected = modalSelectedMediaIds.includes(item.id);
|
|
989
|
+
const thumb = item.thumbnailDataUrl;
|
|
990
|
+
return h(
|
|
991
|
+
"div",
|
|
992
|
+
{
|
|
993
|
+
key: item.id,
|
|
994
|
+
onClick: () => toggleModalMedia(item.id),
|
|
995
|
+
style: {
|
|
996
|
+
position: "relative",
|
|
997
|
+
width: "100%",
|
|
998
|
+
paddingTop: "100%",
|
|
999
|
+
borderRadius: "10px",
|
|
1000
|
+
overflow: "hidden",
|
|
1001
|
+
cursor: "pointer",
|
|
1002
|
+
border: selected ? "2px solid rgba(127,90,240,0.75)" : "1px solid var(--ck-border-subtle)",
|
|
1003
|
+
boxShadow: selected ? "0 0 10px rgba(127,90,240,0.25)" : "none",
|
|
1004
|
+
background: "rgba(0,0,0,0.25)"
|
|
1005
|
+
}
|
|
1006
|
+
},
|
|
1007
|
+
item.mimeType?.startsWith("video/") ? h("div", {
|
|
1008
|
+
style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", color: "white", fontSize: "1.4rem" }
|
|
1009
|
+
}, "\u{1F3A5}") : h("img", {
|
|
1010
|
+
src: thumb,
|
|
1011
|
+
style: { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }
|
|
1012
|
+
}),
|
|
1013
|
+
selected && h("div", {
|
|
1014
|
+
style: {
|
|
1015
|
+
position: "absolute",
|
|
1016
|
+
top: "6px",
|
|
1017
|
+
right: "6px",
|
|
1018
|
+
width: "20px",
|
|
1019
|
+
height: "20px",
|
|
1020
|
+
borderRadius: "50%",
|
|
1021
|
+
background: "rgba(127,90,240,0.9)",
|
|
1022
|
+
display: "flex",
|
|
1023
|
+
alignItems: "center",
|
|
1024
|
+
justifyContent: "center",
|
|
1025
|
+
color: "white",
|
|
1026
|
+
fontSize: "0.75rem",
|
|
1027
|
+
fontWeight: 800
|
|
1028
|
+
}
|
|
1029
|
+
}, "\u2713")
|
|
1030
|
+
);
|
|
1031
|
+
})
|
|
1032
|
+
)
|
|
1033
|
+
)
|
|
1034
|
+
)
|
|
825
1035
|
),
|
|
826
1036
|
// Right — social-post-style preview
|
|
827
1037
|
h(
|
|
@@ -890,14 +1100,26 @@
|
|
|
890
1100
|
style: { color: "var(--ck-text-tertiary)", fontSize: "0.85rem", fontStyle: "italic", padding: "1.5rem 0", textAlign: "center" }
|
|
891
1101
|
}, "Start writing to see a preview")
|
|
892
1102
|
),
|
|
893
|
-
// Media preview
|
|
894
|
-
modalMediaUrl && h(
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1103
|
+
// Media preview (selected library media first, then URL)
|
|
1104
|
+
(modalSelectedMediaIds.length > 0 || modalMediaUrl) && h(
|
|
1105
|
+
"div",
|
|
1106
|
+
null,
|
|
1107
|
+
...modalSelectedMediaIds.slice(0, 1).map((id) => {
|
|
1108
|
+
const item = modalMediaLibrary.find((m) => m.id === id);
|
|
1109
|
+
if (!item) return null;
|
|
1110
|
+
return item.mimeType?.startsWith("video/") ? h("div", {
|
|
1111
|
+
key: id,
|
|
1112
|
+
style: { background: "rgba(0,0,0,0.4)", padding: "1.25rem", textAlign: "center", color: "var(--ck-text-secondary)" }
|
|
1113
|
+
}, "\u{1F3A5} Video") : h("img", { key: id, src: item.thumbnailDataUrl, style: { width: "100%", display: "block" } });
|
|
1114
|
+
}),
|
|
1115
|
+
modalMediaUrl && h("img", {
|
|
1116
|
+
src: modalMediaUrl,
|
|
1117
|
+
style: { width: "100%", display: "block" },
|
|
1118
|
+
onError: (e) => {
|
|
1119
|
+
e.target.style.display = "none";
|
|
1120
|
+
}
|
|
1121
|
+
})
|
|
1122
|
+
),
|
|
901
1123
|
// Engagement bar
|
|
902
1124
|
h(
|
|
903
1125
|
"div",
|