fix: ck editor in darkmode

This commit is contained in:
Sabda Yagra 2026-02-05 18:02:24 +07:00
parent 27fbb39396
commit 587e0568fc
13 changed files with 266 additions and 116 deletions

View File

@ -6,7 +6,7 @@ const page = () => {
return ( return (
<div className=""> <div className="">
<SiteBreadcrumb /> <SiteBreadcrumb />
<div className="bg-slate-100"> <div className="bg-slate-100 dark:bg-default-50">
<CategoriesUpdateForm /> <CategoriesUpdateForm />
</div> </div>
</div> </div>

View File

@ -150,10 +150,10 @@ export default function UserDetailPage() {
<p className="text-lg font-mono">{user.statusId}</p> <p className="text-lg font-mono">{user.statusId}</p>
</div> </div>
<div> {/* <div>
<label className="text-sm font-medium text-gray-600">Keycloak ID</label> <label className="text-sm font-medium text-gray-600">Keycloak ID</label>
<p className="text-xs font-mono break-all bg-gray-100 p-2 rounded">{user.keycloakId}</p> <p className="text-xs font-mono break-all p-2 rounded">{user.keycloakId}</p>
</div> </div> */}
<div> <div>
<label className="text-sm font-medium text-gray-600">Dibuat Oleh</label> <label className="text-sm font-medium text-gray-600">Dibuat Oleh</label>
@ -185,10 +185,10 @@ export default function UserDetailPage() {
<p className="text-lg">{formatDateToIndonesian(user.updatedAt)}</p> <p className="text-lg">{formatDateToIndonesian(user.updatedAt)}</p>
</div> </div>
<div> {/* <div>
<label className="text-sm font-medium text-gray-600">Foto Profil</label> <label className="text-sm font-medium text-gray-600">Foto Profil</label>
<p className="text-lg">{user.profilePicturePath ? "Tersedia" : "Tidak ada"}</p> <p className="text-lg">{user.profilePicturePath ? "Tersedia" : "Tidak ada"}</p>
</div> </div> */}
</div> </div>
{/* Additional Information (only show if data exists) */} {/* Additional Information (only show if data exists) */}

View File

@ -133,25 +133,6 @@
} }
} }
@layer base {
/* CKEditor force light mode even in dark */
.ck-viewer .ck.ck-editor__main > .ck-editor__editable {
@apply bg-white text-black;
}
.ck-viewer .ck-content {
@apply text-black;
}
.ck-viewer .ck-content h1,
.ck-viewer .ck-content h2,
.ck-viewer .ck-content h3,
.ck-viewer .ck-content p,
.ck-viewer .ck-content li {
@apply text-black;
}
}
/* @import "tailwindcss"; /* @import "tailwindcss";
@import "tw-animate-css"; @import "tw-animate-css";

View File

@ -7,7 +7,7 @@ import Navbar from "@/components/landing-page/navbar";
export default function Home() { export default function Home() {
return ( return (
<div className="relative min-h-screen font-[family-name:var(--font-geist-sans)]"> <div className="relative min-h-screen font-[family-name:var(--font-geist-sans)]">
<div className="relative z-10 bg-white w-full mx-auto"> <div className="relative z-10 bg-white dark:bg-default-50 w-full mx-auto">
<Navbar /> <Navbar />
<div className="flex-1"> <div className="flex-1">
<Header /> <Header />

View File

@ -2,40 +2,213 @@
import React from "react"; import React from "react";
import { CKEditor } from "@ckeditor/ckeditor5-react"; import { CKEditor } from "@ckeditor/ckeditor5-react";
import Editor from "@/vendor/ckeditor5/build/ckeditor"; import Editor from "ckeditor5-custom-build";
function CustomEditor(props) { function CustomEditor(props) {
const maxHeight = props.maxHeight || 600;
return ( return (
<CKEditor <div className="ckeditor-wrapper">
editor={Editor} <CKEditor
data={props.initialData} editor={Editor}
onChange={(event, editor) => { data={props.initialData}
const data = editor.getData(); onChange={(event, editor) => {
console.log({ event, editor, data }); const data = editor.getData();
props.onChange(data); console.log({ event, editor, data });
}} props.onChange(data);
config={{ }}
toolbar: [ config={{
"heading", toolbar: [
"fontsize", "heading",
"bold", "fontsize",
"italic", "bold",
"link", "italic",
"numberedList", "link",
"bulletedList", "numberedList",
"undo", "bulletedList",
"redo", "undo",
"alignment", "redo",
"outdent", "alignment",
"indent", "outdent",
"blockQuote", "indent",
"insertTable", "blockQuote",
"codeBlock", "insertTable",
"sourceEditing", "codeBlock",
], "sourceEditing",
}} ],
/> content_style: `
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #111 !important;
background: #fff !important;
margin: 0;
padding: 1rem;
}
p {
margin: 0.5em 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.5em 0;
color: inherit !important;
}
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;
color: inherit !important;
}
`,
height: props.height || 400,
removePlugins: ["Title"],
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;
background: #fff !important;
color: #111 !important;
}
/* Dark mode support */
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable) {
background: #111 !important;
color: #f9fafb !important;
}
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h1),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h2),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h3),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h4),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h5),
:global(.dark) .ckeditor-wrapper :global(.ck.ck-editor__editable h6) {
color: #f9fafb !important;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable blockquote) {
background-color: #1f2937 !important;
border-left-color: #374151 !important;
color: #f3f4f6 !important;
}
/* 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;
}
/* Dark mode scrollbar */
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-track) {
background: #1f2937;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb) {
background: #4b5563;
}
:global(.dark)
.ckeditor-wrapper
:global(.ck.ck-editor__editable::-webkit-scrollbar-thumb:hover) {
background: #6b7280;
}
/* Ensure content doesn't overflow */
.ckeditor-wrapper :global(.ck.ck-editor__editable .ck-content) {
overflow: hidden;
}
`}</style>
</div>
); );
} }
export default CustomEditor; export default CustomEditor;
// // components/custom-editor.js
// import React from "react";
// import { CKEditor } from "@ckeditor/ckeditor5-react";
// import Editor from "@/vendor/ckeditor5/build/ckeditor";
// function CustomEditor(props) {
// return (
// <CKEditor
// editor={Editor}
// data={props.initialData}
// onChange={(event, editor) => {
// const data = editor.getData();
// console.log({ event, editor, data });
// props.onChange(data);
// }}
// config={{
// toolbar: [
// "heading",
// "fontsize",
// "bold",
// "italic",
// "link",
// "numberedList",
// "bulletedList",
// "undo",
// "redo",
// "alignment",
// "outdent",
// "indent",
// "blockQuote",
// "insertTable",
// "codeBlock",
// "sourceEditing",
// ],
// }}
// />
// );
// }
// export default CustomEditor;

View File

@ -1,39 +1,18 @@
// import React from "react";
// import { CKEditor } from "@ckeditor/ckeditor5-react";
// import Editor from "@/vendor/ckeditor5/build/ckeditor";
// function ViewEditor(props) {
// return (
// <CKEditor
// editor={Editor}
// data={props.initialData}
// disabled={true}
// config={{
// // toolbar: [],
// isReadOnly: true,
// }}
// />
// );
// }
// export default ViewEditor;
import React from "react"; import React from "react";
import { CKEditor } from "@ckeditor/ckeditor5-react"; import { CKEditor } from "@ckeditor/ckeditor5-react";
import Editor from "@/vendor/ckeditor5/build/ckeditor"; import Editor from "@/vendor/ckeditor5/build/ckeditor";
function ViewEditor({ initialData }) { function ViewEditor(props) {
return ( return (
<div className="ck-viewer"> <CKEditor
<CKEditor editor={Editor}
editor={Editor} data={props.initialData}
data={initialData} disabled={true}
disabled config={{
config={{ // toolbar: [],
isReadOnly: true, isReadOnly: true,
}} }}
/> />
</div>
); );
} }

View File

@ -122,11 +122,28 @@ export default function CategoriesUpdateForm() {
// 🔹 hanya kirim data mandatory // 🔹 hanya kirim data mandatory
const payload = { const payload = {
id: formData.id, id: formData.id,
description: formData.description || "", title: formData.title,
statusId: formData.statusId || 1, description: formData.description,
title: formData.title || "", statusId: formData.statusId,
// ⬇️ FIELD KRUSIAL (WAJIB)
isActive: true,
is_active: true,
isPublish: formData.isPublish,
publishedAt: formData.publishedAt,
parentId: formData.parentId,
slug: formData.slug,
createdById: formData.createdById,
}; };
// const payload = {
// id: formData.id,
// description: formData.description || "",
// statusId: formData.statusId || 1,
// title: formData.title || "",
// };
console.log("UPDATE PAYLOAD:", payload);
const res = await updateArticleCategory(Number(id), payload); const res = await updateArticleCategory(Number(id), payload);
if (!res?.error) { if (!res?.error) {

View File

@ -56,7 +56,7 @@ export default function Category() {
return ( return (
<section className="px-4 py-10"> <section className="px-4 py-10">
<div className="max-w-[1350px] mx-auto bg-white rounded-xl shadow-md p-6"> <div className="max-w-[1350px] mx-auto bg-white dark:bg-default-50 dark:border dark:border-slate-50 rounded-xl shadow-md p-6">
<h2 className="text-xl font-semibold mb-5"> <h2 className="text-xl font-semibold mb-5">
{loading {loading
? t("loadCategory") ? t("loadCategory")
@ -89,7 +89,7 @@ export default function Category() {
return ( return (
<button <button
key={index} key={index}
className="px-4 py-2 rounded border border-gray-300 text-gray-700 text-sm font-medium hover:bg-gray-100 hover:border-gray-400 transition-all duration-200" className="px-4 py-2 rounded border border-gray-300 text-gray-700 dark:text-white text-sm font-medium hover:bg-gray-100 hover:border-gray-400 transition-all duration-200"
onClick={() => { onClick={() => {
// Navigate to category page or search by category // Navigate to category page or search by category
console.log( console.log(

View File

@ -100,7 +100,7 @@ export default function Footer() {
}, []); }, []);
return ( return (
<footer className="border-t bg-white text-center"> <footer className="border-t bg-white dark:bg-default-50 text-center">
<style jsx>{swiperStyles}</style> <style jsx>{swiperStyles}</style>
<div className="max-w-[1350px] mx-auto"> <div className="max-w-[1350px] mx-auto">
<div className="py-6"> <div className="py-6">
@ -195,7 +195,7 @@ export default function Footer() {
<div className="border-t my-6 w-full max-w-6xl mx-auto" /> <div className="border-t my-6 w-full max-w-6xl mx-auto" />
<div className="flex flex-col md:flex-row items-center justify-between gap-4 px-4 pb-6 max-w-6xl mx-auto text-sm text-gray-600"> <div className="flex flex-col md:flex-row items-center justify-between gap-4 px-4 pb-6 max-w-6xl mx-auto text-sm text-gray-600 dark:text-white">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>ver 1.0.0 @2025 - {t("netidhub")}</span> <span>ver 1.0.0 @2025 - {t("netidhub")}</span>
<Image <Image
@ -208,7 +208,7 @@ export default function Footer() {
</div> </div>
{/* Social Media */} {/* Social Media */}
<div className="flex gap-3 text-gray-800"> <div className="flex gap-3 text-gray-800 dark:text-white">
<Instagram className="hover:text-black" /> <Instagram className="hover:text-black" />
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@ -294,7 +294,7 @@ function Card({
return ( return (
<div> <div>
<div <div
className={`rounded-xl overflow-hidden shadow hover:shadow-lg transition-all bg-white ${ className={`rounded-xl overflow-hidden shadow hover:shadow-lg transition-all bg-white dark:bg-black dark:border dark:border-slate-50 ${
isBig isBig
? "w-full lg:max-w-[670px] lg:min-h-[680px]" ? "w-full lg:max-w-[670px] lg:min-h-[680px]"
: "w-full h-[350px] md:h-[330px]" : "w-full h-[350px] md:h-[330px]"

View File

@ -358,15 +358,15 @@ export default function MediaUpdate() {
} }
return ( return (
<section className="bg-white px-4 py-10 border max-w-[1350px] mx-auto rounded-md border-[#CDD5DF] my-10"> <section className="bg-white dark:bg-default-50 px-4 py-10 border max-w-[1350px] mx-auto rounded-md border-[#CDD5DF] my-10">
<div className="max-w-screen-xl mx-auto"> <div className="max-w-screen-xl mx-auto">
<h2 className="text-2xl font-semibold text-center mb-6"> <h2 className="text-2xl font-semibold text-center mb-6">
{t("title")} {t("title")}
</h2> </h2>
{/* Main Tab */} {/* Main Tab */}
<div className="flex justify-center mb-6 bg-white"> <div className="flex justify-center mb-6 bg-white dark:bg-default-50">
<Card className="bg-[#FFFFFF] rounded-xl flex flex-row p-3 gap-2 shadow-md border border-gray-200"> <Card className="bg-[#FFFFFF] dark:bg-default-50 rounded-xl flex flex-row p-3 gap-2 shadow-md border border-gray-200">
<button <button
onClick={() => setTab("latest")} onClick={() => setTab("latest")}
className={`px-6 py-3 rounded-lg text-sm font-semibold transition-all duration-200 ${ className={`px-6 py-3 rounded-lg text-sm font-semibold transition-all duration-200 ${
@ -392,7 +392,7 @@ export default function MediaUpdate() {
{/* Content Type Filter */} {/* Content Type Filter */}
<div className="flex justify-center mb-8"> <div className="flex justify-center mb-8">
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-2xl p-4 border-2 border-blue-100 shadow-lg"> <div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-2xl p-4 border-2 border-blue-100 shadow-lg dark:bg-default-50">
<div className="flex flex-wrap justify-center gap-2"> <div className="flex flex-wrap justify-center gap-2">
{/* <button {/* <button
onClick={() => setContentType("all")} onClick={() => setContentType("all")}
@ -465,7 +465,7 @@ export default function MediaUpdate() {
> >
{filteredData.map((item) => ( {filteredData.map((item) => (
<SwiperSlide key={item.id}> <SwiperSlide key={item.id}>
<div className="rounded-xl shadow-md overflow-hidden bg-white"> <div className="rounded-xl shadow-md overflow-hidden bg-white dark:bg-default-50 dark:border dark:border-slate-50">
{/* ✅ Kondisi: jika typeId = 3 (text) atau 4 (audio) tampilkan ikon, lainnya tampilkan thumbnail */} {/* ✅ Kondisi: jika typeId = 3 (text) atau 4 (audio) tampilkan ikon, lainnya tampilkan thumbnail */}
{item.typeId === 3 ? ( {item.typeId === 3 ? (
// 📝 TEXT // 📝 TEXT

View File

@ -122,7 +122,7 @@ export default function Navbar() {
<button <button
onClick={() => setDropdownOpen(!isDropdownOpen)} onClick={() => setDropdownOpen(!isDropdownOpen)}
className={cn( className={cn(
"relative text-gray-500 hover:text-black transition-colors", "relative text-gray-500 dark:text-white dark:hover:text-slate-300 hover:text-black transition-colors",
isDropdownOpen || isDropdownOpen ||
pathname.startsWith("/public/publication") pathname.startsWith("/public/publication")
? "text-black" ? "text-black"
@ -147,7 +147,7 @@ export default function Navbar() {
<Link <Link
key={sub.label} key={sub.label}
href={sub.href} href={sub.href}
className="block px-4 py-2 text-sm hover:bg-gray-100 text-gray-700" className="block px-4 py-2 text-sm hover:bg-gray-100 text-gray-700 dark:text-white"
> >
{sub.label} {sub.label}
</Link> </Link>
@ -160,7 +160,7 @@ export default function Navbar() {
href={item.href} href={item.href}
onClick={handleClick} onClick={handleClick}
className={cn( className={cn(
"relative text-gray-500 hover:text-black transition-colors", "relative text-gray-500 dark:text-white dark:hover:text-slate-300 hover:text-black transition-colors",
isActive && "text-black", isActive && "text-black",
)} )}
> >
@ -194,7 +194,7 @@ export default function Navbar() {
<div className="relative"> <div className="relative">
<button <button
onClick={() => setShowProfileMenu((prev) => !prev)} onClick={() => setShowProfileMenu((prev) => !prev)}
className="flex items-center gap-2 border-2 py-1 px-3 rounded-lg hover:bg-gray-50 cursor-pointer" className="flex items-center gap-2 border-2 py-1 px-3 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-700 cursor-pointer"
> >
<div className="w-9 h-9 rounded-full overflow-hidden border"> <div className="w-9 h-9 rounded-full overflow-hidden border">
<Image <Image
@ -205,17 +205,17 @@ export default function Navbar() {
className="object-cover" className="object-cover"
/> />
</div> </div>
<span className="text-sm font-medium text-gray-800"> <span className="text-sm font-medium text-gray-800 dark:text-white">
{fullname} {fullname}
</span> </span>
<ChevronDown className="w-4 h-4 text-gray-600" /> <ChevronDown className="w-4 h-4 text-gray-600" />
</button> </button>
{showProfileMenu && ( {showProfileMenu && (
<div className="absolute right-0 mt-2 w-40 bg-white border rounded shadow z-50 "> <div className="absolute right-0 mt-2 w-40 bg-white dark:bg-black border rounded shadow z-50 ">
<Link <Link
href="/admin/dashboard" href="/admin/dashboard"
className="flex flex-row items-center text-left px-4 py-2 hover:bg-gray-100 text-gray-700" className="flex flex-row items-center text-left px-4 py-2 hover:bg-gray-300 dark:hover:bg-gray-700 text-gray-700 dark:text-white"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -233,7 +233,7 @@ export default function Navbar() {
<button <button
onClick={handleLogout} onClick={handleLogout}
className="w-full flex flex-row text-left px-4 py-2 hover:bg-gray-100 text-gray-700 cursor-pointer" className="w-full flex flex-row text-left px-4 py-2 hover:bg-gray-300 text-gray-700 dark:text-white cursor-pointer"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -312,7 +312,7 @@ export default function Navbar() {
</div> </div>
<div> <div>
<h3 className="text-[16px] font-bold text-gray-700 mb-2"> <h3 className="text-[16px] font-bold text-gray-700 dark:text-white mb-2">
{t("features")} {t("features")}
</h3> </h3>
<div className="space-y-5 ml-3"> <div className="space-y-5 ml-3">
@ -331,7 +331,7 @@ export default function Navbar() {
} }
setIsSidebarOpen(false); setIsSidebarOpen(false);
}} }}
className="block text-[15px] text-gray-800 text-left w-full" className="block text-[15px] text-gray-800 dark:text-white text-left w-full"
> >
{item.label} {item.label}
</button> </button>
@ -340,19 +340,19 @@ export default function Navbar() {
</div> </div>
<div className="space-y-5 text-[16px] font-bold"> <div className="space-y-5 text-[16px] font-bold">
<Link href="/about" className="block text-black"> <Link href="/about" className="block text-black dark:text-white">
{t("about")} {t("about")}
</Link> </Link>
<Link href="/advertising" className="block text-black"> <Link href="/advertising" className="block text-black dark:text-white">
{t("advertising")} {t("advertising")}
</Link> </Link>
<Link href="/contact" className="block text-black"> <Link href="/contact" className="block text-black dark:text-white">
{t("contact")} {t("contact")}
</Link> </Link>
{!isLoggedIn ? ( {!isLoggedIn ? (
<> <>
<Link href="/auth" className="block text-lg text-gray-800"> <Link href="/auth" className="block text-lg text-gray-800 dark:text-white">
{t("login")} {t("login")}
</Link> </Link>
<Link <Link

View File

@ -1,7 +1,7 @@
import type { Config } from "tailwindcss"; import type { Config } from "tailwindcss";
const config = { const config = {
darkMode: ["class", "html"], darkMode: ["class"],
content: [ content: [
"./pages/**/*.{ts,tsx}", "./pages/**/*.{ts,tsx}",
"./components/**/*.{js,ts,tsx}", "./components/**/*.{js,ts,tsx}",