Browse code

Initial commit

Joseph Weston authored on 05/11/2021 02:41:53
Showing 15 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,20 @@
1
+{:lint-as {day8.re-frame.tracing/defn-traced clojure.core/defn
2
+           day8.re-frame.tracing/fn-traced clojure.core/fn
3
+           garden.def/defcssfn clojure.core/def
4
+           garden.def/defkeyframes clojure.core/def
5
+           garden.def/defrule clojure.core/def
6
+           garden.def/defstyles clojure.core/def
7
+           garden.def/defstylesheet clojure.core/def}
8
+ :linters {:unresolved-symbol {:exclude [goog.DEBUG]}
9
+           :unused-namespace {:exclude [cljs.repl]}
10
+           :unused-referred-var {:exclude {cljs.repl [Error->map
11
+                                                      apropos
12
+                                                      dir
13
+                                                      doc
14
+                                                      error->str
15
+                                                      ex-str
16
+                                                      ex-triage
17
+                                                      find-doc
18
+                                                      print-doc
19
+                                                      pst
20
+                                                      source]}}}}
0 21
new file mode 100644
... ...
@@ -0,0 +1,19 @@
1
+/out/
2
+/resources/public/js/compiled/
3
+/target/
4
+/*-init.clj
5
+/*.log
6
+.lsp/*
7
+
8
+# Leiningen
9
+/.lein-*
10
+/.nrepl-port
11
+
12
+# Node.js dependencies
13
+/node_modules/
14
+
15
+# shadow-cljs cache, port files
16
+/.shadow-cljs/
17
+
18
+# clj-kondo cache
19
+/.clj-kondo/.cache
0 20
new file mode 100644
... ...
@@ -0,0 +1,229 @@
1
+# dm
2
+A web shell for dungeon masters.
3
+Inspired by https://initiative.sh
4
+
5
+### Dice notation
6
+https://sophiehoulden.com/dice/documentation/notation.html
7
+
8
+## Getting Started
9
+
10
+### Project Overview
11
+
12
+* Architecture:
13
+[Single Page Application (SPA)](https://en.wikipedia.org/wiki/Single-page_application)
14
+* Languages
15
+  - Front end is [ClojureScript](https://clojurescript.org/) with ([re-frame](https://github.com/day8/re-frame))
16
+  - CSS compilation is [Garden](https://github.com/noprompt/garden) with [Spade](https://github.com/dhleong/spade)
17
+* Dependencies
18
+  - UI framework: [re-frame](https://github.com/day8/re-frame)
19
+  ([docs](https://github.com/day8/re-frame/blob/master/docs/README.md),
20
+  [FAQs](https://github.com/day8/re-frame/blob/master/docs/FAQs/README.md)) ->
21
+  [Reagent](https://github.com/reagent-project/reagent) ->
22
+  [React](https://github.com/facebook/react)
23
+  - CSS rendering: [Garden](https://github.com/noprompt/garden)
24
+* Build tools
25
+  - CLJS compilation, dependency management, REPL, & hot reload: [`shadow-cljs`](https://github.com/thheller/shadow-cljs)
26
+* Development tools
27
+  - Debugging: [CLJS DevTools](https://github.com/binaryage/cljs-devtools),
28
+  [`re-frame-10x`](https://github.com/day8/re-frame-10x)
29
+  - Emacs integration: [CIDER](https://github.com/clojure-emacs/cider)
30
+  - Linter: [clj-kondo](https://github.com/borkdude/clj-kondo)
31
+
32
+#### Directory structure
33
+
34
+* [`/`](/../../): project config files
35
+* [`.clj-kondo/`](.clj-kondo/): lint config and cache files (cache files are not tracked; see
36
+[`.gitignore`](.gitignore))
37
+* [`dev/`](dev/): source files compiled only with the [dev](#running-the-app) profile
38
+  - [`user.cljs`](dev/cljs/user.cljs): symbols for use during development in the
39
+[ClojureScript REPL](#connecting-to-the-browser-repl-from-a-terminal)
40
+* [`resources/public/`](resources/public/): SPA root directory;
41
+[dev](#running-the-app) / [prod](#production) profile depends on the most recent build
42
+  - [`index.html`](resources/public/index.html): SPA home page
43
+    - Dynamic SPA content rendered in the following `div`:
44
+        ```html
45
+        <div id="app"></div>
46
+        ```
47
+    - Customizable; add headers, footers, links to other scripts and styles, etc.
48
+  - Generated directories and files
49
+    - Created on build with either the [dev](#running-the-app) or [prod](#production) profile
50
+    - `js/compiled/`: compiled CLJS (`shadow-cljs`)
51
+      - Not tracked in source control; see [`.gitignore`](.gitignore)
52
+* [`src/dm/styles.cljs`](src/dm/styles.cljs): CSS compilation source file (ClojureScript,
53
+[Garden](https://github.com/noprompt/garden))
54
+* [`src/dm/`](src/dm/): SPA source files (ClojureScript,
55
+[re-frame](https://github.com/Day8/re-frame))
56
+  - [`core.cljs`](src/dm/core.cljs): contains the SPA entry point, `init`
57
+* [`.github/workflows/`](.github/workflows/): contains the
58
+[github actions](https://github.com/features/actions) pipelines.
59
+  - [`test.yaml`](.github/workflows/test.yaml): Pipeline for testing.
60
+
61
+
62
+### Editor/IDE
63
+
64
+Use your preferred editor or IDE that supports Clojure/ClojureScript development. See
65
+[Clojure tools](https://clojure.org/community/resources#_clojure_tools) for some popular options.
66
+
67
+### Environment Setup
68
+
69
+1. Install [JDK 8 or later](https://openjdk.java.net/install/) (Java Development Kit)
70
+2. Install [Node.js](https://nodejs.org/) (JavaScript runtime environment) which should include
71
+   [NPM](https://docs.npmjs.com/cli/npm) or if your Node.js installation does not include NPM also install it.
72
+4. Install [clj-kondo](https://github.com/borkdude/clj-kondo/blob/master/doc/install.md) (linter)
73
+5. Clone this repo and open a terminal in the `dm` project root directory
74
+6. (Optional) Setup [lint cache](https://github.com/borkdude/clj-kondo#project-setup):
75
+    ```sh
76
+    clj-kondo --lint "$(npx shadow-cljs classpath)"
77
+    ```
78
+7. Setup
79
+[linting in your editor](https://github.com/borkdude/clj-kondo/blob/master/doc/editor-integration.md)
80
+
81
+### Browser Setup
82
+
83
+Browser caching should be disabled when developer tools are open to prevent interference with
84
+[`shadow-cljs`](https://github.com/thheller/shadow-cljs) hot reloading.
85
+
86
+Custom formatters must be enabled in the browser before
87
+[CLJS DevTools](https://github.com/binaryage/cljs-devtools) can display ClojureScript data in the
88
+console in a more readable way.
89
+
90
+#### Chrome/Chromium
91
+
92
+1. Open [DevTools](https://developers.google.com/web/tools/chrome-devtools/) (Linux/Windows: `F12`
93
+or `Ctrl-Shift-I`; macOS: `⌘-Option-I`)
94
+2. Open DevTools Settings (Linux/Windows: `?` or `F1`; macOS: `?` or `Fn+F1`)
95
+3. Select `Preferences` in the navigation menu on the left, if it is not already selected
96
+4. Under the `Network` heading, enable the `Disable cache (while DevTools is open)` option
97
+5. Under the `Console` heading, enable the `Enable custom formatters` option
98
+
99
+#### Firefox
100
+
101
+1. Open [Developer Tools](https://developer.mozilla.org/en-US/docs/Tools) (Linux/Windows: `F12` or
102
+`Ctrl-Shift-I`; macOS: `⌘-Option-I`)
103
+2. Open [Developer Tools Settings](https://developer.mozilla.org/en-US/docs/Tools/Settings)
104
+(Linux/macOS/Windows: `F1`)
105
+3. Under the `Advanced settings` heading, enable the `Disable HTTP Cache (when toolbox is open)`
106
+option
107
+
108
+Unfortunately, Firefox does not yet support custom formatters in their devtools. For updates, follow
109
+the enhancement request in their bug tracker:
110
+[1262914 - Add support for Custom Formatters in devtools](https://bugzilla.mozilla.org/show_bug.cgi?id=1262914).
111
+
112
+## Development
113
+
114
+### Running the App
115
+
116
+Start a temporary local web server, build the app with the `dev` profile, and serve the app,
117
+browser test runner and karma test runner with hot reload:
118
+
119
+```sh
120
+npm install
121
+npx shadow-cljs watch app
122
+```
123
+
124
+Please be patient; it may take over 20 seconds to see any output, and over 40 seconds to complete.
125
+
126
+When `[:app] Build completed` appears in the output, browse to
127
+[http://localhost:8280/](http://localhost:8280/).
128
+
129
+[`shadow-cljs`](https://github.com/thheller/shadow-cljs) will automatically push ClojureScript code
130
+changes to your browser on save. To prevent a few common issues, see
131
+[Hot Reload in ClojureScript: Things to avoid](https://code.thheller.com/blog/shadow-cljs/2019/08/25/hot-reload-in-clojurescript.html#things-to-avoid).
132
+
133
+Opening the app in your browser starts a
134
+[ClojureScript browser REPL](https://clojurescript.org/reference/repl#using-the-browser-as-an-evaluation-environment),
135
+to which you may now connect.
136
+
137
+#### Connecting to the browser REPL from Emacs with CIDER
138
+
139
+Connect to the browser REPL:
140
+```
141
+M-x cider-jack-in-cljs
142
+```
143
+
144
+See
145
+[Shadow CLJS User's Guide: Emacs/CIDER](https://shadow-cljs.github.io/docs/UsersGuide.html#cider)
146
+for more information. Note that the mentioned [`.dir-locals.el`](.dir-locals.el) file has already
147
+been created for you.
148
+
149
+#### Connecting to the browser REPL from VS Code with Calva
150
+
151
+See the [re-frame-template README](https://github.com/day8/re-frame-template) for [Calva](https://github.com/BetterThanTomorrow/calva) instuctions. See also https://calva.io for Calva documentation.
152
+
153
+
154
+#### Connecting to the browser REPL from other editors
155
+
156
+See
157
+[Shadow CLJS User's Guide: Editor Integration](https://shadow-cljs.github.io/docs/UsersGuide.html#_editor_integration).
158
+Note that `npm run watch` runs `npx shadow-cljs watch` for you, and that this project's running build ids is
159
+`app`, `browser-test`, `karma-test`, or the keywords `:app`, `:browser-test`, `:karma-test` in a Clojure context.
160
+
161
+Alternatively, search the web for info on connecting to a `shadow-cljs` ClojureScript browser REPL
162
+from your editor and configuration.
163
+
164
+For example, in Vim / Neovim with `fireplace.vim`
165
+1. Open a `.cljs` file in the project to activate `fireplace.vim`
166
+2. In normal mode, execute the `Piggieback` command with this project's running build id, `:app`:
167
+    ```vim
168
+    :Piggieback :app
169
+    ```
170
+
171
+#### Connecting to the browser REPL from a terminal
172
+
173
+1. Connect to the `shadow-cljs` nREPL:
174
+    ```sh
175
+    lein repl :connect localhost:8777
176
+    ```
177
+    The REPL prompt, `shadow.user=>`, indicates that is a Clojure REPL, not ClojureScript.
178
+
179
+2. In the REPL, switch the session to this project's running build id, `:app`:
180
+    ```clj
181
+    (shadow.cljs.devtools.api/nrepl-select :app)
182
+    ```
183
+    The REPL prompt changes to `cljs.user=>`, indicating that this is now a ClojureScript REPL.
184
+3. See [`user.cljs`](dev/cljs/user.cljs) for symbols that are immediately accessible in the REPL
185
+without needing to `require`.
186
+
187
+### Running `shadow-cljs` Actions
188
+
189
+See a list of [`shadow-cljs CLI`](https://shadow-cljs.github.io/docs/UsersGuide.html#_command_line)
190
+actions:
191
+```sh
192
+npx shadow-cljs --help
193
+```
194
+
195
+Please be patient; it may take over 10 seconds to see any output. Also note that some actions shown
196
+may not actually be supported, outputting "Unknown action." when run.
197
+
198
+Run a shadow-cljs action on this project's build id (without the colon, just `app`):
199
+```sh
200
+npx shadow-cljs <action> app
201
+```
202
+### Debug Logging
203
+
204
+The `debug?` variable in [`config.cljs`](src/cljs/dm/config.cljs) defaults to `true` in
205
+[`dev`](#running-the-app) builds, and `false` in [`prod`](#production) builds.
206
+
207
+Use `debug?` for logging or other tasks that should run only on `dev` builds:
208
+
209
+```clj
210
+(ns dm.example
211
+  (:require [dm.config :as config])
212
+
213
+(when config/debug?
214
+  (println "This message will appear in the browser console only on dev builds."))
215
+```
216
+
217
+## Production
218
+
219
+Build the app with the `prod` profile:
220
+
221
+```sh
222
+npm install
223
+npm run release
224
+```
225
+
226
+Please be patient; it may take over 15 seconds to see any output, and over 30 seconds to complete.
227
+
228
+The `resources/public/js/compiled` directory is created, containing the compiled `app.js` and
229
+`manifest.edn` files.
0 230
new file mode 100644
... ...
@@ -0,0 +1,11 @@
1
+(ns cljs.user
2
+  "Commonly used symbols for easy access in the ClojureScript REPL during
3
+  development."
4
+  (:require
5
+    [cljs.repl :refer (Error->map apropos dir doc error->str ex-str ex-triage
6
+                       find-doc print-doc pst source)]
7
+    [clojure.pprint :refer (pprint)]
8
+    [clojure.string :as str]))
9
+
10
+(comment
11
+  (pprint (str/trim "This line suppresses some clj-kondo warnings.")))
0 12
new file mode 100644
... ...
@@ -0,0 +1,27 @@
1
+module.exports = function (config) {
2
+  var junitOutputDir = process.env.CIRCLE_TEST_REPORTS || "target/junit"
3
+
4
+  config.set({
5
+    browsers: ['ChromeHeadless'],
6
+    basePath: 'target',
7
+    files: ['karma-test.js'],
8
+    frameworks: ['cljs-test'],
9
+    plugins: [
10
+        'karma-cljs-test',
11
+        'karma-chrome-launcher',
12
+        'karma-junit-reporter'
13
+    ],
14
+    colors: true,
15
+    logLevel: config.LOG_INFO,
16
+    client: {
17
+      args: ['shadow.test.karma.init']
18
+    },
19
+
20
+    // the default configuration
21
+    junitReporter: {
22
+      outputDir: junitOutputDir + '/karma', // results will be saved as outputDir/browserName.xml
23
+      outputFile: undefined, // if included, results will be saved as outputDir/browserName/outputFile
24
+      suite: '' // suite will become the package name attribute in xml testsuite element
25
+    }
26
+  })
27
+}
0 28
new file mode 100644
... ...
@@ -0,0 +1,16 @@
1
+{
2
+	"name": "dm",
3
+	"scripts": {
4
+		"ancient": "clojure -Sdeps '{:deps {com.github.liquidz/antq {:mvn/version \"RELEASE\"}}}' -m antq.core",
5
+		"watch": "npx shadow-cljs watch app browser-test karma-test",
6
+		"release": "npx shadow-cljs release app",
7
+		"build-report": "npx shadow-cljs run shadow.cljs.build-report app target/build-report.html"
8
+	},
9
+	"dependencies": {
10
+		"react": "17.0.2",
11
+		"react-dom": "17.0.2"
12
+	},
13
+	"devDependencies": {
14
+		"shadow-cljs": "2.15.2"
15
+	}
16
+}
0 17
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset='utf-8'>
5
+    <meta name="viewport" content="width=device-width,initial-scale=1">
6
+    <title>dm</title>
7
+  </head>
8
+  <body>
9
+    <noscript>
10
+      dm is a JavaScript app. Please enable JavaScript to continue.
11
+    </noscript>
12
+    <div id="app"></div>
13
+    <script src="/js/compiled/app.js"></script>
14
+  </body>
15
+</html>
0 16
new file mode 100644
... ...
@@ -0,0 +1,39 @@
1
+{:nrepl {:port 8777}
2
+
3
+ :jvm-opts ["-Xmx1G"]
4
+
5
+ :source-paths ["src" "test"]
6
+
7
+ :dependencies
8
+ [[reagent "1.1.0"]
9
+  [re-frame "1.2.0"]
10
+  [day8.re-frame/tracing "0.6.2"]
11
+  [garden "1.3.10"]
12
+  [net.dhleong/spade "1.1.0"]
13
+
14
+  [binaryage/devtools "1.0.3"]
15
+  [day8.re-frame/re-frame-10x "1.2.0"]
16
+  [cider/cider-nrepl "0.26.0"]]
17
+
18
+ :dev-http
19
+ {8280 "resources/public"
20
+  8290 "target/browser-test"}
21
+
22
+ :builds
23
+ {:app
24
+  {:target     :browser
25
+   :output-dir "resources/public/js/compiled"
26
+   :asset-path "/js/compiled"
27
+   :modules
28
+   {:app {:init-fn dm.core/init}}
29
+   :devtools
30
+   {:preloads [day8.re-frame-10x.preload]}
31
+   :dev
32
+   {:compiler-options
33
+    {:closure-defines
34
+     { re-frame.trace.trace-enabled? true
35
+      day8.re-frame.tracing.trace-enabled? true}}}
36
+   :release
37
+   {:build-options
38
+    {:ns-aliases
39
+     {day8.re-frame.tracing day8.re-frame.tracing-stubs}}}}}}
0 40
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+(ns dm.config)
2
+
3
+(def debug?
4
+  ^boolean goog.DEBUG)
0 5
new file mode 100644
... ...
@@ -0,0 +1,24 @@
1
+(ns dm.core
2
+  (:require
3
+   [reagent.dom :as rdom]
4
+   [re-frame.core :as re-frame]
5
+   [dm.events :as events]
6
+   [dm.views :as views]
7
+   [dm.config :as config]
8
+   ))
9
+
10
+
11
+(defn dev-setup []
12
+  (when config/debug?
13
+    (println "dev mode")))
14
+
15
+(defn ^:dev/after-load mount-root []
16
+  (re-frame/clear-subscription-cache!)
17
+  (let [root-el (.getElementById js/document "app")]
18
+    (rdom/unmount-component-at-node root-el)
19
+    (rdom/render [views/main-panel] root-el)))
20
+
21
+(defn init []
22
+  (re-frame/dispatch-sync [::events/initialize-db])
23
+  (dev-setup)
24
+  (mount-root))
0 25
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+(ns dm.db)
2
+
3
+(def default-db
4
+  {:name "re-frame"})
0 5
new file mode 100644
... ...
@@ -0,0 +1,11 @@
1
+(ns dm.events
2
+  (:require
3
+   [re-frame.core :as re-frame]
4
+   [dm.db :as db]
5
+   [day8.re-frame.tracing :refer-macros [fn-traced]]
6
+   ))
7
+
8
+(re-frame/reg-event-db
9
+ ::initialize-db
10
+ (fn-traced [_ _]
11
+   db/default-db))
0 12
new file mode 100644
... ...
@@ -0,0 +1,28 @@
1
+(ns dm.styles
2
+  (:require-macros
3
+    [garden.def :refer [defcssfn]])
4
+  (:require
5
+    [spade.core   :refer [defglobal defclass]]
6
+    [garden.units :refer [deg px]]
7
+    [garden.color :refer [rgba]]))
8
+
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]]))
14
+
15
+(defglobal defaults
16
+  [: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})
0 29
new file mode 100644
... ...
@@ -0,0 +1,8 @@
1
+(ns dm.subs
2
+  (:require
3
+   [re-frame.core :as re-frame]))
4
+
5
+(re-frame/reg-sub
6
+ ::name
7
+ (fn [db]
8
+   (:name db)))
0 9
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+(ns dm.views
2
+  (:require
3
+   [re-frame.core :as re-frame]
4
+   [dm.styles :as styles]
5
+   [dm.subs :as subs]
6
+   ))
7
+
8
+(defn main-panel []
9
+  (let [name (re-frame/subscribe [::subs/name])]
10
+    [:div
11
+     [:h1
12
+      {:class (styles/level1)}
13
+      "Hello from " @name]
14
+     ]))