diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0dcd9a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +*.class +*.jar +*.json +/.idea/ +/.lein-* +/.node-xmlhttprequest-sync-* +/.nrepl-port +/browser-tests/ +/checkouts +/classes +/config.edn +/dev-server/ +/dev-tests/ +/figwheel_server.log +/node_modules/ +/npm-debug.log +/pom.xml +/pom.xml.asc +/resources/public/contracts/build/ +/resources/public/css/ +/resources/public/js/ +/server/ +/smart-contracts-tests/ +/target \ No newline at end of file diff --git a/.projectile b/.projectile new file mode 100644 index 0000000..c6b8c6d --- /dev/null +++ b/.projectile @@ -0,0 +1,12 @@ +-/.cljs_node_repl +-/dev-server +-/figwheel_server.log +-/node_modules +-/resources/public/assets +-/resources/public/contracts/build +-/resources/public/css +-/resources/public/fonts +-/resources/public/icons +-/resources/public/js/compiled +-/server +-/target diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d921d3d --- /dev/null +++ b/LICENSE @@ -0,0 +1,214 @@ +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM +CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + +a) in the case of the initial Contributor, the initial code and +documentation distributed under this Agreement, and + +b) in the case of each subsequent Contributor: + +i) changes to the Program, and + +ii) additions to the Program; + +where such changes and/or additions to the Program originate from and are +distributed by that particular Contributor. A Contribution 'originates' from +a Contributor if it was added to the Program by such Contributor itself or +anyone acting on such Contributor's behalf. Contributions do not include +additions to the Program which: (i) are separate modules of software +distributed in conjunction with the Program under their own license +agreement, and (ii) are not derivative works of the Program. + +"Contributor" means any person or entity that distributes the Program. + +"Licensed Patents" mean patent claims licensable by a Contributor which are +necessarily infringed by the use or sale of its Contribution alone or when +combined with the Program. + +"Program" means the Contributions distributed in accordance with this +Agreement. + +"Recipient" means anyone who receives the Program under this Agreement, +including all Contributors. + +2. GRANT OF RIGHTS + +a) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free copyright license to +reproduce, prepare derivative works of, publicly display, publicly perform, +distribute and sublicense the Contribution of such Contributor, if any, and +such derivative works, in source code and object code form. + +b) Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free patent license under +Licensed Patents to make, use, sell, offer to sell, import and otherwise +transfer the Contribution of such Contributor, if any, in source code and +object code form. This patent license shall apply to the combination of the +Contribution and the Program if, at the time the Contribution is added by the +Contributor, such addition of the Contribution causes such combination to be +covered by the Licensed Patents. The patent license shall not apply to any +other combinations which include the Contribution. No hardware per se is +licensed hereunder. + +c) Recipient understands that although each Contributor grants the licenses +to its Contributions set forth herein, no assurances are provided by any +Contributor that the Program does not infringe the patent or other +intellectual property rights of any other entity. Each Contributor disclaims +any liability to Recipient for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, each Recipient hereby +assumes sole responsibility to secure any other intellectual property rights +needed, if any. For example, if a third party patent license is required to +allow Recipient to distribute the Program, it is Recipient's responsibility +to acquire that license before distributing the Program. + +d) Each Contributor represents that to its knowledge it has sufficient +copyright rights in its Contribution, if any, to grant the copyright license +set forth in this Agreement. + +3. REQUIREMENTS + +A Contributor may choose to distribute the Program in object code form under +its own license agreement, provided that: + +a) it complies with the terms and conditions of this Agreement; and + +b) its license agreement: + +i) effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title +and non-infringement, and implied warranties or conditions of merchantability +and fitness for a particular purpose; + +ii) effectively excludes on behalf of all Contributors all liability for +damages, including direct, indirect, special, incidental and consequential +damages, such as lost profits; + +iii) states that any provisions which differ from this Agreement are offered +by that Contributor alone and not by any other party; and + +iv) states that source code for the Program is available from such +Contributor, and informs licensees how to obtain it in a reasonable manner on +or through a medium customarily used for software exchange. + +When the Program is made available in source code form: + +a) it must be made available under this Agreement; and + +b) a copy of this Agreement must be included with each copy of the Program. + +Contributors may not remove or alter any copyright notices contained within +the Program. + +Each Contributor must identify itself as the originator of its Contribution, +if any, in a manner that reasonably allows subsequent Recipients to identify +the originator of the Contribution. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain responsibilities with +respect to end users, business partners and the like. While this license is +intended to facilitate the commercial use of the Program, the Contributor who +includes the Program in a commercial product offering should do so in a +manner which does not create potential liability for other Contributors. +Therefore, if a Contributor includes the Program in a commercial product +offering, such Contributor ("Commercial Contributor") hereby agrees to defend +and indemnify every other Contributor ("Indemnified Contributor") against any +losses, damages and costs (collectively "Losses") arising from claims, +lawsuits and other legal actions brought by a third party against the +Indemnified Contributor to the extent caused by the acts or omissions of such +Commercial Contributor in connection with its distribution of the Program in +a commercial product offering. The obligations in this section do not apply +to any claims or Losses relating to any actual or alleged intellectual +property infringement. In order to qualify, an Indemnified Contributor must: +a) promptly notify the Commercial Contributor in writing of such claim, and +b) allow the Commercial Contributor to control, and cooperate with the +Commercial Contributor in, the defense and any related settlement +negotiations. The Indemnified Contributor may participate in any such claim +at its own expense. + +For example, a Contributor might include the Program in a commercial product +offering, Product X. That Contributor is then a Commercial Contributor. If +that Commercial Contributor then makes performance claims, or offers +warranties related to Product X, those performance claims and warranties are +such Commercial Contributor's responsibility alone. Under this section, the +Commercial Contributor would have to defend claims against the other +Contributors related to those performance claims and warranties, and if a +court requires any other Contributor to pay any damages as a result, the +Commercial Contributor must pay those damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON +AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER +EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR +CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the +appropriateness of using and distributing the Program and assumes all risks +associated with its exercise of rights under this Agreement , including but +not limited to the risks and costs of program errors, compliance with +applicable laws, damage to or loss of data, programs or equipment, and +unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY +CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION +LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE +EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES. + +7. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of the +remainder of the terms of this Agreement, and without further action by the +parties hereto, such provision shall be reformed to the minimum extent +necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Program itself +(excluding combinations of the Program with other software or hardware) +infringes such Recipient's patent(s), then such Recipient's rights granted +under Section 2(b) shall terminate as of the date such litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it fails to +comply with any of the material terms or conditions of this Agreement and +does not cure such failure in a reasonable period of time after becoming +aware of such noncompliance. If all Recipient's rights under this Agreement +terminate, Recipient agrees to cease use and distribution of the Program as +soon as reasonably practicable. However, Recipient's obligations under this +Agreement and any licenses granted by Recipient relating to the Program shall +continue and survive. + +Everyone is permitted to copy and distribute copies of this Agreement, but in +order to avoid inconsistency the Agreement is copyrighted and may only be +modified in the following manner. The Agreement Steward reserves the right to +publish new versions (including revisions) of this Agreement from time to +time. No one other than the Agreement Steward has the right to modify this +Agreement. The Eclipse Foundation is the initial Agreement Steward. The +Eclipse Foundation may assign the responsibility to serve as the Agreement +Steward to a suitable separate entity. Each new version of the Agreement will +be given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly +stated in Sections 2(a) and 2(b) above, Recipient receives no rights or +licenses to the intellectual property of any Contributor under this +Agreement, whether expressly, by implication, estoppel or otherwise. All +rights in the Program not expressly granted under this Agreement are +reserved. + +This Agreement is governed by the laws of the State of New York and the +intellectual property laws of the United States of America. No party to this +Agreement will bring a legal action under this Agreement more than one year +after the cause of action arose. Each party waives its rights to a jury trial +in any resulting litigation. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0fc6f81 --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# Free Lunch + +Based on [MemeFactory](https://github.com/district0x/memefactory). + +## Install + +### [Leiningen](https://leiningen.org/) + +``` +brew install leiningen +``` + +### [Node](https://nodejs.org/) + +``` +brew install node +``` + +### [Ganache](https://truffleframework.com/ganache) + +``` +npm install -g ganache-cli +``` + +### [IPFS](https://ipfs.io/) + +``` +brew install ipfs +``` + +### [Solidity](https://github.com/ethereum/solidity) + +``` +brew install solidity +``` + +## Develop + +### Ganache + +``` +ganache-cli -p 8549 +``` + +### IPFS + +``` +ipfs daemon +``` + +### Solidity + +``` +lein solc auto +``` + +### FreeLunch Server + +``` +lein repl +``` + +```clj +(start-server!) +``` + +### FreeLunch UI + +``` +lein repl +``` + +```clj +(start-ui!) +``` + +Open http://localhost:4598/. diff --git a/dev/user.clj b/dev/user.clj new file mode 100644 index 0000000..8c2013b --- /dev/null +++ b/dev/user.clj @@ -0,0 +1,27 @@ +(ns user + (:require [figwheel-sidecar.repl-api])) + +(defn start-server! [] + (figwheel-sidecar.repl-api/start-figwheel! + (assoc-in (figwheel-sidecar.config/fetch-config) + [:data :figwheel-options :server-port] 4578) + "dev-server") + (figwheel-sidecar.repl-api/cljs-repl "dev-server")) + +(defn start-ui! [] + (figwheel-sidecar.repl-api/start-figwheel! + (figwheel-sidecar.config/fetch-config) + "dev") + (figwheel-sidecar.repl-api/cljs-repl "dev")) + +(defn start-tests! [] + (figwheel-sidecar.repl-api/start-figwheel! + (assoc-in (figwheel-sidecar.config/fetch-config) + [:data :figwheel-options :server-port] 4579) + "server-tests") + (figwheel-sidecar.repl-api/cljs-repl "server-tests")) + +(comment + (start-ui!) + (start-server!) + (start-tests!)) diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..928cb32 --- /dev/null +++ b/project.clj @@ -0,0 +1,160 @@ +(defproject free-lunch "1.0.0" + :description "Free Lunch on the Ethereum blockchain" + :url "https://github.com/domkm/free-lunch" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[akiroz.re-frame/storage "0.1.2"] + [camel-snake-kebab "0.4.0"] + [cljs-web3 "0.19.0-0-10"] + [cljsjs/buffer "5.1.0-1"] + [cljsjs/d3 "4.12.0-0"] + [cljsjs/react-infinite "0.13.0-0"] + [com.andrewmcveigh/cljs-time "0.5.2"] + [com.taoensso/encore "2.92.0"] + [com.taoensso/timbre "4.10.0"] + [district0x/bignumber "1.0.3"] + [district0x/cljs-ipfs-native "0.0.5-SNAPSHOT"] + [district0x/cljs-solidity-sha3 "1.0.0"] + [district0x/district-cljs-utils "1.0.3"] + [district0x/district-encryption "1.0.0"] + [district0x/district-format "1.0.0"] + [district0x/district-format "1.0.1"] + [district0x/district-graphql-utils "1.0.5"] + [district0x/district-server-config "1.0.1"] + [district0x/district-server-db "1.0.3"] + [district0x/district-server-graphql "1.0.15"] + [district0x/district-server-logging "1.0.2"] + [district0x/district-server-middleware-logging "1.0.0"] + [district0x/district-server-smart-contracts "1.0.8"] + [district0x/district-server-web3 "1.0.1"] + [district0x/district-server-web3-watcher "1.0.2"] + [district0x/district-time "1.0.0"] + [district0x/district-ui-component-active-account "1.0.0"] + [district0x/district-ui-component-active-account-balance "1.0.0"] + [district0x/district-ui-component-form "0.1.10-SNAPSHOT"] + [district0x/district-ui-component-notification "1.0.0"] + [district0x/district-ui-component-tx-button "1.0.0"] + [district0x/district-ui-graphql "1.0.6"] + [district0x/district-ui-logging "1.0.1"] + [district0x/district-ui-notification "1.0.1"] + [district0x/district-ui-now "1.0.2"] + [district0x/district-ui-reagent-render "1.0.1"] + [district0x/district-ui-router "1.0.3"] + [district0x/district-ui-router-google-analytics "1.0.0"] + [district0x/district-ui-smart-contracts "1.0.5"] + [district0x/district-ui-web3 "1.0.1"] + [district0x/district-ui-web3-account-balances "1.0.2"] + [district0x/district-ui-web3-accounts "1.0.5"] + [district0x/district-ui-web3-balances "1.0.2"] + [district0x/district-ui-web3-sync-now "1.0.3"] + [district0x/district-ui-web3-tx "1.0.9"] + [district0x/district-ui-web3-tx-id "1.0.1"] + [district0x/district-ui-web3-tx-log "1.0.2"] + [district0x/district-ui-window-size "1.0.1"] + [district0x/district-web3-utils "1.0.2"] + [district0x/re-frame-ipfs-fx "0.0.2"] + [medley "1.0.0"] + [mount "0.1.12"] + [org.clojars.mmb90/cljs-cache "0.1.4"] + [org.clojure/clojurescript "1.10.238"] + [org.clojure/core.match "0.3.0-alpha4"] + [print-foo-cljs "2.0.3"] + [re-frame "0.10.5"]] + + :exclusions [express-graphql + cljsjs/react-with-addons] + + :plugins [[lein-auto "0.1.2"] + [lein-cljsbuild "1.1.7"] + [lein-figwheel "0.5.16"] + [lein-shell "0.5.0"] + [lein-solc "1.0.1"] + [lein-doo "0.1.8"] + [lein-npm "0.6.2"] + [lein-pdo "0.1.1"]] + + :npm {:dependencies [;; needed until v0.6.13 is officially released + [chalk "2.3.0"] + [express-graphql "./resources/libs/express-graphql-0.6.13.tgz"] + [graphql-tools "3.0.1"] + [graphql "0.13.1"] + [express "4.15.3"] + [cors "2.8.4"] + [graphql-fields "1.0.2"] + [solc "0.4.20"] + [source-map-support "0.5.3"] + [ws "4.0.0"] + ;; this isn't required directly by free-lunch but 0.6.1 is broken and + ;; district0x/district-server-web3 needs [ganache-core "2.0.2"] who also needs "ethereumjs-wallet": "~0.6.0" + ;; https://github.com/ethereumjs/ethereumjs-wallet/issues/64 + [ethereumjs-wallet "0.6.0"]]} + + :solc {:src-path "resources/public/contracts/src" + :build-path "resources/public/contracts/build" + :solc-err-only true + :verbose false + :wc true + :contracts :all} + + :source-paths ["src"] + + :figwheel {:server-port 4598 + :css-dirs ["resources/public/css"] + :repl-eval-timeout 30000} + + :clean-targets ^{:protect false} ["resources/public/js/compiled" "target" "server" "dev-server" "resources/public/js/compiled" "resources/public/contracts/build"] + + :aliases {"clean-prod-server" ["shell" "rm" "-rf" "server"] + "build-prod-server" ["do" ["clean-prod-server"] ["cljsbuild" "once" "server"]] + "build-prod-ui" ["do" ["clean"] ["cljsbuild" "once" "ui"]] + "build-prod" ["pdo" ["build-prod-server"] ["build-prod-ui"]]} + + :profiles {:dev {:dependencies [[org.clojure/clojure "1.9.0"] + [binaryage/devtools "0.9.10"] + [com.cemerick/piggieback "0.2.2"] + [figwheel-sidecar "0.5.16"] + [org.clojure/tools.reader "1.3.0"] + [re-frisk "0.5.3"]] + :source-paths ["dev" "src"] + :resource-paths ["resources"]}} + + :cljsbuild {:builds [{:id "dev-server" + :source-paths ["src/free_lunch/server" "src/free_lunch/shared"] + :figwheel {:on-jsload "free-lunch.server.dev/on-jsload"} + :compiler {:main "free-lunch.server.dev" + :output-to "dev-server/free-lunch.js" + :output-dir "dev-server" + :target :nodejs + :optimizations :none + :closure-defines {goog.DEBUG true} + :source-map true}} + {:id "dev" + :source-paths ["src/free_lunch/ui" "src/free_lunch/shared"] + :figwheel {:on-jsload "district.ui.reagent-render/rerender"} + :compiler {:main "free-lunch.ui.core" + :output-to "resources/public/js/compiled/app.js" + :output-dir "resources/public/js/compiled/out" + :asset-path "js/compiled/out" + :source-map-timestamp true + :preloads [print.foo.preloads.devtools + re-frisk.preload] + :closure-defines {goog.DEBUG true} + :external-config {:devtools/config {:features-to-install :all}}}} + {:id "server" + :source-paths ["src"] + :compiler {:main "free-lunch.server.core" + :output-to "server/free-lunch.js" + :output-dir "server" + :target :nodejs + :optimizations :simple + :source-map "server/free-lunch.js.map" + :closure-defines {goog.DEBUG false} + :pretty-print false}} + {:id "ui" + :source-paths ["src"] + :compiler {:main "free-lunch.ui.core" + :output-to "resources/public/js/compiled/app.js" + :optimizations :advanced + :closure-defines {goog.DEBUG false} + :pretty-print false + :pseudo-names false}}]}) diff --git a/resources/libs/express-graphql-0.6.13.tgz b/resources/libs/express-graphql-0.6.13.tgz new file mode 100644 index 0000000..97738c4 Binary files /dev/null and b/resources/libs/express-graphql-0.6.13.tgz differ diff --git a/resources/public/assets/icons/about.png b/resources/public/assets/icons/about.png new file mode 100644 index 0000000..5a68e93 Binary files /dev/null and b/resources/public/assets/icons/about.png differ diff --git a/resources/public/assets/icons/about.svg b/resources/public/assets/icons/about.svg new file mode 100644 index 0000000..6c02d38 --- /dev/null +++ b/resources/public/assets/icons/about.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/conveyer.png b/resources/public/assets/icons/conveyer.png new file mode 100644 index 0000000..de206da Binary files /dev/null and b/resources/public/assets/icons/conveyer.png differ diff --git a/resources/public/assets/icons/dankregistry.png b/resources/public/assets/icons/dankregistry.png new file mode 100644 index 0000000..5e9714a Binary files /dev/null and b/resources/public/assets/icons/dankregistry.png differ diff --git a/resources/public/assets/icons/dankregistry.svg b/resources/public/assets/icons/dankregistry.svg new file mode 100644 index 0000000..f890b4d --- /dev/null +++ b/resources/public/assets/icons/dankregistry.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/district0x-footer-logo.png b/resources/public/assets/icons/district0x-footer-logo.png new file mode 100644 index 0000000..ec9b782 Binary files /dev/null and b/resources/public/assets/icons/district0x-footer-logo.png differ diff --git a/resources/public/assets/icons/dropdown.png b/resources/public/assets/icons/dropdown.png new file mode 100644 index 0000000..9ed14bd Binary files /dev/null and b/resources/public/assets/icons/dropdown.png differ diff --git a/resources/public/assets/icons/ethereum.png b/resources/public/assets/icons/ethereum.png new file mode 100644 index 0000000..5e0a4f1 Binary files /dev/null and b/resources/public/assets/icons/ethereum.png differ diff --git a/resources/public/assets/icons/gears-button-bg-l.png b/resources/public/assets/icons/gears-button-bg-l.png new file mode 100644 index 0000000..a035d72 Binary files /dev/null and b/resources/public/assets/icons/gears-button-bg-l.png differ diff --git a/resources/public/assets/icons/gears-button-bg-r.png b/resources/public/assets/icons/gears-button-bg-r.png new file mode 100644 index 0000000..015db32 Binary files /dev/null and b/resources/public/assets/icons/gears-button-bg-r.png differ diff --git a/resources/public/assets/icons/gears-button-bg.png b/resources/public/assets/icons/gears-button-bg.png new file mode 100644 index 0000000..df703c3 Binary files /dev/null and b/resources/public/assets/icons/gears-button-bg.png differ diff --git a/resources/public/assets/icons/howitworks.png b/resources/public/assets/icons/howitworks.png new file mode 100644 index 0000000..2d8c013 Binary files /dev/null and b/resources/public/assets/icons/howitworks.png differ diff --git a/resources/public/assets/icons/howitworks.svg b/resources/public/assets/icons/howitworks.svg new file mode 100644 index 0000000..0a489b8 --- /dev/null +++ b/resources/public/assets/icons/howitworks.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/leaderboard.png b/resources/public/assets/icons/leaderboard.png new file mode 100644 index 0000000..f150359 Binary files /dev/null and b/resources/public/assets/icons/leaderboard.png differ diff --git a/resources/public/assets/icons/leaderboard.svg b/resources/public/assets/icons/leaderboard.svg new file mode 100644 index 0000000..c7b0522 --- /dev/null +++ b/resources/public/assets/icons/leaderboard.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/leaderboardicon.png b/resources/public/assets/icons/leaderboardicon.png new file mode 100644 index 0000000..e3cf0e8 Binary files /dev/null and b/resources/public/assets/icons/leaderboardicon.png differ diff --git a/resources/public/assets/icons/marketplace.png b/resources/public/assets/icons/marketplace.png new file mode 100644 index 0000000..8e3ae61 Binary files /dev/null and b/resources/public/assets/icons/marketplace.png differ diff --git a/resources/public/assets/icons/marketplace.svg b/resources/public/assets/icons/marketplace.svg new file mode 100644 index 0000000..aea8268 --- /dev/null +++ b/resources/public/assets/icons/marketplace.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/marketplaceicon.png b/resources/public/assets/icons/marketplaceicon.png new file mode 100644 index 0000000..0a836f9 Binary files /dev/null and b/resources/public/assets/icons/marketplaceicon.png differ diff --git a/resources/public/assets/icons/mememouth.png b/resources/public/assets/icons/mememouth.png new file mode 100644 index 0000000..87c8841 Binary files /dev/null and b/resources/public/assets/icons/mememouth.png differ diff --git a/resources/public/assets/icons/memesubmiticon.png b/resources/public/assets/icons/memesubmiticon.png new file mode 100644 index 0000000..439f6d3 Binary files /dev/null and b/resources/public/assets/icons/memesubmiticon.png differ diff --git a/resources/public/assets/icons/mf.png b/resources/public/assets/icons/mf.png new file mode 100644 index 0000000..693a6ba Binary files /dev/null and b/resources/public/assets/icons/mf.png differ diff --git a/resources/public/assets/icons/mymemefolio-green.png b/resources/public/assets/icons/mymemefolio-green.png new file mode 100644 index 0000000..e15be2d Binary files /dev/null and b/resources/public/assets/icons/mymemefolio-green.png differ diff --git a/resources/public/assets/icons/mymemefolio.png b/resources/public/assets/icons/mymemefolio.png new file mode 100644 index 0000000..d92e232 Binary files /dev/null and b/resources/public/assets/icons/mymemefolio.png differ diff --git a/resources/public/assets/icons/mymemefolio.svg b/resources/public/assets/icons/mymemefolio.svg new file mode 100644 index 0000000..ae6e454 --- /dev/null +++ b/resources/public/assets/icons/mymemefolio.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/mysettings.png b/resources/public/assets/icons/mysettings.png new file mode 100644 index 0000000..f9805b3 Binary files /dev/null and b/resources/public/assets/icons/mysettings.png differ diff --git a/resources/public/assets/icons/mysettings.svg b/resources/public/assets/icons/mysettings.svg new file mode 100644 index 0000000..11b5dc8 --- /dev/null +++ b/resources/public/assets/icons/mysettings.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/assets/icons/newicon.png b/resources/public/assets/icons/newicon.png new file mode 100644 index 0000000..5fd2429 Binary files /dev/null and b/resources/public/assets/icons/newicon.png differ diff --git a/resources/public/assets/icons/randomicon.png b/resources/public/assets/icons/randomicon.png new file mode 100644 index 0000000..bf50987 Binary files /dev/null and b/resources/public/assets/icons/randomicon.png differ diff --git a/resources/public/assets/icons/rarefindicon.png b/resources/public/assets/icons/rarefindicon.png new file mode 100644 index 0000000..fbaa449 Binary files /dev/null and b/resources/public/assets/icons/rarefindicon.png differ diff --git a/resources/public/assets/icons/search-background.png b/resources/public/assets/icons/search-background.png new file mode 100644 index 0000000..74cb994 Binary files /dev/null and b/resources/public/assets/icons/search-background.png differ diff --git a/resources/public/assets/icons/search.png b/resources/public/assets/icons/search.png new file mode 100644 index 0000000..8207f24 Binary files /dev/null and b/resources/public/assets/icons/search.png differ diff --git a/resources/public/assets/images/examplememe0.png b/resources/public/assets/images/examplememe0.png new file mode 100644 index 0000000..7d93957 Binary files /dev/null and b/resources/public/assets/images/examplememe0.png differ diff --git a/resources/public/assets/images/examplememe1.png b/resources/public/assets/images/examplememe1.png new file mode 100644 index 0000000..1e66eb6 Binary files /dev/null and b/resources/public/assets/images/examplememe1.png differ diff --git a/resources/public/assets/images/examplememe2.png b/resources/public/assets/images/examplememe2.png new file mode 100644 index 0000000..418e4da Binary files /dev/null and b/resources/public/assets/images/examplememe2.png differ diff --git a/resources/public/assets/images/logo.svg b/resources/public/assets/images/logo.svg new file mode 100644 index 0000000..e87529e --- /dev/null +++ b/resources/public/assets/images/logo.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/public/contracts/src/FreeLunch.sol b/resources/public/contracts/src/FreeLunch.sol new file mode 100644 index 0000000..72e25a3 --- /dev/null +++ b/resources/public/contracts/src/FreeLunch.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.4.24; + +contract FreeLunch { + + mapping (string => bytes) freebies; + + event Freebie(string); + + function setFreebie(string k, bytes dataHash) public { + freebies[k] = dataHash; + emit Freebie(k); + } + + function loadFreebie(string k) public view returns (string, bytes) { + return (k, freebies[k]); + } + +} diff --git a/resources/public/fonts/Bungee-Regular.ttf b/resources/public/fonts/Bungee-Regular.ttf new file mode 100644 index 0000000..3229ee2 Binary files /dev/null and b/resources/public/fonts/Bungee-Regular.ttf differ diff --git a/resources/public/fonts/icons.eot b/resources/public/fonts/icons.eot new file mode 100644 index 0000000..0eb3fdc Binary files /dev/null and b/resources/public/fonts/icons.eot differ diff --git a/resources/public/fonts/icons.svg b/resources/public/fonts/icons.svg new file mode 100644 index 0000000..b1d55c2 --- /dev/null +++ b/resources/public/fonts/icons.svg @@ -0,0 +1,56 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/public/fonts/icons.ttf b/resources/public/fonts/icons.ttf new file mode 100644 index 0000000..db29505 Binary files /dev/null and b/resources/public/fonts/icons.ttf differ diff --git a/resources/public/fonts/icons.woff b/resources/public/fonts/icons.woff new file mode 100644 index 0000000..0e86dee Binary files /dev/null and b/resources/public/fonts/icons.woff differ diff --git a/resources/public/icons/fonts/memefactory.eot b/resources/public/icons/fonts/memefactory.eot new file mode 100755 index 0000000..60fc1a7 Binary files /dev/null and b/resources/public/icons/fonts/memefactory.eot differ diff --git a/resources/public/icons/fonts/memefactory.svg b/resources/public/icons/fonts/memefactory.svg new file mode 100755 index 0000000..12d9250 --- /dev/null +++ b/resources/public/icons/fonts/memefactory.svg @@ -0,0 +1,264 @@ + + + + + + +{ + "fontFamily": "free-lunch", + "majorVersion": 1, + "minorVersion": 0, + "version": "Version 1.0", + "fontId": "free-lunch", + "psName": "free-lunch", + "subFamily": "Regular", + "fullName": "free-lunch", + "description": "Font generated by IcoMoon." +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/public/icons/fonts/memefactory.ttf b/resources/public/icons/fonts/memefactory.ttf new file mode 100755 index 0000000..8891076 Binary files /dev/null and b/resources/public/icons/fonts/memefactory.ttf differ diff --git a/resources/public/icons/fonts/memefactory.woff b/resources/public/icons/fonts/memefactory.woff new file mode 100755 index 0000000..f74fa4c Binary files /dev/null and b/resources/public/icons/fonts/memefactory.woff differ diff --git a/resources/public/icons/style.css b/resources/public/icons/style.css new file mode 100755 index 0000000..a1b4d0f --- /dev/null +++ b/resources/public/icons/style.css @@ -0,0 +1,1192 @@ +@font-face { + font-family: 'free-lunch'; + src: url('fonts/free-lunch.eot?caukyf'); + src: url('fonts/free-lunch.eot?caukyf#iefix') format('embedded-opentype'), + url('fonts/free-lunch.ttf?caukyf') format('truetype'), + url('fonts/free-lunch.woff?caukyf') format('woff'), + url('fonts/free-lunch.svg?caukyf#free-lunch') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class^="icon-"], [class*=" icon-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'free-lunch' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-about:before { + content: "\e900"; +} +.icon-arrow-down2:before { + content: "\e901"; +} +.icon-arrow-right:before { + content: "\e902"; + color: #2d398f; +} +.icon-cart-green-blue .path1:before { + content: "\e903"; + color: rgb(6, 23, 21); + opacity: 0.27; +} +.icon-cart-green-blue .path2:before { + content: "\e904"; + margin-left: -1.7958984375em; + color: rgb(0, 208, 183); +} +.icon-cart-green-blue .path3:before { + content: "\e905"; + margin-left: -1.7958984375em; + color: rgb(8, 76, 161); +} +.icon-cart-green-blue .path4:before { + content: "\e906"; + margin-left: -1.7958984375em; + color: rgb(8, 76, 161); +} +.icon-cart-green-blue .path5:before { + content: "\e907"; + margin-left: -1.7958984375em; + color: rgb(8, 76, 161); +} +.icon-cart:before { + content: "\e908"; +} +.icon-chevron-down:before { + content: "\e909"; +} +.icon-diamond .path1:before { + content: "\e90a"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-diamond .path2:before { + content: "\e90b"; + margin-left: -1.6474609375em; + color: rgb(255, 234, 0); +} +.icon-diamond .path3:before { + content: "\e90c"; + margin-left: -1.6474609375em; + color: rgb(157, 11, 219); +} +.icon-diamond .path4:before { + content: "\e90d"; + margin-left: -1.6474609375em; + color: rgb(31, 242, 200); +} +.icon-district0x:before { + content: "\e90e"; +} +.icon-ethereum:before { + content: "\e90f"; + color: #2d398f; +} +.icon-how-it-works:before { + content: "\e910"; +} +.icon-magnifier:before { + content: "\e911"; + color: #0d3f1a; +} +.icon-mf-logo .path1:before { + content: "\e912"; + color: rgb(255, 0, 144); +} +.icon-mf-logo .path2:before { + content: "\e913"; + margin-left: -1.2958984375em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-logo .path3:before { + content: "\e914"; + margin-left: -1.2958984375em; + color: rgb(4, 255, 204); +} +.icon-mf-logo .path4:before { + content: "\e915"; + margin-left: -1.2958984375em; + color: rgb(4, 255, 204); +} +.icon-mf-logo .path5:before { + content: "\e916"; + margin-left: -1.2958984375em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-logo .path6:before { + content: "\e917"; + margin-left: -1.2958984375em; + color: rgb(255, 234, 0); +} +.icon-mf-logo .path7:before { + content: "\e918"; + margin-left: -1.2958984375em; + color: rgb(33, 33, 33); +} +.icon-mf-logo .path8:before { + content: "\e919"; + margin-left: -1.2958984375em; + color: rgb(255, 0, 144); +} +.icon-mf-search .path1:before { + content: "\e91a"; + color: rgb(4, 255, 204); +} +.icon-mf-search .path2:before { + content: "\e91b"; + margin-left: -1.0263671875em; + color: rgb(4, 255, 204); +} +.icon-mf-search .path3:before { + content: "\e91c"; + margin-left: -1.0263671875em; + color: rgb(255, 0, 144); +} +.icon-mf-search .path4:before { + content: "\e91d"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-search .path5:before { + content: "\e91e"; + margin-left: -1.0263671875em; + color: rgb(4, 255, 204); +} +.icon-mf-search .path6:before { + content: "\e91f"; + margin-left: -1.0263671875em; + color: rgb(4, 255, 204); +} +.icon-mf-search .path7:before { + content: "\e920"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-search .path8:before { + content: "\e921"; + margin-left: -1.0263671875em; + color: rgb(255, 234, 0); +} +.icon-mf-search .path9:before { + content: "\e922"; + margin-left: -1.0263671875em; + color: rgb(33, 33, 33); +} +.icon-mf-search .path10:before { + content: "\e923"; + margin-left: -1.0263671875em; + color: rgb(255, 0, 144); +} +.icon-mf-search .path11:before { + content: "\e924"; + margin-left: -1.0263671875em; + color: rgb(255, 234, 0); +} +.icon-mf-search .path12:before { + content: "\e925"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-search2 .path1:before { + content: "\e926"; + color: rgb(4, 255, 204); +} +.icon-mf-search2 .path2:before { + content: "\e927"; + margin-left: -1.0263671875em; + color: rgb(172, 255, 110); +} +.icon-mf-search2 .path3:before { + content: "\e928"; + margin-left: -1.0263671875em; + color: rgb(255, 0, 144); +} +.icon-mf-search2 .path4:before { + content: "\e929"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-search2 .path5:before { + content: "\e92a"; + margin-left: -1.0263671875em; + color: rgb(4, 255, 204); +} +.icon-mf-search2 .path6:before { + content: "\e92b"; + margin-left: -1.0263671875em; + color: rgb(4, 255, 204); +} +.icon-mf-search2 .path7:before { + content: "\e92c"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mf-search2 .path8:before { + content: "\e92d"; + margin-left: -1.0263671875em; + color: rgb(255, 234, 0); +} +.icon-mf-search2 .path9:before { + content: "\e92e"; + margin-left: -1.0263671875em; + color: rgb(33, 33, 33); +} +.icon-mf-search2 .path10:before { + content: "\e92f"; + margin-left: -1.0263671875em; + color: rgb(255, 0, 144); +} +.icon-mf-search2 .path11:before { + content: "\e930"; + margin-left: -1.0263671875em; + color: rgb(0, 186, 226); +} +.icon-mf-search2 .path12:before { + content: "\e931"; + margin-left: -1.0263671875em; + color: rgb(0, 0, 0); + opacity: 0.12; +} +.icon-mouth .path1:before { + content: "\e932"; + color: rgb(33, 33, 33); +} +.icon-mouth .path2:before { + content: "\e933"; + margin-left: -3.37890625em; + color: rgb(255, 0, 144); +} +.icon-network .path1:before { + content: "\e934"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-network .path2:before { + content: "\e935"; + margin-left: -1.7958984375em; + color: rgb(255, 242, 0); +} +.icon-network .path3:before { + content: "\e936"; + margin-left: -1.7958984375em; + color: rgb(230, 24, 85); +} +.icon-network2 .path1:before { + content: "\e937"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-network2 .path2:before { + content: "\e938"; + margin-left: -1.7958984375em; + color: rgb(255, 0, 144); +} +.icon-network2 .path3:before { + content: "\e939"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path4:before { + content: "\e93a"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path5:before { + content: "\e93b"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path6:before { + content: "\e93c"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path7:before { + content: "\e93d"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path8:before { + content: "\e93e"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path9:before { + content: "\e93f"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path10:before { + content: "\e940"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path11:before { + content: "\e941"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path12:before { + content: "\e942"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path13:before { + content: "\e943"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path14:before { + content: "\e944"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path15:before { + content: "\e945"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path16:before { + content: "\e946"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path17:before { + content: "\e947"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path18:before { + content: "\e948"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path19:before { + content: "\e949"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-network2 .path20:before { + content: "\e94a"; + margin-left: -1.7958984375em; + color: rgb(255, 234, 0); +} +.icon-new .path1:before { + content: "\e94b"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-new .path2:before { + content: "\e94c"; + margin-left: -1.689453125em; + color: rgb(255, 234, 0); +} +.icon-new .path3:before { + content: "\e94d"; + margin-left: -1.689453125em; + color: rgb(255, 0, 144); +} +.icon-new .path4:before { + content: "\e94e"; + margin-left: -1.689453125em; + color: rgb(255, 0, 144); +} +.icon-new .path5:before { + content: "\e94f"; + margin-left: -1.689453125em; + color: rgb(255, 0, 144); +} +.icon-new .path6:before { + content: "\e950"; + margin-left: -1.689453125em; + color: rgb(255, 255, 255); +} +.icon-new .path7:before { + content: "\e951"; + margin-left: -1.689453125em; + color: rgb(255, 0, 144); +} +.icon-new .path8:before { + content: "\e952"; + margin-left: -1.689453125em; + color: rgb(255, 0, 144); +} +.icon-pattern1 .path1:before { + content: "\e953"; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path2:before { + content: "\e954"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path3:before { + content: "\e955"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path4:before { + content: "\e956"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path5:before { + content: "\e957"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path6:before { + content: "\e958"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path7:before { + content: "\e959"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path8:before { + content: "\e95a"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path9:before { + content: "\e95b"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path10:before { + content: "\e95c"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path11:before { + content: "\e95d"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path12:before { + content: "\e95e"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path13:before { + content: "\e95f"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path14:before { + content: "\e960"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path15:before { + content: "\e961"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path16:before { + content: "\e962"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path17:before { + content: "\e963"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path18:before { + content: "\e964"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path19:before { + content: "\e965"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path20:before { + content: "\e966"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path21:before { + content: "\e967"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path22:before { + content: "\e968"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path23:before { + content: "\e969"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path24:before { + content: "\e96a"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path25:before { + content: "\e96b"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path26:before { + content: "\e96c"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path27:before { + content: "\e96d"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path28:before { + content: "\e96e"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path29:before { + content: "\e96f"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path30:before { + content: "\e970"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path31:before { + content: "\e971"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path32:before { + content: "\e972"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path33:before { + content: "\e973"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path34:before { + content: "\e974"; + margin-left: -26.4267578125em; + color: rgb(255, 0, 144); +} +.icon-pattern1 .path35:before { + content: "\e975"; + margin-left: -26.4267578125em; + color: rgb(255, 0, 144); +} +.icon-pattern1 .path36:before { + content: "\e976"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path37:before { + content: "\e977"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path38:before { + content: "\e978"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path39:before { + content: "\e979"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path40:before { + content: "\e97a"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path41:before { + content: "\e97b"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path42:before { + content: "\e97c"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path43:before { + content: "\e97d"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path44:before { + content: "\e97e"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path45:before { + content: "\e97f"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path46:before { + content: "\e980"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path47:before { + content: "\e981"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path48:before { + content: "\e982"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path49:before { + content: "\e983"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path50:before { + content: "\e984"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path51:before { + content: "\e985"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path52:before { + content: "\e986"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path53:before { + content: "\e987"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path54:before { + content: "\e988"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path55:before { + content: "\e989"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path56:before { + content: "\e98a"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path57:before { + content: "\e98b"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path58:before { + content: "\e98c"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path59:before { + content: "\e98d"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path60:before { + content: "\e98e"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path61:before { + content: "\e98f"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path62:before { + content: "\e990"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path63:before { + content: "\e991"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path64:before { + content: "\e992"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path65:before { + content: "\e993"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path66:before { + content: "\e994"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path67:before { + content: "\e995"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path68:before { + content: "\e996"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path69:before { + content: "\e997"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path70:before { + content: "\e998"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path71:before { + content: "\e999"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path72:before { + content: "\e99a"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path73:before { + content: "\e99b"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path74:before { + content: "\e99c"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path75:before { + content: "\e99d"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path76:before { + content: "\e99e"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path77:before { + content: "\e99f"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path78:before { + content: "\e9a0"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path79:before { + content: "\e9a1"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path80:before { + content: "\e9a2"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path81:before { + content: "\e9a3"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path82:before { + content: "\e9a4"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path83:before { + content: "\e9a5"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path84:before { + content: "\e9a6"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path85:before { + content: "\e9a7"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path86:before { + content: "\e9a8"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path87:before { + content: "\e9a9"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path88:before { + content: "\e9aa"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path89:before { + content: "\e9ab"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path90:before { + content: "\e9ac"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path91:before { + content: "\e9ad"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path92:before { + content: "\e9ae"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path93:before { + content: "\e9af"; + margin-left: -26.4267578125em; + color: rgb(255, 0, 144); +} +.icon-pattern1 .path94:before { + content: "\e9b0"; + margin-left: -26.4267578125em; + color: rgb(255, 0, 144); +} +.icon-pattern1 .path95:before { + content: "\e9b1"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path96:before { + content: "\e9b2"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path97:before { + content: "\e9b3"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path98:before { + content: "\e9b4"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path99:before { + content: "\e9b5"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path100:before { + content: "\e9b6"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path101:before { + content: "\e9b7"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path102:before { + content: "\e9b8"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path103:before { + content: "\e9b9"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path104:before { + content: "\e9ba"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path105:before { + content: "\e9bb"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path106:before { + content: "\e9bc"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path107:before { + content: "\e9bd"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path108:before { + content: "\e9be"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path109:before { + content: "\e9bf"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path110:before { + content: "\e9c0"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path111:before { + content: "\e9c1"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path112:before { + content: "\e9c2"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path113:before { + content: "\e9c3"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path114:before { + content: "\e9c4"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path115:before { + content: "\e9c5"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path116:before { + content: "\e9c6"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path117:before { + content: "\e9c7"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path118:before { + content: "\e9c8"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path119:before { + content: "\e9c9"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path120:before { + content: "\e9ca"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path121:before { + content: "\e9cb"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 0); +} +.icon-pattern1 .path122:before { + content: "\e9cc"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path123:before { + content: "\e9cd"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path124:before { + content: "\e9ce"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path125:before { + content: "\e9cf"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path126:before { + content: "\e9d0"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path127:before { + content: "\e9d1"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path128:before { + content: "\e9d2"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path129:before { + content: "\e9d3"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-pattern1 .path130:before { + content: "\e9d4"; + margin-left: -26.4267578125em; + color: rgb(4, 255, 204); +} +.icon-pattern1 .path131:before { + content: "\e9d5"; + margin-left: -26.4267578125em; + color: rgb(255, 255, 255); +} +.icon-pattern1 .path132:before { + content: "\e9d6"; + margin-left: -26.4267578125em; + color: rgb(46, 2, 72); +} +.icon-portfolio:before { + content: "\e9d7"; +} +.icon-portfolio2 .path1:before { + content: "\e9d8"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-portfolio2 .path2:before { + content: "\e9d9"; + margin-left: -1.7958984375em; + color: rgb(205, 255, 30); +} +.icon-portfolio2 .path3:before { + content: "\e9da"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path4:before { + content: "\e9db"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path5:before { + content: "\e9dc"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path6:before { + content: "\e9dd"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path7:before { + content: "\e9de"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path8:before { + content: "\e9df"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-portfolio2 .path9:before { + content: "\e9e0"; + margin-left: -1.7958984375em; + color: rgb(18, 178, 171); +} +.icon-settings:before { + content: "\e9e1"; +} +.icon-thumb-up-green-blue .path1:before { + content: "\e9e2"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-thumb-up-green-blue .path2:before { + content: "\e9e3"; + margin-left: -1.6591796875em; + color: rgb(172, 255, 111); +} +.icon-thumb-up-green-blue .path3:before { + content: "\e9e4"; + margin-left: -1.6591796875em; + color: rgb(9, 0, 124); +} +.icon-thumb-up-green-blue .path4:before { + content: "\e9e5"; + margin-left: -1.6591796875em; + color: rgb(172, 255, 111); +} +.icon-thumb-up-green-blue .path5:before { + content: "\e9e6"; + margin-left: -1.6591796875em; + color: rgb(172, 255, 111); +} +.icon-thumb-up:before { + content: "\e9e7"; +} +.icon-thumb-up2:before { + content: "\e9e8"; +} +.icon-trophy:before { + content: "\e9e9"; +} +.icon-trophy2 .path1:before { + content: "\e9ea"; + color: rgb(6, 23, 21); + opacity: 0.0600; +} +.icon-trophy2 .path2:before { + content: "\e9eb"; + margin-left: -1.7978515625em; + color: rgb(255, 234, 0); +} +.icon-trophy2 .path3:before { + content: "\e9ec"; + margin-left: -1.7978515625em; + color: rgb(255, 0, 144); +} +.icon-checkbox:before { + content: "\e9ed"; +} diff --git a/resources/public/index.html b/resources/public/index.html new file mode 100644 index 0000000..deab063 --- /dev/null +++ b/resources/public/index.html @@ -0,0 +1,18 @@ + + + + + + Free Lunch + + + + + + +
+
+ + + + diff --git a/resources/schema.graphql b/resources/schema.graphql new file mode 100644 index 0000000..c09a83a --- /dev/null +++ b/resources/schema.graphql @@ -0,0 +1,13 @@ +scalar Date +scalar Keyword + +type Query { + freebies: [Freebie] +} + +type Freebie { + freebie_id: ID + freebie_name: String + freebie_description: String + freebie_streetAddress: String +} diff --git a/src/free_lunch/server/contract/free_lunch.cljs b/src/free_lunch/server/contract/free_lunch.cljs new file mode 100644 index 0000000..1b91663 --- /dev/null +++ b/src/free_lunch/server/contract/free_lunch.cljs @@ -0,0 +1,14 @@ +(ns free-lunch.server.contract.free-lunch + (:require + [district.server.smart-contracts :refer [contract-call instance contract-address]] + [free-lunch.shared.contract.free-lunch :refer [parse-load-freebie]])) + +(defn set-freebie [freebie-key freebie-data & [opts]] + (contract-call :free-lunch :set-freebie freebie-key freebie-data (merge {:gas 100000} opts))) + +(defn load-freebie [freebie-key] + (parse-load-freebie (contract-call :free-lunch :load-freebie freebie-key))) + +(defn freebie-event [contract-key & args] + (apply contract-call contract-key :Freebie args)) + diff --git a/src/free_lunch/server/core.cljs b/src/free_lunch/server/core.cljs new file mode 100644 index 0000000..240a73c --- /dev/null +++ b/src/free_lunch/server/core.cljs @@ -0,0 +1,64 @@ +(ns free-lunch.server.core + (:require + [cljs-time.core :as t] + [cljs.nodejs :as nodejs] + [district.graphql-utils :as graphql-utils] + [district.server.config :refer [config]] + [district.server.graphql :as graphql] + [district.server.graphql.utils :as utils] + [district.server.logging] + [district.server.middleware.logging :refer [logging-middlewares]] + [district.server.web3-watcher] + [free-lunch.server.db] + [free-lunch.server.deployer] + [free-lunch.server.generator] + [free-lunch.server.graphql-resolvers :refer [resolvers-map]] + [free-lunch.server.syncer] + [free-lunch.shared.graphql-schema :refer [graphql-schema]] + [free-lunch.shared.smart-contracts] + [mount.core :as mount] + [taoensso.timbre :refer-macros [info warn error]])) + +(nodejs/enable-util-print!) + +(defn -main [& _] + (-> (mount/with-args + {:config {:default {:web3 {:port 8545}}} + :smart-contracts {:contracts-var #'free-lunch.shared.smart-contracts/smart-contracts} + :logging {:level "info" + :console? true} + :graphql {:port 6300 + :middlewares [logging-middlewares] + :schema (utils/build-schema graphql-schema + resolvers-map + {:kw->gql-name graphql-utils/kw->gql-name + :gql-name->kw graphql-utils/gql-name->kw}) + :field-resolver (utils/build-default-field-resolver graphql-utils/gql-name->kw) + :path "/graphql" + :graphiql true} + :web3-watcher {:on-online (fn [] + (warn "Ethereum node went online again") + (mount/stop #'free-lunch.server.db/db) + (mount/start #'free-lunch.server.db/db + #'free-lunch.server.syncer/syncer)) + :on-offline (fn [] + (warn "Ethereum node went offline") + (mount/stop #'free-lunch.server.syncer/syncer))} + :syncer {:ipfs-config {:host "http://127.0.0.1:5001" :endpoint "/api/v0"}}}) + (mount/except [#'free-lunch.server.deployer/deployer + #'free-lunch.server.generator/generator]) + (mount/start)) + (warn "System started" {:config @config})) + +(set! *main-cli-fn* -main) + +(comment + (-> (mount/only [#'free-lunch.server.generator/generator]) + mount/stop + cljs.pprint/pprint) + (-> (mount/with-args {:generator {:memes/use-accounts 1 + :memes/items-per-account 3 + :memes/scenarios [:scenario/buy]}}) + (mount/only [#'free-lunch.server.generator/generator]) + mount/start + cljs.pprint/pprint)) diff --git a/src/free_lunch/server/db.cljs b/src/free_lunch/server/db.cljs new file mode 100644 index 0000000..df47fbe --- /dev/null +++ b/src/free_lunch/server/db.cljs @@ -0,0 +1,71 @@ +(ns free-lunch.server.db + (:require + [district.server.config :refer [config]] + [district.server.db :as db] + [district.server.db.column-types :refer [address not-nil default-nil default-zero default-false sha3-hash primary-key]] + [district.server.db.honeysql-extensions] + [honeysql.core :as sql] + [honeysql.helpers :refer [merge-where merge-order-by merge-left-join defhelper]] + [medley.core :as medley] + [mount.core :as mount :refer [defstate]] + [print.foo :refer [look] :include-macros true] + [taoensso.timbre :as logging :refer-macros [info warn error]])) + +(declare start) +(declare stop) +(defstate ^{:on-reload :noop} db + :start (start (merge + (:db @config) + (:db (mount/args)))) + :stop (stop)) + +(def ipfs-hash (sql/call :char (sql/inline 46))) + +(def freebies-columns + [[:freebie/id :varchar primary-key not-nil] + [:freebie/name :varchar not-nil] + [:freebie/street-address :varchar] + [:freebie/description :varchar not-nil]]) + +(def freebies-column-names (map first freebies-columns)) + +(defn start [opts] + (db/run! {:create-table [:freebies] + :with-columns [freebies-columns]})) + +(defn stop [] + (db/run! {:drop-table [:freebies]})) + +(defn create-insert-fn [table-name column-names & [{:keys [:insert-or-replace?]}]] + (fn [item] + (let [item (select-keys item column-names)] + (db/run! {(if insert-or-replace? :insert-or-replace-into :insert-into) table-name + :columns (keys item) + :values [(vals item)]})))) + +(defn create-update-fn [table-name column-names id-keys] + (fn [item] + (let [item (select-keys item column-names) + id-keys (if (sequential? id-keys) id-keys [id-keys])] + (db/run! {:update table-name + :set item + :where (concat + [:and] + (for [id-key id-keys] + [:= id-key (get item id-key)]))})))) + +(defn create-get-fn [table-name id-keys] + (let [id-keys (if (sequential? id-keys) id-keys [id-keys])] + (fn [item fields] + (cond-> (db/get {:select (if (sequential? fields) fields [fields]) + :from [table-name] + :where (concat + [:and] + (for [id-key id-keys] + [:= id-key (get item id-key)]))}) + (keyword? fields) fields)))) + +(def insert-freebie! (create-insert-fn :freebies freebies-column-names)) +(def insert-or-replace-freebie! (create-insert-fn :freebies freebies-column-names {:insert-or-replace? true})) +(def update-freebie! (create-update-fn :freebies freebies-column-names [:freebie/place-id])) +(def get-freebie (create-get-fn :freebies :freebie/place-id)) diff --git a/src/free_lunch/server/deployer.cljs b/src/free_lunch/server/deployer.cljs new file mode 100644 index 0000000..cdfd94d --- /dev/null +++ b/src/free_lunch/server/deployer.cljs @@ -0,0 +1,25 @@ +(ns free-lunch.server.deployer + (:require + [cljs-web3.core :as web3] + [cljs-web3.eth :as web3-eth] + [district.cljs-utils :refer [rand-str]] + [district.server.config :refer [config]] + [district.server.smart-contracts :refer [contract-event-in-tx contract-address deploy-smart-contract! write-smart-contracts!]] + [district.server.web3 :refer [web3]] + [mount.core :as mount :refer [defstate]])) + +(declare deploy) +(defstate ^{:on-reload :noop} deployer + :start (deploy (merge (:deployer @config) + (:deployer (mount/args))))) + +(defn deploy-free-lunch! [default-opts] + (deploy-smart-contract! :free-lunch (merge default-opts {:gas 1000000}))) + +(defn deploy [{:keys [:write?] + :as deploy-opts}] + (let [accounts (web3-eth/accounts @web3) + deploy-opts (merge {:from (last accounts)} deploy-opts)] + (deploy-free-lunch! deploy-opts) + (when write? + (write-smart-contracts!)))) diff --git a/src/free_lunch/server/dev.cljs b/src/free_lunch/server/dev.cljs new file mode 100644 index 0000000..960f250 --- /dev/null +++ b/src/free_lunch/server/dev.cljs @@ -0,0 +1,109 @@ +(ns free-lunch.server.dev + (:require + [bignumber.core :as bn] + [camel-snake-kebab.core :as cs :include-macros true] + [cljs-time.core :as t] + [cljs-web3.core :as web3] + [cljs-web3.eth :as web3-eth] + [cljs-web3.evm :as web3-evm] + [cljs.nodejs :as nodejs] + [cljs.pprint :as pprint] + [clojure.pprint :refer [print-table]] + [clojure.string :as str] + [district.graphql-utils :as graphql-utils] + [district.server.config :refer [config]] + [district.server.db :as db] + [district.server.graphql :as graphql] + [district.server.graphql.utils :as utils] + [district.server.logging :refer [logging]] + [district.server.middleware.logging :refer [logging-middlewares]] + [district.server.smart-contracts] + [district.server.web3 :refer [web3]] + [district.server.web3-watcher] + [free-lunch.server.db] + [free-lunch.server.deployer] + [free-lunch.server.generator] + [free-lunch.server.graphql-resolvers :refer [resolvers-map]] + [free-lunch.server.ipfs] + [free-lunch.server.syncer] + [free-lunch.shared.graphql-schema :refer [graphql-schema]] + [free-lunch.shared.smart-contracts] + [goog.date.Date] + [graphql-query.core :refer [graphql-query]] + [mount.core :as mount] + [print.foo :include-macros true])) + +(nodejs/enable-util-print!) + +(def graphql-module (nodejs/require "graphql")) +(def parse-graphql (aget graphql-module "parse")) +(def visit (aget graphql-module "visit")) + +(defn on-jsload [] + (graphql/restart {:schema (utils/build-schema graphql-schema + resolvers-map + {:kw->gql-name graphql-utils/kw->gql-name + :gql-name->kw graphql-utils/gql-name->kw}) + :field-resolver (utils/build-default-field-resolver graphql-utils/gql-name->kw)})) + +(defn deploy-to-mainnet [] + (mount/stop #'district.server.web3/web3 + #'district.server.smart-contracts/smart-contracts) + (mount/start-with-args (merge + (mount/args) + {:web3 {:port 8545} + :deployer {:write? true + :gas-price (web3/to-wei 4 :gwei)}}) + #'district.server.web3/web3 + #'district.server.smart-contracts/smart-contracts)) + +(defn redeploy [] + (mount/stop) + (-> (mount/with-args + (merge + (mount/args) + {:deployer {:write? true}})) + (mount/start) + pprint/pprint)) + +(defn resync [] + (mount/stop #'free-lunch.server.db/db + #'free-lunch.server.syncer/syncer) + (-> (mount/start #'free-lunch.server.db/db + #'free-lunch.server.syncer/syncer) + pprint/pprint)) + +(defn -main [& _] + (-> (mount/with-args + {:config {:default {:logging {:level "info" + :console? true} + :graphql {:port 6300 + :middlewares [logging-middlewares] + :schema (utils/build-schema graphql-schema + resolvers-map + {:kw->gql-name graphql-utils/kw->gql-name + :gql-name->kw graphql-utils/gql-name->kw}) + :field-resolver (utils/build-default-field-resolver graphql-utils/gql-name->kw) + :path "/graphql" + :graphiql true} + :web3 {:port 8549} + :deployer {} + :ipfs {:host "http://127.0.0.1:5001" :endpoint "/api/v0" :gateway "http://127.0.0.1:8080/ipfs"} + :smart-contracts {:contracts-var #'free-lunch.shared.smart-contracts/smart-contracts + :print-gas-usage? true + :auto-mining? true} + :syncer {:initial-param-query {:meme-registry-db [:max-total-supply + :max-auction-duration + :deposit]}}}}}) + (mount/except [#'free-lunch.server.deployer/deployer + #'free-lunch.server.generator/generator]) + (mount/start) + pprint/pprint)) + +(set! *main-cli-fn* -main) + +(comment + (resync)) + +(comment + (redeploy)) diff --git a/src/free_lunch/server/generator.cljs b/src/free_lunch/server/generator.cljs new file mode 100644 index 0000000..8397b09 --- /dev/null +++ b/src/free_lunch/server/generator.cljs @@ -0,0 +1,59 @@ +(ns free-lunch.server.generator + (:require + [bignumber.core :as bn] + [cljs-ipfs-api.files :as ipfs-files] + [cljs-web3.core :as web3] + [cljs-web3.eth :as web3-eth] + [cljs-web3.evm :as web3-evm] + [cljs-web3.utils :refer [js->cljkk camel-case]] + [district.cljs-utils :refer [rand-str]] + [district.format :as format] + [district.server.config :refer [config]] + [district.server.smart-contracts :refer [contract-address contract-call instance]] + [district.server.web3 :refer [web3]] + [free-lunch.server.contract.free-lunch :as free-lunch] + [free-lunch.server.deployer] + [mount.core :as mount :refer [defstate]] + [print.foo :refer [look] :include-macros true] + [taoensso.timbre :as log]) + (:require-macros + [free-lunch.shared.macros :refer [try-catch]])) + +(def fs (js/require "fs")) + +(declare start) +(defstate ^{:on-reload :noop} generator :start (start (merge (:generator @config) + (:generator (mount/args))))) + +(defn upload-freebie-data [data] + (let [json (format/clj->json data)] + (log/info "Uploading freebie data" {:freebie-data json} ::upload-freebie-data) + (js/Promise. + (fn [resolve reject] + (ipfs-files/add + (js/Buffer.from json) + (fn [err {data-hash :Hash}] + (if err + (log/error "IPFS error" {:error err} ::upload-freebie-data) + (do + (log/info "Uploaded freebie data received " {:data-hash data-hash} ::upload-freebie-data) + (resolve data-hash))))))))) + +(def freebies + {"ChIJyWEHuEmuEmsRm9hTkapTCrk" #:freebie{:name "Rhythmboat Cruises" + :description "Cruises and shit"} + "ChIJqwS6fjiuEmsRJAMiOY9MSms" #:freebie{:name "Private Charter Sydney Habour Cruise" + :description "private"}}) + +(defn generate-freebies [{:keys [accounts]}] + (log/info "Going to generate" freebies ::generate-freebies) + (doseq [[k m] freebies] + (-> m + (upload-freebie-data) + (.then (fn [data-hash] + (try-catch + (free-lunch/set-freebie k data-hash {:from (first accounts)}))))))) + +(defn start [opts] + (let [opts (assoc opts :accounts (web3-eth/accounts @web3))] + (generate-freebies opts))) diff --git a/src/free_lunch/server/graphql_resolvers.cljs b/src/free_lunch/server/graphql_resolvers.cljs new file mode 100644 index 0000000..acfc235 --- /dev/null +++ b/src/free_lunch/server/graphql_resolvers.cljs @@ -0,0 +1,26 @@ +(ns free-lunch.server.graphql-resolvers + (:require + [bignumber.core :as bn] + [cljs-time.core :as t] + [cljs-web3.core :as web3-core] + [cljs-web3.eth :as web3-eth] + [cljs.nodejs :as nodejs] + [clojure.string :as str] + [clojure.string :as str] + [clojure.string :as string] + [district.graphql-utils :as graphql-utils] + [district.server.config :refer [config]] + [district.server.db :as db] + [district.server.web3 :as web3] + [honeysql.core :as sql] + [honeysql.helpers :as sqlh] + [print.foo :refer [look] :include-macros true] + [taoensso.timbre :as log]) + (:require-macros + [free-lunch.shared.macros :refer [try-catch-throw]])) + +(def resolvers-map + {:Query {:freebies (fn [& _] + (db/all + {:select [:*] + :from [:freebies]}))}}) diff --git a/src/free_lunch/server/ipfs.cljs b/src/free_lunch/server/ipfs.cljs new file mode 100644 index 0000000..2cf197c --- /dev/null +++ b/src/free_lunch/server/ipfs.cljs @@ -0,0 +1,17 @@ +(ns free-lunch.server.ipfs + (:require + [cljs-ipfs-api.core :as ipfs-core] + [district.server.config :refer [config]] + [mount.core :as mount :refer [defstate]])) + +(defn start [opts] + (try + (let [conn (ipfs-core/init-ipfs opts)] + conn) + (catch :default e + (throw (js/Error. "Can't connect to IPFS node"))))) + +(defstate ipfs + :start (start (merge (:ipfs @config) + (:ipfs (mount/args)))) + :stop :stopped) diff --git a/src/free_lunch/server/syncer.cljs b/src/free_lunch/server/syncer.cljs new file mode 100644 index 0000000..dcf161c --- /dev/null +++ b/src/free_lunch/server/syncer.cljs @@ -0,0 +1,83 @@ +(ns free-lunch.server.syncer + (:require + [bignumber.core :as bn] + [camel-snake-kebab.core :as cs :include-macros true] + [cljs-ipfs-api.files :as ifiles] + [cljs-web3.core :as web3] + [cljs-web3.eth :as web3-eth] + [district.server.config :refer [config]] + [district.server.smart-contracts :as smart-contracts :refer [replay-past-events]] + [district.server.web3 :refer [web3]] + [district.web3-utils :as web3-utils] + [free-lunch.server.contract.free-lunch :as free-lunch] + [free-lunch.server.db :as db] + [free-lunch.server.deployer] + [free-lunch.server.generator] + [mount.core :as mount :refer [defstate]] + [print.foo :refer [look] :include-macros true] + [taoensso.timbre :as log]) + (:require-macros + [free-lunch.shared.macros :refer [try-catch]])) + +(declare start) +(declare stop) +(defstate ^{:on-reload :noop} syncer + :start (start (merge + (:syncer @config) + (:syncer (mount/args)))) + :stop (stop syncer)) + +(def info-text "smart-contract event") +(def error-text "smart-contract event error") + +(defn get-ipfs-data [data-hash & [default]] + (js/Promise. + (fn [resolve reject] + (log/info (str "Downloading: " "/ipfs/" data-hash) ::get-ipfs-data) + (ifiles/fget (str "/ipfs/" data-hash) + {:req-opts {:compress false}} + (fn [err content] + (try + (if (and + (not err) + (not-empty content)) + ;; Get returns the entire content, this include CIDv0+more meta+data + ;; TODO add better way of parsing get return + (-> (re-find #".+(\{.+\})" content) + second + js/JSON.parse + (js->clj :keywordize-keys true) + resolve) + (throw (js/Error. (str (or err "Error") " when downloading " "/ipfs/" data-hash )))) + (catch :default e + (log/error error-text {:error (ex-message e)} ::get-meme-data) + (when goog.DEBUG + (resolve default))))))))) + +(defn on-freebie [_ event] + (let [freebie (-> event + :args + vals + first + free-lunch/load-freebie)] + (-> freebie + :freebie/data-hash + get-ipfs-data ;; TODO deal with removal + (.then (fn [data err] + (reduce-kv + (fn [m k v] + (assoc m (keyword :freebie k) v)) + {:freebie/id (:freebie/id freebie)} ; TODO necessary? + data))) + (.then db/insert-or-replace-freebie!)))) + +(defn start [{:keys [:initial-param-query] :as opts}] + (when-not (web3/connected? @web3) + (throw (js/Error. "Can't connect to Ethereum node"))) + [(-> (free-lunch/freebie-event :free-lunch {} {:from-block 0 :to-block "latest"}) + (replay-past-events on-freebie)) + (free-lunch/freebie-event :free-lunch {} "latest" on-freebie)]) + +(defn stop [syncer] + (doseq [filter (remove nil? @syncer)] + (web3-eth/stop-watching! filter (fn [err])))) diff --git a/src/free_lunch/shared/contract/free_lunch.cljs b/src/free_lunch/shared/contract/free_lunch.cljs new file mode 100644 index 0000000..b2bcd37 --- /dev/null +++ b/src/free_lunch/shared/contract/free_lunch.cljs @@ -0,0 +1,13 @@ +(ns free-lunch.shared.contract.free-lunch + (:require + [bignumber.core :as bn] + [cljs-web3.core :as web3] + [district.web3-utils :refer [web3-time->local-date-time empty-address? wei->eth-number]])) + +(def load-freebie-keys [:freebie/id + :freebie/data-hash]) + +(defn parse-load-freebie [freebie & [{:keys [:parse-dates?]}]] + (when freebie + (let [freebie (zipmap load-freebie-keys freebie)] + (update freebie :freebie/data-hash web3/to-ascii)))) diff --git a/src/free_lunch/shared/graphql_schema.cljs b/src/free_lunch/shared/graphql_schema.cljs new file mode 100644 index 0000000..25f8de8 --- /dev/null +++ b/src/free_lunch/shared/graphql_schema.cljs @@ -0,0 +1,6 @@ +(ns free-lunch.shared.graphql-schema + (:require-macros + [free-lunch.shared.macros :refer [slurp-resource]])) + +(def graphql-schema + (slurp-resource "schema.graphql")) diff --git a/src/free_lunch/shared/macros.clj b/src/free_lunch/shared/macros.clj new file mode 100644 index 0000000..6f5151f --- /dev/null +++ b/src/free_lunch/shared/macros.clj @@ -0,0 +1,31 @@ +(ns free-lunch.shared.macros + (:require + [cljs.core :as cljs] + [clojure.java.io :as io] + [taoensso.timbre :as log])) + +(defn- compiletime-info + [and-env and-form ns] + (let [meta-info (meta and-form)] + {:ns (str (ns-name ns)) + :line (:line meta-info) + :file (:file meta-info)})) + +(defmacro try-catch [& body] + `(try + ~@body + (catch js/Object e# + (log/error "Unexpected exception" (merge {:error (cljs/ex-message e#)} ~(compiletime-info &env &form *ns*)))))) + +(defmacro try-catch-throw [& body] + `(try + ~@body + (catch js/Object e# + (log/error "Unexpected exception" (merge {:error (cljs/ex-message e#)} ~(compiletime-info &env &form *ns*))) + (throw (js/Error. e#))))) + +(defmacro slurp-resource [s] + (-> s + io/resource + io/reader + slurp)) diff --git a/src/free_lunch/shared/routes.cljs b/src/free_lunch/shared/routes.cljs new file mode 100644 index 0000000..d6f29bc --- /dev/null +++ b/src/free_lunch/shared/routes.cljs @@ -0,0 +1,3 @@ +(ns free-lunch.shared.routes) + +(def routes [["/" :route/home]]) \ No newline at end of file diff --git a/src/free_lunch/shared/smart_contracts.cljs b/src/free_lunch/shared/smart_contracts.cljs new file mode 100644 index 0000000..424815f --- /dev/null +++ b/src/free_lunch/shared/smart_contracts.cljs @@ -0,0 +1,6 @@ +(ns free-lunch.shared.smart-contracts) + +(def smart-contracts +{:free-lunch + {:name "FreeLunch", + :address "0x07a457d878bf363e0bb5aa0b096092f941e19962"}}) \ No newline at end of file diff --git a/src/free_lunch/shared/utils.cljs b/src/free_lunch/shared/utils.cljs new file mode 100644 index 0000000..968bdb0 --- /dev/null +++ b/src/free_lunch/shared/utils.cljs @@ -0,0 +1,26 @@ +(ns free-lunch.shared.utils + (:require + [bignumber.core :as bn] + [cljs.core.match :refer-macros [match]] + [district.web3-utils :as web3-utils] + [print.foo :refer [look] :include-macros true])) + +(def not-nil? (complement nil?)) + +(defn calculate-meme-auction-price [{:keys [:meme-auction/start-price + :meme-auction/end-price + :meme-auction/duration + :meme-auction/started-on] :as auction} now] + (let [seconds-passed (- now started-on) + total-price-change (- end-price start-price) + current-price-change (/ (* total-price-change seconds-passed) duration)] + (if (<= duration seconds-passed) + end-price + (+ start-price current-price-change)))) + +(defn parse-uint-date [date parse-as-date?] + (let [date (bn/number date)] + (match [(= 0 date) parse-as-date?] + [true _] nil + [false true] (web3-utils/web3-time->local-date-time date) + [false (:or nil false)] date))) diff --git a/src/free_lunch/ui/contract/free_lunch.cljs b/src/free_lunch/ui/contract/free_lunch.cljs new file mode 100644 index 0000000..004de65 --- /dev/null +++ b/src/free_lunch/ui/contract/free_lunch.cljs @@ -0,0 +1,34 @@ +(ns free-lunch.ui.contract.free-lunch + (:require + [cljs-web3.core :as web3] + [cljs-web3.eth :as web3-eth] + [cljs.spec.alpha :as s] + [district.ui.logging.events :as logging] + [district.ui.notification.events :as notification-events] + [district.ui.smart-contracts.queries :as contract-queries] + [district.ui.web3-accounts.queries :as account-queries] + [district.ui.web3-tx.events :as tx-events] + [district0x.re-frame.spec-interceptors :as spec-interceptors] + [goog.string :as gstring] + [print.foo :refer [look] :include-macros true] + [re-frame.core :as re-frame :refer [reg-event-fx]])) + +(def interceptors [re-frame/trim-v]) + +(re-frame/reg-event-fx + ::set-freebie + (fn [{:keys [db]} [_ {:keys [freebie/id]} {:keys [Hash]}]] + {:dispatch [::tx-events/send-tx + {:instance (contract-queries/instance db :free-lunch) + :fn :set-freebie + :args [id Hash] + :tx-opts {:from (account-queries/active-account db) + :gas 6000000} + :tx-id {::set-freebie id} + :on-tx-success [::set-freebie-success] + :on-tx-hash-error [::logging/error [::set-freebie]] + :on-tx-error [::logging/error [::set-freebie]]}]})) + +(re-frame/reg-event-fx + ::set-freebie-success + (constantly nil)) diff --git a/src/free_lunch/ui/core.cljs b/src/free_lunch/ui/core.cljs new file mode 100644 index 0000000..6de443c --- /dev/null +++ b/src/free_lunch/ui/core.cljs @@ -0,0 +1,57 @@ +(ns free-lunch.ui.core + (:require + [cljs.spec.alpha :as s] + [clojure.string :as str] + [district.ui.component.router :refer [router]] + [district.ui.graphql] + [district.ui.notification] + [district.ui.now] + [district.ui.reagent-render] + [district.ui.router] + [district.ui.smart-contracts] + [district.ui.web3] + [district.ui.web3-account-balances] + [district.ui.web3-accounts] + [district.ui.web3-sync-now] + [district.ui.web3-tx] + [district.ui.web3-tx-id] + [district.ui.web3-tx-log] + [district.ui.window-size] + [free-lunch.shared.graphql-schema :refer [graphql-schema]] + [free-lunch.shared.routes :refer [routes]] + [free-lunch.shared.smart-contracts :refer [smart-contracts]] + [free-lunch.ui.home.page] + [free-lunch.ui.ipfs] + [free-lunch.ui.subs] + [mount.core :as mount] + [print.foo :include-macros true] + [re-frisk.core :refer [enable-re-frisk!]])) + +(def ^boolean debug? js/goog.DEBUG) + +(defn dev-setup [] + (when debug? + (enable-console-print!) + (enable-re-frisk!))) + +(def skipped-contracts [:ds-guard :param-change-registry-db :meme-registry-db :minime-token-factory]) + +(defn ^:export init [] + (s/check-asserts debug?) + (dev-setup) + (-> (mount/with-args + (merge {:web3 {:url "http://localhost:8549"} + :smart-contracts {:contracts (apply dissoc smart-contracts skipped-contracts)} + ;; :web3-balances {:contracts (select-keys smart-contracts [:DANK])} + :web3-account-balances {:for-contracts [:ETH]} + :web3-tx-log {:open-on-tx-hash? true + :tx-costs-currencies [:USD]} + :reagent-render {:id "app" + :component-var #'router} + :router {:routes routes + :default-route :route/home} + ; :router-google-analytics {:enabled? (not debug?)} + :graphql {:schema graphql-schema + :url "http://localhost:6300/graphql"} + :ipfs {:host "http://127.0.0.1:5001" :endpoint "/api/v0"}})) + (mount/start))) diff --git a/src/free_lunch/ui/events.cljs b/src/free_lunch/ui/events.cljs new file mode 100644 index 0000000..031983c --- /dev/null +++ b/src/free_lunch/ui/events.cljs @@ -0,0 +1,21 @@ +(ns free-lunch.ui.events + (:require + [cljsjs.buffer] + [free-lunch.ui.contract.free-lunch :as free-lunch] + [print.foo :refer [look] :include-macros true] + [re-frame.core :as re-frame])) + +(defn- build-challenge-meta-string [{:keys [comment] :as data}] + (-> {:comment comment} + clj->js + js/JSON.stringify)) + +;; Adds the challenge to ipfs and if successfull dispatches ::create-challenge +(re-frame/reg-event-fx + ::add-freebie + (fn [{:keys [db]} [_ {:keys [] :as data}]] + (prn "Uploading freebie " data) + {:ipfs/call {:func "add" + :args [(-> data clj->js js/JSON.stringify js/buffer.Buffer.from)] + :on-success [::free-lunch/set-freebie data] + :on-error [::error]}})) diff --git a/src/free_lunch/ui/home/page.cljs b/src/free_lunch/ui/home/page.cljs new file mode 100644 index 0000000..f1c7c33 --- /dev/null +++ b/src/free_lunch/ui/home/page.cljs @@ -0,0 +1,68 @@ +(ns free-lunch.ui.home.page + (:require + [district.ui.component.page :refer [page]] + [district.ui.graphql.subs :as gql] + [free-lunch.shared.utils :as shared-utils] + [free-lunch.ui.contract.free-lunch :as free-lunch] + [free-lunch.ui.events :as ev] + [free-lunch.ui.utils :as utils] + [print.foo :refer [look] :include-macros true] + [re-frame.core :refer [subscribe dispatch]] + [react-infinite] + [reagent.core :as r])) + +(def freebies-query + [:freebies + [:freebie/id + :freebie/name]]) + +(defmethod page :route/home [] + (let [freebies (subscribe [::gql/query + {:queries [freebies-query]} + {:refetch-on #{::free-lunch/set-freebie-success}}]) + form (r/atom {}) + on-change (fn [k event] + (->> event + .-target + .-value + prn + ) + (->> event + .-target + .-value + (swap! form assoc k )) + (prn @form))] + (fn [] + [:div + [:form {:on-submit (fn [event] + (.preventDefault event) + (dispatch [::ev/add-freebie @form]) + (reset! form {}))} + [:label "ID" + [:input {:type "text" + :value (:freebie/id @form) + :on-change #(on-change :freebie/id %)}]] + [:br] + [:label "Name" + [:input {:type "text" + :value (:freebie/name @form) + :on-change #(on-change :freebie/name %)}]] + [:br] + [:label "Street Address" + [:input {:type "text" + :value (:freebie/street-address @form) + :on-change #(on-change :freebie/street-address %)}]] + [:br] + [:label "Description" + [:input {:type "text" + :value (:freebie/description @form) + :on-change #(on-change :freebie/description %)}]] + [:br] + [:input {:type "submit" :value "Submit"}]] + [:ul + (some->> @freebies + :freebies + (map (fn [{:keys [freebie/id freebie/name]}] + [:li {:key id} + name])) + doall)]]))) diff --git a/src/free_lunch/ui/ipfs.cljs b/src/free_lunch/ui/ipfs.cljs new file mode 100644 index 0000000..efcda18 --- /dev/null +++ b/src/free_lunch/ui/ipfs.cljs @@ -0,0 +1,17 @@ +(ns free-lunch.ui.ipfs + (:require + [district0x.re-frame.ipfs-fx :as ipfs-fx] + [mount.core :as mount :refer [defstate]] + [re-frame.core :as re-frame])) + +(def interceptors [re-frame/trim-v]) + +(re-frame/reg-event-fx + ::init-ipfs + [interceptors] + (fn [_ [config]] + {:ipfs/init config})) + +(defstate district-ui-ipfs + :start (re-frame/dispatch-sync [::init-ipfs (:ipfs (mount/args))]) + :stop ::stopped) diff --git a/src/free_lunch/ui/subs.cljs b/src/free_lunch/ui/subs.cljs new file mode 100644 index 0000000..c254bc8 --- /dev/null +++ b/src/free_lunch/ui/subs.cljs @@ -0,0 +1,11 @@ +(ns free-lunch.ui.subs + (:require + [re-frame.core :as re-frame])) + +(re-frame/reg-sub + ::active-page + (fn [db _] + (::active-page db))) + + + diff --git a/src/free_lunch/ui/utils.cljs b/src/free_lunch/ui/utils.cljs new file mode 100644 index 0000000..fde3d61 --- /dev/null +++ b/src/free_lunch/ui/utils.cljs @@ -0,0 +1,16 @@ +(ns free-lunch.ui.utils + (:require + [cemerick.url :as url] + [cljs-time.coerce :as time-coerce] + [district.ui.router.utils :as router-utils])) + +(defn gql-date->date + "parse GraphQL Date type as JS Date object ready to be formatted" + [gql-date] + (time-coerce/from-long (* 1000 gql-date))) + +(defn path [& args] + (str "#" (apply router-utils/resolve args))) + +(defn path-with-query [path query-params-map] + (str path "?" (url/map->query query-params-map)))