Declarative UIs in Emacs with vui.el

News

Let's Check out vui.el

It's React.js but for Emacs UI:

https://github.com/d12frosted/vui.el

M-x package-install RET buttercup

(use-package vui
  :vc (:url "https://github.com/d12frosted/vui.el"
            :rev "v1.0.0"))

Here's the non-working code we were experimenting with:x

;;; -*- lexical-binding: t -*-
(require 'vui)

;; POMODORO UI
;; - Start timer button, potentially that changes to Cancel
;; - See the timer text on the scren (can we center it?
;; - A list of completed timers?  Maybe include cancelled?

(vui-defcomponent pomodoro-timer ()
  :state ((time-text "25:00")
          (timer-start nil)
          (timer-end nil)
          (button-label "Start")
          (timer-history '()))
  :render
  (progn
    (vui-set-state :timer-start (current-time))
    (vui-set-state :timer-end (time-add (current-time) (* 25 60)))

    (vui-use-effect ()
      ;; Setup: start timer (use vui-with-async-context for callback)
      ;; Use #'1+ functional update to avoid stale closure capture
      (let ((timer (run-with-timer
                    1 1
                    (vui-with-async-context
                     (message "Delta is: %s"
                              (format-time-string "%M:%S"
                                                        (time-subtract timer-end
                                                                       (current-time))))

                     (vui-set-state :time-text
                                    (format-time-string "%M:%S"
                                                        (time-subtract timer-end
                                                                       (current-time))))))))
        ;; Cleanup: cancel timer
        (lambda ()
          (cancel-timer timer))))

    (vui-fragment
     (vui-newline)
     (vui-newline)
     (vui-text time-text :face '(nil :foreground red))
     (vui-newline)
     (vui-newline)
     (vui-button button-label
       :on-click (lambda ()
                   (if timer-start
                       (progn
                         ;; TODO: Cancel the existing timer
                         (vui-set-state :timer-start nil)
                         (vui-set-state :time-text "25:00"))
                     (vui-set-state :timer-start (current-time))))))))

;; Mount it
(vui-mount (vui-component 'pomodoro-timer))

Enjoyed this stream? Explore our hands-on courses for deeper, structured learning on Guile Scheme and more.

Get the System Crafters Newsletter
Updates on open source tools, tutorials, and community projects. We'll also occasionally let you know about new courses and resources.
Name (optional)
Email Address