ok
This commit is contained in:
54
package-lock.json
generated
54
package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router-dom": "^7.6.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
@@ -12866,6 +12867,53 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.1.tgz",
|
||||
"integrity": "sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.1.tgz",
|
||||
"integrity": "sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router/node_modules/cookie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
||||
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
@@ -13703,6 +13751,12 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/set-cookie-parser": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router-dom": "^7.6.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
|
||||
1034
src/App.js
1034
src/App.js
File diff suppressed because it is too large
Load Diff
409
src/LandingPage.js
Normal file
409
src/LandingPage.js
Normal file
@@ -0,0 +1,409 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import formatRupiah from './helpers/formatRupiah';
|
||||
|
||||
export default function App() {
|
||||
const { organizationId } = useParams();
|
||||
const [organization, setOrganization] = useState([]);
|
||||
const [tickets, setTickets] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [modalTab, setModalTab] = useState("login"); // "login" or "register"
|
||||
const [selectedTicket, setSelectedTicket] = useState(null);
|
||||
const [formData, setFormData] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if (!organizationId) {
|
||||
setError("Parameter organization tidak ditemukan di URL.");
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(
|
||||
`https://auto.apps.kediritechnopark.com/webhook/mayagen/organization?organization=${organizationId}`
|
||||
)
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error("Gagal mengambil data tiket");
|
||||
return res.json();
|
||||
})
|
||||
.then((data) => {
|
||||
setTickets(data[0].tickets);
|
||||
setOrganization(data[0]);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
setError(err.message);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [organizationId]);
|
||||
|
||||
// Dummy login handler
|
||||
function handleLogin(e) {
|
||||
e.preventDefault();
|
||||
// Kamu bisa validasi di sini
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
|
||||
// Dummy register handler
|
||||
function handleRegister(e) {
|
||||
e.preventDefault();
|
||||
// Kamu bisa validasi dan buat user di sini
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
|
||||
// Form tiket submit
|
||||
function handleSubmitTicket(e) {
|
||||
e.preventDefault();
|
||||
alert(`Form tiket untuk ${selectedTicket.nama_tiket} submitted:\n` + JSON.stringify(formData, null, 2));
|
||||
setShowModal(false);
|
||||
setSelectedTicket(null);
|
||||
setFormData({});
|
||||
}
|
||||
|
||||
// Handle klik beli tiket
|
||||
function handleBuyClick(ticket) {
|
||||
if (!isLoggedIn) {
|
||||
setModalTab("login");
|
||||
setShowModal(true);
|
||||
setSelectedTicket(ticket);
|
||||
} else {
|
||||
setSelectedTicket(ticket);
|
||||
setShowModal(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form input change untuk tiket form
|
||||
function handleFormChange(e) {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
}
|
||||
|
||||
if (loading) return <div>Loading...</div>;
|
||||
if (error) return <div>Error: {error}</div>;
|
||||
|
||||
return (
|
||||
<div className="bg-brand-dark text-gray-300 font-sans antialiased min-h-screen relative">
|
||||
<main>
|
||||
{/* Hero Section */}
|
||||
<section className="relative h-[70vh] flex items-center justify-center text-center text-white overflow-hidden">
|
||||
<div
|
||||
className="absolute inset-0 bg-cover bg-center z-0"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url('https://images.unsplash.com/photo-1524368535928-5b5e00ddc76b?q=80&w=2070&auto=format&fit=crop')",
|
||||
}}
|
||||
></div>
|
||||
<div className="absolute inset-0 bg-black/70 z-10"></div>
|
||||
<div className="relative z-20 container mx-auto px-6">
|
||||
<h1 className="text-4xl md:text-6xl font-extrabold leading-tight">
|
||||
{organization.nama_organization}
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl mx-auto text-lg text-gray-200">
|
||||
{organization.deskripsi}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Acara Section */}
|
||||
<section id="acara" className="py-20">
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="text-center mb-12">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-white">
|
||||
Acara Mendatang
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{tickets.map((ticket, i) => {
|
||||
const isSoldOut = ticket.sold_out || false;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={ticket.tiket_id || i}
|
||||
className={`bg-brand-card rounded-lg overflow-hidden border border-brand-subtle flex flex-col ${isSoldOut ? "relative" : ""
|
||||
}`}
|
||||
>
|
||||
{isSoldOut && (
|
||||
<div className="absolute inset-0 bg-black/60 flex items-center justify-center z-10">
|
||||
<span className="text-white text-2xl font-bold border-2 border-white px-6 py-2 rotate-[-15deg]">
|
||||
TIKET HABIS
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<img
|
||||
src={
|
||||
ticket.poster ||
|
||||
`https://placehold.co/600x400/161B22/FFFFFF?text=${encodeURIComponent(
|
||||
ticket.nama_tiket.replace(/\s/g, "+")
|
||||
)}`
|
||||
}
|
||||
alt="Poster Acara"
|
||||
className={`w-full h-48 object-cover ${isSoldOut ? "filter grayscale" : ""
|
||||
}`}
|
||||
/>
|
||||
<div className="p-6 flex flex-col flex-grow">
|
||||
<h3 className="text-xl font-bold text-white">
|
||||
{ticket.nama_tiket}
|
||||
</h3>
|
||||
<div className="flex items-center text-sm text-gray-400 mt-2 space-x-4">
|
||||
<span>📅 {ticket.tanggal || "Tanggal belum tersedia"}</span>
|
||||
<span>📍 {ticket.lokasi || "Lokasi belum tersedia"}</span>
|
||||
</div>
|
||||
<p
|
||||
className={`mt-4 text-lg font-semibold ${isSoldOut ? "text-gray-500" : "text-white"
|
||||
}`}
|
||||
>
|
||||
{ticket.price === "0.00" ? "Gratis" : formatRupiah(ticket.price)}
|
||||
</p>
|
||||
<div className="mt-auto pt-4">
|
||||
{isSoldOut ? (
|
||||
<button
|
||||
disabled
|
||||
className="block w-full text-center bg-brand-subtle text-gray-500 font-semibold py-2.5 px-5 rounded-lg cursor-not-allowed"
|
||||
>
|
||||
Tiket Habis
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="block w-full text-center bg-brand-accent hover:bg-brand-accent-hover text-white font-semibold py-2.5 px-5 rounded-lg transition-colors"
|
||||
onClick={() => handleBuyClick(ticket)}
|
||||
>
|
||||
{ticket.price == 0 ? "Ambil Tiket" : `Beli Tiket`}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{organization.about &&
|
||||
<section id="tentang" className="py-20 bg-brand-card">
|
||||
<div className="container mx-auto px-6 grid lg:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1523580494863-6f3031224c94?q=80&w=2070&auto=format&fit=crop"
|
||||
className="rounded-lg"
|
||||
alt="Tim SoundVibes Production"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold text-white">
|
||||
Tentang {organization.nama_organization}
|
||||
</h2>
|
||||
<p className="mt-4 text-gray-400">
|
||||
Didirikan pada tahun 2020, SoundVibes Production adalah promotor musik
|
||||
yang berdedikasi untuk menciptakan acara live yang tak terlupakan.
|
||||
Misi kami adalah menghubungkan penggemar dengan artis favorit mereka
|
||||
melalui produksi acara yang berkualitas tinggi, aman, dan nyaman.
|
||||
</p>
|
||||
<p className="mt-4 text-gray-400">
|
||||
Kami percaya bahwa musik memiliki kekuatan untuk menyatukan, dan
|
||||
kami bangga menjadi jembatan antara panggung dan penonton.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer
|
||||
id="kontak"
|
||||
className="bg-brand-dark border-t border-brand-subtle"
|
||||
>
|
||||
<div className="container mx-auto px-6 py-8 text-center text-gray-400">
|
||||
<h3 className="text-2xl font-bold text-white">
|
||||
{organization.nama_organization}
|
||||
</h3>
|
||||
<p className="mt-2">Ikuti kami untuk update acara terbaru!</p>
|
||||
<div className="flex justify-center space-x-6 mt-4">
|
||||
<a href="#" className="hover:text-white">
|
||||
Instagram
|
||||
</a>
|
||||
<a href="#" className="hover:text-white">
|
||||
Twitter
|
||||
</a>
|
||||
<a href="#" className="hover:text-white">
|
||||
Facebook
|
||||
</a>
|
||||
</div>
|
||||
<p className="mt-8 text-sm text-gray-500">
|
||||
Data dalam situs ini mungkin dilindungi hak cipta oleh {organization.nama_organization}.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{/* Modal */}
|
||||
{showModal && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-70 flex justify-center items-center z-50">
|
||||
<div className="bg-brand-card rounded-lg max-w-md w-full p-6 relative">
|
||||
<button
|
||||
className="absolute top-3 right-3 text-gray-400 hover:text-white"
|
||||
onClick={() => {
|
||||
setShowModal(false);
|
||||
setSelectedTicket(null);
|
||||
setFormData({});
|
||||
}}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{!isLoggedIn && (
|
||||
<>
|
||||
{/* Tabs */}
|
||||
<div className="flex mb-4 border-b border-gray-600">
|
||||
<button
|
||||
className={`flex-1 py-2 ${modalTab === "login"
|
||||
? "border-b-2 border-brand-accent font-bold"
|
||||
: "text-gray-400"
|
||||
}`}
|
||||
onClick={() => setModalTab("login")}
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
className={`flex-1 py-2 ${modalTab === "register"
|
||||
? "border-b-2 border-brand-accent font-bold"
|
||||
: "text-gray-400"
|
||||
}`}
|
||||
onClick={() => setModalTab("register")}
|
||||
>
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Login Form */}
|
||||
{modalTab === "login" && (
|
||||
<form onSubmit={handleLogin} className="space-y-4">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-brand-accent py-2 rounded hover:bg-brand-accent-hover transition-colors"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{/* Register Form */}
|
||||
{modalTab === "register" && (
|
||||
<form onSubmit={handleRegister} className="space-y-4">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nama Lengkap"
|
||||
required
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-brand-accent py-2 rounded hover:bg-brand-accent-hover transition-colors"
|
||||
>
|
||||
Register
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Jika sudah login, tampilkan form tiket */}
|
||||
{isLoggedIn && selectedTicket && (
|
||||
<form onSubmit={handleSubmitTicket} className="space-y-4">
|
||||
<h2 className="text-xl font-bold mb-4 text-white">
|
||||
Formulir {selectedTicket.nama_tiket}
|
||||
</h2>
|
||||
{Object.entries(selectedTicket.form).map(([key, type]) => {
|
||||
if (type === "text") {
|
||||
return (
|
||||
<div key={key}>
|
||||
<label className="block mb-1 text-gray-300 capitalize" htmlFor={key}>
|
||||
{key.replace(/_/g, " ")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id={key}
|
||||
name={key}
|
||||
required
|
||||
value={formData[key] || ""}
|
||||
onChange={handleFormChange}
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (type === "selection") {
|
||||
// Contoh opsi metode pembayaran (bisa disesuaikan)
|
||||
const options = [
|
||||
"Transfer Bank",
|
||||
"Kartu Kredit",
|
||||
"Cash",
|
||||
"E-Wallet",
|
||||
];
|
||||
return (
|
||||
<div key={key}>
|
||||
<label className="block mb-1 text-gray-300 capitalize" htmlFor={key}>
|
||||
{key.replace(/_/g, " ")}
|
||||
</label>
|
||||
<select
|
||||
id={key}
|
||||
name={key}
|
||||
required
|
||||
value={formData[key] || ""}
|
||||
onChange={handleFormChange}
|
||||
className="w-full p-2 rounded bg-gray-800 text-white"
|
||||
>
|
||||
<option value="">Pilih {key.replace(/_/g, " ")}</option>
|
||||
{options.map((opt) => (
|
||||
<option key={opt} value={opt}>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-brand-accent py-2 rounded hover:bg-brand-accent-hover transition-colors"
|
||||
>
|
||||
{selectedTicket.price == 0 ? "Dapatkan Tiket" : `Bayar Rp ${selectedTicket.price}`}
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
8
src/helpers/formatRupiah.js
Normal file
8
src/helpers/formatRupiah.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export default function formatRupiah(number) {
|
||||
return new Intl.NumberFormat('id-ID', {
|
||||
style: 'currency',
|
||||
currency: 'IDR',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(number);
|
||||
}
|
||||
643
src/index.css
643
src/index.css
@@ -1,614 +1,37 @@
|
||||
/* 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;
|
||||
}
|
||||
/* Tambahan untuk font */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
||||
|
||||
/* Custom Theme Overrides */
|
||||
:root {
|
||||
--color-brand-dark: #0D1117;
|
||||
--color-brand-card: #161B22;
|
||||
--color-brand-accent: #10B981;
|
||||
--color-brand-accent-hover: #059669;
|
||||
--color-brand-subtle: #30363D;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-[var(--color-brand-dark)] text-gray-300 font-sans antialiased;
|
||||
}
|
||||
|
||||
/* Font override for Inter */
|
||||
* {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
@keyframes marquee {
|
||||
0% {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-marquee {
|
||||
animation: marquee 40s linear infinite;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
// tailwind.config.js
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
"./src/**/*.{js,jsx,ts,tsx}", // pastikan path sesuai struktur project kamu
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
'brand-dark': '#0D1117',
|
||||
'brand-card': '#161B22',
|
||||
'brand-accent': '#10B981',
|
||||
'brand-accent-hover': '#059669',
|
||||
'brand-subtle': '#30363D',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user