(defisland
  ()
  (let
    ((next-id (signal 1))
      (items (signal (list)))
      (add-item
        (fn
          (e)
          (batch
            (fn
              ()
              (swap!
                items
                (fn
                  (old)
                  (append
                    old
                    (dict
                      "id"
                      (deref next-id)
                      "text"
                      (str "Item " (deref next-id))))))
              (swap! next-id inc)))))
      (remove-item
        (fn
          (id)
          (swap!
            items
            (fn
              (old)
              (filter (fn (item) (not (= (get item "id") id))) old))))))
    (div
      (~tw :tokens "rounded border border-violet-200 bg-violet-50 p-4 my-4")
      (div
        (~tw :tokens "flex items-center gap-3 mb-3")
        (button
          (~tw :tokens "px-3 py-1 rounded bg-violet-600 text-white text-sm font-medium hover:bg-violet-700")
          :on-click add-item
          "Add Item")
        (span
          (~tw :tokens "text-sm text-stone-500")
          (deref (computed (fn () (len (deref items)))))
          " items"))
      (ul
        (~tw :tokens "space-y-1")
        (map
          (fn
            (item)
            (li
              :key (str (get item "id"))
              (~tw :tokens "flex items-center justify-between bg-white rounded px-3 py-2 text-sm")
              (span (get item "text"))
              (button
                (~tw :tokens "text-stone-400 hover:text-red-500 text-xs")
                :on-click (fn (e) (remove-item (get item "id")))
                "✕")))
          (deref items))))))
