Blob


1 (in-package #:phos/ui)
3 (defparameter *title-1-font* "serif 22"
4 "Font for the level 1 title.")
6 (defparameter *title-2-font* "serif 19"
7 "Font for the level 2 title.")
9 (defparameter *title-3-font* "serif 16"
10 "Font for the level 3 title.")
12 (defparameter *verbatim-font* "monospace 12"
13 "Font for the verbatim element.")
15 (defparameter *item-font* "serif 12"
16 "Font for the item.")
18 (defparameter *link-font* "serif 12"
19 "Font for the links.")
21 (defparameter *paragraph-font* "serif 12"
22 "Font for the normal text")
24 (defparameter *url-bar* nil)
25 (defparameter *window-content* nil)
27 (defparameter *current-url* nil)
29 (defun join-paths (url path query)
30 (setf (quri:uri-query url) query)
31 (if (uiop:string-prefix-p "/" path)
32 (setf (quri:uri-path url) path)
33 (let ((p (quri:uri-path url)))
34 (setf (quri:uri-path url)
35 (format nil "~a~a"
36 (if (uiop:string-suffix-p "/" p)
37 p
38 (directory-namestring p))
39 path))))
40 url)
42 (defun navigate-to (uri)
43 (let ((hostname (quri:uri-host uri))
44 (path (quri:uri-path uri))
45 (query (quri:uri-query uri)))
46 (if hostname
47 (do-render uri)
48 (do-render (join-paths (quri:copy-uri *current-url*)
49 path
50 query)))))
52 (defgeneric render (obj frame)
53 (:documentation "Render OBJ in the nodgui FRAME"))
55 (defmethod render ((l list) f)
56 (dolist (el l)
57 (render el f)))
59 (defmethod render ((title gemtext:title) f)
60 (with-slots ((text phos/gemtext:text)
61 (level phos/gemtext:level))
62 title
63 (let ((w (make-instance 'label
64 :master f
65 :font (case level
66 (1 *title-1-font*)
67 (2 *title-2-font*)
68 (3 *title-3-font*))
69 :text (format nil "~v{~A~:*~} ~a" level '("#") text))))
70 (pack w :side :top :fill :both :expand t))))
72 (defmethod render ((link gemtext:link) f)
73 (with-slots ((text phos/gemtext:text)
74 (url phos/gemtext:url))
75 link
76 (let ((w (make-instance 'button
77 :master f
78 ;; :font *link-font*
79 :text (format nil "~a" (or text url))
80 :command (lambda ()
81 (navigate-to url)))))
82 (pack w :side :top :fill :both :expand t))))
84 (defmethod render ((item gemtext:item) f)
85 (with-slots ((text phos/gemtext:text)) item
86 (let ((w (make-instance 'label
87 :master f
88 :font *item-font*
89 :text (format nil "* ~a" text))))
90 (pack w :side :top :fill :both :expand t))))
92 (defmethod render ((par gemtext:paragraph) f)
93 (with-slots ((text phos/gemtext:text)) par
94 (let ((w (make-instance 'message
95 :master f
96 :font *paragraph-font*
97 :justify "left"
98 :text text
99 :width 600)))
100 ;; (setf (text w) text)
101 ;; (configure w :state "disabled")
102 (pack w :side :top :expand t :anchor "w"))))
104 (defmethod render ((v gemtext:verbatim) f)
105 (with-slots ((text phos/gemtext:text)
106 (alt phos/gemtext:alt))
108 (let ((w (make-instance 'label
109 :master f
110 :font *verbatim-font*
111 :text text)))
112 (pack w :side :top :fill :both :expand t)
113 (when alt
114 (pack (make-instance 'label
115 :master f
116 :text alt)
117 :side :top
118 :fill :both
119 :expand t)))))
121 (defun clear-window ()
122 (pack-forget-all *window-content*))
124 (defun do-render (url)
125 (let* ((uri (quri:uri url)))
126 (setf *current-url* uri)
127 (setf (text *url-bar*) url)
128 (clear-window)
129 (render (gemtext:parse-string "# loading...")
130 *window-content*)
131 (multiple-value-bind (status body) (gemini:request url)
132 (declare (ignore status))
133 (clear-window)
134 (render (gemtext:parse-string body)
135 *window-content*))))
137 (defun navigate-button-cb ()
138 (navigate-to (quri:uri (string-trim '(#\newline #\space) (text *url-bar*)))))
140 (defun main (url)
141 (with-nodgui (:title "phos")
142 (set-geometry *tk* 800 600 0 0)
143 (let* ((nav (make-instance 'frame))
144 (back-btn (make-instance 'button :text "←" :master nav))
145 (forw-btn (make-instance 'button :text "→" :master nav))
146 (go-btn (make-instance 'button :text "GO!" :master nav :command #'navigate-button-cb))
147 (url-bar (make-instance 'text :height 1 :master nav))
148 (sf (make-instance 'scrolled-frame :padding 10 :takefocus nil)))
149 (setf *url-bar* url-bar)
150 (setf *window-content* (interior sf))
151 (setf (text url-bar) "about:phos")
152 (pack nav :fill :both)
153 (pack back-btn :side :left)
154 (pack forw-btn :side :left)
155 (pack url-bar :side :left :expand t :fill :both)
156 (pack go-btn :side :left)
157 (pack sf :side :top :fill :both :expand t)
158 (do-render url))))
160 ;; (nodgui.demo:demo)
162 ;; (main "gemini://gemini.omarpolo.com/")