Browse code

Add MVP for "web terminal" with history

Joseph Weston authored on 06/11/2021 04:14:58
Showing 5 changed files
... ...
@@ -1,4 +1,6 @@
1 1
 (ns dm.db)
2 2
 
3 3
 (def default-db
4
-  {:name "re-frame"})
4
+  {:name "DMR"
5
+   :cmdline {:current ""
6
+             :history []}})
5 7
\ No newline at end of file
... ...
@@ -1,5 +1,6 @@
1 1
 (ns dm.events
2 2
   (:require
3
+   [clojure.string :refer [trim]]
3 4
    [re-frame.core :as re-frame]
4 5
    [dm.db :as db]
5 6
    [day8.re-frame.tracing :refer-macros [fn-traced]]
... ...
@@ -9,3 +10,19 @@
9 10
  ::initialize-db
10 11
  (fn-traced [_ _]
11 12
    db/default-db))
13
+
14
+(re-frame/reg-event-db
15
+ ::update-cmdline
16
+ (fn-traced [db [_ current]]
17
+  (assoc-in db [:cmdline :current] current)))
18
+
19
+(re-frame/reg-event-db
20
+ ::submit-cmd
21
+ (fn-traced [db _]
22
+  (let [cmdline (-> db (get-in [:cmdline :current]) trim)
23
+        not-empty? #(not (empty? %))]
24
+    ; TODO replace this with a "->when" macro so that we
25
+    ; don't always have to prefix with a conditional
26
+    (cond-> db
27
+     true (update-in [:cmdline :current] (constantly nil))
28
+     (not-empty? cmdline) (update-in [:cmdline :history] conj cmdline)))))
12 29
\ No newline at end of file
... ...
@@ -2,27 +2,100 @@
2 2
   (:require-macros
3 3
     [garden.def :refer [defcssfn]])
4 4
   (:require
5
-    [spade.core   :refer [defglobal defclass]]
6
-    [garden.units :refer [deg px]]
7
-    [garden.color :refer [rgba]]))
5
+    [spade.core   :refer [defglobal defclass]]))
8 6
 
9
-(defcssfn linear-gradient
10
- ([c1 p1 c2 p2]
11
-  [[c1 p1] [c2 p2]])
12
- ([dir c1 p1 c2 p2]
13
-  [dir [c1 p1] [c2 p2]]))
7
+(def gruvbox-colors
8
+  {:dark0-hard       :#1d2021
9
+   :dark0            :#282828
10
+   :dark0-soft       :#32302f
11
+   :dark1            :#3c3836
12
+   :dark2            :#504945
13
+   :dark3            :#665c54
14
+   :dark4            :#7c6f64
15
+
16
+   :gray-245         :#928374
17
+   :gray-244         :#928374
18
+
19
+   :light0-hard      :#f9f5d7
20
+   :light0           :#fbf1c7
21
+   :light0-soft      :#f2e5bc
22
+   :light1           :#ebdbb2
23
+   :light2           :#d5c4a1
24
+   :light3           :#bdae93
25
+   :light4           :#a89984
26
+
27
+   :bright-red       :#fb4934
28
+   :bright-green     :#b8bb26
29
+   :bright-yellow    :#fabd2f
30
+   :bright-blue      :#83a598
31
+   :bright-purple    :#d3869b
32
+   :bright-aqua      :#8ec07c
33
+   :bright-orange    :#fe8019
34
+
35
+   :neutral-red      :#cc241d
36
+   :neutral-green    :#98971a
37
+   :neutral-yellow   :#d79921
38
+   :neutral-blue     :#458588
39
+   :neutral-purple   :#b16286
40
+   :neutral-aqua     :#689d6a
41
+   :neutral-orange   :#d65d0e
42
+
43
+   :faded-red        :#9d0006
44
+   :faded-green      :#79740e
45
+   :faded-yellow     :#b57614
46
+   :faded-blue       :#076678
47
+   :faded-purple     :#8f3f71
48
+   :faded-aqua       :#427b58
49
+   :faded-orange     :#af3a03})
50
+
51
+; TODO: put this in an atom and put it in the appstate
52
+(def colorscheme gruvbox-colors)
53
+
54
+(defcssfn calc)
55
+
56
+(def mono-font ["Source Code Pro" "monospace"])
14 57
 
15 58
 (defglobal defaults
16 59
   [:body
17
-   {:color               :red
18
-    :background-color    :#ddd
19
-    :background-image    [(linear-gradient :white (px 2) :transparent (px 2))
20
-                          (linear-gradient (deg 90) :white (px 2) :transparent (px 2))
21
-                          (linear-gradient (rgba 255 255 255 0.3) (px 1) :transparent (px 1))
22
-                          (linear-gradient (deg 90) (rgba 255 255 255 0.3) (px 1) :transparent (px 1))]
23
-    :background-size     [[(px 100) (px 100)] [(px 100) (px 100)] [(px 20) (px 20)] [(px 20) (px 20)]]
24
-    :background-position [[(px -2) (px -2)] [(px -2) (px -2)] [(px -1) (px -1)] [(px -1) (px -1)]]}])
25
-
26
-(defclass level1
27
-  []
28
-  {:color :green})
60
+   {
61
+    :color (colorscheme :dark1)
62
+    :font-family mono-font
63
+    :font-size :100%
64
+    :line-height :1.2rem
65
+    :background-color    (colorscheme :light0-hard)
66
+   }])
67
+
68
+(defclass history-style []
69
+  {:list-style-type :none
70
+   :padding 0}
71
+  [:li
72
+   {:font-weight :bold
73
+    :background-color (colorscheme :light0-soft)
74
+    :padding-bottom :0.4rem
75
+    :margin-bottom :0.4rem}])
76
+
77
+(defclass prompt-style []
78
+  {:background-color (colorscheme :light0-soft)
79
+   :font-family mono-font
80
+   ;:font-weight :bold
81
+   :margin "1.4rem 0 0.5rem"
82
+   :padding-left :0.4rem
83
+   :position :relative
84
+   :white-space :nowrap}
85
+  [:&:before {:content "'λ '"}]
86
+  [:input
87
+   {:background :none
88
+    :border :none
89
+    :font-family mono-font
90
+    :font-weight :bold
91
+    :font-size :100%
92
+    :color (colorscheme :dark1)
93
+    :height :1.2rem
94
+    :margin-bottom 0
95
+    :margin-left 0
96
+    :margin-right 0
97
+    :margin-top 0
98
+    :padding 0
99
+    :width (calc "100% - 2ch")}
100
+   [:&:focus
101
+    {:outline :none}]])
29 102
\ No newline at end of file
... ...
@@ -6,3 +6,13 @@
6 6
  ::name
7 7
  (fn [db]
8 8
    (:name db)))
9
+
10
+(re-frame/reg-sub
11
+ ::cmdline
12
+ (fn [db]
13
+   (get-in db [:cmdline :current])))
14
+
15
+(re-frame/reg-sub
16
+ ::cmd-history
17
+ (fn [db]
18
+   (get-in db [:cmdline :history])))
... ...
@@ -3,12 +3,29 @@
3 3
    [re-frame.core :as re-frame]
4 4
    [dm.styles :as styles]
5 5
    [dm.subs :as subs]
6
-   ))
6
+   [dm.events :as events]))
7 7
 
8
-(defn main-panel []
8
+(defn prompt []
9
+  (let [cmdline (re-frame/subscribe [::subs/cmdline])
10
+        update-cmdline #(re-frame/dispatch
11
+                        [::events/update-cmdline (-> % .-target .-value)])
12
+        submit-cmd #((.preventDefault %)
13
+                     (re-frame/dispatch [::events/submit-cmd]))]
14
+  [:form {:class (styles/prompt-style)
15
+          :on-submit submit-cmd}
16
+   [:input {:value @cmdline
17
+            :on-change update-cmdline
18
+            :type "text"}]]))
19
+
20
+(defn history []
21
+  (let [history (re-frame/subscribe [::subs/cmd-history])]
22
+    (into
23
+     [:ul {:class (styles/history-style)}]
24
+     (map #(vector :li %) @history))))
25
+
26
+(defn title []
9 27
   (let [name (re-frame/subscribe [::subs/name])]
10
-    [:div
11
-     [:h1
12
-      {:class (styles/level1)}
13
-      "Hello from " @name]
14
-     ]))
28
+    [:h1 "Welcome to " @name]))
29
+
30
+(defn main-panel []
31
+  [:div (title) (history) (prompt)])
15 32
\ No newline at end of file