This commit is contained in:
Andrey Shovkoplyas 2017-11-10 14:36:21 -05:00
parent be5a030b61
commit 5b45654c1e
31 changed files with 634 additions and 9 deletions

17
.gitignore vendored
View File

@ -1,15 +1,18 @@
.DS_Store
pom.xml
*jar
lib/*
classes/*
out/*
target/*
lib/
classes/
out/
target/
.lein-deps-sum
.lein-repl-history
.lein-plugins/*
node_modules/*
.lein-plugins/
node_modules/
*.iml
*.ipr
*.iws
electron/*
electron/
.idea/workspace.xml
app/dev/js/
app/prod/js/

View File

@ -13,6 +13,11 @@ You should have status-react and status-electron in the same directory
```
Make simlink to resources folder
```
ln -s /Users/*/status-dev-folder/status-react/resources /Users/*/status-dev-folder/status-electron/resources
```
## Requirements

31
app/dev/index.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>Status</title>
</head>
<style>
.app, html, body {
height:100%;
margin:0;
}
.app {
display: flex;
flex-direction: column;
}
input:focus,
select:focus,
textarea:focus,
button:focus {
outline: none;
}
</style>
<body>
<div id="app" class="app">
<p>Loading...</p>
</div>
<script type="text/javascript" src="js/out_front/goog/base.js" charset="utf-8"></script>
<script type="text/javascript" src="js/front.js" charset="utf-8"></script>
<script type="text/javascript">goog.require('status_desktop_front.init')</script>
</body>
</html>

5
app/dev/package.json Normal file
View File

@ -0,0 +1,5 @@
{
"name": "status-desktop",
"version": "0.1.0",
"main": "js/main.js"
}

BIN
app/dev/status.icns Normal file

Binary file not shown.

17
app/prod/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script>
and Electron <script>document.write(process.versions['electron'])</script>.
<div id="app">
<p>Reagent does not work.</p>
</div>
<script type="text/javascript" src="js/front.js" charset="utf-8"></script>
</body>
</html>

5
app/prod/package.json Normal file
View File

@ -0,0 +1,5 @@
{
"name": "status-desktop",
"version": "0.1.0",
"main": "js/main.js"
}

View File

@ -6,7 +6,7 @@
:dependencies [[org.clojure/clojure "1.9.0-alpha17"]
[org.clojure/clojurescript "1.9.908"]
[org.clojure/core.async "0.3.443"]
[reagent "0.7.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server]]
[reagent "0.7.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server cljsjs/create-react-class]]
[re-frame "0.10.1"]
[com.andrewmcveigh/cljs-time "0.5.0"]
[com.taoensso/timbre "4.10.0"]
@ -133,7 +133,8 @@
;;:source-map "app/prod/js/test.js.map"
:pretty-print true
:output-wrapper true}}
:prod-front {:source-paths ["src_front" "src_front_profile/status_desktop_front/prod" "../status-react/src"]
:prod-front {:source-paths ["src_front" "src_front_profile/status_desktop_front/prod"
"../status-react/src"]
:incremental true
:jar true
:assert true

View File

@ -0,0 +1,43 @@
(ns status-desktop.core
(:require [cljs.nodejs :as nodejs]))
(def path (nodejs/require "path"))
(def Electron (nodejs/require "electron"))
(def BrowserWindow (.-BrowserWindow Electron))
(def Os (nodejs/require "os"))
(def *win* (atom nil))
(def app (.-app Electron))
(defn -main []
;; error listener
(.on nodejs/process "error"
(fn [err] (.log js/console err)))
;; window all closed listener
(.on app "window-all-closed"
(fn [] (if (not= (.-platform nodejs/process) "darwin")
(.quit app))))
;; ready listener
(.on app "ready"
(fn []
(reset! *win* (BrowserWindow. (clj->js {:width 800 :height 600 :icon (.resolve path (js* "__dirname") "../status.icns")})))
;; when no optimize comment out
(.loadURL @*win* (str "file://" (.resolve path (js* "__dirname") "../index.html")))
;; when no optimize uncomment
;; (.loadURL @*win* (str "file://" (.resolve path (js* "__dirname") "../../../index.html")))
(.on @*win* "closed" (fn [] (reset! *win* nil))))))
(nodejs/enable-util-print!)
;;; "Linux" or "Darwin" or "Windows_NT"
(.log js/console (str "Start descjop application on " (.type Os) "."))
(set! *main-cli-fn* -main)

View File

@ -0,0 +1 @@
(ns cljsjs.create-react-class)

View File

@ -0,0 +1,2 @@
(ns cljsjs.react)

View File

@ -0,0 +1 @@
(ns cljsjs.react.dom)

View File

@ -0,0 +1 @@
(ns cljsjs.react.dom.server)

View File

@ -0,0 +1,28 @@
(ns status-desktop-front.core
(:require [reagent.core :as reagent :refer [atom]]
[re-frisk-remote.core :refer [enable-re-frisk-remote!]]
[re-frame.core :as re-frame]
[status-desktop-front.ui.screens.chat.view :refer [chat]]
[status-desktop-front.protocol :as protocol]
status-desktop-front.ui.screens.subs
status-desktop-front.ui.screens.events))
(defn mount-root []
(println "ROOT")
(reagent/render [chat]
(.getElementById js/document "app")))
(re-frame/reg-event-db :init-app-db
(fn [db]
;(test-send-message!)
(assoc db :view-id :chat-list :messages [{:text "At least i hope so"} {:text "That's what i thought"} {:text "a minute ago"}])))
(defn init []
(re-frame/dispatch-sync [:init-app-db])
(mount-root)
(protocol/test-post-shh))
(defn init! [setting]
(println "RElOAD")
(init))
;(enable-re-frisk-remote! {:on-init init}))

View File

@ -0,0 +1,69 @@
(ns status-desktop-front.protocol
(:require [status-im.protocol.core :as protocol]
[status-im.utils.random :as random]))
(def identity-1 "0x0493c4c7f79dab83651e85695bf9fc0c236cb0ec8070108dc929eabe6d5a5f1c6dd6835264990de710a887a53bc0306c53b2421e1dda9cc2a0c2e3ec855b7e8e81")
(def identity-2 "0x047071d8929ad79d9312870fbd74736541ba443fd96e7b374a85b0cd9bcf7a2ab673e55e632d2b1d09cb460169049013210c83846370cf3d9adc8045cba288216f")
(def rpc-url "http://localhost:8645")
(def Web3 (js/require "web3"))
(def web3 (Web3. (Web3.providers.HttpProvider. rpc-url)))
(defn make-callback [identity]
(fn [& args]
(.log js/console (str :post-callback " " identity "\n" args))))
(defn post-error-callback [identity]
(fn [& args]
(.log js/console (str :post-error " " identity "\n" args))))
(defn test-post-shh [])
(defn init-whisper! []
(let [
{:keys [private public]} (protocol/new-keypair!)
common-config {:web3 web3
:identity identity-1
:groups []
:callback (make-callback identity-1)
:ack-not-received-s-interval 125
:default-ttl 120
:send-online-s-interval 180
:ttl-config {:public-group-message 2400}
:max-attempts-number 1
:delivery-loop-ms-interval 500
:profile-keypair {:public public
:private private}
:hashtags []
:pending-messages []
:contacts []
:post-error-callback (post-error-callback identity-1)}]
(protocol/init-whisper! common-config)
(protocol/contact-request!
{:web3 web3
:message {:from identity-1
:to identity-2
:message-id (random/id)
:payload {:contact {:name "testname"
:profile-image ""
:address "0"
:status "teststatus"}
:keypair {:public public
:private private}}}})))
(defn send-message [text]
(let [mess-id (random/id)]
(protocol/send-message!
{:web3 web3
:message {:message-id mess-id
:from identity-1
:to identity-2
:payload {:message-id mess-id
:requires-ack? false,
:type :message,
:timestamp 1498723691404,
:content text,
:content-type "text/plain",
:clock-value 1,
:show? true}}})))

View File

@ -0,0 +1,20 @@
(ns status-desktop-front.react-native-web
(:require [reagent.core :as reagent]))
(def react-native-web (js/require "react-native-web"))
(defn get-react-property [name]
(aget react-native-web name))
(defn adapt-class [class]
(when class
(reagent/adapt-react-class class)))
(defn get-class [name]
(adapt-class (get-react-property name)))
(def view (get-class "View"))
(def text (get-class "Text"))
(def touchable-highlight (get-class "TouchableOpacity"))
(def scroll-view (get-class "ScrollView"))
(def text-input (get-class "TextInput"))

View File

@ -0,0 +1,87 @@
(ns status-desktop-front.ui.components.icons
(:require-macros [status-desktop-front.utils :refer [slurp-web-svg]])
(:require [status-desktop-front.react-native-web :as react]
[status-im.components.styles :as styles]))
(def icons {:icons/chats (slurp-web-svg "../status-react/resources/icons/bottom/chats_gray.svg")
:icons/chats-active (slurp-web-svg "../status-react/resources/icons/bottom/chats_active.svg")
:icons/contacts (slurp-web-svg "../status-react/resources/icons/bottom/contacts_gray.svg")
:icons/contacts-active (slurp-web-svg "../status-react/resources/icons/bottom/contacts_active.svg")
:icons/discover (slurp-web-svg "../status-react/resources/icons/bottom/discover_gray.svg")
:icons/discover-active (slurp-web-svg "../status-react/resources/icons/bottom/discover_active.svg")
:icons/wallet (slurp-web-svg "../status-react/resources/icons/bottom/wallet_gray.svg")
:icons/wallet-active (slurp-web-svg "../status-react/resources/icons/bottom/wallet_active.svg")
:icons/speaker (slurp-web-svg "../status-react/resources/icons/speaker.svg")
:icons/speaker-off (slurp-web-svg "../status-react/resources/icons/speaker_off.svg")
:icons/transaction-history (slurp-web-svg "../status-react/resources/icons/transaction_history.svg")
:icons/add (slurp-web-svg "../status-react/resources/icons/add.svg")
:icons/add-wallet (slurp-web-svg "../status-react/resources/icons/add_wallet.svg")
:icons/address (slurp-web-svg "../status-react/resources/icons/address.svg")
:icons/arrow-left (slurp-web-svg "../status-react/resources/icons/arrow_left.svg")
:icons/arrow-right (slurp-web-svg "../status-react/resources/icons/arrow_right.svg")
:icons/flash-active (slurp-web-svg "../status-react/resources/icons/flash_active.svg")
:icons/flash-inactive (slurp-web-svg "../status-react/resources/icons/flash_inactive.svg")
:icons/attach (slurp-web-svg "../status-react/resources/icons/attach.svg")
:icons/back (slurp-web-svg "../status-react/resources/icons/back.svg")
:icons/browse (slurp-web-svg "../status-react/resources/icons/browse.svg")
:icons/close (slurp-web-svg "../status-react/resources/icons/close.svg")
:icons/copy-from (slurp-web-svg "../status-react/resources/icons/copy_from.svg")
:icons/dots-horizontal (slurp-web-svg "../status-react/resources/icons/dots_horizontal.svg")
:icons/dots-vertical (slurp-web-svg "../status-react/resources/icons/dots_vertical.svg")
:icons/exclamation_mark (slurp-web-svg "../status-react/resources/icons/exclamation_mark.svg")
:icons/filter (slurp-web-svg "../status-react/resources/icons/filter.svg")
:icons/forward (slurp-web-svg "../status-react/resources/icons/forward.svg")
:icons/fullscreen (slurp-web-svg "../status-react/resources/icons/fullscreen.svg")
:icons/group-big (slurp-web-svg "../status-react/resources/icons/group_big.svg")
:icons/group-chat (slurp-web-svg "../status-react/resources/icons/group_chat.svg")
:icons/hamburger (slurp-web-svg "../status-react/resources/icons/hamburger.svg")
:icons/hidden (slurp-web-svg "../status-react/resources/icons/hidden.svg")
:icons/mic (slurp-web-svg "../status-react/resources/icons/mic.svg")
:icons/ok (slurp-web-svg "../status-react/resources/icons/ok.svg")
:icons/public (slurp-web-svg "../status-react/resources/icons/public.svg")
:icons/public-chat (slurp-web-svg "../status-react/resources/icons/public_chat.svg")
:icons/qr (slurp-web-svg "../status-react/resources/icons/QR.svg")
:icons/search (slurp-web-svg "../status-react/resources/icons/search.svg")
:icons/smile (slurp-web-svg "../status-react/resources/icons/smile.svg")
:icons/commands-list (slurp-web-svg "../status-react/resources/icons/commands_list.svg")
:icons/dropdown-up (slurp-web-svg "../status-react/resources/icons/dropdown_up.svg")
:icons/dropdown (slurp-web-svg "../status-react/resources/icons/dropdown.svg")
:icons/grab (slurp-web-svg "../status-react/resources/icons/grab.svg")
:icons/share (slurp-web-svg "../status-react/resources/icons/share.svg")
:icons/tooltip-triangle (slurp-web-svg "../status-react/resources/icons/tooltip-triangle.svg")
:icons/open (slurp-web-svg "../status-react/resources/icons/open.svg")
:icons/network (slurp-web-svg "../status-react/resources/icons/network.svg")})
(defn normalize-property-name [n]
(if (= n :icons/options)
:icons/dots-horizontal
n))
(def default-viewbox {:width 24 :height 24 :viewBox "0 0 24 24"})
(defn icon
([name] (icon name nil))
([name {:keys [color container-style style accessibility-label]
:or {accessibility-label :icon}}]
^{:key name}
[react/view
(if-let [icon-fn (get icons (normalize-property-name name))]
(into []
(concat
[:svg (merge default-viewbox style)]
(icon-fn
(cond
(keyword? color)
(case color
:dark styles/icon-dark-color
:gray styles/icon-gray-color
:blue styles/color-light-blue
:active styles/color-blue4
:white styles/color-white
:red styles/icon-red-color
styles/icon-dark-color)
(string? color)
color
:else
styles/icon-dark-color))))
(throw (js/Error. (str "Unknown icon: " name))))]))

View File

@ -0,0 +1,50 @@
(ns status-desktop-front.ui.components.tabs
(:require [status-desktop-front.react-native-web :as react]
[status-im.components.tabs.styles :as tabs.styles]
[re-frame.core :as re-frame]
[status-desktop-front.ui.components.icons :as icons])
(:require-macros [status-im.utils.views :as views]))
(def tabs-list-data
[{:view-id :wallet
:content {:title "Wallet"
:icon-inactive :icons/wallet
:icon-active :icons/wallet-active}}
{:view-id :chat-list
:content {:title "Chats"
:icon-inactive :icons/chats
:icon-active :icons/chats-active}}
{:view-id :discover
:content {:title "Discover"
:icon-inactive :icons/discover
:icon-active :icons/discover-active}}
{:view-id :contact-list
:content {:title "Contacts"
:icon-inactive :icons/contacts
:icon-active :icons/contacts-active}}])
(defn- tab-content [{:keys [title icon-active icon-inactive]}]
(fn [active?]
[react/view {:style tabs.styles/tab-container}
(let [icon (if active? icon-active icon-inactive)]
[react/view
[icons/icon icon {:color (:color (tabs.styles/tab-icon active?))}]])
[react/view
[react/text {:style (tabs.styles/tab-title active?)}
title]]]))
(def tabs-list-indexed (map-indexed vector (map #(update % :content tab-content) tabs-list-data)))
(defn tab [index content view-id active?]
[react/touchable-highlight {:style (tabs.styles/tab active?)
:disabled active?
:on-press #(re-frame/dispatch [:set-view view-id])}
[react/view
[content active?]]])
(views/defview main-tabs []
(views/letsubs [current-tab [:view-id]]
[react/view {:styles {:border-color :red :border-width 1}}
[react/view {:style tabs.styles/tabs-container}
(for [[index {:keys [content view-id]}] tabs-list-indexed]
^{:key index} [tab index content view-id (= current-tab view-id)])]]))

View File

@ -0,0 +1,16 @@
(ns status-desktop-front.ui.screens.chat.events
(:require [re-frame.core :as re-frame]
[status-desktop-front.protocol :as protocol]))
(re-frame/reg-event-db
:set-message-text
(fn [db [_ text]]
(assoc db :message-text text)))
(re-frame/reg-event-db
:send-message
(fn [{:keys [message-text] :as db} _]
(protocol/send-message message-text)
(-> db
(assoc :message-text "")
(update :messages conj {:me? true :text message-text}))))

View File

@ -0,0 +1,12 @@
(ns status-desktop-front.ui.screens.chat.subs
(:require [re-frame.core :as re-frame]))
(re-frame/reg-sub
:messages
(fn [db _]
(get db :messages)))
(re-frame/reg-sub
:message-text
(fn [db _]
(get db :message-text)))

View File

@ -0,0 +1,57 @@
(ns status-desktop-front.ui.screens.chat.view
(:require [status-desktop-front.react-native-web :as react]
[status-desktop-front.ui.components.tabs :refer [main-tabs]]
[re-frame.core :as re-frame]
[status-desktop-front.ui.components.icons :as icons]
[status-desktop-front.protocol :as protocol])
(:require-macros [status-im.utils.views :as views]))
(defn message [text & [me?]]
[react/view {:style {:padding-bottom 8 :padding-horizontal 60 :flex-direction :row :flex 1}}
(when-not me?
[react/view {:style {:flex 1}}])
[react/view {:style {:padding 12 :background-color :white :border-radius 8}}
[react/text
text]]])
(views/defview messages []
(views/letsubs [messages [:messages]]
[react/view {:style {:flex 1 :background-color "#eef2f5"}}
[react/scroll-view
[react/view {:style {:padding-vertical 60}}
(for [[index {:keys [me? text]}] (map-indexed vector messages)]
^{:key index} [message text me?])]]]))
(views/defview chat []
(views/letsubs [message-text [:message-text]]
[react/view {:style {:flex 1 :flex-direction :row}}
[react/view {:style {:width 340 :background-color :white}}
[react/view {:style {:height 64 :align-items :center :flex-direction :row :padding-horizontal 11}}
[icons/icon :icons/hamburger]
[react/view {:style {:flex 1 :margin-horizontal 11 :height 38 :border-radius 8 :background-color "#edf1f3"}}]
[icons/icon :icons/add]]
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
[react/view {:style {:flex 1}}]
[main-tabs]]
[react/view {:style {:flex 1 :background-color "#eef2f5"}}
[react/view {:style {:height 64 :align-items :center :padding-horizontal 11 :justify-content :center}}
[react/text {:style {:font-size 16 :color :black :font-weight "600"}}
"Kurt Weller"]
[react/text {:style {:font-size 14 :color "#939ba1" :margin-top 3}}
"Active now"]]
[react/view {:style {:height 1 :background-color "#e8ebec" :margin-horizontal 16}}]
[messages]
[react/view {:style {:height 90 :margin-horizontal 16 :margin-bottom 16 :background-color :white :border-radius 12
:box-shadow "0 0.5px 4.5px 0 rgba(0, 0, 0, 0.04)"}}
[react/view {:style {:flex-direction :row :margin-horizontal 16 :margin-top 16}}
[react/view {:style {:flex 1}}
[react/text-input {:value (or message-text "")
:placeholder "Type a message..."
:on-change (fn [e]
(let [native-event (.-nativeEvent e)
text (.-text native-event)]
(re-frame/dispatch [:set-message-text text])))}]]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:send-message])}
[react/view {:style {:margin-left 16 :width 30 :height 30 :border-radius 15 :background-color "#eef2f5" :align-items :center
:justify-content :center}}
[icons/icon :icons/dropdown-up]]]]]]]))

View File

@ -0,0 +1,8 @@
(ns status-desktop-front.ui.screens.events
(:require [re-frame.core :as re-frame]
status-desktop-front.ui.screens.chat.events))
(re-frame/reg-event-db
:set-view
(fn [db [_ view-id]]
(assoc db :view-id view-id)))

View File

@ -0,0 +1,8 @@
(ns status-desktop-front.ui.screens.subs
(:require [re-frame.core :as re-frame]
status-desktop-front.ui.screens.chat.subs))
(re-frame/reg-sub
:view-id
(fn [db _]
(get db :view-id)))

View File

@ -0,0 +1,24 @@
(ns status-desktop-front.utils
(:require [clojure.string :as string]
[hickory.core :as hickory]))
(def svg-tags #{:g :rect :path :use :defs})
(defmacro slurp-web-svg [file]
(let [svg (-> (clojure.core/slurp file)
(string/replace #"[\n]\s*" ""))
svg-hiccup (first (map hickory/as-hiccup (hickory/parse-fragment svg)))
color (gensym "args")]
`(fn [~color]
~(into []
(clojure.walk/prewalk
(fn [node]
(if (svg-tags node)
node
(if (vector? node)
(let [[k v] node]
(if (and (= :fill k) v)
[k color]
node))
node)))
(rest (rest svg-hiccup)))))))

View File

@ -0,0 +1,43 @@
(ns status-im.react-native.js-dependencies)
(def action-button #js {:default #js {:Item #js {}}})
(def android-sms-listener #js {})
(def autolink #js {:default #js {}})
(def config #js {:default #js {}})
(def camera #js {:constants #js {}})
(def circle-checkbox #js {})
(def contacts #js {})
(def dialogs #js {})
(def dismiss-keyboard #js {})
(def drawer #js {})
(def emoji-picker #js {:default #js {}})
(def fs #js {})
(def http-bridge #js {})
(def i18n #js {})
(def image-crop-picker #js {})
(def image-resizer #js {})
(def instabug #js {})
(def invertible-scroll-view #js {})
(def linear-gradient #js {})
(def mapbox-gl #js {:setAccessToken (fn [])})
(def nfc #js {})
(def orientation #js {})
(def popup-menu #js {})
(def qr-code #js {})
(def random-bytes #js {})
(def react-native
#js {:NativeModules #js {}
:Animated #js {:View #js {}
:Text #js {}}
:DeviceEventEmitter #js {:addListener (fn [])}
:Dimensions #js {:get (fn [])}})
(def realm #js {:schemaVersion (fn [])
:close (fn [])})
(def sortable-listview #js {})
(def swiper #js {})
(def vector-icons #js {:default #js {}})
(def webview-bridge #js {:default #js {}})
(def svg #js {:default #js {}})
(def react-native-fcm #js {:default #js {}})

View File

@ -0,0 +1,36 @@
(ns status-im.react-native.resources)
(def add-icon nil)
(def att nil)
(def chat-icon nil)
(def icon-close-gray nil)
(def logo-icon nil)
(def nav-back-icon nil)
(def user-no-photo nil)
(def online-icon nil)
(def play nil)
(def trash-icon nil)
(def v nil)
(def contacts
{:auction-house nil
:mkr-market nil
:oaken-water-meter nil
:flight-delays-suck nil
:jarrad nil
:firstblood nil
:gnosis nil
:melonport nil
:bchat nil
:dentacoin nil
:augur nil
:ethlance nil
:commiteth nil
:etherplay nil})
(def assets
{:ethereum nil})
(def ui
{:empty-hashtags nil
:empty-recent nil})

View File

@ -0,0 +1,3 @@
(ns status-desktop-front.conf)
(def setting {:my-env "this-is-dev"})

View File

@ -0,0 +1,23 @@
(ns status-desktop-front.init
(:require [figwheel.client :as fw :include-macros true]
[status-desktop-front.core :as core]
[status-desktop-front.conf :as conf]
[reagent.core :as r]))
(enable-console-print!)
(fw/watch-and-reload
:websocket-url "ws://localhost:3449/figwheel-ws"
:jsload-callback 'start-descjop!)
(def cnt (r/atom 0))
(defn reloader [] @cnt [status-desktop-front.ui.screens.chat.view/chat])
(def root-el (r/as-element [reloader]))
(defn start-descjop! []
(println "CALLBACK")
(swap! cnt inc)
(core/init! conf/setting))
(start-descjop!)

View File

@ -0,0 +1,3 @@
(ns status-desktop-front.conf)
(def setting {:my-env "this-is-prod"})

View File

@ -0,0 +1,10 @@
(ns status-desktop-front.init
(:require [status-desktop-front.core :as core]
[status-desktop-front.conf :as conf]))
(enable-console-print!)
(defn start-descjop! []
(core/init! conf/setting))
(start-descjop!)

View File

@ -0,0 +1,13 @@
(ns figwheel-middleware
(:require [ring.middleware.resource :refer (wrap-resource)]))
(defn handler [request]
{:status 404
:headers {"Content-Type" "text/html"}
:body (str "Cannot find:" (:uri request))})
(def app
;; static resources in resources/public
;; (wrap-resource "public")
;; static resources from webjars dependencies
(wrap-resource handler "/META-INF/resources"))