Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Summary of ChangesHello @Ardelyo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! Pull request ini menghadirkan peningkatan signifikan pada antarmuka pengguna dan arsitektur aplikasi, terutama berfokus pada presentasi konten yang dinamis dan efek animasi. Perubahan inti melibatkan perombakan total halaman 'Story' dengan transisi ke pustaka animasi GSAP untuk pengalaman berbasis scroll yang lebih canggih. Selain itu, komponen UI baru untuk efek visual dan tampilan waktu video telah ditambahkan, dan data untuk halaman video telah dieksternalisasi untuk pemeliharaan yang lebih baik. Penyesuaian kecil pada teks dan jalur gambar di berbagai halaman juga berkontribusi pada peningkatan branding dan lokalisasi. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
Secara keseluruhan, ini adalah pull request yang sangat baik dan masif, melakukan refactoring besar pada halaman Story dengan beralih dari framer-motion ke gsap, yang merupakan perubahan arsitektur yang signifikan. Perubahan ini juga memperkenalkan beberapa komponen efek baru yang dapat digunakan kembali seperti GlitchText dan MatrixRain, serta memisahkan data ke dalam file khusus, yang sangat meningkatkan keterbacaan dan pemeliharaan kode. Selain itu, ada banyak perbaikan branding dan lokalisasi teks ke Bahasa Indonesia, yang menunjukkan perhatian terhadap detail. Saya menemukan beberapa masalah tingkat menengah hingga tinggi terkait dependensi hook, penanganan event, dan type safety yang perlu ditangani untuk menyempurnakan implementasi.
| useGSAP(() => { | ||
| if (!elementRef.current) return; | ||
|
|
||
| const obj = { val: 0 }; | ||
| gsap.to(obj, { | ||
| val: numericValue, | ||
| duration: duration, | ||
| ease: "power2.out", | ||
| scrollTrigger: { | ||
| trigger: elementRef.current, | ||
| start: "top 90%", | ||
| }, | ||
| onUpdate: () => { | ||
| if (elementRef.current) { | ||
| const formatted = obj.val % 1 === 0 ? obj.val.toFixed(0) : obj.val.toFixed(1); | ||
| elementRef.current.innerText = formatted + suffix; | ||
| } | ||
| } | ||
| }); | ||
| }, { scope: elementRef }); |
There was a problem hiding this comment.
Hook useGSAP di sini tidak memiliki array dependensi. Callback di dalam useGSAP bergantung pada props numericValue dan duration. Tanpa menyertakannya dalam dependensi, animasi tidak akan diperbarui jika props ini berubah setelah render awal. Ini dapat menyebabkan perilaku yang tidak konsisten jika komponen AnimatedNumber dirender ulang dengan nilai yang berbeda.
Untuk memperbaikinya, tambahkan numericValue dan duration ke dalam objek konfigurasi useGSAP.
| useGSAP(() => { | |
| if (!elementRef.current) return; | |
| const obj = { val: 0 }; | |
| gsap.to(obj, { | |
| val: numericValue, | |
| duration: duration, | |
| ease: "power2.out", | |
| scrollTrigger: { | |
| trigger: elementRef.current, | |
| start: "top 90%", | |
| }, | |
| onUpdate: () => { | |
| if (elementRef.current) { | |
| const formatted = obj.val % 1 === 0 ? obj.val.toFixed(0) : obj.val.toFixed(1); | |
| elementRef.current.innerText = formatted + suffix; | |
| } | |
| } | |
| }); | |
| }, { scope: elementRef }); | |
| useGSAP(() => { | |
| if (!elementRef.current) return; | |
| const obj = { val: 0 }; | |
| gsap.to(obj, { | |
| val: numericValue, | |
| duration: duration, | |
| ease: "power2.out", | |
| scrollTrigger: { | |
| trigger: elementRef.current, | |
| start: "top 90%", | |
| }, | |
| onUpdate: () => { | |
| if (elementRef.current) { | |
| const formatted = obj.val % 1 === 0 ? obj.val.toFixed(0) : obj.val.toFixed(1); | |
| elementRef.current.innerText = formatted + suffix; | |
| } | |
| } | |
| }); | |
| }, { scope: elementRef, dependencies: [numericValue, duration] }); |
| <button className="flex items-center gap-2 text-white font-bold uppercase tracking-widest text-xs group"> | ||
| Eksplorasi <ChevronRight className="group-hover:translate-x-1 transition-transform" size={16} /> | ||
| </button> |
There was a problem hiding this comment.
Elemen ini terlihat seperti tombol interaktif, tetapi saat ini tidak memiliki fungsi apa pun (tidak ada onClick atau href). Ini dapat membingungkan pengguna. Sebaiknya jadikan elemen ini sebagai tautan (<Link>) yang mengarah ke halaman detail divisi yang relevan, atau tambahkan handler onClick jika ada aksi yang dimaksudkan.
| <button className="flex items-center gap-2 text-white font-bold uppercase tracking-widest text-xs group"> | |
| Eksplorasi <ChevronRight className="group-hover:translate-x-1 transition-transform" size={16} /> | |
| </button> | |
| <Link to={`/division/${title.toLowerCase()}`} className="flex items-center gap-2 text-white font-bold uppercase tracking-widest text-xs group"> | |
| Eksplorasi <ChevronRight className="group-hover:translate-x-1 transition-transform" size={16} /> | |
| </Link> |
| <div className="flex justify-center gap-12 text-gray-600 font-bold uppercase tracking-widest text-xs"> | ||
| <span className="hover:text-white transition-colors cursor-pointer">Instagram</span> | ||
| <span className="hover:text-white transition-colors cursor-pointer">Discord</span> | ||
| <span className="hover:text-white transition-colors cursor-pointer">GitHub</span> | ||
| </div> |
There was a problem hiding this comment.
Tautan media sosial ini saat ini menggunakan tag <span>, yang membuatnya tidak dapat diklik dan tidak dapat diakses oleh pembaca layar. Untuk fungsionalitas dan aksesibilitas yang benar, elemen-elemen ini harus diubah menjadi tag <a> dengan atribut href yang sesuai.
| <div className="flex justify-center gap-12 text-gray-600 font-bold uppercase tracking-widest text-xs"> | |
| <span className="hover:text-white transition-colors cursor-pointer">Instagram</span> | |
| <span className="hover:text-white transition-colors cursor-pointer">Discord</span> | |
| <span className="hover:text-white transition-colors cursor-pointer">GitHub</span> | |
| </div> | |
| <div className="flex justify-center gap-12 text-gray-600 font-bold uppercase tracking-widest text-xs"> | |
| <a href="#" className="hover:text-white transition-colors cursor-pointer">Instagram</a> | |
| <a href="#" className="hover:text-white transition-colors cursor-pointer">Discord</a> | |
| <a href="#" className="hover:text-white transition-colors cursor-pointer">GitHub</a> | |
| </div> |
| const handleResize = () => { | ||
| canvas.width = window.innerWidth; | ||
| canvas.height = window.innerHeight; | ||
| const newColumns = canvas.width / fontSize; | ||
| for (let i = drops.length; i < newColumns; i++) { | ||
| drops[i] = 1; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Fungsi handleResize saat ini hanya menangani kasus ketika jendela diperlebar (menambah drops baru), tetapi tidak menangani kasus ketika jendela menyempit. Hal ini dapat menyebabkan array drops terus bertambah tanpa batas jika pengguna mengubah ukuran jendela berulang kali, yang berpotensi menyebabkan kebocoran memori kecil.
Sebaiknya atur ulang panjang array drops agar sesuai dengan jumlah kolom yang baru setiap kali ukuran jendela diubah.
const handleResize = () => {
if (!canvas) return;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const newColumns = canvas.width / fontSize;
drops.length = Math.floor(newColumns);
for (let i = 0; i < drops.length; i++) {
if (!drops[i]) drops[i] = 1;
}
};
| import { useTransform } from 'framer-motion'; | ||
|
|
||
| interface TimecodeProps { | ||
| scrollProgress: any; |
There was a problem hiding this comment.
Tipe prop scrollProgress diatur sebagai any. Untuk meningkatkan keamanan tipe (type safety) dan keterbacaan kode dalam proyek TypeScript, sebaiknya gunakan tipe yang lebih spesifik. Dari framer-motion, tipe yang sesuai adalah MotionValue<number>.
| scrollProgress: any; | |
| scrollProgress: MotionValue<number>; |
| </div> | ||
| <div className="text-center mt-20 text-gray-600 text-xs font-mono"> | ||
| <p>TERMINAL SESSION ACTIVE // ID: {Math.random().toString(36).substr(2, 6).toUpperCase()}</p> | ||
| <p>SESI TERMINAL AKTIF // ID: {Math.random().toString(36).substr(2, 6).toUpperCase()}</p> |
There was a problem hiding this comment.
ID sesi terminal ini dibuat menggunakan Math.random() langsung di dalam JSX, yang berarti ID baru akan dibuat setiap kali komponen dirender ulang. Hal ini mungkin bukan perilaku yang diinginkan jika Anda ingin ID tetap konsisten selama masa aktif komponen.
Untuk memastikan ID hanya dibuat sekali saat komponen pertama kali dimuat, gunakan hook useMemo.
| <p>SESI TERMINAL AKTIF // ID: {Math.random().toString(36).substr(2, 6).toUpperCase()}</p> | |
| <p>SESI TERMINAL AKTIF // ID: {sessionId}</p> |
📋 Deskripsi
Jelaskan perubahan yang kamu buat secara singkat.
🔗 Issue Terkait
Fixes #(nomor issue)
🔄 Tipe Perubahan
📸 Screenshot (jika UI berubah)
✅ Checklist
📝 Catatan untuk Reviewer
Tambahkan catatan atau pertanyaan untuk reviewer di sini.