Warung makan kecil umumnya mencari cara termurah untuk tampil di internet: satu halaman yang memuat menu beserta harganya, alamat, nomor telepon, jam buka, dan sarana memesan. Halaman semacam itu tidak butuh server khusus; HTML, CSS, dan sedikit JavaScript saja mampu menopangnya. Proyek ini membangun halaman tersebut untuk Warung Melati, warung masakan rumahan Sunda milik Dewi Lestari di Bandung.

Hasil Akhir yang Dibangun #

Target akhirnya adalah satu halaman Warung Melati yang siap dibagikan kepada pelanggan. Fitur yang kita bangun secara bertahap:

  • Dokumen valid dengan metadata lengkap (charset, viewport, title, description).
  • Header hero berisi logo SVG, nama warung, dan tagline.
  • Menu makanan dalam dl yang memasangkan nama hidangan dengan keterangan dan harga.
  • Section kontak dengan address, tautan tel: dan mailto:, serta tabel jam buka.
  • Tampilan hangat dari styles/style.css dengan layout dua kolom sederhana.
  • Form pemesanan mini: validasi native, perhitungan total lewat JavaScript, dan dialog ringkasan.

Prasyarat #

Proyek ini merangkai konsep dari section sebelumnya; baca dahulu bila materinya masih asing:

  • Section Semantic HTML: header, main, footer, section, dan address.
  • Section Tables: table, caption, dan th scope.
  • Section HTML dan CSS: selector, custom properties, dan flexbox.
  • Section Forms serta Form Validation: label, select, required, min, dan max.
  • Section HTML dan JavaScript serta Interactive Elements: addEventListener dan dialog.

Empat Bagian Proyek #

Kerjakan keempat bagian berurutan; setiap bagian memakai hasil bagian sebelumnya:

BagianFokus
Bagian 1: Menyusun Struktur HalamanKerangka valid dan header hero
Bagian 2: Menu dan Kontakdl menu, address dengan tel:, tabel jam buka
Bagian 3: Styling DasarPalet hangat, tipografi menu, dua kolom
Bagian 4: Interaksi Pemesanan SederhanaForm mini, validasi native, dialog ringkasan

Memakai File Pendukung #

Tiga folder proyek menyimpan berkas pendukung. Susun salinan lokalnya mengikuti pohon berikut:

text
website-restoran/
├── assets/
│   └── logo-resto.svg
├── styles/
│   └── style.css
├── tests/
│   └── cek-struktur.html
├── part-1-struktur-halaman/
│   └── restoran.html
├── part-2-menu-dan-kontak/
│   └── restoran-konten.html
├── part-3-styling-dasar/
│   └── restoran-styling.html
└── part-4-interaksi-pemesanan-sederhana/
    ├── restoran-pesan.html
    └── pesan.js
  • assets/logo-resto.svg: logo bundar warung untuk header setiap tahap.
  • styles/style.css: stylesheet final dari Bagian 3, dipakai Bagian 4.
  • tests/cek-struktur.html: checklist sepuluh butir; kemajuan tersimpan di localStorage.

Unduh contoh tiap bagian lewat tautan pada header code block, lalu letakkan sesuai pohon di atas agar jalur relatif seperti ../assets/logo-resto.svg dan ../styles/style.css tetap benar.

Referensi resmi untuk pendalaman:

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

styles/style.css

Unduh berkas
css
/* Stylesheet proyek Website Restoran - ditulis pada Bagian 3, dipakai Bagian 3 dan 4 */
:root {
  --warna-utama: #b45309;
  --warna-utama-tua: #7c3a06;
  --warna-teks: #292524;
  --warna-latar: #fbf3e4;
  --warna-putih: #ffffff;
  --warna-garis: #ecd9bd;
  --jarak: 16px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  color: var(--warna-teks);
  background-color: var(--warna-latar);
}

header.hero {
  background-color: var(--warna-utama);
  color: var(--warna-putih);
  padding: 48px var(--jarak);
  text-align: center;
}

header.hero img {
  border-radius: 50%;
}

header.hero h1 {
  margin: 8px 0 4px;
  font-family: Georgia, serif;
  font-size: 2rem;
}

header.hero p {
  margin: 0;
  font-style: italic;
}

main {
  max-width: 960px;
  margin: 0 auto;
  padding: var(--jarak);
  display: flex;
  flex-wrap: wrap;
  gap: var(--jarak);
  align-items: flex-start;
}

main section {
  flex: 1 1 300px;
  padding: var(--jarak);
  background-color: var(--warna-putih);
  border-radius: 8px;
}

main #menu {
  flex: 2 1 380px;
}

h2 {
  margin-top: 0;
  font-family: Georgia, serif;
  color: var(--warna-utama-tua);
}

dl.menu dt {
  font-weight: bold;
}

dl.menu dd {
  margin: 0 0 var(--jarak);
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--warna-garis);
}

address {
  font-style: normal;
  line-height: 1.9;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}

caption {
  margin-bottom: 8px;
  text-align: left;
  font-size: 0.9rem;
  color: #6b7280;
}

th,
td {
  padding: 8px;
  border: 1px solid var(--warna-garis);
  text-align: left;
}

form div {
  margin-bottom: var(--jarak);
}

label {
  display: block;
  margin-bottom: 4px;
  font-weight: bold;
}

input,
select {
  width: 100%;
  padding: 8px;
  border: 1px solid var(--warna-garis);
  border-radius: 6px;
  font-size: 1rem;
  background-color: var(--warna-putih);
  color: var(--warna-teks);
}

button {
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  font-size: 1rem;
  background-color: var(--warna-utama);
  color: var(--warna-putih);
  cursor: pointer;
}

dialog {
  max-width: 360px;
  padding: var(--jarak);
  border: none;
  border-radius: 8px;
}

dialog::backdrop {
  background-color: rgba(41, 37, 36, 0.5);
}

footer {
  background-color: var(--warna-utama-tua);
  color: var(--warna-putih);
}

footer p {
  margin: 0;
  padding: var(--jarak);
  text-align: center;
}

tests/cek-struktur.html

Unduh berkas
html
<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Checklist Pemeriksaan Website Restoran</title>
  <style>
    body {
      font-family: system-ui, sans-serif;
      max-width: 720px;
      margin: 0 auto;
      padding: 16px;
      line-height: 1.6;
      color: #1f2937;
    }
    h1 {
      font-size: 1.4rem;
    }
    ul {
      padding-left: 20px;
    }
    li {
      margin-bottom: 8px;
    }
    #progres {
      width: 100%;
      height: 16px;
    }
  </style>
</head>
<body>
  <header>
    <img src="../assets/logo-resto.svg" alt="Logo Warung Melati" width="48" height="48">
    <h1>Checklist Pemeriksaan Website Restoran</h1>
  </header>
  <p>Gunakan halaman ini untuk memeriksa hasil setiap Bagian proyek. Centang butir yang telah dipenuhi; kemajuan tersimpan otomatis di browser.</p>
  <p id="ringkasan" aria-live="polite">0 dari 10 butir terpenuhi.</p>
  <progress id="progres" value="0" max="10"></progress>
  <ul>
    <li><label><input type="checkbox" data-cek="1"> Dokumen dimulai dengan <code>doctype</code> dan <code>html lang="id"</code></label></li>
    <li><label><input type="checkbox" data-cek="2"> Head memuat <code>meta charset</code>, <code>viewport</code>, <code>title</code>, dan <code>description</code></label></li>
    <li><label><input type="checkbox" data-cek="3"> Header hero memuat logo, nama warung, dan tagline</label></li>
    <li><label><input type="checkbox" data-cek="4"> Menu tersusun di dalam <code>dl</code> dengan harga pada setiap <code>dd</code></label></li>
    <li><label><input type="checkbox" data-cek="5"> Kontak dibungkus <code>address</code> dengan tautan <code>tel:</code> dan <code>mailto:</code></label></li>
    <li><label><input type="checkbox" data-cek="6"> Jam buka tersusun sebagai <code>table</code> dengan <code>caption</code> dan <code>th scope</code></label></li>
    <li><label><input type="checkbox" data-cek="7"> Halaman terhubung ke stylesheet <code>styles/style.css</code></label></li>
    <li><label><input type="checkbox" data-cek="8"> Form pemesanan memakai <code>label for</code>, <code>required</code>, serta <code>min</code> dan <code>max</code></label></li>
    <li><label><input type="checkbox" data-cek="9"> Total pesanan dihitung JavaScript lalu ditampilkan pada elemen <code>dialog</code></label></li>
    <li><label><input type="checkbox" data-cek="10"> Dialog ringkasan terbuka lewat submit dan tertutup tanpa menghalangi keyboard</label></li>
  </ul>
  <p>Sintaks seluruh file proyek juga dapat diperiksa dengan Nu Html Checker di <a href="https://validator.w3.org/nu/">validator.w3.org/nu</a>.</p>
  <script>
    const daftar = document.querySelectorAll("input[type='checkbox']");
    const progres = document.querySelector("#progres");
    const ringkasan = document.querySelector("#ringkasan");
    const KUNCI = "cek-website-restoran";

    function simpan() {
      const status = [];
      daftar.forEach(function (butir) {
        status.push(butir.checked);
      });
      try {
        localStorage.setItem(KUNCI, JSON.stringify(status));
      } catch (galat) {
        // penyimpanan tidak tersedia; status tetap berlaku selama halaman terbuka
      }
    }

    function muat() {
      try {
        const status = JSON.parse(localStorage.getItem(KUNCI));
        if (Array.isArray(status)) {
          daftar.forEach(function (butir, indeks) {
            butir.checked = status[indeks] === true;
          });
        }
      } catch (galat) {
        // biarkan semua butir pada keadaan awalnya
      }
    }

    function perbarui() {
      let terisi = 0;
      daftar.forEach(function (butir) {
        if (butir.checked) {
          terisi += 1;
        }
      });
      progres.value = terisi;
      ringkasan.textContent = terisi + " dari " + daftar.length + " butir terpenuhi.";
    }

    muat();
    perbarui();
    daftar.forEach(function (butir) {
      butir.addEventListener("change", function () {
        perbarui();
        simpan();
      });
    });
  </script>
</body>
</html>