Ikhtisar dasar tentang cara membangun komponen setelan {i>slider<i} dan kotak centang.
Dalam postingan ini, saya ingin berbagi pemikiran tentang cara membangun komponen Setelan untuk web yang responsif, mendukung beberapa input perangkat, dan berfungsi di browser. Coba demonya.
Jika Anda lebih menyukai video, atau menginginkan pratinjau UI/UX terkait hal yang kami kembangkan, berikut panduan singkat di YouTube:
Ringkasan
Saya telah membagi beberapa aspek komponen ini menjadi beberapa bagian berikut:
- Tata Letak
- Warna
- Input rentang kustom
- Input kotak centang kustom
- Pertimbangan aksesibilitas
- JavaScript
Tata letak
Ini adalah demo Tantangan GUI pertama yang menjadi semua Petak CSS. Berikut adalah setiap petak yang ditandai dengan Chrome DevTools untuk petak:
Hanya untuk jeda
Tata letak yang paling umum:
foo {
display: grid;
gap: var(--something);
}
Saya menyebut tata letak ini "hanya untuk celah" karena hanya menggunakan petak untuk menambahkan celah antarblok.
Lima tata letak menggunakan strategi ini, berikut semuanya ditampilkan:
Elemen fieldset
, yang berisi setiap grup input (.fieldset-item
), menggunakan gap: 1px
untuk
membuat batas garis rambut antar-elemen. Tidak ada solusi pembatas 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 akhirnya menjadi tata letak makro, yaitu sistem
tata letak logis antara <main>
dan <form>
.
Memusatkan konten ke tengah
Flexbox dan petak memberikan kemampuan untuk align-items
atau
align-content
, dan saat menangani elemen penggabungan, perataan tata letak content
akan mendistribusikan ruang di antara turunan sebagai satu kelompok.
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 di tata letak satu dan dua kolom.
Tonton video di atas bagaimana "konten" tetap di tengah, meskipun penggabungan telah terjadi.
Ulangi paskan otomatis minmax
<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) dengan column-gap
(--space-xxl)
untuk menempatkan sentuhan kustom tersebut di tata letak responsif. Saat kolom ditumpuk, kita menginginkan
kesenjangan yang besar, tetapi tidak sebesar jika kita berada di layar yang 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 pada tata letak kita, jika Anda membandingkannya dengan tata letak Una:
- Kita meneruskan fungsi
min()
tambahan. - Kita menentukan
align-items: flex-start
. - Ada gaya
max-width: 89vw
.
Fungsi min()
tambahan dijelaskan dengan baik oleh Evan Minto di blognya dalam postingan Petak CSS yang Responsif terhadap Intrinsik dengan minmax() dan min(). Sebaiknya baca hal tersebut. Koreksi perataan flex-start
adalah
menghapus efek regang default, sehingga turunan tata letak ini tidak
perlu memiliki ketinggian yang sama, tetapi dapat memiliki ketinggian intrinsik alami. Video
YouTube memberikan penjelasan singkat tentang penambahan penyelarasan ini.
max-width: 89vw
perlu dijelaskan secara singkat dalam postingan ini.
Izinkan saya menunjukkan tata letak dengan dan tanpa penerapan gaya:
Apa yang terjadi??? Jika max-width
ditentukan, fungsi ini akan memberikan konteks,
pengubahan ukuran eksplisit, atau pengubahan
ukuran yang pasti untuk algoritma
tata letak auto-fit
guna mengetahui
jumlah pengulangan yang dapat ditampung dalam ruang. Meskipun tampaknya sudah jelas bahwa
ruangnya memiliki "lebar penuh", sesuai spesifikasi petak CSS, ukuran yang pasti atau ukuran maksimum
harus disediakan. Saya telah memberikan ukuran maksimum.
Jadi, mengapa 89vw
? Karena "berhasil" untuk tata letak saya.
Saya dan beberapa rekan Chrome lainnya sedang menyelidiki mengapa nilai yang lebih masuk akal,
seperti 100vw
tidaklah cukup, dan apakah ini sebenarnya adalah bug.
Spasi
Sebagian besar harmoni tata letak ini berasal dari palet spasi yang terbatas, yaitu 7 tepat.
: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 baik dengan petak, CSS @nest, dan sintaksis @media level 5. Berikut adalah contohnya, kumpulan gaya tata letak <main>
yang 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);
}
}
}
{i>Grid<i} dengan konten di tengah, dengan padding yang cukup secara {i>default<i} (seperti di perangkat seluler). Namun, jika makin banyak ruang area pandang yang tersedia, area ini akan menyebar dengan meningkatkan padding. CSS 2021 terlihat cukup bagus!
Ingat tata letak sebelumnya, "hanya untuk celah"? Berikut adalah versi yang lebih lengkap tampilannya 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 menonjol sebagai ekspresif namun minimal. 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 saya dengan angka, bukan nama seperti
surface-dark
dan surface-darker
karena dalam kueri media, saya akan membaliknya,
dan terang serta gelap tidak akan bermakna.
Saya memasukkannya ke 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 membahas detail sintaksis warna. Tapi, karena saya sudah terlalu terlalu cepat, izinkan saya kembali.
LCH?
Tanpa terlalu mendalami teori warna, LCH adalah sintaksis berorientasi manusia, yang melayani cara kita memandang warna, bukan cara kita mengukur warna dengan matematika (seperti 255). Cara ini memberi keunggulan karena manusia dapat menulisnya dengan lebih mudah, dan orang lain akan dapat menyesuaikan dengan penyesuaian ini.
Untuk hari ini, dalam demo ini, mari kita fokus pada sintaks dan nilai yang saya balik untuk membuat terang dan gelap. Mari kita lihat 1 platform 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 10%
kecerahan, 0 kroma, dan 0 hue: abu-abu tidak berwarna yang sangat gelap. Kemudian, pada kueri media untuk mode terang, kecerahan
dibalik menjadi 90%
dengan --surface1: lch(90 0 0);
. Dan itulah inti dari strategi tersebut. Mulailah dengan hanya mengubah kecerahan di antara 2 tema, mempertahankan
rasio kontras yang diperlukan desain, atau apa yang dapat mempertahankan aksesibilitas.
Bonus dari lch()
di sini adalah bahwa kecerahan berorientasi pada manusia, dan kita dapat
merasakan perubahan %
padanya, sehingga akan secara persepsi dan konsisten
bahwa %
berbeda. hsl()
misalnya, tidak terlalu
andal.
Ada lebih banyak hal yang dapat
dipelajari tentang
ruang warna dan lch()
jika Anda tertarik. Segera hadir!
Saat ini CSS tidak dapat mengakses warna ini sama sekali. Izinkan saya mengulangi: Kita tidak memiliki akses ke sepertiga warna di sebagian besar monitor modern. Dan ini bukan sekadar warna, tetapi warna paling jernih yang dapat ditampilkan layar. Situs kami hancur karena monitor hardware berevolusi lebih cepat daripada spesifikasi CSS dan implementasi browser.
Lea Verou
Kontrol bentuk adaptif dengan skema warna
Banyak browser mengirimkan kontrol tema gelap, saat ini Safari dan Chromium, tetapi Anda harus menentukan dalam CSS atau HTML bahwa desain Anda akan menggunakannya.
Hal di atas menunjukkan efek properti dari panel Styles DevTools. Demo ini menggunakan tag HTML, yang menurut saya umumnya merupakan lokasi yang lebih baik:
<meta name="color-scheme" content="dark light">
Pelajari semuanya di artikel
color-scheme
oleh Thomas
Steiner. Ada lebih banyak hal yang bisa didapatkan
daripada input kotak centang gelap!
CSS accent-color
Sudah ada aktivitas
terbaru seputar
accent-color
pada elemen formulir, yaitu gaya CSS tunggal yang dapat mengubah
warna tint yang digunakan di elemen input browser. Baca selengkapnya di sini di
GitHub. Saya telah memasukkannya ke
dalam gaya saya untuk komponen ini. Karena browser mendukungnya, kotak centang saya akan
lebih ke tema dengan pop warna merah muda dan ungu.
input[type="checkbox"] {
accent-color: var(--brand);
}
Pop warna dengan gradien tetap dan fokus di dalam
Warna muncul paling banyak jika tidak sering digunakan, dan salah satu cara yang ingin saya capai adalah melalui interaksi UI yang penuh warna.
Ada banyak lapisan umpan balik UI dan interaksi dalam video di atas, yang membantu memberikan kepribadian pada interaksi dengan cara:
- Menyoroti konteks.
- Memberikan masukan UI tentang "seberapa lengkap" nilai dalam rentang.
- Memberikan masukan UI bahwa suatu kolom menerima input.
Untuk memberikan masukan saat suatu elemen berinteraksi, CSS menggunakan pseudo class
:focus-within
untuk mengubah tampilan berbagai elemen. Mari kita uraikan
.fieldset-item
, dan ini sangat menarik:
.fieldset-item {
...
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
}
Jika salah satu turunan elemen ini memiliki focus-dalam:
- Latar belakang
.fieldset-item
diberi warna permukaan kontras yang lebih tinggi. svg
bertingkat diisi dengan warna putih untuk kontras yang lebih tinggi.<picture>
clip-path
bertingkat diperluas ke lingkaran penuh dan latar belakang diisi dengan gradien tetap yang cerah.
Rentang kustom
Dengan elemen input HTML berikut, saya akan menunjukkan cara menyesuaikan penampilannya:
<input type="range">
Ada 3 bagian untuk 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 khusus dari gaya, dan saya harap pelabelan yang jelas akan membantu. Gaya lainnya sebagian besar adalah gaya yang direset, untuk memberikan fondasi yang konsisten dalam membangun bagian komponen yang rumit.
Gaya trek
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 isian yang cerah. Hal ini dilakukan dengan gradien perhentian keras di bagian atas. Gradien transparan hingga persentase pengisian, dan setelah itu menggunakan warna platform trek yang tidak terisi. Di balik permukaan yang tidak terisi itu, ada warna dengan lebar penuh, yang menunggu transparansi untuk mengungkapnya.
Melacak gaya pengisian
Desain saya memerlukan JavaScript untuk mempertahankan gaya isian. Hanya ada strategi CSS tertentu, tetapi strategi tersebut memerlukan elemen thumb agar sama tingginya dengan lagu, dan saya tidak bisa 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));
})
})
Menurut saya, ini adalah peningkatan visual yang bagus. Penggeser berfungsi dengan baik tanpa
JavaScript, properti --track-fill
tidak diperlukan, hanya tidak akan memiliki
gaya pengisian jika tidak ada. Jika JavaScript tersedia, isi properti
kustom sekaligus amati setiap perubahan yang dilakukan pengguna, dengan menyinkronkan properti
kustom dengan nilai.
Berikut ini postingan
bagus tentang
CSS-Tricks oleh Ana
Tudor, yang menunjukkan solusi khusus CSS untuk
pengisian jalur. Saya juga merasa
elemen range
ini sangat menginspirasi.
Gaya jempol
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;
}
Mayoritas gaya ini adalah untuk membuat lingkaran yang bagus.
Sekali lagi, Anda akan melihat gradien latar belakang tetap di sana yang menyatukan
warna dinamis thumbnail, trek, dan elemen SVG terkait.
Saya memisahkan gaya untuk interaksi guna membantu mengisolasi teknik box-shadow
yang digunakan untuk sorotan pengarahan kursor:
@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 dengan animasi yang mudah dikelola untuk mendapatkan masukan pengguna. Dengan menggunakan bayangan kotak, saya dapat menghindari tata letak pemicu dengan efek. Saya melakukannya dengan membuat bayangan yang tidak diburamkan dan menyesuaikan dengan bentuk lingkaran elemen thumb. Lalu saya mengubah dan mentransisikan ukuran penyebarannya saat mengarahkan kursor.
Jika hanya efek sorotan yang begitu mudah di kotak centang...
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 penampilannya:
<input type="checkbox">
Ada 3 bagian untuk 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 pseudo yang akan kita perkenalkan nanti
untuk menata gaya sorotan. Jika tidak, itu sebagian besar berisi
gaya opini minor dari saya. Saya suka kursor menjadi pointer, saya suka
offset garis, kotak centang default terlalu kecil, dan jika accent-color
didukung, masukkan
kotak centang ini ke dalam skema warna merek.
Label kotak centang
Penting untuk memberikan label untuk kotak centang karena 2 alasan. Yang pertama adalah untuk menyatakan untuk apa nilai kotak centang digunakan, untuk menjawab "aktif atau nonaktif untuk apa?" Kedua, untuk UX, pengguna web sudah terbiasa berinteraksi dengan kotak centang melalui label terkait.
<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 Anda, tempatkan atribut for
yang mengarah ke kotak centang menurut ID: <label for="text-notifications">
. Pada kotak centang, gandakan nama dan ID untuk
memastikannya ditemukan dengan berbagai alat dan teknologi, seperti mouse atau pembaca layar:
<input type="checkbox" id="text-notifications" name="text-notifications">
.
:hover
, :active
, dan lainnya hadir secara gratis dengan koneksi ini, yang meningkatkan
cara formulir Anda dapat berinteraksi.
Sorotan kotak centang
Saya ingin menjaga antarmuka saya konsisten, dan elemen {i>slider <i}memiliki
sorot thumbnail yang bagus yang ingin saya gunakan dengan kotak centang. Thumbnail tersebut dapat menggunakan box-shadow
dan properti spread
-nya untuk menskalakan bayangan ke atas dan ke bawah. Namun, efek tersebut tidak berfungsi di sini karena kotak centang kita adalah, dan seharusnya, berbentuk persegi.
Saya dapat mencapai efek visual yang sama dengan elemen pseudo, dan CSS yang rumit dalam jumlah sangat sedikit:
@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 pseudo lingkaran adalah pekerjaan mudah, tetapi menempatkannya di belakang elemen yang dikaitkan lebih sulit. Ini sebelum dan setelah saya memperbaikinya:
Ini jelas merupakan interaksi mikro, namun penting bagi saya untuk menjaga
konsistensi visual. Teknik penskalaan animasinya sama seperti yang telah kita gunakan di
tempat lain. Kita menetapkan properti khusus ke nilai baru dan membiarkan CSS mentransisikannya berdasarkan preferensi gerakan. Fitur utamanya di sini adalah translateZ(-1px)
. Induk
membuat ruang 3D dan turunan elemen semu ini mengetuknya dengan
menempatkan dirinya sedikit kembali di ruang z.
Aksesibilitas
Video YouTube memberikan demonstrasi yang bagus tentang interaksi mouse, keyboard, dan pembaca layar untuk komponen setelan ini. Saya akan menyebutkan beberapa detailnya di sini.
Pilihan Elemen HTML
<form>
<header>
<fieldset>
<picture>
<label>
<input>
Masing-masing berisi petunjuk dan tips untuk alat penjelajahan pengguna. Beberapa elemen memberikan petunjuk interaksi, beberapa menghubungkan interaktivitas, dan beberapa membantu membentuk hierarki aksesibilitas yang dibuka 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 bergerak langsung dari satu penggeser ke penggeser berikutnya. Itu karena kita telah menyembunyikan ikon yang mungkin menjadi perhentian dalam perjalanan ke {i>slider<i} berikutnya. Tanpa atribut ini, pengguna harus berhenti, memproses, dan melewati gambar yang mungkin tidak dapat dilihat.
SVG adalah kumpulan matematika, mari kita tambahkan elemen <title>
untuk judul pengarahan kursor
mouse gratis dan komentar yang dapat dibaca manusia tentang apa yang dibuat oleh matematika:
<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 cukup jelas, sehingga pengujian bentuknya sangat baik di seluruh mouse, {i>keyboard<i}, pengontrol {i>video game<i}, dan pembaca layar.
JavaScript
Saya sudah membahas cara warna isian trek dikelola dari JavaScript, jadi sekarang mari kita lihat JavaScript terkait <form>
:
const form = document.querySelector('form');
form.addEventListener('input', event => {
const formData = Object.fromEntries(new FormData(form));
console.table(formData);
})
Setiap kali formulir berinteraksi dan diubah, konsol akan mencatat formulir sebagai objek ke dalam tabel agar mudah ditinjau sebelum dikirim ke server.
Kesimpulan
Sekarang Anda tahu bagaimana saya melakukannya, bagaimana Anda akan?! Inilah arsitektur komponen yang menyenangkan! Siapa yang akan membuat versi pertama dengan slot di framework favorit mereka? 🙂
Mari lakukan diversifikasi pendekatan dan pelajari semua cara untuk membangun di web. Buat demo, link tweet me, dan saya akan menambahkannya ke bagian Remix komunitas di bawah.