commit d637579eff36f34093208bc21f1736e932451c03 Author: Daniel O'Connell Date: Sat Sep 12 20:05:18 2020 +0200 Calendar view diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..174f710 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +/out/ +/resources/public/js/compiled/ +/target/ +/*-init.clj +/*.log + +# Leiningen +/.lein-* +/.nrepl-port + +# Node.js dependencies +/node_modules/ + +# shadow-cljs cache, port files +/shadow-cljs.edn +/.shadow-cljs/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..f3a0850 --- /dev/null +++ b/README.md @@ -0,0 +1,268 @@ +# chicken-master + +A [re-frame](https://github.com/day8/re-frame) application designed to ... well, that part is up to +you. + +## Getting Started + +### Project Overview + +* Architecture: +[Single Page Application (SPA)](https://en.wikipedia.org/wiki/Single-page_application) +* Languages + - Front end ([re-frame](https://github.com/day8/re-frame)): [ClojureScript](https://clojurescript.org/) (CLJS) + - Back end/middleware ([Compojure](https://github.com/weavejester/compojure)): [Clojure](https://clojure.org/) + - CSS compilation ([`lein-garden`](https://github.com/noprompt/lein-garden)): [Clojure](https://clojure.org/) +* Dependencies + - UI framework: [re-frame](https://github.com/day8/re-frame) + ([docs](https://github.com/day8/re-frame/blob/master/docs/README.md), + [FAQs](https://github.com/day8/re-frame/blob/master/docs/FAQs/README.md)) -> + [Reagent](https://github.com/reagent-project/reagent) -> + [React](https://github.com/facebook/react) + - Full stack framework: [Compojure](https://github.com/weavejester/compojure) + ([Wiki](https://github.com/weavejester/compojure/wiki), [API docs](http://weavejester.github.com/compojure)) -> + [Ring](https://github.com/ring-clojure/ring) + ([Wiki](https://github.com/ring-clojure/ring/wiki), [API docs](http://ring-clojure.github.com/ring)) + - CSS rendering: [Garden](https://github.com/noprompt/garden) +* Build tools + - Project task & dependency management: [Leiningen](https://github.com/technomancy/leiningen) + - CLJS compilation, REPL, & hot reload: [`shadow-cljs`](https://github.com/thheller/shadow-cljs) + - CSS compilation: [`lein-garden`](https://github.com/noprompt/lein-garden) +* Development tools + - Debugging: [CLJS DevTools](https://github.com/binaryage/cljs-devtools) + - Emacs integration: [CIDER](https://github.com/clojure-emacs/cider) + +#### Directory structure + +* [`/`](/../../): project config files +* [`dev/`](dev/): source files compiled only with the [dev](#running-the-app) profile + - [`cljs/user.cljs`](dev/cljs/user.cljs): symbols for use during development in the +[ClojureScript REPL](#connecting-to-the-browser-repl-from-a-terminal) +* [`resources/public/`](resources/public/): SPA root directory; +[dev](#running-the-app) / [prod](#production) profile depends on the most recent build + - [`index.html`](resources/public/index.html): SPA home page + - Dynamic SPA content rendered in the following `div`: + ```html +
+ ``` + - Customizable; add headers, footers, links to other scripts and styles, etc. + - Generated directories and files + - Created on build with either the [dev](#running-the-app) or [prod](#production) profile + - Deleted on `lein clean` (run by all `lein` aliases before building) + - `css/`: compiled CSS (`lein-garden`, can also be +[compiled manually](#compiling-css-with-lein-garden)) + - `js/compiled/`: compiled CLJS (`shadow-cljs`) + - Not tracked in source control; see [`.gitignore`](.gitignore) +* [`src/clj/chicken_master/`](src/clj/chicken_master/): Backend and middleware source files (Clojure, +[Compojure](https://github.com/weavejester/compojure)) +* [`src/clj/chicken_master/`](src/clj/chicken_master/): CSS compilation source files (Clojure, +[Garden](https://github.com/noprompt/garden)) +* [`src/cljs/chicken_master/`](src/cljs/chicken_master/): SPA source files (ClojureScript, +[re-frame](https://github.com/Day8/re-frame)) + - [`core.cljs`](src/cljs/chicken_master/core.cljs): contains the SPA entry point, `init` + +### Editor/IDE + +Use your preferred editor or IDE that supports Clojure/ClojureScript development. See +[Clojure tools](https://clojure.org/community/resources#_clojure_tools) for some popular options. + +### Environment Setup + +1. Install [JDK 8 or later](https://openjdk.java.net/install/) (Java Development Kit) +2. Install [Leiningen](https://leiningen.org/#install) (Clojure/ClojureScript project task & +dependency management) +3. Install [Node.js](https://nodejs.org/) (JavaScript runtime environment) which should include + [NPM](https://docs.npmjs.com/cli/npm) or if your Node.js installation does not include NPM also install it. +7. Clone this repo and open a terminal in the `chicken-master` project root directory +8. (Optional) Download project dependencies: + ```sh + lein deps + ``` + +### Browser Setup + +Browser caching should be disabled when developer tools are open to prevent interference with +[`shadow-cljs`](https://github.com/thheller/shadow-cljs) hot reloading. + +Custom formatters must be enabled in the browser before +[CLJS DevTools](https://github.com/binaryage/cljs-devtools) can display ClojureScript data in the +console in a more readable way. + +#### Chrome/Chromium + +1. Open [DevTools](https://developers.google.com/web/tools/chrome-devtools/) (Linux/Windows: `F12` +or `Ctrl-Shift-I`; macOS: `⌘-Option-I`) +2. Open DevTools Settings (Linux/Windows: `?` or `F1`; macOS: `?` or `Fn+F1`) +3. Select `Preferences` in the navigation menu on the left, if it is not already selected +4. Under the `Network` heading, enable the `Disable cache (while DevTools is open)` option +5. Under the `Console` heading, enable the `Enable custom formatters` option + +#### Firefox + +1. Open [Developer Tools](https://developer.mozilla.org/en-US/docs/Tools) (Linux/Windows: `F12` or +`Ctrl-Shift-I`; macOS: `⌘-Option-I`) +2. Open [Developer Tools Settings](https://developer.mozilla.org/en-US/docs/Tools/Settings) +(Linux/macOS/Windows: `F1`) +3. Under the `Advanced settings` heading, enable the `Disable HTTP Cache (when toolbox is open)` +option + +Unfortunately, Firefox does not yet support custom formatters in their devtools. For updates, follow +the enhancement request in their bug tracker: +[1262914 - Add support for Custom Formatters in devtools](https://bugzilla.mozilla.org/show_bug.cgi?id=1262914). + +## Development + +### Running the App + +Start a temporary local web server, build the app with the `dev` profile, and serve the app, +browser test runner and karma test runner with hot reload: + +```sh +lein watch +``` + +Please be patient; it may take over 20 seconds to see any output, and over 40 seconds to complete. + +When `[:app] Build completed` appears in the output, browse to +[http://localhost:8280/](http://localhost:8280/). + +[`shadow-cljs`](https://github.com/thheller/shadow-cljs) will automatically push ClojureScript code +changes to your browser on save. To prevent a few common issues, see +[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). + +Opening the app in your browser starts a +[ClojureScript browser REPL](https://clojurescript.org/reference/repl#using-the-browser-as-an-evaluation-environment), +to which you may now connect. + +#### Connecting to the browser REPL from Emacs with CIDER + +Connect to the browser REPL: +``` +M-x cider-jack-in-cljs +``` + +See +[Shadow CLJS User's Guide: Emacs/CIDER](https://shadow-cljs.github.io/docs/UsersGuide.html#cider) +for more information. Note that the mentioned [`.dir-locals.el`](.dir-locals.el) file has already +been created for you. + +#### Connecting to the browser REPL from other editors + +See +[Shadow CLJS User's Guide: Editor Integration](https://shadow-cljs.github.io/docs/UsersGuide.html#_editor_integration). +Note that `lein watch` runs `shadow-cljs watch` for you, and that this project's running build ids is +`app`, `browser-test`, `karma-test`, or the keywords `:app`, `:browser-test`, `:karma-test` in a Clojure context. + +Alternatively, search the web for info on connecting to a `shadow-cljs` ClojureScript browser REPL +from your editor and configuration. + +For example, in Vim / Neovim with `fireplace.vim` +1. Open a `.cljs` file in the project to activate `fireplace.vim` +2. In normal mode, execute the `Piggieback` command with this project's running build id, `:app`: + ```vim + :Piggieback :app + ``` + +#### Connecting to the browser REPL from a terminal + +1. Connect to the `shadow-cljs` nREPL: + ```sh + lein repl :connect localhost:8777 + ``` + The REPL prompt, `shadow.user=>`, indicates that is a Clojure REPL, not ClojureScript. + +2. In the REPL, switch the session to this project's running build id, `:app`: + ```clj + (shadow.cljs.devtools.api/nrepl-select :app) + ``` + The REPL prompt changes to `cljs.user=>`, indicating that this is now a ClojureScript REPL. +3. See [`user.cljs`](dev/cljs/user.cljs) for symbols that are immediately accessible in the REPL +without needing to `require`. + +### Compiling CSS with `lein-garden` + +Use Clojure and [Garden](https://github.com/noprompt/garden) to edit styles in `.clj` files located +in the [`src/clj/chicken_master/`](src/clj/chicken_master/) directory. CSS files are compiled +automatically on [`dev`](#running-the-app) or [`prod`](#production) build. + +Manually compile CSS files: +```sh +lein garden once +``` + +The `resources/public/css/` directory is created, containing the compiled CSS files. + +#### Compiling CSS with Garden on change + +Enable automatic compiling of CSS files when source `.clj` files are changed: +```sh +lein garden auto +``` + +### Running `shadow-cljs` Actions + +See a list of [`shadow-cljs CLI`](https://shadow-cljs.github.io/docs/UsersGuide.html#_command_line) +actions: +```sh +lein run -m shadow.cljs.devtools.cli --help +``` + +Please be patient; it may take over 10 seconds to see any output. Also note that some actions shown +may not actually be supported, outputting "Unknown action." when run. + +Run a shadow-cljs action on this project's build id (without the colon, just `app`): +```sh +lein run -m shadow.cljs.devtools.cli app +``` +### Debug Logging + +The `debug?` variable in [`config.cljs`](src/cljs/chicken_master/config.cljs) defaults to `true` in +[`dev`](#running-the-app) builds, and `false` in [`prod`](#production) builds. + +Use `debug?` for logging or other tasks that should run only on `dev` builds: + +```clj +(ns chicken-master.example + (:require [chicken-master.config :as config]) + +(when config/debug? + (println "This message will appear in the browser console only on dev builds.")) +``` + +## Production + +Build the app with the `prod` profile: + +```sh +lein with-profile release uberjar +``` + +Please be patient; it may take a few seconds to see any output, and over 50 seconds to complete. + +The `resources/public/js/compiled` directory is created, containing the compiled `app.js` and +`manifest.edn` files. The `target/` directory is then created, containing the +standalone `chicken-master.jar`. + +### Running the Server + +[Run the jar](https://github.com/ring-clojure/ring/wiki/Setup-for-production#run-the-server), +setting the port the Ring server will use by setting the environment variable, `port`. + +```sh +port=2000 java -jar target/chicken-master.jar +``` + +If `port` is not set, the server will run on port 3000 by default. + +### Deploying to Heroku + +1. [Create a Heroku app](https://devcenter.heroku.com/articles/creating-apps): + ```sh + heroku create + ``` + +2. [Deploy the app code](https://devcenter.heroku.com/articles/git#deploying-code): + + ```sh + git push heroku master + ``` diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..ba2cc63 --- /dev/null +++ b/project.clj @@ -0,0 +1,93 @@ +(defproject chicken-master "0.1.0-SNAPSHOT" + :dependencies [[org.clojure/clojure "1.10.1"] + [org.clojure/clojurescript "1.10.773" + :exclusions [com.google.javascript/closure-compiler-unshaded + org.clojure/google-closure-library + org.clojure/google-closure-library-third-party]] + [thheller/shadow-cljs "2.11.0"] + [reagent "0.10.0"] + [re-frame "1.1.1"] + [garden "1.3.10"] + [ns-tracker "0.4.0"] + [compojure "1.6.2"] + [yogthos/config "1.1.7"] + [ring "1.8.1"]] + + :plugins [[lein-shadow "0.2.2"] + [lein-garden "0.3.0"] + [lein-shell "0.5.0"]] + + :min-lein-version "2.9.0" + + :jvm-opts ["-Xmx1G"] + + :source-paths ["src/clj" "src/cljs"] + + :clean-targets ^{:protect false} ["resources/public/js/compiled" "target" + "resources/public/css"] + + + :garden {:builds [{:id "screen" + :source-paths ["src/clj"] + :stylesheet chicken-master.css/screen + :compiler {:output-to "resources/public/css/screen.css" + :pretty-print? true}}]} + + :shadow-cljs {:nrepl {:port 8777} + + :builds {:app {:target :browser + :output-dir "resources/public/js/compiled" + :asset-path "/js/compiled" + :modules {:app {:init-fn chicken-master.core/init + :preloads [devtools.preload]}} + + :devtools {:http-root "resources/public" + :http-port 8280 + :http-handler chicken-master.handler/dev-handler + }}}} + + :shell {:commands {"karma" {:windows ["cmd" "/c" "karma"] + :default-command "karma"} + "open" {:windows ["cmd" "/c" "start"] + :macosx "open" + :linux "xdg-open"}}} + + :aliases {"dev" ["do" + ["shell" "echo" "\"DEPRECATED: Please use lein watch instead.\""] + ["watch"]] + "watch" ["with-profile" "dev" "do" + ["shadow" "watch" "app" "browser-test" "karma-test"]] + + "prod" ["do" + ["shell" "echo" "\"DEPRECATED: Please use lein release instead.\""] + ["release"]] + + "release" ["with-profile" "prod" "do" + ["shadow" "release" "app"]] + + "build-report" ["with-profile" "prod" "do" + ["shadow" "run" "shadow.cljs.build-report" "app" "target/build-report.html"] + ["shell" "open" "target/build-report.html"]] + + "karma" ["do" + ["shell" "echo" "\"DEPRECATED: Please use lein ci instead.\""] + ["ci"]] + "ci" ["with-profile" "prod" "do" + ["shadow" "compile" "karma-test"] + ["shell" "karma" "start" "--single-run" "--reporters" "junit,dots"]]} + + :profiles + {:dev + {:dependencies [[binaryage/devtools "1.0.2"]] + :source-paths ["dev"]} + + :prod {} + + :uberjar {:source-paths ["env/prod/clj"] + :omit-source true + :main chicken-master.server + :aot [chicken-master.server] + :uberjar-name "chicken-master.jar" + :prep-tasks ["compile" ["prod"]["garden" "once"]]}} + + :prep-tasks [["garden" "once"]]) diff --git a/resources/public/index.html b/resources/public/index.html new file mode 100644 index 0000000..d274a48 --- /dev/null +++ b/resources/public/index.html @@ -0,0 +1,16 @@ + + + + + + + chicken-master + + + +
+ + + diff --git a/src/clj/chicken_master/css.clj b/src/clj/chicken_master/css.clj new file mode 100644 index 0000000..1378619 --- /dev/null +++ b/src/clj/chicken_master/css.clj @@ -0,0 +1,60 @@ +(ns chicken-master.css + (:require [garden.def :refer [defstyles]])) + +(defstyles screen + [:html {:height "100%"} + [:body {:height "100%"} + [:.full-height {:height "100%"}] + [:.popup {:position :fixed + :height "100%" + :width "100%" + :overflow :auto + :z-index 1 + :background-color "rgba(0,0,0,0.4)"} + [:form { + :background-color "#fefefe" + :margin "15% auto" + :padding "20px" + :border "1px solid #888" + :width "15%" + } + [:.input-item + [:label {:min-width "60px" + :display :inline-block}]] + [:.form-buttons {:margin "10px"} + [:* {:margin "20px"}]]]] + + [:.calendar {:display :grid + :grid-template-columns "14% 14% 14% 14% 14% 14% 14%" + :grid-template-rows "50% 50%" + } + [:.day-header {:border "2px solid black" + :text-align :center + :font-size "30px"}] + [:.day.today {:border "2px solid red"}] + [:.day {:border "2px solid black" + :overflow :auto} + + ; If each day has a header, then hide the rest of the border + [:.day-header {:border "none" + :border-bottom "2px solid black"}] + + [:.orders {:padding-left "25px"} + + [:.actions {:display :none + :float :right}] + [:.order:hover [:.actions {:display :inline}]] + + [:.who {:font-size "18px" + :font-weight :bold + :white-space :nowrap + :overflow :hidden + :text-overflow :ellipsis}] + [:.products {:padding-left "25px"} + [:.product {:margin-bottom "5px"} + [:.product-amount {:width "40px" + :margin-right "10px" + :max-height "5px"}]] + + ]]]]]] +) diff --git a/src/clj/chicken_master/handler.clj b/src/clj/chicken_master/handler.clj new file mode 100644 index 0000000..151c28d --- /dev/null +++ b/src/clj/chicken_master/handler.clj @@ -0,0 +1,15 @@ +(ns chicken-master.handler + (:require + [compojure.core :refer [GET defroutes]] + [compojure.route :refer [resources]] + [ring.util.response :refer [resource-response]] + [ring.middleware.reload :refer [wrap-reload]] + [shadow.http.push-state :as push-state])) + +(defroutes routes + (GET "/" [] (resource-response "index.html" {:root "public"})) + (resources "/")) + +(def dev-handler (-> #'routes wrap-reload push-state/handle)) + +(def handler routes) diff --git a/src/clj/chicken_master/server.clj b/src/clj/chicken_master/server.clj new file mode 100644 index 0000000..30b7bfe --- /dev/null +++ b/src/clj/chicken_master/server.clj @@ -0,0 +1,9 @@ +(ns chicken-master.server + (:require [chicken-master.handler :refer [handler]] + [config.core :refer [env]] + [ring.adapter.jetty :refer [run-jetty]]) + (:gen-class)) + + (defn -main [& _args] + (let [port (or (env :port) 3000)] + (run-jetty handler {:port port :join? false}))) diff --git a/src/cljs/chicken_master/calendar.cljs b/src/cljs/chicken_master/calendar.cljs new file mode 100644 index 0000000..e67aaef --- /dev/null +++ b/src/cljs/chicken_master/calendar.cljs @@ -0,0 +1,81 @@ +(ns chicken-master.calendar + (:require + [re-frame.core :as re-frame] + [chicken-master.subs :as subs] + [chicken-master.time :as time] + )) + +(defn get-day [date] + {:date date + :customers [{:who "mr.blobby (649 234 234)" :when date :products {:eggs 2 :milk 3}} + {:who "da police (0118 999 881 999 119 725 123123 12 3123 123 )" :when date :products {:eggs 12}} + {:who "johnny" :when date :products {:eggs 5}}]}) + + +(defn modal [content on-submit] + [:div {:class :popup} + [:form {:action "#"} + content + [:div {:class :form-buttons} + [:input {:type :submit :value "add"}] + [:button {:type :button} "cancel"]]]]) + +(defn add-product [date order-id] + (modal + [:div + [:div {:class :input-item} + [:label {:for :product} "co"] + [:input {:type :text :name :product :id :product}]] + [:div {:class :input-item} + [:label {:for :amount} "ile"] + [:input {:type :number :name :amount :id :amount}]]] + js/console.log)) + +(defn add-order [date] + (modal + [:div + [:div {:class :input-item} + [:label {:for :who} "kto"] + [:input {:type :text :name :who :id :who :required true :step "60"}]] + [:div {:class :input-item} + [:label {:for :when} "kiedy"] + [:input {:type :time :name :when :id :when}]] + [:div {} + [:label "co"] + ]] + js/console.log)) + +(defn format-product [[product amount]] + [:li {:class :product} + [:input {:class :product-amount :type :number :min 0 :defaultValue amount}] + [:span {:class :product-name} product]]) + +(defn format-order [{:keys [who when products]}] + [:li {:class :order} + [:div {:class :actions} + [:button "+"] [:button "O"] [:button "-"]] + [:div {:class :who} who] + (if (subs/settings :show-order-time) + [:div {:class :when} (str (.getHours when) ":" (.getMinutes when))]) + (->> products + (map format-product) + (into [:ul {:class :products}]))]) + +(defn day [{:keys [date customers]}] + [:div {:class [:day (when (time/today? date) :today)]} + [:div {:class :day-header} (time/format-date date)] + [:div + [:ul {:class :orders} + (map format-order customers) + [:button {:type :button} "+"]]]]) + +(defn calendar-header [] + (->> (subs/settings :day-names) + (map (fn [day] [:div {:class :day-header} day])) + (into []))) + +(defn calendar [days] + (->> days + (map (comp day get-day)) + (concat (when-not (subs/settings :always-day-names) (calendar-header))) + (into [:div {:class [:calendar :full-height]}]))) diff --git a/src/cljs/chicken_master/config.cljs b/src/cljs/chicken_master/config.cljs new file mode 100644 index 0000000..8da7c1f --- /dev/null +++ b/src/cljs/chicken_master/config.cljs @@ -0,0 +1,4 @@ +(ns chicken-master.config) + +(def debug? + ^boolean goog.DEBUG) diff --git a/src/cljs/chicken_master/core.cljs b/src/cljs/chicken_master/core.cljs new file mode 100644 index 0000000..08cea23 --- /dev/null +++ b/src/cljs/chicken_master/core.cljs @@ -0,0 +1,24 @@ +(ns chicken-master.core + (:require + [reagent.dom :as rdom] + [re-frame.core :as re-frame] + [chicken-master.events :as events] + [chicken-master.views :as views] + [chicken-master.config :as config] + )) + + +(defn dev-setup [] + (when config/debug? + (println "dev mode"))) + +(defn ^:dev/after-load mount-root [] + (re-frame/clear-subscription-cache!) + (let [root-el (.getElementById js/document "app")] + (rdom/unmount-component-at-node root-el) + (rdom/render [views/main-panel] root-el))) + +(defn init [] + (re-frame/dispatch-sync [::events/initialize-db]) + (dev-setup) + (mount-root)) diff --git a/src/cljs/chicken_master/db.cljs b/src/cljs/chicken_master/db.cljs new file mode 100644 index 0000000..b0c10ec --- /dev/null +++ b/src/cljs/chicken_master/db.cljs @@ -0,0 +1,4 @@ +(ns chicken-master.db) + +(def default-db + {:name "re-frame"}) diff --git a/src/cljs/chicken_master/events.cljs b/src/cljs/chicken_master/events.cljs new file mode 100644 index 0000000..37bb7e8 --- /dev/null +++ b/src/cljs/chicken_master/events.cljs @@ -0,0 +1,10 @@ +(ns chicken-master.events + (:require + [re-frame.core :as re-frame] + [chicken-master.db :as db] + )) + +(re-frame/reg-event-db + ::initialize-db + (fn [_ _] + db/default-db)) diff --git a/src/cljs/chicken_master/subs.cljs b/src/cljs/chicken_master/subs.cljs new file mode 100644 index 0000000..6ad834c --- /dev/null +++ b/src/cljs/chicken_master/subs.cljs @@ -0,0 +1,13 @@ +(ns chicken-master.subs + (:require + [re-frame.core :as re-frame])) + +(re-frame/reg-sub + ::name + (fn [db] + (:name db))) + +(def settings {:first-day-offset 1 + :day-names ["Niedz" "Pon" "Wt" "Śr" "Czw" "Pt" "Sob"] + :always-day-names true + :show-order-time false}) diff --git a/src/cljs/chicken_master/time.cljs b/src/cljs/chicken_master/time.cljs new file mode 100644 index 0000000..d7ac8e3 --- /dev/null +++ b/src/cljs/chicken_master/time.cljs @@ -0,0 +1,35 @@ +(ns chicken-master.time + (:require + [chicken-master.subs :as subs]) + (:import [goog.date DateTime Date Interval])) + +(defn date-offset + "Return the `date` offset by the given number of `days`" + [date days] + (let [new-day (new DateTime date)] + (.add new-day (new Interval Interval/DAYS days)) + new-day)) + +(defn start-of-week + "Get the start of the week for the given `date" + [date] + (->> (.getDay date) + (- (subs/settings :first-day-offset)) + (date-offset date))) + +(defn days-range + "Return dates starting from `date`" + ([date] (map (partial date-offset date) (range))) + ([date n] (take n (days-range date)))) + +(defn same-day? + "Returns true when both dates are from the same day" [d1 d2] + (-> (new Date d1) + (.equals (new Date d2)))) + +(defn today? "true when `d1` is today" [d1] (same-day? (js/Date.) d1)) + +(defn format-date [date] + (str + (->> date .getDay (nth (subs/settings :day-names))) + " " (.getMonth date) "/" (.getDate date))) diff --git a/src/cljs/chicken_master/views.cljs b/src/cljs/chicken_master/views.cljs new file mode 100644 index 0000000..0dafea1 --- /dev/null +++ b/src/cljs/chicken_master/views.cljs @@ -0,0 +1,17 @@ +(ns chicken-master.views + (:require + [re-frame.core :as re-frame] + [chicken-master.subs :as subs] + [chicken-master.calendar :as cal] + [chicken-master.time :as time] + )) + +(defn main-panel [] + (let [name (re-frame/subscribe [::subs/name])] + [:div {:class :full-height} + (cal/add-order (new js/Date)) + (-> (new js/Date) + time/start-of-week + (time/days-range 14) + cal/calendar) + ])) diff --git a/src/cljs/deps.cljs b/src/cljs/deps.cljs new file mode 100644 index 0000000..d285777 --- /dev/null +++ b/src/cljs/deps.cljs @@ -0,0 +1 @@ +{:npm-dev-deps {"shadow-cljs" "2.11.0"}}