← Semua tutor

Hasil akhir · harga yang bisa dimainkan

Harga diam jadi bisa dicoba.

Sebelum · harga statis

Sesudah · toggle dari asset.inwebsite.online

Coba sendiri ↗

Dua web yang sama, bedanya satu snippet. Di kanan, pengunjung menekan Cicil 3× dan harga tiap paket bergulir ke nominal per cicilan, lengkap dengan total aslinya.

Langkah 1 · Siapkan dulu

Yang perlu ada sebelum mulai.

  • Editor kode apa saja. VS Code, Cursor, atau yang kamu biasa pakai.
  • Node.js dan proyek React. Snippet berjalan di React dan memakai kelas Tailwind CSS.
  • AI agent (opsional, tapi paling cepat). Di panduan ini contohnya Claude Code.
  • Akun InWebAsset. Mencari dan merencanakan gratis tanpa login, tapi kode hanya bisa diambil setelah login.
Perlu loginTanpa login kamu bisa menjelajah, melihat pratinjau, dan memakai MCP untuk mencari. Tombol Copy kode dan API key MCP baru bisa dipakai setelah Sign in.
Batas harian: 5 salinanAkun gratis boleh menyalin kode snippet 5 kali sehari. Setiap salinan dihitung, termasuk snippet yang pernah kamu salin, dan kuotanya dipakai bersama antara situs dan MCP. Akun Pro tanpa batas.

Mencari, melihat pratinjau, dan perencanaan lewat agent tidak memakai kuota.

Langkah 2 · Jelajahi katalog

Pilih desain yang mau diambil.

Buka asset.inwebsite.online. Katalognya berisi 172 snippet. Persempit lewat kategori, tempat pemakaian, atau kata kunci.

  • Pilih kategori Cards & Sections.
  • Di Where it goes, pilih Pricing.
  • Ketik pricing di kolom cari untuk mempersempit.
  • Arahkan kursor ke kartu untuk melihat pratinjau bergerak, lalu klik Pricing Toggle Cards.
REKAMAN · KATALOG
REKAMAN · HALAMAN SNIPPET

Langkah 3 · Buka halaman snippet

Lihat dulu, baru ambil.

  • Tab Preview: tekan Monthly/Yearly di pratinjau. Angka bergulir per digit dan badge Save muncul.
  • Tab Code: sebelum login, kodenya terkunci. Muncul tombol Sign in to copy.
  • Install: npm i gsap @gsap/react. Syaratnya React + Tailwind CSS.
  • Assets in this snippet: badge flat-sale-burst dipakai langsung dari URL-nya, bisa ditukar dengan badge lain dari keluarga yang sama.
  • For agents: ada tombol Copy prompt dan tautan registry untuk AI agent.
IngatUntuk menyalin kode kamu harus login, dan akun gratis dibatasi 5 salinan per hari.

Langkah 4 · Ambil kodenya

Dua jalur, pilih satu.

JALUR A · LEBIH CEPATPakai MCP lewat AI agent

Agent mencari, memilih, dan memasang snippet sendiri. Buka halaman For agents, login, buat API key, lalu salin perintahnya.

$claude mcp add --transport http InWebAsset https://asset.inwebsite.online/mcp --header "Authorization: Bearer <API key-mu>"

Perintah di atas untuk Claude Code. Halaman itu juga punya versi Claude Desktop, Cursor, dan VS Code. Jangan pernah membagikan API key-mu.

Mencari dan perencanaan tanpa kunci. Kodenya (get_snippet) baru keluar dengan API key, dan memakai jatah 5 salinan akun gratis.

JALUR B · MANUALSalin source code

Login, buka halaman snippet, tekan Copy di tab Code. Simpan sebagai komponen, lalu pasang sendiri atau kirim ke agent.

$ npm i gsap @gsap/react

Simpan sebagai components/PricingToggleCards.jsx. Tiap Copy memakai 1 dari 5 jatah harian akun gratis.

REKAMAN · HALAMAN FOR AGENTS

Langkah 5 · Beri konteks ke agent

Bilang apa yang harus berubah.

Snippet ini aslinya Monthly/Yearly dengan harga dolar. Web contohnya studio branding yang menjual paket proyek, jadi agent perlu tahu datanya, cara bayarnya, dan warnanya. Tanpa itu, kamu dapat tabel langganan dolar.

Bagian web section #paketFile Packages.jsxData PACKAGES di data.jsToggle Lunas / Cicil 3×Warna #e8461eStack React + CSS biasa
Kalau pakai Jalur B: tempel kodenya setelah prompt ini
Ini kode komponen dari asset.inwebsite.online. Pasang di section #paket (src/sections/Packages.jsx) menggantikan tiga kartu harga yang ada. Ambil data dari PACKAGES di src/data.js (harga dalam juta rupiah). Ganti toggle Monthly/Yearly jadi "Bayar lunas" / "Cicil 3×": harga cicilan = total dibagi 3, satu angka desimal, dan tulis totalnya di bawah. Proyek saya React + CSS biasa tanpa Tailwind: pasang Tailwind v4 tanpa preflight supaya gaya lama tidak berubah. Aksen #e8461e, ease tenang (power3.out). Tombol paket tetap memanggil onPick lalu turun ke #kontak.

<tempel kode di sini>
contoh · Claude Code (Jalur A)
# sekali saja: sambungkan MCP
$ claude mcp add --transport http InWebAsset https://asset.inwebsite.online/mcp --header "Authorization: Bearer <API key-mu>"

# masuk ke folder proyek, jalankan agent
$ claude

> Pakai InWebAsset MCP. Ambil snippet cards-sections/pricing-toggle-cards dan pasang di section #paket (src/sections/Packages.jsx) menggantikan tiga kartu harga yang ada. Data dari PACKAGES di src/data.js (harga dalam juta rupiah). Ganti toggle Monthly/Yearly jadi "Bayar lunas" / "Cicil 3×": harga per cicilan = total dibagi 3, satu desimal, total ditulis di bawahnya. Proyek saya React + CSS biasa tanpa Tailwind, jadi pasang Tailwind v4 tanpa preflight. Kirim look situs (terang, aksen #e8461e, sudut bulat, gerak tenang) ke get_snippet supaya dapat daftar penyesuaian. Cek dulu dengan includeCode:false, lalu ambil kodenya sekali. Jangan ubah bagian lain.

Yang kamu dapat

Snippet itu titik awal.

Kode di kanan adalah komponen yang terpasang di web contoh. Ini yang diubah dari versi asli di katalog:

  • Monthly/Yearlyjadi Bayar lunas / Cicil 3×. Harga kedua = total ÷ 3, bukan diskon tahunan.
  • SLOTSditambah koma, supaya angka seperti 9,3 ikut bergulir per digit.
  • $ · /mojadi Rp dan jt / cicilan. Total asli ditulis di bawah harga cicilan.
  • warnabiru, ungu, dan kuning diganti aksen situs #e8461e; glow berputar ikut aksen.
  • easeback dan elastic diganti power3.out, sesuai saran "Fit this site" dari get_snippet.
  • Tailwindweb contoh tidak memakai Tailwind. Dipasang v4 tanpa preflight (hanya theme + utilities) agar gaya lama tetap.
  • tombolmemanggil onPick lalu turun ke form kontak, seperti tombol lamanya.
components/PricingToggleCards.jsx · terpasang di web contoh
/*
 * Pricing Toggle Cards — diadaptasi untuk Tandarupa
 * Asal: https://asset.inwebsite.online/snippets/cards-sections/pricing-toggle-cards (v1.0.1)
 * Perubahan: Monthly/Yearly → Lunas/Cicil 3×, harga Rupiah (juta), warna aksen #e8461e,
 * ease back/elastic → power3.out, tombol memilih paket lalu turun ke form kontak.
 */
import { useEffect, useRef, useState } from 'react'
import gsap from 'gsap'
import { useGSAP } from '@gsap/react'

gsap.registerPlugin(useGSAP)

const BADGE = 'https://inassetweb-cdn.inwebsite.online/sprinkles/v1/badges/flat-sale-burst.png'
const SLOTS = [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',']
const GLOW = 'conic-gradient(from 0deg, #e8461e, #ff9a6b, #141311, #e8461e, #ffc4a8, #e8461e)'
const ACCENT = '#e8461e'

// 9.3 → "9,3", 4 → "4"
const fmt = (n) => (Number.isInteger(n) ? String(n) : n.toFixed(1).replace('.', ','))

function reelColumns(a, b) {
  const width = Math.max(a.length, b.length)
  const pa = a.padStart(width, ' ')
  const pb = b.padStart(width, ' ')
  return Array.from({ length: width }, (_, i) => ({ a: SLOTS.indexOf(pa[i]), b: SLOTS.indexOf(pb[i]), fromRight: width - 1 - i }))
}

function Check() {
  return (
    <svg viewBox="0 0 16 16" aria-hidden className="mt-0.5 size-3.5 shrink-0">
      <circle cx="8" cy="8" r="8" className="fill-current opacity-15" />
      <path d="M4.6 8.3l2.2 2.1 4.6-4.8" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  )
}

export default function PricingToggleCards({ plans, onPick }) {
  const root = useRef(null)
  const mounted = useRef(false)
  const wobble = useRef(null)
  const [cicil, setCicil] = useState(false)

  const priced = plans.map((p) => {
    const per = Math.round((p.total / 3) * 10) / 10
    return { ...p, per, columns: reelColumns(fmt(p.total), fmt(per)) }
  })

  // Masuk + bingkai glow yang berputar pelan
  useGSAP(
    () => {
      gsap.set('.ptc-spin', { xPercent: -50, yPercent: -50 })
      gsap.from('.ptc-card', { y: 28, autoAlpha: 0, duration: 0.7, ease: 'power3.out', stagger: 0.08 })
      gsap.to('.ptc-spin', { rotation: 360, duration: 6, ease: 'none', repeat: -1 })
    },
    { scope: root },
  )

  // Tiap ganti cara bayar: angka bergulir, thumb bergeser, badge muncul
  useGSAP(
    (context) => {
      const instant = !mounted.current
      mounted.current = true
      const q = gsap.utils.selector(root)
      context.ignore(() => {
        q('.ptc-price').forEach((price, plan) => {
          price.querySelectorAll('.ptc-col').forEach((col) => {
            const index = Number(cicil ? col.dataset.b : col.dataset.a)
            const reel = col.firstElementChild
            const reelVars = { yPercent: (-index * 100) / SLOTS.length }
            const colVars = { width: index === 0 ? 0 : SLOTS[index] === ',' ? '0.28em' : '0.6em' }
            if (instant) {
              gsap.set(reel, reelVars)
              gsap.set(col, colVars)
              return
            }
            const delay = Number(col.dataset.r) * 0.07 + plan * 0.06
            gsap.to(reel, { ...reelVars, duration: 0.85, ease: 'power3.out', delay, overwrite: true })
            gsap.to(col, { ...colVars, duration: 0.5, ease: 'power3.inOut', delay, overwrite: true })
          })
        })

        const active = q(`[data-ptc-seg="${cicil ? 'cicil' : 'lunas'}"]`)[0]
        if (active) {
          const vars = { x: active.offsetLeft, width: active.offsetWidth }
          if (instant) gsap.set(q('.ptc-thumb'), vars)
          else gsap.to(q('.ptc-thumb'), { ...vars, duration: 0.55, ease: 'power3.out', overwrite: 'auto' })
        }

        wobble.current?.kill()
        if (cicil) {
          if (instant) gsap.set(q('.ptc-badge'), { scale: 1, rotation: -12, autoAlpha: 1 })
          else {
            gsap.fromTo(q('.ptc-badge'), { scale: 0, rotation: -70, autoAlpha: 1 }, { scale: 1, rotation: -12, duration: 0.7, ease: 'power3.out', overwrite: true })
            wobble.current = gsap.to(q('.ptc-badge'), { rotation: -4, scale: 1.05, duration: 0.8, ease: 'power2.inOut', yoyo: true, repeat: -1, delay: 0.7 })
          }
        } else if (instant) gsap.set(q('.ptc-badge'), { scale: 0, autoAlpha: 0 })
        else gsap.to(q('.ptc-badge'), { scale: 0, rotation: 25, autoAlpha: 0, duration: 0.3, ease: 'power2.in', overwrite: true })

        if (!instant) gsap.fromTo(q('.ptc-note'), { y: 6, autoAlpha: 0 }, { y: 0, autoAlpha: 1, duration: 0.4, delay: 0.15, stagger: 0.05 })
      })
    },
    { scope: root, dependencies: [cicil, plans], revertOnUpdate: false },
  )

  useEffect(
    () => () => {
      wobble.current?.kill()
      mounted.current = false
    },
    [],
  )

  const segment = 'relative z-10 cursor-pointer rounded-full border-0 bg-transparent px-5 py-2.5 text-[15px] font-semibold transition-colors focus-visible:outline-none'

  return (
    <div ref={root} className="mx-auto w-full max-w-[1440px] text-[#141311]">
      <div className="mb-8 flex justify-center pt-4">
        <div role="group" aria-label="Cara bayar" className="relative flex rounded-full bg-white p-1 shadow-sm ring-1 ring-black/10">
          <span aria-hidden className="ptc-thumb absolute top-1 bottom-1 left-0 rounded-full bg-[#141311] shadow-md" />
          <button type="button" data-ptc-seg="lunas" aria-pressed={!cicil} onClick={() => setCicil(false)} className={`${segment} ${cicil ? 'text-[#5b5750]' : 'text-[#f1ede4]'}`}>
            Bayar lunas
          </button>
          <button type="button" data-ptc-seg="cicil" aria-pressed={cicil} onClick={() => setCicil(true)} className={`${segment} ${cicil ? 'text-[#f1ede4]' : 'text-[#5b5750]'}`}>
            Cicil 3×
          </button>
          <span aria-hidden className="ptc-badge pointer-events-none invisible absolute -top-7 -right-10 grid size-[68px] place-items-center">
            <img src={BADGE} alt="" className="absolute inset-0 size-full drop-shadow-md" />
            <span className="relative text-center leading-none font-black text-white">
              <span className="block text-[8px] tracking-[0.18em]">CICIL</span>
              <span className="block text-[17px]">3×</span>
            </span>
          </span>
        </div>
      </div>

      <div className="grid gap-4 md:grid-cols-3">
        {priced.map((plan) => {
          const body = (
            <div className={`relative flex h-full flex-col gap-3 rounded-[22px] p-6 md:p-7 ${plan.featured ? 'bg-[#141311] text-[#f1ede4]' : 'bg-white/60 ring-1 ring-black/10'}`}>
              <div>
                <div className="flex items-center gap-2">
                  <h3 className="m-0 text-[26px] font-bold tracking-[-0.03em]">{plan.name}</h3>
                  {plan.featured && <span className="rounded-full px-2 py-0.5 text-[10px] font-semibold tracking-wide text-white uppercase" style={{ background: ACCENT }}>Terlaris</span>}
                </div>
                <p className="m-0 mt-1 min-h-[3em] text-[15px] opacity-65">{plan.for}</p>
              </div>

              <div className="mt-2">
                <div className="flex items-end gap-1">
                  <span className="mb-auto pt-1 text-lg font-semibold opacity-80">Rp</span>
                  <span aria-hidden className="ptc-price flex text-[56px] leading-none font-extrabold tracking-tight tabular-nums">
                    {plan.columns.map((c, i) => (
                      <span key={i} data-a={c.a} data-b={c.b} data-r={c.fromRight} className="ptc-col relative block h-[1em] w-[0.6em] overflow-hidden">
                        <span className="block">
                          {SLOTS.map((s, si) => (
                            <span key={si} className="block h-[1em] text-center">{s}</span>
                          ))}
                        </span>
                      </span>
                    ))}
                  </span>
                  <span className="sr-only">Rp {cicil ? fmt(plan.per) : fmt(plan.total)} juta</span>
                  <span className="mb-1.5 ml-1 text-sm font-semibold opacity-70">jt{cicil ? ' / cicilan' : ''}</span>
                </div>
                <p className="m-0 mt-2 h-5 text-[13px] opacity-60">
                  <span className="ptc-note inline-block">{cicil ? `3× cicilan · total Rp ${fmt(plan.total)} jt` : `dibayar sekali · ± ${plan.time}`}</span>
                </p>
              </div>

              <ul className="m-0 mt-3 flex-1 list-none space-y-2.5 p-0 text-[15px]">
                {plan.items.map((f) => (
                  <li key={f} className={`flex gap-2 ${plan.featured ? 'text-white/85' : 'opacity-85'}`}>
                    <span style={{ color: ACCENT }}><Check /></span>
                    {f}
                  </li>
                ))}
              </ul>

              <button
                type="button"
                onClick={() => onPick?.(plan.name)}
                className={`mt-4 min-h-[48px] cursor-pointer rounded-full border-0 px-5 text-[15px] font-semibold transition-transform hover:-translate-y-0.5 ${plan.featured ? 'text-white' : 'bg-[#141311] text-[#f1ede4]'}`}
                style={plan.featured ? { background: ACCENT } : undefined}
              >
                Pilih {plan.name}
              </button>
            </div>
          )

          return plan.featured ? (
            <div key={plan.name} className="ptc-card relative">
              <div aria-hidden className="absolute -inset-1 overflow-hidden rounded-[28px] opacity-50 blur-xl">
                <span className="ptc-spin absolute top-1/2 left-1/2 aspect-square w-[220%]" style={{ background: GLOW }} />
              </div>
              <div className="relative h-full overflow-hidden rounded-[24px] p-[2px]">
                <span aria-hidden className="ptc-spin absolute top-1/2 left-1/2 aspect-square w-[220%]" style={{ background: GLOW }} />
                {body}
              </div>
            </div>
          ) : (
            <div key={plan.name} className="ptc-card relative">{body}</div>
          )
        })}
      </div>
    </div>
  )
}

Langkah 6 · Bandingkan

Sebelum vs sesudah.

Sebelum

Sesudah

Di layar lebar, kartu kanan hidup: tekan Bayar lunas / Cicil 3× di dalamnya. Di HP, kartu menampilkan rekamannya.

01 · SIAPKANEditor, React, agent, akun (login)
02 · JELAJAHCards & Sections → Pricing
03 · BUKAPratinjau, install, kode (login)
04 · PASANGBeri data, cara bayar, dan warna ke agent