feat: update ckeditor
This commit is contained in:
parent
df2546bc08
commit
902f8de516
|
|
@ -48,7 +48,8 @@ import {
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { useParams, useSearchParams } from "next/navigation";
|
import { useParams, useSearchParams } from "next/navigation";
|
||||||
import { UserIcon } from "lucide-react";
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
import columns from "./column";
|
import columns from "./column";
|
||||||
import TablePagination from "@/components/table/table-pagination";
|
import TablePagination from "@/components/table/table-pagination";
|
||||||
|
|
@ -57,7 +58,16 @@ import {
|
||||||
deleteMediaBlastCampaignAccount,
|
deleteMediaBlastCampaignAccount,
|
||||||
saveMediaBlastCampaignAccount,
|
saveMediaBlastCampaignAccount,
|
||||||
} from "@/service/broadcast/broadcast";
|
} from "@/service/broadcast/broadcast";
|
||||||
import { close, loading, error } from "@/config/swal";
|
import { close, loading, error, success } from "@/config/swal";
|
||||||
|
|
||||||
|
// Mock data for available accounts - replace with actual API call
|
||||||
|
const availableAccounts = [
|
||||||
|
{ id: "1", accountName: "Account 1", category: "polri" },
|
||||||
|
{ id: "2", accountName: "Account 2", category: "jurnalis" },
|
||||||
|
{ id: "3", accountName: "Account 3", category: "umum" },
|
||||||
|
{ id: "4", accountName: "Account 4", category: "ksp" },
|
||||||
|
{ id: "5", accountName: "Account 5", category: "polri" },
|
||||||
|
];
|
||||||
|
|
||||||
const AccountListTable = () => {
|
const AccountListTable = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
@ -82,9 +92,11 @@ const AccountListTable = () => {
|
||||||
const [filtered, setFiltered] = React.useState<string[]>([]);
|
const [filtered, setFiltered] = React.useState<string[]>([]);
|
||||||
|
|
||||||
// --- state utk Dialog Pilih Akun ---
|
// --- state utk Dialog Pilih Akun ---
|
||||||
|
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
||||||
const [accountCategory, setAccountCategory] = React.useState<string>("");
|
const [accountCategory, setAccountCategory] = React.useState<string>("");
|
||||||
const [selectedAccount, setSelectedAccount] = React.useState<any[]>([]);
|
const [selectedAccount, setSelectedAccount] = React.useState<any[]>([]);
|
||||||
const [selectedCategory, setSelectedCategory] = React.useState<string>("");
|
const [selectedCategory, setSelectedCategory] = React.useState<string>("");
|
||||||
|
const [availableAccountsList, setAvailableAccountsList] = React.useState<any[]>(availableAccounts);
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data: dataTable,
|
data: dataTable,
|
||||||
|
|
@ -154,6 +166,42 @@ const AccountListTable = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveCampaignAccount() {
|
async function saveCampaignAccount() {
|
||||||
|
try {
|
||||||
|
loading();
|
||||||
|
|
||||||
|
if (accountCategory === "all-account") {
|
||||||
|
// Handle all accounts selection
|
||||||
|
const allAccounts = availableAccountsList.map(acc => ({
|
||||||
|
mediaBlastCampaignId: campaignId,
|
||||||
|
mediaBlastAccountId: acc.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (const request of allAccounts) {
|
||||||
|
const response = await saveMediaBlastCampaignAccount(request);
|
||||||
|
if (response?.error) {
|
||||||
|
error(response.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (accountCategory === "kategori" && selectedCategory) {
|
||||||
|
// Handle category selection
|
||||||
|
const categoryAccounts = availableAccountsList.filter(
|
||||||
|
acc => acc.category === selectedCategory
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const acc of categoryAccounts) {
|
||||||
|
const request = {
|
||||||
|
mediaBlastCampaignId: campaignId,
|
||||||
|
mediaBlastAccountId: acc.id,
|
||||||
|
};
|
||||||
|
const response = await saveMediaBlastCampaignAccount(request);
|
||||||
|
if (response?.error) {
|
||||||
|
error(response.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (accountCategory === "custom") {
|
||||||
|
// Handle custom selection
|
||||||
for (const acc of selectedAccount) {
|
for (const acc of selectedAccount) {
|
||||||
const request = {
|
const request = {
|
||||||
mediaBlastCampaignId: campaignId,
|
mediaBlastCampaignId: campaignId,
|
||||||
|
|
@ -162,10 +210,27 @@ const AccountListTable = () => {
|
||||||
const response = await saveMediaBlastCampaignAccount(request);
|
const response = await saveMediaBlastCampaignAccount(request);
|
||||||
if (response?.error) {
|
if (response?.error) {
|
||||||
error(response.message);
|
error(response.message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
success("Akun berhasil ditambahkan ke campaign!");
|
||||||
|
resetDialogState();
|
||||||
fetchData();
|
fetchData();
|
||||||
|
} catch (err) {
|
||||||
|
close();
|
||||||
|
error("Terjadi kesalahan saat menyimpan akun");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetDialogState = () => {
|
||||||
|
setAccountCategory("");
|
||||||
|
setSelectedAccount([]);
|
||||||
|
setSelectedCategory("");
|
||||||
|
setIsDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handleFilter = (id: string, checked: boolean) => {
|
const handleFilter = (id: string, checked: boolean) => {
|
||||||
let temp = [...filtered];
|
let temp = [...filtered];
|
||||||
|
|
@ -174,27 +239,54 @@ const AccountListTable = () => {
|
||||||
setFiltered(temp);
|
setFiltered(temp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAccountSelection = (accountId: string, checked: boolean) => {
|
||||||
|
if (checked) {
|
||||||
|
const account = availableAccountsList.find(acc => acc.id === accountId);
|
||||||
|
if (account && !selectedAccount.find(acc => acc.id === accountId)) {
|
||||||
|
setSelectedAccount([...selectedAccount, account]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setSelectedAccount(selectedAccount.filter(acc => acc.id !== accountId));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeSelectedAccount = (accountId: string) => {
|
||||||
|
setSelectedAccount(selectedAccount.filter(acc => acc.id !== accountId));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFilteredAccounts = () => {
|
||||||
|
if (accountCategory === "kategori" && selectedCategory) {
|
||||||
|
return availableAccountsList.filter(acc => acc.category === selectedCategory);
|
||||||
|
}
|
||||||
|
return availableAccountsList;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
<div className="w-full overflow-x-auto bg-white p-4 rounded-sm space-y-3">
|
||||||
<div className="flex justify-between mb-3 items-center">
|
<div className="flex justify-between mb-3 items-center">
|
||||||
<p className="text-xl font-medium text-default-900">Daftar Akun</p>
|
<p className="text-xl font-medium text-default-900">Daftar Akun</p>
|
||||||
<div className="flex flex-row gap-3">
|
<div className="flex flex-row gap-3">
|
||||||
{/* === Dialog Pilih Akun === */}
|
{/* === Dialog Pilih Akun === */}
|
||||||
<Dialog>
|
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button size="sm" className="text-sm">
|
<Button size="sm" className="text-sm">
|
||||||
<Icon icon="tdesign:user-add-filled" className="mr-2" />
|
<Icon icon="tdesign:user-add-filled" className="mr-2" />
|
||||||
Pilih Akun
|
Pilih Akun
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="max-w-lg">
|
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Pilih Akun Untuk Campaign Ini</DialogTitle>
|
<DialogTitle>Pilih Akun Untuk Campaign Ini</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={accountCategory}
|
value={accountCategory}
|
||||||
onValueChange={(val) => setAccountCategory(val)}
|
onValueChange={(val) => {
|
||||||
|
setAccountCategory(val);
|
||||||
|
setSelectedAccount([]);
|
||||||
|
setSelectedCategory("");
|
||||||
|
}}
|
||||||
className="space-y-3"
|
className="space-y-3"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
|
@ -211,34 +303,10 @@ const AccountListTable = () => {
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<div className="mt-4 space-y-4">
|
{/* Category Selection */}
|
||||||
{accountCategory === "custom" && (
|
|
||||||
<>
|
|
||||||
<Select
|
|
||||||
onValueChange={(val) =>
|
|
||||||
setSelectedAccount([...selectedAccount, { id: val }])
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger>
|
|
||||||
<SelectValue placeholder="Pilih akun" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{dataTable.map((acc) => (
|
|
||||||
<SelectItem key={acc.id} value={acc.id}>
|
|
||||||
{acc.accountName}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
{selectedAccount.length < 1 && (
|
|
||||||
<p className="text-sm text-red-500">
|
|
||||||
Pilih minimal 1 akun
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{accountCategory === "kategori" && (
|
{accountCategory === "kategori" && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Pilih Kategori:</Label>
|
||||||
<Select onValueChange={(val) => setSelectedCategory(val)}>
|
<Select onValueChange={(val) => setSelectedCategory(val)}>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Pilih kategori" />
|
<SelectValue placeholder="Pilih kategori" />
|
||||||
|
|
@ -250,10 +318,64 @@ const AccountListTable = () => {
|
||||||
<SelectItem value="jurnalis">Jurnalis</SelectItem>
|
<SelectItem value="jurnalis">Jurnalis</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Custom Account Selection */}
|
||||||
|
{accountCategory === "custom" && (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Label>Pilih Akun:</Label>
|
||||||
|
<div className="grid grid-cols-1 gap-2 max-h-60 overflow-y-auto">
|
||||||
|
{getFilteredAccounts().map((acc) => (
|
||||||
|
<div key={acc.id} className="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
id={`acc-${acc.id}`}
|
||||||
|
checked={selectedAccount.some(selected => selected.id === acc.id)}
|
||||||
|
onCheckedChange={(checked) => handleAccountSelection(acc.id, Boolean(checked))}
|
||||||
|
/>
|
||||||
|
<Label htmlFor={`acc-${acc.id}`} className="text-sm">
|
||||||
|
{acc.accountName} ({acc.category.toUpperCase()})
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Selected Accounts Display */}
|
||||||
|
{selectedAccount.length > 0 && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Akun Terpilih:</Label>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{selectedAccount.map((acc) => (
|
||||||
|
<Badge key={acc.id} variant="secondary" className="flex items-center gap-1">
|
||||||
|
{acc.accountName}
|
||||||
|
<X
|
||||||
|
className="h-3 w-3 cursor-pointer"
|
||||||
|
onClick={() => removeSelectedAccount(acc.id)}
|
||||||
|
/>
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* All Accounts Info */}
|
||||||
{accountCategory === "all-account" && (
|
{accountCategory === "all-account" && (
|
||||||
<p className="text-sm text-gray-600">Semua akun dipilih</p>
|
<div className="p-3 bg-blue-50 rounded-md">
|
||||||
|
<p className="text-sm text-blue-700">
|
||||||
|
Semua akun ({availableAccountsList.length} akun) akan ditambahkan ke campaign ini.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Category Accounts Info */}
|
||||||
|
{accountCategory === "kategori" && selectedCategory && (
|
||||||
|
<div className="p-3 bg-green-50 rounded-md">
|
||||||
|
<p className="text-sm text-green-700">
|
||||||
|
{getFilteredAccounts().length} akun dari kategori "{selectedCategory}" akan ditambahkan.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -261,13 +383,17 @@ const AccountListTable = () => {
|
||||||
<Button
|
<Button
|
||||||
onClick={saveCampaignAccount}
|
onClick={saveCampaignAccount}
|
||||||
disabled={
|
disabled={
|
||||||
accountCategory === "custom" && selectedAccount.length < 1
|
!accountCategory ||
|
||||||
|
(accountCategory === "custom" && selectedAccount.length < 1) ||
|
||||||
|
(accountCategory === "kategori" && !selectedCategory)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Simpan
|
Simpan
|
||||||
</Button>
|
</Button>
|
||||||
<DialogClose asChild>
|
<DialogClose asChild>
|
||||||
<Button variant="outline">Batal</Button>
|
<Button variant="outline" onClick={resetDialogState}>
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -575,10 +575,108 @@ html[dir="rtl"] .react-select .select__loading-indicator {
|
||||||
background: #9ca3af;
|
background: #9ca3af;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CKEditor Styling */
|
||||||
.ck-editor__editable_inline {
|
.ck-editor__editable_inline {
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Main CKEditor content area styling */
|
||||||
|
.ck.ck-editor__editable {
|
||||||
|
padding: 1.5em 2em !important;
|
||||||
|
min-height: 400px;
|
||||||
|
max-height: 600px;
|
||||||
|
line-height: 1.6;
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor content styling */
|
||||||
|
.ck.ck-editor__editable .ck-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor scrollbar styling */
|
||||||
|
.ck.ck-editor__editable::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable::-webkit-scrollbar-track {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor editable area focus state */
|
||||||
|
.ck.ck-editor__editable.ck-focused {
|
||||||
|
border-color: #1a9aef;
|
||||||
|
box-shadow: 0 0 0 2px rgba(26, 154, 239, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor toolbar styling */
|
||||||
|
.ck.ck-toolbar {
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor editable border styling */
|
||||||
|
.ck.ck-editor__editable {
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CKEditor content typography */
|
||||||
|
.ck.ck-editor__editable p {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* View Editor specific styling (read-only mode) */
|
||||||
|
.ckeditor-view-wrapper .ck.ck-editor__editable {
|
||||||
|
background-color: #f8fafc !important;
|
||||||
|
color: #4b5563 !important;
|
||||||
|
cursor: default !important;
|
||||||
|
border: 1px solid #d1d5db !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper .ck.ck-editor__editable.ck-focused {
|
||||||
|
border-color: #d1d5db !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper .ck.ck-toolbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable h1,
|
||||||
|
.ck.ck-editor__editable h2,
|
||||||
|
.ck.ck-editor__editable h3,
|
||||||
|
.ck.ck-editor__editable h4,
|
||||||
|
.ck.ck-editor__editable h5,
|
||||||
|
.ck.ck-editor__editable h6 {
|
||||||
|
margin: 1em 0 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable ul,
|
||||||
|
.ck.ck-editor__editable ol {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable blockquote {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-left: 4px solid #d1d5db;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hide FullCalendar grid elements */
|
/* Hide FullCalendar grid elements */
|
||||||
.fc-view-harness:has(.hide-calendar-grid) {
|
.fc-view-harness:has(.hide-calendar-grid) {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import type { Metadata } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import "./theme.css";
|
import "./theme.css";
|
||||||
|
import "../../style/ckeditor.css";
|
||||||
import { ThemeProvider } from "@/providers/theme-provider";
|
import { ThemeProvider } from "@/providers/theme-provider";
|
||||||
import MountedProvider from "@/providers/mounted.provider";
|
import MountedProvider from "@/providers/mounted.provider";
|
||||||
import { Toaster } from "@/components/ui/toaster";
|
import { Toaster } from "@/components/ui/toaster";
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ import { CKEditor } from "@ckeditor/ckeditor5-react";
|
||||||
import Editor from "ckeditor5-custom-build";
|
import Editor from "ckeditor5-custom-build";
|
||||||
|
|
||||||
function CustomEditor(props) {
|
function CustomEditor(props) {
|
||||||
|
const maxHeight = props.maxHeight || 600; // Default max height 600px
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="ckeditor-wrapper">
|
||||||
<CKEditor
|
<CKEditor
|
||||||
editor={Editor}
|
editor={Editor}
|
||||||
data={props.initialData}
|
data={props.initialData}
|
||||||
|
|
@ -33,8 +36,87 @@ function CustomEditor(props) {
|
||||||
"codeBlock",
|
"codeBlock",
|
||||||
"sourceEditing",
|
"sourceEditing",
|
||||||
],
|
],
|
||||||
|
// Add content styling configuration
|
||||||
|
content_style: `
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: 1em 0 0.5em 0;
|
||||||
|
}
|
||||||
|
ul, ol {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-left: 4px solid #d1d5db;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// Editor appearance settings
|
||||||
|
height: props.height || 400,
|
||||||
|
removePlugins: ['Title'],
|
||||||
|
// Better mobile support
|
||||||
|
mobile: {
|
||||||
|
theme: 'silver'
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<style jsx>{`
|
||||||
|
.ckeditor-wrapper {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__main) {
|
||||||
|
min-height: ${props.height || 400}px;
|
||||||
|
max-height: ${maxHeight}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable) {
|
||||||
|
min-height: ${(props.height || 400) - 50}px;
|
||||||
|
max-height: ${maxHeight - 50}px;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar styling for webkit browsers */
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar) {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-track) {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-thumb) {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover) {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure content doesn't overflow */
|
||||||
|
.ckeditor-wrapper :global(.ck.ck-editor__editable .ck-content) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import { CKEditor } from "@ckeditor/ckeditor5-react";
|
||||||
import Editor from "ckeditor5-custom-build";
|
import Editor from "ckeditor5-custom-build";
|
||||||
|
|
||||||
function ViewEditor(props) {
|
function ViewEditor(props) {
|
||||||
|
const maxHeight = props.maxHeight || 600; // Default max height 600px
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="ckeditor-view-wrapper">
|
||||||
<CKEditor
|
<CKEditor
|
||||||
editor={Editor}
|
editor={Editor}
|
||||||
data={props.initialData}
|
data={props.initialData}
|
||||||
|
|
@ -11,8 +14,98 @@ function ViewEditor(props) {
|
||||||
config={{
|
config={{
|
||||||
// toolbar: [],
|
// toolbar: [],
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
|
// Add content styling configuration for read-only mode
|
||||||
|
content_style: `
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin: 1em 0 0.5em 0;
|
||||||
|
}
|
||||||
|
ul, ol {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border-left: 4px solid #d1d5db;
|
||||||
|
background-color: #f9fafb;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
// Editor appearance settings
|
||||||
|
height: props.height || 400,
|
||||||
|
removePlugins: ['Title'],
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<style jsx>{`
|
||||||
|
.ckeditor-view-wrapper {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__main) {
|
||||||
|
min-height: ${props.height || 400}px;
|
||||||
|
max-height: ${maxHeight}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable) {
|
||||||
|
min-height: ${(props.height || 400) - 50}px;
|
||||||
|
max-height: ${maxHeight - 50}px;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #cbd5e1 #f1f5f9;
|
||||||
|
background-color:rgb(253, 253, 253);
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar styling for webkit browsers */
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar) {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-track) {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-thumb) {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover) {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure content doesn't overflow */
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable .ck-content) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-only specific styling */
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-editor__editable.ck-read-only) {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
color: #4b5563;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide toolbar for view-only mode */
|
||||||
|
.ckeditor-view-wrapper :global(.ck.ck-toolbar) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -950,8 +950,8 @@ export default function FormImageDetail() {
|
||||||
setCheckedLevels(levels);
|
setCheckedLevels(levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -261,8 +261,8 @@ export default function FormAudioTaDetail() {
|
||||||
});
|
});
|
||||||
setupPlacementCheck(details?.files?.length);
|
setupPlacementCheck(details?.files?.length);
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -247,8 +247,8 @@ export default function FormImageTaDetail() {
|
||||||
});
|
});
|
||||||
setupPlacementCheck(details?.files?.length);
|
setupPlacementCheck(details?.files?.length);
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -246,8 +246,8 @@ export default function FormTeksTaDetail() {
|
||||||
format: details?.files[0]?.format,
|
format: details?.files[0]?.format,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -237,8 +237,8 @@ export default function FormVideoTaDetail() {
|
||||||
format: details?.files[0]?.format,
|
format: details?.files[0]?.format,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -519,8 +519,8 @@ export default function FormTeksDetail() {
|
||||||
setCheckedLevels(levels);
|
setCheckedLevels(levels);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ export default function FormVideoDetail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details?.publishedForObject) {
|
if (details?.publishedForObject) {
|
||||||
const publisherIds = details.publishedForObject.map(
|
const publisherIds = details?.publishedForObject?.map(
|
||||||
(obj: any) => obj.id
|
(obj: any) => obj.id
|
||||||
);
|
);
|
||||||
setSelectedPublishers(publisherIds);
|
setSelectedPublishers(publisherIds);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
/* CKEditor Custom Styling */
|
||||||
|
|
||||||
|
/* Main editor container */
|
||||||
|
.ck.ck-editor {
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toolbar styling */
|
||||||
|
.ck.ck-toolbar {
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-bottom: none;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-toolbar .ck-toolbar__items {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main editable area */
|
||||||
|
.ck.ck-editor__editable {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 0 6px 6px;
|
||||||
|
padding: 1.5em 2em !important;
|
||||||
|
min-height: 400px;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focus state */
|
||||||
|
.ck.ck-editor__editable.ck-focused {
|
||||||
|
border-color: #1a9aef;
|
||||||
|
box-shadow: 0 0 0 2px rgba(26, 154, 239, 0.2);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content styling */
|
||||||
|
.ck.ck-editor__editable .ck-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography improvements */
|
||||||
|
.ck.ck-editor__editable p {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable h1,
|
||||||
|
.ck.ck-editor__editable h2,
|
||||||
|
.ck.ck-editor__editable h3,
|
||||||
|
.ck.ck-editor__editable h4,
|
||||||
|
.ck.ck-editor__editable h5,
|
||||||
|
.ck.ck-editor__editable h6 {
|
||||||
|
margin: 1em 0 0.5em 0;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable h1 { font-size: 1.75em; }
|
||||||
|
.ck.ck-editor__editable h2 { font-size: 1.5em; }
|
||||||
|
.ck.ck-editor__editable h3 { font-size: 1.25em; }
|
||||||
|
.ck.ck-editor__editable h4 { font-size: 1.1em; }
|
||||||
|
.ck.ck-editor__editable h5 { font-size: 1em; }
|
||||||
|
.ck.ck-editor__editable h6 { font-size: 0.9em; }
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
.ck.ck-editor__editable ul,
|
||||||
|
.ck.ck-editor__editable ol {
|
||||||
|
margin: 0.5em 0;
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable li {
|
||||||
|
margin: 0.25em 0;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blockquotes */
|
||||||
|
.ck.ck-editor__editable blockquote {
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 0.75em 1em;
|
||||||
|
border-left: 4px solid #1a9aef;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
font-style: italic;
|
||||||
|
color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
.ck.ck-editor__editable table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable table td,
|
||||||
|
.ck.ck-editor__editable table th {
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
padding: 0.5em 0.75em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable table th {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
.ck.ck-editor__editable a {
|
||||||
|
color: #1a9aef;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable a:hover {
|
||||||
|
color: #0d7cd6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
.ck.ck-editor__editable pre {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 1em 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable code {
|
||||||
|
background-color: #f1f5f9;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Images */
|
||||||
|
.ck.ck-editor__editable img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal rule */
|
||||||
|
.ck.ck-editor__editable hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #d1d5db;
|
||||||
|
margin: 2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Placeholder text */
|
||||||
|
.ck.ck-editor__editable.ck-blurred:empty::before {
|
||||||
|
content: attr(data-placeholder);
|
||||||
|
color: #9ca3af;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile responsiveness */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.ck.ck-editor__editable {
|
||||||
|
padding: 1em 1.5em !important;
|
||||||
|
font-size: 16px; /* Better for mobile */
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-toolbar {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-toolbar .ck-toolbar__items {
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode support */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.ck.ck-editor__editable {
|
||||||
|
background: #1f2937;
|
||||||
|
color: #f9fafb;
|
||||||
|
border-color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable h1,
|
||||||
|
.ck.ck-editor__editable h2,
|
||||||
|
.ck.ck-editor__editable h3,
|
||||||
|
.ck.ck-editor__editable h4,
|
||||||
|
.ck.ck-editor__editable h5,
|
||||||
|
.ck.ck-editor__editable h6 {
|
||||||
|
color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable blockquote {
|
||||||
|
background-color: #374151;
|
||||||
|
border-left-color: #1a9aef;
|
||||||
|
color: #d1d5db;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable pre {
|
||||||
|
background-color: #374151;
|
||||||
|
border-color: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-editor__editable code {
|
||||||
|
background-color: #4b5563;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue