6
Antarmuka Pengguna
Seluruh antarmuka github-roast berada di satu komponen, src/routes/+page.svelte, berukuran 126 baris. Komponen ini memegang lima variabel reaktif, satu select berisi 15 bahasa, satu tombol pemicu, dan satu blok hasil yang dirender lewat SvelteMarkdown. Tidak ada komponen anak: formulir, tombol, dan kotak hasil ditulis langsung di berkas itu src/routes/+page.svelte:6-101. Halaman ini hanya membahas lapisan tampilan; urutan request sampai ke model dijelaskan di Alur Permintaan Roast, dan bentuk response dijelaskan di Endpoint POST /llama.
State Komponen dan Pemetaannya ke DOM
Lima variabel di blok <script> menjadi satu-satunya sumber kebenaran tampilan. username, roast, loading, mounted, dan selectedLanguage masing-masing mengikat satu bagian DOM, sehingga perubahan satu variabel langsung mengubah satu elemen src/routes/+page.svelte:6-101.
| Variabel | Nilai awal | Elemen yang diikat |
|---|---|---|
username | '' | input lewat bind:value; juga syarat disabled pada tombol |
selectedLanguage | 'english' | select lewat bind:value |
loading | false | atribut disabled pada input, select, dan button |
roast | '' | <SvelteMarkdown source={roast} /> |
mounted | false | syarat tampil blok hasil, di-set true oleh onMount |
Ikatan itu membentuk satu graf pendek dari state ke elemen:
graph TD
username["username"] --> inputEl["input bind:value"]
username --> buttonEl["button: disabled bila loading atau username kosong"]
selectedLanguage["selectedLanguage"] --> selectEl["select bind:value"]
languages["languages: 15 entri"] --> selectEl
loading["loading"] --> inputEl
loading --> selectEl
loading --> buttonEl
roast["roast"] --> markdownEl["SvelteMarkdown source"]
mounted["mounted dari onMount"] --> bubbleEl["div transition:fade"]
markdownEl --> bubbleEl
style username fill:#8b5cf6,color:#fff
style selectedLanguage fill:#8b5cf6,color:#fff
style roast fill:#8b5cf6,color:#fff
style loading fill:#f59e0b,color:#000
style mounted fill:#f59e0b,color:#000
style bubbleEl fill:#2d7d46,color:#fff
%% fig: Pemetaan state komponen ke elemen DOM
%% desc: Variabel di blok script mengikat input, select, dan tombol; roast plus mounted menentukan blok hasil yang dirender SvelteMarkdown.mounted di-set true di dalam onMount, jadi blok hasil hanya bisa muncul setelah komponen terpasang di browser. Pemeriksaan {#if roast && mounted} memakai dua syarat sekaligus: teks hasil harus tidak kosong dan komponen harus sudah terpasang src/routes/+page.svelte:30-322.
Siklus Hidup Satu Roast di Komponen
handleRoast adalah satu-satunya jalur yang mengubah roast dan loading. Fungsi ini menolak berjalan bila username kosong, menyalakan loading, mengirim POST ke /llama dengan body berisi { username, language: selectedLanguage }, lalu menutup loading di blok finally src/routes/+page.svelte:34-593.
Ada dua jalur keluar dari fetch. Bila response.ok bernilai false, kode melempar new Error('Failed to fetch roast'); bila response berhasil, nilai data.roast disalin ke variabel roast. Keduanya bertemu di catch, dan catch menulis console.error('Error:', error) lalu mengganti roast dengan string 'Oops! Looks like our roasting machine is on a coffee break. Try again later!' src/routes/+page.svelte:34-593.
stateDiagram-v2
[*] --> Idle
Idle --> Loading: klik button atau tekan Enter
Loading --> Rendered: response.ok, roast = data.roast
Loading --> Fallback: response tidak ok, lempar 'Failed to fetch roast'
Rendered --> Loading: roast berikutnya
Fallback --> Loading: roast berikutnya
Rendered --> [*]
Fallback --> [*]
style Loading fill:#f59e0b,color:#000
style Rendered fill:#2d7d46,color:#fff
style Fallback fill:#dc2626,color:#fff
style Idle fill:#8b5cf6,color:#fff
%% fig: Siklus loading sampai roast tampil atau gagal
%% desc: handleRoast memindahkan komponen dari Idle ke Loading, lalu ke Rendered bila response ok atau ke Fallback bila tidak; keduanya kembali ke Loading pada percobaan berikutnya.Karena catch menulis pesan yang sama ke roast, kegagalan tidak pernah tampil sebagai pesan error mentah di layar. Pengguna hanya melihat kalimat pengganti bernada lelucon, sedangkan detail error tetap tercatat di console browser src/routes/+page.svelte:53-584.
⚠️ Blok
catchmengganti isiroasttanpa memeriksa jeniserror.timeoutjaringan,responsedengan status 500, danJSONyang rusak semuanya berakhir di kalimat yang sama, sehingga pengguna tidak bisa membedakan gangguan sementara dari kegagalan permanen src/routes/+page.svelte:47-555.
Elemen Formulir, Pilihan Bahasa, dan Tombol
Markup utama berada di satu div dengan kelas container mx-auto p-4 max-w-md, diikuti <h1> bertitel GitHub Roaster. Isinya berupa input teks, select bahasa, dan button, masing-masing dibungkus div dengan kelas mb-4 src/routes/+page.svelte:70-1026.
| Elemen | Atribut kunci | Perilaku saat loading |
|---|---|---|
input teks | bind:value={username}, placeholder="Enter GitHub username", on:keydown={handleKeyDown} | disabled={loading} |
select | bind:value={selectedLanguage}, 15 option dari {#each languages as language} | disabled={loading} |
button | on:click={handleRoast}, `disabled={loading |
Label tombol dipilih lewat satu ekspresi ternary: Roasting... ketika loading benar, dan Roast This GitHub! selebihnya. Tombol juga nonaktif selama username masih kosong, sehingga handleRoast tidak perlu menangani kasus itu dari sisi tampilan, meski fungsi itu tetap memeriksa if (!username) return sebagai pengaman src/routes/+page.svelte:96-1027.
handleKeyDown hanya satu baris, event.key === 'Enter' && handleRoast();, jadi menekan Enter di dalam input menjalankan jalur yang sama dengan menekan tombol src/routes/+page.svelte:61-638.
Daftar languages memuat 15 entri, dari english sampai traditionalChinese, dan tiap entri berupa pasangan value serta label. Semua nilai value diteruskan apa adanya ke body request sebagai language src/routes/+page.svelte:12-289. Satu entri memakai value yang tidak sama dengan labelnya: value: 'indian' dengan label 'हिंदी (Hindi)'; nilai inilah yang harus dikenali oleh prompt di Prompt Multibahasa src/routes/+page.svelte:1710.
<svelte:head> menetapkan title halaman menjadi GitHub Profile Roast 🔥🔥🔥, menggantikan judul bawaan dari templat HTML src/routes/+page.svelte:66-6811. Sementara itu src/app.html hanya berisi kerangka %sveltekit.head% dan %sveltekit.body% beserta body data-sveltekit-preload-data="hover" src/app.html:1-1212.
Rendering Markdown dan Animasi Munculnya Hasil
Hasil roast ditampilkan sebagai markdown, bukan teks biasa. SvelteMarkdown diimpor dari paket svelte-markdown pada package.json versi ^0.4.1 dan dipakai sebagai <SvelteMarkdown source={roast} /> di dalam <p> src/routes/+page.svelte:104-11113. Karena itu bold, daftar, dan tautan yang dihasilkan model di Prompt Multibahasa tetap terbaca sebagai format, bukan sebagai karakter mentah.
Blok pembungkus memakai transition:fade={{ duration: 300 }}, sehingga kotak hasil memudar masuk setiap kali {#if roast && mounted} berubah dari salah menjadi benar. div kecil dengan border-8 dan border-b-gray-100 membentuk segitiga penunjuk di atas kotak, meniru balon percakapan yang mengarah ke formulir src/routes/+page.svelte:104-11113.
Di bawah blok hasil ada empat baris keterangan: hak cipta © 2024 github-roast.pages.dev, tautan ke akun admin di x.com/rubi1945, tautan Source code on GitHub, dan tautan ke issues/47 bertajuk Permanently opt out and delete all roasts related to your GitHub account. Semua tautan luar memakai target="_blank" src/routes/+page.svelte:113-12514.
Styling Tailwind dan Kerangka Halaman
Styling tidak memakai blok <style> di dalam komponen. Seluruh kelas berasal dari Tailwind, yang diaktifkan oleh tiga direktif di src/app.css: @tailwind base, @tailwind components, dan @tailwind utilities src/app.css:1-315. Berkas itu diimpor satu kali oleh layout root, src/routes/+layout.svelte, yang isinya hanya import '../app.css' dan <slot /> src/routes/+layout.svelte:1-516.
tailwind.config.js memindai ./src/**/*.{html,js,svelte,ts} sebagai content, dengan theme.extend dan plugins dibiarkan kosong. Artinya hanya kelas yang benar-benar tertulis di berkas sumber yang ikut di-build; kelas yang dirakit lewat penggabungan string tidak akan dikenali pemindai ini tailwind.config.js:1-817. Warna aksen halaman seluruhnya kelas bawaan Tailwind: text-purple-600 pada judul, bg-purple-500 dengan hover:bg-purple-600 pada tombol, serta disabled:bg-purple-300 dan disabled:cursor-not-allowed saat tombol nonaktif src/routes/+page.svelte:70-1026.
Halaman Statis tanpa Data Dinamis
src/routes/+page.js hanya mengekspor export const prerender = true;. Karena halaman ini tidak membaca data dinamis apa pun saat dirender di server, hasilnya disajikan sebagai aset statis di produksi, sedangkan panggilan /llama tetap terjadi di browser src/routes/+page.js:1-318. Konsekuensi prerender terhadap build dan deploy dibahas di Deployment ke Cloudflare Pages.