Antarmuka Web: HTML & CSS (Index.html)
Di Google Apps Script, kita dapat menyatukan seluruh struktur antarmuka (HTML) dan desain visual (CSS) ke dalam satu file tunggal: Index.html.
Dengan menaruh kode CSS di dalam tag <style> di bagian <head>, proyek kita menjadi sangat ringkas—hanya terdiri dari 2 file:
Editor Google Apps Script:├── Code.gs # Backend: Logika CRUD & router web (doGet & doPost)└── Index.html # Frontend: Struktur HTML + Styling CSS dalam 1 file1. Prompt untuk Membuat Index.html (Framework T-C-R-E-I)
Section titled “1. Prompt untuk Membuat Index.html (Framework T-C-R-E-I)”[PERSONA]Bertindaklah sebagai asisten UI/UX dan Frontend Web Developer Google Apps Script.
[TASK]- Buatkan satu file Index.html lengkap yang memuat struktur HTML dan styling CSS modern untuk aplikasi absensi presensi sederhana.- Pastikan form absensi dan tabel riwayat kehadiran tampil rapi, elegan, dan responsif.
[CONTEXT]- Header aplikasi: Judul "PresensiApp".- Formulir input (CREATE): Input Nama Lengkap (wajib), Dropdown Status (Hadir, Izin, Sakit), Catatan singkat (opsional), Tombol "Kirim Presensi" (method="POST").- Tabel riwayat (READ & DELETE): Kolom Waktu, Nama, Status (badge), Catatan, dan Tombol hapus di setiap baris data.- Desain visual: Tema gelap arang (Deep Charcoal #121212 - #181818), border halus #333333, teks putih bersih, dan tata letak responsif (2 kolom di laptop, 1 kolom di HP).
[OUTPUT FORMAT]Satu file Index.html lengkap yang menggabungkan seluruh kode HTML dengan tag <style>...</style> di dalam <head>.Bertindaklah sebagai frontend developer Google Apps Script. Bantu saya membuat tampilan aplikasi absensi dalam 1 file Index.html.
Context:- Form absensi: Input Nama, Status (Hadir, Izin, Sakit), Catatan, tombol kirim via method="POST".- Tabel riwayat: Menampilkan data kehadiran dari Google Sheets dan tombol hapus baris.- Desain: Tema gelap arang (Deep Charcoal #121212) responsif untuk HP dan laptop.- Satukan seluruh kode CSS di dalam tag <style> di dalam Index.html.
Output format:Berikan satu file Index.html lengkap yang siap disalin ke editor Google Apps Script.2. Kode Hasil Index.html (HTML & CSS Terpadu)
Section titled “2. Kode Hasil Index.html (HTML & CSS Terpadu)”Berikut adalah kode lengkap Index.html yang siap kamu salin ke editor Apps Script:
<!DOCTYPE html><html lang="id"><head> <base target="_top"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Aplikasi Presensi Karyawan</title>
<!-- ======================================================================= STYLING MODERN CSS (Deep Charcoal Theme) ======================================================================= --> <style> :root { --bg-main: #121212; --bg-surface: #181818; --bg-card: #242424; --border-color: #333333; --text-primary: #fafafa; --text-secondary: #a3a3a3; --accent: #e5e5e5; --accent-hover: #ffffff; --success: #22c55e; --warning: #eab308; --danger: #ef4444; --radius-md: 0.5rem; --radius-lg: 0.75rem; }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background-color: var(--bg-main); color: var(--text-primary); line-height: 1.5; min-height: 100vh; display: flex; flex-direction: column; }
.container { width: 100%; max-width: 1100px; margin: 0 auto; padding: 0 1.25rem; }
/* Header */ .app-header { background-color: var(--bg-surface); border-bottom: 1px solid var(--border-color); padding: 1.25rem 0; }
.brand h1 { font-size: 1.35rem; font-weight: 700; color: var(--text-primary); }
.brand h1 span { color: var(--text-secondary); }
.brand p { font-size: 0.85rem; color: var(--text-secondary); }
/* Layout 2 Kolom Responsif */ .main-layout { flex: 1; display: grid; grid-template-columns: 1fr; gap: 1.5rem; padding-top: 2rem; padding-bottom: 2rem; }
@media (min-width: 768px) { .main-layout { grid-template-columns: 360px 1fr; align-items: start; } }
.card { background-color: var(--bg-surface); border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 1.5rem; }
.card h2 { font-size: 1.15rem; font-weight: 600; margin-bottom: 0.25rem; }
.section-desc { font-size: 0.85rem; color: var(--text-secondary); margin-bottom: 1.25rem; }
/* Formulir */ .form-group { margin-bottom: 1.15rem; }
.form-group label { display: block; font-size: 0.85rem; font-weight: 500; color: var(--text-primary); margin-bottom: 0.35rem; }
.form-group input, .form-group select { width: 100%; padding: 0.65rem 0.85rem; background-color: var(--bg-card); border: 1px solid var(--border-color); border-radius: var(--radius-md); color: var(--text-primary); font-size: 0.9rem; outline: none; transition: border-color 0.2s; }
.form-group input:focus, .form-group select:focus { border-color: var(--accent); }
.btn-primary { width: 100%; padding: 0.75rem; background-color: var(--accent); color: var(--bg-main); border: none; border-radius: var(--radius-md); font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: background-color 0.2s; }
.btn-primary:hover { background-color: var(--accent-hover); }
/* Tabel Riwayat */ .table-responsive { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.data-table th, .data-table td { padding: 0.75rem 0.85rem; text-align: left; border-bottom: 1px solid var(--border-color); }
.data-table th { color: var(--text-secondary); font-weight: 600; }
/* Status Badges */ .badge { display: inline-block; padding: 0.2rem 0.55rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; }
.badge-hadir { background-color: rgba(34, 197, 94, 0.15); color: var(--success); border: 1px solid rgba(34, 197, 94, 0.3); }
.badge-izin { background-color: rgba(234, 179, 8, 0.15); color: var(--warning); border: 1px solid rgba(234, 179, 8, 0.3); }
.badge-sakit { background-color: rgba(239, 68, 68, 0.15); color: var(--danger); border: 1px solid rgba(239, 68, 68, 0.3); }
.btn-delete { background: transparent; border: none; cursor: pointer; color: var(--danger); opacity: 0.7; transition: opacity 0.2s; }
.btn-delete:hover { opacity: 1; }
/* Footer */ .app-footer { text-align: center; padding: 2rem 0; color: var(--text-secondary); font-size: 0.85rem; border-top: 1px solid var(--border-color); } </style></head><body> <!-- Header Aplikasi --> <header class="app-header"> <div class="container header-wrapper"> <div class="brand"> <h1>Presensi<span>App</span></h1> <p>Sistem pencatatan kehadiran harian sederhana</p> </div> </div> </header>
<!-- Konten Utama --> <main class="container main-layout"> <!-- Bagian 1: Form Absen Masuk (CREATE) --> <section class="card form-card"> <h2>Catat Kehadiran</h2> <p class="section-desc">Silakan isi data kehadiranmu untuk hari ini.</p>
<!-- Form submit langsung ke doPost() di Code.gs --> <form method="POST"> <input type="hidden" name="action" value="create">
<div class="form-group"> <label for="nama">Nama Lengkap</label> <input type="text" id="nama" name="nama" placeholder="Contoh: Sarah Azhari" required> </div>
<div class="form-group"> <label for="status">Status Kehadiran</label> <select id="status" name="status" required> <option value="Hadir" selected>Hadir</option> <option value="Izin">Izin</option> <option value="Sakit">Sakit</option> </select> </div>
<div class="form-group"> <label for="catatan">Catatan / Keterangan (Opsional)</label> <input type="text" id="catatan" name="catatan" placeholder="Contoh: Bekerja dari kantor / dinas luar"> </div>
<button type="submit" class="btn-primary">Kirim Presensi</button> </form> </section>
<!-- Bagian 2: Tabel Riwayat Kehadiran (READ & DELETE) --> <section class="card table-card"> <h2>Daftar Kehadiran Hari Ini</h2> <p class="section-desc">Daftar presensi yang tercatat di Google Sheets.</p>
<div class="table-responsive"> <table class="data-table"> <thead> <tr> <th>Waktu</th> <th>Nama</th> <th>Status</th> <th>Catatan</th> <th>Aksi</th> </tr> </thead> <tbody> <? if (attendanceData && attendanceData.length > 0) { ?> <? for (var i = 0; i < attendanceData.length; i++) { ?> <tr> <td><?= attendanceData[i].timestamp ?></td> <td><strong><?= attendanceData[i].nama ?></strong></td> <td> <span class="badge badge-<?= attendanceData[i].status.toLowerCase() ?>"> <?= attendanceData[i].status ?> </span> </td> <td><?= attendanceData[i].catatan ?></td> <td> <!-- Tombol Hapus (DELETE) --> <form method="POST" style="display:inline;" onsubmit="return confirm('Hapus catatan ini?');"> <input type="hidden" name="action" value="delete"> <input type="hidden" name="id" value="<?= attendanceData[i].id ?>"> <button type="submit" class="btn-delete" title="Hapus"> <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg> </button> </form> </td> </tr> <? } ?> <? } else { ?> <tr> <td colspan="5" style="text-align:center; color: var(--text-secondary); padding: 2rem;"> Belum ada data presensi hari ini. </td> </tr> <? } ?> </tbody> </table> </div> </section> </main>
<footer class="app-footer"> <div class="container"> <p>© 2026 PresensiApp — Didukung oleh Google Sheets & Apps Script.</p> </div> </footer></body></html>Checkpoint
Section titled “Checkpoint”- Memahami alasan menggabungkan HTML dan CSS langsung ke dalam file
Index.html. - Membuat file
Index.htmldi editor Google Apps Script dan menyalin kode di atas. - Siap melanjutkan ke backend
Code.gsuntuk menghubungkan database Google Sheets.