Ringkasan dasar tentang cara membuat komponen setelan berupa penggeser dan kotak centang.
Dalam postingan ini, saya ingin berbagi pemikiran tentang cara membuat komponen Setelan untuk web yang responsif, mendukung beberapa input perangkat, dan berfungsi di seluruh browser. Coba demo.
Jika Anda lebih suka video, atau ingin melihat pratinjau UI/UX dari apa yang kami bangun, berikut adalah panduan singkat di YouTube:
Ringkasan
Saya telah membagi aspek komponen ini ke dalam bagian berikut:
- Tata Letak
- Warna
- Input rentang kustom
- Input kotak centang kustom
- Pertimbangan aksesibilitas
- JavaScript
Tata letak
Ini adalah demo GUI Challenge pertama yang semuanya menggunakan Petak CSS. Berikut setiap petak yang ditandai dengan Chrome DevTools untuk petak:
Khusus untuk kesenjangan
Tata letak yang paling umum:
foo {
display: grid;
gap: var(--something);
}
Saya menyebut tata letak ini "hanya untuk ruang" karena hanya menggunakan petak untuk menambahkan ruang di antara blok.
Lima tata letak menggunakan strategi ini, berikut semua tata letaknya ditampilkan:
Elemen fieldset
, yang berisi setiap grup input (.fieldset-item
), menggunakan gap: 1px
untuk
membuat batas tipis di antara elemen. Tidak ada solusi batas yang rumit.
.grid { display: grid; gap: 1px; background: var(--bg-surface-1); & > .fieldset-item { background: var(--bg-surface-2); } }
.grid { display: grid; & > .fieldset-item { background: var(--bg-surface-2); &:not(:last-child) { border-bottom: 1px solid var(--bg-surface-1); } } }
Penggabungan petak alami
Tata letak yang paling kompleks adalah tata letak makro, sistem tata letak
logis antara <main>
dan <form>
.
Memusatkan konten yang digabungkan
Flexbox dan petak memberikan kemampuan untuk align-items
atau
align-content
, dan saat menangani elemen pembungkus, perataan tata letak content
akan mendistribusikan ruang di antara turunan sebagai grup.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
}
Elemen utama menggunakan singkatan perataan place-content: center
sehingga
turunan dipusatkan secara vertikal dan horizontal dalam tata letak satu dan dua kolom.
Tonton video di atas untuk melihat bagaimana "konten" tetap berada di tengah, meskipun telah terjadi pelipatan.
Ulangi minmaks pengepasan otomatis
<form>
menggunakan tata letak petak adaptif untuk setiap bagian.
Tata letak ini beralih dari satu ke dua kolom berdasarkan ruang yang tersedia.
form {
display: grid;
gap: var(--space-xl) var(--space-xxl);
grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
max-width: 89vw;
}
Petak ini memiliki nilai yang berbeda untuk row-gap
(--space-xl) daripada column-gap
(--space-xxl)
untuk memberikan sentuhan kustom pada tata letak responsif. Saat kolom ditumpuk, kita menginginkan jarak yang besar, tetapi tidak sebesar jika kita menggunakan layar lebar.
Properti grid-template-columns
menggunakan 3 fungsi CSS: repeat()
, minmax()
, dan
min()
. Una Kravets memiliki postingan blog tata letak yang bagus tentang hal ini, yang menyebutnya
RAM.
Ada 3 tambahan khusus dalam tata letak kami, jika Anda membandingkannya dengan tata letak Una:
- Kita meneruskan fungsi
min()
tambahan. - Kami menentukan
align-items: flex-start
. - Ada gaya
max-width: 89vw
.
Fungsi min()
tambahan dijelaskan dengan baik oleh Evan Minto di blognya dalam postingan Intrinsically Responsive CSS Grid with minmax() and min().
Sebaiknya baca postingan tersebut. Koreksi perataan flex-start
adalah untuk
menghapus efek peregangan default, sehingga turunan tata letak ini tidak
perlu memiliki tinggi yang sama, mereka dapat memiliki tinggi intrinsik alami. Video YouTube memberikan ringkasan singkat tentang penambahan perataan ini.
max-width: 89vw
layak dibahas secara singkat dalam postingan ini.
Saya akan menunjukkan tata letak dengan dan tanpa gaya yang diterapkan:
Apa yang terjadi? Jika max-width
ditentukan, max-width
akan memberikan konteks, ukuran eksplisit, atau ukuran pasti untuk algoritma tata letak auto-fit
agar mengetahui berapa banyak pengulangan yang dapat dimuat dalam ruang. Meskipun tampaknya jelas bahwa ruangnya "lebar penuh", sesuai dengan spesifikasi petak CSS, ukuran atau ukuran maksimum yang pasti harus diberikan. Saya telah memberikan ukuran maksimum.
Jadi, mengapa 89vw
? Karena "berfungsi" untuk tata letak saya.
Saya dan beberapa orang lain di Chrome sedang menyelidiki mengapa nilai yang lebih wajar, seperti 100vw
, tidak cukup, dan apakah ini sebenarnya bug.
Spasi
Sebagian besar keharmonisan tata letak ini berasal dari palet jarak yang terbatas, tepatnya 7.
:root {
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
}
Penggunaan alur ini sangat cocok dengan petak, CSS @nest, dan sintaksis level 5 @media. Berikut contohnya, kumpulan gaya tata letak <main>
lengkap.
main {
display: grid;
gap: var(--space-xl);
place-content: center;
padding: var(--space-sm);
@media (width >= 540px) {
& {
padding: var(--space-lg);
}
}
@media (width >= 800px) {
& {
padding: var(--space-xl);
}
}
}
Petak dengan konten yang berada di tengah, diberi padding sedang secara default (seperti di perangkat seluler). Namun, saat lebih banyak ruang tampilan tersedia, ruang tersebut akan menyebar dengan meningkatkan padding. CSS 2021 terlihat cukup bagus.
Ingat tata letak sebelumnya, "hanya untuk celah"? Berikut adalah versi yang lebih lengkap tentang tampilan mereka dalam komponen ini:
header {
display: grid;
gap: var(--space-xxs);
}
section {
display: grid;
gap: var(--space-md);
}
Warna
Penggunaan warna yang terkontrol membantu desain ini tampil ekspresif namun minimalis. Saya melakukannya seperti ini:
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
}
Saya menamai warna permukaan dan teks dengan angka, bukan nama seperti
surface-dark
dan surface-darker
karena dalam kueri media, saya akan membalik
keduanya, dan terang serta gelap tidak akan bermakna.
Saya membaliknya dalam kueri media preferensi seperti ini:
:root {
...
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
}
}
}
Penting untuk melihat sekilas gambaran dan strategi secara keseluruhan sebelum kita mempelajari detail sintaksis warna. Namun, karena saya terlalu bersemangat, izinkan saya mengulang sedikit.
LCH?
Tanpa terlalu mendalami teori warna, LCH adalah sintaksis yang berorientasi pada manusia, yang sesuai dengan cara kita melihat warna, bukan cara kita mengukur warna dengan matematika (seperti 255). Hal ini memberikan keunggulan yang berbeda karena manusia dapat menulisnya dengan lebih mudah dan manusia lain akan selaras dengan penyesuaian ini.

Untuk hari ini, dalam demo ini, mari kita fokus pada sintaksis dan nilai yang saya balikkan untuk membuat terang dan gelap. Mari kita lihat 1 warna permukaan dan 1 warna teks:
:root {
--surface1: lch(10 0 0);
--text1: lch(95 0 0);
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--text1: lch(40 0 0);
}
}
}
--surface1: lch(10 0 0)
diterjemahkan menjadi kecerahan 10%
, chroma 0, dan hue 0: abu-abu tanpa warna yang sangat gelap. Kemudian, dalam kueri media untuk mode terang, kecerahan
dibalik menjadi 90%
dengan --surface1: lch(90 0 0);
. Itulah inti dari strategi tersebut. Mulailah dengan hanya mengubah kecerahan antara 2 tema, dengan mempertahankan rasio kontras yang diperlukan desain atau yang dapat mempertahankan aksesibilitas.
Bonus dengan lch()
di sini adalah bahwa kecerahan berorientasi pada manusia, dan kita dapat merasa senang dengan perubahan %
, bahwa perubahan tersebut akan secara perseptual dan konsisten berbeda %
. hsl()
misalnya, tidak seandalan.
Ada lebih banyak yang
dapat dipelajari tentang
ruang warna dan lch()
jika Anda tertarik. Segera hadir!
CSS saat ini tidak dapat mengakses warna ini sama sekali. Izinkan saya mengulanginya: Kita tidak memiliki akses ke sepertiga warna di sebagian besar monitor modern. Dan ini bukan sekadar warna, tetapi warna paling cerah yang dapat ditampilkan layar. Situs kami terlihat pudar karena hardware monitor berkembang lebih cepat daripada spesifikasi CSS dan penerapan browser.
Lea Verou
Kontrol formulir adaptif dengan color-scheme
Banyak browser menyediakan kontrol tema gelap, saat ini Safari dan Chromium, tetapi Anda harus menentukan di CSS atau HTML bahwa desain Anda menggunakannya.
Di atas menunjukkan efek properti dari panel Styles di DevTools. Demo ini menggunakan tag HTML, yang menurut saya umumnya merupakan lokasi yang lebih baik:
<meta name="color-scheme" content="dark light">
Pelajari semuanya dalam color-scheme
artikel ini oleh Thomas
Steiner. Ada banyak hal lain yang bisa didapatkan
selain input kotak centang gelap.
CSS accent-color
Ada aktivitas
terbaru di sekitar
accent-color
pada elemen formulir, yang merupakan satu gaya CSS yang dapat mengubah
warna semu yang digunakan dalam elemen input browser. Baca selengkapnya di sini di GitHub. Saya telah menyertakannya dalam
gaya untuk komponen ini. Saat browser mendukungnya, kotak centang saya akan lebih sesuai dengan tema warna merah muda dan ungu.
input[type="checkbox"] {
accent-color: var(--brand);
}
Pop warna dengan gradien tetap dan fokus dalam
Warna akan paling terlihat saat digunakan dengan hemat, dan salah satu cara yang saya sukai untuk mencapainya adalah melalui interaksi UI yang penuh warna.
Ada banyak lapisan umpan balik dan interaksi UI dalam video di atas, yang membantu memberikan kepribadian pada interaksi dengan:
- Menyoroti konteks.
- Memberikan masukan UI tentang "seberapa penuh" nilai dalam rentang.
- Memberikan masukan UI bahwa kolom menerima input.
Untuk memberikan masukan saat elemen berinteraksi, CSS menggunakan
:focus-within
pseudo class untuk mengubah tampilan berbagai elemen. Mari kita bahas
.fieldset-item
, sangat menarik:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Saat salah satu turunan elemen ini memiliki fokus dalam:
- Latar belakang
.fieldset-item
diberi warna permukaan dengan kontras yang lebih tinggi. svg
bertingkat diisi dengan warna putih untuk kontras yang lebih tinggi.<picture>
clip-path
bertingkat meluas menjadi lingkaran penuh dan latar belakang diisi dengan gradien tetap cerah.
Rentang kustom
Dengan elemen input HTML berikut, saya akan menunjukkan cara menyesuaikan tampilannya:
<input type="range">
Ada 3 bagian elemen ini yang perlu kita sesuaikan:
Gaya elemen rentang
input[type="range"] {
/* style setting variables */
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
appearance: none; /* clear styles, make way for mine */
display: block;
inline-size: 100%; /* fill container */
margin: 1ex 0; /* ensure thumb isn't colliding with sibling content */
background: transparent; /* bg is in the track */
outline-offset: 5px; /* focus styles have space */
}
Beberapa baris pertama CSS adalah bagian kustom dari gaya, dan saya harap pelabelan yang jelas dapat membantu. Gaya lainnya sebagian besar adalah gaya reset, untuk memberikan fondasi yang konsisten untuk membangun bagian komponen yang rumit.
Gaya jalur
input[type="range"]::-webkit-slider-runnable-track {
appearance: none; /* clear styles, make way for mine */
block-size: var(--track-height);
border-radius: 5ex;
background:
/* hard stop gradient:
- half transparent (where colorful fill we be)
- half dark track fill
- 1st background image is on top
*/
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
/* colorful fill effect, behind track surface fill */
var(--brand-bg-gradient) fixed;
}
Triknya adalah "mengungkapkan" warna pengisi yang cerah. Hal ini dilakukan dengan gradien penghentian keras di atas. Gradien transparan hingga persentase pengisian, dan setelah itu menggunakan warna permukaan jalur yang tidak terisi. Di belakang permukaan yang tidak terisi tersebut, ada warna lebar penuh, yang menunggu transparansi untuk menampilkannya.
Gaya pengisian jalur
Desain saya memerlukan JavaScript untuk mempertahankan gaya pengisian. Ada strategi khusus CSS, tetapi strategi tersebut mengharuskan elemen ibu jari memiliki tinggi yang sama dengan jalur, dan saya tidak dapat menemukan keselarasan dalam batas tersebut.
/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')
/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
const max = slider.getAttribute('max') || 10;
const percent = slider.value / max * 100;
return `${parseInt(percent)}%`;
};
/* on page load, set the fill amount */
sliders.forEach(slider => {
slider.style.setProperty('--track-fill', rangeToPercent(slider));
/* when a slider changes, update the fill prop */
slider.addEventListener('input', e => {
e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
})
})
Saya rasa ini akan memberikan peningkatan visual yang bagus. Penggeser berfungsi dengan baik tanpa
JavaScript, properti --track-fill
tidak diperlukan, dan tidak akan memiliki
gaya pengisian jika tidak ada. Jika JavaScript tersedia, isi properti kustom sambil mengamati perubahan pengguna, menyinkronkan properti kustom dengan nilai.
Berikut adalah postingan
bagus di
CSS-Tricks oleh Ana
Tudor, yang menunjukkan solusi khusus CSS untuk
pengisian jalur. Saya juga merasa terinspirasi dengan
elemen range
ini.
Gaya thumbnail
input[type="range"]::-webkit-slider-thumb {
appearance: none; /* clear styles, make way for mine */
cursor: ew-resize; /* cursor style to support drag direction */
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-top: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
}
Sebagian besar gaya ini adalah untuk membuat lingkaran yang bagus.
Sekali lagi Anda melihat gradien latar belakang tetap yang menyatukan
warna dinamis pada thumbnail, jalur, dan elemen SVG terkait.
Saya memisahkan gaya untuk interaksi guna membantu mengisolasi teknik yang digunakan untuk sorotan saat mengarahkan kursor:box-shadow
@custom-media --motionOK (prefers-reduced-motion: no-preference);
::-webkit-slider-thumb {
…
/* shadow spread is initally 0 */
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
/* if motion is OK, transition the box-shadow change */
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
/* on hover/active state of parent, increase size prop */
@nest input[type="range"]:is(:hover,:active) & {
--thumb-highlight-size: 10px;
}
}
Tujuannya adalah sorotan visual animasi yang mudah dikelola untuk masukan pengguna. Dengan menggunakan bayangan kotak, saya dapat menghindari pemicuan tata letak dengan efek. Saya melakukannya dengan membuat bayangan yang tidak buram dan cocok dengan bentuk lingkaran elemen jempol. Kemudian, saya mengubah dan mentransisikan ukuran penyebarannya saat kursor diarahkan.
Jika saja efek sorotan pada kotak centang semudah ini…
Pemilih lintas browser
Saya mendapati bahwa saya memerlukan pemilih -webkit-
dan -moz-
ini untuk mencapai konsistensi lintas browser:
input[type="range"] {
&::-webkit-slider-runnable-track {}
&::-moz-range-track {}
&::-webkit-slider-thumb {}
&::-moz-range-thumb {}
}
Kotak Centang Kustom
Dengan elemen input HTML berikut, saya akan menunjukkan cara menyesuaikan tampilannya:
<input type="checkbox">
Ada 3 bagian elemen ini yang perlu kita sesuaikan:
Elemen kotak centang
input[type="checkbox"] {
inline-size: var(--space-sm); /* increase width */
block-size: var(--space-sm); /* increase height */
outline-offset: 5px; /* focus style enhancement */
accent-color: var(--brand); /* tint the input */
position: relative; /* prepare for an absolute pseudo element */
transform-style: preserve-3d; /* create a 3d z-space stacking context */
margin: 0;
cursor: pointer;
}
Gaya transform-style
dan position
mempersiapkan elemen semu yang akan kita perkenalkan nanti
untuk memberi gaya pada sorotan. Jika tidak, sebagian besar
adalah hal-hal kecil terkait gaya penulisan dari saya. Saya ingin kursor menjadi penunjuk, saya ingin offset garis luar, kotak centang default terlalu kecil, dan jika accent-color
didukung, bawa kotak centang ini ke dalam skema warna merek.
Label kotak centang
Penting untuk memberikan label pada kotak centang karena 2 alasan. Yang pertama adalah untuk merepresentasikan penggunaan nilai kotak centang, untuk menjawab "aktif atau nonaktif untuk apa?" Kedua adalah untuk UX, pengguna web telah terbiasa berinteraksi dengan kotak centang melalui label terkaitnya.
<input type="checkbox" id="text-notifications" name="text-notifications" >
<label for="text-notifications"> <h3>Text Messages</h3> <small>Get notified about all text messages sent to your device</small> </label>
Pada label, masukkan atribut for
yang mengarah ke kotak centang menurut ID: <label for="text-notifications">
. Pada kotak centang, gandakan nama dan ID untuk
memastikan kotak centang ditemukan dengan berbagai alat dan teknologi, seperti mouse atau pembaca layar:
<input type="checkbox" id="text-notifications" name="text-notifications">
.
:hover
, :active
, dan lainnya tersedia gratis dengan koneksi, sehingga meningkatkan
cara interaksi dengan formulir Anda.
Sorotan kotak centang
Saya ingin menjaga konsistensi antarmuka, dan elemen penggeser memiliki sorotan
thumbnail yang bagus yang ingin saya gunakan dengan kotak centang. Thumbnail dapat menggunakan box-shadow
dan properti spread
untuk menskalakan bayangan ke atas dan ke bawah. Namun, efek tersebut tidak berfungsi di sini karena kotak centang kita berbentuk persegi, dan harus
berbentuk persegi.
Saya dapat mencapai efek visual yang sama dengan elemen semu, dan CSS rumit yang sayangnya cukup banyak:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
input[type="checkbox"]::before {
--thumb-scale: .01; /* initial scale of highlight */
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%); /* circle shape */
position: absolute; /* this is why position relative on parent */
top: 50%; /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
left: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center; /* goal is a centered scaling circle */
transform: /* order here matters!! */
translateX(-50%) /* counter balances left: 50% */
translateY(-50%) /* counter balances top: 50% */
translateZ(-1px) /* PUTS IT BEHIND THE CHECKBOX */
scale(var(--thumb-scale)) /* value we toggle for animation */
;
will-change: transform;
@media (--motionOK) { /* transition only if motion is OK */
& {
transition: transform .2s ease;
}
}
}
/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
--thumb-scale: 1;
}
Membuat elemen semu lingkaran adalah pekerjaan yang mudah, tetapi menempatkannya di belakang elemen yang terlampir padanya lebih sulit. Berikut sebelum dan setelah saya memperbaikinya:
Ini jelas merupakan interaksi mikro, tetapi penting bagi saya untuk menjaga konsistensi visual. Teknik penskalaan animasi sama dengan yang telah kita gunakan di tempat lain. Kita menetapkan properti kustom ke nilai baru dan membiarkan CSS mentransisikannya berdasarkan preferensi gerakan. Fitur utamanya di sini adalah translateZ(-1px)
. Elemen induk membuat ruang 3D dan elemen turunan semu ini memanfaatkannya dengan menempatkan dirinya sedikit ke belakang dalam ruang z.
Aksesibilitas
Video YouTube tersebut mendemonstrasikan interaksi mouse, keyboard, dan pembaca layar untuk komponen setelan ini dengan sangat baik. Saya akan menyebutkan beberapa detailnya di sini.
Pilihan Elemen HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Setiap penyimpanan ini berisi petunjuk dan tips untuk alat penjelajahan pengguna. Beberapa elemen memberikan petunjuk interaksi, beberapa menghubungkan interaktivitas, dan beberapa membantu membentuk hierarki aksesibilitas yang dinavigasi pembaca layar.
Atribut HTML
Kita dapat menyembunyikan elemen yang tidak diperlukan oleh pembaca layar, dalam hal ini ikon di samping penggeser:
<picture aria-hidden="true">
Video di atas menunjukkan alur pembaca layar di Mac OS. Perhatikan bagaimana fokus input berpindah langsung dari satu penggeser ke penggeser berikutnya. Hal ini karena kami telah menyembunyikan ikon yang mungkin menjadi perhentian dalam perjalanan ke penggeser berikutnya. Tanpa atribut ini, pengguna harus berhenti, mendengarkan, dan melewati gambar yang mungkin tidak dapat mereka lihat.
SVG adalah sekumpulan matematika, mari tambahkan elemen <title>
untuk judul saat mengarahkan kursor mouse secara bebas dan komentar yang mudah dibaca tentang apa yang dibuat oleh matematika tersebut:
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
Selain itu, kami telah menggunakan HTML yang ditandai dengan jelas, sehingga pengujian formulir berjalan dengan baik di mouse, keyboard, pengontrol video game, dan pembaca layar.
JavaScript
Saya telah membahas cara warna pengisian jalur dikelola dari JavaScript,
jadi mari kita lihat JavaScript terkait <form>
sekarang:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
Setiap kali formulir digunakan dan diubah, konsol mencatat formulir sebagai objek ke dalam tabel agar mudah ditinjau sebelum dikirimkan ke server.
Kesimpulan
Sekarang setelah Anda tahu cara saya melakukannya, bagaimana Anda?! Hal ini menghasilkan arsitektur komponen yang menarik. Siapa yang akan membuat versi pertama dengan slot di framework favorit mereka? 🙂
Mari kita diversifikasi pendekatan kita dan pelajari semua cara untuk membangun di web. Buat demo, kirimkan linknya kepada saya di Twitter, dan saya akan menambahkannya ke bagian Remix komunitas di bawah.