Kembali ke showcase

Todo App Lengkap

Aplikasi todo list production-ready dengan reaktivitas, localStorage persistence, dan input handling.

app localStorage reactive
Buka Aplikasi

Aplikasi terbuka di tab baru dengan navigasi penuh.

todo-app/index.pjs
---
judul: "Todo App Pro"
todos: ["Belajar PromptJS","Buat aplikasi pertama","Deploy ke production"]
---

Gaya:
    body
        font-family: 'Inter', system-ui, -apple-system, sans-serif
        margin: 0
        min-height: 100vh
        background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%)
        color: #e0e0e0
        display: flex
        align-items: center
        justify-content: center
        padding: 20px
    .app-container
        width: 100%
        max-width: 520px
        background: rgba(255,255,255,0.05)
        backdrop-filter: blur(20px)
        -webkit-backdrop-filter: blur(20px)
        border: 1px solid rgba(255,255,255,0.1)
        border-radius: 24px
        padding: 36px
        box-shadow: 0 25px 60px rgba(0,0,0,0.4)
    .app-header
        display: flex
        align-items: center
        justify-content: space-between
        margin-bottom: 24px
    .app-header h1
        margin: 0
        font-size: 1.5rem
        font-weight: 800
        background: linear-gradient(135deg, #7dd3fc, #d3b6e9)
        -webkit-background-clip: text
        -webkit-text-fill-color: transparent
        background-clip: text
    .badge
        font-size: 0.75rem
        font-weight: 700
        padding: 4px 12px
        border-radius: 999px
        background: rgba(134,239,172,0.15)
        color: #86efac
    .input-row
        display: flex
        gap: 8px
        margin-bottom: 24px
    .input-row input
        flex: 1
        padding: 12px 16px
        background: rgba(255,255,255,0.06)
        border: 1px solid rgba(255,255,255,0.12)
        border-radius: 12px
        color: #e0e0e0
        font-size: 0.95rem
        outline: none
        font-family: inherit
        transition: border-color 0.15s
    .input-row input:focus
        border-color: #7dd3fc
        box-shadow: 0 0 0 3px rgba(125,211,252,0.1)
    .input-row input::placeholder
        color: #475569
    .input-row button
        padding: 12px 22px
        background: linear-gradient(135deg, #7dd3fc, #4f9ef7)
        border: none
        border-radius: 12px
        color: #0f172a
        font-weight: 700
        font-size: 0.95rem
        cursor: pointer
        transition: opacity 0.15s
        font-family: inherit
        white-space: nowrap
    .input-row button:hover
        opacity: 0.9
    .task-list
        list-style: none
        padding: 0
        margin: 0 0 16px
        display: grid
        gap: 6px
    .task-item
        display: flex
        align-items: center
        gap: 10px
        padding: 12px 16px
        background: rgba(255,255,255,0.03)
        border: 1px solid rgba(255,255,255,0.05)
        border-radius: 12px
        transition: all 0.15s
    .task-item:hover
        background: rgba(255,255,255,0.06)
    .task-text
        flex: 1
        font-size: 0.95rem
        color: #e0e0e0
        word-break: break-word
    .del-btn
        background: none
        border: 1px solid rgba(239,68,68,0.2)
        color: #fca5a5
        cursor: pointer
        padding: 4px 10px
        border-radius: 8px
        font-size: 0.85rem
        transition: all 0.15s
        font-family: inherit
        flex-shrink: 0
    .del-btn:hover
        background: rgba(239,68,68,0.1)
        border-color: rgba(239,68,68,0.4)
    .footer-stats
        display: flex
        align-items: center
        justify-content: space-between
        padding-top: 16px
        border-top: 1px solid rgba(255,255,255,0.06)
    .footer-stats .summary
        font-size: 0.8rem
        color: #64748b
    .footer-stats .clear-btn
        font-size: 0.8rem
        background: none
        border: none
        color: #fca5a5
        cursor: pointer
        font-family: inherit
        opacity: 0.7
        transition: opacity 0.15s
    .footer-stats .clear-btn:hover
        opacity: 1
    .empty-state
        text-align: center
        padding: 24px
        color: #475569
        font-size: 0.9rem

Halaman TodoApp:
    data daftar = []
    data tugas = ""

    Ketika muat:
        simpan $todos ke daftar

    Buat div.app-container:
        Buat div.app-header:
            Buat h1: $judul
            Buat span.badge: "PRO"

        Buat div.input-row:
            Buat masukan#task-input:
                placeholder = "Apa yang ingin kamu kerjakan?"
                on_diketik = simpan document.querySelector("#task-input").value ke tugas
            Buat tombol#btn-tambah:
                "➕ Tambah"
                on_klik = tambahkan tugas ke daftar

        Buat daftar.task-list:
            Ulangi untuk item dari daftar:
                Buat li.task-item:
                    Buat span.task-text: item
                    Buat tombol.del-btn:
                        "✕"
                        on_klik = hapus item dari daftar

        Buat div.footer-stats:
            Buat div.summary:
                "📋 "
            Saat daftar:
                Buat span:
                    panjang(daftar)
            Buat span:
                " tugas"
            Buat tombol.clear-btn:
                "Bersihkan"
                on_klik = simpan [] ke daftar