This commit is contained in:
Kevin Dwi Wijaya
2025-08-20 10:10:13 +00:00
parent 144736c02c
commit e356aabc31
20 changed files with 17862 additions and 1 deletions

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -1 +1,70 @@
# maragen # Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

16202
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

44
package.json Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "maragen",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.7.0",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^13.5.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.21",
"postcss": "^8.5.6",
"tailwindcss": "3.4"
}
}

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

16
public/index.html Normal file
View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Otomatisasi Cerdas untuk Bisnismu</title>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

BIN
public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
public/manifest.json Normal file
View File

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

38
src/App.css Normal file
View File

@@ -0,0 +1,38 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

767
src/App.js Normal file
View File

@@ -0,0 +1,767 @@
import React, { useState, useEffect, useRef } from 'react';
import './index.css'; // Pastikan untuk mengimpor file CSS Anda
function App() {
// State untuk mengontrol tampilan: 'landing' atau 'dashboard'
const [view, setView] = useState('landing');
// State untuk modal login/register
const [isAuthModalOpen, setAuthModalOpen] = useState(false);
const [authForm, setAuthForm] = useState('login'); // 'login' atau 'register'
// State untuk bagian aktif di dashboard
const [activeDashboardSection, setActiveDashboardSection] = useState('chatbot');
// State untuk fungsionalitas Chatbot
const [messages, setMessages] = useState([
{ sender: 'bot', text: 'Halo! Ada yang bisa saya bantu hari ini?' }
]);
const [chatInput, setChatInput] = useState('');
const [isChatLoading, setChatLoading] = useState(false);
const chatMessagesEndRef = useRef(null);
// State untuk fungsionalitas Image Generation
const [imagePrompt, setImagePrompt] = useState('');
const [generatedImageUrl, setGeneratedImageUrl] = useState('');
const [isImageLoading, setImageLoading] = useState(false);
// State untuk koneksi media sosial di profil
const [socialConnections, setSocialConnections] = useState({
twitter: false,
instagram: false,
});
// Fungsi untuk scroll otomatis ke pesan terbaru
const scrollToBottom = () => {
chatMessagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};
useEffect(() => {
if (view === 'dashboard' && activeDashboardSection === 'chatbot') {
scrollToBottom();
}
}, [messages, view, activeDashboardSection]);
// --- Fungsi Handler ---
const showDashboard = () => {
setAuthModalOpen(false);
setView('dashboard');
};
const showLanding = () => {
setView('landing');
};
const handleLogin = (e) => {
e.preventDefault();
// Logika login simulasi
const email = e.target.loginEmail.value;
const password = e.target.loginPassword.value;
if (email === "user@example.com" && password === "password123") {
alert("Login berhasil!");
showDashboard();
} else {
alert("Email atau kata sandi salah.");
}
};
const handleRegister = (e) => {
e.preventDefault();
// Logika registrasi simulasi
const password = e.target.registerPassword.value;
const confirmPassword = e.target.confirmPassword.value;
if (password !== confirmPassword) {
alert("Kata sandi tidak cocok.");
return;
}
alert("Registrasi berhasil! Silakan masuk.");
setAuthForm('login');
};
const handleSendMessage = async () => {
const userMessage = chatInput.trim();
if (userMessage === "") return;
// Tambahkan pesan pengguna ke state
setMessages(prev => [...prev, { sender: 'user', text: userMessage }]);
setChatInput('');
setChatLoading(true);
// Simulasi panggilan API ke Gemini
setTimeout(() => {
// Ini adalah respons palsu. Ganti dengan panggilan fetch API asli Anda.
const botResponse = `Ini adalah respons AI untuk: "${userMessage}". Dalam aplikasi nyata, ini akan datang dari API.`;
setMessages(prev => [...prev, { sender: 'bot', text: botResponse }]);
setChatLoading(false);
}, 1500);
};
const handleGenerateImage = async () => {
if (imagePrompt.trim() === "") {
alert("Mohon masukkan deskripsi gambar.");
return;
}
setImageLoading(true);
setGeneratedImageUrl('');
// Simulasi panggilan API pembuatan gambar
setTimeout(() => {
// Ganti URL ini dengan hasil dari API Anda
const mockImageUrl = `https://placehold.co/512x512/142F32/E5FFCC?text=Hasil:+${encodeURIComponent(imagePrompt.substring(0, 20))}`;
setGeneratedImageUrl(mockImageUrl);
setImageLoading(false);
}, 2000);
};
const handleConnectSocial = (platform) => {
setSocialConnections(prev => ({
...prev,
[platform]: !prev[platform]
}));
};
const handleLogout = () => {
// Logika logout
showLanding();
alert("Anda telah berhasil keluar.");
};
// --- Komponen-Komponen Kecil ---
const Header = () => (
<header className="header-bg py-4 px-6 flex justify-between items-center fixed top-0 left-0 w-full z-10">
<div className="flex items-center">
<img src="https://placehold.co/40x40/142F32/E5FFCC?text=M" alt="Logo Maragen" className="h-8 w-8 mr-2 rounded-full" />
<span className="text-2xl font-bold text-gray-800">Maragen</span>
</div>
<nav className="hidden md:flex space-x-8">
<a href="#beranda" className="text-gray-600 hover:text-gray-900 font-medium">Beranda</a>
<a href="#tentang" className="text-gray-600 hover:text-gray-900 font-medium">Tentang</a>
<a href="#layanan" className="text-gray-600 hover:text-gray-900 font-medium">Layanan</a>
<a href="#kontak" className="text-gray-600 hover:text-gray-900 font-medium">Kontak</a>
</nav>
<button onClick={() => setAuthModalOpen(true)} className="button-sign-up px-6 py-2 rounded-lg font-semibold hidden md:block">
Daftar
</button>
<button className="md:hidden text-gray-600 hover:text-gray-900 focus:outline-none">
<i className="fas fa-bars text-2xl"></i>
</button>
</header>
);
const LandingPage = () => (
<div id="landingPage" className="landing-page-content">
{/* Hero Section */}
<section className="hero-section pt-24 pb-12">
<div className="max-w-4xl mx-auto">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-extrabold mb-4 leading-tight text-gray-900">
Masa Depan Otomatisasi dengan <span className="text-142F32">Teknologi Terbaru</span>
</h1>
<p className="text-lg sm:text-xl mb-8 text-gray-600">
Ahli teknologi untuk meningkatkan bisnis Anda. Mari bawa bisnis Anda lebih jauh.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={() => setAuthModalOpen(true)}
className="button-primary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50"
>
Mulai Sekarang
</button>
<button
onClick={showDashboard}
className="button-secondary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-gray-300 focus:ring-opacity-50"
>
Coba Demo
</button>
</div>
<div className="mt-6 flex items-center justify-center text-gray-600">
<i className="fas fa-star text-yellow-400 mr-1"></i>
<i className="fas fa-star text-yellow-400 mr-1"></i>
<i className="fas fa-star text-yellow-400 mr-1"></i>
<i className="fas fa-star text-yellow-400 mr-1"></i>
<i className="fas fa-star-half-alt text-yellow-400 mr-2"></i>
<span>5.0</span>
<span className="ml-2">dari 80+ ulasan</span>
</div>
</div>
{/* Stat Cards Grid */}
<div className="max-w-6xl mx-auto stats-grid mt-16 px-4">
<div className="stat-card overflow-hidden">
<img src="https://placehold.co/400x300/142F32/E5FFCC?text=Otomatisasi" alt="Otomatisasi Visual" className="card-image" />
<div className="p-4 text-center">
<p className="text-gray-700 font-semibold">Visual Otomatisasi</p>
</div>
</div>
<div className="stat-card p-6 dark-bg">
<div className="flex items-center mb-2">
<i className="fas fa-users text-E5FFCC text-2xl mr-3"></i>
<p className="text-3xl font-bold text-white">100+</p>
</div>
<p className="text-gray-400 text-sm">Klien & Mitra Terhormat Kami</p>
</div>
<div className="stat-card p-6">
<div className="flex items-center mb-2">
<i className="fas fa-project-diagram text-142F32 text-2xl mr-3"></i>
<p className="text-3xl font-bold text-gray-800">1951+</p>
</div>
<p className="text-gray-600 text-sm">Total Proyek <span className="text-green-500">126 bulan ini</span></p>
</div>
<div className="stat-card p-6 dark-bg">
<div className="flex items-center mb-2">
<i className="fas fa-calendar-alt text-E5FFCC text-2xl mr-3"></i>
<p className="text-3xl font-bold text-white">6+</p>
</div>
<p className="text-gray-400 text-sm">Tahun Layanan Khusus</p>
</div>
</div>
</section>
{/* Bottom Section (Layanan Otomatisasi) */}
<section className="bottom-section">
<div className="max-w-6xl mx-auto">
<h2 className="text-3xl sm:text-4xl font-extrabold mb-4 text-white">
Layanan Otomatisasi yang Efisien dan Terintegrasi
</h2>
<p className="text-lg sm:text-xl mb-12 opacity-80">
Sederhanakan operasi Anda dengan layanan berkualitas dan berorientasi efisiensi.
</p>
<div className="bottom-grid">
<div className="bottom-card">
<div className="flex items-center justify-between mb-4">
<i className="fas fa-robot text-E5FFCC text-3xl"></i>
<i className="fas fa-arrow-up-right-from-square text-gray-500 hover:text-E5FFCC cursor-pointer"></i>
</div>
<h3 className="text-xl font-semibold mb-2 text-white">Alur Kerja Otomatis</h3>
<p className="text-gray-400 text-sm">
Detail tentang proses otomatisasi, kemampuan integrasi, dan jenis alur kerja yang didukung.
</p>
</div>
<div className="bottom-card">
<div className="flex items-center justify-between mb-4">
<i className="fas fa-cogs text-E5FFCC text-3xl"></i>
<i className="fas fa-arrow-up-right-from-square text-gray-500 hover:text-E5FFCC cursor-pointer"></i>
</div>
<h3 className="text-xl font-semibold mb-2 text-white">Kustomisasi Solusi</h3>
<p className="text-gray-400 text-sm">
Pembuatan solusi otomatisasi khusus dengan opsi desain dan kustomisasi.
</p>
</div>
<div className="bottom-card">
<div className="flex items-center justify-between mb-4">
<i className="fas fa-chart-line text-E5FFCC text-3xl"></i>
<i className="fas fa-arrow-up-right-from-square text-gray-500 hover:text-E5FFCC cursor-pointer"></i>
</div>
<h3 className="text-xl font-semibold mb-2 text-white">Pemantauan & Analisis</h3>
<p className="text-gray-400 text-sm">
Prosedur dan sistem untuk memastikan kualitas output otomatisasi yang tinggi.
</p>
</div>
</div>
</div>
</section>
{/* Key Benefits Section */}
<section className="key-benefits-section">
<div className="benefits-image-card">
<div className="flex items-center justify-between mb-4">
<span className="text-gray-800 font-semibold">Total Proyek</span>
<span className="text-green-500 text-sm">56%</span>
</div>
<div className="space-y-2 text-sm text-gray-600 mb-6">
<div className="flex justify-between">
<span>Selesai</span>
<span>10%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-blue-600 h-2.5 rounded-full" style={{width: '10%'}}></div>
</div>
<div className="flex justify-between">
<span>Sedang Berjalan</span>
<span>13%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-yellow-500 h-2.5 rounded-full" style={{width: '13%'}}></div>
</div>
<div className="flex justify-between">
<span>Ditolak</span>
<span>11%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-red-500 h-2.5 rounded-full" style={{width: '11%'}}></div>
</div>
</div>
<div className="stat-card p-6 dark-bg p-4 mt-4">
<div className="flex items-center mb-2">
<i className="fas fa-project-diagram text-E5FFCC text-2xl mr-3"></i>
<p className="text-3xl font-bold text-white">1951+</p>
</div>
<p className="text-gray-400 text-sm">Peningkatan <span className="text-green-500">126 bulan ini</span></p>
</div>
</div>
<div className="benefits-content">
<h2 className="text-3xl sm:text-4xl font-extrabold mb-6 text-gray-900">
Manfaat Utama Sistem Kami untuk <span className="text-142F32">Efisiensi Bisnis Anda</span>
</h2>
<p className="text-lg sm:text-xl mb-8 text-gray-600">
Sistem kami meningkatkan produktivitas, mengurangi biaya, dan mendorong pertumbuhan bisnis.
</p>
<div className="space-y-6">
<div className="benefit-item">
<i className="fas fa-check-circle text-142F32"></i>
<div>
<h3 className="text-xl font-semibold text-gray-800">Meningkatkan Kualitas dengan Teknologi</h3>
<p className="text-gray-600 text-base">
Dengan teknologi canggih, kami membantu Anda mencapai kualitas produk terbaik. Pelajari bagaimana kami dapat meningkatkan standar Anda.
</p>
</div>
</div>
<div className="benefit-item">
<i className="fas fa-check-circle text-142F32"></i>
<div>
<h3 className="text-xl font-semibold text-gray-800">Optimasi Proses Produksi</h3>
<p className="text-gray-600 text-base">
Meningkatkan efisiensi dan produktivitas pabrik dengan solusi inovatif kami. Lihat bagaimana teknologi terbaru dapat memaksimalkan output Anda.
</p>
</div>
</div>
<div className="benefit-item">
<i className="fas fa-check-circle text-142F32"></i>
<div>
<h3 className="text-xl font-semibold text-gray-800">Produksi Berbasis AI</h3>
<p className="text-gray-600 text-base">
Manfaatkan kekuatan AI untuk mengubah proses manufaktur Anda, mencapai hasil yang lebih cepat dan efektif.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Tailored Plans Section */}
<section className="tailored-plans-section">
<div className="max-w-4xl mx-auto mb-12">
<h2 className="text-3xl sm:text-4xl font-extrabold mb-4 text-white">
Paket yang Disesuaikan untuk <span className="text-E5FFCC">Skala Bisnis Anda</span>
</h2>
<p className="text-lg sm:text-xl opacity-80">
Harga fleksibel untuk setiap ukuran bisnis.
</p>
</div>
<div className="pricing-grid">
<div className="pricing-card">
<h3 className="text-2xl font-semibold mb-2 text-white">Starter</h3>
<p className="text-gray-400 text-base mb-4">
Paket ini menawarkan fitur dasar yang Anda butuhkan untuk memulai.
</p>
<div className="flex items-baseline mb-6">
<span className="price">$39</span>
<span className="price-per-month">/ bulan</span>
</div>
<button className="button-primary w-full py-3 rounded-lg font-semibold text-lg">
Mulai Sekarang
</button>
<div className="feature-list mt-6">
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Produksi hingga 10.000 unit per bulan</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Dukungan teknis 24/7</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Akses ke dasbor produksi</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Pengaturan awal</span></div>
</div>
</div>
<div className="pricing-card">
<h3 className="text-2xl font-semibold mb-2 text-white">Enterprise</h3>
<p className="text-gray-400 text-base mb-4">
Paket ini menyediakan akses penuh ke semua fitur premium.
</p>
<div className="flex items-baseline mb-6">
<span className="price">$99</span>
<span className="price-per-month">/ bulan</span>
</div>
<button className="button-primary w-full py-3 rounded-lg font-semibold text-lg">
Mulai Sekarang
</button>
<div className="feature-list mt-6">
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Unit produksi tak terbatas</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Manajer akun khusus</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Solusi manufaktur yang disesuaikan</span></div>
<div className="feature-item"><i className="fas fa-check-circle text-E5FFCC"></i><span>Optimalisasi produksi prediktif</span></div>
</div>
</div>
</div>
</section>
{/* Seamless Integrations Section */}
<section className="integrations-section">
<div className="integrations-content">
<h2 className="text-3xl sm:text-4xl font-extrabold mb-6 text-gray-900">
Memberdayakan Perusahaan Top dengan <span className="text-142F32">Integrasi Tanpa Batas</span>
</h2>
<p className="text-lg sm:text-xl mb-8 text-gray-600">
Rasakan koneksi tanpa batas dengan solusi inovatif kami, dirancang untuk berintegrasi dengan mudah dengan sistem Anda yang ada, meningkatkan produktivitas, dan mendorong bisnis Anda menuju kesuksesan yang lebih besar.
</p>
<button className="button-primary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50">
Bekerja Bersama Kami
</button>
</div>
<div className="integrations-visual">
<div className="integration-icon-grid">
<div className="integration-icon"><i className="fab fa-slack"></i></div>
<div className="integration-icon"><i className="fab fa-google-drive"></i></div>
<div className="integration-icon"><i className="fab fa-dropbox"></i></div>
<div className="integration-icon"><i className="fab fa-jira"></i></div>
<div className="integration-icon"><i className="fab fa-github"></i></div>
<div className="integration-icon"><i className="fab fa-trello"></i></div>
<div className="integration-icon"><i className="fab fa-salesforce"></i></div>
<div className="integration-icon"><i className="fab fa-microsoft"></i></div>
<div className="integration-icon"><i className="fab fa-aws"></i></div>
</div>
</div>
</section>
{/* From Idea to Production Section */}
<section className="idea-to-production-section">
<div className="max-w-4xl mx-auto">
<h2 className="text-3xl sm:text-4xl font-extrabold mb-4 text-white">
Dari Ide ke Produksi dalam Hitungan Hari
</h2>
<p className="text-lg sm:text-xl mb-8 opacity-80">
Percepat produksi Anda dengan teknologi kami. Kurangi waktu henti dan optimalkan biaya. Dapatkan penawaran spesial sekarang!
</p>
<button className="button-primary px-8 py-4 text-lg sm:text-xl font-semibold rounded-lg focus:outline-none focus:ring-4 focus:ring-blue-300 focus:ring-opacity-50">
Bekerja Bersama Kami
</button>
</div>
</section>
<Footer />
</div>
);
const Footer = () => (
<footer className="footer-section">
<div className="max-w-6xl mx-auto footer-grid">
<div className="footer-col">
<div className="flex items-center mb-4">
<img src="https://placehold.co/40x40/142F32/E5FFCC?text=P" alt="Logo Maragen" className="h-8 w-8 mr-2 rounded-full"/>
<span className="text-2xl font-bold text-white">Maragen</span>
</div>
<p className="mb-4">
Solusi kami membuat produksi lebih cepat dan lebih murah. Hubungi kami untuk informasi lebih lanjut.
</p>
</div>
<div className="footer-col">
<h3>Perusahaan</h3>
<ul>
<li><a href="#">Tentang Kami</a></li>
<li><a href="#">Pelanggan</a></li>
<li><a href="#">Berita</a></li>
<li><a href="#">Acara</a></li>
</ul>
</div>
<div className="footer-col">
<h3>Industri</h3>
<ul>
<li><a href="#">Manufaktur Logam Presisi</a></li>
<li><a href="#">Manufaktur Industri</a></li>
<li><a href="#">Teknologi Tinggi & Elektronik</a></li>
<li><a href="#">Dirgantara</a></li>
</ul>
</div>
<div className="footer-col">
<h3>Produk</h3>
<ul>
<li><a href="#">Sistem Eksekusi Manufaktur</a></li>
<li><a href="#">Perencanaan Sumber Daya Perusahaan</a></li>
<li><a href="#">Sistem Manajemen Kualitas</a></li>
<li><a href="#">Perencanaan Rantai Pasokan</a></li>
</ul>
</div>
<div className="footer-col">
<h3>Hubungi Kami</h3>
<p className="mb-4">halo@maragen.com</p>
<div className="social-icons">
<a href="#"><i className="fab fa-linkedin"></i></a>
<a href="#"><i className="fab fa-instagram"></i></a>
<a href="#"><i className="fab fa-facebook"></i></a>
<a href="#"><i className="fab fa-twitter"></i></a>
</div>
</div>
</div>
<div className="text-center mt-8 pt-8 border-t border-gray-700">
<p>&copy; 2024 Maragen. Semua hak dilindungi undang-undang.</p>
<div className="flex justify-center space-x-4 mt-2">
<a href="#" className="hover:text-white">Syarat & Ketentuan</a>
<a href="#" className="hover:text-white">Kebijakan Privasi</a>
</div>
</div>
</footer>
);
const AuthModal = () => (
<div className={`modal ${isAuthModalOpen ? 'show' : ''}`}>
<div className="modal-content">
<span className="close-button" onClick={() => setAuthModalOpen(false)}>&times;</span>
<h2 className="text-3xl font-extrabold mb-6 text-gray-900">Masuk atau Daftar</h2>
{authForm === 'login' ? (
<>
<form onSubmit={handleLogin} className="space-y-4">
<input type="email" name="loginEmail" placeholder="Email" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" required defaultValue="user@example.com"/>
<input type="password" name="loginPassword" placeholder="Kata Sandi" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" required defaultValue="password123"/>
<button type="submit" className="button-primary w-full py-3 rounded-lg font-semibold">Masuk</button>
</form>
<p className="mt-4 text-gray-600">
Belum punya akun? <a href="#" onClick={(e) => { e.preventDefault(); setAuthForm('register'); }} className="text-142F32 font-semibold hover:underline">Daftar di sini</a>
</p>
</>
) : (
<>
<form onSubmit={handleRegister} className="space-y-4">
<input type="email" name="registerEmail" placeholder="Email" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" required/>
<input type="password" name="registerPassword" placeholder="Kata Sandi" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" required/>
<input type="password" name="confirmPassword" placeholder="Konfirmasi Kata Sandi" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" required/>
<button type="submit" className="button-primary w-full py-3 rounded-lg font-semibold">Daftar</button>
</form>
<p className="mt-4 text-gray-600">
Sudah punya akun? <a href="#" onClick={(e) => { e.preventDefault(); setAuthForm('login'); }} className="text-142F32 font-semibold hover:underline">Masuk di sini</a>
</p>
</>
)}
</div>
</div>
);
const Dashboard = () => {
const sidebarItems = [
{ id: 'chatbot', icon: 'fa-comments', label: 'Chatbot' },
{ id: 'imageGen', icon: 'fa-image', label: 'Buat Gambar' },
{ id: 'scheduling', icon: 'fa-calendar-alt', label: 'Penjadwalan' },
{ id: 'monitoring', icon: 'fa-chart-line', label: 'Pemantauan Konten' },
{ id: 'notifications', icon: 'fa-bell', label: 'Notifikasi' },
{ id: 'profile', icon: 'fa-user-circle', label: 'Pengaturan Profil' },
];
return (
<div id="userDashboard" className="dashboard-container">
{/* Sidebar */}
<aside className="dashboard-sidebar">
<h2 className="text-3xl font-bold mb-8 text-E5FFCC">Dashboard</h2>
<div className="w-full">
{sidebarItems.map(item => (
<div
key={item.id}
className={`dashboard-sidebar-item ${activeDashboardSection === item.id ? 'active' : ''}`}
onClick={() => setActiveDashboardSection(item.id)}
>
<i className={`fas ${item.icon} mr-3`}></i> {item.label}
</div>
))}
</div>
<button onClick={handleLogout} className="button-secondary mt-auto w-full py-2 rounded-lg text-E5FFCC border-E5FFCC hover:bg-E5FFCC hover:text-142F32">
<i className="fas fa-sign-out-alt mr-2"></i> Keluar
</button>
</aside>
{/* Main Content */}
<main className="dashboard-main-content">
{activeDashboardSection === 'chatbot' && (
<section className="dashboard-section-content">
<h2 className="text-142F32">Chatbot AI</h2>
<p className="mb-6">Ajukan pertanyaan atau mulai percakapan dengan AI kami.</p>
<div className="chat-container">
<div className="chat-messages">
{messages.map((msg, index) => (
<div key={index} className={`chat-message ${msg.sender}`}>
{msg.text}
</div>
))}
<div ref={chatMessagesEndRef} />
</div>
{isChatLoading && <div className="loading-indicator show">Mengetik...</div>}
<div className="chat-input-area">
<input
type="text"
placeholder="Ketik pesan Anda..."
value={chatInput}
onChange={(e) => setChatInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
autoFocus
/>
<button onClick={handleSendMessage}>Kirim</button>
</div>
</div>
</section>
)}
{activeDashboardSection === 'imageGen' && (
<section className="dashboard-section-content">
<h2 className="text-142F32">Buat Gambar AI</h2>
<p className="mb-6">Masukkan deskripsi untuk membuat gambar.</p>
<div className="flex flex-col gap-4">
<input
type="text"
placeholder="Deskripsikan gambar yang ingin Anda buat (mis: 'seekor kucing di luar angkasa')"
className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32"
value={imagePrompt}
onChange={(e) => setImagePrompt(e.target.value)}
/>
<button onClick={handleGenerateImage} className="button-primary py-3 rounded-lg font-semibold" disabled={isImageLoading}>
{isImageLoading ? 'Membuat...' : 'Buat Gambar'}
</button>
{isImageLoading && <div className="loading-indicator show">Membuat gambar...</div>}
{generatedImageUrl && (
<div className="text-center">
<img src={generatedImageUrl} className="image-gen-preview" alt="Gambar yang Dihasilkan" />
<div className="flex justify-center gap-4 mt-4">
<button className="button-secondary py-2 px-4 rounded-lg">Jadwalkan</button>
<button className="button-primary py-2 px-4 rounded-lg">Posting Langsung</button>
</div>
</div>
)}
</div>
</section>
)}
{activeDashboardSection === 'scheduling' && (
<section className="dashboard-section-content">
<h2 className="text-142F32">Penjadwalan Konten</h2>
<p className="mb-6">Kelola konten yang akan dipublikasikan di masa mendatang.</p>
<div>
<ul>
<li>
<span>Postingan Blog: "Masa Depan Otomatisasi"</span>
<span className="text-gray-500 text-sm">2025-08-15 10:00 AM</span>
</li>
<li>
<span>Gambar AI: "Pemandangan Kota Futuristik"</span>
<span className="text-gray-500 text-sm">2025-08-18 02:30 PM</span>
</li>
</ul>
</div>
<button className="button-primary mt-6 py-2 px-4 rounded-lg">Tambah Jadwal Baru</button>
</section>
)}
{activeDashboardSection === 'monitoring' && (
<section className="dashboard-section-content">
<h2>Pemantauan & Analisis Tren</h2>
<p className="mb-6">Pantau kinerja konten Anda dan temukan tren viral berikutnya.</p>
<div>
<h3>Kinerja Konten Saya</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="stat-card p-6 p-4">
<p className="text-gray-600 text-sm">Total Penayangan</p>
<p className="text-2xl font-bold text-gray-800">1.2M</p>
<p className="text-green-500 text-xs">15% bulan ini</p>
</div>
<div className="stat-card p-6 p-4">
<p className="text-gray-600 text-sm">Total Suka</p>
<p className="text-2xl font-bold text-gray-800">89K</p>
<p className="text-green-500 text-xs">12% bulan ini</p>
</div>
<div className="stat-card p-6 p-4">
<p className="text-gray-600 text-sm">Pengikut Baru</p>
<p className="text-2xl font-bold text-gray-800">5,210</p>
<p className="text-green-500 text-xs">8% bulan ini</p>
</div>
</div>
</div>
<div className="mt-8">
<h3>Konten yang Sedang Tren</h3>
<div className="space-y-4">
{/* Konten tren akan diisi oleh data dari API */}
<p className="text-gray-500">Fitur ini sedang dalam pengembangan.</p>
</div>
</div>
</section>
)}
{activeDashboardSection === 'notifications' && (
<section className="dashboard-section-content">
<h2>Notifikasi</h2>
<p className="mb-6">Pembaruan terkini tentang akun dan konten Anda.</p>
<ul className="space-y-3">
{/* Notifikasi akan diisi oleh data dari API */}
<li>Postingan Anda "Masa Depan Otomatisasi" telah dijadwalkan.</li>
<li>Selamat! Anda mendapatkan 50 pengikut baru minggu ini.</li>
</ul>
</section>
)}
{activeDashboardSection === 'profile' && (
<section className="dashboard-section-content">
<h2>Pengaturan Profil</h2>
<p className="mb-6">Kelola informasi akun dan koneksi media sosial Anda.</p>
<div className="space-y-6 max-w-lg mx-auto text-left">
<div>
<label htmlFor="profileName" className="block text-sm font-medium text-gray-700">Nama Pengguna</label>
<input type="text" id="profileName" defaultValue="Pengguna Maragen"
className="mt-1 w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-142F32" />
</div>
<div>
<label htmlFor="profileEmail" className="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="profileEmail" defaultValue="user@example.com" disabled
className="mt-1 w-full p-3 border border-gray-300 rounded-lg bg-gray-100 cursor-not-allowed" />
</div>
<div className="pt-4 border-t">
<h3 className="text-lg font-semibold text-gray-800 mb-4">Autentikasi Media Sosial</h3>
<div className="flex justify-between items-center p-3 bg-gray-50 rounded-lg mb-3">
<div className="flex items-center">
<i className="fab fa-twitter text-2xl text-blue-400 mr-4"></i>
<div>
<p className="font-semibold text-gray-700">Twitter</p>
<span className={`connection-status ${socialConnections.twitter ? 'connected' : 'not-connected'}`}>
{socialConnections.twitter ? 'Terhubung' : 'Belum Terhubung'}
</span>
</div>
</div>
<button onClick={() => handleConnectSocial('twitter')} className="button-primary py-2 px-4 rounded-lg text-sm">
{socialConnections.twitter ? 'Putuskan' : 'Hubungkan'}
</button>
</div>
<div className="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
<div className="flex items-center">
<i className="fab fa-instagram text-2xl text-pink-500 mr-4"></i>
<div>
<p className="font-semibold text-gray-700">Instagram</p>
<span className={`connection-status ${socialConnections.instagram ? 'connected' : 'not-connected'}`}>
{socialConnections.instagram ? 'Terhubung' : 'Belum Terhubung'}
</span>
</div>
</div>
<button onClick={() => handleConnectSocial('instagram')} className="button-primary py-2 px-4 rounded-lg text-sm">
{socialConnections.instagram ? 'Putuskan' : 'Hubungkan'}
</button>
</div>
</div>
<div className="pt-4">
<button className="button-primary py-3 px-6 rounded-lg font-semibold">Simpan Perubahan</button>
<button onClick={handleLogout} className="button-secondary py-3 px-6 rounded-lg font-semibold ml-4">
Keluar
</button>
</div>
</div>
</section>
)}
</main>
</div>
);
};
return (
<>
<Header />
{view === 'landing' && <LandingPage />}
{view === 'dashboard' && <Dashboard />}
{isAuthModalOpen && <AuthModal />}
</>
);
}
export default App;

8
src/App.test.js Normal file
View File

@@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

614
src/index.css Normal file
View File

@@ -0,0 +1,614 @@
/* Direktif Tailwind */
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
font-family: 'Manrope', sans-serif;
background-color: #f8fafc; /* Background utama, mirip dengan brand guide */
color: #282930; /* Teks gelap utama */
margin: 0;
overflow-x: hidden; /* Mencegah scroll horizontal */
}
/* Custom styles for sections and elements */
.header-bg {
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.hero-section {
background-color: #ffffff;
/* padding: 4rem 2rem; */
text-align: center;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr)); /* 1 kolom di layar kecil */
gap: 1.5rem;
margin-top: 3rem;
}
@media (min-width: 640px) { /* sm breakpoint */
.stats-grid {
grid-template-columns: repeat(2, minmax(0, 1fr)); /* 2 kolom di layar sedang */
}
}
@media (min-width: 1024px) { /* lg breakpoint */
.stats-grid {
grid-template-columns: repeat(4, minmax(0, 1fr)); /* 4 kolom di layar besar */
}
}
.stat-card {
background-color: #ffffff;
border-radius: 1rem;
text-align: left;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
transition: transform 0.2s ease-in-out;
}
.stat-card.dark-bg {
background-color: #282930; /* Menggunakan warna gelap dari brand guide */
color: #e2e8f0;
}
.stat-card.light-green-bg {
background-color: #E5FFCC; /* Menggunakan warna hijau terang dari brand guide */
color: #142F32; /* Teks gelap di atas hijau terang */
}
.stat-card:hover {
transform: translateY(-5px);
}
.bottom-section {
background-color: #282930; /* Menggunakan warna gelap dari brand guide */
padding: 4rem 2rem;
color: #e2e8f0;
text-align: center;
}
.bottom-grid {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr)); /* 1 kolom di layar kecil */
gap: 1.5rem;
margin-top: 3rem;
}
@media (min-width: 768px) { /* md breakpoint */
.bottom-grid {
grid-template-columns: repeat(3, minmax(0, 1fr)); /* 3 kolom di layar sedang */
}
}
.bottom-card {
background-color: #142F32; /* Menggunakan warna hijau gelap dari brand guide */
border-radius: 1rem;
padding: 2rem;
text-align: left;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease-in-out;
}
.bottom-card:hover {
transform: translateY(-5px);
}
.button-primary {
background-color: #142F32; /* Menggunakan warna hijau gelap dari brand guide */
color: white;
transition: all 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.button-primary:hover {
background-color: #0d1e20; /* Hijau gelap lebih gelap */
transform: translateY(-2px);
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
}
.button-secondary {
background-color: transparent;
border: 1px solid #9ca3af; /* Gray border */
color: #4b5563; /* Dark gray text */
transition: all 0.3s ease;
}
.button-secondary:hover {
background-color: #f3f4f6; /* Light gray background */
transform: translateY(-2px);
}
.button-sign-up {
background-color: #142F32; /* Menggunakan warna hijau gelap dari brand guide */
color: white;
transition: all 0.3s ease;
}
.button-sign-up:hover {
background-color: #0d1e20; /* Hijau gelap lebih gelap */
}
/* Responsive image for the first card */
.card-image {
width: 100%;
height: auto;
border-radius: 0.75rem; /* Sudut membulat untuk gambar */
object-fit: cover; /* Memastikan gambar menutupi area */
}
/* Styles for Key Benefits Section */
.key-benefits-section {
background-color: #f8fafc;
padding: 4rem 2rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
@media (min-width: 768px) {
.key-benefits-section {
flex-direction: row;
text-align: left;
justify-content: center;
gap: 4rem;
}
}
.benefits-content {
flex: 1;
max-width: 600px;
}
.benefits-image-card {
flex: 1;
background-color: #ffffff;
border-radius: 1rem;
padding: 1.5rem;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
margin-top: 2rem;
max-width: 400px;
}
@media (min-width: 768px) {
.benefits-image-card {
margin-top: 0;
}
}
.benefit-item {
display: flex;
align-items: flex-start;
margin-bottom: 1rem;
}
.benefit-item i {
color: #22c55e; /* Hijau centang */
margin-right: 0.75rem;
font-size: 1.25rem;
margin-top: 0.25rem;
}
/* Styles for Tailored Plans Section */
.tailored-plans-section {
background-color: #282930; /* Menggunakan warna gelap dari brand guide */
padding: 4rem 2rem;
color: #e2e8f0;
text-align: center;
}
.pricing-grid {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: 2rem;
margin-top: 3rem;
max-width: 900px;
margin-left: auto;
margin-right: auto;
}
@media (min-width: 768px) {
.pricing-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.pricing-card {
background-color: #142F32; /* Menggunakan warna hijau gelap dari brand guide */
border-radius: 1rem;
padding: 2.5rem;
text-align: left;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.1);
}
.pricing-card .price {
font-size: 3rem;
font-weight: 800;
color: #ffffff;
margin-bottom: 0.5rem;
}
.pricing-card .price-per-month {
color: #9ca3af;
font-size: 1rem;
}
.pricing-card .feature-list {
margin-top: 1.5rem;
margin-bottom: 2rem;
}
.pricing-card .feature-item {
display: flex;
align-items: center;
margin-bottom: 0.75rem;
color: #cbd5e0;
}
.pricing-card .feature-item i {
color: #22c55e; /* Hijau centang */
margin-right: 0.5rem;
}
/* New styles for Seamless Integrations Section */
.integrations-section {
background-color: #f8fafc;
padding: 4rem 2rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
@media (min-width: 768px) {
.integrations-section {
flex-direction: row;
text-align: left;
justify-content: center;
gap: 4rem;
}
}
.integrations-content {
flex: 1;
max-width: 600px;
}
.integrations-visual {
flex: 1;
background-color: #E5FFCC; /* Menggunakan warna hijau terang dari brand guide */
border-radius: 1rem;
padding: 2rem;
margin-top: 2rem;
max-width: 500px;
position: relative;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 300px;
}
@media (min-width: 768px) {
.integrations-visual {
margin-top: 0;
}
}
.integration-icon-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
width: 100%;
height: 100%;
position: relative;
justify-items: center;
align-items: center;
}
.integration-icon {
background-color: #ffffff;
border-radius: 50%;
width: 60px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
font-size: 1.5rem;
color: #4a5568;
}
/* From Idea to Production Section */
.idea-to-production-section {
background-color: #282930; /* Menggunakan warna gelap dari brand guide */
padding: 4rem 2rem;
color: #e2e8f0;
text-align: center;
}
/* Footer Section */
.footer-section {
background-color: #282930; /* Menggunakan warna gelap dari brand guide */
padding: 4rem 2rem;
color: #a0aec0; /* Teks abu-abu lebih terang */
font-size: 0.9rem;
}
.footer-grid {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: 2rem;
}
@media (min-width: 640px) {
.footer-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (min-width: 1024px) {
.footer-grid {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
.footer-col h3 {
font-weight: 600;
color: #ffffff;
margin-bottom: 1rem;
}
.footer-col ul li {
margin-bottom: 0.5rem;
}
.footer-col ul li a {
color: #a0aec0;
transition: color 0.2s ease;
}
.footer-col ul li a:hover {
color: #ffffff;
}
.social-icons a {
color: #a0aec0;
font-size: 1.25rem;
margin-right: 1rem;
transition: color 0.2s ease;
}
.social-icons a:hover {
color: #ffffff;
}
/* Modal Styles */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.modal.show {
opacity: 1;
visibility: visible;
}
.modal-content {
background-color: #ffffff;
padding: 2.5rem;
border-radius: 1rem;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
max-width: 450px;
width: 90%;
text-align: center;
position: relative;
transform: translateY(-20px);
transition: transform 0.3s ease;
}
.modal.show .modal-content {
transform: translateY(0);
}
.close-button {
position: absolute;
top: 1rem;
right: 1rem;
font-size: 1.5rem;
cursor: pointer;
color: #4b5563;
}
/* Dashboard Styles */
.dashboard-container {
display: none; /* Hidden by default */
grid-template-columns: 250px 1fr; /* Sidebar fixed width, content fills */
min-height: 100vh;
background-color: #f8fafc;
color: #282930;
}
@media (max-width: 768px) {
.dashboard-container {
grid-template-columns: 1fr; /* Stack on small screens */
}
.dashboard-sidebar {
width: 100%;
position: relative;
box-shadow: none;
}
}
.dashboard-sidebar {
background-color: #142F32; /* Hijau gelap */
color: #E5FFCC;
padding: 2rem 1rem;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
}
.dashboard-sidebar-item {
width: 100%;
padding: 0.75rem 1rem;
margin-bottom: 0.5rem;
border-radius: 0.5rem;
display: flex;
align-items: center;
cursor: pointer;
transition: background-color 0.2s ease, color 0.2s ease;
}
.dashboard-sidebar-item:hover {
background-color: rgba(229, 255, 204, 0.1); /* Hijau terang transparan */
color: #E5FFCC;
}
.dashboard-sidebar-item.active {
background-color: #E5FFCC;
color: #142F32;
font-weight: 600;
}
.dashboard-main-content {
padding: 2rem;
background-color: #f8fafc;
overflow-y: auto;
}
.chat-container {
display: flex;
flex-direction: column;
height: calc(100vh - 4rem); /* Adjust for padding */
background-color: #ffffff;
border-radius: 1rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.chat-messages {
flex-grow: 1;
padding: 1.5rem;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 1rem;
}
.chat-message {
max-width: 80%;
padding: 0.75rem 1rem;
border-radius: 0.75rem;
word-wrap: break-word;
}
.chat-message.user {
background-color: #E5FFCC;
align-self: flex-end;
color: #142F32;
}
.chat-message.bot {
background-color: #f1f5f9;
align-self: flex-start;
color: #282930;
}
.chat-input-area {
display: flex;
padding: 1rem;
border-top: 1px solid #e2e8f0;
background-color: #ffffff;
}
.chat-input-area input {
flex-grow: 1;
padding: 0.75rem 1rem;
border: 1px solid #cbd5e0;
border-radius: 0.5rem;
margin-right: 0.75rem;
font-size: 1rem;
}
.chat-input-area button {
background-color: #142F32;
color: white;
padding: 0.75rem 1.25rem;
border-radius: 0.5rem;
transition: background-color 0.2s ease;
}
.chat-input-area button:hover {
background-color: #0d1e20;
}
.loading-indicator {
display: none;
text-align: center;
padding: 1rem;
color: #777C90;
}
.loading-indicator.show {
display: block;
}
.image-gen-preview {
max-width: 100%;
height: auto;
border-radius: 0.75rem;
margin-top: 1.5rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.dashboard-section-content {
background-color: #ffffff;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
min-height: calc(100vh - 8rem); /* Adjust for header/footer/padding */
}
.dashboard-section-content h2 {
font-size: 2.25rem;
font-weight: 800;
margin-bottom: 1.5rem;
color: #282930;
}
.dashboard-section-content p {
color: #4b5563;
margin-bottom: 1rem;
}
.dashboard-section-content ul {
list-style: none;
padding: 0;
}
.dashboard-section-content ul li {
background-color: #f1f5f9;
padding: 1rem;
border-radius: 0.75rem;
margin-bottom: 0.75rem;
display: flex;
justify-content: space-between;
align-items: center;
}

17
src/index.js Normal file
View File

@@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

1
src/logo.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

13
src/reportWebVitals.js Normal file
View File

@@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

5
src/setupTests.js Normal file
View File

@@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

10
tailwind.config.js Normal file
View File

@@ -0,0 +1,10 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}