├── .gitignore
├── plotSVG
├── img
│ └── plot.png
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ ├── chart.cljs
│ └── plot_svg.cljs
├── lens
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── lens.cljs
├── contacts
├── .gitignore
├── public
│ ├── css
│ │ └── main.css
│ └── index.html
├── package.json
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── contacts.cljs
├── hoplife
├── .gitignore
├── package.json
├── public
│ ├── css
│ │ └── main.css
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── hoplife.cljs
├── inputs
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
├── src
│ ├── index.cljs.hl
│ └── demo
│ │ └── inputs.cljs
└── package-lock.json
├── tictactoe
├── .gitignore
├── package.json
├── public
│ ├── index.html
│ └── css
│ │ └── main.css
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ ├── tictactoe
│ ├── advanced.cljs
│ ├── basic.cljs
│ └── element.cljs
│ └── tictactoe.cljs
├── todoFRP
├── .gitignore
├── public
│ ├── image
│ │ └── bg.png
│ ├── index.html
│ └── css
│ │ └── main.css
├── package.json
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── todo_frp.cljs
├── tworker
├── .gitignore
├── package.json
├── public
│ └── index.html
├── src
│ └── demo
│ │ ├── demo_worker.cljs
│ │ └── tworker.cljs
├── README.md
└── shadow-cljs.edn
├── async-webinar
├── .gitignore
├── package.json
├── public
│ ├── index.html
│ └── css
│ │ └── main.css
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── async_webinar.cljs
├── demos-homepage
├── .gitignore
├── package.json
├── src
│ ├── macros
│ │ └── core.clj
│ ├── demo
│ │ └── homepage.cljs
│ └── hoplon
│ │ └── twitter
│ │ └── bootstrap.cljs
├── shadow-cljs.edn
├── public
│ ├── index.html
│ ├── css
│ │ └── main.css
│ └── image
│ │ └── Lambda_lc.svg
└── README.md
├── validated-form
├── .gitignore
├── src
│ ├── vform
│ │ └── core.clj
│ └── demo
│ │ └── validated_form.cljs
├── package.json
├── shadow-cljs.edn
├── public
│ ├── index.html
│ └── css
│ │ └── main.css
└── README.md
├── w3c-worker
├── .gitignore
├── package.json
├── src
│ ├── counter_worker
│ │ └── counts.cljs
│ └── demo
│ │ └── w3c_worker.cljs
├── public
│ └── index.html
├── README.md
└── shadow-cljs.edn
├── infinite-scroll
├── .gitignore
├── package.json
├── public
│ ├── index.html
│ └── css
│ │ └── main.css
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── infinite_scroll.cljs
├── counters
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── counter.cljs
├── infinite-scroll-paginated
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── infinite_scroll_paginated.cljs
├── Makefile
├── duracell
├── .gitignore
├── package.json
├── public
│ └── index.html
├── shadow-cljs.edn
├── README.md
└── src
│ └── demo
│ └── duracell.cljs
├── README.md
└── epl-v10.html
/.gitignore:
--------------------------------------------------------------------------------
1 | .gh-pages/
2 |
--------------------------------------------------------------------------------
/plotSVG/img/plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoplon/demos/HEAD/plotSVG/img/plot.png
--------------------------------------------------------------------------------
/lens/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/contacts/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/hoplife/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/inputs/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/plotSVG/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/tictactoe/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/todoFRP/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/todoFRP/public/image/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hoplon/demos/HEAD/todoFRP/public/image/bg.png
--------------------------------------------------------------------------------
/tworker/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/async-webinar/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/demos-homepage/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/validated-form/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/w3c-worker/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/infinite-scroll/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/counters/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .cpcache/
3 | .nrepl-*
4 | .shadow-cljs/
5 | node_modules/
6 | public/js/
7 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/js/
6 |
--------------------------------------------------------------------------------
/contacts/public/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 20px;
4 | }
5 |
6 | h1 {
7 | color: blue;
8 | }
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | help:
2 | @echo "USAGE: make [help|deploy]"
3 |
4 | deploy:
5 | cp -R .gh-pages/demos-homepage/* .gh-pages/
6 | ghp-import -p .gh-pages
7 |
--------------------------------------------------------------------------------
/contacts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/counters/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/hoplife/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/inputs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lens/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tictactoe/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/w3c-worker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/demos-homepage/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/infinite-scroll/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/duracell/.gitignore:
--------------------------------------------------------------------------------
1 | .clj-kondo/**/
2 | .nrepl-*
3 | .shadow-cljs/
4 | node_modules/
5 | public/cljs-runtime/
6 | public/dcells.js
7 | public/main.js
8 | public/shared.js
9 | public/manifest.edn
10 |
--------------------------------------------------------------------------------
/validated-form/src/vform/core.clj:
--------------------------------------------------------------------------------
1 | (ns vform.core
2 | (:require [javelin.core :refer [defc=]]))
3 |
4 | (defmacro defv [i c v]
5 | `(defc= ~i {:valid? (if (~v ~c) true false)
6 | :value ~c}))
7 |
--------------------------------------------------------------------------------
/hoplife/public/css/main.css:
--------------------------------------------------------------------------------
1 | table,th,td { margin:0; padding:0; border-spacing:0; }
2 | table { border:1px solid black; }
3 | td { width:16px; height:16px; cursor:pointer; }
4 | td.alive { background-color: black; }
5 |
--------------------------------------------------------------------------------
/duracell/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/plotSVG/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/todoFRP/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/tworker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/async-webinar/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/validated-form/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hoplon-demo",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "shadow-cljs": "2.25.8"
7 | },
8 | "dependencies": {
9 | "jquery": "^3.7.0"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/counters/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Counters
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lens/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AATree • Lens
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/plotSVG/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plot SVG Chart
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/w3c-worker/src/counter_worker/counts.cljs:
--------------------------------------------------------------------------------
1 | (ns counter-worker.counts)
2 |
3 | (def i (atom 0))
4 |
5 | (defn timed-count []
6 | (swap! i + 1)
7 | (.postMessage js/self @i)
8 | (.setTimeout js/self timed-count 500))
9 |
10 | (defn main []
11 | (timed-count))
12 |
--------------------------------------------------------------------------------
/duracell/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Duracell demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tworker/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | tworker demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/w3c-worker/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | W3C Worker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/contacts/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Contacts
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/hoplife/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hoplife
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/todoFRP/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hoplon • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/inputs/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Inputs - Hoplon Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/async-webinar/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Async Webinar Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/infinite-scroll/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Infinite scroll
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tictactoe/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hoplon • Tic Tac Toe
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Infinite scroll paginated
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/demos-homepage/src/macros/core.clj:
--------------------------------------------------------------------------------
1 | (ns macros.core
2 | (:require
3 | [clojure.java.io :as io]))
4 |
5 | (defmacro demo-dirs []
6 | (->> (. (io/file "../") listFiles)
7 | (filter #(and (.isDirectory %)
8 | (not (. (.getName %) (startsWith ".")))
9 | (not (.exists (io/file % ".no-demo")))))
10 | (map #(.getName %))
11 | sort
12 | vec))
13 |
--------------------------------------------------------------------------------
/inputs/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.inputs/init}}
8 | :devtools {:before-load demo.inputs/stop
9 | :after-load demo.inputs/start}}}}
10 |
--------------------------------------------------------------------------------
/contacts/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.contacts/init}}
8 | :devtools {:before-load demo.contacts/stop
9 | :after-load demo.contacts/start}}}}
10 |
--------------------------------------------------------------------------------
/counters/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.counter/init}}
8 | :devtools {:before-load demo.counter/stop
9 | :after-load demo.counter/start}}}}
10 |
--------------------------------------------------------------------------------
/hoplife/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.hoplife/init}}
8 | :devtools {:before-load demo.hoplife/stop
9 | :after-load demo.hoplife/start}}}}
10 |
--------------------------------------------------------------------------------
/plotSVG/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.plot-svg/init}}
8 | :devtools {:before-load demo.plot-svg/stop
9 | :after-load demo.plot-svg/start}}}}
10 |
--------------------------------------------------------------------------------
/todoFRP/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.todo-frp/init}}
8 | :devtools {:before-load demo.todo-frp/stop
9 | :after-load demo.todo-frp/start}}}}
10 |
--------------------------------------------------------------------------------
/tictactoe/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.tictactoe/init}}
8 | :devtools {:before-load demo.tictactoe/stop
9 | :after-load demo.tictactoe/start}}}}
10 |
--------------------------------------------------------------------------------
/demos-homepage/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.homepage/init}}
8 | :devtools {:before-load demo.homepage/stop
9 | :after-load demo.homepage/start}}}}
10 |
--------------------------------------------------------------------------------
/async-webinar/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.async-webinar/init}}
8 | :devtools {:before-load demo.async-webinar/stop
9 | :after-load demo.async-webinar/start}}}}
10 |
--------------------------------------------------------------------------------
/validated-form/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.validated-form/init}}
8 | :devtools {:before-load demo.validated-form/stop
9 | :after-load demo.validated-form/start}}}}
10 |
--------------------------------------------------------------------------------
/demos-homepage/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hoplon • Demos
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/infinite-scroll/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.infinite-scroll/init}}
8 | :devtools {:before-load demo.infinite-scroll/stop
9 | :after-load demo.infinite-scroll/start}}}}
10 |
--------------------------------------------------------------------------------
/lens/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [aatree/aautil "0.0.4"]
5 | [binaryage/devtools "1.0.7"]]
6 | :dev-http {8000 "public"}
7 | :builds {:app {:target :browser
8 | :modules {:main {:init-fn demo.lens/init}}
9 | :devtools {:before-load demo.lens/stop
10 | :after-load demo.lens/start}}}}
11 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.infinite-scroll-paginated/init}}
8 | :devtools {:before-load demo.infinite-scroll-paginated/stop
9 | :after-load demo.infinite-scroll-paginated/start}}}}
10 |
--------------------------------------------------------------------------------
/tworker/src/demo/demo_worker.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.demo-worker
2 | (:require-macros
3 | [aaworker.worker-macros :refer [deflpc!]])
4 | (:require
5 | [aaworker.api :as api]))
6 |
7 | (def clicks (atom 0))
8 |
9 | (deflpc! click []
10 | (if (< 2 @clicks)
11 | (throw "too many clicks!")
12 | (do
13 | (if (= 2 @clicks)
14 | (api/send-notice :alert "Enough clicks already!"))
15 | (do
16 | (swap! clicks + 1)
17 | @clicks))))
18 |
19 | (defn main []
20 | (api/process-requests))
21 |
--------------------------------------------------------------------------------
/infinite-scroll/public/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: monospace;
3 | }
4 |
5 | #container {
6 | margin: 0 auto;
7 | width: 300px;
8 | text-align: center;
9 | }
10 |
11 | #wrapper {
12 | position: relative;
13 | }
14 |
15 | #loading {
16 | padding: 10px;
17 | width: 300px;
18 | position: absolute;
19 | z-index: 1000;
20 | color: white;
21 | background-color: orange;
22 | }
23 |
24 | #scroll {
25 | top: 0px;
26 | width: 100%;
27 | height: 400px;
28 | overflow-y: scroll;
29 | }
30 |
--------------------------------------------------------------------------------
/validated-form/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hoplon • Validated Form
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demos-homepage/README.md:
--------------------------------------------------------------------------------
1 | # demos-homepage
2 |
3 | This project is a page with links for [Hoplon][1] demos
4 |
5 | [See this page.][3]
6 |
7 | ## Dependencies
8 |
9 | - java 1.8+
10 | - npm
11 |
12 | ## Setup
13 |
14 | Run:
15 |
16 | ```bash
17 | $ npm install
18 | ```
19 |
20 | ## Usage
21 |
22 | 1. Start the auto-compiler. In a terminal:
23 |
24 | ```bash
25 | $ npx shadow-cljs watch app
26 | ```
27 |
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/
34 |
--------------------------------------------------------------------------------
/tictactoe/README.md:
--------------------------------------------------------------------------------
1 | # hoplon-tictactoe
2 |
3 | This project demonstrates Tic Tac Toe in [Hoplon][1].
4 |
5 | [See this demo.][3]
6 |
7 | ## Dependencies
8 |
9 | - java 1.8+
10 | - npm
11 |
12 | ## Setup
13 |
14 | Run:
15 |
16 | ```bash
17 | $ npm install
18 | ```
19 |
20 | ## Usage
21 |
22 | 1. Start the auto-compiler. In a terminal:
23 |
24 | ```bash
25 | $ npx shadow-cljs watch app
26 | ```
27 |
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/tictactoe/
34 |
--------------------------------------------------------------------------------
/counters/README.md:
--------------------------------------------------------------------------------
1 | # counters
2 |
3 | This project demonstrates a simple counting widget in [Hoplon][1].
4 |
5 | [See this demo.][3]
6 |
7 | ## Dependencies
8 |
9 | - java 1.8+
10 | - npm
11 |
12 | ## Setup
13 |
14 | Run:
15 |
16 | ```bash
17 | $ npm install
18 | ```
19 |
20 | ## Usage
21 |
22 | 1. Start the auto-compiler. In a terminal:
23 |
24 | ```bash
25 | $ npx shadow-cljs watch app
26 | ```
27 |
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/counters/
34 |
--------------------------------------------------------------------------------
/tworker/README.md:
--------------------------------------------------------------------------------
1 | # tworker demo
2 |
3 | This demo exercises [aaworker](https://github.com/aatree/aaworker).
4 |
5 | [See this demo.][3]
6 |
7 | ## Dependencies
8 |
9 | - java 1.8+
10 | - npm
11 |
12 | ## Setup
13 |
14 | Run:
15 |
16 | ```bash
17 | $ npm install
18 | ```
19 |
20 | ## Usage
21 |
22 | 1. Start the auto-compiler. In a terminal:
23 |
24 | ```bash
25 | $ npx shadow-cljs watch app
26 | ```
27 |
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/tworker/
34 |
--------------------------------------------------------------------------------
/validated-form/README.md:
--------------------------------------------------------------------------------
1 | # inputs
2 |
3 | This project demonstrates forms with validations using [Hoplon][1].
4 | Check out [the demo][3].
5 |
6 | ## Dependencies
7 |
8 | - java 1.8+
9 | - npm
10 |
11 | ## Setup
12 |
13 | Run:
14 |
15 | ```bash
16 | $ npm install
17 | ```
18 |
19 | ## Usage
20 |
21 | 1. Start the auto-compiler. In a terminal:
22 |
23 | ```bash
24 | $ npx shadow-cljs watch app
25 | ```
26 |
27 |
28 | 2. Go to [http://localhost:8000][2] in your browser.
29 |
30 | [1]: https://hoplon.io
31 | [2]: http://localhost:8000
32 | [3]: https://hoplon.github.io/demos/validated-form/
33 |
--------------------------------------------------------------------------------
/todoFRP/README.md:
--------------------------------------------------------------------------------
1 | # TodoFRP
2 |
3 | An implementation of [TodoMVC][4] using [Hoplon][1].
4 |
5 | ## Demo
6 |
7 | [View the demo here][3].
8 |
9 | ## Dependencies
10 |
11 | - java 1.8+
12 | - npm
13 |
14 | ## Setup
15 |
16 | Run:
17 |
18 | ```bash
19 | $ npm install
20 | ```
21 |
22 | ## Usage
23 |
24 | 1. Start the auto-compiler. In a terminal:
25 |
26 | ```bash
27 | $ npx shadow-cljs watch app
28 | ```
29 |
30 |
31 | 2. Go to [http://localhost:8000][2] in your browser.
32 |
33 | [1]: https://hoplon.io
34 | [2]: http://localhost:8000
35 | [3]: https://hoplon.github.io/demos/todoFRP/
36 | [4]: http://todomvc.com
37 |
--------------------------------------------------------------------------------
/inputs/README.md:
--------------------------------------------------------------------------------
1 | # inputs
2 |
3 | This project demonstrates inputs that receive their values from cells and
4 | update the cells on change in [Hoplon][1].
5 |
6 | [View the demo here][3].
7 |
8 | ## Dependencies
9 |
10 | - java 1.8+
11 | - npm
12 |
13 | ## Setup
14 |
15 | Run:
16 |
17 | ```bash
18 | $ npm install
19 | ```
20 |
21 | ## Usage
22 |
23 | 1. Start the auto-compiler. In a terminal:
24 |
25 | ```bash
26 | $ npx shadow-cljs watch app
27 | ```
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: http://hoplon.github.io/demos/inputs
34 |
--------------------------------------------------------------------------------
/lens/README.md:
--------------------------------------------------------------------------------
1 | # lens demo
2 |
3 | This project exercises dewdrop in the [aautil repository][4]
4 | and integrates dewdrop with [Hoplon][1].
5 |
6 | [See this demo.][3]
7 |
8 | ## Dependencies
9 |
10 | - java 1.8+
11 | - npm
12 |
13 | ## Setup
14 |
15 | Run:
16 |
17 | ```bash
18 | $ npm install
19 | ```
20 |
21 | ## Usage
22 |
23 | 1. Start the auto-compiler. In a terminal:
24 |
25 | ```bash
26 | $ npx shadow-cljs watch app
27 | ```
28 |
29 |
30 | 2. Go to [http://localhost:8000][2] in your browser.
31 |
32 | [1]: https://hoplon.io
33 | [2]: http://localhost:8000
34 | [3]: https://hoplon.github.io/demos/lens/
35 | [4]: https://github.com/aatree/aautil#dewdrop
36 |
--------------------------------------------------------------------------------
/plotSVG/README.md:
--------------------------------------------------------------------------------
1 | # plotSVG
2 |
3 | A [Hoplon][1] demo that plots some data using SVG.
4 |
5 | ![example plot][4]
6 |
7 | [Demo][3]
8 |
9 | ## Dependencies
10 |
11 | - java 1.8+
12 | - npm
13 |
14 | ## Setup
15 |
16 | Run:
17 |
18 | ```bash
19 | $ npm install
20 | ```
21 |
22 | ## Usage
23 |
24 | 1. Start the auto-compiler. In a terminal:
25 |
26 | ```bash
27 | $ npx shadow-cljs watch app
28 | ```
29 |
30 |
31 | 2. Go to [http://localhost:8000][2] in your browser.
32 |
33 | [1]: https://hoplon.io
34 | [2]: http://localhost:8000
35 | [3]: https://hoplon.github.io/demos/plotSVG/
36 | [4]: https://github.com/hoplon/demos/blob/master/plotSVG/img/plot.png?raw=true
37 |
--------------------------------------------------------------------------------
/w3c-worker/README.md:
--------------------------------------------------------------------------------
1 | # w3c-worker demo
2 |
3 | This project is an adoption of the [w3c schools webworker example][4] in [Hoplon][1].
4 |
5 | [See this demo.][3]
6 |
7 | ## Dependencies
8 |
9 | - java 1.8+
10 | - npm
11 |
12 | ## Setup
13 |
14 | Run:
15 |
16 | ```bash
17 | $ npm install
18 | ```
19 |
20 | ## Usage
21 |
22 | 1. Start the auto-compiler. In a terminal:
23 |
24 | ```bash
25 | $ npx shadow-cljs watch app
26 | ```
27 |
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/w3c-worker/
34 | [4]: http://www.w3schools.com/html/html5_webworkers.asp
35 |
--------------------------------------------------------------------------------
/contacts/README.md:
--------------------------------------------------------------------------------
1 | # Contacts
2 |
3 | This project demonstrates a simple contact list application on [Hoplon][1] inspired
4 | by the [Om Basic Tutorial](https://github.com/swannodette/om/wiki/Basic-Tutorial).
5 |
6 | Check out [the demo][3].
7 |
8 | ## Dependencies
9 |
10 | - java 1.8+
11 | - npm
12 |
13 | ## Setup
14 |
15 | Run:
16 |
17 | ```bash
18 | $ npm install
19 | ```
20 |
21 | ## Usage
22 |
23 | 1. Start the auto-compiler. In a terminal:
24 |
25 | ```bash
26 | $ npx shadow-cljs watch app
27 | ```
28 |
29 | 2. Go to [http://localhost:8000][2] in your browser.
30 |
31 | [1]: https://hoplon.io
32 | [2]: http://localhost:8000
33 | [3]: https://hoplon.github.io/demos/contacts/
34 |
--------------------------------------------------------------------------------
/w3c-worker/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]]
5 | :dev-http {8000 "public"}
6 | :builds {:app {:target :browser
7 | :modules {:main {:init-fn demo.w3c-worker/init
8 | :depends-on #{:shared}}
9 | :shared {:entries []}
10 | :worker {:init-fn counter-worker.counts/main
11 | :depends-on #{:shared}
12 | :web-worker true}}
13 | :devtools {:before-load demo.w3c-worker/stop
14 | :after-load demo.w3c-worker/start}}}}
15 |
--------------------------------------------------------------------------------
/tworker/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [binaryage/devtools "1.0.7"]
5 | [aatree/aaworker "0.1.0"]]
6 | :dev-http {8000 "public"}
7 | :builds {:app {:target :browser
8 | :modules {:main {:init-fn demo.tworker/init
9 | :depends-on #{:shared}}
10 | :shared {:entries []}
11 | :worker {:init-fn demo.demo-worker/main
12 | :depends-on #{:shared}
13 | :web-worker true}}
14 | :devtools {:before-load demo.tworker/stop
15 | :after-load demo.tworker/start}}}}
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hoplon Demos
2 |
3 | [Hoplon](https://hoplon.io) is a set of tools
4 | and libraries for making web application front ends.
5 |
6 | This repository contains example Hoplon projects.
7 |
8 | [Check the demos out](https://hoplon.github.io/demos/).
9 |
10 | ## License
11 |
12 | Copyright (c) Alan Dipert and Micha Niskin. All rights
13 | reserved. The use and distribution terms for this software are
14 | covered by the Eclipse Public License 1.0
15 | (http://opensource.org/licenses/eclipse-1.0.php) which can be
16 | found in the file epl-v10.html at the root of this
17 | distribution. By using this software in any fashion, you are
18 | agreeing to be bound by the terms of this license. You must not
19 | remove this notice, or any other, from this software.
20 |
--------------------------------------------------------------------------------
/hoplife/README.md:
--------------------------------------------------------------------------------
1 | # hoplife
2 |
3 | This project demonstrates [Conway's Game of Life](http://en.wikipedia.org/wiki/Conway's_Game_of_Life) in [Hoplon][1].
4 |
5 | Christophe Grand's [extremely elegant and terse method](http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/) is used to implement the game rules.
6 |
7 | See [this demo][3].
8 |
9 | ## Dependencies
10 |
11 | - java 1.8+
12 | - npm
13 |
14 | ## Setup
15 |
16 | Run:
17 |
18 | ```bash
19 | $ npm install
20 | ```
21 |
22 | ## Usage
23 |
24 | 1. Start the auto-compiler. In a terminal:
25 |
26 | ```bash
27 | $ npx shadow-cljs watch app
28 | ```
29 |
30 | 2. Go to [http://localhost:8000][2] in your browser.
31 |
32 | [1]: https://hoplon.io
33 | [2]: http://localhost:8000
34 | [3]: https://hoplon.github.io/demos/hoplife/
35 |
--------------------------------------------------------------------------------
/tictactoe/public/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | color: #333;
4 | }
5 |
6 | pre {
7 | padding: 10px;
8 | background-color: black;
9 | color: chartreuse;
10 | }
11 |
12 | table.tictac {
13 | border-collapse: collapse;
14 | border: 5px solid black;
15 | margin-right: 20px;
16 | }
17 |
18 | table.score {
19 | border-collapse: collapse;
20 | padding-left: 20px;
21 | }
22 |
23 | table.score th {
24 | padding: 5px;
25 | border-bottom: 2px solid black;
26 | }
27 |
28 | table.score td {
29 | padding: 5px;
30 | }
31 |
32 | table.tictac td {
33 | border: 5px solid black;
34 | cursor: pointer;
35 | width: 1.3em;
36 | height: 1.3em;
37 | text-align: center;
38 | vertical-align: middle;
39 | font: bold 36px sans-serif
40 | }
--------------------------------------------------------------------------------
/infinite-scroll/README.md:
--------------------------------------------------------------------------------
1 | # Hoplon • Infinite Scroll Demo
2 |
3 | An infinitely scrollable container built using [Hoplon][1]. Keep scrolling
4 | to see more images; when you reach the bottom it'll fetch more images and
5 | append them so you can continue scrolling and seeing more images...forever.
6 |
7 | ## Demo
8 |
9 | [View the demo here][3].
10 |
11 | ## Dependencies
12 |
13 | - java 1.8+
14 | - npm
15 |
16 | ## Setup
17 |
18 | Run:
19 |
20 | ```bash
21 | $ npm install
22 | ```
23 |
24 | ## Usage
25 |
26 | 1. Start the auto-compiler. In a terminal:
27 |
28 | ```bash
29 | $ npx shadow-cljs watch app
30 | ```
31 |
32 |
33 | 2. Go to [http://localhost:8000][2] in your browser.
34 |
35 | [1]: https://hoplon.io
36 | [2]: http://localhost:8000
37 | [3]: http://hoplon.github.io/demos/infinite-scroll
38 |
--------------------------------------------------------------------------------
/duracell/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | ;; shadow-cljs configuration
2 | {:source-paths ["src"]
3 | :dependencies [[hoplon/hoplon "7.3.5"]
4 | [aatree/durable-cells "0.1.0"]
5 | [binaryage/devtools "1.0.7"]]
6 | :dev-http {8000 "public"}
7 | :builds {:app {:target :browser
8 | :output-dir "public"
9 | :asset-path "/"
10 | :modules {:main {:init-fn demo.duracell/init
11 | :depends-on #{:shared}}
12 | :shared {:entries []}
13 | :dcells {:init-fn durable-cells.dc-api/start
14 | :depends-on #{:shared}
15 | :web-worker true}}
16 | :devtools {:before-load demo.duracell/stop
17 | :after-load demo.duracell/start}}}}
18 |
--------------------------------------------------------------------------------
/duracell/README.md:
--------------------------------------------------------------------------------
1 | # duracell demo
2 |
3 | This is a demo showing how easy it is to use
4 | [IndexedDb](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
5 | running in a
6 | [web worker](http://www.w3schools.com/html/html5_webworkers.asp).
7 |
8 | The duracell demo builds on [Hoplon](https://hoplon.io),
9 | [aaworker](https://github.com/aatree/aaworker)
10 | and [durable-cells](https://github.com/aatree/durable-cells).
11 |
12 | [See this demo.](https://hoplon.github.io/demos/duracell/)
13 |
14 | ## Dependencies
15 |
16 | - java 1.8+
17 | - npm
18 |
19 | ## Setup
20 |
21 | Run:
22 |
23 | ```bash
24 | $ npm install
25 | ```
26 |
27 | ## Usage
28 |
29 | 1. Start the auto-compiler. In a terminal:
30 |
31 | ```bash
32 | $ npx shadow-cljs watch app
33 | ```
34 |
35 |
36 | 2. Go to [http://localhost:8000](http://localhost:8000) in your browser.
37 |
--------------------------------------------------------------------------------
/tictactoe/src/demo/tictactoe/advanced.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.tictactoe.advanced
2 | (:require
3 | [hoplon.core :as h]
4 | [demo.tictactoe.element :as tictactoe]
5 | [javelin.core :refer [cell cell= defc defc= dosync]]))
6 |
7 | (defc winners nil)
8 |
9 | (h/defelem board
10 | [_ [page]]
11 | (h/div
12 | (h/h2 "Small Board")
13 | (tictactoe/game {:size "3"})
14 | (h/h2 "Big Board")
15 | (tictactoe/game {:size "5"})
16 | (h/h2 "Wire Up A Scoreboard")
17 | (tictactoe/game {:size "3" :history winners :style "float:left"})
18 | (tictactoe/scoreboard {:history winners})
19 | (h/div {:style "clear:both"}
20 | (h/div {:style "padding-top: 20px;padding-bottom:50px;"}
21 | (h/a {:href "https://github.com/hoplon/demos/blob/master/tictactoe/src/demo/tictactoe/advanced.cljs"}
22 | "Source Code")
23 | " "
24 | (h/a {:href "#" :click #(reset! page :index)} "Index")))))
25 |
--------------------------------------------------------------------------------
/w3c-worker/src/demo/w3c_worker.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.w3c-worker
2 | (:require
3 | [clojure.string :as str]
4 | [hoplon.core :as h]
5 | [hoplon.goog]
6 | [javelin.core :refer [cell cell= defc defc= dosync]]))
7 |
8 | (defc counter nil)
9 | (def w (atom nil))
10 |
11 | (defn start-worker []
12 | (if (not @w)
13 | (reset! w (js/Worker. "js/worker.js"))
14 | (println "already exists!"))
15 | (set! (.-onmessage @w) #(reset! counter (.-data %))))
16 |
17 | (defn stop-worker []
18 | (when @w
19 | (.terminate @w)
20 | (reset! w nil)))
21 |
22 | (h/defelem w3c-worker []
23 | (h/div
24 | (h/p (h/text "Count numbers: ~{counter}"))
25 | (h/button :click start-worker "Start worker")
26 | (h/button :click stop-worker "Stop worker")))
27 |
28 | (defn mount-components []
29 | (.replaceChildren (.getElementById js/document "app")
30 | (w3c-worker)))
31 |
32 | (defn start []
33 | (mount-components)
34 | (js/console.log "Starting..."))
35 |
36 | (defn stop []
37 | (js/console.log "Stopping..."))
38 |
39 | (defn init []
40 | (js/console.log "Initializing...")
41 | (start))
42 |
--------------------------------------------------------------------------------
/tworker/src/demo/tworker.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.tworker
2 | (:require
3 | [aaworker.lpc :as lpc]
4 | [hoplon.core :as h]
5 | [hoplon.jquery]
6 | [javelin.core :refer [cell cell= defc defc= dosync]]))
7 |
8 | (defc state 0)
9 | (defc error nil)
10 | (defc loading nil)
11 |
12 | (def clear-error! #(reset! error nil))
13 | (defc= loading? (seq loading))
14 |
15 | (lpc/new-worker! "js/worker.js")
16 | (def click (lpc/mklocal! 'click "js/worker.js" state error loading))
17 |
18 | (defn click-it [] (click))
19 |
20 | (h/defelem tworker []
21 | (h/div
22 | (h/div
23 | :id "error"
24 | :click clear-error!
25 | :slide-toggle error
26 | :css {:display "none"}
27 | (h/text "~{error}"))
28 | (h/p state
29 | (h/text " ")
30 | (h/button :click click-it "Click!"))))
31 |
32 | (defn mount-components []
33 | (.replaceChildren (.getElementById js/document "app")
34 | (tworker)))
35 |
36 | (defn start []
37 | (mount-components)
38 | (js/console.log "Starting..."))
39 |
40 | (defn stop []
41 | (js/console.log "Stopping..."))
42 |
43 | (defn init []
44 | (js/console.log "Initializing...")
45 | (start))
46 |
--------------------------------------------------------------------------------
/async-webinar/README.md:
--------------------------------------------------------------------------------
1 | # async-webinar
2 |
3 | A [Hoplon][1] demo that performs the examples from [Designing Front End Applications with core.async][4]
4 | Cognitect's webinar. The original code can be found [here][5].
5 |
6 | Examples 4 & 5 were not reproduced as they seemed explicitly core.async-centric. Also, I believe
7 | that example 6 exposes a bug in the original, wherein if you click the B button before the A button,
8 | the click is queued and immediately triggers the next message. It seems that the proper behavior should
9 | be to discard clicks to B until the A button has been clicked and then wait for a click to B.
10 |
11 | [See this demo.][3]
12 |
13 | ## Dependencies
14 |
15 | - java 1.8+
16 | - npm
17 |
18 | ## Setup
19 |
20 | Run:
21 |
22 | ```bash
23 | $ npm install
24 | ```
25 |
26 | ## Usage
27 |
28 | 1. Start the auto-compiler. In a terminal:
29 |
30 | ```bash
31 | $ npx shadow-cljs watch app
32 | ```
33 |
34 |
35 | 2. Go to [http://localhost:8000][2] in your browser.
36 |
37 | [1]: https://hoplon.io
38 | [2]: http://localhost:8000
39 | [3]: https://hoplon.github.io/demos/async-webinar/
40 | [4]: http://go.cognitect.com/core_async_webinar_recording
41 | [5]: https://github.com/cognitect/async-webinar
42 |
--------------------------------------------------------------------------------
/demos-homepage/public/css/main.css:
--------------------------------------------------------------------------------
1 | @import url('http://fonts.googleapis.com/css?family=Bree+Serif');
2 |
3 | .container h1,
4 | .container h2,
5 | .container h3,
6 | .container h4,
7 | .container h5,
8 | .container h6 {
9 | /* font-family: 'Bree Serif', serif; */
10 | /* font-family: 'Lilita One', serif; */
11 | font-family: 'Bree Serif', serif;
12 | }
13 |
14 | div.jumbotron {
15 | padding: 0px;
16 | background: #ffcc33;
17 | background: -moz-linear-gradient(45deg, #ffcc33 0%, #990000 100%);
18 | background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#020031), color-stop(100%,#990000));
19 | background: -webkit-linear-gradient(45deg, #ffcc33 0%,#990000 100%);
20 | background: -o-linear-gradient(45deg, #ffcc33 0%,#990000 100%);
21 | background: -ms-linear-gradient(45deg, #ffcc33 0%,#990000 100%);
22 | background: linear-gradient(45deg, #ffcc33 0%,#990000 100%);
23 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffcc33', endColorstr='#990000',GradientType=1 );
24 | width: 100%;
25 | }
26 |
27 | .lambda {
28 | background-image: url(../image/Lambda_lc.svg);
29 | background-repeat: no-repeat;
30 | background-position: right;
31 | padding:48px;
32 | height: 250px;
33 | }
34 |
--------------------------------------------------------------------------------
/duracell/src/demo/duracell.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.duracell
2 | (:require
3 | [durable-cells.core :refer [open-durable-cells! error ready]]
4 | [hoplon.core :as h]
5 | [hoplon.jquery]
6 | [javelin.core :refer [cell cell= dosync defc]]))
7 |
8 | (set! cljs.core/*print-fn* #(.log js/console %))
9 |
10 | (def clear-error! #(reset! error nil))
11 | (defc txt nil)
12 |
13 | (open-durable-cells! {"txt" txt})
14 |
15 | (h/defelem duracell []
16 | (h/div
17 | :css {:display "none"}
18 | :toggle ready
19 | (h/div
20 | :id "error"
21 | :click clear-error!
22 | :slide-toggle error
23 | :css {:display "none"}
24 | (h/text "~{error}"))
25 | (h/h2 (h/text "IndexedDB Demo: Duracell"))
26 | (h/p (h/input
27 | :type "text"
28 | :value txt
29 | :keyup #(reset! txt @%)))
30 | (h/p (h/text "Type something and then refresh the page--nothing is lost."))))
31 |
32 | (defn mount-components []
33 | (.replaceChildren (.getElementById js/document "app")
34 | (duracell)))
35 |
36 | (defn start []
37 | (mount-components)
38 | (js/console.log "Starting..."))
39 |
40 | (defn stop []
41 | (js/console.log "Stopping..."))
42 |
43 | (defn init []
44 | (js/console.log "Initializing...")
45 | (start))
46 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/README.md:
--------------------------------------------------------------------------------
1 | # Hoplon • Infinite Scroll Demo with pagination
2 |
3 | A potentially infinitely scrollable container built using [Hoplon][1].
4 | Keep scrolling to see more numbers divided in pages; when you almost reach
5 | the bottom it'll fetch more pages full of numbers and append them so you can
6 | continue scrolling and seeing more numbers... until page 99.
7 |
8 | The address bar will change to show in witch page you are. If you type an
9 | already loaded page on address bar it will scroll to that page. If you
10 | type a page that isn't loaded the browser will refresh and take you there.
11 | If didn't start on the first page you can scroll up too.
12 |
13 | It's not really connecting to a server, all the data is fake.
14 |
15 | ## Demo
16 |
17 | [View the demo here][3].
18 |
19 | ## Dependencies
20 |
21 | - java 1.8+
22 | - npm
23 |
24 | ## Setup
25 |
26 | Run:
27 |
28 | ```bash
29 | $ npm install
30 | ```
31 |
32 | ## Usage
33 |
34 | 1. Start the auto-compiler. In a terminal:
35 |
36 | ```bash
37 | $ npx shadow-cljs watch app
38 | ```
39 |
40 |
41 | 2. Go to [http://localhost:8000][2] in your browser.
42 |
43 | [1]: https://hoplon.io
44 | [2]: http://localhost:8000
45 | [3]: http://hoplon.github.io/demos/infinite-scroll-paginated
46 |
--------------------------------------------------------------------------------
/lens/src/demo/lens.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.lens
2 | (:require
3 | [hoplon.core :as h]
4 | [aautil.dewdrop :as lens]
5 | [hoplon.goog]
6 | [javelin.core :refer [cell cell= defc defc= dosync]]))
7 |
8 | (set! cljs.core/*print-fn* #(.log js/console %))
9 |
10 | (defc composite-data {"A" "Apple" "B" "Boy"})
11 | (defc lens-key "A")
12 |
13 | (def keyed-lens (lens/atom-key-lens lens-key))
14 | (def keyed-view (lens/lview keyed-lens composite-data))
15 |
16 | (defn revalue [_ _] @keyed-view)
17 |
18 | (defc= value
19 | (revalue lens-key composite-data)
20 | (fn [item] (reset! keyed-view item)))
21 |
22 | (h/defelem lens
23 | []
24 | (h/div
25 | (h/p (h/text "data: ~{composite-data}"))
26 | (h/p (h/text "key: ")
27 | (h/input
28 | :type "text"
29 | :value lens-key
30 | :keyup #(reset! lens-key @%)))
31 | (h/p (h/text "valuesss: ")
32 | (h/input
33 | :type "text"
34 | :value value
35 | :keyup #(reset! value @%)))
36 | (h/p (h/a :href "https://github.com/hoplon/demos/tree/master/lens" "Source code"))))
37 |
38 | (defn mount-components []
39 | (.replaceChildren (.getElementById js/document "app")
40 | (lens)))
41 |
42 | (defn start []
43 | (mount-components)
44 | (js/console.log "Starting..."))
45 |
46 | (defn stop []
47 | (js/console.log "Stopping..."))
48 |
49 | (defn init []
50 | (js/console.log "Initializing...")
51 | (start))
52 |
--------------------------------------------------------------------------------
/async-webinar/public/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0 0 300px 0;
3 | padding: 0;
4 | font-family: helvetica, arial, sans-serif;
5 | }
6 |
7 | button {
8 | outline: none;
9 | color: #666;
10 | font-size: 16px;
11 | border: 2px solid #666;
12 | background-color: white;
13 | border-radius: 4px;
14 | padding: 4px 12px;
15 | text-transform: uppercase;
16 | }
17 |
18 | button:hover {
19 | color: black;
20 | border-color: black;
21 | }
22 |
23 | button.disabled:hover {
24 | color: #666;
25 | border-color: #666;
26 | }
27 |
28 | button:active {
29 | background-color: #efefef;
30 | }
31 |
32 | button.disabled:active {
33 | background-color: white;
34 | }
35 |
36 | table td.left {
37 | vertical-align: top;
38 | }
39 |
40 | .example {
41 | padding: 20px;
42 | border-bottom: 1px solid #333;
43 | }
44 |
45 | .example table {
46 | width: 100%;
47 | }
48 |
49 | .example table td {
50 | width: 50%;
51 | }
52 |
53 | h2 {
54 | margin-top: 0px;
55 | }
56 |
57 | .display {
58 | background-color: #efefef;
59 | padding: 10px;
60 | font-family: courier, monospace;
61 | font-size: 16px;
62 | border: 1px solid #ccc;
63 | }
64 |
65 | .scrolling {
66 | position: relative;
67 | height: 220px;
68 | max-height: 200px;
69 | overflow-y: hidden;
70 | }
71 |
72 | .scrolling > div {
73 | position: absolute;
74 | bottom: -12px;
75 | left: 0px;
76 | right: 0px;
77 | }
78 |
79 | button.disabled {
80 | opacity: 0.5;
81 | }
--------------------------------------------------------------------------------
/tictactoe/src/demo/tictactoe.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.tictactoe
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.goog]
5 | [demo.tictactoe.advanced :as advanced]
6 | [demo.tictactoe.basic :as basic]
7 | [javelin.core :refer [cell cell= dosync]]))
8 |
9 | (defonce page (cell :index))
10 |
11 | (h/defelem index
12 | []
13 | (h/div
14 | (h/h1 "Tic Tac Toe in Hoplon")
15 | (h/p
16 | (h/a {:href "https://hoplon.io"} "Hoplon")
17 | " is a set of libraries and tools for creating dynamic web applications.")
18 | (h/p "This project demonstrates a Hoplon Tic Tac Toe in two ways:")
19 | (h/ol
20 | (h/li
21 | (h/a {:href "#" :click #(reset! page :basic)} "basic.cljs")
22 | " - a simple game of Tic Tac Toe.")
23 | (h/li
24 | (h/a {:href "#" :click #(reset! page :advanced)} "advanced.cljs")
25 | " - games of Tic Tac Toe with different sizes and score"))
26 | (h/p
27 | (h/a
28 | {:href "https://github.com/hoplon/demos/tree/master/tictactoe"}
29 | "Source Code"))))
30 |
31 | (h/defelem tictactoe []
32 | (h/div
33 | (h/case-tpl page
34 | :index (index)
35 | :basic (basic/board page)
36 | :advanced (advanced/board page)
37 | (h/a {:href "#" :click #(reset! page :index)} "Index"))))
38 |
39 | (defn mount-components []
40 | (.replaceChildren (.getElementById js/document "app")
41 | (tictactoe)))
42 |
43 | (defn start []
44 | (mount-components)
45 | (js/console.log "Starting..."))
46 |
47 | (defn stop []
48 | (js/console.log "Stopping..."))
49 |
50 | (defn init []
51 | (js/console.log "Initializing...")
52 | (start))
53 |
--------------------------------------------------------------------------------
/counters/src/demo/counter.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.counter
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.goog]
5 | [javelin.core :as j]))
6 |
7 | (h/defelem swap-button
8 | [{:keys [state func] :or {func identity} :as attr} kids]
9 | (let [attr (dissoc attr :state :func)]
10 | (h/button (assoc attr :click #(swap! state func))
11 | kids)))
12 |
13 | (h/defelem counter
14 | [attr _]
15 | (let [my-count (j/cell 0)]
16 | (h/div attr
17 | (h/label (h/text "~{my-count}"))
18 | (swap-button :state my-count :func inc "+")
19 | (swap-button :state my-count :func dec "-"))))
20 |
21 | (h/defelem counters
22 | [{:keys [size] :or {size 10} :as attr} _]
23 | (let [last-clicked (j/cell nil)
24 | attr (dissoc attr :size)]
25 | (h/div attr
26 | (h/h1 "A Counting Widget!")
27 | (h/p {:toggle last-clicked}
28 | (h/text "Last clicked item was ~{last-clicked}"))
29 | (h/loop-tpl :bindings [i (j/cell= (range 0 size))]
30 | (counter :click #(reset! last-clicked @i))))))
31 |
32 | (defn mount-components []
33 | (.replaceChildren (.getElementById js/document "app")
34 | (counters :size 10)
35 | (h/p (h/a :href "https://github.com/hoplon/demos/blob/master/counters/src/demo/counter.cljs" "Source code"))
36 | (h/p "Inspired by " (h/a :href "https://github.com/swannodette/om/tree/master/examples/counters" "the Om demo of the same name."))))
37 |
38 | (defn start []
39 | (mount-components)
40 | (js/console.log "Starting..."))
41 |
42 | (defn stop []
43 | (js/console.log "Stopping..."))
44 |
45 | (defn init []
46 | (js/console.log "Initializing...")
47 | (start))
48 |
--------------------------------------------------------------------------------
/hoplife/src/demo/hoplife.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.hoplife
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.goog]
5 | [javelin.core :refer [cell cell= defc]]))
6 |
7 | (def default #{[2 1] [2 2] [0 1] [1 2] [2 0] [13 11] [12 11] [11 11]})
8 | (def +size+ 16)
9 | (def +interval+ 100)
10 | (defc running? true)
11 | (defc alive default)
12 |
13 | ;; See http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/
14 | ;; Slightly modified to be toroidal
15 | (defn neighbours [[x y]]
16 | (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
17 | [(mod (+ dx x) +size+) (mod (+ dy y) +size+)]))
18 |
19 | (defn step [cells]
20 | (set (for [[loc n] (frequencies (mapcat neighbours cells))
21 | :when (or (= n 3) (and (= n 2) (cells loc)))]
22 | loc)))
23 |
24 | (defn click [cells xy]
25 | ((if (contains? cells xy) disj conj) cells xy))
26 |
27 | (h/defelem hoplife []
28 | (h/div
29 | (h/h2 "Hoplife ")
30 | (h/button :click #(swap! running? not) :text (cell= (if running? "Stop" "Start")))
31 | (h/button :click #(swap! alive into default) "Reset")
32 | (h/table
33 | (for [x (range +size+)]
34 | (h/tr (for [y (range +size+)]
35 | (h/td :click #(swap! alive click [x y])
36 | :class (cell= {"alive" (contains? alive [x y])}))))))
37 | (h/p (h/a :href "https://github.com/hoplon/demos/tree/master/hoplife" "Source Code"))))
38 |
39 | (defn mount-components []
40 | (.replaceChildren (.getElementById js/document "app")
41 | (hoplife)))
42 |
43 | (defn start []
44 | (mount-components)
45 | (js/console.log "Starting..."))
46 |
47 | (defn stop []
48 | (js/console.log "Stopping..."))
49 |
50 | (defn init []
51 | (js/console.log "Initializing...")
52 | (start)
53 | (h/with-init!
54 | (h/with-interval +interval+
55 | (when @running?
56 | (swap! alive step)))))
57 |
--------------------------------------------------------------------------------
/demos-homepage/src/demo/homepage.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.homepage
2 | (:require-macros
3 | [macros.core :refer [demo-dirs]])
4 | (:require
5 | [hoplon.twitter.bootstrap :refer [container]]
6 | [clojure.string :as str]
7 | [hoplon.core :as h]
8 | [hoplon.goog]
9 | [javelin.core :refer [cell cell= dosync]]))
10 |
11 | (def url:hoplon "https://hoplon.io")
12 | (def url:hoplon-demos "https://github.com/hoplon/demos")
13 | (def url:hoplon-slack "https://clojurians.slack.com/messages/hoplon/")
14 | (def url:clojurians "http://clojurians.net/")
15 |
16 | (h/defelem demo-item [_ [name]]
17 | (h/li :class "list-group-item"
18 | (h/a :href name name)))
19 |
20 | (h/defelem copyright-footer [_ _]
21 | (h/div :css {:padding "30px 0px"}
22 | (h/div :css {:text-align "center"}
23 | "Copyright © Alan Dipert and Micha Niskin. All rights reserved.")))
24 |
25 | (h/defelem homepage []
26 | (h/div
27 | (h/div :class "jumbotron"
28 | (container :class "lambda"
29 | (h/h1 "Hoplon Demos")
30 | (h/p "A simpler way to program the web, with examples!")))
31 | (container
32 | (h/div :col {:sm 6}
33 | (h/p "Check out the demos, then try these links:")
34 | (h/ul
35 | (h/li "The " (h/a :href url:hoplon "Hoplon website."))
36 | (h/li "Source code for all demos is " (h/a :href url:hoplon-demos "here."))
37 | (h/li
38 | "Join the " (h/a :href url:hoplon-slack "Hoplon Slack channel.") " "
39 | "Grab an invite to Slack " (h/a :href url:clojurians "here") " if you are not registered.")))
40 | (h/div :col {:sm 6}
41 | (h/ul :class "list-group"
42 | (mapv demo-item (demo-dirs)))))
43 | (h/hr)
44 | (copyright-footer)))
45 |
46 | (defn mount-components []
47 | (.replaceChildren (.getElementById js/document "app")
48 | (homepage)))
49 |
50 | (defn start []
51 | (mount-components)
52 | (js/console.log "Starting..."))
53 |
54 | (defn stop []
55 | (js/console.log "Stopping..."))
56 |
57 | (defn init []
58 | (js/console.log "Initializing...")
59 | (start))
60 |
--------------------------------------------------------------------------------
/tictactoe/src/demo/tictactoe/basic.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.tictactoe.basic
2 | (:require
3 | [hoplon.core :as h]
4 | [javelin.core :refer [cell cell= defc defc= dosync]]))
5 |
6 | (def transpose (partial apply map vector))
7 | (def diagonal (partial map (comp first drop) (range)))
8 | (def indexed (partial map-indexed vector))
9 | (def new-game (vec (repeat 9 nil)))
10 |
11 | (defc game new-game)
12 | (defc undos ())
13 | (defc= rows (partition 3 game))
14 | (defc= columns (transpose rows))
15 | (defc= diagonals [(diagonal rows) (diagonal (map reverse rows))])
16 | (defc= runs (concat rows columns diagonals))
17 | (defc= winner (->> runs
18 | (map set)
19 | (remove #(contains? % nil))
20 | (filter #(= 1 (count %)))
21 | ffirst))
22 | (defc= moves (->> (indexed game)
23 | (filter (comp nil? second))
24 | (map first)))
25 | (defc= no-moves? (not (seq moves)))
26 | (defc= over (cond winner (str winner " won!")
27 | no-moves? "Cat's game."))
28 |
29 | (defn undo! []
30 | (when (seq @undos)
31 | (reset! game (peek @undos))
32 | (swap! undos pop)))
33 |
34 | (defn ai! []
35 | (when-not @over
36 | (swap! game assoc (rand-nth @moves) "O")))
37 |
38 | (defn play! [i j]
39 | (let [idx (+ (* i 3) j)]
40 | (when (and (not @over) (nil? (get @game idx)))
41 | (swap! undos conj @game)
42 | (swap! game assoc idx "X"))))
43 |
44 | (defn reset-game! []
45 | (reset! game new-game)
46 | (reset! undos ()))
47 |
48 | (h/defelem board
49 | [_ [page]]
50 | (h/div
51 | (h/table :class "tictac"
52 | (h/loop-tpl :bindings [[i row] (cell= (indexed rows))]
53 | (h/tr
54 | (h/loop-tpl :bindings [[j x] (cell= (indexed row))]
55 | (h/td :click #(and (play! @i @j) (ai!)) (h/text "~{x}"))))))
56 | (h/div :toggle (cell= (and (not over) (seq undos)))
57 | (h/button :click undo! "Undo"))
58 | (h/div :toggle over
59 | (h/p (h/text "~{over}"))
60 | (h/button :click reset-game! "Play Again"))
61 | (h/a :href "https://github.com/hoplon/demos/blob/master/tictactoe/src/demo/tictactoe/basic.cljs"
62 | "Source Code")
63 | " "
64 | (h/a {:href "#" :click #(reset! page :index)} " Index")))
65 |
--------------------------------------------------------------------------------
/plotSVG/src/demo/chart.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.chart
2 | (:require
3 | [hoplon.core :as h]
4 | [javelin.core :refer [cell cell= dosync cell-let]]
5 | [clojure.string :as str]
6 | [hoplon.svg :as svg]))
7 |
8 | (defrecord Chart [width height min-x max-x min-y max-y])
9 |
10 | (defn config [& {:keys [width height min-x max-x min-y max-y]}]
11 | (Chart. width height min-x max-x min-y max-y))
12 |
13 | (defn rel-coord [{:keys [width height min-x max-x min-y max-y]} x y]
14 | (let [w (- max-x min-x)
15 | h (- max-y min-y)
16 | dw (- x min-x)
17 | dh (- y min-y)]
18 | [(* width (/ dw w)) (* height (- 1 (/ dh h)))]))
19 |
20 | (h/defelem container [{:keys [chart] :as attr} kids]
21 | (cell-let [{:keys [width height]} chart]
22 | (svg/svg (assoc (dissoc attr :chart) :width width :height height) kids)))
23 |
24 | (h/defelem point-circle [{:keys [chart x y] :as attr} _]
25 | (let [coord (cell= (rel-coord chart x y))]
26 | ((svg/circle
27 | :cx (cell= (first coord))
28 | :cy (cell= (second coord)))
29 | (dissoc attr :chart :x :y)
30 | (svg/title (h/text "[~{x}, ~{y}]")))))
31 |
32 | (h/defelem point-rect [{:keys [chart x y width height] :as attr} _]
33 | (let [coord (cell= (rel-coord chart x y))]
34 | ((svg/rect
35 | :x (cell= (- (first coord) (/ width 2)))
36 | :y (cell= (- (second coord) (/ height 2))))
37 | (dissoc attr :chart :x :y)
38 | (svg/title (h/text "[~{x}, ~{y}]")))))
39 |
40 | (h/defelem points-rect [{:keys [chart data width height] :as attr} _]
41 | (svg/g
42 | (h/loop-tpl :bindings [[x y] data]
43 | ((point-rect :chart chart :x x :y y :width width :height height)
44 | (dissoc attr :chart :data :width :height)))))
45 |
46 | (h/defelem points-circle [{:keys [chart data] :as attr} _]
47 | (svg/g
48 | (h/loop-tpl :bindings [[x y] data]
49 | ((point-circle :chart chart :x x :y y) (dissoc attr :chart :data)))))
50 |
51 | (h/defelem polygon [{:keys [chart data] :as attr} _]
52 | (let [start (cell= (str "0," (:height chart)))
53 | end (cell= (str (:width chart) "," (:height chart)))
54 | rels (cell= (for [[x y] data]
55 | (let [[x' y'] (rel-coord chart x y)]
56 | (str x' "," y'))))
57 | points (cell= (str start " " (str/join " " rels) " " end))]
58 | ((svg/polygon :points points) (dissoc attr :chart :data))))
59 |
60 | (h/defelem polyline [{:keys [chart data] :as attr} _]
61 | (let [rels (cell= (for [[x y] data]
62 | (let [[x' y'] (rel-coord chart x y)]
63 | (str x' "," y'))))
64 | points (cell= (str/join " " rels))]
65 | ((svg/polyline :points points) (dissoc attr :chart :data))))
66 |
--------------------------------------------------------------------------------
/infinite-scroll/src/demo/infinite_scroll.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.infinite-scroll
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.goog]
5 | [javelin.core :refer [cell cell= dosync defc defc=]]))
6 |
7 | (defn new-image
8 | [random]
9 | (str "https://picsum.photos/280/200?random=" random))
10 |
11 | (def random-index (atom -1))
12 | (defc images "The current list of image urls." [])
13 | (defc loading "A vector of in-progress async calls." [])
14 | (defc= loading? "True if there are in-progress async calls." (seq loading))
15 |
16 | (defmethod h/on! :scroll-end
17 | ;; Add the :scroll-end attribute, which fires its callback when the element is
18 | ;; scrolled down as far as it can go--to the bottom.
19 | [elem _ callback]
20 | (h/on! elem :scroll
21 | #(let [el (.-target %)
22 | ch (.-clientHeight el)
23 | sh (.-scrollHeight el)
24 | st (.-scrollTop el)
25 | at-end? (= ch (- sh st))]
26 | (when at-end? (callback %)))))
27 |
28 | (defn fetch-images!
29 | "Append more images"
30 | []
31 | (when-not @loading?
32 | (swap! loading conj :loading)
33 | (h/with-timeout 500
34 | (swap! loading pop)
35 | (swap! images into [(new-image (swap! random-index inc))
36 | (new-image (swap! random-index inc))
37 | (new-image (swap! random-index inc))
38 | (new-image (swap! random-index inc))
39 | (new-image (swap! random-index inc))
40 | (new-image (swap! random-index inc))
41 | (new-image (swap! random-index inc))
42 | (new-image (swap! random-index inc))
43 | (new-image (swap! random-index inc))
44 | (new-image (swap! random-index inc))]))))
45 |
46 | (h/defelem infinite-scroll []
47 | (h/div :id "container"
48 | (h/h2 "Infinite Scroll ")
49 | (h/p "Scroll down to see more images...")
50 | (h/div :id "wrapper"
51 | (h/div :id "loading" :style "display:none" :toggle loading? "LOADING IMAGES...")
52 | (h/div :id "scroll" :scroll-end fetch-images!
53 | (h/loop-tpl :bindings [image images]
54 | (h/div (h/img :src image)))))
55 |
56 | (h/p (h/a :href "https://github.com/hoplon/demos/tree/master/infinite-scroll" "Source Code"))))
57 |
58 | (defn mount-components []
59 | (.replaceChildren (.getElementById js/document "app")
60 | (infinite-scroll)))
61 |
62 | (defn start []
63 | (mount-components)
64 | (fetch-images!)
65 | (js/console.log "Starting..."))
66 |
67 | (defn stop []
68 | (js/console.log "Stopping..."))
69 |
70 | (defn init []
71 | (js/console.log "Initializing...")
72 | (start))
73 |
--------------------------------------------------------------------------------
/validated-form/src/demo/validated_form.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.validated-form
2 | (:require-macros [vform.core :refer [defv]])
3 | (:require
4 | [hoplon.core :as h]
5 | [hoplon.jquery]
6 | [javelin.core :refer [cell cell= defc defc= dosync]]))
7 |
8 | ;; input cells
9 |
10 | (defc form-name nil)
11 | (defc form-email nil)
12 |
13 | ;; helpers / validators
14 |
15 | (defn validate-presence [v] (seq v))
16 |
17 | (defn validate-regexp [r]
18 | (fn [v] (re-matches r (or v ""))))
19 |
20 | ;; formula cells
21 |
22 | (defv form-name-valid? form-name validate-presence)
23 | (defv form-email-valid? form-email (validate-regexp #"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b"))
24 |
25 | (defc= is-form-valid? (and (:valid? form-name-valid?) (:valid? form-email-valid?)))
26 |
27 | (defc= form-data {:name form-name
28 | :email form-email})
29 |
30 | ;; operations
31 |
32 | (defn submit-form [_] (js/alert (str "Send: " (pr-str @form-data))))
33 |
34 | ;; custom elements
35 |
36 | (h/defelem cell-input [{:keys [cell] :as attrs}]
37 | (let [target-value #(h/do! (-> % .-currentTarget) :value)]
38 | (h/input (-> attrs
39 | (dissoc :cell)
40 | (assoc :type (:type attrs "text")
41 | :value cell
42 | :input #(reset! cell (target-value %)))))))
43 |
44 | (h/defelem form-group [{:keys [valid?] :as attrs} body]
45 | (let [dirty? (fn [v] (-> v nil? not))]
46 | ((h/div (dissoc attrs :valid?) body)
47 | :class (cell= {:form-group true
48 | :has-error (and (dirty? (:value valid?)) (not (:valid? valid?)))}))))
49 |
50 | (h/defelem input-control [attrs]
51 | ((cell-input attrs) :class {:form-control true}))
52 |
53 | ;; interface
54 | (h/defelem validated-form []
55 | (h/div :class "site-wrapper"
56 | (h/div :class "site-wrapper-inner"
57 | (h/div :class "cover-container"
58 | (h/div :class "inner cover"
59 | (h/form :submit submit-form
60 | (form-group :valid? form-name-valid?
61 | (h/label "Name")
62 | (input-control :cell form-name))
63 | (form-group :valid? form-email-valid?
64 | (h/label "Email")
65 | (input-control :cell form-email))
66 | (h/div :class "text-right"
67 | (h/button :class "btn btn-primary"
68 | :type "submit"
69 | :disabled (cell= (not is-form-valid?)) "Submit"))))))))
70 |
71 | (defn mount-components []
72 | (.replaceChildren (.getElementById js/document "app")
73 | (validated-form)))
74 |
75 | (defn start []
76 | (mount-components)
77 | (js/console.log "Starting..."))
78 |
79 | (defn stop []
80 | (js/console.log "Stopping..."))
81 |
82 | (defn init []
83 | (js/console.log "Initializing...")
84 | (start))
85 |
--------------------------------------------------------------------------------
/tictactoe/src/demo/tictactoe/element.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.tictactoe.element
2 | (:require
3 | [hoplon.core :as h]
4 | [javelin.core :refer [cell cell= defc defc=]]))
5 |
6 | (def transpose (partial apply map vector))
7 | (def diagonal (partial map (comp first drop) (range)))
8 | (def indexed (partial map-indexed vector))
9 | (def new-game #(vec (repeat % nil)))
10 |
11 | (h/defelem scoreboard
12 | [{:keys [history]} _]
13 | (let [sorted (cell= (indexed (->> history (sort-by second) reverse)))]
14 | (h/table :class "score"
15 | (h/tr (h/th "rank") (h/th "player") (h/th "score"))
16 | (h/loop-tpl :bindings [[rank [player score]] sorted]
17 | (h/tr
18 | (h/td :align "center" (h/text "~(inc rank)"))
19 | (h/td :align "center" (h/text "~{player}"))
20 | (h/td :align "center" (h/text "~{score}")))))))
21 |
22 | (h/defelem game
23 | [{:keys [size history] :or {size 3 history (cell [])} :as attr} _]
24 | (let [rowsize (js/parseInt size)
25 | sizen (* rowsize rowsize)
26 | game (cell (new-game sizen))
27 | rows (cell= (partition rowsize game))
28 | columns (cell= (transpose rows))
29 | diagonals (cell= [(diagonal rows) (diagonal (map reverse rows))])
30 | runs (cell= (concat rows columns diagonals))
31 | winner (cell= (->> runs
32 | (map set)
33 | (remove #(contains? % nil))
34 | (filter #(= 1 (count %)))
35 | ffirst))
36 | moves (cell= (->> (indexed game)
37 | (filter (comp nil? second))
38 | (map first)))
39 | no-moves? (cell= (not (seq moves)))
40 | over (cell= (cond winner (str winner " won!")
41 | no-moves? "Cat's game."))
42 | ai! (fn []
43 | (when-not @over
44 | (swap! game assoc (rand-nth @moves) "O")))
45 | play! (fn [i j]
46 | (let [idx (+ (* i rowsize) j)]
47 | (when (and (not @over)
48 | (nil? (get @game idx)))
49 | (swap! game assoc idx "X"))))]
50 | (reset! history {"X" 0 "O" 0 "cat" 0})
51 | (cell=
52 | (when (or winner no-moves?)
53 | (swap! ~(cell history) update-in [(or winner "cat")] inc)))
54 | (h/div (dissoc attr :size :history)
55 | (h/table :class "tictac"
56 | (h/loop-tpl :bindings [[i row] (cell= (indexed rows))]
57 | (h/tr
58 | (h/loop-tpl :bindings [[j x] (cell= (indexed row))]
59 | (h/td :click #(and (play! @i @j) (ai!)) (h/text "~{x}"))))))
60 | (h/div :toggle over
61 | (h/p (h/text "~{over}"))
62 | (h/button :click #(reset! game (new-game sizen)) "Play Again")))))
63 |
--------------------------------------------------------------------------------
/demos-homepage/src/hoplon/twitter/bootstrap.cljs:
--------------------------------------------------------------------------------
1 | (ns hoplon.twitter.bootstrap
2 | (:require
3 | [hoplon.core :as h]
4 | [javelin.core :refer [cell cell=]]))
5 |
6 | (def ^:private cols-prefixes
7 | (for [i [:xs :sm :md :lg] j (range 1 13)]
8 | [(str "col-" (name i)) j]))
9 |
10 | (defn- mkreset [sep]
11 | (->> cols-prefixes
12 | (map (fn [[k v]] [(keyword (str k sep v)) false]))
13 | (into {} )))
14 |
15 | (def ^:private cols-seps
16 | {:col "-" :push "-push-" :pull "-pull-" :offset "-offset-"})
17 |
18 | (def ^:private cols-reset
19 | (->> cols-seps (map #(vector (key %) (mkreset (val %)))) (into {})))
20 |
21 | (defn- mkcol-key [key m]
22 | (reduce-kv #(assoc %1 (keyword (str "col-" (name %2) (cols-seps key) %3)) true) {} m))
23 |
24 | (defn- do-classes [elem key val]
25 | (h/do! elem :class (merge (cols-reset key) (mkcol-key key val))))
26 |
27 | (defmethod h/do! :col [elem key val] (do-classes elem key val))
28 | (defmethod h/do! :offset [elem key val] (do-classes elem key val))
29 | (defmethod h/do! :push [elem key val] (do-classes elem key val))
30 | (defmethod h/do! :pull [elem key val] (do-classes elem key val))
31 |
32 | (defmethod h/do! :success [elem _ val] (h/do! elem :class {:has-success (boolean val)}))
33 | (defmethod h/do! :warning [elem _ val] (h/do! elem :class {:has-warning (boolean val)}))
34 | (defmethod h/do! :error [elem _ val] (h/do! elem :class {:has-error (boolean val)}))
35 |
36 | (h/defelem container [attr kids] (h/div :class "container" attr kids))
37 | (h/defelem form-horizontal [attr kids] (h/form :role "form" :class "form-horizontal" attr kids))
38 | (h/defelem control-label [attr kids] (h/label :class "control-label" attr kids))
39 | (h/defelem form-group [attr kids] (h/div :class "form-group" attr kids))
40 | (h/defelem checkbox [attr kids] (h/div :class "checkbox" attr kids))
41 |
42 | (h/defelem active
43 | [{:keys [state]} [kid]]
44 | (kid :class (cell= {:active state})))
45 |
46 | (h/defelem deck
47 | [{:keys [state]} kids]
48 | (->> kids
49 | (map-indexed #(active :state (cell= (= %1 state)) %2))))
50 |
51 | (h/defelem selector
52 | [{:keys [state event]} kids]
53 | (->> kids
54 | (deck :state state)
55 | (map-indexed #(%2 event (fn [_] (reset! state %1))))))
56 |
57 | (h/defelem tab-tab [attr [txt]] (h/a :href "javascript:void(0)" txt))
58 | (h/defelem content [attr kids] (h/div kids))
59 | (h/defelem tab [attr kids] [(tab-tab (:name attr)) (content kids)])
60 |
61 | (def ^:private trans (partial apply map vector))
62 |
63 | (h/defelem tabs
64 | [{:keys [state]} kids]
65 | (let [[trigs ctnrs] (trans (partition 2 kids))
66 | state (or state (cell 0))
67 | trigs (selector :state state :event :click (map h/li trigs))
68 | ctnrs (deck :state state (map #(% :class "tab-pane") ctnrs))]
69 | [(h/ul :class "nav nav-tabs" trigs)
70 | (h/div :class "tab-content" ctnrs)]))
71 |
--------------------------------------------------------------------------------
/validated-form/public/css/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Globals
3 | */
4 |
5 | /* Links */
6 | a,
7 | a:focus,
8 | a:hover {
9 | color: #fff;
10 | }
11 |
12 | /*
13 | * Base structure
14 | */
15 |
16 | html,
17 | body {
18 | height: 100%;
19 | }
20 | body {
21 | box-shadow: inset 0 0 100px rgba(0,0,0,.5);
22 | }
23 |
24 | /* Extra markup and styles for table-esque vertical and horizontal centering */
25 | .site-wrapper {
26 | display: table;
27 | width: 100%;
28 | height: 100%; /* For at least Firefox */
29 | min-height: 100%;
30 | }
31 | .site-wrapper-inner {
32 | display: table-cell;
33 | vertical-align: top;
34 | }
35 | .cover-container {
36 | margin-right: auto;
37 | margin-left: auto;
38 | }
39 |
40 | .cover-heading {
41 | text-align: center;
42 | }
43 |
44 | /* Padding for spacing */
45 | .inner {
46 | padding: 30px;
47 | }
48 |
49 |
50 | /*
51 | * Header
52 | */
53 | .masthead-brand {
54 | margin-top: 10px;
55 | margin-bottom: 10px;
56 | }
57 |
58 | .masthead-nav > li {
59 | display: inline-block;
60 | }
61 | .masthead-nav > li + li {
62 | margin-left: 20px;
63 | }
64 | .masthead-nav > li > a {
65 | padding-right: 0;
66 | padding-left: 0;
67 | font-size: 16px;
68 | font-weight: bold;
69 | color: #fff; /* IE8 proofing */
70 | color: rgba(255,255,255,.75);
71 | border-bottom: 2px solid transparent;
72 | }
73 | .masthead-nav > li > a:hover,
74 | .masthead-nav > li > a:focus {
75 | background-color: transparent;
76 | border-bottom-color: rgba(255,255,255,.25);
77 | }
78 | .masthead-nav > .active > a,
79 | .masthead-nav > .active > a:hover,
80 | .masthead-nav > .active > a:focus {
81 | color: #fff;
82 | border-bottom-color: #fff;
83 | }
84 |
85 | @media (min-width: 768px) {
86 | .masthead-brand {
87 | float: left;
88 | }
89 | .masthead-nav {
90 | float: right;
91 | }
92 | }
93 |
94 |
95 | /*
96 | * Cover
97 | */
98 |
99 | .cover {
100 | padding: 0 20px;
101 | }
102 | .cover .btn-lg {
103 | padding: 10px 20px;
104 | font-weight: bold;
105 | }
106 |
107 |
108 | /*
109 | * Footer
110 | */
111 |
112 | .mastfoot {
113 | color: #999; /* IE8 proofing */
114 | color: rgba(255,255,255,.5);
115 | }
116 |
117 | .masthead,
118 | .mastfoot,
119 | .cover-container {
120 | width: 400px; /* Must be percentage or pixels for horizontal alignment */
121 | }
122 |
123 |
124 | /*
125 | * Affix and center
126 | */
127 |
128 | @media (min-width: 768px) {
129 | /* Pull out the header and footer */
130 | .masthead {
131 | position: fixed;
132 | top: 0;
133 | }
134 | .mastfoot {
135 | position: fixed;
136 | bottom: 0;
137 | }
138 | /* Start the vertical centering */
139 | .site-wrapper-inner {
140 | vertical-align: middle;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/contacts/src/demo/contacts.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.contacts
2 | (:require
3 | [clojure.string :as str]
4 | [hoplon.core :as h]
5 | [hoplon.goog]
6 | [javelin.core :refer [cell cell= dosync]]))
7 |
8 | (def my-contacts
9 | (cell #{{:first "Ben" :last "Bitdiddle" :email "benb@mit.edu"}
10 | {:first "Alyssa" :middle-initial "P" :last "Hacker" :email "aphacker@mit.edu"}
11 | {:first "Eva" :middle "Lu" :last "Ator" :email "eval@mit.edu"}
12 | {:first "Louis" :last "Reasoner" :email "prolog@mit.edu"}
13 | {:first "Cy" :middle-initial "D" :last "Effect" :email "bugs@mit.edu"}
14 | {:first "Lem" :middle-initial "E" :last "Tweakit" :email "morebugs@mit.edu"}}))
15 |
16 | (defn middle-name [{:keys [middle middle-initial]}]
17 | (cond
18 | middle (str " " middle)
19 | middle-initial (str " " middle-initial ".")))
20 |
21 | (defn display-name [{:keys [first last] :as contact}]
22 | (str last ", " first (middle-name contact)))
23 |
24 | (h/defelem contact-list [{:keys [from sorted-by] :or {sorted-by identity}}]
25 | (h/loop-tpl :bindings [contact (cell= (sort-by sorted-by from))]
26 | (h/li (h/span (cell= (display-name contact)))
27 | (h/button :click #(swap! from disj @contact) "Delete"))))
28 |
29 | (defn parse-contact [contact-str]
30 | (let [[first middle last :as parts] (str/split contact-str #"\s+")
31 | [first last middle] (if (nil? last) [first middle] [first last middle])
32 | middle (when middle (str/replace middle "." ""))
33 | c (if middle (count middle) 0)]
34 | (when (>= (count parts) 2)
35 | (cond-> {:first first :last last}
36 | (== c 1) (assoc :middle-initial middle)
37 | (>= c 2) (assoc :middle middle)))))
38 |
39 | (h/defelem contact-input [{:keys [to]} [label]]
40 | (let [new-contact (cell "")
41 | parsed (cell= (parse-contact new-contact))]
42 | (h/div
43 | (h/input
44 | :value new-contact
45 | :input #(reset! new-contact @%))
46 | (h/button
47 | :click #(when-let [c @parsed]
48 | (dosync (swap! to conj c)
49 | (reset! new-contact "")))
50 | :disabled (cell= (not parsed))
51 | label)
52 | (h/pre (cell= (pr-str parsed))))))
53 |
54 | (h/defelem contact []
55 | (h/div
56 | (h/h2 "Contact list")
57 | (h/ul (contact-list :from my-contacts :sorted-by :last))
58 | (contact-input :to my-contacts "Add contact")
59 | (h/hr)
60 | (h/p (h/em "Note: The Add contact button is disabled until you enter a valid contact. A valid contact consists of two or three whitespace-delimited names."))
61 | (h/a :href "https://github.com/tailrecursion/hoplon-demos/tree/master/contacts" "Source code on Github")))
62 |
63 | (defn mount-components []
64 | (.replaceChildren (.getElementById js/document "app")
65 | (contact)))
66 |
67 | (defn start []
68 | (mount-components)
69 | (js/console.log "Starting..."))
70 |
71 | (defn stop []
72 | (js/console.log "Stopping..."))
73 |
74 | (defn init []
75 | (js/console.log "Initializing...")
76 | (start))
77 |
--------------------------------------------------------------------------------
/demos-homepage/public/image/Lambda_lc.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
61 |
--------------------------------------------------------------------------------
/plotSVG/src/demo/plot_svg.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.plot-svg
2 | (:require
3 | [clojure.string :as str]
4 | [hoplon.core :as h]
5 | [hoplon.jquery]
6 | [demo.chart :as c]
7 | [javelin.core :refer [cell cell= defc defc= dosync]]))
8 |
9 | (defn by-id [id]
10 | (.getElementById js/document (name id)))
11 |
12 | (defn val-id [id]
13 | (h/do! (by-id id) :value))
14 |
15 | ;; Source code
16 | (def src-url "https://github.com/hoplon/demos/blob/master/plotSVG")
17 |
18 | ;; colors
19 | (def c1 "#006666")
20 | (def c2 "#660066")
21 |
22 | ;; returns a seq of random [x y] pairs, 0 <= y <= 9
23 | (defn data! []
24 | (vec (for [x (range 0 11)] [x (rand-int 11)])))
25 |
26 | ;; push a random value onto the end of a data series
27 | (defn add! [data]
28 | (conj data [(-> data last first inc) (rand-int 11)]))
29 |
30 | ;; two data series
31 | (defc data1 (data!))
32 | (defc data2 (data!))
33 |
34 | ;; user configurations "knobs"
35 | (defc pwidth 400)
36 | (defc paused? false)
37 |
38 | ;; "clipped" data (moving strip-chart)
39 | (defc= series1 (take-last 10 data1))
40 | (defc= series2 (take-last 10 data2))
41 |
42 | ;; configure the plotting envelope (linear scale)
43 | (defc= chart1
44 | (let [min-x (max (ffirst series1) (ffirst series2))
45 | max-x (min (first (last series1)) (first (last series2)))]
46 | (c/config
47 | :width pwidth :height 200
48 | :min-x min-x :max-x max-x
49 | :min-y 0 :max-y 10)))
50 |
51 | (h/defelem plot-svg []
52 | (h/div :css {:width "400px"
53 | :margin "0 auto"
54 | :text-align "center"
55 | :padding "20px"
56 | :font-family "sans-serif"}
57 |
58 | (h/h2 "Hoplon • Chart Demo")
59 |
60 | (h/hr)
61 |
62 | (h/p
63 | "Click the plot area to pause/play. "
64 | "Hover over a point to see its coordinates. "
65 | "Slide the slider to adjust plot width.")
66 |
67 | (c/container
68 | :chart chart1
69 | :css (cell= {:border "1px solid black"
70 | :margin-left (str "-" (- (/ (:width chart1) 2) 200) "px")})
71 | :click #(swap! paused? not)
72 |
73 | ;; draw shading first so it doesn't cover lines or points
74 | (c/polygon :chart chart1 :data series1 :css {:fill c1 :stroke "none" :fill-opacity 0.5})
75 | (c/polygon :chart chart1 :data series2 :css {:fill c2 :stroke "none" :fill-opacity 0.5})
76 |
77 | ;; draw lines
78 | (c/polyline :chart chart1 :data series1 :css {:fill "none" :stroke c1 :stroke-width 2})
79 | (c/polyline :chart chart1 :data series2 :css {:fill "none" :stroke c2 :stroke-width 2})
80 |
81 | ;; draw points last so they're not covered by lines or shading
82 | (c/points-circle :chart chart1 :data series1 :r 3 :css {:stroke c1 :fill c1})
83 | (c/points-rect :chart chart1 :data series2 :width 6 :height 6 :css {:stroke c2 :fill c2}))
84 |
85 | (h/br)
86 |
87 | ;; slider that lets the user change the width of the plot
88 | (h/input
89 | :id "w" :style "width:400px"
90 | :type "range" :min 400 :max 800 :step 1 :value 400
91 | :change #(reset! pwidth (val-id "w")))
92 |
93 | (h/p (h/a :href src-url "Source Code"))))
94 |
95 | (defn mount-components []
96 | (.replaceChildren (.getElementById js/document "app")
97 | (plot-svg)))
98 |
99 | (defn start []
100 | (mount-components)
101 | (js/console.log "Starting..."))
102 |
103 | (defn stop []
104 | (js/console.log "Stopping..."))
105 |
106 | (defn init []
107 | (js/console.log "Initializing...")
108 | (start)
109 | ;; add data random data points every 1000ms
110 | (h/with-init!
111 | (h/with-interval 1000
112 | (when-not @paused?
113 | (swap! data1 add!)
114 | (swap! data2 add!)))))
115 |
--------------------------------------------------------------------------------
/inputs/src/index.cljs.hl:
--------------------------------------------------------------------------------
1 | (page "index.html")
2 |
3 | ;; Cells for each input example.
4 | (defc text-input "")
5 | (defc range-input 20)
6 | (defc select-input "green")
7 | (defc multi-select #{"green"})
8 | (defc check-box false)
9 | (defc radio-input "b")
10 |
11 | (html
12 | (head
13 | (title "Hoplon • Inputs"))
14 | (body
15 | (h1
16 | "Inputs and state in Hoplon")
17 | (p
18 | "Each input example has a corresponding Javelin cell.
19 | When you change the input its cell is updated.")
20 | (h2 "A simple text input")
21 | (p "This shows that you can have more than one field pointing to the same
22 | cell. Edit one input and see everything change in sync.")
23 | (input
24 | :type "text"
25 | :placeholder "Type something here"
26 |
27 | ;; The cell is used as the value of the input.
28 | :value text-input
29 |
30 | ;; The on-keyup event fires on every keystroke for demo purposes. In
31 | ;; practice you should only update on-blur or on-change.
32 | :keyup #(reset! text-input @%))
33 | ;; On all the examples we are using the event to get the value of the
34 | ;; input. So no id is necessary.
35 |
36 | ;; This second input is just to show that you can point two inputs to the
37 | ;; same cell and update them in sync. It's the same as the first input.
38 | (input
39 | :type "text"
40 | :placeholder "Type something here"
41 | :value text-input
42 | :keyup #(reset! text-input @%))
43 | (p (text "Value of text input: ~{text-input}"))
44 |
45 | (h2 "A range input")
46 | (p "Every example gets the value from a cell and updates it when it changes.")
47 | (input
48 | :style "width:400px"
49 | :type "range" :min 0 :max 100 :step 1
50 | :value range-input
51 | :input #(reset! range-input @%))
52 | (p (text "Value of range input: ~{range-input}"))
53 |
54 | (h2 "A select input")
55 | (select
56 | :change #(reset! select-input @%)
57 | :value select-input
58 | (option :selected (cell= (= select-input "blue")) :value "blue" "blue")
59 | (option :selected (cell= (= select-input "green")) :value "green" "green")
60 | (option :selected (cell= (= select-input "gold")) :value "gold" "gold")
61 | (option :selected (cell= (= select-input "indigo")) :value "indigo" "indigo"))
62 | (p (text "Value of select input: ~{select-input}"))
63 |
64 | (h2 "Multiple select input")
65 | (select
66 |
67 | ;; The handler is more complex here because of the parsing of the
68 | ;; selectedOptions object. The cell is a set in this case.
69 | :change #(let [options (.. % -target -selectedOptions)
70 | l (.-length options)]
71 | (reset! multi-select
72 | (set
73 | (for [i (range l)]
74 | (.-value (.item options i))))))
75 | :multiple "true"
76 |
77 | ;; You need to check each option value against the multi-select cell to
78 | ;; se if it should be selected.
79 | (option :selected (cell= (multi-select "blue")) :value "blue" "blue")
80 | (option :selected (cell= (multi-select "green")) :value "green" "green")
81 | (option :selected (cell= (multi-select "gold")) :value "gold" "gold")
82 | (option :selected (cell= (multi-select "indigo")) :value "indigo" "indigo"))
83 | (p (text "Value of multiple select input: ~{multi-select}"))
84 |
85 | (h2 "A checkbox")
86 | (label
87 | (input
88 | :type "checkbox"
89 |
90 | ;; On checkboxes you need to return true from the handler or the
91 | ;; checkbox will not uncheck (at the moment).
92 | :click #(do
93 | (swap! check-box not)
94 | true)
95 | :value check-box)
96 | "Checkbox")
97 | (p (text "Value of checkbox: ~{check-box}"))
98 |
99 | (h2 "A radio button")
100 |
101 | ;; Radio buttons require more code, but work fine with cells too.
102 | (label
103 | (input
104 | :type "radio"
105 | :click #(reset! radio-input @%)
106 |
107 | ;; You need to check each input to se if it is checked.
108 | :checked (cell= (= "a" radio-input))
109 | :name "radio-group"
110 | :value "a")
111 | "a")
112 |
113 | (label
114 | (input
115 | :type "radio"
116 | :click #(reset! radio-input @%)
117 | :checked (cell= (= "b" radio-input))
118 | :name "radio-group"
119 | :value "b")
120 | "b")
121 | (p (text "Selected radio: ~{radio-input}"))))
122 |
--------------------------------------------------------------------------------
/inputs/src/demo/inputs.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.inputs
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.goog]
5 | [javelin.core :refer [cell cell= defc]]))
6 |
7 | ;; Cells for each input example.
8 | (defc text-input "")
9 | (defc range-input 20)
10 | (defc select-input "green")
11 | (defc multi-select #{"green"})
12 | (defc check-box true)
13 | (defc radio-input "b")
14 |
15 | (h/defelem inputs []
16 |
17 | (h/div
18 | (h/h1
19 | "Inputs and state in Hoplon")
20 | (h/p
21 | "Each input example has a corresponding Javelin cell.
22 | When you change the input its cell is updated.")
23 | (h/h2 "A simple text input")
24 | (h/p "This shows that you can have more than one field pointing to the same
25 | cell. Edit one input and see everything change in sync.")
26 | (h/input
27 | :type "text"
28 | :placeholder "Type something here"
29 |
30 | ;; The cell is used as the value of the input.
31 | :value text-input
32 |
33 | ;; The on-keyup event fires on every keystroke for demo purposes. In
34 | ;; practice you should only update on-blur or on-change.
35 | :keyup #(reset! text-input @%))
36 | ;; On all the examples we are using the event to get the value of the
37 | ;; input. So no id is necessary.
38 |
39 | ;; This second input is just to show that you can point two inputs to the
40 | ;; same cell and update them in sync. It's the same as the first input.
41 | (h/input
42 | :type "text"
43 | :placeholder "Type something here"
44 | :value text-input
45 | :keyup #(reset! text-input @%))
46 | (h/p (h/text "Value of text input: ~{text-input}"))
47 |
48 | (h/h2 "A range input")
49 | (h/p "Every example gets the value from a cell and updates it when it changes.")
50 | (h/input
51 | :style "width:400px"
52 | :type "range" :min 0 :max 100 :step 1
53 | :value range-input
54 | :input #(reset! range-input @%))
55 | (h/p (h/text "Value of range input: ~{range-input}"))
56 |
57 | (h/h2 "A select input")
58 | (h/select
59 | :change #(reset! select-input @%)
60 | :value select-input
61 | (h/option :selected (cell= (= select-input "blue")) :value "blue" "blue")
62 | (h/option :selected (cell= (= select-input "green")) :value "green" "green")
63 | (h/option :selected (cell= (= select-input "gold")) :value "gold" "gold")
64 | (h/option :selected (cell= (= select-input "indigo")) :value "indigo" "indigo"))
65 | (h/p (h/text "Value of select input: ~{select-input}"))
66 |
67 | (h/h2 "Multiple select input")
68 | (h/select
69 |
70 | ;; The handler is more complex here because of the parsing of the
71 | ;; selectedOptions object. The cell is a set in this case.
72 | :change #(let [options (.. % -target -selectedOptions)
73 | l (.-length options)]
74 | (reset! multi-select
75 | (set
76 | (for [i (range l)]
77 | (.-value (.item options i))))))
78 | :multiple "true"
79 |
80 | ;; You need to check each option value against the multi-select cell to
81 | ;; se if it should be selected.
82 | (h/option :selected (cell= (multi-select "blue")) :value "blue" "blue")
83 | (h/option :selected (cell= (multi-select "green")) :value "green" "green")
84 | (h/option :selected (cell= (multi-select "gold")) :value "gold" "gold")
85 | (h/option :selected (cell= (multi-select "indigo")) :value "indigo" "indigo"))
86 | (h/p (h/text "Value of multiple select input: ~{multi-select}"))
87 |
88 | (h/h2 "A checkbox")
89 | (h/label
90 | (h/input
91 | :type "checkbox"
92 |
93 | ;; On checkboxes you need to return true from the handler or the
94 | ;; checkbox will not uncheck (at the moment).
95 | :click #(do
96 | (swap! check-box not)
97 | true)
98 | :value check-box)
99 | "Checkbox")
100 | (h/p (h/text "Value of checkbox: ~{check-box}"))
101 |
102 | (h/h2 "A radio button")
103 |
104 | ;; Radio buttons require more code, but work fine with cells too.
105 | (h/label
106 | (h/input
107 | :type "radio"
108 | :click #(reset! radio-input (.getAttribute (.-target %) "data-id"))
109 |
110 | ;; You need to check each input to se if it is checked.
111 | :checked (cell= (= "a" radio-input))
112 | :data-id "a"
113 | :name "radio-group")
114 | "a")
115 |
116 | (h/label
117 | (h/input
118 | :type "radio"
119 | :click #(reset! radio-input (.getAttribute (.-target %) "data-id"))
120 | :checked (cell= (= "b" radio-input))
121 | :data-id "b"
122 | :name "radio-group")
123 | "b")
124 | (h/p (h/text "Selected radio: ~{radio-input}"))))
125 |
126 | (defn mount-components []
127 | (.replaceChildren (.getElementById js/document "app")
128 | (inputs)))
129 |
130 | (defn start []
131 | (mount-components)
132 | (js/console.log "Starting..."))
133 |
134 | (defn stop []
135 | (js/console.log "Stopping..."))
136 |
137 | (defn init []
138 | (js/console.log "Initializing...")
139 | (start))
140 |
--------------------------------------------------------------------------------
/todoFRP/src/demo/todo_frp.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.todo-frp
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.storage-atom :refer [local-storage]]
5 | [hoplon.jquery]
6 | [javelin.core :refer [cell cell= defc defc= dosync with-let]]))
7 |
8 | ;; utility functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 |
10 | (defn pluralize
11 | [word count]
12 | (str word (when (not= 1 count) "s")))
13 |
14 | (def mapv-indexed (comp vec map-indexed))
15 |
16 | (defn dissocv [v i]
17 | (let [z (- (dec (count v)) i)]
18 | (cond (neg? z) v
19 | (zero? z) (pop v)
20 | (pos? z) (into (subvec v 0 i) (subvec v (inc i))))))
21 |
22 | (defn decorate [todo route editing i]
23 | (let [{done? :completed text :text} todo]
24 | (-> todo
25 | (assoc :editing (= editing i)
26 | :visible (and (not (empty? text))
27 | (or (= "#/" route)
28 | (and (= "#/active" route) (not done?))
29 | (and (= "#/completed" route) done?)))))))
30 |
31 | (defn route-cell
32 | "Defines a cell whose value is the URI fragment."
33 | [& [default]]
34 | (let [c (cell (.. js/window -location -hash))]
35 | (with-let [_ (cell= (or (and (seq c) c) default))]
36 | (-> js/window
37 | (.addEventListener "hashchange" #(reset! c (.. js/window -location -hash)))))))
38 |
39 | ;; persisted state cell (AKA: stem cell) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 |
41 | (def state (-> (cell []) (local-storage ::store)))
42 |
43 | ;; local state cells ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 |
45 | (defc loaded? false)
46 | (defc editing nil)
47 | (def route (route-cell "#/"))
48 |
49 | ;; formula cells (computed state) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 |
51 | (defc= completed (filter :completed state))
52 | (defc= active (remove :completed state))
53 | (defc= plural-item (pluralize "item" (count active)))
54 | (defc= todos (mapv-indexed #(list %1 (decorate %2 route editing %1)) state))
55 | (defc= reverse-todos (reverse todos))
56 |
57 | ;; state transition functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 |
59 | (defn todo [t] {:completed false :text t})
60 | (defn destroy! [i] (swap! state dissocv i))
61 | (defn done! [i v] (swap! state update-in [i :completed] not))
62 | (defn clear-done! [& _] (swap! state #(vec (remove :completed %))))
63 | (defn new! [t] (when (seq t) (swap! state conj (todo t))))
64 | (defn all-done! [v] (swap! state #(mapv (fn [x] (assoc x :completed v)) %)))
65 | (defn editing! [i v] (reset! editing (if v i nil)))
66 | (defn text! [i v] (if (empty? v) (destroy! i) (swap! state assoc-in [i :text] v)))
67 |
68 | (h/defelem todo-mvc []
69 | (h/div
70 | (h/section :id "todoapp"
71 | (h/header :id "header"
72 | (h/h1 "todos")
73 | (let [new-todo-txt (cell "")]
74 | (h/form
75 | :submit #(do (new! @new-todo-txt)
76 | (reset! new-todo-txt "")
77 | (.preventDefault %))
78 | (h/input
79 | :id "new-todo"
80 | :type "text"
81 | :autofocus true
82 | :placeholder "What needs to be done?"
83 | :value new-todo-txt
84 | :change #(reset! new-todo-txt @%)
85 | :blur #(reset! new-todo-txt "")))))
86 | (h/section
87 | :id "main"
88 | :toggle (cell= (not (and (empty? active) (empty? completed))))
89 | (h/input
90 | :id "toggle-all"
91 | :type "checkbox"
92 | :attr (cell= {:checked (seq active)})
93 | :click #(all-done! true))
94 | (h/label :for "toggle-all"
95 | "Mark all as complete")
96 | (h/ul :id "todo-list"
97 | (h/loop-tpl
98 | :bindings [[i {edit? :editing done? :completed todo-text :text show? :visible}] reverse-todos]
99 | (h/li
100 | :class (cell= {:completed done? :editing edit?})
101 | :toggle show?
102 | (h/div :class "view"
103 | :dblclick #(editing! @i true)
104 | (h/input
105 | :type "checkbox"
106 | :class "toggle"
107 | :attr (cell= {:checked done?})
108 | :click #(done! @i @%))
109 | (h/label (h/text "~{todo-text}"))
110 | (h/button
111 | :type "submit"
112 | :class "destroy"
113 | :click #(destroy! @i)))
114 | (h/form
115 | :submit #(do (editing! @i false)
116 | (.preventDefault %))
117 | (h/input
118 | :type "text"
119 | :class "edit"
120 | :value todo-text
121 | :focus edit?
122 | :blur #(when @edit? (editing! @i false))
123 | :change #(when @edit? (text! @i @%))))))))
124 | (h/footer
125 | :id "footer"
126 | :toggle (cell= (not (and (empty? active) (empty? completed))))
127 | (h/span :id "todo-count"
128 | (h/strong (h/text "~(count active) "))
129 | (h/span (h/text "~{plural-item} left")))
130 | (h/ul :id "filters"
131 | (h/li (h/a :href "#/" :class (cell= {:selected (= "#/" route)}) "All"))
132 | (h/li (h/a :href "#/active" :class (cell= {:selected (= "#/active" route)}) "Active"))
133 | (h/li (h/a :href "#/completed" :class (cell= {:selected (= "#/completed" route)}) "Completed")))
134 | (h/button
135 | :type "submit"
136 | :id "clear-completed"
137 | :click #(clear-done!)
138 | (h/text "Clear completed (~(count completed))"))))
139 | (h/footer :id "info"
140 | (h/p "Double-click to edit a todo")
141 | (h/p "Part of " (h/a :href "http://github.com/hoplon/demos/" "Hoplon demos"))))
142 |
143 | )
144 |
145 | (defn mount-components []
146 | (.replaceChildren (.getElementById js/document "app")
147 | (todo-mvc)))
148 |
149 | (defn start []
150 | (mount-components)
151 | (js/console.log "Starting..."))
152 |
153 | (defn stop []
154 | (js/console.log "Stopping..."))
155 |
156 | (defn init []
157 | (js/console.log "Initializing...")
158 | (start))
159 |
--------------------------------------------------------------------------------
/infinite-scroll-paginated/src/demo/infinite_scroll_paginated.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.infinite-scroll-paginated
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.jquery]
5 | [javelin.core :refer [cell cell= dosync defc defc=]]
6 | [clojure.string :as str]))
7 |
8 | (defn generate-numbers
9 | "This generates a data vector with ten maps of sequential numbers.
10 | Example: [{:number \"0\"} {:number \"1\"} ... {:number \"9\"}]"
11 | [n]
12 | (vec (map (fn [x] {:number (str x)}) (range (* (dec n) 10)
13 | (+ (* (dec n) 10) 10)))))
14 | (defn generate-data
15 | "This generates a page map with this format
16 | {\"1\" {:page 1, :data [...]}}"
17 | [n]
18 | {(str n) {:page n
19 | :data (generate-numbers n)}})
20 |
21 | (def fake-api
22 | "This is a vector of pages from 1 to 99"
23 | (into {} (map generate-data (range 1 100))))
24 |
25 | ;; The application starts here.
26 |
27 | (defc state "The current state, a vector of loaded pages." [])
28 | (defc error "It will be a error message when a page is not found." nil)
29 | (defc loading "When it isn't empty, something is loading." [])
30 |
31 | (defc= loading? "True when there is something loading" (seq loading))
32 |
33 | (defc= sorted-state
34 | "A vector of pages sorted by page"
35 | (vec (sort-by :page state)))
36 |
37 | (defc pages-loaded "Page numbers of loaded pages." [])
38 |
39 | (defc= prev-page
40 | "Previous page that should be loaded (when scrolling up)."
41 | (dec (apply min pages-loaded)))
42 |
43 | (defc= next-page
44 | "Next page number that should be loaded."
45 | (inc (apply max pages-loaded)))
46 |
47 | (defc last-scroll "Last scroll position" 0)
48 | (defc hash-scroll "When false disable the handler to scroll on hashchange." true)
49 | (defc timeout-id "Last setTimeout id so we can cancel it if needed." 0)
50 |
51 | (defn get-page
52 | "Get a page from the fake api and run a callback on the result."
53 | [p callback]
54 | (callback (fake-api p)))
55 |
56 | (defn fetch-page!
57 | "Put the page p on the state and on the pages-loaded."
58 | [p]
59 | (when-not @loading?
60 | (reset! error nil)
61 | (swap! loading conj :loading)
62 | (let [q (str p)]
63 | (get-page q
64 | #(do
65 | (swap! loading pop)
66 | (when %
67 | (swap! state conj %)
68 | (swap! pages-loaded conj p))
69 | (when-not % (reset! error "Sem mais páginas")))))))
70 |
71 | (defn fetch-next-page!
72 | "Put the next page on the state and pages-loaded."
73 | []
74 | (fetch-page! @next-page))
75 |
76 | (defn fetch-prev-page!
77 | "Put the previous page on the state and pages-loaded and fix the scroll
78 | position."
79 | []
80 | (let [p @prev-page]
81 | (fetch-page! p)
82 | (.scrollTop (js/jQuery js/window)
83 | (+ (.scrollTop (js/jQuery js/window))
84 | (.height (js/jQuery (str "#page-" p)))))))
85 |
86 | (defn mostly-visible
87 | "Returns true if the element is the most visible on screen."
88 | [el]
89 | (let [w (js/jQuery js/window)
90 | vertical-scroll (.scrollTop w)
91 | window-height (.height w)
92 | el-top (.-top (.offset (js/jQuery el)))
93 | el-height (.height (js/jQuery el))
94 | el-bottom (+ el-top el-height)]
95 | (and (> (- el-bottom (* el-height 0.25)) vertical-scroll)
96 | (< el-top (+ vertical-scroll (* 0.5 window-height))))))
97 |
98 |
99 |
100 | (h/defelem infinite-scroll-paginated []
101 | (h/div
102 | (h/div :id "header"
103 | (h/h1 "Infinite Scrolling")
104 | (h/p "Scroll down to see more pages..."))
105 | (h/div :id "wrapper"
106 | (h/div :id "loading" :toggle loading? "LOADING IMAGES...")
107 | (h/div :id "error" :toggle error
108 | "No more pages: "
109 | (h/a :href "javascript:void(0)" :click fetch-next-page! "try again"))
110 | (h/div
111 | (h/loop-tpl :bindings [{p :page d :data} sorted-state]
112 | (h/div
113 | :id (cell= (str "page-" p))
114 | :class "item-page"
115 | :data-url (cell= (str "#/page/" p))
116 | (h/h1 :id (cell= (str "page-" p))
117 | (h/text "Page: ~{p}"))
118 | (h/loop-tpl :bindings [{it :number} d]
119 | (h/div
120 | :css {:height 100}
121 | (h/h2 (h/text "Number: ~{it}"))))))))))
122 |
123 | (defn mount-components []
124 | (.replaceChildren (.getElementById js/document "app")
125 | (infinite-scroll-paginated)))
126 |
127 | (defn start []
128 | (mount-components)
129 | (if (= (.-length (.-hash (.-location js/window))) 0)
130 | (fetch-page! 1)
131 | (fetch-page! (js/parseInt (last (str/split (.-hash (.-location js/window)) #"/")))))
132 |
133 | (h/on! js/window :scroll
134 | #(let [w (js/jQuery js/window)
135 | vertical-scroll (.scrollTop w)
136 | window-height (.height w)
137 | document-height (.height (js/jQuery js/document))
138 | at-end? (>= vertical-scroll
139 | (* 0.9 (- document-height window-height)))
140 | header-height (.height (js/jQuery "#header"))
141 | at-begin? (= vertical-scroll 0)]
142 | ;; This part of code checks what is the page most visible on screen and
143 | ;; changes the hash if that changed. It disables the scroll on
144 | ;; hashchange event and reenables it after.
145 | (when (> (.abs js/Math (- vertical-scroll @last-scroll))
146 | (* 0.1 window-height))
147 | (reset! last-scroll vertical-scroll)
148 | (.each (js/jQuery ".item-page")
149 | (fn [i v]
150 | (if (mostly-visible v)
151 | (do
152 | (js/clearTimeout @timeout-id)
153 | (reset! hash-scroll false)
154 | (set! (.-hash (.-location js/window))
155 | (.attr (js/jQuery v) "data-url"))
156 | (reset! timeout-id (js/setTimeout
157 | (fn [] (reset! hash-scroll true))
158 | 500)))))))
159 | ;; This checks if we are scrolling near the end of the page or at the
160 | ;; beginning. Them it loads the next or previous page.
161 | (if at-end?
162 | (fetch-next-page!)
163 | (when at-begin?
164 | (fetch-prev-page!)))))
165 |
166 | ;; This part makes the page scroll on hashchange if the page asked is already
167 | ;; loaded and triggers a reload when it isn't.
168 | (h/on! js/window :hashchange
169 | #(when @hash-scroll
170 | (let [p (last (str/split (.-hash (.-location js/window)) #"/"))
171 | el (js/jQuery (str "#page-"p))]
172 | (if (> (.-length el) 0)
173 | (let [position (.position el)
174 | tp (.-top position)
175 | b (js/jQuery "html,body")]
176 | (.animate b (clj->js {:scrollTop tp})))
177 | (do
178 | (reset! last-scroll 0)
179 | (.reload (.-location js/window) true))))))
180 | (js/console.log "Starting..."))
181 |
182 | (defn stop []
183 | (js/console.log "Stopping..."))
184 |
185 | (defn init []
186 | (js/console.log "Initializing...")
187 | (start))
188 |
--------------------------------------------------------------------------------
/todoFRP/public/css/main.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | color: inherit;
16 | -webkit-appearance: none;
17 | /*-moz-appearance: none;*/
18 | -ms-appearance: none;
19 | -o-appearance: none;
20 | appearance: none;
21 | }
22 |
23 | body {
24 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25 | line-height: 1.4em;
26 | background: #eaeaea url('../image/bg.png');
27 | color: #4d4d4d;
28 | width: 550px;
29 | margin: 0 auto;
30 | -webkit-font-smoothing: antialiased;
31 | -moz-font-smoothing: antialiased;
32 | -ms-font-smoothing: antialiased;
33 | -o-font-smoothing: antialiased;
34 | font-smoothing: antialiased;
35 | }
36 |
37 | #todoapp {
38 | background: #fff;
39 | background: rgba(255, 255, 255, 0.9);
40 | margin: 130px 0 40px 0;
41 | border: 1px solid #ccc;
42 | position: relative;
43 | border-top-left-radius: 2px;
44 | border-top-right-radius: 2px;
45 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
46 | 0 25px 50px 0 rgba(0, 0, 0, 0.15);
47 | }
48 |
49 | #todoapp:before {
50 | content: '';
51 | border-left: 1px solid #f5d6d6;
52 | border-right: 1px solid #f5d6d6;
53 | width: 2px;
54 | position: absolute;
55 | top: 0;
56 | left: 40px;
57 | height: 100%;
58 | }
59 |
60 | #todoapp input::-webkit-input-placeholder {
61 | font-style: italic;
62 | }
63 |
64 | #todoapp input:-moz-placeholder {
65 | font-style: italic;
66 | color: #a9a9a9;
67 | }
68 |
69 | #todoapp h1 {
70 | position: absolute;
71 | top: -120px;
72 | width: 100%;
73 | font-size: 70px;
74 | font-weight: bold;
75 | text-align: center;
76 | color: #b3b3b3;
77 | color: rgba(255, 255, 255, 0.3);
78 | text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
79 | -webkit-text-rendering: optimizeLegibility;
80 | -moz-text-rendering: optimizeLegibility;
81 | -ms-text-rendering: optimizeLegibility;
82 | -o-text-rendering: optimizeLegibility;
83 | text-rendering: optimizeLegibility;
84 | }
85 |
86 | #header {
87 | padding-top: 15px;
88 | border-radius: inherit;
89 | }
90 |
91 | #header:before {
92 | content: '';
93 | position: absolute;
94 | top: 0;
95 | right: 0;
96 | left: 0;
97 | height: 15px;
98 | z-index: 2;
99 | border-bottom: 1px solid #6c615c;
100 | background: #8d7d77;
101 | background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
102 | background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
103 | background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
104 | background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
105 | background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
106 | background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
107 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
108 | border-top-left-radius: 1px;
109 | border-top-right-radius: 1px;
110 | }
111 |
112 | #new-todo,
113 | .edit {
114 | position: relative;
115 | margin: 0;
116 | width: 100%;
117 | font-size: 24px;
118 | font-family: inherit;
119 | line-height: 1.4em;
120 | border: 0;
121 | outline: none;
122 | color: inherit;
123 | padding: 6px;
124 | border: 1px solid #999;
125 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
126 | -webkit-box-sizing: border-box;
127 | -moz-box-sizing: border-box;
128 | -ms-box-sizing: border-box;
129 | -o-box-sizing: border-box;
130 | box-sizing: border-box;
131 | -webkit-font-smoothing: antialiased;
132 | -moz-font-smoothing: antialiased;
133 | -ms-font-smoothing: antialiased;
134 | -o-font-smoothing: antialiased;
135 | font-smoothing: antialiased;
136 | }
137 |
138 | #new-todo {
139 | padding: 16px 16px 16px 60px;
140 | border: none;
141 | background: rgba(0, 0, 0, 0.02);
142 | z-index: 2;
143 | box-shadow: none;
144 | }
145 |
146 | #main {
147 | position: relative;
148 | z-index: 2;
149 | border-top: 1px dotted #adadad;
150 | }
151 |
152 | label[for='toggle-all'] {
153 | display: none;
154 | }
155 |
156 | #toggle-all {
157 | position: absolute;
158 | top: -56px;
159 | left: -15px;
160 | width: 65px;
161 | height: 41px;
162 | text-align: center;
163 | border: none; /* Mobile Safari */
164 | -webkit-appearance: none;
165 | /*-moz-appearance: none;*/
166 | -ms-appearance: none;
167 | -o-appearance: none;
168 | appearance: none;
169 | -webkit-transform: rotate(90deg);
170 | /*-moz-transform: rotate(90deg);*/
171 | -ms-transform: rotate(90deg);
172 | /*-o-transform: rotate(90deg);*/
173 | transform: rotate(90deg);
174 | }
175 |
176 | #toggle-all:before {
177 | content: '»';
178 | font-size: 28px;
179 | color: #d9d9d9;
180 | padding: 0 25px 7px;
181 | }
182 |
183 | #toggle-all:checked:before {
184 | color: #737373;
185 | }
186 |
187 | #todo-list {
188 | margin: 0;
189 | padding: 0;
190 | list-style: none;
191 | }
192 |
193 | #todo-list li {
194 | position: relative;
195 | font-size: 24px;
196 | border-bottom: 1px dotted #ccc;
197 | }
198 |
199 | #todo-list li:last-child {
200 | border-bottom: none;
201 | }
202 |
203 | #todo-list li.editing {
204 | border-bottom: none;
205 | padding: 0;
206 | }
207 |
208 | #todo-list li.editing .edit {
209 | display: block;
210 | width: 506px;
211 | padding: 13px 17px 12px 17px;
212 | margin: 0 0 0 43px;
213 | }
214 |
215 | #todo-list li.editing .view {
216 | display: none;
217 | }
218 |
219 | #todo-list li .toggle {
220 | text-align: center;
221 | width: 40px;
222 | height: 40px;
223 | position: absolute;
224 | top: 0;
225 | bottom: 0;
226 | margin: auto 0;
227 | border: none; /* Mobile Safari */
228 | -webkit-appearance: none;
229 | /*-moz-appearance: none;*/
230 | -ms-appearance: none;
231 | -o-appearance: none;
232 | appearance: none;
233 | }
234 |
235 | #todo-list li .toggle:after {
236 | font-size: 18px;
237 | content: '✔';
238 | line-height: 43px; /* 40 + a couple of pixels visual adjustment */
239 | font-size: 20px;
240 | color: #d9d9d9;
241 | text-shadow: 0 -1px 0 #bfbfbf;
242 | }
243 |
244 | #todo-list li .toggle:checked:after {
245 | color: #85ada7;
246 | text-shadow: 0 1px 0 #669991;
247 | bottom: 1px;
248 | position: relative;
249 | }
250 |
251 | #todo-list li label {
252 | word-break: break-word;
253 | padding: 15px;
254 | margin-left: 45px;
255 | display: block;
256 | line-height: 1.2;
257 | -webkit-transition: color 0.4s;
258 | -moz-transition: color 0.4s;
259 | -ms-transition: color 0.4s;
260 | -o-transition: color 0.4s;
261 | transition: color 0.4s;
262 | }
263 |
264 | #todo-list li.completed label {
265 | color: #a9a9a9;
266 | text-decoration: line-through;
267 | }
268 |
269 | #todo-list li .destroy {
270 | display: none;
271 | position: absolute;
272 | top: 0;
273 | right: 10px;
274 | bottom: 0;
275 | width: 40px;
276 | height: 40px;
277 | margin: auto 0;
278 | font-size: 22px;
279 | color: #a88a8a;
280 | -webkit-transition: all 0.2s;
281 | -moz-transition: all 0.2s;
282 | -ms-transition: all 0.2s;
283 | -o-transition: all 0.2s;
284 | transition: all 0.2s;
285 | }
286 |
287 | #todo-list li .destroy:hover {
288 | text-shadow: 0 0 1px #000,
289 | 0 0 10px rgba(199, 107, 107, 0.8);
290 | -webkit-transform: scale(1.3);
291 | -moz-transform: scale(1.3);
292 | -ms-transform: scale(1.3);
293 | -o-transform: scale(1.3);
294 | transform: scale(1.3);
295 | }
296 |
297 | #todo-list li .destroy:after {
298 | content: '✖';
299 | }
300 |
301 | #todo-list li:hover .destroy {
302 | display: block;
303 | }
304 |
305 | #todo-list li .edit {
306 | display: none;
307 | }
308 |
309 | #todo-list li.editing:last-child {
310 | margin-bottom: -1px;
311 | }
312 |
313 | #footer {
314 | color: #777;
315 | padding: 0 15px;
316 | position: absolute;
317 | right: 0;
318 | bottom: -31px;
319 | left: 0;
320 | height: 20px;
321 | z-index: 1;
322 | text-align: center;
323 | }
324 |
325 | #footer:before {
326 | content: '';
327 | position: absolute;
328 | right: 0;
329 | bottom: 31px;
330 | left: 0;
331 | height: 50px;
332 | z-index: -1;
333 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
334 | 0 6px 0 -3px rgba(255, 255, 255, 0.8),
335 | 0 7px 1px -3px rgba(0, 0, 0, 0.3),
336 | 0 43px 0 -6px rgba(255, 255, 255, 0.8),
337 | 0 44px 2px -6px rgba(0, 0, 0, 0.2);
338 | }
339 |
340 | #todo-count {
341 | float: left;
342 | text-align: left;
343 | }
344 |
345 | #filters {
346 | margin: 0;
347 | padding: 0;
348 | list-style: none;
349 | position: absolute;
350 | right: 0;
351 | left: 0;
352 | }
353 |
354 | #filters li {
355 | display: inline;
356 | }
357 |
358 | #filters li a {
359 | color: #83756f;
360 | margin: 2px;
361 | text-decoration: none;
362 | }
363 |
364 | #filters li a.selected {
365 | font-weight: bold;
366 | }
367 |
368 | #clear-completed {
369 | float: right;
370 | position: relative;
371 | line-height: 20px;
372 | text-decoration: none;
373 | background: rgba(0, 0, 0, 0.1);
374 | font-size: 11px;
375 | padding: 0 10px;
376 | border-radius: 3px;
377 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
378 | }
379 |
380 | #clear-completed:hover {
381 | background: rgba(0, 0, 0, 0.15);
382 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
383 | }
384 |
385 | #info {
386 | margin: 65px auto 0;
387 | color: #a6a6a6;
388 | font-size: 12px;
389 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
390 | text-align: center;
391 | }
392 |
393 | #info a {
394 | color: inherit;
395 | }
396 |
397 | #noscript {
398 | color: white;
399 | background: red;
400 | width: 100%;
401 | text-align: center;
402 | }
403 |
404 | #noscript p {
405 | margin: 0px;
406 | padding: 15px;
407 | font-size: large;
408 | font-weight: bold;
409 | }
410 |
411 | /*
412 | Hack to remove background from Mobile Safari.
413 | Can't use it globally since it destroys checkboxes in Firefox and Opera
414 | */
415 | @media screen and (-webkit-min-device-pixel-ratio:0) {
416 | #toggle-all,
417 | #todo-list li .toggle {
418 | background: none;
419 | }
420 | }
421 |
422 | .hidden{
423 | display:none;
424 | }
425 |
--------------------------------------------------------------------------------
/async-webinar/src/demo/async_webinar.cljs:
--------------------------------------------------------------------------------
1 | (ns demo.async-webinar
2 | (:require
3 | [hoplon.core :as h]
4 | [hoplon.jquery]
5 | [javelin.core :refer [cell cell= defc defc= dosync]]))
6 |
7 | (defn mouse-loc->vec
8 | "Given a Google Closure normalized DOM mouse event return the
9 | mouse x and y position as a two element vector."
10 | [e]
11 | [(.-clientX e) (.-clientY e)])
12 |
13 | ;; =============================================================================
14 | ;; Example 1
15 |
16 | (defc ex1-content ["Waiting for a click ...."])
17 | (defc ex1-click-count 0)
18 | (defn ex1 []
19 | (when (< @ex1-click-count 1)
20 | (swap! ex1-click-count inc)
21 | (swap! ex1-content conj "Got a click!")))
22 |
23 | ;; =============================================================================
24 | ;; Example 2
25 |
26 | (defc ex2-content ["Waiting for a click ...."])
27 | (defc ex2-click-count 0)
28 | (defn ex2 []
29 | (when (= @ex2-click-count 1)
30 | (swap! ex2-click-count inc)
31 | (swap! ex2-content conj "Done"))
32 | (when (= @ex2-click-count 0)
33 | (swap! ex2-click-count inc)
34 | (swap! ex2-content conj "Got a Click!" "Waiting for another click ....")))
35 |
36 | ;; =============================================================================
37 | ;; Example 3
38 |
39 | (defc ex3-content ["Waiting for a click from Button A ....."])
40 | (defc ex3-click-count-a 0)
41 | (defc ex3-click-count-b 0)
42 | (defn ex3a []
43 | (when (= @ex3-click-count-a 0)
44 | (swap! ex3-click-count-a inc)
45 | (swap! ex3-content conj "Got a click!" "Waiting for a click from Button B ....")) )
46 | (defn ex3b []
47 | (when (and (= @ex3-click-count-a 1) (= @ex3-click-count-b 0))
48 | (swap! ex3-click-count-b inc)
49 | (swap! ex3-content conj "Done!")))
50 |
51 | ;; =============================================================================
52 | ;; Example 6
53 |
54 | (defc ex6-content ["Click the button to start tracking the mouse."])
55 | (defc ex6-button-name "GO!")
56 | (defn ex6-toggle []
57 | (let [new-name (if (= @ex6-button-name "GO!") "STOP!" "GO!")]
58 | (reset! ex6-button-name new-name)))
59 | (defn ex6 [e]
60 | (when (= @ex6-button-name "STOP!")
61 | (swap! ex6-content conj (str (mouse-loc->vec e)))))
62 |
63 | ;; =============================================================================
64 | ;; Example 7
65 |
66 | (defc ex7-content ["Click the button to start tracking the mouse."])
67 | (defc ex7-button-name "GO!")
68 | (defn ex7-toggle []
69 | (let [new-name (if (= @ex7-button-name "GO!") "STOP!" "GO!")]
70 | (reset! ex7-button-name new-name)))
71 | (defn ex7 [e]
72 | (when (= @ex7-button-name "STOP!")
73 | (let [[_x y :as m] (mouse-loc->vec e)]
74 | (when (zero? (mod y 5))
75 | (swap! ex7-content conj (str m))))))
76 |
77 | ;; =============================================================================
78 | ;; Example 8
79 |
80 | (defc ex8-content ["Click the button ten times."])
81 | (defc ex8-click-count 0)
82 | (defn ex8 []
83 | (when (< @ex8-click-count 10)
84 | (swap! ex8-click-count inc)
85 | (when (= @ex8-click-count 1)
86 | (swap! ex8-content conj "1 Click!"))
87 | (when (> @ex8-click-count 1)
88 | (swap! ex8-content conj (str @ex8-click-count " clicks!")))
89 | (when (= @ex8-click-count 10)
90 | (swap! ex8-content conj "Done."))))
91 |
92 | ;; =============================================================================
93 | ;; Example 9
94 |
95 | (defc ex9-index 0)
96 | (defc ex9-animals [:aardvark :beetle :cat :dog :elk :ferret
97 | :goose :hippo :ibis :jellyfish :kangaroo])
98 | (defc= ex9-card (nth ex9-animals ex9-index))
99 | (defn ex9-prev []
100 | (when (> @ex9-index 0)
101 | (swap! ex9-index dec)))
102 | (defn ex9-next []
103 | (when (< @ex9-index (dec (count @ex9-animals)))
104 | (swap! ex9-index inc)))
105 |
106 | ;; =============================================================================
107 | ;; Example 10
108 |
109 | (defc ex10-button-name "START!")
110 | (defc ex10-index 0)
111 | (defn ex10 []
112 | (let [the-name @ex10-button-name]
113 | (when (= the-name"START!")
114 | (reset! ex10-button-name "STOP!"))
115 | (when (= the-name"STOP!")
116 | (reset! ex10-button-name "DONE!"))))
117 | (defc ex10-animals [:aardvark :beetle :cat :dog :elk :ferret
118 | :goose :hippo :ibis :jellyfish :kangaroo])
119 | (defc= ex10-max (dec (count ex10-animals)))
120 | (defc= ex10-card (nth ex10-animals ex10-index))
121 | (defn ex10-prev []
122 | (if (> @ex10-index 0)
123 | (swap! ex10-index dec)
124 | (reset! ex10-index @ex10-max)))
125 | (defn ex10-next []
126 | (if (< @ex10-index @ex10-max)
127 | (swap! ex10-index inc)
128 | (reset! ex10-index 0)))
129 | (defn ex10-nav [k]
130 | (when (= @ex10-button-name "STOP!")
131 | (when (= k :next)
132 | (ex10-next))
133 | (when (= k :prev)
134 | (ex10-prev))))
135 |
136 | (defn ex10-keys [e]
137 | (when (= @ex10-button-name "STOP!")
138 | (when (= (.-keyCode e) 39) (ex10-nav :next))
139 | (when (= (.-keyCode e) 37) (ex10-nav :prev))))
140 |
141 |
142 | (h/defelem async-webinar []
143 | (h/div
144 | (h/